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}
来源:oschina
链接:https://my.oschina.net/u/4383141/blog/4459838