寄存器相关的知识
phase1
// 对bomb可执行文件进行调试
gdb bomb
// 通过disas指令可以通过反汇编操作查看phase_1这个函数的汇编代码
disas phase_1
// 或者可以直接通过这个指令生成整个反汇编文件
objdump -d bomb > bomb.s
- 通过下面这个文件可以发现,read_line函数的结果rax放入了rdi寄存器,也就是作为phase_1函数的第一个参数,然后调用了phase_1函数
400e32: e8 67 06 00 00 callq 40149e <read_line>
400e37: 48 89 c7 mov %rax,%rdi
400e3a: e8 a1 00 00 00 callq 400ee0 <phase_1>
- 在phase_1函数中,又将0x402400放入esi寄存器,调用了strings_not_equal函数。
- 此时rdi寄存器存的是readline函数的结果,esi寄存器存的是一个地址,分别作为strings_not_equal函数第一个和第二个参数。
- 因此可以猜测,我们需要输入的就是0x402400这个地方存的字符串。通过
x/s 0x402400
即可获得这个字符串
Dump of assembler code for function phase_1:
// 函数调用时的压栈操作
0x0000000000400ee0 <+0>: sub $0x8,%rsp
// 将0x402400这个地址放入esi寄存器
// 作为strings_not_equal的一个参数
0x0000000000400ee4 <+4>: mov $0x402400,%esi
0x0000000000400ee9 <+9>: callq 0x401338 <strings_not_equal>
// 将eax和eax寄存器进行按位与操作,并把结果放入标志寄存器
// eax是上面那个函数的返回值,如果eax为0,说明这两个字符是相同的
0x0000000000400eee <+14>: test %eax,%eax
// 如果零标志位为1,则je成功运行,即躲过explode_bomb
// 也就是说零标志位如果是0,代表eax不是0,那么就会爆炸
0x0000000000400ef0 <+16>: je 0x400ef7 <phase_1+23>
// 爆炸
0x0000000000400ef2 <+18>: callq 0x40143a <explode_bomb>
0x0000000000400ef7 <+23>: add $0x8,%rsp
0x0000000000400efb <+27>: retq
End of assembler dump.
phase2
反汇编代码如下
这个phase的大意是通过sccanf读取我们输入的6个数字,如果能够满足是1 2 4 8 16 32的话,那就可以通过。
结合着汇编代码去看,应该不难理解这个phase的意思。
0000000000400efc <phase_2>:
400efc: 55 push %rbp
400efd: 53 push %rbx
400efe: 48 83 ec 28 sub $0x28,%rsp
400f02: 48 89 e6 mov %rsp,%rsi
400f05: e8 52 05 00 00 callq 40145c <read_six_numbers>
400f0a: 83 3c 24 01 cmpl $0x1,(%rsp) // 栈指针指向的内存的值应该是1
400f0e: 74 20 je 400f30 <phase_2+0x34>
400f10: e8 25 05 00 00 callq 40143a <explode_bomb>
400f15: eb 19 jmp 400f30 <phase_2+0x34>
400f17: 8b 43 fc mov -0x4(%rbx),%eax // 将rbx-4的位置的内存值给到eax
400f1a: 01 c0 add %eax,%eax // eax乘2
400f1c: 39 03 cmp %eax,(%rbx) // 即eax乘2后,要等于rbx指向的值,eax实际上是rbx下面的一个值
400f1e: 74 05 je 400f25 <phase_2+0x29>
400f20: e8 15 05 00 00 callq 40143a <explode_bomb>
400f25: 48 83 c3 04 add $0x4,%rbx // 再给rbx+4
400f29: 48 39 eb cmp %rbp,%rbx
400f2c: 75 e9 jne 400f17 <phase_2+0x1b> // 重复
400f2e: eb 0c jmp 400f3c <phase_2+0x40> //结束当前程序
400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx // 栈顶指针+4,给到rbx
400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp // 栈顶指针+24,给到rbp,即栈底指针
400f3a: eb db jmp 400f17 <phase_2+0x1b>
400f3c: 48 83 c4 28 add $0x28,%rsp
400f40: 5b pop %rbx
400f41: 5d pop %rbp
400f42: c3 retq
但是有个问题就是,我们输入的应该是正序还是倒序的?这个需要结合read_six_numbers来看了。
- 这个函数其实关键是调用了sscanf函数,解析我们输入的字符串
- 而sccanf的参数为
int sscanf(const char *str, const char *format, ...)
,其中后面的省略号就是通过str解析出来的结果,可能有多个,在这里,就是6个数字。 - 可以发现,这里将0x4025c3放入了esi,即作为sscanf的第二个参数,那么说明这个地址存放的东西就是解析的format,通过打印这个地址的值可以发现就是"%d %d %d %d %d %d",说明除了str和format,我们还需要传递六个参数。
- 可以发现,第一个参数rdi,这里没有显式地设置,因为这个rdi从phase_2函数开始就没有变过,一直都是我们输入的字符串。
- read_six_numbers在调用sscanf之前的那么多行,其实就是在传递后面的六个参数,也就是第3个到第8个参数。
- 通过前几行就可以发现,第1个值被放在了rsi处,而rsi其实就是phase_2的栈顶位置,也就是说第一个被解析出来的值放在栈底,也就是1。因此我们的字符串应该是从1开始增长,而不是从32开始逆序
000000000040145c <read_six_numbers>:
40145c: 48 83 ec 18 sub $0x18,%rsp
401460: 48 89 f2 mov %rsi,%rdx // 第3个参数,也是被解析的第一个值
401463: 48 8d 4e 04 lea 0x4(%rsi),%rcx // 第4个参数,也是被解析的第二个值
401467: 48 8d 46 14 lea 0x14(%rsi),%rax
40146b: 48 89 44 24 08 mov %rax,0x8(%rsp)
401470: 48 8d 46 10 lea 0x10(%rsi),%rax
401474: 48 89 04 24 mov %rax,(%rsp)
401478: 4c 8d 4e 0c lea 0xc(%rsi),%r9
40147c: 4c 8d 46 08 lea 0x8(%rsi),%r8
401480: be c3 25 40 00 mov $,%esi
401485: b8 00 00 00 00 mov $0x0,%eax
40148a: e8 61 f7 ff ff callq 400bf0 <__isoc99_sscanf@plt>
40148f: 83 f8 05 cmp $0x5,%eax
401492: 7f 05 jg 401499 <read_six_numbers+0x3d>
401494: e8 a1 ff ff ff callq 40143a <explode_bomb>
401499: 48 83 c4 18 add $0x18,%rsp
40149d: c3 retq
phase3
这个phase会让你输入两个数字
- 第一个数字是介于0-6之间的数,小于7即可
- 第二个数字根据第一个数字,通过switch指令进行跳转
一开始做的时候还没看懂那个switch的跳转指令。通过gdb调试不断往下走才确定了我输入的6对应的是哪个位置。
0000000000400f43 <phase_3>:
400f43: 48 83 ec 18 sub $0x18,%rsp // 减小栈指针,挪出24字节的空间
400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx // 栈指针+12 给rcx
400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx // 栈指针+8 给rdx
400f51: be cf 25 40 00 mov $0x4025cf,%esi // %d %d,sscanf的参数
400f56: b8 00 00 00 00 mov $0x0,%eax
400f5b: e8 90 fc ff ff callq 400bf0 <__isoc99_sscanf@plt>
400f60: 83 f8 01 cmp $0x1,%eax // 匹配成功的数目要大于1,即大于等于2,应该是2
400f63: 7f 05 jg 400f6a <phase_3+0x27>
400f65: e8 d0 04 00 00 callq 40143a <explode_bomb>
400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp)
400f6f: 77 3c ja 400fad <phase_3+0x6a> // 7如果大于rsp+8指向的值,则直接爆炸
400f71: 8b 44 24 08 mov 0x8(%rsp),%eax // rsp+8指向的值给eax
400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8) // 间接寻址0x402470+8*rax,其实这里就是个switch操作,根据你输入的第一个数字是0-6,给你传送到下面对应的mov
400f7c: b8 cf 00 00 00 mov $0xcf,%eax // 将eax置为0xcf,即11001111 15+64+128=207
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 mov $0x2c3,%eax
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 mov $0x100,%eax
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 mov $0x185,%eax
400f96: eb 26 jmp 400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 mov $0xce,%eax
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 mov $0x2aa,%eax
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 mov $0x147,%eax
400fab: eb 11 jmp 400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00 callq 40143a <explode_bomb>
400fb2: b8 00 00 00 00 mov $0x0,%eax
400fb7: eb 05 jmp 400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00 mov $0x137,%eax
400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax // 比较eax是否等于rsp+12指向的值
400fc2: 74 05 je 400fc9 <phase_3+0x86> // 等于的话,直接退出程序
400fc4: e8 71 04 00 00 callq 40143a <explode_bomb> // 不等于的话,就爆炸
400fc9: 48 83 c4 18 add $0x18,%rsp
400fcd: c3 retq
phase4
phase_4反汇编的代码如下
要求我们两个数字,其中第一个数字要小于等于14,第二个数字必须为0。其中第一个数字要通过func4函数,并且使其返回0。
000000000040100c <phase_4>:
40100c: 48 83 ec 18 sub $0x18,%rsp // 栈指针下移,挪出24字节的位置
401010: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx // 将rcx置为栈顶指针+12
401015: 48 8d 54 24 08 lea 0x8(%rsp),%rdx // 将rdx置为栈顶指针+8
40101a: be cf 25 40 00 mov $0x4025cf,%esi //
40101f: b8 00 00 00 00 mov $0x0,%eax
401024: e8 c7 fb ff ff callq 400bf0 <__isoc99_sscanf@plt>
401029: 83 f8 02 cmp $0x2,%eax
40102c: 75 07 jne 401035 <phase_4+0x29> // 如果输入参数个数不是两个,直接爆炸
40102e: 83 7c 24 08 0e cmpl $0xe,0x8(%rsp) // 将14 和 栈顶指针+8指向的值 比较
401033: 76 05 jbe 40103a <phase_4+0x2e> // 如果小于等于,则跳过炸弹继续执行
401035: e8 00 04 00 00 callq 40143a <explode_bomb> // 如果大于则直接爆炸
40103a: ba 0e 00 00 00 mov $0xe,%edx // 将edx置为14,func4的第3个参数
40103f: be 00 00 00 00 mov $0x0,%esi // 将esi置为0,func4的第2个参数
401044: 8b 7c 24 08 mov 0x8(%rsp),%edi // 将rsp+8指向的值给edi,func4的第1个参数
401048: e8 81 ff ff ff callq 400fce <func4> // 调用一个函数
40104d: 85 c0 test %eax,%eax // 如果eax不为0,则直接爆炸
40104f: 75 07 jne 401058 <phase_4+0x4c> // eax不为0,跳到炸弹那里去
401051: 83 7c 24 0c 00 cmpl $0x0,0xc(%rsp) // 比较0和rsp+12指向的值
401056: 74 05 je 40105d <phase_4+0x51> // 如果rsp+12指向的值就是0,则通过
401058: e8 dd 03 00 00 callq 40143a <explode_bomb>
40105d: 48 83 c4 18 add $0x18,%rsp
401061: c3 retq
func4函数的反汇编的代码
- func4是一个递归程序,这个代码如果要完全弄清楚,非常复杂,有一些大佬将其一步步分析成C语言代码,但是依然很恶心。不过如果只是想要通过,就没那么难。
- 首先,func4有3个参数,第一个参数就是我们输入的第一个数字,第二个参数固定为0,第三个参数固定为14
- 在func4的第一次跳转之前,ecx一定是7。然后我们用第一个数字和ecx即7比较,如果小于等于7就会跳转。
- 跳转之后,又用我们第一个数字和ecx即7进行比较,如果小于等于7,就会直接结束函数,并且返回0
- 因此,可以发现,7就是一个答案。并且是最简单的那个,都不会触发递归。
0000000000400fce <func4>:
400fce: 48 83 ec 08 sub $0x8,%rsp
400fd2: 89 d0 mov %edx,%eax // eax被置为14
400fd4: 29 f0 sub %esi,%eax // eax被置为14
400fd6: 89 c1 mov %eax,%ecx // ecx被置为14
400fd8: c1 e9 1f shr $0x1f,%ecx // ecx被置为0
400fdb: 01 c8 add %ecx,%eax // eax被置为14 0b1110
400fdd: d1 f8 sar %eax // eax被置为0b111,即7
400fdf: 8d 0c 30 lea (%rax,%rsi,1),%ecx // ecx被置为7
400fe2: 39 f9 cmp %edi,%ecx // x和7比较
400fe4: 7e 0c jle 400ff2 <func4+0x24> // 如果x<=7,跳转
400fe6: 8d 51 ff lea -0x1(%rcx),%edx
400fe9: e8 e0 ff ff ff callq 400fce <func4>
400fee: 01 c0 add %eax,%eax
400ff0: eb 15 jmp 401007 <func4+0x39>
400ff2: b8 00 00 00 00 mov $0x0,%eax // 将eax置为0
400ff7: 39 f9 cmp %edi,%ecx // 将x和7比较
400ff9: 7d 0c jge 401007 <func4+0x39> // 如果大于等于7,则直接跳出程序
400ffb: 8d 71 01 lea 0x1(%rcx),%esi // 将esi置为8
400ffe: e8 cb ff ff ff callq 400fce <func4> // 递归
401003: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
401007: 48 83 c4 08 add $0x8,%rsp
40100b: c3 retq
我刚开始做phase4的时候,陷入了func4这个函数里,完全搞不清楚它在干啥。这也有了一个教训,看汇编代码的时候,不要陷进去汇编的细节,要能够提取它的作用,用C语言的形式去想一下,或者想一想它具体在完成什么动作。
phase5
这个炸弹很有意思文章来源:https://www.toymoban.com/news/detail-618858.html
- 首先阅读汇编代码,搞清楚每个语句的作用,然后按照代码的逻辑给它划分,看的更加有层次感,最后搞清楚每个层次都干了什么
- 首先,这个phase需要我们输入一个长度为6的字符串
- 然后根据我们这些字符串的ascii码的二进制表示的最低4位的值为偏移,去系统给出的一个字符串取字符
- 根据输入的6个字符取出来的6个字符需要刚好和系统给定的另一个字符串相同
做的时候踩了些坑 - 第一遍阅读汇编代码的时候,就可以尝试去划分和理解,不用等到完全读了一遍之后再来划分。这样效率其实很低。耐下心来正确地分析代码,还是可以在第一遍读代码的时候就理解代码的逻辑的。这样就算没有很清楚,也可以通过第二轮去专门划分
- 有的时候各种寄存器一波操作,其实就是完成了一个很简单的逻辑,不要迷失在细节里了
- 分清楚传的是寄存器的值还是这个寄存器指向的内存的值
0000000000401062 <phase_5>:
// 将fs:0x28的值放到rsp+24字节的位置
401062: 53 push %rbx
401063: 48 83 ec 20 sub $0x20,%rsp // 给栈挪出32字节的位置
401067: 48 89 fb mov %rdi,%rbx // 将我们的输入给rbx
40106a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax // 将段寄存器偏移40字节的值给rax
401071: 00 00
401073: 48 89 44 24 18 mov %rax,0x18(%rsp) // 将rax给栈顶指针+24字节的位置
// 判断输入字符串的长度是否是6,如果不是6则直接爆炸
401078: 31 c0 xor %eax,%eax // eax清零
40107a: e8 9c 02 00 00 callq 40131b <string_length> // 获取我们输入的字符串的长度
40107f: 83 f8 06 cmp $0x6,%eax // 判断是否是6
401082: 74 4e je 4010d2 <phase_5+0x70> // 如果是6的话,则跳过炸弹
401084: e8 b1 03 00 00 callq 40143a <explode_bomb> // 如果不是6,则直接爆炸
401089: eb 47 jmp 4010d2 <phase_5+0x70>
// 这一段就是把我们输入的字符串通过一些奇怪的处理,放置在栈上rsp+16开始的位置,16-21
// 这个奇怪的处理应该是根据我们输入的字符,用它们的ascii码为偏移,去0x4024b0地址取字符放到rsp+16开始的位置
40108b: 0f b6 0c 03 movzbl (%rbx,%rax,1),%ecx // 将rbx+rax指向的值放入ecx,这里的rbx就是我们的输入,这里应该就是依次把字符给ecx
40108f: 88 0c 24 mov %cl,(%rsp) // 将ecx的值为栈顶指向的位置
401092: 48 8b 14 24 mov (%rsp),%rdx // 把栈顶的值给edx
401096: 83 e2 0f and $0xf,%edx // 用0b1111与edx按位与
401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),%edx // 将0x4024b0+edx指向的值给edx
4010a0: 88 54 04 10 mov %dl,0x10(%rsp,%rax,1) // 将edx的值放到16+rsp+rax指向的位置
4010a4: 48 83 c0 01 add $0x1,%rax // 给rax+1
4010a8: 48 83 f8 06 cmp $0x6,%rax // 6和rax比较
4010ac: 75 dd jne 40108b <phase_5+0x29> // 如果不同,则继续循环
// 判断我们放在栈上的字符串是否和0x40245e这个地址的字符一样
4010ae: c6 44 24 16 00 movb $0x0,0x16(%rsp) // 将rsp+22指向的值置为0
4010b3: be 5e 24 40 00 mov $0x40245e,%esi // 给esi一个地址0x40245e // "flyers"
4010b8: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi // 给rdi一个地址rsp+16 // "maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"
4010bd: e8 76 02 00 00 callq 401338 <strings_not_equal> // 比较这两个地址指向的字符串
4010c2: 85 c0 test %eax,%eax
4010c4: 74 13 je 4010d9 <phase_5+0x77> // 如果字符串相同,则跳过炸弹
4010c6: e8 6f 03 00 00 callq 40143a <explode_bomb> // 如果字符串不相同,则爆炸
4010cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
4010d0: eb 07 jmp 4010d9 <phase_5+0x77>
4010d2: b8 00 00 00 00 mov $0x0,%eax // 将eax置0
4010d7: eb b2 jmp 40108b <phase_5+0x29> // 跳转
// 比较%fs:0x2和栈上0x18(%rsp)开始的值是否一样,一样则成功。这个测试正常来说不会有问题。
4010d9: 48 8b 44 24 18 mov 0x18(%rsp),%rax // 将rsp+24指向的值给rax
4010de: 64 48 33 04 25 28 00 xor %fs:0x28,%rax // 将rax和一个地址的值异或
4010e5: 00 00
4010e7: 74 05 je 4010ee <phase_5+0x8c> // 如果等于0,则跳过下面这个函数,成功返回
4010e9: e8 42 fa ff ff callq 400b30 <__stack_chk_fail@plt>
4010ee: 48 83 c4 20 add $0x20,%rsp
4010f2: 5b pop %rbx
4010f3: c3 retq
phase6
这个lab也很有意思啊文章来源地址https://www.toymoban.com/news/detail-618858.html
- 首先,它需要我们输入六个数字
- 其次,它要求我们这个六个数字都小于等于6,并且不重复
- 然后,它会把我们这六个数字替换为7-x,即如果输入是123456,就会被替换成654321
- 然后,它会根据现在的数字,去一个链表里取6个数字。比如我们现在的数字被变成了6454321,那么它就会去这个链表里取出从第六个到第一个结点的地址。再将这个地址放到栈中从rsp+0x20开始的地方
- 然后,它会依次把取出来的六个结点串成一个链表
- 最后,它会检查这个链表是否是一个单调递减链表
因此,我们输入的六个数字其实就相当于是一个排序的方法,如果我们输入214356,那就代表着我们把原链表里的顺序从123456改为214356,然后判断修改之后是否是单调递减的。注意,这里说的123456指的是链表的结点编号,排序的依据是这个节点的val。
00000000004010f4 <phase_6>:
// 准备操作
4010f4: 41 56 push %r14
4010f6: 41 55 push %r13
4010f8: 41 54 push %r12
4010fa: 55 push %rbp
4010fb: 53 push %rbx
// 开始操作
4010fc: 48 83 ec 50 sub $0x50,%rsp // 开辟了80个字节的栈空间
401100: 49 89 e5 mov %rsp,%r13 // 将栈顶指针给r13
401103: 48 89 e6 mov %rsp,%rsi // 将栈顶指针给了rsi,即函数的第二个参数
401106: e8 51 03 00 00 callq 40145c <read_six_numbers> // 将我们输入的6个数字读入栈中
40110b: 49 89 e6 mov %rsp,%r14 // 把栈指针给了r14
40110e: 41 bc 00 00 00 00 mov $0x0,%r12d // 将r12置为0
// 下面这一波就是判断,是否六个数字都不同,并且六个数字都小于等于6
401114: 4c 89 ed mov %r13,%rbp // 把r13给rbp,rbp是栈底指针啊
401117: 41 8b 45 00 mov 0x0(%r13),%eax // 把r13指向的东西赋给了eax,r13现在是栈底,应该就是我们输入的第一个数字
40111b: 83 e8 01 sub $0x1,%eax // 将输入的第一个数字减1
40111e: 83 f8 05 cmp $0x5,%eax // 5和输入的数字进行比较
401121: 76 05 jbe 401128 <phase_6+0x34> // 输入的数字减1后小于等于5,则跳过炸弹,否则爆炸
401123: e8 12 03 00 00 callq 40143a <explode_bomb>
401128: 41 83 c4 01 add $0x1,%r12d // 给r12加1,r12在这之前刚被置为0
40112c: 41 83 fc 06 cmp $0x6,%r12d // 6和r12对比,如果一样则跳转,第一次到这里应该是不会跳转
401130: 74 21 je 401153 <phase_6+0x5f>
401132: 44 89 e3 mov %r12d,%ebx // 将r12给ebx,即ebx置为1
// 下面这一段是判断输入的第2到第6数是否都不和第1个数相同,如果存在相同的,则直接爆炸
401135: 48 63 c3 movslq %ebx,%rax // 将ebx给rax,rax=1
401138: 8b 04 84 mov (%rsp,%rax,4),%eax // eax=rsp+4*rax指向的值,第一次运行到这里应该是rsp+4,访问的是输入的第2个数字
40113b: 39 45 00 cmp %eax,0x0(%rbp) // eax和rbp指向的值比较,即第一个数和第二个数进行比较
40113e: 75 05 jne 401145 <phase_6+0x51> // 如果不同,则跳转,否则就爆炸
401140: e8 f5 02 00 00 callq 40143a <explode_bomb>
401145: 83 c3 01 add $0x1,%ebx // ebx+=1
401148: 83 fb 05 cmp $0x5,%ebx // ebx和5进行对比,如果ebx小于等于5,则跳转
40114b: 7e e8 jle 401135 <phase_6+0x41>
// 给r13加4
40114d: 49 83 c5 04 add $0x4,%r13
401151: eb c1 jmp 401114 <phase_6+0x20>
401153: 48 8d 74 24 18 lea 0x18(%rsp),%rsi // 将rsi指向rsp+24的位置
401158: 4c 89 f0 mov %r14,%rax // 把r14给rax,第一次运行到这里的时候r14这时候就是rsp
40115b: b9 07 00 00 00 mov $0x7,%ecx // ecx置为7
// 这是一个小循环,循环6次,将我们输入的数,都换成7-x
401160: 89 ca mov %ecx,%edx // edx置为7
401162: 2b 10 sub (%rax),%edx // 7-rsp指向的值
401164: 89 10 mov %edx,(%rax) // 再将7-rsp指向的值放到rsp指向的位置
401166: 48 83 c0 04 add $0x4,%rax // rax+4
40116a: 48 39 f0 cmp %rsi,%rax // rsi和rax比较
40116d: 75 f1 jne 401160 <phase_6+0x6c> // 如果不一样,则继续循环
// 现在栈顶的6个数字分别是,6 5 4 3 2 1
// 下面的操作是根据栈顶的六个数字,去一个链表里取结点
40116f: be 00 00 00 00 mov $0x0,%esi // esi置为0
401174: eb 21 jmp 401197 <phase_6+0xa3> // 跳转
401176: 48 8b 52 08 mov 0x8(%rdx),%rdx // rdx+8指向的值放到rdx中
40117a: 83 c0 01 add $0x1,%eax // eax+1
40117d: 39 c8 cmp %ecx,%eax // ecx中存放的是我们输入的数字,
40117f: 75 f5 jne 401176 <phase_6+0x82> // 如果不同的话,就不断循环
401181: eb 05 jmp 401188 <phase_6+0x94>
401183: ba d0 32 60 00 mov $0x6032d0,%edx
401188: 48 89 54 74 20 mov %rdx,0x20(%rsp,%rsi,2) // 6304544 6304528 6304512 6304496 6304480 0x6032d0
40118d: 48 83 c6 04 add $0x4,%rsi
401191: 48 83 fe 18 cmp $0x18,%rsi
401195: 74 14 je 4011ab <phase_6+0xb7>
401197: 8b 0c 34 mov (%rsp,%rsi,1),%ecx // 取出栈顶的元素放到ecx
40119a: 83 f9 01 cmp $0x1,%ecx // 元素和1相比
40119d: 7e e4 jle 401183 <phase_6+0x8f> // 如果元素小于等于1,则跳转
40119f: b8 01 00 00 00 mov $0x1,%eax // eax置为1
4011a4: ba d0 32 60 00 mov $0x6032d0,%edx // edx置为0x6032d0
4011a9: eb cb jmp 401176 <phase_6+0x82>
// 上面的操作花了这么大牛劲,就是把6304544 6304528 6304512 6304496 6304480 0x6032d0这六个地址放在了rsp+32 +0 +8 +16 +24 +32 +40的位置 好像刚好放满了这个栈
4011ab: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx // 把rbx置为rsp+32指向的值
4011b0: 48 8d 44 24 28 lea 0x28(%rsp),%rax // 把rax置为rsp+40,即上述操作栈的第二个元素的位置
4011b5: 48 8d 74 24 50 lea 0x50(%rsp),%rsi // 把rsi置为rsp+80,即整个栈的终点
4011ba: 48 89 d9 mov %rbx,%rcx // 把rcx置为第一个值
// 这里好像是循环着把一个链表给串起来
4011bd: 48 8b 10 mov (%rax),%rdx // 把rdx置为第二个值
4011c0: 48 89 51 08 mov %rdx,0x8(%rcx) // 把第二个值放到rcx+8指向的位置
4011c4: 48 83 c0 08 add $0x8,%rax // rax+=1,即指向下一个值
4011c8: 48 39 f0 cmp %rsi,%rax // 比较是否到了终点
4011cb: 74 05 je 4011d2 <phase_6+0xde> // 到了终点则跳转
4011cd: 48 89 d1 mov %rdx,%rcx // 否则将rcx变成rdx,即变成第二个点
4011d0: eb eb jmp 4011bd <phase_6+0xc9>
// 将链表最后一个节点的next指针置为0
4011d2: 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx)
4011d9: 00
// 链表降序排序 443 477 691 924 168 332
4011da: bd 05 00 00 00 mov $0x5,%ebp // ebp置为5
4011df: 48 8b 43 08 mov 0x8(%rbx),%rax // 此时rbx是第一个结点的地址,因此rax是第二个结点的地址
4011e3: 8b 00 mov (%rax),%eax // 将eax置为第二个结点
4011e5: 39 03 cmp %eax,(%rbx) // 比较第二个结点和第一个结点的值
4011e7: 7d 05 jge 4011ee <phase_6+0xfa> // 第一个如果要大于等于第二个,那么就跳过炸弹,否则就爆炸
4011e9: e8 4c 02 00 00 callq 40143a <explode_bomb>
4011ee: 48 8b 5b 08 mov 0x8(%rbx),%rbx
4011f2: 83 ed 01 sub $0x1,%ebp
4011f5: 75 e8 jne 4011df <phase_6+0xeb>
4011f7: 48 83 c4 50 add $0x50,%rsp
4011fb: 5b pop %rbx
4011fc: 5d pop %rbp
4011fd: 41 5c pop %r12
4011ff: 41 5d pop %r13
401201: 41 5e pop %r14
401203: c3 retq
到了这里,关于lab2 bomblab的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!