attacker lab
advice
phase 1
ctarget 会先调用test , test调用getbuf, getbuf调用Get。
任务目的是通过缓冲区注入攻击,将函数getbuf返回直接重定向到函数touch1。
0x28 是 40 比特,
gdb ./ctarget
401971: e8 32 fe ff ff callq 4017a8 <getbuf>
401976: 89 c2 mov %eax,%edx
rsp 指向的虚拟地址 0x5561dca0, 这个地址对应的内容是 0x00401976, 所以在输入没有超过40个字符的情况,rsp 指向的是getbuf 之后的下一个地址。
401971 + 5 个字节(e8 32 fe ff ff) 是 401976.
getbuf 下一次执行的指令是401976, rsp对应的汇编文件行数,
通过objdump 可以获取地址,
40个字符加上touch1的地址,
课件的例子1
课件的例子2
ret 返回的地址是通过rsp存储的虚拟地址,在访存阶段后,从内存获取的值。
call 在访存阶段回更新内存的地址,将下一条指令放入,进程的堆栈里,所以对应的进程的栈的范围的最顶端,是ret的地址。
rsp 是stack pointer register, rip 也可以理解为PC, 是指令寄存器。
valp 等属于电路概念,不详细讨论。
phase 2
ctarget 会先调用test , test调用getbuf, getbuf调用Get。
在phase1, 里通过修改缓冲区,是getbuf函数执行ret之后,跳转到touch1, 和touch1 不同的地方在于 touch2 是有入参数的,入参数需要通过在缓冲区里增加对rdi的修改,进行赋值。同时也要ret 执行后,确保rsp指向的地址的内容是touch2函数地址。
根据汇编可以看到,使用edi寄存器传递参数给edx。
任务目的是通过缓冲区注入攻击,将函数getbuf返回直接重定向到函数touch2。
参考了知乎网友的翻译,这里需要判断val,储存在rdi的值,和 cookie的值,cookie的值是0x59b997fa。
pushq $0x4017ec
mov $0x59b997fa, %rdi # save cookie into rdi
retq #
将汇编代码转为二进制
gcc -c phase2_mov.s
objdump -d phase2_mov.o > phase2_mov.d
[root@edb3963640a6 target1]# ./hex2raw < phase2.txt > phase2-raw.txt
[root@edb3963640a6 target1]# ./ctarget -q < phase2-raw.txt
使用gdb 查看stack frame,
多层stack frame,
简单介绍stack frame和函数调用的关系
需要获取rsp 的初始地址,
调用函数getbuf时候rsp是0x5561dca0 - 0x28 的到 0x5561dc78
getbuf 函数在调用get函数前,会存入ret address, 这个地址放入rsp, 之后rsp - 0x28, 写入0x28个字符,这部分字符的内容是修改rdi, 然后调用touch2, 然后多出来的部分会影响函数,使函数的返回地址修改rdi的值的地址。
答案如下:
phase3
汇编相关语法
pushq
call 指令
stack frame
函数
stack frame
call_echo 函数调用 echo 函数, call_echo函数的底部是echo执行完之后的地址。
control flow
pushq 指令
pushq指令在执行时会将栈指针rsp减小8个字节,以便为要压入栈中的数据腾出空间。这样,rsp将指向新的栈顶位置,即之前压入的数据的下一个位置。因此,pushq指令会通过减小rsp的值来更新栈指针。
rip寄存器
rip寄存器的值是由call指令或条件跳转指令等控制流指令来改变的。
参数寄存器
入参数寄存器是指在函数调用时,将参数值存储到特定的寄存器中,以便被调用的函数使用。不同的计算机体系结构和函数调用约定可能会有不同的入参数寄存器。
以下是一些常见的入参数寄存器:
-
x86架构:在x86架构中,通常使用EAX、EBX、ECX和EDX寄存器来存储前四个整型参数。如果参数超过四个,额外的参数会通过堆栈传递。
-
ARM架构:在ARM架构中,通常使用R0、R1、R2和R3寄存器来存储前四个整型参数。如果参数超过四个,额外的参数会通过堆栈传递。
-
MIPS架构:在MIPS架构中,通常使用A0、A1、A2和A3寄存器来存储前四个整型参数。如果参数超过四个,额外的参数会通过堆栈传递。
需要注意的是,这些寄存器的使用方式可能会受到编译器和函数调用约定的影响。不同的编译器和函数调用约定可能会使用不同的寄存器来存储参数。
对于其他类型的参数(如浮点数参数),通常会使用特定的浮点寄存器来存储。例如,在x86架构中,浮点数参数会使用XMM0、XMM1、XMM2等寄存器来存储。
总之,入参数寄存器用于存储函数调用时传递的参数值,以便被调用的函数使用。它们可以提高函数调用的效率,因为参数可以直接存储在寄存器中,而不需要通过堆栈传递。
edi寄存器
EDI寄存器是x86架构中的一个通用寄存器,全称为Extended Destination Index。它是32位寄存器,可以存储32位的数据。
EDI寄存器在x86体系结构中通常用于存储目的地址,特别是在字符串操作和数据传输指令中经常使用。例如,字符串复制指令"rep movs"中,源地址会存储在ESI寄存器中,而目的地址则存储在EDI寄存器中。
EDI寄存器也可以用于存储其他类型的数据,不仅限于地址。在函数调用中,EDI寄存器可以用作通用的临时寄存器,存储临时变量或计算结果。它可以在函数内部进行数据操作和传递。
EDI寄存器是可被程序员使用的通用寄存器之一,但在函数调用过程中,它也会被用作传递参数的寄存器之一。根据函数调用约定,EDI寄存器可能会被用来存储函数调用的返回地址或其他参数。
需要注意的是,EDI寄存器是32位寄存器,如果需要存储64位数据,可以使用EDI寄存器的低32位来存储。在64位x86架构中,RDI寄存器是EDI寄存器的64位版本。
总之,EDI寄存器是x86架构中的一个通用寄存器,用于存储目的地址或其他数据。它在字符串操作、数据传输和函数调用中经常使用。
参考资料
https://www.cs.cmu.edu/afs/cs/academic/class/15213-f17/www/lectures/09-machine-advanced.pdf
https://www.cs.cmu.edu/afs/cs/academic/class/15213-f15/www/lectures/07-machine-procedures.pdf
https://github.com/magna25/Attack-Lab/blob/master/Phase%202.md
https://zhuanlan.zhihu.com/p/107048472
https://zhuanlan.zhihu.com/p/105428280
https://zhuanlan.zhihu.com/p/60724948
https://zhuanlan.zhihu.com/p/107450834