引用:
https://www.freebuf.com/articles/system/226003.html
https://bbs.pediy.com/thread-259298.htm
前言
直接先说使用方法:
fini_array[1]放想要调用的地址addrA,fini_array[0]放__libc_csu_fini的地址,就可以无限调用addrA
也可以用来栈迁移
fini_array[0]放leave,ret,fini_array[1]放ret
概括一下,大致的做法就是先将fini_array[0]改为__libc_csu_fini,将fini_array[1]改为main
然后构造rop链在fini_array[2]上(fini_array+0x10)
最后再将fini_array[0]改为leave_ret,fini_array[1]改为ret
//libc_start_main函数原型
__libc_start_main(main,argc,argv&env,init,fini,rtld_fini)
用gdb调试main函数的时候,不难发现main的返回地址是__libc_start_main也就是说main并不是程序真正开始的地方,__libc_start_main是main的爸爸
然鹅,__libc_start_main也有爸爸,他就是_start也就是Entry point程序的进入点啦,可以通过readelf -h
其中,Entry point address: 0x401a60就是_start的地址
rdi <- main
rcx <- __libc_csu_init //在main函数前执行
r8 <- __libc_csu_fini //在main函数后执行
fini:
.text:0000000000402CB0 fini proc near ; DATA XREF: start+F↑o
.text:0000000000402CB0 ; __unwind {
.text:0000000000402CB0 push rbp
.text:0000000000402CB1 lea rax, unk_4B80C0
.text:0000000000402CB8 lea rbp, off_4B80B0 ;把fini_array的地址放入rbp
.text:0000000000402CBF push rbx
.text:0000000000402CC0 sub rax, rbp ; rax=0x10
.text:0000000000402CC3 sub rsp, 8
.text:0000000000402CC7 sar rax, 3 ; rax=2
.text:0000000000402CCB jz short loc_402CE6
.text:0000000000402CCD lea rbx, [rax-1] ; rbx=1
.text:0000000000402CD1 nop dword ptr [rax+00000000h]
.text:0000000000402CD8
.text:0000000000402CD8 loc_402CD8: ; CODE XREF: fini+34↓j
.text:0000000000402CD8 call qword ptr [rbp+rbx*8+0] ; 先call1,再call0
.text:0000000000402CDC sub rbx, 1 ; rbx=0
.text:0000000000402CE0 cmp rbx, 0FFFFFFFFFFFFFFFFh ; 与-1比较
.text:0000000000402CE4 jnz short loc_402CD8 ; 如果不相等
.text:0000000000402CE6
.text:0000000000402CE6 loc_402CE6: ; CODE XREF: fini+1B↑j
.text:0000000000402CE6 add rsp, 8
.text:0000000000402CEA pop rbx
.text:0000000000402CEB pop rbp
.text:0000000000402CEC jmp sub_4911EC
.text:0000000000402CEC ; } // starts at 402CB0
.text:0000000000402CEC fini endp
fini_array:
.fini_array:00000000004B80B0 _fini_array segment para public 'DATA' use64
.fini_array:00000000004B80B0 assume cs:_fini_array
.fini_array:00000000004B80B0 ;org 4B80B0h
.fini_array:00000000004B80B0 off_4B80B0 dq offset sub_401BB0 ; DATA XREF: .text:0000000000402C6C↑o
.fini_array:00000000004B80B0 ; fini+8↑o
.fini_array:00000000004B80B8 dq offset sub_401620
.fini_array:00000000004B80B8 _fini_array ends
这里保存了两个函数指针,分别是fini_array[0]和fini_array[1],参照fini的汇编,是先执行1,再执行0
看注释应该足够过一遍了,如果还是没懂的话建议配套上面的引用里的文章看
最后提一嘴mov和lea的差别:
mov:
对于变量,加不加[]都表示取值;
对于寄存器而言,无[]表示取值,有[]表示取地址。
lea:
对于变量,其后面的有无[]皆可,都表示取变量地址,相当于指针。
对于寄存器而言,无[]表示取地址,有[]表示取值。
也就是mov加[]是地址,lea加[]是值
注意:
(1) MOV指令中的源操作数绝对不能是立即数和代码段CS寄存器;
(2) MOV指令中绝对不允许在两个存储单元之间直接传送数据;
(3) MOV指令中绝对不允许在两个段寄存器之间直接传送数据;
(4) MOV指令不会影响标志位
来自:
一、Memory Monster II
https://blog.csdn.net/carol2358/article/details/106319203