BUUCTF Reverse 1-20

[toc]

1. easyre

64位程序,没有加壳

使用64位ida,shift+f12检索字符串,得flag

image-20221118221619560

2. reverse1

64位程序

image-20221118223514705

丢入ida,shift+f12查看字符串

image-20221118224543123

双击,发现被sub_1400118C0调用

image-20221118224558299

str2为{hello_world}

image-20221118224626103

转为伪代码,判断输入的字符串和str2相等即可

image-20221118224708634

str2是对{hello_world}进行字符串替换得到的,o替换为0

最后的flag:{hell0_w0rld}

3. reverse2

image-20221118225059918

ida64打开,check+f12查看字符串,跟进right flag

image-20221118225601389

main函数调用,跟进

image-20221118225631294

和上一个题目差不多,查看s2的生成过程,将flag中的i和r替换为1

1
2
3
4
5
for ( i = 0; i <= strlen(&flag); ++i )
{
if ( *(&flag + i) == 'i' || *(&flag + i) == 'r' )
*(&flag + i) = '1';
}

flag为{hacking_for_fun}

image-20221118225735932

那么最后的flag为flag{hack1ng_fo1_fun}

4. 内涵的软件

32位

image-20221118225857209

ida32打开,将DBAPP修改为flag提交

image-20221118230121326

5. 新年快乐

32位,UPX加壳

image-20221118230249938

手动脱壳

查看xdbg的断点

image-20221119102612074

根据ESP定律找OEP(Original Entry Point),程序的入口点

F9运行到这里,往上可以看到一个popad的指令,该指令将寄存器的值进行还原。找到下面一个jmp指令所要跳转的位置,就是程序的OEP

image-20221119113042857

F8

image-20221119113216349

dump下来,使用Scylla插件

image-20221119113404315

第一步,生成dump.exe

image-20221119113437195

第二步,进行修复

Misc–>options

image-20221119113601965

然后点击IAT Autosearch,点击Get Imports,而后fix dump

image-20221119113659179

生成dump_SCY.exe

image-20221119113727179

丢入ida,修复之后的文件

image-20221119112329498

进行一个字符串比较,最后的flag为flag{HappyNewYear!}

6. xor

image-20221119163159094

1
2
3
4
5
6
7
8
9
10
11
12
13
# 将字符串分割为单个字符
string = ['f',0x0A,'k',0x0C,'w','&','O','.','@',0x11,'x',0x0D,'Z',';','U',0x11,'p',0x19,'F',0x1F,'v','"','M','#','D',0x0E,'g',0x6,'h',0x0F,'G','2','O',0x0]

flag = 'f'
# 转字符串
for i in (range(len(string))):
if(type(string[i]) == int):
string[i] = chr(string[i])
print(string)
# 异或
for i in range(1,len(string)):
flag += chr(ord(string[i])^ord(string[i-1]))
print(flag)

image-20221119163056735

7. helloword

apk文件,使用jadx打开

image-20221119163841163

或者丢入ida,使用APK Android打开

image-20221119163939686

shift+f12查看字符串

image-20221119164048373

8. reverse3

32位

image-20221119164218026

main函数,对输入的字符串调用sub_4110BE进行处理,然后进行移位处理

image-20221119172736607

跟进sub_4110BE,跟进sub_411AB0

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
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 *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
v5 = v4 + 1;
*((_BYTE *)v12 + v5) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | (16 * (byte_41A144[0] & 3))];
*((_BYTE *)v12 + ++v5) = aAbcdefghijklmn[64];
*((_BYTE *)v12 + ++v5) = aAbcdefghijklmn[64];
v4 = v5 + 1;
break;
case 2:
*((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
v6 = v4 + 1;
*((_BYTE *)v12 + v6) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | (16 * (byte_41A144[0] & 3))];
*((_BYTE *)v12 + ++v6) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | (4 * (byte_41A144[1] & 0xF))];
*((_BYTE *)v12 + ++v6) = aAbcdefghijklmn[64];
v4 = v6 + 1;
break;
case 3:
*((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
v7 = v4 + 1;
*((_BYTE *)v12 + v7) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | (16 * (byte_41A144[0] & 3))];
*((_BYTE *)v12 + ++v7) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | (4 * (byte_41A144[1] & 0xF))];
*((_BYTE *)v12 + ++v7) = aAbcdefghijklmn[byte_41A144[2] & 0x3F];
v4 = v7 + 1;
break;
}
}
*((_BYTE *)v12 + v4) = 0;
return v12;

image-20221119172905225

base64编码,3位变4位

所以先逆向移位,然后base64解码

1
2
3
4
5
6
7
8
9
import base64

str2 = 'e3nifIH9b_C@n@dH'
flag = ''
for i in range(len(str2)):
# print(i)
flag += chr(ord(str2[i])-i)
print(flag)
print(base64.b64decode(flag))

image-20221119173030796

9. 不一样的flag

32位

image-20221119173207289

shift+f12查看字符串

image-20221121193738324

主逻辑在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
 __main();
v3[26] = 0;
*(_WORD *)&v3[27] = 0;
v4 = 0;
strcpy(v3, "*11110100001010000101111#");
while ( 1 )
{
puts("you can choose one action to execute");
puts("1 up");
puts("2 down");
puts("3 left");
printf("4 right\n:");
scanf("%d", &v5);
if ( v5 == 2 )
{
++*(_DWORD *)&v3[25];
}
else if ( v5 > 2 )
{
if ( v5 == 3 )
{
--v4;
}
else
{
if ( v5 != 4 )
LABEL_13:
exit(1);
++v4;
}
}
else
{
if ( v5 != 1 )
goto LABEL_13;
--*(_DWORD *)&v3[25];
}
for ( i = 0; i <= 1; ++i )
{
if ( *(int *)&v3[4 * i + 25] < 0 || *(int *)&v3[4 * i + 25] > 4 )
exit(1);
}
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '1' )
exit(1);
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '#' )
{
puts("\nok, the order you enter is the flag!");
exit(0);
}
}

上面的*11110100001010000101111#是迷宫的地图

对v4的操作相当于迷宫中的左移和右移

image-20221121193958206

而对(_DWORD *)&v3[25]的操作相当于上移和下移,而*5表示是5行

image-20221121194022644

迷宫地图为

1
2
3
4
5
*1111
01000
01010
00010
1111#

走到#成功,这个过程中不能走到1

image-20221121193809020

所以应该是下下下右右上上右右下下下,也就是222441144222

10. SimpleRev

64位

小端序和大端序问题

image-20221123202910817

可以看到这里的两个十六进制是大端序,但是数据在内存中都是小端序,所以要将其,反转一下。一般在CPU,x86都是小端序,但是IDA将之转换为了大端序

主要逻辑

image-20221123203009784

从65到91爆破一下

exp

1
2
3
4
5
6
7
8
9
10
11
12
text = 'killshadow'
key = 'ADSFKNDCLS'
print(key.lower())
flag = ''
for i in range(0,10):
for j in range(65,91):

if((((j - 39 - ord(key.lower()[i]) + 97)%26)+97) == ord(text[i])):
print(chr(j))
flag += chr(j)
break
print(flag)