2020-10-09

逆向练习#5

[BUUCTF-Reverse3]

1.

根据之前的经验,我觉得放进exeinfo、然后扔进ida找关键函数再f5的操作可以省略不写了。(成长了?其实是懒狗)

2.

亲爱的伪代码在这里

image-20201009183056688

直接看得出“right flag”这里,肯定是让DestStr2进行比较。

Dest是由输入的Str被函数sub_4110BE加密处理后得出的。(其实这里我一头雾水,是因为我不知道strcpy函数是复制字符串到dest)

str2是e3nifIH9b_C@n@dH

然而还有一个步骤

image-20201009191230322

意为让Dest每一位字符串都加上对应位置数字ascii码

所以解密之前每一位还得先减去对应位置的数字。

3.

那么跟进sub_4110BE

image-20201009184705272

再跟进

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
void *__cdecl sub_411AB0(char *a1, unsigned int a2, int *a3)
{
int v4; // STE0_4
int v5; // STE0_4
int v6; // STE0_4
int v7; // [esp+D4h] [ebp-38h]
signed int i; // [esp+E0h] [ebp-2Ch]
unsigned int v9; // [esp+ECh] [ebp-20h]
int v10; // [esp+ECh] [ebp-20h]
signed int v11; // [esp+ECh] [ebp-20h]
void *Dst; // [esp+F8h] [ebp-14h]
char *v13; // [esp+104h] [ebp-8h]

if ( !a1 || !a2 )
return 0;
v9 = a2 / 3;
if ( (signed int)(a2 / 3) % 3 )
++v9;
v10 = 4 * v9;
*a3 = v10;
Dst = malloc(v10 + 1);
if ( !Dst )
return 0;
j_memset(Dst, 0, v10 + 1);
v13 = a1;
v11 = a2;
v7 = 0;
while ( v11 > 0 )
{
byte_41A144[2] = 0;
byte_41A144[1] = 0;
byte_41A144[0] = 0;
for ( i = 0; i < 3 && v11 >= 1; ++i )
{
byte_41A144[i] = *v13;
--v11;
++v13;
}
if ( !i )
break;
switch ( i )
{
case 1:
*((_BYTE *)Dst + v7) = aAbcdefghijklmn[(signed int)(unsigned __int8)byte_41A144[0] >> 2];
v4 = v7 + 1;
*((_BYTE *)Dst + v4++) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | 16 * (byte_41A144[0] & 3)];
*((_BYTE *)Dst + v4++) = aAbcdefghijklmn[64];
*((_BYTE *)Dst + v4) = aAbcdefghijklmn[64];
v7 = v4 + 1;
break;
case 2:
*((_BYTE *)Dst + v7) = aAbcdefghijklmn[(signed int)(unsigned __int8)byte_41A144[0] >> 2];
v5 = v7 + 1;
*((_BYTE *)Dst + v5++) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | 16 * (byte_41A144[0] & 3)];
*((_BYTE *)Dst + v5++) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | 4 * (byte_41A144[1] & 0xF)];
*((_BYTE *)Dst + v5) = aAbcdefghijklmn[64];
v7 = v5 + 1;
break;
case 3:
*((_BYTE *)Dst + v7) = aAbcdefghijklmn[(signed int)(unsigned __int8)byte_41A144[0] >> 2];
v6 = v7 + 1;
*((_BYTE *)Dst + v6++) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | 16 * (byte_41A144[0] & 3)];
*((_BYTE *)Dst + v6++) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | 4 * (byte_41A144[1] & 0xF)];
*((_BYTE *)Dst + v6) = aAbcdefghijklmn[byte_41A144[2] & 0x3F];
v7 = v6 + 1;
break;
}
}
*((_BYTE *)Dst + v7) = 0;
return Dst;
}

这家伙好厉害!我看不懂

于是百度,说是base64加密。这代码属实触及我的知识盲区,也许以后可以靠记忆?长得像这样的就拿base64套(雾)

其实代码里出现了好多次aAbcdefghijklmn,跟进去看看。

image-20201009185340604

而这就是base64加密的关键

它是用64个可打印字符表示二进制所有数据方法。由于2的6次方等于64,所以可以用每6个位元为一个单元,对应某个可打印字符。我们知道三个字节有24个位元,就可以刚好对应于4个Base64单元,即3个字节需要用4个Base64的可打印字符来表示。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9 ,这样共有62个字符,此外两个可打印符号在不同的系统中一般有所不同。但是,我们经常所说的Base64另外2个字符是:“+/”。

(我大致能理解,算课外拓展了,记得以前学过一遍。那个等于号是作后缀)

Python有base64加密解密的库,于是写脚本。

1
2
3
4
5
6
7
8
import  base64
str = 'e3nifIH9b_C@n@dH'
flag=''
for i in range(len(str)):
x = chr(ord(str[i]) - i)
flag+=x
flag = base64.b64decode(flag)
print(flag)

先减去对应位置的数字,组成新的字符串,再对他进行base64解密。

得出flag{i_l0ve_you}

总结:以前看伪代码的时候感觉眼花缭乱的,比如我刚开始在纠结那个for循环,以及下面lowword等东西是啥。其实应该赶紧抓住重点,这大概要我不断写题积累吧。也许掌握C++可能会更好?