ROP实例分析(二)---------------------------DynELF使用
DynELF使用
需要使用者进行的工作主要集中在leak函数的具体实现上,上面的代码只是个模板。
其中,address就是leak函数要泄漏信息的起始地址,而payload就是触发目标程序泄漏address处信息的攻击代码。
使用条件
不管有没有libc文件,要想获得目标系统的system函数地址,首先都要求目标二进制程序中存在一个能够泄漏目标系统内存中libc空间内信息的漏洞。同时,由于我们是在对方内存中不断搜索地址信息,故我们需要这样的信息泄露漏洞能够被反复调用。以下是大致归纳的主要使用条件:
1)目标程序存在可以泄露libc空间信息的漏洞,如[email protected]就指向libc地址空间内;
2)目标程序中存在的信息泄露漏洞能够反复触发,从而可以不断泄露libc地址空间内的信息。
当然,以上仅仅是实现利用的基本条件,不同的目标程序和运行环境都会有一些坑需要绕过。
通用GADGET:
__libc_csu_init函数是程序调用libc库用来对程序进行初始化的函数,一般先于main函数执行
而我们则是要利用__libc_csu_init中两端特殊的gadget(简单点理解,gadget就是一小段程序代码)
传参规则
在32位汇编下
将参数直接压栈
在64位汇编下
当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9
当参数大于等于7个时,前 6 个与前面一样, 但后面的依次从右向左放入栈中,即和32位汇编一样。
对于上面的gadget1,特别的要设置
rbx=0 ,为了配合gadgt2中call指令,使得call指令跳转到r12
rbp=1 ,为了配合gadgt2中call指令之后的add和cmp指令,使得cmp后转向add rsp,8
r12=target_function/call address,要调用的函数地址。注意是got地址而不是plt地址,因为用的是call指令
r13,r14,r15就是我们要调用的函数的参数,为了配合gadget2,r15中布置arg1,其他以此类推。
即
Gadget2
0x400880处的gadget
首先将 r13 r14 r15 的值和rdx rsi edi交换,进行了参数传递。(上面我们提到了64位参数传递规则,所以r15即arg1被保存到edi中,也即rdi中。其他以此类推)
然后call [ r12+rbx*8 ],因为前面我们设置了rbx为0,所以此处就是call [ r12],就是调用我们想要调用的函数。
再然后将rbx自加1即rbx+1(前面设置rbx为0,故此时为1)和rbp进行比较,前面rbp我们设置为1,所以两者相等,cmp后转向add rsp,8继续执行。
因此在ret之前,栈顶指针rsp一共移动了56个字节(一次add,六次pop)。所以我们在栈中布置56个字节就可以了。
即
这两段代码普遍存在于x64二进制程序中,只不过是间接地传递参数。
可能用到的其他的gadget
pop_rdi_ret = l64(0x4008a3)
#0x4008a3:
pop rdi;
ret
pop_rsi_ret = l64(0x4008a1)
#0x4008a1:
pop rsi;
pop r15;
ret