解压完出现了三个文件bomb、bomb.c、readme,其中bomb.c是实验的源代码,不过他最重要的部分被删除了。我们可以通过将可执行文件bomb反汇编来查看内部情况。通过objdump -d bomb > bomb.asm我们获得了一个新的文件,内容是bomb的汇编代码。
gdb的使用
| 基本命令 | 
 | 
 | 
| 1.进入调试状态 | 
gdb bomb | 
后面的bomb是我们要调试的程序 | 
| 2.查看源码 | 
(gdb) l | 
前面的(gdb)代表已经进入调试状态,后面的l,将源码按行号显示 | 
| 3.设置断点 | 
(gdb) b   6 | 
意思是运行到源码的第六行时停止(第六行的指令没有执行) | 
| 4.查看断点情况 | 
(gdb) info b | 
将我们设置的断点列举出来 | 
| 5.运行代码 | 
(gdb) r | 
 | 
| 6.显示变量值 | 
(gdb) p n | 
p(print)变量名 | 
| 7.单步运行 | 
(gdb) n | 
next | 
| 8.程序继续运行 | 
(gdb) c | 
continue | 
| 9.退出 | 
(gdb) q | 
quit | 
| 10.访问内存 | 
x/参数 <地址> | 
参数s是输出为字符串,d为十进制输出,x为十六进制输出 | 
| 11.跟踪寄存器 | 
display<$寄存器> | 
碰到断点停下时显示所有跟踪寄存器的值 | 
用$前缀表示一个立即数
函数传参:当参数个数小于等于6个时,使用寄存器rdi,rsi,rdx,rcx,r8,r9,从第7个参数开始通过栈传递,顺序为从右往左入栈。csapp 3.7
实验部分
phase_1
这就是第一个炸弹

1 2 3 4 5 6 7 8 9
   | 0000000000400ee0 <phase_1>:   400ee0:	48 83 ec 08          	sub    $0x8,%rsp                   ;创建栈帧   400ee4:	be 00 24 40 00       	mov    $0x402400,%esi              ;将0x402400复制到esi中,前去查看   400ee9:	e8 4a 04 00 00       	call   401338 <strings_not_equal>  ;根据名字来看,调用比较函数   400eee:	85 c0                	test   %eax,%eax                       400ef0:	74 05                	je     400ef7 <phase_1+0x17>        ;相等则跳转   400ef2:	e8 43 05 00 00       	call   40143a <explode_bomb>        ;爆炸   400ef7:	48 83 c4 08          	add    $0x8,%rsp                    ;恢复栈帧   400efb:	c3                   	ret    
   | 
 
test执行过程与and相似,但他只设置条件码寄存器,不改变目的寄存器中的值。这里的用法是,如果返回值为零,则条件码寄存器置1,je进行跳转。
我们用x/s 0x402400查看以0x402400为首地址的字符串。
先把一个值(字符串的地址)放到了%esi里,而放到%edi里的就是我们输入的字符串地址,记住传参顺序,di、si、dx、cx、r8、r9.
1 2
   | (gdb) x/s 0x402400 0x402400:       "Border relations with Canada have never been better."
   | 
 
phase_2
第二个
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
   | 0000000000400efc <phase_2>:   400efc:	55                   	push   rbp                     ;保存栈帧寄存器   400efd:	53                   	push   rbx                   400efe:	48 83 ec 28          	sub    rsp,0x28                   400f02:	48 89 e6             	mov    rsi,rsp        ;-------------------为函数的调用做准备   400f05:	e8 52 05 00 00       	call   40145c <read_six_numbers>   400f0a:	83 3c 24 01          	cmp    DWORD PTR [rsp],0x1   400f0e:	74 20                	je     400f30 <phase_2+0x34>   400f10:	e8 25 05 00 00       	call   40143a <explode_bomb>   400f15:	eb 19                	jmp    400f30 <phase_2+0x34>   400f17:	8b 43 fc             	mov    eax,DWORD PTR [rbx-0x4]   400f1a:	01 c0                	add    eax,eax   400f1c:	39 03                	cmp    DWORD PTR [rbx],eax   400f1e:	74 05                	je     400f25 <phase_2+0x29>   400f20:	e8 15 05 00 00       	call   40143a <explode_bomb>   400f25:	48 83 c3 04          	add    rbx,0x4   400f29:	48 39 eb             	cmp    rbx,rbp   400f2c:	75 e9                	jne    400f17 <phase_2+0x1b>   400f2e:	eb 0c                	jmp    400f3c <phase_2+0x40>   400f30:	48 8d 5c 24 04       	lea    rbx,[rsp+0x4]             ;将(rsp)+0x4赋值给rbx   400f35:	48 8d 6c 24 18       	lea    rbp,[rsp+0x18]   400f3a:	eb db                	jmp    400f17 <phase_2+0x1b>   400f3c:	48 83 c4 28          	add    rsp,0x28   400f40:	5b                   	pop    rbx   400f41:	5d                   	pop    rbp   400f42:	c3                   	ret    
   | 
 
