ret2_dl_resolve
GOT & PLT
动态链接需要考虑的两点
- 需要存放外部函数的数据段(GOT)
- 获取数据段存放函数地址的一小段额外代码(PLT)
PLT
PLT内容是一段代码,所以PLT位于代码段,不可更改
GOT
GOT是一个表,表里面存的是函数的地址。
GOT表项中还保存了三个公共表项
got[0]: 本ELF动态段.dynamic的装载地址
got[1]: 本ELF的link_map数据结构描述符地址
got[2]: dl_rumtime_resolve函数的地址
流程

延迟重定向
在函数第一次调用前,got表项的内容都是链接器生成的,他的值指向对应的plt中jmp代码的下一条指令。
1 |
|
最后都会跳到<common@plt>【也就是plt[0]】中去执行代码。
这是动态链接做符号解析和重定位的公共入口。
common@plt内容
1 | |
所有动态链接库函数在第一次调用时都会通过
xxx@plt ===> common@plt ===> dl_runtime_resolve() 完成调用。
dl_runtime_resolve
调用流程

两个参数
link_map的指针
包含了.dynamic的指针,使dl_runtime_resolve可以访问到这个段。
- offset
1 |
|
这里push的数字其实是函数的ID,这个ID就是offset。
这也就解释了,dl_runtime_resolve如何知道是查找哪个函数。
攻击手段
改写.dynstr节的指针
让这个指针指向我们需要的函数名字符串,例如system字符串
- 缺陷
只有在NO RELRO时候才有权限更改
.dynstr。
伪造结构体
通过栈溢出,让函数返回到<common@plt>中,利用伪造的参数达到调用函数的目的。
因为函数的执行过程就是不断地寻找结构体,从结构体中拿数据,而在函数源码中,并不会检查offset是否会过界,所以我们可以在可控制的地方伪造结构体来达到目的。
-
计算fake_rel和
.rel.plt的距离偏移量作为offset,注意64位需要除以sizeof(ELF32_REL)。 -
伪造一
fake_rel,使他的rel_info字段成为0x******07,这个07是导入函数的参数。暂时不知道干嘛的,但最好不要改。 -
******是指fake_sym距离.dynsym的偏移/sizeof(ELF32_SYM)。 -
fake_sym中st_name是fake_string距离.dynstr的偏移量。