地址重定位与GOT/PLT机制

1.地址重定位与GOT/PLT机制

地址重定位与GOT/PLT机制详解

地址重定位
  • 定义与作用
    地址重定位是将程序中的逻辑地址(编译时生成的虚拟地址)转换为运行时物理地址的过程,确保程序在内存中任意位置正确运行。其核心解决多道程序环境下地址冲突、内存共享及动态加载问题,通过静态或动态方式实现地址映射。
  • 类型
    • 静态重定位:程序加载时一次性完成地址转换,位置固定(如早期系统),无法移动。
    • 动态重定位:运行时通过硬件(如MMU)动态调整地址,支持程序在内存中移动,提升灵活性和内存利用率。
GOT(全局偏移表)机制
  • 结构与功能
    GOT是数据段中的数组,存储外部符号(函数、全局变量)的实际地址。典型布局包括:
    • GOT[0]:指向动态链接元数据(.dynamic段地址)。
    • GOT[1]:动态链接器标识(如link_map结构地址)。
    • GOT[2]:动态链接器入口函数(如_dl_runtime_resolve)。
    • 其余条目:外部函数/变量的实际地址,支持位置无关代码(PIC)。
  • 工作原理
    程序通过访问GOT获取符号地址。例如,调用printf时,先读取GOT中printf的地址条目,直接跳转或取值。动态链接器在运行时解析符号地址并更新GOT,实现动态绑定。
PLT(过程链接表)机制
  • 结构与流程
    PLT是代码段中的短代码片段,每个外部函数对应一个条目,典型结构为:
    • jmp *GOT[entry]:跳转到GOT中该函数的地址。
    • push $symbol_id:压入符号标识符(用于动态链接器解析)。
    • jmp PLT[0]:跳转到动态链接器入口。
  • 延迟绑定(Lazy Binding)
    首次调用函数时,PLT检查GOT地址是否已解析。若未解析,触发动态链接器解析符号地址,更新GOT后跳转;后续调用直接通过GOT跳转,避免重复解析开销。此机制显著提升程序启动速度和内存效率。
  • 示例
    调用printf时,先跳转到printf@plt,检查GOT中printf地址。首次调用时,GOT指向PLT的解析逻辑,动态链接器解析真实地址并写入GOT;后续调用直接通过GOT跳转。
GOT与PLT的协同
  • 动态链接核心
    GOT存储地址,PLT处理跳转逻辑,两者配合实现动态链接。GOT提供地址存储,PLT负责调用路径的动态解析,共同支持延迟绑定、共享库更新及运行时符号解析。
  • 性能优势
    延迟绑定减少启动时符号解析开销,仅当函数首次调用时解析地址,优化内存和CPU资源。例如,未使用的函数不会加载,提升程序启动速度和运行效率。
  • 安全性与防御
    • GOT劫持攻击:攻击者通过缓冲区溢出等漏洞修改GOT条目,重定向函数调用至恶意代码。防御措施包括:
      • ASLR(地址空间布局随机化):随机化GOT内存位置,增加攻击难度。
      • RELRO(重定位只读):标记GOT为只读,防止非法修改。
      • 栈保护(Canary):防止栈溢出攻击,间接保护GOT。
应用场景与案例
  • Linux动态链接库
    在ELF格式中,GOT和PLT是动态链接的关键组件。例如,libc.so中的函数通过PLT/GOT机制被程序调用,动态链接器在运行时解析地址并更新GOT。
  • 安全漏洞利用
    GOT劫持常见于CTF题目或实际攻击中,通过覆盖GOT条目实现任意代码执行。例如,将exit函数的GOT条目修改为恶意代码地址,触发后执行攻击代码。
总结

地址重定位解决程序运行时地址映射问题,而GOT/PLT机制通过动态链接和延迟绑定,实现高效、灵活的符号解析和函数调用。两者协同工作,不仅提升程序性能和内存效率,还支持共享库的动态更新和安全防护。理解这些机制对系统编程、漏洞分析和性能优化具有重要意义。

2.全局偏移表

全局偏移表(GOT)详解

定义与核心作用

全局偏移表(Global Offset Table,简称GOT)是动态链接中用于存储外部符号(如函数、全局变量)地址的关键数据结构。它允许程序在运行时解析符号地址,支持动态加载共享库(如Linux的.so、Windows的.dll)和模块化编程。GOT通过地址无关代码(PIC)技术,使程序在内存中的位置无关,提升代码复用性和内存效率。

结构与组成
  • ELF格式(Linux/Unix)
    • .got段:存储全局变量的地址。
    • .got.plt段:存储函数的地址,与过程链接表(PLT)配合使用。
    • 特殊条目
      • GOT[0]:指向.dynamic段(包含动态链接信息)。
      • GOT[1]:动态链接器标识(如link_map对象)。
      • GOT[2]:动态链接器的延迟绑定函数地址(如_dl_runtime_resolve)。
  • PE格式(Windows):类似结构为导入地址表(IAT),功能与GOT一致。