不太熟悉lea指令,先学一下。
lea是“load effective address”的缩写,把一个内存变量的有效地址送给指定的寄存器,简单地说lea指令可以用来将一个内存地址直接赋值给目的操作数。lea eax,[ebx+8]是将ebx+8这个值直接赋值给eax,与之相似的mov指令,mov eax,[ebx+8]是将内存地址为ebx+8处的数据赋值给eax。对于lea指令,lea eax,eax是会报错的,只能lea eax,[eax] 等同于mov eax,eax其实就是【eax】就是eax的值。
理一下逻辑:
1.调用函数,接收六个数字
2.[rsp]和0x1对比,所以(rsp)=1
3.如果相等则进行跳转,不相等则爆炸!!!
4.将rsp+4和rsp+0x18分别赋值给rbx和rbp
5.跳转,将地址为rbx-4处的数据赋值给eax
6.将eax乘2
7.[rbx]和eax进行比较
8.相等则将rbx+4,不相等则爆炸!!!!
9.比较rbx和rbp,如果相等则结束程序(success),如果不相等则跳转到步骤5.
第四行的指令mov rsi,rsp,rsi是传递第二个参数的寄存器,他保存的是什么值?保存的是栈指针,也就是栈顶地址。那么第一个参数呢,我们有理由怀疑我们的输入是第一个参数,正如pgase1中,根据函数名我们可以判断,读入六个数字。

可以看到他将第二个参数赋值给了rdx,然后下面的rsi+4和rsi+0x14,0x14==24,通过lea指令将距离栈顶第二个元素的地址和第七个元素的地址(末尾标志)传入了相关寄存器,注意这里的[rsi],因为前面提到过,rsi里存放的是栈顶地址,所以可以这么解释。这么复杂加上后面的sscanf大概猜测一下,就是将我们输入的6个数字放入首地址为rsp的内存空间中。我么可以查看一下mov esi,0x4025c3这条指令输入的十六个整型。

回到phase2函数,再调用完读取函数之后,进行了一次比较,如果输入的第一个数不是0x1则爆炸。继续往下,将输入的第二个数(【rsp+4】)送入rbp,将[rsp+0x18]送入rbp(栈帧寄存器),下面其实是个循环,通过比较指令和跳转指令来实现,add    rbx,0x4这条指令相当于一个计数器。大致实现的逻辑是将第二个如放入rbx,将钱一个数字放入rax,将rax进行乘2操作,进行比较。其实只要看出这一题的循环,很多东西都是水到渠成的顺出来的。
1 2 3
   | cmp    rbx,rbp 75 e9                	jne    400f17 <phase_2+0x1b> eb 0c                	jmp    400f3c <phase_2+0x40>
   | 
 
每比较一次都会对rbx+4,当rbx+4与我们设置的末尾表值相同时就会结束循环。0x4–>0x18,差为24,正好循环六次
1 2 3 4 5 6 7 8 9 10 11
   | #include<stdio.h> int main() {     int arr[6]={1};     for(int i=0;i<6;i++)     {         arr[i+1]=arr[i]*2;         printf("%d ",arr[i]);     } } ;1 2 4 8 16 32
   | 
 
