-
-
[分享]unicorn模拟linker加载so
-
发表于: 1天前 429
-
搭框架
新建一个项目,然后把ElfParser直接拿来用

把ElfParser当作模块





然后测试一下test能不能跑起来

新建r0dbg-android模块


新建包


导入模块


然后把框架搭好

加载
然后就可以实现linker了
从dl_open开始,对比着源码一点点复写


do_dlopen的返回值是soinfo,我们也创建个soinfo对象命名为ElfModule

find_library 中 调用了find_library_library_internal返回了soinfo指针,然后做了个引用计数,si->ref_count为0才能释放



find_library_library_internal

elfName的优先级高

find_loaded_library,维护一个列表,如果该so文件已经加载过就不会重复加载

load_library中就是打开该so文件,然后初始化一个ElfReader对象,调用elf_reader.Load方法,最后给soinfo对象初始化一些值

Load方法

ReadElfHeader是读elf头 ,VerifyElfHeader是验证elf头格式是否有问题,ReadProgramHeader是读程序头


对应java代码,前三步在ElfFile对象初始化中已经完成





往下看ReserveAddressSpace,主要是调用phdr_table_get_load_size方法,重要的是load_bias_, 他是实际内存地址和期望内存地址的差值。比如实际内存地址为0x1000,期望内存地址为0x100,
比如elf文件中要找0x1200,0x1200-0x100=x-0x1000, x=0x2100 , 所有0x1200在实际内存中被映射到0x2100, 那么0x1200+(0x1000-0x100)就能找到0x2100

phdr_table_get_load_size中做的事情就是遍历所有程序头,只取p_type=PT_LOAD的元素,找到所有PT_LOAD元素中p_vaddr的最小值赋值给min_vaddr,找到p_vaddr+p_memsz最大值赋值给max_vaddr, 然后页对齐,最后返回所有PT_LOAD段所需内存大小。

ReserveAddressSpace对应的java代码


然后看LoadSegments, 就是把PT_LOAD段加载到内存


loadSegments中存放的都是PT_LOAD段,就不用再筛选了


然后回到上面的load_library方法


链接
以上就加载完了,接下来是 链接 和重定位,回到上面代码

接下来看soinfo_link_image





对应的java代码

找到PT_DYNAMIC段

找到所有tag=DT_NEEDED,意思是需要依赖的其他so文件

dt_StringTable的赋值在这里


dtNeeded的赋值

接下来看重定位操作,soinfo_relocate方法
前置:







然后看soinfo_do_lookup



然后看soinfo_elf_lookup


对应的java代码是一样的操作


这里只是单纯的去依赖库里面找

初始化
完成链接和重定位后,回过头来看初始化 ,先调用依赖模块的初始化函数,然后调用自己的初始化函数



对应的java实现

模拟执行

注:上述内容均为unidbg原理与实操课程内容,复写一遍使自己记忆深刻一些