时间不是很充裕,有一些细节没有完善,有兴趣的可以深入分析、比如后续 GOT 链接这些的...本人也是刚学
分析一款可以共享密码的解压缩 app,其中用到了 native 的知识点
本文将介绍两种 native 解密方法


其中 getQPWAT 调用 libZMCoreUnZip.so 的 executeGBS native 方法
发现能识别 elf,但是 export 符号很奇怪,不是可见字符,且指示条不正常

发现 JNI_OnLoad export 不存在,所以看 init_array

发现不是很好找,这里根据 elf 结构我们可以直接根据 Elf64_Dyn 类型引用定位到 ELF Dynamic Information 然后找到 DT_INIT_ARRAY


随后发现 init_array 均为空值 0,说明需要重定向。
查看 DT_RELA 元素为 Elf64_Rela
注意我们需要 r_info == 0x403 的项目,且 r_offset 需要位于 [DT_INIT_ARRAY, DT_INIT_ARRAY + DT_INIT_ARRAYSZ) 之中,即 [0x55DB00, 0x55DB00+0x20)

所以 init_array 为
可以通过编写以下脚本来应用重定向
借助 ai 分析,能够找到关键全局变量并创建结构体
三个 init 函数分别有以下功能
注意到:
dynstr_dynsym_decode_Impl @ 0x54D6B8 做两件事:先解 .dynstr,再修 .dynsym
给出修复脚本
函数概括为六个阶段:
RuntimeMalloc、RuntimeFree、RuntimeMemcpy 等名称对应 API 表里的 libc 函数;AcquireFlag4String/AcquireFlag8String/AcquireFlag10String 只是按控制它们的 flag 命名,具体业务语义仍未确认。
该样本将会执行两次 core_decode 而不执行 xor_decode_fixed_key_blocks
sub_557170 @ 0x557170 是壳内置 zlib 的一次性解压包装器,参数语义与 uncompress2() 基本一致:
zlib 解压后的 main_payload 输出长度为 0x530268
以下 Elf64_Phdr 来自于第一次 core_decode 解出的 metadata 开头
metadata 开头连续保存 6 个 Elf64_Phdr;筛选 p_type == PT_LOAD 后得到:
完整运行时映射为:
第二段的 p_memsz - p_filesz = 0x30,第三段为 0xB848;这两块段尾内存必须清零。
当前 IDB 的 VA 0..0x18F 已经保存原始 ELF header 和 Program Header Table,为了避免静态 patch 时覆盖这些结构,可以仅对首段执行:
编写 test 脚本
将原来的前 0x190 字节复制到 dump 的即可分析
其实还应该解密 elf 最后的 .data 段用于实现 GOT、LPT 定位的,但是比较麻烦就先不做了(分配到动态内存中了),而上述静态分析方法可以直接解密(或者这里结合一下静态的脚本解密一下也可以),下面给出一个工具脚本,用于 patch GOT,当然不使用也可以
| 顺序 |
动作 |
结果 |
| 1 |
dlopen("libc.so") |
获得 libc 句柄 |
| 2 |
dlsym("__system_property_get") |
获得系统属性读取函数 |
| 3 |
读取 ro.build.version.sdk |
记录 Android SDK 版本 |
| 4 |
打开 /proc/self/maps |
枚举当前进程映射 |
| 5 |
按 "%lx-%lx %4s %*x %*x:%*x %*d%n" 解析映射行 |
获得区间和页权限 |
| 6 |
结合 SDK、模块位置和权限写入全局状态 |
给 init3 与 load2_load_packed_segments 使用 |
| item |
value |
DT_SYMTAB |
0x55FD38 |
DT_STRTAB |
0x5BA5E8 |
DT_STRSZ |
0x817E0 |
DT_HASH.nchain |
0x2F28 |
loader_meta.sym_index_begin |
0x3A |
loader_meta.sym_index_end |
0x2F28 |
loader_meta.dynsym_seed3 |
0x815C0 |
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!