phase_3
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
   | 0000000000400f43 <phase_3>:   400f43:	48 83 ec 18          	sub    rsp,0x18   400f47:	48 8d 4c 24 0c       	lea    rcx,[rsp+0xc]           ;参数4     0x00   400f4c:	48 8d 54 24 08       	lea    rdx,[rsp+0x8]           ;参数3   400f51:	be cf 25 40 00       	mov    esi,0x4025cf            ;参数2查看之后是%d,诡异的是接收两个整形   400f56:	b8 00 00 00 00       	mov    eax,0x0                 ;应该是个计数器   400f5b:	e8 90 fc ff ff       	call   400bf0 <__isoc99_sscanf@plt>;读取我们的input作为scand的参数   400f60:	83 f8 01             	cmp    eax,0x1                 ;eax里的值和1比较,eax存放的是函数的返回值   400f63:	7f 05                	jg     400f6a <phase_3+0x27>   ;如果大于一则跳转     jg是由符号运算大于则跳转   400f65:	e8 d0 04 00 00       	call   40143a <explode_bomb>   ;不大于一直接爆炸   400f6a:	83 7c 24 08 07       	cmp    DWORD PTR [rsp+0x8],0x7 ;调准到此处,与0x7进行比较   400f6f:	77 3c                	ja     400fad <phase_3+0x6a>   ;无符号大于则跳转,爆炸   400f71:	8b 44 24 08          	mov    eax,DWORD PTR [rsp+0x8]    400f75:	ff 24 c5 70 24 40 00 	jmp    QWORD PTR [rax*8+0x402470];用x/x查明之后,是机器码0xb9,对应的汇编指令是MOV cx,immed16   400f7c:	b8 cf 00 00 00       	mov    eax,0xcf   400f81:	eb 3b                	jmp    400fbe <phase_3+0x7b>   400f83:	b8 c3 02 00 00       	mov    eax,0x2c3   400f88:	eb 34                	jmp    400fbe <phase_3+0x7b>   400f8a:	b8 00 01 00 00       	mov    eax,0x100   400f8f:	eb 2d                	jmp    400fbe <phase_3+0x7b>   400f91:	b8 85 01 00 00       	mov    eax,0x185   400f96:	eb 26                	jmp    400fbe <phase_3+0x7b>   400f98:	b8 ce 00 00 00       	mov    eax,0xce   400f9d:	eb 1f                	jmp    400fbe <phase_3+0x7b>   400f9f:	b8 aa 02 00 00       	mov    eax,0x2aa   400fa4:	eb 18                	jmp    400fbe <phase_3+0x7b>   400fa6:	b8 47 01 00 00       	mov    eax,0x147   400fab:	eb 11                	jmp    400fbe <phase_3+0x7b>   400fad:	e8 88 04 00 00       	call   40143a <explode_bomb>   400fb2:	b8 00 00 00 00       	mov    eax,0x0   400fb7:	eb 05                	jmp    400fbe <phase_3+0x7b>   400fb9:	b8 37 01 00 00       	mov    eax,0x137   400fbe:	3b 44 24 0c          	cmp    eax,DWORD PTR [rsp+0xc]   400fc2:	74 05                	je     400fc9 <phase_3+0x86>   400fc4:	e8 71 04 00 00       	call   40143a <explode_bomb>   400fc9:	48 83 c4 18          	add    rsp,0x18   400fcd:	c3                   	ret    
   | 
 
