type
status
date
slug
summary
tags
category
icon
password

0、前言

创建一个简单的app,里面就是一个数据验证和一句话,然后360免费加固
学习参考来自SWDD大佬和oacia大佬
PKID看确实是360加固
app里的代码:
notion image
mt查看如下:
notion image
notion image
内容如上,输入66才有反应

1、初探

放入jadx,把learn.so放入ida
notion image
java层是可以发现一些蛛丝马迹的,比如这里的libjiagu字符,这是360加固的标志性字符
native层倒是不能直接确定加壳方式

2. java层初步分析

我们在资源目录下找到AndroidManifest.xml
,从里面可以得知360加固的入口是com.stub.StubApp
notion image
因为com.stub.StubApp是第一个实例化的application,且StubAppattachBaseContext方法是加固逻辑的第一个执行入口
我们在这个类中,不仅能看见attachBaseContext还能找到onCreate
Application 的 onCreate 和 attachBaseContext 是 Application 的两个回调方法,通常我们会在其中做一些初始化操作, attachBaseContext 在 onCreate 之前执行
notion image
分析attachBaseContext,中间的内容明显是被加密了的,我们查看a方法
notion image
可以发现其实就是异或16的操作,写脚本解密过后注释上去
notion image
  • 在 Android 9.0 (API 28) 中,Google 限制了非 SDK 接口的访问。这段代码通过反射绕过该限制,确保加固框架能够正常调用系统隐藏 API
  • mHiddenApiWarningShown字段控制隐藏 API 警告的显示,设置为true可避免触发警告
notion image
下面这些内容就是它会判断手机的架构,针对不同的架构加载不同的Native文件
notion image
再往下可以找到DtcLoader初始化的操作,jadx貌似反编译不出来,我们使用jeb
notion image
可以发现它调用了native层的jgdtc.so,当DtcLoader被加载到jvm时,会调用这个so文件,但是我们跟着路径去寻找是找不到这个文件的(看其他文章都略过了,应该不重要。。。)
我们要分析的是libjiagu.so,这个 so 在 assets 目录下

3. 壳elf导入导出表修复

选取libjiagu_a64.so分析,可以发现它导入表导出表都没有内容的,我们需要去修复
先去看看dlopen调用了哪些so文件
notion image
这也是我们要分析的so,需要把libjiagu_64.sodump下来
然后使用Sofixer工具去修复elf
命令如下./SoFixer-macOS-64 -s /Users/lanzhiqiang/Desktop/360test/protect/assets/libjiagu_64.so_Dump -o /Users/lanzhiqiang/Desktop/360test/protect/assets/libjiagu_fix.so -m 0x7250470000 -d
notion image
notion image

4. 壳elf分析

虽然有了导入表和导出表,但是我们还是需要想办法跟踪逻辑找关键函数,那我们就可以hook open函数来看看打开了哪些
notion image
这里可以注意到反复调用了/proc/self/maps,这就是典型的内存映射检测反frida,因为frida使用时会在内存中注入frida-agent.so文件
绕过方式呢也不难,即然它检测的这个maps,那我们就手动调用open函数,在其调用maps时重定向至其他自定义maps即可
比如我在data/data/com.example.learn/下新建了一个maps空文件
然后用如下脚本去看看是否成功 and 调用了哪些dex
notion image
通过返回结果,即可以确定是调用maps去隐藏内存映射,也发现打开了三个dex文件
那么我们就要去追踪这些dex文件的调用情况,即追踪调用栈
我们在上一份代码中加一些内容即可
notion image
这里不管是精确还是模糊,都能看出三个dex文件的调用栈基本一致
根据偏移,我们去ida里寻找
notion image
填充的一堆数据,目前也不知道有啥用,往下继续翻到
notion image
发现被调用了,查看是sub_8510函数
notion image
这里的内容像是so的加载器,这时候是得猜测是自定义linker实现加固so
此时可以hookdlopen验证猜想
  1. 明显重复多次调用libjiagu_64.so,标准调用一般是不会重复调用的
      • 每次加载时解密不同部分的代码,防止一次性获取完整逻辑
  1. 加固后的库被存储在应用私有目录的隐藏文件夹(.jiagu)中
