WriteUp:QCTF Xman-babymips

题目描述

QCTF 的 Xman-babymips 题目。

题目本体见这里

题目最大的特点就是 Mips 平台的 ELF,所以阅读和动态调试比较麻烦。

不过好在以前蹭隔壁计算机系课的时候学过一点 Mips,读起来也不算很吃力。

第一段加密

首先快速定位到输入的位置,很容易发现 flag 为 32 位并且在输入后进入了下面第一段加密

这段逻辑的伪代码为

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
var_30 = 0
v0 = var_30
if v0 < 0x20
v0 = 1
else
v0 = 0
while v0 != 0
v0 = var_30
v1 = &var_30
v0 += v1
v1 = (byte)m[v0 + 4]
v0 = var_30
v0 &= 0xff
a0 = 0x20
v0 = a0 - v0
v0 &= 0xff
v0 <<= 24
v0 >>= 24
v0 = v1 ^ v0 // 这里有个异或运算
v1 = v0 << 24
v1 >>= 24
v0 = var_30
a0 = &var_30
v0 = a0 + v0
(byte)m[v0 + 4] = v1
v0 = var_30
v0 += 1
var_30 = v0

v0 = var_30
if v0 < 0x20
v0 = 1
else
v0 = 0

v0 = 0x41 << 16
v1 = "Q|j{g"
v0 = &var_2C
a2 = 5
a1 = v1
a0 = v0
strncmp(&var_2C, "Q|j{g", 5) // n = 5

主要有两个要注意的地方,一是题目对输入的字符串进行了一遍异或运算,二是这里只比较了前 5 个字符。

第二段加密

第一段加密过了之后就是第二段加密了

这段加密稍微复杂一点,不过只要稍微耐心一点还是很简单的。

这段加密逻辑的伪代码为

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
arg_0 = var_2C
var_10 = 5

while strlen(arg_0) > var_10

v0 = var_10
v0 &= 1
if v0 = 0
v0 = (byte)m[arg_0 + var_10]
v0 <<= 2
a0 = v0 << 24
a0 >>= 24
v0 = (byte)m[arg_0 + var_10]
v0 >>= 6
v1 = v0 << 24
v1 >>= 24
v0 = var_10
a1 = arg_0
v0 = a1 + v1
v1 = a0 | v1 // a0 = v0 << 2 v1 = v0 >> 6
v1 <<= 24
v1 >>= 24
m[v0] = (byte)v1

else
v0 = (byte)m[arg_0 + var_10]
v0 >>= 2
a0 = v0 << 24
a0 >>= 24
v0 = (byte)m[arg_0 + var_10]
v0 <<= 6
v1 = v0 << 24
v1 >>= 24
v0 = var_10
a1 = arg_0
v0 = a1 + v0
v1 = a0 | v1 // a0 = v0 >> 2 v1 = v0 << 6
v1 <<= 24
v1 >>= 24
m[v0] = (byte)v1

v0 = var_10
v0 += 1
var_10 = v0

v0 = arg_0
v1 = v0 + 5
v0 =
strncmp(v1, 0x410D04, 0x1B) // 0x410D04 是密文的位置

假设原字节为 87654321( 1-8 表示第 1-8 个 bit),在 v0 为奇数的时候加密后为 65432187, 在 v0 为偶数的时候加密后为 21345678。

最后比较的是一段密文,这个过程都是可逆的,我们只要反推出来输入就可以了。

爆破脚本

所以最后脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
enc = b'\x52\xFD\x16\xA4\x89\xBD\x92\x80\x13\x41\x54\xA0\x8D\x45\x18\x81\xDE\xFC\x95\xF0\x16\x79\x1A\x15\x5B\x75\x1F'
head = b'Q|j{g'
f = ''

for i in range(5):
f += chr(head[i] ^ 0x20 - i)

for i in range(27):
if i % 2 == 1:
f += chr((((enc[i] & 0b11111100) >> 2 ) | ((enc[i] & 0b00000011) << 6 )) ^ 0x20 - 5 - i)
else:
f += chr((((enc[i] & 0b00111111) << 2 ) | ((enc[i] & 0b11000000) >> 6 )) ^ 0x20 - 5 - i)

print(f)

后记

mips 还是挺新颖的,本身逆向难度不大。

参考资料里给出了一篇入门文章和 mips 指令集,赞美 RISC !

参考资料

MIPS Instruction Reference
MIPS Architecture and Assembly Language Overview