这个实验要很小心很小心的做,因为会炸。
基础知识
- GDB 调试基础 GDB 常用命令
- Assembly Language 汇编语言 基本命令
0x01 strcmp()
仔细看这段汇编代码,里面首先从0x804a6b8这个位置获取的变量移到$ebp-0xc位置中,然后调用strings_not_equal() 函数,传入我们的输入$ebp+0x8 这个字符串,以及刚刚获取到的变量。结果存在$eax寄存器中,然后使用test指令对于$eax中保存的结果进行处理。test指令对于两个操作数进行and操作,并根据结果对于ZF进行标记。如果and操作为零,则ZF标志为1。而je指令在ZF被置位的时候跳转。因此我们需要上一个 调用函数的返回值为0。
我们再研究一下这个函数strings_not_equal() 这个函数。
对于传入的两个字符串变量首先进行计算长度(调用string_length())函数,然后将数据存储在的eax和ebx两个寄存器中的数据,进行比较。如果长度相等,则继续调用后面的函数进行比较。否则,返回1.C语言代码如下。 比较两个字符串,相同返回0,不同返回1。
因此我们需要输入和题目字符串中相同的字符串量。"What were the last four digits of your childhood telephone number?"
0x02 funcall
注意加断点!加断点!加断点!不要让程序去一个你不知道的地方。首先看汇编。
程序传入了三个字符串,然后调用了一个叫func_game()的函数。在func_game()函数中,传入了4个参数,分别是(input_string, “rock”,”paper”,”scissors”) 分别存储在$ebp+0x8, $ebp+0xc,$ebp+0x10, $ebp+0x14位置。然后将其传入本地变量中进行保存,同时调用string_not_equal()函数进行处理,如果出现不同的情况,eax返回为1,将不进行跳转,对于$ebp-0xc中的变量进行加一操作。最后,从第72行开始,判断$ebp-0xc中变量中的值,如果不是2的话,则bomb,否则输出key. 我们在string_not_equal()函数进行加断点处理,看这个函数的参数是那两个,就可以知道我们需要输入的是那个啦。
0x03 password
废话不多说,直接上汇编。
注意里面对于输入的字符串调用了一个strings_equal()函数,并且需要这个函数的返回值为1(因为后续经过一个test指令加上一个jne指令),也就是和这个字符串不同,在strings_equal()函数里面,对两个字符串进行取长度操作,并将长度作为返回值的依据,如果长度相等,则返回0, 不同则返回1。因此,我们只需要输入一个长度不同于11的字符串便可以解除这个炸弹了。
0x04 quick
首先调用read_six_number() 函数,暗示我们需要输入6个数字,将数字存储在eax寄存器所指向的$ebp-0x24这个位置。然后将第一个数字的位置,$ebp-0x24位置的数字进行test 然后通过jns进行跳转。所以要求第一个位置的数字不得小于0。之后通过$eax, $ebx,$ecx, 以及$edx四个寄存器进行循环判断,相对应位置的值是否满足条件a[i] = a[i-1] + i,如果不满足就bomb.
因此,我们只要输入符合要求的一组数据即可。
0x05 jump
先上汇编
jump函数首先调用sscanf()函数,从输入字符串中读取两个数,读到$ebp-0x14和$ebp-0x18中, 并且返回读到数字的个数在$eax中。首先判断返回值是否大于1, 不大于则bomb。 紧接着判断$ebp-0x14这个数是否比7大,如果超过7,则bomb。然后进行条件跳转,按照$ebp-0x14中读到的数进行跳转。如果输入的为零,则跳转到0x804951e这个位置。最后将对应数字进行比较,如果不相等,则跳转bomb.
0x06 binary
和前面的类似,读取两个数到$ebp-0x18以及$ebp-0x1c这两个位置,然后将返回值所在的$eax位置的数据和2进行比较,所以输入的必须是两个数字。然后将读到的第一个数字和0以及和e(16进制数,换成十进制就是14) 进行比较,如果小于0或者大于14都将爆炸。然后调用func4()函数,通过几个判断指令,控制程序的跳转。func4()函数的返回值必须为11。通过测试以及计算,1 11符合条件。
0x07 array
和前面类似,读取两个数到$ebp-0x18以及$ebp-0x1c这两个位置。使用代码进行计算
1 | a = [0xa, 2, 0xe, 7, 8, 0xc, 0xf, 0xb, 0, 4, 1, 0xd, 3, 9, 6, 5] |
0x08 list
首先调用read_six_number()函数,暗示我们的输入是6个数字。然后通过一个循环,要求每个数字都不一样,同时在1-6这个范围中。逻辑比较麻烦,但是还是可以理解的。注意观察到里面的一个链表结构。
1 | for a1 in range(1, 7): |
0x09 pi
在compute_pi()函数计算结束时候,查看相对应的内存即可。
0x10 secret
secret() 函数里面存在迭代,使用下面函数进行求解。
1 | d = { |