这些信息可以确定它是自定义linker
我们在010中对libjiagu_64.so(壳elf)分析可以找到一个新的elf文件,这里大概率就是上面在ida中找到的自定义linker实现加固so后的so文件
notion image
我们需要想办法把它dump下来
然后我们这里dump出来的main.so就是主elf了

5. 主elf分析

notion image
其实是可以看出elf的program header table
是被加密了的,ida也无法分析
notion image
那我们就需要想办法解密主elf了
壳 elf 在代码中自己实现了解析 ELF 文件的函数,并将解析结果赋值到 soinfo 结构体中,随后调用 dlopen 进行手动加载
  • soinfo 是 Android 系统中用于表示和管理动态链接库 (Shared Object, SO) 的核心结构体,全称为 "Shared Object Information"。它位于 Bionic C 库 (bionic/libc/include/bits/soinfo.h) 中,是动态链接器 (Linker) 的核心数据结构之一
在ida中对dlopen进行交叉引用,查看调用
notion image
notion image
这个函数的内容和AOSP里的linker.cpp源码很像,如下
notion image
notion image
这里基本就是自定义linker实现的预链接函数了,我们需要导入soinfo结构体
在 ida 中依次点击 View->Open subviews->Local Types , 然后按下键盘上的 Insert 将下面的结构体添加到对话框中
导入后,在ida中sub_8510函数的a1进行类型声明soinfo* a1
notion image
但是我们观察一下可以发现,其实360加固里的soinfo是被魔改了的,比如上图中框起来的部分,没有完全修复
向上找调用关系,去看怎么魔改的
notion image
在源码中也可以找到类似的地方
notion image
所以可以直接说sub_4C7C是register_soinfo_tls函数,往里面找到
notion image
这里的0x38,我们在010里看对应关系
notion image
恰好程序头大小也是0x38,那么这个方法肯定就是在加载程序头了
其他的比较乱,我们去找程序执行流,再通过上面发现的内容去推
prelink_image <- sub_4D48 <- sub_4EB0
这是我们在ida里交叉引用的结果,再接下来sub_4EB0 可能被 sub_8510sub_918C 调用,我们看上面的程序流程,可以确定是sub_8510
这个函数并不陌生,我们在分析壳elf时就曾找到过这个函数(世界线收束)
跟着函数调用链一处一处的在 IDA 中跳转到相应的地址进行查看,只用关注这两个函数之间的内容
然后我们找到了rc4的函数sub_6234 # rc4_enc
notion image
找到了rc4的加密部分,还要找初始化部分,对其交叉引用
notion image
notion image
这里没有被识别,按P创建函数
notion image
果然是rc4的init函数,基于对rc4加密的理解,可以确定result就是key,也就是args[0],把它hook出来
刚刚对rc4_enc还原中也可以发现rc4是魔改了的,也hook rc4_enc的传入传出参数看看
notion image
notion image
notion image
我们发现传入的第一个参数是sub_8510的v3[0],也就是qword_3E260数组,第二个参数是sub_8510的v3[1]
而这这个数组的数据就是壳elf填充的,我们解密这一段即可
刚刚分析过程中,知道rc4_enc是魔改过的,且sbox本来是256长度,但他用了257和258,所以我们需要吧sbox hook出来看看(顺便规整这个rc4调用的脚本)
我们就得到了完整的sbox[258],直接解密的结果很混乱,继续看调用链
notion image
我们能找到sub_380C,且它调用了下面inflateInit_inflateinflateEnd三个zlib标准库里面的函数,说明这个函数是解压缩函数,即uncompress
然后我们来尝试解密
notion image
但是解密内容肯定是不对的,不过往下翻还是能找到一个elf
notion image
还需要找其他关键东西
继续看调用链
能看见在sub_55BC里也出现了像样的内容,也有0x38,且这个函数是被sub_4D48所调用的(这个函数同时也调用了preLinker_image,之前分析过)。所以大概率得从这个函数入手分析,从调用链和函数逻辑都合理
最后的逻辑范围被缩小到了sub_5C4C、sub_5794、sub_5950之中,我们挨个找,能发现在sub_5C4C中有很奇怪的逻辑
notion image
这里是ARM64 NEON 的两个指令,用于向量操作,参考:
  • vdupq_n_s8 用于将单个 8 位有符号整数复制到 64 位向量的所有元素
  • veorq_s8 用于对两个 64 位向量的 8 位有符号整数元素进行按位异或运算
