[ctfs.me] reverse me 0x01

第一次做正经的CTF练习,花了点时间做这道逆向,记录一下。
下载下来是一个压缩包,解压有两个文件: reverseme-x86和reverseme-x86_64,为了省事就做reverseme-x86了。
file看了一眼

reverseme-x86: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=22cc5cd877bf6c08537feefce6e9fbdf7b16c224, stripped

运行一下试试,不给参数的话要求你给参数作为flag,给参数的话报一个印尼语“答案是错的”。用IDA打开寻找相关字符串,没有。嗯,看来不像reverseme 0x02那么简单了(那题直接读源码就好)。
仔细看了一下main函数,发现在函数中有几个疑似对字符串做了解密的地方。


特别是LABEL7的标签,明显是报错的语句。而asc_804A055的长度恰好与印尼语的报错语句"Keynya salah!"长度相同(如果考虑'\0'和'\n'的话)。


假如猜测是真的,那么14次循环的比较函数中,必然就是最后做flag比对的地方了。
但是如何输入明文flag,使得密文与hardcode的数据相同?更何况此时还不知道hardcode的数据到底是啥。想来想去还是开动态调试,看看寄存器吧。
按照 这篇文章 搭建基于Windows IDA的动态调试(原谅我实在对GDB不熟悉)。和Android的IDA动态调试区别不大,基本就是在Linux下开一个钩子程序打开监听,然后再win的IDA配置debugger,使得其能钩住Linux监听即可。debuggerp配置如下:

Application选择Linux端路径或本地均可,Parameters填argv[1]给的参数,Hostname和Password不知道为啥要,就按Linux用户信息填好了。

配置好之后开始动态调试。先把断点设在14次循环的比较函数,发现比较的目标位于[ebp-8h]或[esp+48h]再减去55(0x37)的位置。

本例中,EBP=0xFFAD2748,ESP=0xFFAD2710,所以v25的位置是0xFFAD2709。


栈窗口显示,按小端表示的话,实际的正确密文flag应该是[0x6f,0xfa,0x29,0xcd,0x45,0xf2,0xdd,0x85,0xe0,0x2c,0x5a,0x1c,0x43,0x6e]。现在问题来了,如何计算明文的输入,使得它的输出恰好是这个数组的值。
花了很多时间去尝试和思考,得到的一个可能并非最优的方法如下。
开源码检查decode_chars函数,发现于明文输入相关的计算只有一个异或。也就是说每一个明文输入(v16)的字节异或上一个数字,就是密文(好在不是充分混杂的对称加密)。


所以只要得到异或的那len长度(即14位),图中标号v19数组,即可反向获取明文。由于可以控制输入,所以把输入全部写成0,即./reverseme-x86 0..*14,再观察输出内容的栈,就知道v19中的值了。
再次在循环14次处设断点。


双击v9,观察内存的值。


得到理论上的v19用于加密的数。与之前获得的加密flag异或,获得数组:

buf = [0x39,0xA6,0x78,0x9A,0x0E,0xA3,0x8F,0xC0,0xB5,0x70,0x03,0x58,0x12,0x23]
target = [0x6f,0xfa,0x29,0xcd,0x45,0xf2,0xdd,0x85,0xe0,0x2c,0x5a,0x1c,0x43,0x6e]

for i in range(0x0e):
    k = buf[i] ^ target[i]
    print(hex(k))
    print(chr(k))

结果:

0x56
V
0x5c
\
0x51
Q
0x57
W
0x4b
K
0x51
Q
0x52
R
0x45
E
0x55
U
0x5c
\
0x59
Y
0x44
D
0x51
Q
0x4d
M

已经都是可打印字符啦,把明文字符输进去测试,发现,

不对!!!

回头再瞄了一眼加密后的输入,发现与密文每个字符都差了那么一点。难道还有另外的坑?!
仔细想了想,觉得应该是输入字符的'0'被解码成0x30做的异或,使得预估出现了偏差,修改程序,多异或一个0x30即可。

buf = [0x39,0xA6,0x78,0x9A,0x0E,0xA3,0x8F,0xC0,0xB5,0x70,0x03,0x58,0x12,0x23]
target = [0x6f,0xfa,0x29,0xcd,0x45,0xf2,0xdd,0x85,0xe0,0x2c,0x5a,0x1c,0x43,0x6e]

for i in range(0x0e):
    k = buf[i] ^ target[i] ^ 0x30
    print(hex(k))
    print(chr(k))

最终flag:

Comments
Write a Comment