ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ELF文件格式之.plt与.got表

2022-05-20 02:01:16  阅读:198  来源: 互联网

标签:__ 定位 plt ELF Elf32 地址 文件格式 got


重定位

windows系统

mov eax, [0x50010];
  • 数据重定位:在windows操作系统上全局数据的重定位是通过重定位表来实现的,例如上述代码,0x50010地址存放的数全局数据,默认的加载地址是0x40000,那么加载地址变为0x30000时,需要在程序加载时由windows加载器利用重定位表将0x50010数据修正为0x50010-0x40000 + 0x30000 = 0x40010。而mov eax,[0x50010]对应的机器码为A1 10000500, mov eax,[0x40010]对应的机器码为A1 10000400,所以操作系统只需要将10000500改为10000400即可。
  • 地址重定位:对于外部函数调用通过输入表进行重定位。

linux系统

因为windows操作系统的数据重定位操作需要修改代码部分,linux为了方便将数据重定位抽离出来避免修改代码。这样做也可能与linux有时候使用arm指令集有关,因为arm指令集采用位解析(精简指令集),所以不像x86那样好修改。

.plt表与.got表

外部函数引用重定位

通过readelf查看elf文件的所有节区section

linux使用.plt表存放外部函数调用的PLT条目,通过.plt索引到.got表中对应函数调用的实际地址(got表有点windows中的输入地址表的意思)。
例如_start函数调用libc.so的导出函数__libc_init()。
指令ADR R12, 0x504是将相对于当前PC偏移0x504的值传给R12,因为arm指令是三级流水线,执行此条指令时pc指针指向第三条指令即PC值为0x504。索引R12 = 0x504 + 0x504
指令ADD R12,R12,#0x3000是将R12 = R12 + 0x3000 = 0x504 + 0x504+ 0x3000
指令LDR PC,[R12,#(__libc_init_ptr -0x3504 )]将PC = [R12 + __libc_init_ptr - 0x3504] = [0x504 + 0x504+ 0x3000 + __libc_init_ptr - 0x3504] = [0x504 + __libc_init_ptr], 而当前指令的地址为0x504,而__libc_init_ptr是plt条目对应的.got表项的相对于当前指令地址的偏移,所以最后将.got表中实际的函数地址传给PC并调用。

注意:(因为0x504相当于执行第一条指令得到的当前指令的地址,所以无论程序加载何处都没关系,总结为 plt表条目相当于做了一件事 :LDR PC,[当前指令地址 + 函数对应.got表项偏移])

__libc_init_ptr是plt条目对应的.got表项的相对于调用指令地址的偏移,.got表项中存放的是实际调用的外部函数的地址,需要在程序加载时由linker程序修复,(windows输入表修复)。

全局数据重定位

windows上全局数据重定位直接通过重定位表修改对应的指令机器码,但是linux上的arm指令的机器码是精简指令集修改比较复杂,linux通过.got表实现全局数据的重定位。

以访问全局数据__PREINIT_ARRAY__为例
指令LDR R1, =(__PREINIT_ARRAY___ptr - 0x568)是将R1 = __PREINIT_ARRAY___ptr - 0x568
指令LDR R1,[PC,R1]是将R1 = [PC + R1] = [PC + __PREINIT_ARRAY___ptr - 0x568 ] ,因为当前pc的值第三条指令的地址为0x568,而__PREINIT_ARRAY___ptr为全局数据__PREINIT_ARRAY__对应的.got表项相对于当前指令的偏移,R1 = [__PREINIT_ARRAY___ptr ]相当于获取了实际全局数据__PREINIT_ARRAY__的地址赋给R1.

__PREINIT_ARRAY___ptr为相对于全局数据访问指令地址的偏移,指向.got表项中存放的是对应全局数据实际的地址,会在程序加载的时候修复。

结论

liunx的外部函数引用重定位与全局数据重定位都是通过.got表实现的,其中外部函数引用重定位还需要.plt表参与。.got表中存放的是所有需要重定位修复的地址信息(32位就每4个字节一项,64位就每8个字节一项)。
注意:.plt表也属于程序代码

操作系统如何进行重定位

在程序加载时.got表中的数据要进行重定位,那么操作系统是如何索引到.got表并进行重定位呢?

.rel.dyn表和.rel.plt表

通过readelf可以查看到这两个表,直接在ida中是查看不到的。(两个表相当于widnwos PE中的重定位表)

struct Elf32_Dyn
{
  Elf32_Sword d_tag;
  union{
        Elf32_Word d_val;
        Elf32_Addr d_ptr;
    }d_un;
};
}

这两个节区可以通过.dynamic节区(等同于DYNAMIC program)找到,.dynamic节区是一个Elf32_Dyn数组,数组每一项都会描述一个特定类型的节区,d_tag为其对应的类型。其中DT_REL类型为.rel.dyn节区,DT_JMPREL为.rel.plt节区。而d_ptr就指向其节区对应的偏移地址。

typedef struct {
        Elf32_Addr      r_offset;
        Elf32_Word      r_info;
} Elf32_Rel;

.rel.dyn包含了除外部函数引用外需要重定位的数据的信息,.rel.plt包含了外部函数引用需要重定位的数据的信息。二者都是一个Elf32_Rel类型的数组。
r_offset:对于可重定位文件,该值表示节偏移。对于可执行文件或共享目标文件,该值表示受重定位影响的存储单元的虚拟地址。(最终指向.got表)

r_info:指定了需要重定位数据的符号表索引以及要应用的重定位类型。(如果需要重定位的是一个外部函数引用地址,那么就要包含函数名称信息)。计算方法如下。

#define ELF32_R_SYM(info)             ((info)>>8)
#define ELF32_R_TYPE(info)            ((unsigned char)(info))
#define ELF32_R_INFO(sym, type)       (((sym)<<8)+(unsigned char)(type))

我们以.rel.plt中的需要冲定位的__libc_init函数的Elf32_Rel结构为例进行解析。
r_offset为0x3FF0,指向对应的.got表项的虚拟地址。

r_info为0x316, ELF32_R_SYM(0x316) == 3,对应在.dynsym符号表中的索引为3。

typedef struct {
        Elf32_Word      st_name;
        Elf32_Addr      st_value;
        Elf32_Word      st_size;
        unsigned char   st_info;
        unsigned char   st_other;
        Elf32_Half      st_shndx;
} Elf32_Sym;

.dynsym符号表为一个Elf32_Sym类型的数组,st_name为对应在字符串表.dynstr中的偏移,此处为0x22。

总结

linux在加载elf文件时就是通过.rel.dyn 和.rel.plt找到对应的符号信息并修正对应.got表项中的信息。
注意:elf的输入表HOOK就是通过在.dynsym字符串表中查找需要hook的函数名称,然后计算出对应的符号表索引。通过符号表索引在.rel.dyn和.rel.plt表中寻找对应的项进而找到对应的.got表项并更改地址为自己的地址。

标签:__,定位,plt,ELF,Elf32,地址,文件格式,got
来源: https://www.cnblogs.com/revercc/p/16290945.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有