通过传到esi里的参数我们可以看出,这次接受的输入是两个整形,下面一堆东西是属比较抽象,静态看实在有点头大,于是多下了几个断点一步一步来,输入2 2尝试一下。cmp eax,0x1,eax里保存的是返回值,只要我们的输入大于一个应该就能正常跳转,下面的比较没太看明白,和0x7进行比较,试一下就知道,其实是和我们的第一个输入进行比较,只要不大于7就能正常跳转,我们接着向下,一步一步调试来到了最后的比较,cmp    eax,DWORD PTR [rsp+0xc],很容易想到[rsp+0xc]其实就是我们的第二个输入,这是只要我们查看一下寄存器的值,就知道如何进行比较
可以看到rax的值为707,推出之后重新运行,输入2 707果然正确。通过这题目的名字可以看出他考察的是分支,关键的没看懂的地方其实是jmp    QWORD PTR [rax*8+0x402470],这一步大概率是根据我们的输入进行不同的跳转的函数。至于我们的输入为什么被放在了[rsp,0xc]和[rsp+0x8]中,我的猜测是这是函数的参数用来指定将接收的输入放置的位置。 __isoc99_sscanf@plt(rdi,rsi,n1,n2,n3…)其中参数rdi保存的是我们input里的输入,rsi保存的是%d之类的,以什么形式接收多少,后面就是放置的位置吧。
看了网上的题解之后,才明白这原来就是个switch分支啊,我们可以通过x命令来查看一下0x402470的内容,这是个跳转表,在《汇编语言》接触过
通过x/8xg
细说一下x命令,很好用。
1 2 3 4 5 6 7 8
   | 格式        x/nfu  addr n是正数表示要显示的数量 f该表的是输出格式,常用的有字符串s,十六进制x,十进制d,字符c u代表一多少个字节作为一个内存单元来显示,b=1byte,h=2 bytes,w=4 bytes,g=8 bytes addr代表内存单元地址  x/8xg 0x402470 这条指令的意思就是从内存地址0x402470处,以十六进制形式8个字节为一个单位显示8组数 为什么这里要用8呢,因为跳转那里是qword也就是两个字,一个字32为两个字就是8字节
   | 
 
phase_4
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
   | 0000000000400fce <func4>:   400fce:	48 83 ec 08          	sub    rsp,0x8   400fd2:	89 d0                	mov    eax,edx  ;0x0e   400fd4:	29 f0                	sub    eax,esi  ;0x0   400fd6:	89 c1                	mov    ecx,eax      400fd8:	c1 e9 1f             	shr    ecx,0x1f  ;右移0x1f   400fdb:	01 c8                	add    eax,ecx   ;   400fdd:	d1 f8                	sar    eax,1     ;算术右移   400fdf:	8d 0c 30             	lea    ecx,[rax+rsi*1]   ;   400fe2:	39 f9                	cmp    ecx,edi   400fe4:	7e 0c                	jle    400ff2 <func4+0x24>      ;有符号小于等于   400fe6:	8d 51 ff             	lea    edx,[rcx-0x1]   400fe9:	e8 e0 ff ff ff       	call   400fce <func4>      ;调用自身  递归   400fee:	01 c0                	add    eax,eax   400ff0:	eb 15                	jmp    401007 <func4+0x39>   400ff2:	b8 00 00 00 00       	mov    eax,0x0   400ff7:	39 f9                	cmp    ecx,edi   400ff9:	7d 0c                	jge    401007 <func4+0x39>;有符号大于等于   400ffb:	8d 71 01             	lea    esi,[rcx+0x1]   400ffe:	e8 cb ff ff ff       	call   400fce <func4>   401003:	8d 44 00 01          	lea    eax,[rax+rax*1+0x1]   401007:	48 83 c4 08          	add    rsp,0x8   40100b:	c3                   	ret    
  000000000040100c <phase_4>:   40100c:	48 83 ec 18          	sub    rsp,0x18   401010:	48 8d 4c 24 0c       	lea    rcx,[rsp+0xc]      ;第二个输入   401015:	48 8d 54 24 08       	lea    rdx,[rsp+0x8]      ;第一个输入   40101a:	be cf 25 40 00       	mov    esi,0x4025cf       ;接收两个整型   40101f:	b8 00 00 00 00       	mov    eax,0x0   401024:	e8 c7 fb ff ff       	call   400bf0 <__isoc99_sscanf@plt>   401029:	83 f8 02             	cmp    eax,0x2            ;如果输入不为2就爆炸   40102c:	75 07                	jne    401035 <phase_4+0x29>   40102e:	83 7c 24 08 0e       	cmp    DWORD PTR [rsp+0x8],0xe  ;第一个输入和0xe进行比较   401033:	76 05                	jbe    40103a <phase_4+0x2e>    ;无符号小于等于则跳转,所以我们的输入必须小于等于14   401035:	e8 00 04 00 00       	call   40143a <explode_bomb>   40103a:	ba 0e 00 00 00       	mov    edx,0xe   40103f:	be 00 00 00 00       	mov    esi,0x0   401044:	8b 7c 24 08          	mov    edi,DWORD PTR [rsp+0x8]   ;------------函数传参   401048:	e8 81 ff ff ff       	call   400fce <func4>      ;调用func4   40104d:	85 c0                	test   eax,eax            ;and操作不过不改变不敌寄存器的值,为0时标志寄存器置0   40104f:	75 07                	jne    401058 <phase_4+0x4c>    ;如果上面eax的值为0则不发生跳转(哦按段是否相等是检测其差是否为0)   401051:	83 7c 24 0c 00       	cmp    DWORD PTR [rsp+0xc],0x0   ;将第二个参数与0进行比较   401056:	74 05                	je     40105d <phase_4+0x51>      ;相等则成功,否则爆炸!!!   401058:	e8 dd 03 00 00       	call   40143a <explode_bomb>   40105d:	48 83 c4 18          	add    rsp,0x18   401061:	c3                   	ret    
   | 
 
