津门杯RE_Inject_and_ClimbToTop

Inject

DebugView的版本是0.76,下载一个相同版本的做bindiff

发现sub_40F8B0相似度不是1

修改了0x487000开头的4个字节,然后跳过去

根据这个函数的字符串信息大概能确定这个函数跟dump功能有关,下个断点在这

选择完文件后确实是断在了上面的地方,为了方便调试直接从入口点跳过去

进入到eax地址处

在easyre节区里,跟踪下去

call之间跳过,到jmp里面去

发现这个,很像是主函数的入口

非常的main函数,猜测应该是解密了一个PE文件手动加载到内存里运行

重新调一遍上面的过程

alloc了一块内存,关注一下这块内存

多了个PE文件头,大小这样0x400

实际上是memcpy了一下,源地址处感觉是更完整的PE文件,dump下来,大小根据上下文能得到

1
2
3
4
5
6
7
auto fp, begin, size, end, dexbyte;
fp = fopen("dump1.exe", "wb");
begin = 0x02E70E48;
size = 0x3e1d8;
end = begin + size;
for ( dexbyte = begin; dexbyte < end; dexbyte ++ )
fputc(Byte(dexbyte), fp);

创建了一个msiexec.exe进程,然后注入

运行上面dump下来的文件,在ResumeThread之前附加到msiexec.exe上,在注入的代码下断点

然后恢复线程运行,调一下注入的代码,发现跟第一次的过程很相似

到上面的地方看ebp内存,一样的是PE文件,dump下来

1
2
3
4
5
6
7
auto fp, begin, size, end, dexbyte;
fp = fopen("dump2.exe", "wb");
begin = 0x120E48;
size = 0x28000;
end = begin + size;
for ( dexbyte = begin; dexbyte < end; dexbyte ++ )
fputc(Byte(dexbyte), fp);

直接就能分析主函数了

打开flag文件读取flag,然后进行一些处理再比较,逆向算法得到flag

第一部分会做字符变换,直接patch一下代码把a~z的变化跑出来之后查表

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
mp = [0x43, 0x23, 0x63, 0x13, 0x53, 0x33, 0x73, 0x0b, 0x4b, 0x2b, 0x6b, 0x1b, 0x5b, 0x3b, 0x7b, 0x07, 0x47, 0x27, 0x67, 0x17, 0x57, 0x37, 0x77, 0x0f, 0x4f, 0x2f, 0x6f, 0x1f, 0x5f, 0x3f, 0x7f]

ls = [0x5B, 0x67, 0x4B, 0x53, 0x0F, 0x53, 0x63]
flag1 = ""
for d in ls:
i = mp.index(d)
flag1 += chr(i+0x61)


# (flag2 * 0x89442161) >> 0x2c == 0x18E82
flag2 = (0x18E82 << 0x2c) // 0x89442161
flag2 += 1
flag2 = flag2.to_bytes(4, 'little').decode()


def enc():
# tmp = flag2 + 0x6FC4108B
tmp = (0x2e73692e + 0x6FC4108B) & 0xffffffff
flag3 = 0x34333231
flag4 = 0x38373635
edx = 0
for i in range(0x20):
edx = (edx + tmp) & 0xffffffff
print(hex(edx))
ecx = ((flag4 >> 5) + 0x69736d7b) & 0xffffffff # {msi
eax = ((flag4 << 4) + 0x67616c66) & 0xffffffff # flag
ecx = ecx ^ eax ^ (edx + flag4) & 0xffffffff

flag3 = (flag3 + ecx) & 0xffffffff
ecx = ((flag3 << 4) + 0x63657865) & 0xffffffff # exec
eax = ((flag3 >> 5) + 0x2e73692e) & 0xffffffff # .is.
ecx = ecx ^ eax ^ (edx + flag3) & 0xffffffff
flag4 = (flag4 + ecx) & 0xffffffff
print(hex(flag3), hex(flag4))

# enc()

tmp = 0x9e3779b9
edx = 0x6526b0d9
flag3 = 0x0C0CEE32
flag4 = 0xB7F3D728
for i in range(0x20):
edx = (edx - tmp) & 0xffffffff

ecx = ((flag3 << 4) + 0x63657865) & 0xffffffff # exec
eax = ((flag3 >> 5) + 0x2e73692e) & 0xffffffff # .is.
ecx = ecx ^ eax ^ (edx + flag3) & 0xffffffff
flag4 = (flag4 - ecx) & 0xffffffff

ecx = ((flag4 >> 5) + 0x69736d7b) & 0xffffffff # {msi
eax = ((flag4 << 4) + 0x67616c66) & 0xffffffff # flag
ecx = ecx ^ eax ^ (edx + flag4) & 0xffffffff
flag3 = (flag3 - ecx) & 0xffffffff

flag3 = flag3.to_bytes(4, 'little').decode()
flag4 = flag4.to_bytes(4, 'little').decode()

print("flag{"+flag1+flag2+flag3+flag4+"}")
# flag{msiexec.is.1nfected}

ClimbToTop

攻防世界上名字是babydsp,但应该不太对

