reversing.kr daily

Easy Crack

这道题是最简单的一道题,运行程序,是一个windows窗体程序,peid查壳发现没有加壳。

image-20200713134419305

要求输入序列号然后点??验证,我们随意输入字符串,发现弹出incorrect password的提示。

拖进ida里面搜索字符串,f5大法,找到关键函数,如下:

image-20200713134600523

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int __cdecl sub_401080(HWND hDlg)
{
CHAR String; // [esp+4h] [ebp-64h]
char v3; // [esp+5h] [ebp-63h]
char v4; // [esp+6h] [ebp-62h]
char v5; // [esp+8h] [ebp-60h]
__int16 v6; // [esp+65h] [ebp-3h]
char v7; // [esp+67h] [ebp-1h]

String = 0;
memset(&v3, 0, 0x60u);
v6 = 0;
v7 = 0;
GetDlgItemTextA(hDlg, 1000, &String, 100);
if ( v3 != 97 || strncmp(&v4, a5y, 2u) || strcmp(&v5, aR3versing) || String != 69 )
return MessageBoxA(hDlg, aIncorrectPassw, Caption, 0x10u);
MessageBoxA(hDlg, Text, Caption, 0x40u);
return EndDialog(hDlg, 0);
}

显然,调用了函数GetDlgItemTextA拿到text控件内的值,然后做了一个简单的判断,如果不满足if内的条件,就输出incorrect。而if内的条件都是内存内的常量字符串或字符,直接将String+v3+v4+v5拼接即可得到flag。

Easy Keygen

这道题也比较容易,下载下来一个压缩包,包含一个exe和一个txt,txt内告诉了你序列号,让你找到序列号对应的用户名。

image-20200713141004707

运行程序,发现让分别输入序列号和用户名:

image-20200713141103496

查壳发现未加密,拖进ida搜索字符串Wrong,定位到_main函数下。

image-20200713141156483

完整代码如下(因为便于观看部分变量被我换了名儿):

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
signed int v3; // ebp
signed int i; // esi
int v6; // [esp+0h] [ebp-13Ch]
int v7; // [esp+0h] [ebp-13Ch]
char v8; // [esp+Ch] [ebp-130h]
char v9; // [esp+Dh] [ebp-12Fh]
char v10; // [esp+Eh] [ebp-12Eh]
char usernameorpass; // [esp+10h] [ebp-12Ch]
char v12; // [esp+11h] [ebp-12Bh]
__int16 v13; // [esp+71h] [ebp-CBh]
char v14; // [esp+73h] [ebp-C9h]
char v15; // [esp+74h] [ebp-C8h]
char v16; // [esp+75h] [ebp-C7h]
__int16 v17; // [esp+139h] [ebp-3h]
char v18; // [esp+13Bh] [ebp-1h]

usernameorpass = 0;
v15 = 0;
memset(&v12, 0, 0x60u);
v13 = 0;
v14 = 0;
memset(&v16, 0, 0xC4u);
v17 = 0;
v18 = 0;
v8 = 16;
v9 = 32;
v10 = 48;
print((int)aInputName, v6);
scanf(aS, &usernameorpass);
v3 = 0;
for ( i = 0; v3 < (signed int)strlen(&usernameorpass); ++i )
{
if ( i >= 3 )
i = 0;
sprintf(&v15, aS02x, &v15, *(&usernameorpass + v3++) ^ *(&v8 + i), v7);// %s%02X
}
memset(&usernameorpass, 0, 0x64u);
print((int)aInputSerial, v7);
scanf(aS, &usernameorpass);
if ( !strcmp(&usernameorpass, &v15) )
print((int)aCorrect, *(int *)&v8);
else
print((int)aWrong, *(int *)&v8);
return 0;
}

其中关键代码如下:

1
2
3
4
5
6
for ( i = 0; v3 < (signed int)strlen(&usernameorpass); ++i )
{
if ( i >= 3 )
i = 0;
sprintf(&v15, aS02x, &v15, *(&usernameorpass + v3++) ^ *(&v8 + i), v7);// %s%02X
}

可以看出,加密的流程为遍历username的每一位,将其每一位与v8、v9、v10(16、32、48)异或(与谁异或取决于循环次数模3的值)。

编写exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
seri = "5B134977135E7D13"
a = 16
v3 = 0
username = ""
for i in range(int(len(seri)/2)):
if v3 >= 3:
v3 = 0
encstr = seri[2*i:2*i+2]
enc = int(encstr,16)
for i2 in range(33,126):
if i2 ^ (a*(v3+1)) == enc:
username += chr(i2)
break
v3+=1
print(username)

image-20200713141606777

成功得到结果,验证之:

image-20200713141638709

0%