看着汇编用c语言大致实现了一遍。
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 50
   | #include<stdio.h> int func4(int di, int si, int dx) {     int ax = dx;     ax = ax - si;     int cx = ax;     cx = cx >> 0x1f;      ax = ax + cx;     ax = ax >> 1;      cx = (ax + si);     if (cx <= di)     {         ax = 0;         if (cx >= di)             return ax;         else             si = (cx + 1);             ax=func4(di, si, dx);             ax = (ax + ax + 1);             return ax;     }     else         dx = (cx - 1);         ax = func4(di, si, dx);         ax = ax+ax;         return ax; } int main() {     int i = 0;     int g = 0;     scanf_s("%d", &i);     scanf_s("%d", &g);     if (i <= 0xe)     {         printf("yes");         int x=func4(i, 0, 0xe);         if (x != 0)             printf("bomb!!");         else             if (g == 0)                 printf("success!!!");             else                 printf("bomb!!!!!!!!");     }     else         printf("bomb");     return 0;
  }
   | 
 
本来tmd早就可以结束的,在test那里出了点问题,test eax,eax; jne bomb 意思是如果返回值eax的值为零,那么爆炸,woc简直了,把c语言的判断写成了         if(ex==0)则爆炸。。。这一题的解题思路不同于上两个,是直接通过代码实现的,经过验证(0~14)其中可行的是0,1,3,7第二个输入是固定的0。
phase_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
   | 0000000000401062 <phase_5>:   401062:	53                   	push   rbx   401063:	48 83 ec 20          	sub    rsp,0x20   401067:	48 89 fb             	mov    rbx,rdi   40106a:	64 48 8b 04 25 28 00 	mov    rax,QWORD PTR fs:0x28   401071:	00 00    401073:	48 89 44 24 18       	mov    QWORD PTR [rsp+0x18],rax   401078:	31 c0                	xor    eax,eax   40107a:	e8 9c 02 00 00       	call   40131b <string_length>    40107f:	83 f8 06             	cmp    eax,0x6                ;如果输入的字符串长度不等于6,则爆炸   401082:	74 4e                	je     4010d2 <phase_5+0x70>         401084:	e8 b1 03 00 00       	call   40143a <explode_bomb>   401089:	eb 47                	jmp    4010d2 <phase_5+0x70>   40108b:	0f b6 0c 03          	movzx  ecx,BYTE PTR [rbx+rax*1]     ;将我们的输入逐字节传送到ecx   40108f:	88 0c 24             	mov    BYTE PTR [rsp],cl            ;送入【rsp】   401092:	48 8b 14 24          	mov    rdx,QWORD PTR [rsp]          ;送入rdx   401096:	83 e2 0f             	and    edx,0xf                      ;将我们的输入and上0xf   401099:	0f b6 92 b0 24 40 00 	movzx  edx,BYTE PTR [rdx+0x4024b0]       ;把该地址处的值存入edx,0扩展并传送(无符号扩展)到edx   4010a0:	88 54 04 10          	mov    BYTE PTR [rsp+rax*1+0x10],dl       ;将修改过的输入传入指定位置   4010a4:	48 83 c0 01          	add    rax,0x1                          ;eax+1   4010a8:	48 83 f8 06          	cmp    rax,0x6                           ;eax的值与6进行比较   4010ac:	75 dd                	jne    40108b <phase_5+0x29>             ;因为在前面eax已经置零,所以这里就是循环六次上面的操作   4010ae:	c6 44 24 16 00       	mov    BYTE PTR [rsp+0x16],0x0         ;向指定位置送个0,像是结尾标志   4010b3:	be 5e 24 40 00       	mov    esi,0x40245e                    ;将比较字符串“flyers”送入   4010b8:	48 8d 7c 24 10       	lea    rdi,[rsp+0x10]                  ;   4010bd:	e8 76 02 00 00       	call   401338 <strings_not_equal>        ;如果不相等则为真返回1否则返回0   4010c2:	85 c0                	test   eax,eax                              4010c4:	74 13                	je     4010d9 <phase_5+0x77>              ;如果返回值rax为0则进行跳转,否则爆炸   4010c6:	e8 6f 03 00 00       	call   40143a <explode_bomb>   4010cb:	0f 1f 44 00 00       	nop    DWORD PTR [rax+rax*1+0x0]                  4010d0:	eb 07                	jmp    4010d9 <phase_5+0x77>   4010d2:	b8 00 00 00 00       	mov    eax,0x0   4010d7:	eb b2                	jmp    40108b <phase_5+0x29>   4010d9:	48 8b 44 24 18       	mov    rax,QWORD PTR [rsp+0x18]         ;   4010de:	64 48 33 04 25 28 00 	xor    rax,QWORD PTR fs:0x28            ;异或操作,实际上是进行比较,其实是进行栈溢出检测   4010e5:	00 00    4010e7:	74 05                	je     4010ee <phase_5+0x8c>            ;如果相等则异或结果为零跳转,成功。   4010e9:	e8 42 fa ff ff       	call   400b30 <__stack_chk_fail@plt>   4010ee:	48 83 c4 20          	add    rsp,0x20   4010f2:	5b                   	pop    rbx   4010f3:	c3                   	ret    
   | 
 
