好久不见呀~
ret2dl_resolve
与FSOP
等同属于伪造结构体这种利用思路。(简单地划分在栈入门题里我觉得不是很合适…当然一定是因为我菜)本篇记录我调试的详细过程。题目是xdctf2015
的pwn200
原理部分
笔者理解过程主要依靠《程序员的自我修养》和《understanding elf》。活久见! 下功夫去读源码自己构造是想依此来对动态链接过程有一个深刻的认识。学习结构体伪造这类利用方法时发现看源码应该是个必要的步骤…对结构体成员不熟悉很容易觉得题解天书。书本已经讲得比较详细了,再去引用难免有拾人牙慧之嫌。下面只记录一下自己的理解。ling
居然看书le
延迟绑定机制使得程序能够只为实际运行过程中被调用的符号进行绑定,且只在这些符号第一次被调用时花费时间去绑定,这能够有效提升程序运行速度减少不必要的资源浪费。实现这一过程的关键函数是dl_runtime
。
调试
一开始尝试自己构造link_map
的时候因为和构造段表的地方重叠,思路过于混乱,无数次在_dl_runtime_resolve
中被检测到段错误非常心累。于是本辣鸡选择改掉原link_map
中用来定位符号表、字符串表、重定位表的3个字段link_map->l_info[DT_SYMTAB]
,l_info[DT_STRTAB]
,l_info[DT_JMPREL]
使它们指向我构造的三个表。
第一次链接时,向dl_runtime
传入两个参数,一个是link_map
,另一个是偏移reloc_arg
。(这里不太明白gdb
里看到是_dl_runtime_resolve
,去elf/dl-runtime.c
里看却好像是_dl_fixup
)。总之_dl_fixup
函数先通过对link_map->l_info
表的索引获得三个表的地址。
三个表的定义位于
elf/elf.h
中。
指向这三个表的指针被存放在l_info
数组中,其结构为:
1 | typedef struct |
这个结构体中d_ptr
指向的就是表真正所在的地址。
l_info[5]
:字符串表。直接用下标索引,不同字符串之间用\0
分隔
l_info[6]
:符号表。
1 | typedef struct |
l_info[23]
:重定位表。(还有一个结构叫Elf32_Rela
不知道区别是什么)r_info>>4
得到其在符号表中的下标,检测r_info&0xf
是否和某个值相等,代码为assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
后面的宏和平台架构有关。(所以F12直接得到的1026并不正确)其值在sysdeps/i386/dl-machine.h
中可以找到,为7。
1 | typedef struct |
整体流程为,由第二个参数reloc_arg
加上重定位表地址得到对应的重定位表(加的时候加的应该不是sizeof(Elf32_Rel)*reloc_arg
,直接就是reloc_arg
);由该重定位表的r_info
得到其在符号表中下标;从符号表中的st_name
字段得到对应的字符串地址,再从库中找到字符串所在地址填入对应重定位表的r_offset
字段。
1 | from pwn import *;from LibcSearcher import * |
但这种做法当程序关闭输出流时便不奏效了,可拓展性很差。目前还在摸索怎么自己构造link_map
。。下次一定!