BUUCTF--SimpleRev
1.准备
获取信息
- 64位文件
2.IDA打开
将main函数反编译为C代码
1 int __cdecl __noreturn main(int argc, const char **argv, const char **envp) 2 { 3 int v3; // eax 4 char v4; // [rsp+Fh] [rbp-1h] 5 6 while ( 1 ) 7 { 8 while ( 1 ) 9 { 10 printf("Welcome to CTF game!\nPlease input d/D to start or input q/Q to quit this program: ", argv, envp); 11 v4 = getchar(); 12 if ( v4 != 'd' && v4 != 'D' ) 13 break; 14 Decry(); 15 } 16 if ( v4 == 'q' || v4 == 'Q' ) 17 Exit(); 18 puts("Input fault format!"); 19 v3 = getchar(); 20 putchar(v3); 21 } 22 }
3.代码分析
很明显,这道题的关键在于Decry()
1 unsigned __int64 Decry() 2 { 3 char v1; // [rsp+Fh] [rbp-51h] 4 int v2; // [rsp+10h] [rbp-50h] 5 int v3; // [rsp+14h] [rbp-4Ch] 6 int i; // [rsp+18h] [rbp-48h] 7 int v5; // [rsp+1Ch] [rbp-44h] 8 char src[8]; // [rsp+20h] [rbp-40h] 9 __int64 v7; // [rsp+28h] [rbp-38h] 10 int v8; // [rsp+30h] [rbp-30h] 11 __int64 v9; // [rsp+40h] [rbp-20h] 12 __int64 v10; // [rsp+48h] [rbp-18h] 13 int v11; // [rsp+50h] [rbp-10h] 14 unsigned __int64 v12; // [rsp+58h] [rbp-8h] 15 16 v12 = __readfsqword(0x28u); 17 *(_QWORD *)src = 'SLCDN'; 18 v7 = 0LL; 19 v8 = 0; 20 v9 = 'wodah'; 21 v10 = 0LL; 22 v11 = 0; 23 text = join(key3, (const char *)&v9); // text = 'killshadow' 24 strcpy(key, key1); 25 strcat(key, src); // key = 'ADSFKNDCLS' 26 v2 = 0; 27 v3 = 0; 28 getchar(); 29 v5 = strlen(key); // v5 = 10 30 for ( i = 0; i < v5; ++i ) 31 { 32 if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )// key = 'adsfkndcls' 33 key[i] = key[v3 % v5] + 32; 34 ++v3; 35 } 36 printf("Please input your flag:", src); 37 while ( 1 ) 38 { 39 v1 = getchar(); 40 if ( v1 == 10 ) 41 break; 42 if ( v1 == 32 ) 43 { 44 ++v2; 45 } 46 else 47 { 48 if ( v1 <= 96 || v1 > 122 ) 49 { 50 if ( v1 > 64 && v1 <= 90 ) // 大写字母 51 str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97; 52 } 53 else // 小写字母 54 { 55 str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97; 56 } 57 if ( !(v3 % v5) ) 58 putchar(' '); 59 ++v2; 60 } 61 } 62 if ( !strcmp(text, str2) ) 63 puts("Congratulation!\n"); 64 else 65 puts("Try again!\n"); 66 return __readfsqword(0x28u) ^ v12; 67 }
转换成可以运行的C代码是
1 #include <bits/stdc++.h> 2 3 #pragma warning(disable:4996) 4 5 int main(void) 6 { 7 int i, j, n = 0, v5 = 10, v3 = 0, v2 = 0; 8 char v1; 9 char flag[11] = { 0 }; 10 char str2[104] = { 0 }; 11 char key[] = "ADSFKNDCLS"; 12 char text[] = "killshadow"; 13 14 15 for (i = 0; i < v5; ++i) 16 { 17 if (key[v3 % v5] > 64 && key[v3 % v5] <= 90) 18 key[i] = key[v3 % v5] + 32; 19 ++v3; 20 } 21 printf("Please input your flag:"); 22 while (1) 23 { 24 v1 = getchar(); 25 printf("v1:%c\nv2:%d\n\n", v1, v2); 26 if (v1 == 10) { 27 printf("进入1\n"); 28 break; 29 } 30 if (v1 == 32) 31 { 32 printf("进入2\n"); 33 ++v2; 34 } 35 else 36 { 37 if (v1 <= 96 || v1 > 122) 38 { 39 if (v1 > 64 && v1 <= 90) { 40 str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97; 41 printf("计算1\n"); 42 } 43 } 44 else 45 { 46 str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97; 47 printf("计算1\n"); 48 } 49 if (!(v3 % v5)) 50 putchar(' '); 51 ++v2; 52 } 53 } 54 if (!strcmp(text, str2)) 55 puts("Congratulation!\n"); 56 else { 57 printf("str2:%s\n", str2); 58 puts("Try again!\n"); 59 } 60 61 system("PAUSE"); 62 return 0; 63 }
第30~35行代码的实际作用是将大写字母转换为小写。
第37~61行代码实际上就是遍历输入的字符(flag),进行str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;运算,最后与text比较。
因此我们只要反向就能求出输入的v1
4.程序获取flag
#include <bits/stdc++.h> #pragma warning(disable:4996) int main(void) { int i, j, n = 0, v5 = 10, v3 = 0, v2 = 0; char v1; char flag[11] = { 0 }; char str2[104] = { 0 }; char key[] = "ADSFKNDCLS"; char text[] = "killshadow"; for (i = 0; i < v5; ++i) { if (key[v3 % v5] > 64 && key[v3 % v5] <= 90) key[i] = key[v3 % v5] + 32; ++v3; } for (j = 0; j < 10; ++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("%s\n", flag); system("PAUSE"); return 0; } } } } system("PAUSE"); return 0; }
5.get flag!
flag{KLDQCUDFZO}