这是一个 32 位的程序,点开之后啥都没有,就是一个空的界面

然后用 idapro 打开它之后,发现主函数中也没有什么有用的东西

所以我就 shift+F12 查看一下字符串,发现有几个可以字符串

双击进去交叉引用一下,可以看到

但是这里无法 F5 查看伪代码,所以我们把红色的全部选中并将它转为函数即可,转为函数后我们就可以来分析了

# main 函数

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
LRESULT __stdcall sub_401640(HWND hWndParent, UINT Msg, WPARAM wParam, LPARAM lParam)
{
int v5; // eax
size_t v6; // eax
DWORD v7; // eax
int v8; // eax
int v9; // eax
int v10; // [esp+4Ch] [ebp-400h]
UINT v11; // [esp+50h] [ebp-3FCh]
CHAR v12[256]; // [esp+54h] [ebp-3F8h] BYREF
char v13[7]; // [esp+154h] [ebp-2F8h] BYREF
__int16 v14; // [esp+15Bh] [ebp-2F1h]
char v15; // [esp+15Dh] [ebp-2EFh]
char Str[33]; // [esp+160h] [ebp-2ECh] BYREF
char v17[220]; // [esp+181h] [ebp-2CBh] BYREF
__int16 v18; // [esp+25Dh] [ebp-1EFh]
char v19; // [esp+25Fh] [ebp-1EDh]
CHAR v20[256]; // [esp+260h] [ebp-1ECh] BYREF
CHAR String[4]; // [esp+360h] [ebp-ECh] BYREF
int v22; // [esp+364h] [ebp-E8h]
__int16 v23; // [esp+368h] [ebp-E4h]
CHAR Text[32]; // [esp+36Ch] [ebp-E0h] BYREF
struct tagRECT Rect; // [esp+38Ch] [ebp-C0h] BYREF
CHAR Buffer[100]; // [esp+39Ch] [ebp-B0h] BYREF
HDC hdc; // [esp+400h] [ebp-4Ch]
struct tagPAINTSTRUCT Paint; // [esp+404h] [ebp-48h] BYREF
int v29; // [esp+444h] [ebp-8h]
int v30; // [esp+448h] [ebp-4h]

LoadStringA(hInstance, 0x6Au, Buffer, 100);
v11 = Msg;
if ( Msg > 0x111 )
{
if ( v11 == 517 )
{
if ( strlen((const char *)String1) > 6 )
ExitProcess(0);
if ( strlen((const char *)String1) )
{
memset(v20, 0, sizeof(v20));
v6 = strlen((const char *)String1);
memcpy(v20, String1, v6);
v7 = strlen((const char *)String1);
sub_40101E(String1, v7, (LPSTR)String1);
strcpy(Str, "0kk`d1a`55k222k2a776jbfgd`06cjjb");
memset(v17, 0, sizeof(v17));
v18 = 0;
v19 = 0;
strcpy(v13, "SS");
*(_DWORD *)&v13[3] = 0;
v14 = 0;
v15 = 0;
v8 = strlen(Str);
sub_401005(v13, (int)Str, v8);
if ( _strcmpi((const char *)String1, Str) )
{
SetWindowTextA(hWndParent, "flag{}");
MessageBoxA(hWndParent, "Are you kidding me?", "^_^", 0);
ExitProcess(0);
}
memcpy(v12, &unk_423030, 0x32u);
v9 = strlen(v12);
sub_401005(v20, (int)v12, v9);
MessageBoxA(hWndParent, v12, 0, 0x32u);
}
++dword_428D54;
}
else
{
if ( v11 != 520 )
return DefWindowProcA(hWndParent, Msg, wParam, lParam);
if ( dword_428D54 == 16 )
{
strcpy(String, "ctf");
v22 = 0;
v23 = 0;
SetWindowTextA(hWndParent, String);
strcpy(Text, "Are you kidding me?");
MessageBoxA(hWndParent, Text, Buffer, 0);
}
++dword_428D54;
}
}
else
{
switch ( v11 )
{
case 0x111u:
v30 = (unsigned __int16)wParam;
v29 = HIWORD(wParam);
v10 = (unsigned __int16)wParam;
if ( (unsigned __int16)wParam == 104 )
{
DialogBoxParamA(hInstance, (LPCSTR)0x67, hWndParent, (DLGPROC)DialogFunc, 0);
}
else
{
if ( v10 != 105 )
return DefWindowProcA(hWndParent, Msg, wParam, lParam);
DestroyWindow(hWndParent);
}
break;
case 2u:
PostQuitMessage(0);
break;
case 0xFu:
hdc = BeginPaint(hWndParent, &Paint);
GetClientRect(hWndParent, &Rect);
v5 = strlen(Buffer);
DrawTextA(hdc, Buffer, v5, &Rect, 1u);
EndPaint(hWndParent, &Paint);
break;
default:
return DefWindowProcA(hWndParent, Msg, wParam, lParam);
}
}
return 0;
}

其中有两个关键函数 sub_40101E,sub_401005,并且 sub_401005 函数进行了两次,那么我们的 flag 就是第二个 MessageBoxA 输出的

# sub_40101E

这个函数百度之后知道是进行 hash 加密,但还不确定是那种类型的 hash

# sub_401005

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
unsigned int __cdecl sub_401590(LPCSTR lpString, int a2, int a3)
{
unsigned int result; // eax
unsigned int i; // [esp+4Ch] [ebp-Ch]
unsigned int v5; // [esp+54h] [ebp-4h]

v5 = lstrlenA(lpString);
for ( i = 0; ; ++i )
{
result = i;
if ( i >= a3 )
break;
*(_BYTE *)(i + a2) ^= lpString[i % v5];
}
return result;
}

一个很简单的异或,其中 a2 是字符串 "0kk`d1a`55k222k2a776jbfgd`06cjjb",a3 是 “SS”,第二次异或的 a2 是 "W^RTI_1miF2n_2lW [TL",而 a3 是 String1,是没有进行过 hash 加密的 String1

# 总体思路

程序将 "0kk`d1a`55k222k2a776jbfgd`06cjjb" 和 SS 字符串进行一次异或,异或之后要将它与 hash 后的 string1 进行对比,在确定 hash 加密类型后我们就可以得到 String1 在 hash 加密之前的原码了,根据第二次 sub_401005 函数传进去的值可以知道,这次异或的 a3 就是 String1,所以我们再进行一次异或就可以得到输出的 flag 了

# 脚本

在第一次异或之后得到了 "c8837b23ff8aaa8a2dde915473ce0991",通过工具可以确定这是 MD5 加密类型,在网站上在线解密一下,得到 String1 为 "123321",后面在进行一次异或即可,脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
a = "0kk`d1a`55k222k2a776jbfgd`06cjjb"
b = 'SS'
a = list(a)
b = list(b)
for i in range(len(a)):
a[i] = chr(ord(b[i % 2]) ^ ord(a[i]))
print(a[i], end='')

print('')

c = [0x57, 0x5E, 0x52, 0x54, 0x49, 0x5F, 0x01, 0x6D, 0x69, 0x46,
0x02, 0x6E, 0x5F, 0x02, 0x6C, 0x57, 0x5B, 0x54, 0x4C]
d = '123321'
d = list(d)
for i in range(len(c)):
c[i] = chr(ord(d[i % 6]) ^ c[i])
print(c[i], end='')

最终结果

得到 flag {n0_Zu0_n0_die}

题目来源:BUUCTF 在线评测 (buuoj.cn)——findKey