首页
社区
课程
招聘
[原创]SO文件格式及linker机制学习总结(1)
2015-2-2 16:38 55171

[原创]SO文件格式及linker机制学习总结(1)

2015-2-2 16:38
55171
收藏
点赞4
打赏
分享
最新回复 (42)
雪    币: 191
活跃值: (195)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
大王叫我挖坟 3 2016-5-27 09:38
26
0
仔细看了代码,在函数load_NeededLibray里面需要载入libfoo.so依赖的so文件啊,所以呢那些so需要复制到Mini_elf_generate编译的同目录就行了,跟libfoo.so放在一个目录,,,,但是还是崩溃,找到函数了崩溃,正在调试中
雪    币: 435
活跃值: (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
qqsunqiang 2016-5-27 10:03
27
0
谢谢楼主的分享。
雪    币: 191
活跃值: (195)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
大王叫我挖坟 3 2016-5-27 18:14
28
0
哈哈成功了,请注意啊,如果你用自己的手机做实验,就要把自己手机的那五个so拷贝到跟Mini_elf_generate同一个目录啊,因为作者大大,在运行Mini_elf_generate的时候就需要那5个so里面的函数重定位把函数地址重新写到libfoo.so的rel结构里面去啊,记得必须是自己手机的不能用,作者的因为,函数地址不一样啊,libfoo.so调用那些函数找不到地址会崩溃的!!!!!!!!!!!!!!!!!!thomasking偶像大大,总结一下,做个记录希望帮助别人
7.rel.plt节和rel.dyn节
//#define ELF32_R_SYM(x) ((x) >> 8)
//#define ELF32_R_TYPE(x) ((x) & 0xff)
//#define R_ARM_JUMP_SLOT        22        /* Create PLT entry */
//#define R_ARM_ABS32        2        /* Direct 32 bit  */
//#define R_ARM_GLOB_DAT        21        /* Create GOT entry */     
#define R_ARM_RELATIVE                23        /* Adjust by program base */

typedef struct elf32_rel {
  Elf32_Addr        r_offset;//重定位结束后的地址,如果是自己的函数或者自己的变量就存放自己的地址如
,thomasking大大那个linker连接器,是解析非R_ARM_RELATIVE把别的库里面的函数地址就写到了
这个r_offset里面了
.fini_array:00003EA8 20 0C 00 00                 DCD sub_C20
data:00004004 AC 22 00 00 off_4004        DCD aGetstring          ; DATA XREF: JNI_OnLoad+34o

同时
Relocation section '.rel.dyn' at offset 0xaf8 contains 12 entries:
Offset     Info    Type            Sym.Value  Sym. Name
00003ea8  00000017 R_ARM_RELATIVE
00004004  00000017 R_ARM_RELATIVE

//包含两个信息,
//用unsigned sym = ELF32_R_SYM(rel->r_info)就是.dynsym节的索引,第几项,
//用ELF32_R_TYPE(r_info)就是类型,如R_ARM_JUMP_SLOT
  Elf32_Word        r_info;  //uint32_t
} Elf32_Rel;

rel.plt节是重定位的函数,也就是so调用的外部函数,来得到外部函数的地址,定位完毕,会把地址存在got表里面

找到函数重定位之后的地址的办法,也是got hook的办法
计算函数hash值,然后根据.dynstr+.hash+dynsym得出,此函数是.dynsym节内容的第几项(symidx )

.rel.plt段中
ELF32_R_SYM(rel.r_info) == symidx && ELF32_R_TYPE(rel.r_info) == R_ARM_JUMP_SLOT

.rel.dyn段中
ELF32_R_SYM(rel.r_info) == symidx &&(ELF32_R_TYPE(rel.r_info) == R_ARM_ABS32
ELF32_R_SYM(rel.r_info) == symidx && ELF32_R_TYPE(rel.r_info) == R_ARM_GLOB_DAT)

就找到了,那个rel.r_offset就是地址啦,替换掉他就是传说中的got hook了
(1)R_ARM_ABS32          .rel.dyn节中 是调用别的so的函数,用函数指针来调用,而且是全局函数指针
(2)通过全局函数指针的方式调用外部函数,它的重定位类型是R_ARM_ABS32,并且位于节区**
整个重定位过程是先位到.got,再从.got定位到.date

(2)R_ARM_GLOB_DAT   .rel.dyn节中 是调用别的so的函数,用函数指针来调用,而且是局部函数指针
过局部函数指针方式调用外部函数它的重定位类型是R_ARM_GLOB_DAT,并

(3)R_ARM_JUMP_SLOT   .rel.plt节中 是调用别的so的函数,纯正调用函数
就是另外一个so里面的函数,直接调用外部函数,它的重定位类型是R_ARM_JUMP_SLOT,并且位于.re.plt节区,
其Offset指向最终调用函数地址的地址(也就是函数指针的指针)**。整个过程是先到.plt,再到.got,
最后才定位到真正的函数地址。

第四种,R_ARM_RELATIV=0x17也是rel.dyn中  自己so里面的函数指针啊,字符串指针啊,等等反正自己的
奇怪为什么got的hook不用这种,这样就可以hook自己的程序字符串?函数指针感觉也没啥用哦!
,在进行重定位时候,就是填写so自己的base,这种用于函数自己的指针,如函数指针啊,char *等等
如果是这个则
unsigned sym = ELF32_R_SYM(rel->r_info);  sym=0;
si->symtab[sym].st_shndx==0;是dynsym节的第一个全00那个
雪    币: 191
活跃值: (195)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
大王叫我挖坟 3 2016-5-27 19:04
29
0
关于重定位我的观点,大神请绕道,给跟我一样的菜鸟看的
我打个比方,你现在写个so叫mytest.so,里面打印log了,需要调用_android_log_print函数是吧,怎么调用了,这个函数在liblog.so里面,这就涉及重定位了,是linker帮助我们完成的过程如下
1.linker加载mytest.so到内存,然后根据dynamic的类型遍历其段结构,得到.hash,.dynstr,dynsym,rel.plt和.got结构
填充其值到soinfo结构体里面,如rel.plt是的首地址和大小soinfo->plt_rel和soinfo->plt_rel_count 这两个里面

2.for循环soinfo->plt_rel_count得到每一项需要重定位的信息,他们的结构是
typedef struct elf32_rel {
Elf32_Addr        r_offset;
        Elf32_Word        r_info;  //uint32_t
} Elf32_Rel;

然后用ELF32_R_SYM(rel->r_info)作为索引(比如值是sym=6),ELF32_R_SYM只是一个宏,#define ELF32_R_SYM(x) ((x) >> 8),,作为索引,到自己的.dynsym节找第几项,那就是第6项,funcname=si->strtab + si->symtab[sym].st_name得到要重定位的函数名,,,注意现在得到名字了,

3、在别的so里面找,在liblog.so里面找,hashval = elfhash(funcname)得到哈希值,然后如果
for(i = bucket[hashval % nbucket]; i != 0; i = chain[i]){
strcmp(strtab + symtab[i].st_name, name)
我们得到symtab[i].st_value//这是个地址,就是我们要找的函数在liblog.so里面的地址了
}
(就表示找到了,注意这里strtab 和symtab可是liblog.so里面的哟,其实linker会遍历很多so,然后把他们存放在soinfo数组里面,看linker.c源码知道最大是128个)
好我们得到这个地址的值了,把这个值填充到si->r_offset里面,哈哈就完成重定位了,
关于跟GOT的关系
比如,si->offset=0x3FE8,我们得到的地址是0x123456,那么重定位完毕后
03FE8: 56 43 21 ;别看ida瞎扯淡,那个401c不是值

还跟plt有关系

.rel.dyn跟这个的区别是

.rel.dyn是调用别的函数的函数指针,和自己的指针
Rel.plt是直接调用别的函数的函数指针罗

//-----------对于rel.dyn的got是

如果是自己的函数指针如,aNativeStringRe则直接填写地址ida给你分析出来了,是224c,等下重定位就加上自己的base就行了,对于调用别人so用函数指针来调用,如__gnu_Unwind_Find_exidx_ptr就跟那个rel.plt一样了
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
十一回武汉 2016-6-16 14:54
30
0
大神的代码我已经成功跑通过了,可是在抽取我自己写的一个so的时候遇到了些问题。这里是我的so的两个PT_LOAD段的信息:
p_offset  0h         p_offset  0x2ea4h
p_vaddr  0h         p_vaddr  0x3ea4h
p_filesz  7993       p_filesz   380
p_memsz 7993         p_memsz  380

按照大神的 load_segment中的方法进行映射,第一个PT_LOAD段的起始位置应该是
[si->base,si->base+0x2000h), 第二个PT_LOAD段起始位置是[si->base+0x3000h,si->base+0x5000h). 观察地址后发现两个LOAD段是不连续的,中间断了1000h,于是我的so抽取就失败了。而我以前成功抽取的so中,两个LOAD段的地址计算出来正好是连续的。
我想知道各位大神有没有遇到过这样的问题,应该怎么处理这种so?
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
十一回武汉 2016-6-17 16:00
31
0
我抽取的so执行时找不到dlopen,dlsym等函数,请问这有什么解决办法
雪    币: 3712
活跃值: (1291)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
不知世事 1 2016-7-14 15:12
32
0
感谢你,最近也在研究thomasking大大的一些列so教程,可否留个联系方式
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
njhu 2016-9-2 11:48
33
0
请问大家在测试的时候有出现过这个问题吗?

”0 failed to map segment from 'libfoo.so' @ 0x017bf000 (0x000022cb). p_vaddr=0x00000000 p_offset=0x00000000“

errno: 12 (Cannot allocate memory)。
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
njhu 2016-9-21 14:34
34
0
请问这个问题怎么解决呢?
雪    币: 346
活跃值: (25)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
OnlyForU 2016-9-21 15:27
35
0
感谢楼主!
雪    币: 3712
活跃值: (1291)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
不知世事 1 2016-9-22 10:12
36
0
你好,请教你个问题,最近在研究这个,在编译大神的Demo时,我的步骤是这样的:
1.把手机中的五个.so文件替换过来;
2.编译没问题,在执行时一直弹出段错误的提示,百度一发说是指针所对应的地址是无效地址,没有物理内存对应该地址,不知道什么原因?求解决万分感谢。。
雪    币: 57
活跃值: (30)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ylmylm杨 2016-9-22 18:15
37
0
请教大神:我抽离完so以后,程序执行的时候,抽离简单的自己写的so,可以正常运行,抽离一些第三方的有JNI_onLoad方法的so,执行完加载程序的JNI_onload方法,就报错了,在 JNI_onload的}的时候报错
雪    币: 57
活跃值: (30)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ylmylm杨 2016-9-27 18:24
38
0
运行的时候,JNI_Onload结束报错
雪    币: 3712
活跃值: (1291)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
不知世事 1 2016-10-20 15:38
39
0
你好,请问大神,这个问题最后怎么解决的
雪    币: 224
活跃值: (16)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
zhoujiamur 1 2016-11-18 20:32
40
0
先顶一下,后面慢慢看
雪    币: 62
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
toToC 2017-5-14 17:55
41
0
正向进行类抽取一直没有学习过,今天仔细的学习了一波,感谢楼主的分享
雪    币: 348
活跃值: (486)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
liumengde 2018-1-24 21:13
42
0
这个加固方案不通用啊  只能自己手机使用
雪    币: 3916
活跃值: (5815)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
huangjw 2021-10-20 14:45
43
0
感谢楼主提供的学习总结及学习思路, 但是有一点要吐槽下,代码逻辑编写得是真的乱, 既然已经开源,最好稍稍加些备注。 了解了思路,结合看代码理解逻辑感觉多发了2倍时间。不过还是作者的文章,让我学到了很多东西
游客
登录 | 注册 方可回帖
返回