实验内容
lab1包含4个题目,需要对4个程序进行逆向。逆向结果为一个flag开头的可见字符串,正则形式为:flag{[0-9a-zA-Z]+}。
● 其中lab1-1是简单的逆向入门用于熟悉软件和环境,lab1-2和lab1-3涉及到数学计算,需要通过基本的
数学运算性质进行逆计算得出flag,lab1-4需要对原有的二进制进行一些修改,之后才能进行正常的输
入输出。
● 每个程序在输入正确的flag后会显示good,如果flag不正确将会输出error flag。
样例
● $ ./lab1-1
● 123
● error flag
● $ ./lab1-1
● flag{XXXXXXXXXXXXX}
● good!
● $
实验文件链接:https://pan.baidu.com/s/1sMm8KQTKll2cRW-ZN0u-sw
提取码:xlxc
实验步骤
1、lab1-1
阅读反汇编后的汇编码,从下图可以看出,程序将字符串存放于栈中,根据输出结果,考虑ASCII码转换,66h是f的十六进制,参照下图,最先被移进栈的八个字符,它们的十六进制为6C65577B67616C66h可以看到66是所有字符中地址最低的,它也是低字节,所以这是低地址放低字节的情况,因而运行程序的机器是小端模式。该题考察的是大端模式与小端模式。我们将整个字符串都变为大端模式可得如下字符串:666c61677b57656c636f6d655f74305f73656375726974795f6330757273657d
参照ASCII码转换表可得出题目答案:flag{Welcome_t0_security_c0urse}
执行程序,验证答案,发现答案正确显示good!
2、lab1-2
main函数分配到了90h字节的空间
从rbp+var_80开始的内存单元,用0填充96个字节(0Ch=12 12*8=96)的存储空间
注:rep是用来循环的,它会根据ecx寄存器的值,循环执行rep后面的指令,stosq指令会用rax寄存器的值填充rdi寄存器所指向的内存单元,并且每次填充4个字,即8个字节。
然后将程序中23个数据存入从rbp+var_80开始的内存空间,每个数据占用4个字节。由上图可知,最后一个数据存放在rbp+var_28的位置。
存完数据,程序读取用户输入(即所输入flag),将其存放在从rbp+var_20开始的位置,读取长度不超过24。
rbp+var_84这个存储单元的值相当于一个计数器,字符的比较是逐个进行的,rbp+var_84开始时的值是0,每比较一个字符之后,rbp+var_84的值就加一,当它的值大于22时,判断出比较成功。
该程序运算逻辑:每一次都是先取用户输入字符,然后让他与计数器的值进行异或,最后比较异或结果与程序原有值是否相等。程序中预先设定了23个值,所以用户的输入也应该是23个,并且与程序的设定值之间有一一对应的关系,即用户输入的第一个字符与rbp+var_80这个存储单元的值相对应,输入的第二个字符与rbp+var_7c相对应,之后的字符以此类推。
程序原有十六进制字符串为
666D63647F7D6975576079547E68786A62627B7178706B
由公式 (ab)a=b 可推出输入值
66h=102D -> 01100110 XOR 00000000 =102D 即为f
6Dh=109D -> 01101101 XOR 00000001 =108D 即为l
…
依此类推
得到结果 flag{xor_is_reversible}
验证一下,答案正确
3、lab1-3
该题是将将用户的输入和程序中预先设定的值进行简单的数学运算之后,再比较两者是否相等。
用户的输入存放在从rbp+var_30开始的位置,输入的字符个数最多不超过29个。
第一个输入与66h进行比较,若不相等,则判断结束,若相等,则将第一个输入和第二个输入相加,之后与D2h比较是否相等,若相等,则再将第二个输入与第三个输入相加,与程序中预先设定的值进行比较,之后以此类推。要注意的是,rbp+var_2A和rbp+var_29这两个存储单元的值相加再与E6h比较这一操作进行了两次
预先设定的值十六进制依此为
66 D2 CD C8 E2 E0 D6 E6 D6 D5 DD D8 DD EB
我们可以推出第一个输入为f
D2h-66h=6Ch 即为 l
CDh-6Ch=61h 即为 a
C8h-61h=67h 即为g
E2h-67h=7Bh 即为{
E0h-7Bh=68h 即为e
D6h-68h=71h 即为q
E6h-71h=75h 即为u
D6h-75h=61h 即为a
D5h-61h=74h 即为t
DDh-74h=69h 即为i
D8h-69h=6Fh 即为o
DDh-6Fh=6Eh 即为n
EBh-6Eh=7Dh 即为}
因此答案为 flag{equation}
验证一下,答案正确
4、lab1-4
阅读源码可以发现在main proc near这个函数声明之后就是retn语句,这样会使得main什么也没做就结束
发现retn的下一条指令是mov rbp rsp,这是函数调用时才会有的指令,猜测push rbp指令被改成了retn指令,将其修改回去
一开始我想采用Assemble直接修改但是显示Invalid operand,无法修改
于是换一种思路,借助了lab1-3中push rbp 的十六进制如下图,进行复制
lab1-4中选中retn使用Pathced bytes进行修改,修改成功
程序中预先给定的数据,每个占一个字节,从rbp+var_20开始连续存放,最后一个数据放在rbp+var_10+4处。rbp+var_24充当计数器使用,初始时的值0,每成功比较一个字节之后,它的值就加一,当它大于20时,整个字符串比较结束,输出输入正确的提示。用户的输入数据存放在rdi寄存器指向的存储单元,运算部分的公式是:
输入的字节 xor 计数器的值 + 计数器的值 = 程序预先给定的值
我们现在需要求出输入的字节是什么,因此根据根据异或运算的性质,有如下公式:
输入的字节 = (程序预先给定的值 - 计数器的值)xor 计数器的值
答案:flag{patch_your_file}