首页
社区
课程
招聘
[原创]自定义Linker SO修复
发表于: 2026-7-2 16:40 3428

[原创]自定义Linker SO修复

2026-7-2 16:40
3428

看之前最好是对linker相关的知识有一定了解,这里推荐文章Android从ELF-Loader到自定义Linker的实现及原理,该文章写的很详细,很好。

因为这是一个壳so(Shell SO)内嵌一个so(Payload SO)。system.loadlibray加载壳so,遵循linker加载so的流程。内嵌so是由壳so通过自定义Linker去加载。

本文目的主要针对壳so和内嵌so的修复,方便IDA等工具分析。

ida加载so,主要可以看到这里,大部分节区信息都被抹掉,导致ida无法正常识别。因为ida是静态分析的,所以依赖section节区。

这里的sub_2A30sub_2A50很明显分别是dlopendlsym,但是这里也没有识别出来。

所以后面需要把壳入口.init_array系统函数进行修复还原。

这里会优先执行.init_array节区里的函数,所以先找到这个节区里有哪些函数。

PT_DYNAMIC:动态链接信息节

Program里 PT_DYNAMIC(.dynamic) 找 DT_INIT_ARRAY(d_tag: 0x19)和 DT_INIT_ARRAYSZ (d_tag: 0x1b)

.dynamic里每个表项数据有16字节,相关结构如下。

typedef struct {

Elf64_Sxword d_tag;

union {

} d_un;

} Elf64_Dyn;

.dynamic表数据:

19 00 00 00 00 00 00 00 08 4D 01 00 00 00 00 00

DT_INIT_ARRAY:0x14D08

1B 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00

DT_INIT_ARRAYSZ: 0x10

这里可以看到,.init_array节区起始是0x14D08,大小为0x10个字节,每8个字节为1个函数槽,也就是有两个函数槽在里面。

进入ida查看,这里的地址0x14D08里面怎么没有对应存储的函数呢,接下来就要去.rela.dyn里去找0x14D08地址存储的函数。因为这里是变量赋值,所以要去重定位表.rela.dyn里查看。

这里在节表里没有发现.rela.dyn,看来也是抹除了,所以需要再去.dynamic里找到.rela.dyn并修复。

.dynamic表获取对应数据

07 00 00 00 00 00 00 00 E8 26 00 00 00 00 00 00

DT_RELA : 0x26e8

08 00 00 00 00 00 00 00 48 00 00 00 00 00 00 00

DT_RELASZ: 0x48

然后点开节表所有的SHN_UNDEF,找里面的s_type为SHT_RELA的节,这里找到两个重定位表,那么用哪一个呢?因为.rela.dyn的s_info为0,所以这里我们就选s_info为0的节。

把上面获取的0x26e8和0x48对应填入。然后s_name的偏移也要在.shstrtab里找到.rela.dyn的字符串偏移。

然后F5刷新下修改的文件。

ida打开,在ida里可以看到,有需要被修复的地址就自动填充进去了,这里只有一个函数槽需要被修复。

但是这样感觉还不得劲,想让它的.init_array节区显示出来,继续去SHN_UNDEF找s_type为SHT_INIT_ARRAY

修复后:

这里的s_offset可以不填。我们只保证虚拟内存地址(s_addr)是正确的就行了。

进入ida可以看到.init_array已经被修复了。

进入0x4780系统函数,明显看出sub_2A30是dlopen函数,sub_2A50是dlsym函数,但是这里都是以函数偏移显示的,没有正常的符号名。那么接下来就要修复这类符号名显示问题。

看.dynsym是否正常显示

看来.dynsym里的所有数据也是被抹除了。

06 00 00 00 00 00 00 00 00 90 16 00 00 00 00 00

DT_SYMTAB: 0x169000

原始的是0x2268,所以这里是假的.dynsym。

修复后:

为什么这里s_offset是0x129000?

这里有个小细节,一个程序头表是由多个节表组成,程序头表里,p_offset和p_vaddr的差值是多少,那么应用在对应的节表里时,s_offset和s_addr也应该是这个差值。ida这里工具解析ELF文件时,会以内存的模式去加载,这里就会去把物理文件的偏移s_offset的数据复制到虚拟内存的偏移s_addr处。

因为0x169000刚好处在segment 0x47000~(0x47000+0x1256d0) 这个范围里。p_vaddr是在p_offset的基础上增加了0x40000。所以这里文件偏移应该是0x169000-0x40000=0x129000

函数在010Editor里已经能正常显示了,这里就好了吗?不是,还需要去修复.rela.plt 函数重定位表。

17 00 00 00 00 00 00 00 30 27 00 00 00 00 00 00

DT_JMPREL:0x2730

02 00 00 00 00 00 00 00 40 02 00 00 00 00 00 00

DT_PLTRELSZ:0x240

修复后:

s_flags: 这里需要的模式是ALLOC|INFO_LINK,也就是0x42。

