能力值:
( LV8,RANK:130 )
|
-
-
26 楼
|
能力值:
( LV2,RANK:10 )
|
-
-
27 楼
谢谢楼主的分享。
|
能力值:
( LV8,RANK:130 )
|
-
-
28 楼
哈哈成功了,请注意啊,如果你用自己的手机做实验,就要把自己手机的那五个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那个
|
能力值:
( LV8,RANK:130 )
|
-
-
29 楼
关于重定位我的观点,大神请绕道,给跟我一样的菜鸟看的
我打个比方,你现在写个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一样了
|
能力值:
( LV2,RANK:10 )
|
-
-
30 楼
大神的代码我已经成功跑通过了,可是在抽取我自己写的一个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?
|
能力值:
( LV2,RANK:10 )
|
-
-
31 楼
我抽取的so执行时找不到dlopen,dlsym等函数,请问这有什么解决办法
|
能力值:
( LV5,RANK:70 )
|
-
-
32 楼
感谢你,最近也在研究thomasking大大的一些列so教程,可否留个联系方式
|
能力值:
( LV2,RANK:10 )
|
-
-
33 楼
请问大家在测试的时候有出现过这个问题吗?
”0 failed to map segment from 'libfoo.so' @ 0x017bf000 (0x000022cb). p_vaddr=0x00000000 p_offset=0x00000000“
errno: 12 (Cannot allocate memory)。
|
能力值:
( LV2,RANK:10 )
|
-
-
34 楼
请问这个问题怎么解决呢?
|
能力值:
( LV3,RANK:30 )
|
-
-
35 楼
感谢楼主!
|
能力值:
( LV5,RANK:70 )
|
-
-
36 楼
你好,请教你个问题,最近在研究这个,在编译大神的Demo时,我的步骤是这样的:
1.把手机中的五个.so文件替换过来;
2.编译没问题,在执行时一直弹出段错误的提示,百度一发说是指针所对应的地址是无效地址,没有物理内存对应该地址,不知道什么原因?求解决万分感谢。。
|
能力值:
( LV2,RANK:10 )
|
-
-
37 楼
请教大神:我抽离完so以后,程序执行的时候,抽离简单的自己写的so,可以正常运行,抽离一些第三方的有JNI_onLoad方法的so,执行完加载程序的JNI_onload方法,就报错了,在 JNI_onload的}的时候报错
|
能力值:
( LV2,RANK:10 )
|
-
-
38 楼
运行的时候,JNI_Onload结束报错
|
能力值:
( LV5,RANK:70 )
|
-
-
39 楼
你好,请问大神,这个问题最后怎么解决的
|
能力值:
( LV4,RANK:50 )
|
-
-
40 楼
先顶一下,后面慢慢看
|
能力值:
( LV2,RANK:10 )
|
-
-
41 楼
正向进行类抽取一直没有学习过,今天仔细的学习了一波,感谢楼主的分享
|
能力值:
( LV3,RANK:30 )
|
-
-
42 楼
这个加固方案不通用啊 只能自己手机使用
|
能力值:
( LV2,RANK:10 )
|
-
-
43 楼
感谢楼主提供的学习总结及学习思路, 但是有一点要吐槽下,代码逻辑编写得是真的乱, 既然已经开源,最好稍稍加些备注。 了解了思路,结合看代码理解逻辑感觉多发了2倍时间。不过还是作者的文章,让我学到了很多东西
|
|
|