这里其实是个多解题目,其实输入的是六个索引值。0x4024b0那里就是字符表(在字符表后发现了隐藏的炸弹好阴险),最后的栈溢出检测浪费了很长时间,应该就是将其和金丝雀值进行对比,通过调试也可以看出,栈是随机化的。
phase_6
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
   | 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    rsp,0x50   401100:	49 89 e5             	mov    r13,rsp   401103:	48 89 e6             	mov    rsi,rsp      ;第二个参数  存放输入的首地址   401106:	e8 51 03 00 00       	call   40145c <read_six_numbers>   40110b:	49 89 e6             	mov    r14,rsp      ;将栈顶地址赋值给r14   40110e:	41 bc 00 00 00 00    	mov    r12d,0x0     ;   401114:	4c 89 ed             	mov    rbp,r13      ;将栈顶地址赋值给rbp   401117:	41 8b 45 00          	mov    eax,DWORD PTR [r13+0x0]   ;把输入1送入eax   40111b:	83 e8 01             	sub    eax,0x1          ;将eax减去1   40111e:	83 f8 05             	cmp    eax,0x5          ;和5进行比较   401121:	76 05                	jbe    401128 <phase_6+0x34>  ;无符号小于等于跳转   401123:	e8 12 03 00 00       	call   40143a <explode_bomb>  ;第一个输入不能大于6   401128:	41 83 c4 01          	add    r12d,0x1      ;给计数器加1   40112c:	41 83 fc 06          	cmp    r12d,0x6      ;与6进行比较   401130:	74 21                	je     401153 <phase_6+0x5f> ;相等则跳转   401132:	44 89 e3             	mov    ebx,r12d     ;   401135:	48 63 c3             	movsxd rax,ebx      ;符号扩展   401138:	8b 04 84             	mov    eax,DWORD PTR [rsp+rax*4];将输入送入eax   40113b:	39 45 00             	cmp    DWORD PTR [rbp+0x0],eax;与输入1进行对比   40113e:	75 05                	jne    401145 <phase_6+0x51>;不相等跳转   401140:	e8 f5 02 00 00       	call   40143a <explode_bomb>;相等爆炸   401145:	83 c3 01             	add    ebx,0x1  ;2   401148:	83 fb 05             	cmp    ebx,0x5   ;比较,循环5次知道ebx=6   40114b:	7e e8                	jle    401135 <phase_6+0x41> ;有符号小于等于跳转   40114d:	49 83 c5 04          	add    r13,0x4  ;r13指向第2个输入   401151:	eb c1                	jmp    401114 <phase_6+0x20>   401153:	48 8d 74 24 18       	lea    rsi,[rsp+0x18]   ;第六个输入的后一个的地址   401158:	4c 89 f0             	mov    rax,r14   40115b:	b9 07 00 00 00       	mov    ecx,0x7   401160:	89 ca                	mov    edx,ecx   401162:	2b 10                	sub    edx,DWORD PTR [rax]   401164:	89 10                	mov    DWORD PTR [rax],edx   401166:	48 83 c0 04          	add    rax,0x4   40116a:	48 39 f0             	cmp    rax,rsi   40116d:	75 f1                	jne    401160 <phase_6+0x6c>    ;又是一个循环   40116f:	be 00 00 00 00       	mov    esi,0x0             401174:	eb 21                	jmp    401197 <phase_6+0xa3>   401176:	48 8b 52 08          	mov    rdx,QWORD PTR [rdx+0x8]   40117a:	83 c0 01             	add    eax,0x1   40117d:	39 c8                	cmp    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    edx,0x6032d0   401188:	48 89 54 74 20       	mov    QWORD PTR [rsp+rsi*2+0x20],rdx   40118d:	48 83 c6 04          	add    rsi,0x4   401191:	48 83 fe 18          	cmp    rsi,0x18   401195:	74 14                	je     4011ab <phase_6+0xb7>   401197:	8b 0c 34             	mov    ecx,DWORD PTR [rsp+rsi*1]   40119a:	83 f9 01             	cmp    ecx,0x1   40119d:	7e e4                	jle    401183 <phase_6+0x8f>   40119f:	b8 01 00 00 00       	mov    eax,0x1   4011a4:	ba d0 32 60 00       	mov    edx,0x6032d0   4011a9:	eb cb                	jmp    401176 <phase_6+0x82>   4011ab:	48 8b 5c 24 20       	mov    rbx,QWORD PTR [rsp+0x20]   4011b0:	48 8d 44 24 28       	lea    rax,[rsp+0x28]   4011b5:	48 8d 74 24 50       	lea    rsi,[rsp+0x50]   4011ba:	48 89 d9             	mov    rcx,rbx   4011bd:	48 8b 10             	mov    rdx,QWORD PTR [rax]   4011c0:	48 89 51 08          	mov    QWORD PTR [rcx+0x8],rdx   4011c4:	48 83 c0 08          	add    rax,0x8   4011c8:	48 39 f0             	cmp    rax,rsi   4011cb:	74 05                	je     4011d2 <phase_6+0xde>   4011cd:	48 89 d1             	mov    rcx,rdx   4011d0:	eb eb                	jmp    4011bd <phase_6+0xc9>   4011d2:	48 c7 42 08 00 00 00 	mov    QWORD PTR [rdx+0x8],0x0   4011d9:	00    4011da:	bd 05 00 00 00       	mov    ebp,0x5   4011df:	48 8b 43 08          	mov    rax,QWORD PTR [rbx+0x8]   4011e3:	8b 00                	mov    eax,DWORD PTR [rax]   4011e5:	39 03                	cmp    DWORD PTR [rbx],eax   4011e7:	7d 05                	jge    4011ee <phase_6+0xfa>   4011e9:	e8 4c 02 00 00       	call   40143a <explode_bomb>   4011ee:	48 8b 5b 08          	mov    rbx,QWORD PTR [rbx+0x8]   4011f2:	83 ed 01             	sub    ebp,0x1   4011f5:	75 e8                	jne    4011df <phase_6+0xeb>   4011f7:	48 83 c4 50          	add    rsp,0x50   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                   	ret    
 
   | 
 
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
   | #define  _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() { 	char arr[]="193456"; 	int rsp=0; 	int ebp; 	int ecx = 0; 	int edx = 0; 	int esi = 0; 	char* r14 = arr; 	char* rsp = arr;                  	int r12d = 0; 	char* r13 = arr;                            jump401114:char* rbp = r13; 	int eax = *(r13 + 0); 	eax = eax - 1; 	int ebx = 0;       	if (eax <= 5) 	{ 		goto jump4001128; 		jump4001128: 		r12d = r12d + 1; 		if (r12d == 6) 		{ 			 			goto jump4001153; 			jump4001153: 			int rsi = 0; 			eax = *r14; 			ecx = 0x7; jump401160: edx = ecx; 			edx = edx - eax; 			eax = edx; 			eax = eax + 4; 			if (eax == rsi) 			{ 				 				rsi = 0; 				goto jump401197; 	jump401197: ecx = *(rsp + rsi); 				if (ecx <= 1) 				{ 					edx = 0x6032d0; 					goto jump401188; 				} 				else             				{ 					eax = 1; 					edx = 0x6032d0; 					goto jump401176; 				jump401176: 					edx = edx + 0x8; 					eax = eax + 1; 					if (eax != ecx) 					{ 						goto jump401176; 					} 					else  					{ 						goto jump401188; 					jump401188: 						rsp = edx; 						rsi = rsi + 4; 						if (rsi == 0x18) 						{ 							 							goto jump4011ab; 						jump4011ab: 							ebx = rsp+0x20; 							eax = rsp+0x28; 							rsi = rsp+0x50; 							ecx = ebx; 		jump4011bd:			edx = eax;  							ecx = edx; 							eax = eax + 8;                                                							if (eax == rsi)                                      							{ 								goto jump4011d2; 							jump4011d2: 								edx = 0; 								ebp = 5; 	      jump4011df:			eax=ebx; 								eax = eax; 								ebx = eax; 								if (ebx >= eax) 								{ 									goto jump4011ee; 								jump4011ee: 									 									ebp = ebp - 1; 									if (ebp != 1)     									{ 										goto jump4011df; 									} 									else 									{ 										printf("w1n!!!_y0u_@r3_my_her0!!!!"); 										return 0; 									} 								} 								else                 								{ 									goto bomb; 								} 							} 							else 							{ 								 								goto jump4011bd; 							} 						} 						else 						{ 							ecx = rsp + 4; 							if (ecx <= 1) 							{ 								 								goto jump401188; 							} 							else  							{ 								eax = 1; 								edx = 0x6032d0; 								goto jump401176; 							 							 							 							 							 							 							 							 							 							 							
  							}
  						} 					} 				} 			} 			else 			{ 				goto jump401160; 			} 		} 		else 		{ 			ebx = r12d;  jump401135:eax = ebx; 			eax = *(rsp + eax); 			if (*(rbp) == eax)          			{ 				printf("401140 bomb!!!"); 				return 0; 			} 			else 			{ 				goto jump401145; 				jump401145: 				ebx = ebx + 1; 				if (ebx <= 5) 				{ 					goto jump401135;   				} 				else 				{ 					r13 = r13 + 1; 					goto jump401114; 				} 			} 		} 	} 	else 		printf("bomb!"); 	    return 0;  	printf("%c", *r13 ); 	return 0; bomb:printf("bomb!!!!!"); 	return 0;
  }
   | 
 