notion image
相当于上图,0xBD是要异或的值,后面是长度0x150,依次分组。知道了逻辑就可以继续往下推,在上面解密脚本中添加如下:
notion image
得到四段,前面我们找过program_header_table有6段,每一段0x38,刚好是0x150,这个a正好满足程序头的大小
然后wrap_elf是由两大部分组成的,wrap_elf中分离出来的4大段数据只是第一部分,长度0x25709,但是我们在wrap_elf找到这个位置
notion image
这后面还有一个elf,也就是wrap_elf的第二部分内容,我们把两段分开
然后我们继续观察,.rela.plt.rela.dyn储存的内容是要远远大于dynamic的,所以我们可以锁定dynamic是d
再加上上面我们分析的
一块一块来搞,我们修复的是wrap_elf_part2(主elf)

修复 program header table

复制 libjiagu.so_0x150_a 的所有字节,然后来到 wrap_elf_part2 中选中 struct program_header_table 粘贴
Mac: command+shift+c/v全复制/粘贴

修复 .dynamic

notion image
program header table的(RW_) Dynamic Segment
的p_offset指向.dynamic段的位置
notion image
然后跳转到该位置去修复,同修复program_header_table
notion image
这里来解析一下.dynamic结构

修复重定位表

我们需要通过 .dynamic 段的 d_tag 字段来直到重定位表的位置
对于我们修复主 ELF 比较重要的 tag
d_tag
含义
DT_JMPREL
0x17
.rela.plt 在文件中的偏移
DT_PLTRELSZ
0x2
.rela.plt 的大小
DT_RELA
0x7
.rela.dyn 在文件中的偏移
DT_RELASZ
0x8
.rela.dyn 的大小
我们可以在.dynamic中发现这些tag以及对应的值
notion image
每一个Elf64_Dyn结构大小刚好是16字节,010里面看是一整行,前四个字节代表表项(tag),依次找0x2、0x17、0x7、0x8
就可以知道.rela.plt 在文件中的偏移为0x2C070,大小为0x1818;.rela.dyn 在文件中的偏移0x8490,大小为0x23BE0。这里的值和我们之前分离出的b和c的大小一样,也证明b是.rela.plt,c是.rela.dyn

修复.rela.plt.rela.dyn

同之前的修复方式,根据找到的偏移和大小去复制粘贴
notion image
再把文件基地址设置为0xe7000
notion image
至此,主elf就修复完了

6. dex释放分析

思路跳回到我们hook open函数的结果,同时ida分析刚刚修复好的主elf
notion image
notion image
跳转到0x19F558,很明显的open逻辑,那么这里就是open dex的,继续看下一个0x135d7c
notion image
再往下就是调用libart.so里的内容,所以解密一定在0x135d7c附近
原因:当应用需要访问某个类(如通过反射或直接调用)时,ART 会通过FindClass在已加载的类定义中查找。若类定义未被正确解密,ART 将无法解析其结构,导致加载失败。
在这个地址所在函数上下去尝试hook,之前我们hook的是Android_dlopen_ext,但是由于这个是主elf不是使用上面的加载的了,所以我们得改用对dlopen做hook,最后找到sub_193D78
notion image
notion image
这个函数的第二个参数居然就是我们的dex文件,那么我们想办法dump下来就行
然后我们把这三个dex pull到电脑上
notion image
0.dex即可看到我们最开始自己写的逻辑
至此分析完毕
Hgame2024reversejava反射机制
Loading...
Sh4d0w
Sh4d0w
漫长学习路ing
最新发布
360加固复现学习
2025-6-15
java反射机制
2025-6-14
classLoader机制
2025-6-14
dex文件结构
2025-6-14
APP启动流程
2025-6-14
JNI学习
2025-6-14
公告
Welcome to Sh4dw’s blog!
敬请指导,Q 467194403