工作机制
  1. 首次调用
    • 程序调用外部函数时,通过PLT跳转到GOT对应条目。
    • 若地址未解析(首次调用),动态链接器(如ld-linux.so)解析符号,将真实地址填入GOT,并跳转到目标函数。
  2. 后续调用
    • 直接通过GOT跳转,无需重新解析,提升效率。
  3. 地址计算
    • 编译器通过_GLOBAL_OFFSET_TABLE_符号定位GOT基址,结合偏移量访问符号地址。
与PLT的协作
  • PLT(过程链接表):存储跳转指令,初始指向动态链接器。首次调用时触发解析,后续直接跳转到GOT中的真实地址。
  • 延迟绑定:通过GOT[2]的_dl_runtime_resolve函数实现按需加载,减少启动开销。
安全风险与防护
  • GOT覆盖攻击
    • 利用缓冲区溢出等漏洞修改GOT条目,劫持程序流(如将fflush的GOT地址覆盖为system("/bin/cat flag"))。
  • 防护措施
    • ASLR(地址空间布局随机化):随机化内存布局,增加攻击难度。
    • NX(不可执行内存):禁止执行栈上的恶意代码。
    • Stack Canaries:检测栈溢出。
    • 代码签名与验证:确保动态库合法性。
跨平台实现差异
  • Linux/Unix:ELF格式明确区分.got.got.plt,支持复杂重定位(如R_X86_64_GLOB_DAT、R_X86_64_JUMP_SLOT)。
  • Windows:PE格式的IAT直接映射导入函数地址,结构更紧凑。
  • Android/嵌入式系统:通过.so动态库和GOT实现跨平台兼容,支持热更新。
应用场景
  • 动态加载:运行时加载共享库,如插件系统、热修复。
  • 逆向工程:通过修改GOT实现函数拦截(如Android逆向中替换系统调用)。
  • 性能优化:减少静态链接的内存占用,提升程序启动速度。
总结

GOT是动态链接的核心枢纽,通过运行时地址解析平衡了灵活性与性能。其设计需兼顾效率与安全,现代系统通过ASLR、NX等技术强化防护。理解GOT机制对开发安全代码、进行系统级优化及逆向分析至关重要。

3.程序中的逻辑地址指什么

程序中的逻辑地址(Logical Address),也称为虚拟地址(Virtual Address),是程序在运行时由CPU生成的地址,它与实际内存中的物理地址(Physical Address)不同,是操作系统和硬件共同构建的抽象层的一部分。以下从多个维度详细解释:

1. 核心定义与作用

  • 抽象隔离:逻辑地址是程序视角的“内存地址”,程序无需关心实际物理内存的布局(如内存碎片、多任务共享内存等),只需使用连续的逻辑地址空间即可。例如,一个程序可能认为自己独占从0x0000到0xFFFF的连续地址空间,但实际物理内存可能被分割存储。
  • 内存管理基础:操作系统通过内存管理单元(MMU,Memory Management Unit)将逻辑地址动态映射到物理地址,实现内存的保护、共享、虚拟内存(如硬盘交换)等功能。

2. 与物理地址的区别

对比维度逻辑地址物理地址
生成主体CPU执行程序时生成(如指令中的地址)内存控制器实际访问的硬件地址
可见性对程序可见(程序员/编译器使用)对程序不可见(由硬件和操作系统管理)
连续性程序视角连续(如数组、函数地址)实际物理内存可能非连续(碎片化)
映射依赖需通过MMU或页表转换直接对应内存硬件单元(如电容、寄存器)

3. 逻辑地址的生成与转换

  • 编译/链接阶段:编译器将源代码中的变量、函数地址转换为相对地址(如相对于段基址的偏移量)。例如,C语言中int a = 10;的变量a可能被分配到数据段的偏移量0x100处,此时逻辑地址为数据段基址+0x100
  • 运行时动态转换:CPU执行指令时,逻辑地址(如mov eax, [0x100])被送入MMU,MMU结合页表(Page Table)段寄存器(如CS、DS),将逻辑地址拆分为页号/段号页内偏移/段内偏移,最终转换为物理地址。例如:
    • 分页系统:逻辑地址 = 页号(高10位)+ 页内偏移(低12位),MMU通过页表查到页号对应的物理页框号,拼接后得到物理地址。
    • 分段系统:逻辑地址 = 段选择子(索引段表)+ 段内偏移,段表记录段的基址和长度,确保访问不越界。

4. 关键应用场景

  • 内存保护:通过逻辑地址到物理地址的映射,操作系统可限制程序访问非法内存(如其他进程的数据、内核空间),提升安全性。
  • 虚拟内存:逻辑地址空间可远大于物理内存(如32位程序有4GB逻辑地址空间,但物理内存可能仅8GB),通过“按需调页”(Demand Paging)将不常用的页存到硬盘,实现“大地址空间”的假象。
  • 地址重定位:静态重定位(编译时确定物理地址,已过时)与动态重定位(运行时由MMU完成,主流方式)的区别,动态重定位支持程序在内存中动态加载(如动态链接库)。
  • 多任务共享:不同进程可使用相同的逻辑地址(如都从0x0000开始),但通过不同的页表映射到不同的物理地址,实现进程隔离。