这一题做的非常的。。。。。。。。怎么说呢,做完了看看别人的解题思路才发现这是个链表,我是直接把汇编还原成c语言,不是完全的还原,只是看着像的那种还原,这样做有一个好处是比直接看汇编简单一点,因为那个跳来跳去的,这样跳转到哪里,跳转条件至少清楚一点。第一层:检测六个数是否都小于等于6,第二层:用7减去原数据放在原始位置上,第三层:将0x6032d0处数据每隔8字节分别复制到栈中,这个复制顺序和我们的输入有关,比如说我们第一个输入是6,7-6=1,就是将0x6032d0+0*8处的数据复制到第一个位置,第二个输入是3,7-3=4,那么将0x6032d0+3*8处的数据复制到第二个位置。第四层:将复制到栈中的数据进行比较,大的在前。查看内存

后面是序号,前面是数据,从大到小排列是345612,这个顺序是被7减过后的,所以原来的是432165
这种做法算是比较粗野的一种,说一下这次做题中遇到的问题,首先是【】的问题,现在在知道了,出现[]一般是要访问内存了,其二注意数据的长度,有dw,qw,b啥的。还有,有时候看不懂的时候就带入具体的数据看一看,比如说第三层那里,看不懂它是将哪里的数据复制到哪里,最后带入654321这样的具体数据一眼就看出了它是如何操作的。
