这部分会比较难,比较复杂,建议学习过ELF文件结构的再来读这份代码,这里推荐读完《程序员的自我修养——链接、装载与库》,以及《ARM汇编与逆向工程 蓝狐卷 基础知识》的第二章知识,然后再来看,这一系列文章。
从这篇文章开始,基于aosp8.1加载SO源码的部分研究,打算将分为3篇写完7个加载步骤,流程十分长,学完对ELF的认识就不会只停留在书籍上了,对研究ELF文件格式、so加固将会有所帮助。
还有一篇番外篇,关于自定义Linker的现实,以及结合开源的so脱壳脚本分析。
第一次调用该方法的加载目标so时候,我后面都称为目标so,传递的参数,如下。
代码如下
so的加载都会被封装成一个LoadTask,load_tasks是本次加载任务链表,是一个链表结构,library_names_count是为1,所在在load_tasks当前只有目标so,下面的代码是为soinfo = nullptr,参数传递的是nullptr。进行soinfo空间分配。
代码如下
load_tasks的大小还是只有1,遍历load_tasks然后调用task->get_needed_by();,needed_by代表的是哪个库需要我。举个例子libA -> libB,A依赖B,此时如果加载的task是libB,则get_needed_by得到的则是libA。needed_by是一个链表结构。
根据结果设置task的属性。find_library_internal,方法会把task和load_tasks传递进去
代码如下
find_library_internal方法的代码如下,这里关注主分支代码,find_loaded_library_by_soname获取的不到,然后会往下走,调用load_library方法,如果上面load_library加载不成功,就会到linked_namespaces进去加载load_library是否存在该so,这里不分析linked_namespaces这部分。
代码如下
我们继续看load_library方法的代码,方法有两个重载。我看先看第一个重载的方法。
代码如下
我们关注主分支流程open_library方法
strchr(name, '/') != nullptr根据注释这里说明如果路径包含斜杠/,则去尝试加载,这里我们不分析。然后往下这里分为三部分。
这里有一篇文章写得非常好,229K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3f1#2x3Y4m8G2K9X3W2W2i4K6u0W2j5$3&6Q4x3V1k6@1K9s2u0W2j5h3c8Q4x3X3b7&6y4o6R3&6y4o6u0Q4x3X3b7I4i4K6u0V1x3g2)9J5k6h3S2@1L8h3H3`.,关于Android7.0以上命名空间详解(dlopen限制)。
代码如下
然后接下来直接看open_library_on_paths方法,该方法中,kZipFileSeparator是const char* const kZipFileSeparator = "!/";不是我们分析的类型,不会走该分支,只有是该分支才会走open_library_in_zipfile,
接下来是调用open(buf, O_RDONLY | O_CLOEXEC),这是Linux系统调用,用于打开文件获取文件描述符fd,然后返回。
代码如下
到此,我们继续回到load_library方法,
load_library方法代码片段如下
然后设置task的fd。以及文件偏移。结合AI分析
那这部分对于普通的so应该就是0。
接着load_library方法开始调用load_library的第二个重载
首先是soinfo_alloc,分配soinfo,task->set_soinfo(si);
然后核心是,task调用read方法,这里说结论,read方法会去读取的内容如下
我们直接来到该方法看看这些方法具体怎么做,该方法处于linker_phdr.cpp中
代码如下
我们挨个进去看,ReadElfHeader
pread64就是read系统调用,这里会进行读取fd_,然后读取的大小是sizeof(header_),文件头的大小,读到header_指针处当中,大小是ElfW(Ehdr)类型是elf文件头的大小。VerifyElfHeader则是验证文件头magic、是32-bit还是64-bit、little-endian等等,比较简单就不贴代码了
代码如下
接下来看看ReadProgramHeaders
该方法读取ProgramHeaders,第一个if,说明phdr_num_不得超过2个字节65536,然后根据elf的phdr_num,来计算size_t size = phdr_num_ * sizeof(ElfW(Phdr));,phdr_fragment_.Map会去调用mmap将ProgramHeaders部分映射到内存中,具体的映射结果的地址以及大小,保存在phdr_fragment_类型是 MappedFileFragment当中,至此,程序头表映射完毕。
代码如下
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
最后于 2025-12-3 09:29
被Ayuer编辑
,原因: