首页
社区
课程
招聘
[原创] 通过问题来理解linker01-为什么PT_LOAD有2段Maps文件有3段
2021-11-17 09:47 19748

[原创] 通过问题来理解linker01-为什么PT_LOAD有2段Maps文件有3段

2021-11-17 09:47
19748

为什么so里面有两个PT_LOAD段, 在maps文件里面却有三段映射

最新在做https://bbs.pediy.com/thread-270030.htm的分析研究, 主要目的是避免监守自盗, 同时也希望在实战中学习,在分析的过程中就遇到了一些疑惑

1
其中一个疑惑便是为什么elf文件里面只有2个段, 但是到内存后却有3段映射.

这里尝试做一些解答.

对应现象

  1. 通过ida观察elf具有两个PT_LOAD段

linker

  1. 通过maps文件观察, 具有3个映射段

linker

  1. 通过源码观察, 确实只加载2个段

linker

内核层mmap观察分配情况

1
2
3
4
5
6
7
130|OnePlus7T:/data/local/tmp # dmesg -w|grep kr|grep sotest
[ 3142.307841] [info]kr_mmap mmap file libsotest.so. vaddr=0x7b51953000, len=0x1d0 prot=1, off=0x0(ReadProgramHeaders)
[ 3142.307861] [info]kr_mmap mmap file libsotest.so. vaddr=0x7b51952000, len=0xae0 prot=1, off=0x35000(ReadSectionHeaders)
[ 3142.307891] [info]kr_mmap mmap file libsotest.so. vaddr=0x7b51950000, len=0x1ca0 prot=1, off=0x34000(ReadDynamicSection)
[ 3142.307906] [info]kr_mmap mmap file libsotest.so. vaddr=0x7b5194f000, len=0xaeb prot=1, off=0x0(ReadDynamicSection)
[ 3142.308172] [info]kr_mmap mmap file libsotest.so. vaddr=0x7abcd88000, len=0x34988 prot=5, off=0x0(LoadSegments)
[ 3142.308199] [info]kr_mmap mmap file libsotest.so. vaddr=0x7abcdcc000, len=0x11f8 prot=3, off=0x34000(LoadSegments)

通过上面的日志信息可以了解到, linker在Android10上面总计进行了6次mmap, 分别为

 

(1) ReadProgramHeaders

 

(2) ReadSectionHeaders

 

(3) ReadDynamicSection

 

(4) ReadDynamicSection

 

(5) LoadSegments(通过文件偏移, 可以知晓这里对应elf的第一个段)

 

(6) LoadSegments(通过文件偏移, 可以知道这里对应elf的第二个段)

 

其中最后2次映射由LoadSegments引发,也就是我们真正要关注的问题点. 通过mmap观察走两次mmap为正常行为,为什么maps有3段呢? 我们还需要进一步分析, 因此我又hook了mprotect的方法

 

(tips: 如果大家仔细观察, 这里又会有另外一个小疑问, 为什么mmap的偏移是0x34000, 但是elf的fileoffset是0x34D18. 这里后面再做详细解答)

详细堆栈信息如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
----------------------------------
kr_openat tgid=7635 path=/proc/7635/maps
kr_openat vaddr=0x7b51953000
        pc=0x7b52dace58 sp=0x7fe046bc00 c->sp=0x7fe046bc00 c->pc=0x7b52dace58 regs_len=320 stack_len=1024 path_len=1024
        #00 0x7b52dace58 /apex/com.android.runtime/bin/linker64+fce58(__dl_mmap64)
        #01 0x7b52cff5e8 /apex/com.android.runtime/bin/linker64+4f5e8(__dlMappedFileFragment::Map(int, long, unsigned long, unsigned long))
        #02 0x7b52cffeb0 /apex/com.android.runtime/bin/linker64+4feb0(__dlElfReader::ReadProgramHeaders())
        #03 0x7b52cff790 /apex/com.android.runtime/bin/linker64+4f790(__dlElfReader::Read(char const*, int, long, long))
        #04 0x7b52cf35ac /apex/com.android.runtime/bin/linker64+435ac(__dlload_library(android_namespace_t*, LoadTask*, std::__1::vector<LoadTask*, std::__1::allocator<LoadTask*> >*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool))
        #05 0x7b52cf23f0 /apex/com.android.runtime/bin/linker64+423f0(__dlload_library(android_namespace_t*, LoadTask*, ZipArchiveCache*, std::__1::vector<LoadTask*, std::__1::allocator<LoadTask*> >*, int, bool))
----------------------------------
kr_openat tgid=7635 path=/proc/7635/maps
kr_openat vaddr=0x7b51952000
        pc=0x7b52dace58 sp=0x7fe046bc00 c->sp=0x7fe046bc00 c->pc=0x7b52dace58 regs_len=320 stack_len=1024 path_len=1024
        #00 0x7b52dace58 /apex/com.android.runtime/bin/linker64+fce58(__dl_mmap64)
        #01 0x7b52cff5e8 /apex/com.android.runtime/bin/linker64+4f5e8(__dlMappedFileFragment::Map(int, long, unsigned long, unsigned long))
        #02 0x7b52d000b4 /apex/com.android.runtime/bin/linker64+500b4(__dlElfReader::ReadSectionHeaders())
        #03 0x7b52cff79c /apex/com.android.runtime/bin/linker64+4f79c(__dlElfReader::Read(char const*, int, long, long))
        #04 0x7b52cf35ac /apex/com.android.runtime/bin/linker64+435ac(__dlload_library(android_namespace_t*, LoadTask*, std::__1::vector<LoadTask*, std::__1::allocator<LoadTask*> >*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool))
        #05 0x7b52cf23f0 /apex/com.android.runtime/bin/linker64+423f0(__dlload_library(android_namespace_t*, LoadTask*, ZipArchiveCache*, std::__1::vector<LoadTask*, std::__1::allocator<LoadTask*> >*, int, bool)
----------------------------------
kr_openat tgid=7635 path=/proc/7635/maps
kr_openat vaddr=0x7b51950000
        pc=0x7b52dace58 sp=0x7fe046bbf0 c->sp=0x7fe046bbf0 c->pc=0x7b52dace58 regs_len=320 stack_len=1040 path_len=1024
        #00 0x7b52dace58 /apex/com.android.runtime/bin/linker64+fce58(__dl_mmap64)
        #01 0x7b52cff5e8 /apex/com.android.runtime/bin/linker64+4f5e8(__dlMappedFileFragment::Map(int, long, unsigned long, unsigned long))
        #02 0x7b52d00630 /apex/com.android.runtime/bin/linker64+50630(__dlElfReader::ReadDynamicSection())
        #03 0x7b52cff7a8 /apex/com.android.runtime/bin/linker64+4f7a8(__dlElfReader::Read(char const*, int, long, long))
        #04 0x7b52cf35ac /apex/com.android.runtime/bin/linker64+435ac(__dlload_library(android_namespace_t*, LoadTask*, std::__1::vector<LoadTask*, std::__1::allocator<LoadTask*> >*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool))
        #05 0x7b52cf23f0 /apex/com.android.runtime/bin/linker64+423f0(__dlload_library(android_namespace_t*, LoadTask*, ZipArchiveCache*, std::__1::vector<LoadTask*, std::__1::allocator<LoadTask*> >*, int, bool)
----------------------------------
kr_openat tgid=7635 path=/proc/7635/maps
kr_openat vaddr=0x7b5194f000
        pc=0x7b52dace58 sp=0x7fe046bbf0 c->sp=0x7fe046bbf0 c->pc=0x7b52dace58 regs_len=320 stack_len=1040 path_len=1024
        #00 0x7b52dace58 /apex/com.android.runtime/bin/linker64+fce58(__dl_mmap64)
        #01 0x7b52cff5e8 /apex/com.android.runtime/bin/linker64+4f5e8(__dlMappedFileFragment::Map(int, long, unsigned long, unsigned long))
        #02 0x7b52d006a8 /apex/com.android.runtime/bin/linker64+506a8(__dlElfReader::ReadDynamicSection())
        #03 0x7b52cff7a8 /apex/com.android.runtime/bin/linker64+4f7a8(__dlElfReader::Read(char const*, int, long, long))
        #04 0x7b52cf35ac /apex/com.android.runtime/bin/linker64+435ac(__dlload_library(android_namespace_t*, LoadTask*, std::__1::vector<LoadTask*, std::__1::allocator<LoadTask*> >*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool))
        #05 0x7b52cf23f0 /apex/com.android.runtime/bin/linker64+423f0(__dlload_library(android_namespace_t*, LoadTask*, ZipArchiveCache*, std::__1::vector<LoadTask*, std::__1::allocator<LoadTask*> >*, int, bool)
----------------------------------
kr_openat tgid=7635 path=/proc/7635/maps
kr_openat vaddr=0x7abcd88000
        pc=0x7b52dace58 sp=0x7fe046c050 c->sp=0x7fe046c050 c->pc=0x7b52dace58 regs_len=320 stack_len=16304 path_len=1024
        #00 0x7b52dace58 /apex/com.android.runtime/bin/linker64+fce58(__dl_mmap64)
        #01 0x7b52d00be4 /apex/com.android.runtime/bin/linker64+50be4(__dlElfReader::LoadSegments())
        #02 0x7b52d007fc /apex/com.android.runtime/bin/linker64+507fc(__dlElfReader::Load(address_space_params*))
        #03 0x7b52cea6e4 /apex/com.android.runtime/bin/linker64+3a6e4(__dlLoadTask::load(address_space_params*))
        #04 0x7b52ce9d04 /apex/com.android.runtime/bin/linker64+39d04(__dlfind_libraries(android_namespace_t*, soinfo*, char const* const*, unsigned long, soinfo**, std::__1::vector<soinfo*, std::__1::allocator<soinfo*> >*, unsigned long, int, android_dlextinfo const*, bool, bool, std::__1::vector<android_namespace_t*, std::__1::allocator<android_namespace_t*> >*))
        #05 0x7b52cecba0 /apex/com.android.runtime/bin/linker64+3cba0(__dldo_dlopen(char const*, int, android_dlextinfo const*, void const*))
        #06 0x7b52ce80dc /apex/com.android.runtime/bin/linker64+380dc(__dl___loader_android_dlopen_ext)
        #07 0x7b4df5b0b8 /apex/com.android.runtime/lib64/bionic/libdl.so+10b8
        #08 0x7b4e2dcfd8 /apex/com.android.runtime/lib64/libnativeloader.so+7fd8
        #09 0x7b4e2dcc5c /apex/com.android.runtime/lib64/libnativeloader.so+7c5c
        #10 0x7acb748938 /apex/com.android.runtime/lib64/libart.so+37b938
        #11 0x7ac16e10e0 /apex/com.android.runtime/lib64/libopenjdkjvm.so+50e0
        #12 0x7164aaf4 /system/framework/arm64/boot.oat+b9af4
----------------------------------
kr_openat tgid=7635 path=/proc/7635/maps
kr_openat vaddr=0x7abcdcc000
        pc=0x7b52dace58 sp=0x7fe046c050 c->sp=0x7fe046c050 c->pc=0x7b52dace58 regs_len=320 stack_len=16304 path_len=1024
        #00 0x7b52dace58 /apex/com.android.runtime/bin/linker64+fce58(__dl_mmap64)
        #01 0x7b52d00be4 /apex/com.android.runtime/bin/linker64+50be4(__dlElfReader::LoadSegments())
        #02 0x7b52d007fc /apex/com.android.runtime/bin/linker64+507fc(__dlElfReader::Load(address_space_params*))
        #03 0x7b52cea6e4 /apex/com.android.runtime/bin/linker64+3a6e4(__dlLoadTask::load(address_space_params*))
        #04 0x7b52ce9d04 /apex/com.android.runtime/bin/linker64+39d04(__dlfind_libraries(android_namespace_t*, soinfo*, char const* const*, unsigned long, soinfo**, std::__1::vector<soinfo*, std::__1::allocator<soinfo*> >*, unsigned long, int, android_dlextinfo const*, bool, bool, std::__1::vector<android_namespace_t*, std::__1::allocator<android_namespace_t*> >*))
        #05 0x7b52cecba0 /apex/com.android.runtime/bin/linker64+3cba0(__dldo_dlopen(char const*, int, android_dlextinfo const*, void const*))
        #06 0x7b52ce80dc /apex/com.android.runtime/bin/linker64+380dc(__dl___loader_android_dlopen_ext)
        #07 0x7b4df5b0b8 /apex/com.android.runtime/lib64/bionic/libdl.so+10b8
        #08 0x7b4e2dcfd8 /apex/com.android.runtime/lib64/libnativeloader.so+7fd8
        #09 0x7b4e2dcc5c /apex/com.android.runtime/lib64/libnativeloader.so+7c5c
        #10 0x7acb748938 /apex/com.android.runtime/lib64/libart.so+37b938
        #11 0x7ac16e10e0 /apex/com.android.runtime/lib64/libopenjdkjvm.so+50e0

补全hook信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[18391.525011] [info]kr_mmap mmap file libsotest.so. vaddr=0x7b5195a000, len=0x1d0 prot=1, off=0x0
[18391.525027] [info]kr_mmap mmap file libsotest.so. vaddr=0x7b51959000, len=0xae0 prot=1, off=0x35000
[18391.525055] [info]kr_mmap mmap file libsotest.so. vaddr=0x7b51957000, len=0x1ca0 prot=1, off=0x34000
[18391.525069] [info]kr_mmap mmap file libsotest.so. vaddr=0x7b51956000, len=0xaeb prot=1, off=0x0
[18391.525315] [info]kr_mmap mmap file libsotest.so. vaddr=0x7abcd16000, len=0x34988 prot=5, off=0x0
[18391.525343] [info]kr_mmap mmap file libsotest.so. vaddr=0x7abcd5a000, len=0x11f8 prot=3, off=0x34000
[18391.525629] [20211115_17:03:46.098714]@6 [info]kr_mprotect start=0x7abcd5a000 len=0x1000 prot=1(关键信息)
[18391.525670] [20211115_17:03:46.098754]@6 [info]kr_mprotect start=0x7b51955000 len=0x1000 prot=1
[18391.525769] [20211115_17:03:46.098853]@6 [info]kr_mprotect start=0x7b51b82000 len=0x64000 prot=1
[18391.525851] [20211115_17:03:46.098936]@6 [info]kr_mprotect start=0x7b51c3a000 len=0x64000 prot=1
[18391.525933] [20211115_17:03:46.099017]@6 [info]kr_mprotect start=0x7b51aeb000 len=0x64000 prot=1
[18391.526019] [20211115_17:03:46.099104]@6 [info]kr_mprotect start=0x7b51a87000 len=0x64000 prot=1
[18391.533599] [20211115_17:03:46.106682]@6 [info]kr_mprotect start=0x7a63101000 len=0x2c000 prot=3
[18391.533950] [20211115_17:03:46.107034]@6 [info]kr_mprotect start=0x7a63101000 len=0x1a2b8 prot=5
[18391.534488] [20211115_17:03:46.107573]@6 [info]kr_mprotect start=0x7a63132000 len=0x12000 prot=3
[18391.534601] [20211115_17:03:46.107685]@6 [info]kr_mprotect start=0x7a63132000 len=0xa78 prot=5
[18391.534683] [20211115_17:03:46.107768]@6 [info]kr_mprotect start=0x7a63101000 len=0x2c000 prot=3

第二次采集的时候通过hook补全了mprotect权限, 发现为了一行关键信息. linker使用mprotect进行了权限修改, 因此内核层便进行了maps分割

 

这里简单画了下对应信息, 方便能够理解背后的行为.

 

20211116191000

 

通过上面的分析的,便解答了心中的疑惑. 那么我们进一步思考linker为什么需要进行上面的行为呢? 这个问题我们就需要去linker源码里面寻找答案了,

 

堆栈信息已经给我们提供了阅读代码的线索, 我们也就可以去大海里遨游不怕迷路了.

linker LoadSegments详细分析

ElfReader::ReadProgramHeaders 进行mmap, 在析构函数进行 munmap

 

ElfReader::ReadSectionHeaders 后续再分析

 

ElfReader::ReadDynamicSection 后续再分析

 

ElfReader::ReadDynamicSection 后续再分析

 

ElfReader::LoadSegments 这里进行一下详细阐述, linker其实是操作系统和elf的连接器, 既要满足elf的要求, 又要满足mmap的一些限制.

 

比如:

 

mmap需要按页分配, elf需要对齐

 

下图详细描述了虚拟地址空间映射和so文件之间的关系

 

linker

 

因为mmap时使用但是PAGE_START(phdr->p_offset), elf的fileoffset是0x34D18, 向上页对齐便是0x34000. 心里的疑惑也就解开了.

 

.bss 也叫做全局变量段

待解答疑问

  1. mprotect由谁调用的,目的是什么?

其他比较好的讲解

liner底层原理

欢迎同行一起交流

https://github.com/yhnu/op7t


[培训]《安卓高级研修班(网课)》月薪三万计划

最后于 2021-11-17 09:48 被github_yhnu编辑 ,原因:
收藏
点赞2
打赏
分享
最新回复 (2)
雪    币: 902
活跃值: (1120)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
血舞长空 2021-11-17 16:20
2
0
发现了对我的分析,楼主对系统的研究很深啊,”mprotect由谁调用的,目的是什么?“,这个问题不是你自己也说了吗,"linker使用mprotect进行了权限修改",然后极其非常粗略又粗暴的解析:alloc出来是rw,mmap之后是r,所以根据PT_LOAD的flags字段,code段被mprotect成rx,bss段被mprotect成rw
雪    币: 26
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
github_yhnu 2021-11-23 11:02
3
0
血舞长空 发现了对我的分析,楼主对系统的研究很深啊,”mprotect由谁调用的,目的是什么?“,这个问题不是你自己也说了吗,"linker使用mprotect进行了权限修改",然后极其非常 ...
 这个问题已经知晓了, github的链接里面有补充. 你的so分析后面再发出来哈
游客
登录 | 注册 方可回帖
返回