题目描述
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 !
参考资料