给了dump文件和pdb文件,用windbg看了半天没看处理咋下一步,换ida

直接把可执行文件dump出来

加载一下pdb文件之后看主函数

这里的Detour把LockResourcehook了,但代码有问题,跑不了

把原本的Detour代码patch调,受用调用NewLockResource,需要修复一下pfnLockResource的地址,还有给.rsrc段加可写权限

LoadRemoteLibraryR函数看名字应该是加载DLL的

rdx指向了一个PE文件,r8是长度,dump下来

识别DllMain函数了,看了一下主要逻辑在main里面,这里生成了很多的随机数

写个简单的程序加载dump下来的dll,方便调试

主函数的开头跟结尾都很好分析

输入长度为0xc0的01串,转换为字节之后跟flag异或得到flag字符串,关键在中间的部分

主函数里一堆switch case

尝试了些控制流平坦化的脚本,没啥用,跳转是靠rcx

手动分析每一个case块

主要是根据v8进行跳转,然后做一系列的操作,case 0x50case 0x51配合可以循环操作

控制流序列如下,中间有一些地址用来是部分块用来寻址存取数据用的

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
control_flow = [
0x81, 0x34, 0x90, 0x56, 0xB5, 0x04, 0xFE, 0x7F,
0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x32,
0x01, 0x00, 0x00, 0x00, 0x33, 0xC2, 0x00, 0x00,
0x00, 0x50, 0x07, 0xC2, 0x00, 0x00, 0x00, 0x82,
0x83, 0x08, 0x90, 0x56, 0xB5, 0x04, 0xFE, 0x7F,
0x00, 0x00, 0x34, 0x90, 0x56, 0xB5, 0x04, 0xFE,
0x7F, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00,
0x40, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x51, 0x00]


# case 0x81
v12 = 0x29

# case 0x34
dword_7FFE04B55690 = v12

# case 0x31
v11 = 0

# case 0x32
v10 = 1

#case 0x33
v9 = 0xc2

# case 0x50
dword_7FFDEB55568C = v8

# case 0x7
v9 += 0xc2

# case 0x82
v12 = getchar()

# case 0x83
if (v12 == '1'):
v10 += 1
v12 = dword_7FFDEB5556A0[v9 + v10]

# case 0x8
v12 += dword_7FFE04B55690

# case 0x34
dword_7FFE04B55690 = v12

# case 0x5
v11 += 1

# case 0x40
if (v11 > 0xc0):
fl = 0
if (v11 == 0xc0):
fl = 2
if (v11 < 0xc0):
fl = 1

# case 0x51
if (fl == 1):
v8 = dword_7FFE04B5568C
else:
break

分析了一下,控制流在case 0x50case 0x51之间循环,每次取出一个输入序列

类似于dp算法题

1
2
3
4
5
1
12 5
2 4 7
7 9 8 10
...

第i层有i个数,输入为1时向右下走,输入0时向下走,对路径上的数字求和

这里的数字是在DllMain中rand生成的,实际上不随机,之间全dump下来,写代码尝试dp求最大值找路径

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
# 输入1往右走一格
# 从rand生成的数里取数字 求和
rand_ls = []
with open("rand_dump.bin", "rb") as f:
f.seek(0x30c)
for i in range(0xc2):
l = []
for j in range(0xc2):
data = f.read(4)
l.append(int.from_bytes(data, byteorder="little"))
rand_ls.append(l)


# 猜测需要找最大路径 dp
dp = [[0, [""]] for _ in range(0xc1)]
dp[0][0] = rand_ls[0][0]


for i in range(1, 0xc1):
for j in range(i, 0, -1):
# 当前位置的最大值可能为上一层之间向下走,也可能是左侧走过来
if (rand_ls[i-1][j] == rand_ls[i-1][j-1]):
dp[j][0] = dp[j][0] + rand_ls[i][j]
tmp = []
for s in dp[j-1][1]:
tmp.append(s + "1")
for s in dp[j][1]:
tmp.append(s + "0")
dp[j][1] = tmp
elif (rand_ls[i-1][j] > rand_ls[i-1][j-1]):
dp[j][0] = dp[j][0] + rand_ls[i][j]
tmp = []
for s in dp[j][1]:
tmp.append(s + "0")
dp[j][1] = tmp
else:
dp[j][0] = dp[j-1][0] + rand_ls[i][j]
tmp = []
for s in dp[j-1][1]:
tmp.append(s + "1")
dp[j][1] = tmp
dp[0][0] = dp[0][0] + rand_ls[i][0]
tmp = []
for s in dp[0][1]:
tmp.append(s + "0")
dp[0][1] = tmp


print(dp)
max = 0
path = ""
for i in range(0xc1):
if (dp[i][0] >= max):
max = dp[i][0]
path = dp[i][1]
print(max, path)

但是得到的最大值路径异或flag得不到正确的flag,题目也没有其他校验和提示,纯谜语,放弃思考


津门杯RE_Inject_and_ClimbToTop
https://blog.noxke.icu/2023/11/18/ctf_wp/津门杯RE-Inject-and-ClimbToTop/
作者
noxke
发布于
2023年11月18日
许可协议