5. 实际例子

假设一个程序尝试访问逻辑地址0x2000:

  1. CPU将0x2000送入MMU。
  2. 若采用分页(页大小4KB),0x2000的二进制为0010 0000 0000 0000,页号=0x2(高10位),页内偏移=0x0(低12位)。
  3. MMU查页表,发现页号0x2对应物理页框号0x5000。
  4. 物理地址 = 0x5000 << 12(页框基址) + 0x0(偏移) = 0x50000000。
  5. 内存控制器访问物理地址0x50000000,完成数据读取。

总结

逻辑地址是程序在抽象内存空间中的“虚拟坐标”,通过硬件(MMU)和操作系统(页表、段表)的协作,映射到物理内存的实际位置。这种抽象不仅简化了程序设计(无需考虑物理内存细节),还实现了内存保护、虚拟内存、多任务隔离等核心功能,是现代操作系统和计算机体系结构的关键设计之一。

4.过程链接表

过程链接表(PLT)详解

定义与核心作用

过程链接表(Procedure Linkage Table, PLT)是动态链接(如ELF格式)中的关键数据结构,主要用于实现函数调用的延迟绑定(Lazy Binding)地址重定向。其核心作用包括:

  • 间接跳转:作为程序调用外部函数(如动态库函数)的中间层。
  • 地址解析延迟:首次调用函数时解析其绝对地址,后续调用直接跳转,提升启动性能。
  • 支持位置无关代码(PIC):使代码可加载到任意内存地址,增强安全性和灵活性(如ASLR)。

工作机制

1. 结构与初始化

  • PLT条目:每个动态链接的程序或共享库包含一个PLT,每个条目对应一个全局函数,包含跳转代码(如jmp [GOT+offset])。
  • GOT(全局偏移表):与PLT协同工作,存储函数地址。初始时,GOT表项指向PLT中的下一条指令(如push操作地址),形成“自调用”结构。

2. 首次调用流程

  1. 程序调用:程序调用func@plt(如gets@plt),跳转到PLT入口。
  2. 初始跳转:PLT条目中的jmp [GOT+offset]跳转到GOT表项指向的地址(初始为PLT下一条指令)。
  3. 压栈与跳转:执行push $n(保存函数ID)后,跳转到动态链接器(如ld.so)的解析函数(如_dl_runtime_resolve)。
  4. 地址解析:动态链接器根据函数ID查找符号表,定位真实函数地址(如libc.so中的gets)。
  5. 更新GOT:将真实地址写入对应GOT表项,并跳转到目标函数执行。

3. 后续调用

  • 直接跳转:GOT表项已存储真实地址,后续调用直接通过jmp [GOT+offset]跳转,无需解析。

关键组件协作

组件作用示例地址/结构
PLT提供跳转桩代码,包含初始化跳转和解析调用流程0x400550 <gets@plt>
GOT存储函数实际地址(初始指向PLT解析流程,解析后更新为真实地址)0x601030
动态链接器解析符号地址并更新GOT表(如_dl_runtime_resolveld.so

优势与应用场景

优势

  • 启动优化:延迟绑定减少程序启动时的符号解析开销。
  • 内存效率:共享库代码段可被多进程共享,节省内存。
  • 安全性:支持ASLR,通过位置无关代码增强系统安全性。
  • 灵活性:动态库可独立更新,无需重新链接整个程序。

应用场景

  • 动态链接库(.so/.dll):实现函数调用的动态解析。
  • 调试与性能分析:通过objdump -d查看PLT/GOT条目,分析函数调用路径。
  • 安全防护:控制GOT表写入可防止部分ROP攻击。
  • 预链接(prelink):减少运行时解析开销,优化性能。

技术细节与扩展

  • 汇编代码示例
    
    

    assembly

    10x400550 <gets@plt>:
    2   jmp    QWORD PTR [rip+0x2009fa]  ; 跳转到GOT表项
    3   push   0x2                       ; 函数ID压栈
    4   jmp    0x4005a0                  ; 跳转到公共解析器
  • 重定位类型:如R_386_RELATIVER_386_GLOB_DATR_386_JMP_SLOT,用于动态链接时的地址修正。
  • GOT特殊项.got.plt的前三项存储动态段地址、link_map结构地址和解析函数地址,后续项存储外部函数地址。

与静态链接的对比

特性静态链接动态链接(PLT/GOT)
代码复制全部代码复制到可执行文件共享库代码按需加载,多进程共享
启动速度快(无解析开销)慢(首次调用需解析)
内存占用高(每个进程独立副本)低(共享库代码共享)
更新维护需重新链接整个程序只需更新共享库

总结

过程链接表(PLT)是动态链接的核心机制,通过延迟绑定和地址重定向,平衡了程序启动性能与运行时效率,支持位置无关代码和共享库的高效利用。其与GOT的协同工作,构成了现代操作系统中动态链接的基础,广泛应用于程序开发、系统安全和性能优化场景。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值