0%

复旦白泽暑期课程逆向入门课wp

re2

首先用ida64打开re2文件,定位到main函数

f5反汇编得到如下代码

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
__int64 __fastcall main(int a1, char **a2, char **a3)
{
unsigned int v3; // eax
__int64 result; // rax
unsigned int v5; // [rsp+4h] [rbp-1Ch]
unsigned int v6; // [rsp+8h] [rbp-18h]
unsigned int v7; // [rsp+Ch] [rbp-14h]
unsigned int v8; // [rsp+10h] [rbp-10h]
unsigned int v9; // [rsp+14h] [rbp-Ch]
int v10; // [rsp+18h] [rbp-8h]

puts("hi all ----------------------");
puts("Welcome to dice game!");
puts("You have to roll 5 dices and get 6, 6, 6, 6, 6 in order.");
puts("Press enter to roll.");
getchar();
v3 = time(0LL);
srand(v3);
v10 = time(0LL);
v9 = rand() % 6 + 1;
v8 = rand() % 6 + 1;
v7 = rand() % 6 + 1;
v6 = rand() % 6 + 1;
v5 = rand() % 6 + 1;
printf("You rolled %d, %d, %d, %d, %d.\n", v9, v8, v7, v6, v5);
if ( v9 != 6 )
goto LABEL_15;
if ( time(0LL) - v10 > 2 )
goto LABEL_13;
if ( v8 != 6 )
goto LABEL_15;
if ( time(0LL) - v10 > 2 )
goto LABEL_13;
if ( v7 != 6 )
goto LABEL_15;
if ( time(0LL) - v10 > 2 )
goto LABEL_13;
if ( v6 != 6 )
goto LABEL_15;
if ( time(0LL) - v10 > 2 )
goto LABEL_13;
if ( v5 == 6 )
{
if ( time(0LL) - v10 > 2 )
{
LABEL_13:
puts("No cheat!");
return 0xFFFFFFFFLL;
}
puts("You rolled as I said! I'll give you the flag.");
sub_4006B6();
result = 0LL;
}
else
{
LABEL_15:
puts("You DID NOT roll as I said!");
puts("Bye bye~");
result = 0xFFFFFFFFLL;
}
return result;
}

分析得知,这是一个摇骰子的游戏,v5到v9是1到6的时间种子随机数,要求v5到v9都是6,且time(0LL) - v10 > 2两个条件都满足才能执行 sub_4006B6()函数,输出正确的flag,而v10 = time(0LL),所以第二个条件无法满足,想到用patch的方法修改判断条件

查看对应汇编代码我们能找到如下指令

类似的条件共有5组,第一个条件对应摇出数字6,第二个条件对应time(0LL) - v10 > 2,现更改汇编,使第一类跳转不执行,第二类跳转均执行,使用keypatcher插件,将第一个条件中的6改为0,由于随机数的范围是1到6所以一定与0不等,再将jnz改为jz,则跳转一定不执行,将第二个条件中的jle改为jmp,则跳转一定执行,如下图所示

将5组条件均进行相同的修改,然后保存

将保存后的re2文件放在linux下执行,运行得到flag

1
flag{4b34098e229eab72739923a0b40b3be6}

re3

首先用ida64打开re3文件,定位到main函数,f5得到如下伪代码

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
![re3_address](%E5%A4%8D%E6%97%A6%E7%99%BD%E6%B3%BD%E6%9A%91%E6%9C%9F%E8%AF%BE%E7%A8%8B%E9%80%86%E5%90%91%E5%85%A5%E9%97%A8%E8%AF%BEwp/re3_address.png)__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 v3; // rbx
int v4; // eax
char v5; // bp
char v6; // al
const char *v7; // rdi
unsigned int v9; // [rsp+0h] [rbp-28h] BYREF
int v10[9]; // [rsp+4h] [rbp-24h] BYREF

v10[0] = 0;
v9 = 0;
puts("Give flag:");
scanf("%s", &s1);
if ( strlen(&s1) != 26 || strncmp(&s1, "flag{", 5uLL) || *(&byte_6010BF + 26) != 125 )
{
LABEL_22:
puts("Wrong flag!");
exit(-1);
}
v3 = 5LL;
if ( strlen(&s1) - 1 > 5 )
{
while ( 1 )
{
v4 = *(&s1 + v3);
v5 = 0;
if ( v4 > 67 )
{
if ( (unsigned __int8)v4 == 68 )
{
v6 = sub_400650(v10);
goto LABEL_14;
}
if ( (unsigned __int8)v4 == 69 )
{
v6 = sub_400660(v10);
goto LABEL_14;
}
}
else
{
if ( (unsigned __int8)v4 == 65 )
{
v6 = sub_400670(&v9);
goto LABEL_14;
}
if ( (unsigned __int8)v4 == 66 )
{
v6 = sub_400680(&v9);
LABEL_14:
v5 = v6;
goto LABEL_15;
}
}
LABEL_15:
if ( !(unsigned __int8)sub_400690(asc_601060, (unsigned int)v10[0], v9) )
goto LABEL_22;
if ( ++v3 >= strlen(&s1) - 1 )
{
if ( v5 )
break;
LABEL_20:
v7 = "Wrong flag!";
goto LABEL_21;
}
}
}
if ( asc_601060[8 * v9 + v10[0]] != 42 )
goto LABEL_20;
v7 = "Congratulations!";
LABEL_21:
puts(v7);
return 0LL;
}

程序大体逻辑是输出一个Give flag:,然后将我们输入的字符串长度为26,存入s1数组,根据判断条件知s1数组的前五位为flag{先随意试一下

双击byte_6010BF,发现它是s1的前一位,则*(&byte_6010BF + 26)对应s1的最后一位,利用ida可将125转换为对应的字符”}”

那我们的任务就是判断剩下的20个字符,它们存储在v4数组中,利用转换字符的功能,可以将68、69、65、66依次转换为D、E、A、B,继续分析,我们注意到判断flag正确与否的关键在这个地方

双击asc_601060发现它是这样的字符串

典型的迷宫问题,42对应”*”,这个字符即为出口,根据asc_601060[8 * v9 + v10[0]],判断出迷宫的行号对应v9,列号对应v10[0],且每行有8列,先把迷宫整理一下,为便于观察用”#”代替” “

将v9、v10[0]改名为row、column,根据函数判断出

再根据第57行的sub_400690函数判断出空格和*可走

则得出flag为

1
flag{EBEEBBDBBBEEEEAADAAE}

验证

re1思考题

由于scanf %s有可能造成溢出,且程序中没有对输入字符串的长度进行检验,所以在正确的flag后,加上任意的字符也会puts(“you are right!”)