s_link: 链接的节.dynsym,在节表的索引。

s_info: 这是got/.got.plt表在节表的索引。

由上可知,s_info我们还不清楚是多少,并且节表字符串里有.got,这里我们要去修复.got表。

怎么选?

只要s_type为SHT_PROGBITS ,s_flags为SF64_Alloc_Exec ,都可以作为.got表。这里就选节表索引14作为.got表。

查询.dynamic

03 00 00 00 00 00 00 00 18 4F 01 00 00 00 00 00

DT_PLTGOT: 0x14f18

.got表的大小需要自己计算,上面已知DT_PLTRELSZ大小为0x240,因为.rela.plt的每项大小为24字节,这里就有0x240/24=24 个函数,并且.got表的前3个槽位是填充,每个槽位大小为8字节,这里.got size则为(24+3)*8=0xd8

修复后:

这里.got表也修复了,接着就可以补全上面.rela.plt的s_info信息,也就是got表在节表的索引为0xE

ida查看,这里函数符号也都能正常显示了

这里是在init_array里进行内嵌so的解密操作,并用自定义linker去加载内嵌so

init_array的运作函数sub_4780

这些地址处的数据比较重要

dword_15040 = dword_15008;

dword_15064 = dword_1500C;

dword_15078 = dword_15010;

dword_15030 = dword_15014;

dword_15088 = dword_15018;

dword_15084 = dword_1501C;

dword_1507C = dword_15020;

dword_15040:内嵌so在壳so的起始地址

dword_15064:壳.dynsym节区的大小

dword_15078:壳.dynstr节区的大小

dword_15030:壳.dynsym节区在内存里的地址(s_addr)

dword_15088:壳.dynstr节区在内存里的地址(s_addr)

dword_15084:壳.hash节区在内存里的地址(s_addr)

dword_1507C:解密内嵌so的密钥偏移地址

垃圾代码,主要是干扰静态分析的,不用理会

读取dword_1507C地址0x14个字节的内容到qword_15050处,前16个字节是rc4解密的密钥,后4个字节是异或解密的密钥(这里值是单字节)。

010Editor查看可知

rc4密钥:2F CE A7 38 12 73 AC 59 57 7E 56 B5 5F 59 C9 85

xor密钥字节:0x95

sub_3184:rc4解密函数

sub_2B1C:xor异或解密函数

这里解密内嵌so前0x1000字节内容,主要解密出程序头表的内容。用于后续装载PT_Load段数据,和重定位修复。

解密PT_Load

这里是解密第二个PT_Load段

从内嵌so偏移64字节开始解密,这里是解密第一个PT_Load段


[招生]科锐逆向工程师培训(2026年7月3日实地,远程教学同时开班, 第56期)!

最后于 2026-7-2 16:41 被九天666编辑 ,原因:
收藏
免费 0
打赏
分享
最新回复 (29)
雪    币: 9172
活跃值: (7612)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2026-7-2 17:14
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
学习
2026-7-2 17:24
0
雪    币: 324
活跃值: (1965)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
学到了
2026-7-2 17:25
0
雪    币: 1551
活跃值: (5358)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
5
666
2026-7-2 20:17
0
雪    币: 3953
活跃值: (5199)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学习一下
2026-7-2 21:39
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
666
2026-7-2 23:25
0
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
向大佬学习
2026-7-3 08:40
0
雪    币: 6417
活跃值: (11497)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
2026-7-3 09:36
0
雪    币: 200
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
tql
2026-7-3 09:50
0
雪    币: 743
活跃值: (920)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
牛逼,感谢分享,看完了,学到了很多
2026-7-4 05:32
0
雪    币: 4888
活跃值: (6035)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
6
2026-7-4 13:51
0
雪    币: 158
活跃值: (2456)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
感谢分享
2026-7-4 14:00
0
雪    币: 556
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
感谢分享,学习
2026-7-4 14:20
0
雪    币: 102
活跃值: (3886)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
15
第一步那里,直接在elf头里把节偏移地址清0,再用ida打开,init_array就正常了。
2026-7-4 15:05
0
雪    币: 59
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
感谢分享,学习
2026-7-4 15:12
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
666
2026-7-4 20:07
0
雪    币: 4461
活跃值: (7467)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
18
感谢分享
2026-7-4 20:36
0
雪    币: 159
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
19
66
2026-7-7 03:14
0
雪    币: 548
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
学习了
2026-7-7 09:57
0
雪    币: 112
活跃值: (9015)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
tql
2026-7-7 16:09
0
雪    币: 234
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
22
666
2026-7-7 18:31
0
雪    币: 3525
活跃值: (3696)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
终于看到有好文章了. 而不是AI文.
2026-7-8 09:29
0
雪    币: 0
活跃值: (300)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
感谢分析
2026-7-9 09:52
0
雪    币: 219
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
25
666
2026-7-10 17:40
0
游客
登录 | 注册 方可回帖
返回