看到有些大佬在做BUUCTF的题,看了一下,题目很多,但是感觉良莠不齐,并且开始的一些题目有些太简单了,就当是多做些题目了。
easyre 确实非常easy,直接拖进IDA看到flag
reverse1 IDA打开,通过字符串窗口找到主程序,整个程序流程很简单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 for ( j = 0 ; ; ++j ) { v8 = j; v2 = j_strlen (Str2); if ( v8 > v2 ) break ; if ( Str2[j] == 'o' ) Str2[j] = '0' ; } sub_1400111D1 ("input the flag:" ); sub_14001128F ("%20s" , &Str1); v3 = j_strlen (Str2); if ( !strncmp (&Str1, Str2, v3) ) sub_1400111D1 ("this is the right flag!\n" ); else sub_1400111D1 ("wrong flag\n" );
只有这一部分有用,str2时内存中的一个字符串,只是将输入的字符串和变换过后的str2进行一个简单的对比,一样则输出正确
str2的变换就是将所有的o变换成0,str2为‘{hello_world}’,所以flag为
reverse2 和上一题完全一样,只不过时ELF64文件,把i和r全部替换成了1
helloworld 安卓逆向,直接apktool反编译,在MainActivity.smail文件里找到了flag
1 flag{7631a988259a00816deda84afb29430a}
新年快乐 简单加壳软件,在加壳时没做任何的修改,直接upx脱壳,IDA反编译,通过字符串直接找到flag
内涵的软件 IDA反编译可以直接发现flag,把花括号里的放进flag{}里即可
1 flag {49 d3 c93 df25 caad81232130 f3 d2 ebfad}
xor 一看题目就是到要逆运算异或,反编译之后发现关键运算
1 2 3 4 5 for ( i = 1 ; i < 33 ; ++i ) v6[i] ^= v6[i - 1 ]; v3 = global; if ( !strncmp (v6, global, 0x21 uLL) ) printf ("Success" , v3);
所以逆运算就好了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <iostream> #include <string> using namespace std;int main () { unsigned char ida_chars[] = { 0x66 , 0x0A , 0x6B , 0x0C , 0x77 , 0x26 , 0x4F , 0x2E , 0x40 , 0x11 , 0x78 , 0x0D , 0x5A , 0x3B , 0x55 , 0x11 , 0x70 , 0x19 , 0x46 , 0x1F , 0x76 , 0x22 , 0x4D , 0x23 , 0x44 , 0x0E , 0x67 , 0x06 , 0x68 , 0x0F , 0x47 , 0x32 , 0x4F }; string flag; flag+=ida_chars[0 ]; for (int i=1 ;i<33 ;i++) { flag+=(ida_chars[i]^ida_chars[i-1 ]); } cout<<flag<<endl; return 0 ; }
直接输出flag
1 flag {QianQiuWanDai_YiTongJiangHu}
reverse3 和bugku的love是同一个题,不再赘述
不一样的flag 比较简单的的迷宫题,上下左右全部都标示的清清楚楚
迷宫如下图
1 2 3 4 5 *1111 01000 01010 00010 1111 #
转换成5*5的方阵,*走到#即可
刮开有奖 IDA反编译出来,发现需要输入8位,经过sub_4010F0这个函数的变换后,在经过两个base64变换(查看函数内部自己发现),满足条件即正确
sub_4010F0这个函数内容比较多,但是和输入的字符串无关,所以直接直接把函数实现然后求出来正确的取值就可以了(后面的条件略多,这里的变换实际上只需要第一位和第五位)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <iostream> #include <string> using namespace std;int __cdecl decrypt (char *a1, int a2, int a3) { int result; int i; int v5; int v6; result = a3; for (i = a2; i <= a3; a2 = i) { v5 = i; v6 = a1[i]; if (a2 < result && i < result) { do { if (v6 > a1[result]) { if (i >= result) break ; ++i; a1[v5] = a1[result]; if (i >= result) break ; while (a1[result] <= v6) { if (++i >= result) goto LABEL_13; } if (i >= result) break ; v5 = i; a1[result] = a1[i]; } --result; } while (i < result); } LABEL_13: a1[result] = v6; decrypt (a1, a2, i - 1 ); result = a3; ++i; } return result; } char v9[20 ] = {90 , 74 , 83 , 69 , 67 , 97 , 78 , 72 , 51 , 110 , 103 };int main () { cout << v9 << endl; decrypt (v9, 0 , 10 ); cout << v9 << endl; return 0 ; }
输出如图所示
接着分析下面的部分
1 2 3 4 5 6 7 8 9 10 if ( String == v9 + 34 && v21 == v13 && 4 * v22 - 141 == 3 * v11 && v23 / 4 == 2 * (v16 / 9 ) && !strcmp (v6, "ak1w" ) && !strcmp (v7,"V1Ax" ) ) { MessageBoxA (hDlg, "U g3t 1T!" , "@_@" , 0 ); }
还多了两个条件就检验正确就可以了
得到flag
SimpleRev 这题没什么难度,IDA打开
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int __cdecl __noreturn main (int argc, const char **argv, const char **envp) { int v3; char v4; while ( 1 ) { while ( 1 ) { printf ("Welcome to CTF game!\nPlease input d/D to start or input q/Q to quit this program: " , argv, envp); v4 = getchar (); if ( v4 != 'd' && v4 != 'D' ) break ; Decry (); } if ( v4 == 'q' || v4 == 'Q' ) Exit (); puts ("Input fault format!" ); v3 = getchar (); putchar (v3); } }
main函数里面没有什么需要注意的东西,解决问题的重点就都放在Decry()这个函数里了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 unsigned __int64 Decry () { char v1; int v2; int v3; int i; int v5; char src[8 ]; __int64 v7; int v8; __int64 v9; __int64 v10; int v11; unsigned __int64 v12; v12 = __readfsqword(0x28 u); *(_QWORD *)src = 'SLCDN' ; v7 = 0LL ; v8 = 0 ; v9 = 'wodah' ; v10 = 0LL ; v11 = 0 ; text = join (key3, (const char *)&v9); strcpy (key, key1); strcat (key, src); v2 = 0 ; v3 = 0 ; getchar (); v5 = strlen (key); for ( i = 0 ; i < v5; ++i ) { if ( key[v3 % v5] > '@' && key[v3 % v5] <= 'Z' ) key[i] = key[v3 % v5] + 32 ; ++v3; } printf ("Please input your flag:" , src); while ( 1 ) { v1 = getchar (); if ( v1 == '\n' ) break ; if ( v1 == ' ' ) { ++v2; } else { if ( v1 <= 96 || v1 > 122 ) { if ( v1 > 64 && v1 <= 90 ) str2[v2] = (v1 - 39 - key[v3++ % v5] + 97 ) % 26 + 97 ; } else { str2[v2] = (v1 - 39 - key[v3++ % v5] + 97 ) % 26 + 97 ; } if ( !(v3 % v5) ) putchar (32 ); ++v2; } } if ( !strcmp (text, str2) ) puts ("Congratulation!\n" ); else puts ("Try again!\n" ); return __readfsqword(0x28 u) ^ v12; }
需要注意src和v9本身是以long long类型赋值,转换成字符串要记得逆序,接下来的过程就很简单了,程序的过程很清楚,直接逆向运算就可以算出来结果了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <iostream> #include <string> using namespace std;int main (void ) { int n = 0 , v5 = 10 , v3 = 10 , v2 = 0 ; char v1; char flag[11 ] = {0 }; char key[] = "adsfkndcls" ; char text[] = "killshadow" ; for (int j = 0 ; j < 4 ; ++j) { for (v2 = 0 ; v2 < 10 ; ++v2) { v1 = text[v2] - 97 + 26 * j - 97 + key[v3++ % v5] + 39 ; if ((v1 >= 65 && v1 <= 90 ) || (v1 >= 97 && v1 <= 122 )) { flag[v2] = v1; if (++n == 10 ) { printf ("flag{%s}\n" , flag); return 0 ; } } } } return 0 ; }
这里的j是用来逆向取余运算时候遍历,放缩之后得到一个范围,然后计算就可以了
Java逆向解密 第一次做Java逆向,顺便也熟悉熟悉Java,所以逆向程序也是用Java写的
附件打开是class文件,IDEA直接可以反编译,反编译出来的代码很简单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import java.util.ArrayList;import java.util.Scanner;public class Reverse { public Reverse () { } public static void main (String[] args) { Scanner s = new Scanner(System.in); System.out.println("Please input the flag :" ); String str = s.next(); System.out.println("Your input is :" ); System.out.println(str); char [] stringArr = str.toCharArray(); Encrypt(stringArr); } public static void Encrypt (char [] arr) { ArrayList<Integer> Resultlist = new ArrayList(); for (int i = 0 ; i < arr.length; ++i) { int result = arr[i] + 64 ^ 32 ; Resultlist.add(result); } int [] KEY = new int []{180 , 136 , 137 , 147 , 191 , 137 , 147 , 191 , 148 , 136 , 133 , 191 , 134 , 140 , 129 , 135 , 191 , 65 }; ArrayList<Integer> KEYList = new ArrayList(); for (int j = 0 ; j < KEY.length; ++j) { KEYList.add(KEY[j]); } System.out.println("Result:" ); if (Resultlist.equals(KEYList)) { System.out.println("Congratulations!" ); } else { System.err.println("Error!" ); } } }
把KEY每个值都减去64^32就好了,没什么难度,所以试试用Java写,练练手
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.company;import java.util.ArrayList;public class Main { public static void main (String[] args) { int [] KEY = new int []{180 , 136 , 137 , 147 , 191 , 137 , 147 , 191 , 148 , 136 , 133 , 191 , 134 , 140 , 129 , 135 , 191 , 65 }; ArrayList<Integer> resultList = new ArrayList<>(); for (int value : KEY) { resultList.add(value - 64 ^ 32 ); } StringBuilder s = new StringBuilder(); for (int value:resultList){ s.append((char )value); } System.out.println("flag{" +s+"}" ); } }
直接输出flag
1 flag{This_ is _ the_f lag_ !}
findit 不管是apktool反编译还是直接cfr反编译到代码,都可以找到一串很像flag的字符数组
1 pvkq {m164675262033 l4 m49 lnp7 p9 mnk28 k75 }
直接凯撒密码解密,a与k之间相差10,所以key=10
1 flag {c164675262033 b4 c49 bdf7 f9 cda28 a75 }
rsa 直接解析公钥 ,然后暴力分解解密就可以了
Comments