frida和逆向的学习
0-前言
之前用frida只晓得使用已经构建好的js,还是系统的学习一下比较好,遇到一些自定义的类也可以自己解决,可以去看大佬们的frida操作手册、某加固新版frida检测绕过-trace、某当劳 Frida 检测,哔哩哔哩上也有相关课程吾爱破解安卓逆向入门教程《安卓逆向这档事》_哔哩哔哩_bilibili、小肩膀出品安卓逆向课程_哔哩哔哩_bilibili、Python入门/Frida逆向 哔哩哔哩_bilibili等
写在前言:单纯绕过root的话直接拖入白名单让它检测不到su环境即可
体会就是:只要有执行权限的都避免不了被hook
用ai编写unidbg进行分析的化,如果是标准版的话,推荐用两个ai,一个专门处理报错,因为ai给的方法很多都不是标准的
app里的so是我随便找的一个有加壳的,如有不合适的地方请联系我删除,水平有限,记录的东西存在错误请多指教
工具:frida+jadx+ida.pro+unidbg+SoFixer
注:unidbg有很多魔改版
可以先熟悉前端的js逆向再深入app的逆向,有很多相通的地方前端游走
1-Java层hook(py)
js是弱参数类型,java是强参数类型,注意转换
普通方法
1>常规hook:
var 类名 = java.use(包名.类名);
类名.方法名.implementation = 具体function函数
构造方法
1 | #特征--构造方法 |
1>常规hook更改$init:
var 类名 = java.use(包名.类名);
类名.$init.implementation = 具体function函数
重载方法
1 | #特征--多个相同方法不同传入参数类型 |
1>常规hook+overload():
var 类名 = java.use(包名.类名);
类名.方法名.overload("int").implementation = 具体function函数
注意String为java系统类
String是单独一个在lang包里面的类,可以在jre里面的lib的rt.jar压包里面找到String.class,示例:
类名.方法名.overload("java.lang.String").implementation = 具体function函数
2>传入对象参数
1 | #传参为自定义的对象 |
#重载hook+类路径
类名.方法名.overload("java.lang.String").implementation = 具体function函数
更改入参
注:
1 | send()比console.log输出多,可以直接输出object的结构 |
1 | var 类名1 = java.use('com.xxx.xxx.类名'); |
更改属性
1 | send(实例化对象test.name); |
反射
可以反射给其他语言例如C++来操作
1 | #类的构造器 |
2-实际生产环境
逆向思路与web的js逆向相似,但存在难点如下
①反调试(Process terminated)
②app自杀逻辑Native 层(C/C++)
③架构不匹配(直接用真机)
常见知识学习
1>>常见调用栈
①android.* 开头的类是 Android 系统自带的 SDK 标准库(系统 UI/框架库)
②非 android 开头的类(例如 com.netease.nis.\*): 这些是 App 自身的代码 或 第三方加固/安全 SDK 的代码
当 App 被“加壳”或集成了安全检测时,你会看到这些特定公司的包名。
com.netease.nis.\*/com.netease.secure.\*: 网易易盾。com.tencent.StubShell.\*/com.tencent.msdk.\*: 腾讯乐固/MSDK。com.secshell.\*/com.secneo.\*: 梆梆加固。com.aliyun.nex.\*: 阿里聚安全。com.qihoo.util.\*/com.qihoo360.\*: 360 加固。
③java.lang.*是java的公开接口,有些脚本可以打印出app调用了哪些jdk的类
④dalvik.system.VMStack.getThreadStackTrace: Java 必须请求 Android 虚拟机(Dalvik 或 ART) 帮忙;虚拟机底层逻辑 (dalvik.* / libcore.*)
这些属于 Android 运行环境(ART/Dalvik)的最底层。
dalvik.system.VMStack: 负责处理虚拟机内部的堆栈,通常出现在调用栈的最顶部(因为你在获取堆栈)。dalvik.system.DexClassLoader: 说明 App 正在动态加载插件或.dex文件(很多加固包会用到)。libcore.io.\*: 处理底层的底层文件读写、网络连接。
⑤okhttp3.*常见的第三方功能库
如果调用栈里出现这些,说明正在执行某些具体功能(如网络请求、图片加载):
okhttp3.\*/retrofit2.\*: 正在进行网络请求。com.google.gson.\*/com.alibaba.fastjson.\*: 正在解析 JSON 数据。com.bumptech.glide.\*: 正在加载图片。kotlinx.coroutines.\*: 正在执行 Kotlin 协程(异步任务)。
⑥com.miui.*, com.samsung.* 等厂商自定义框架
2>>因果链条
①调用栈的顺序是“后进先出”:最上面的是当前正在执行的方法、最下面的是最初启动的方法
3>>实用手法
①根据”1>>”:可以忽略所有 android.* 或 java.* 开头的行
②根据”2>>”:可以优先断定在上面的是执行单位,直接hook执行方法
遇到的可能
1>找调用栈
找输出点,再找判断点,实在没办法了再枚举
①从 Java 到 Native
在动代码之前,先观察 App 的静态特征。
- 查看包名和组件:使用
dumpsys或相关工具确定当前 Activity。 - 解压 APK:查看
lib/目录下有哪些.so文件(判定 Native 逻辑多不多)。 - 查壳:如果是加固壳(如腾讯、爱加密),直接枚举类是无效的,需要先脱壳(或者找薄弱点顺藤摸瓜)。
java加载.so逻辑
1>>关键词 System.loadLibrary
这是 Java 加载 .so 库的标准 API
2>>在 Android 应用启动时,执行顺序
attachBaseContext(最早,甚至此时 Application 对象还没完全初始化好)onCreate
工具
1>>Hook/枚举 Java 类与方法
frida-android-hook: 这是一个综合工具箱,支持追踪类、枚举方法。
Frida-Scripts-Android: 包含 hook_all_methods_classloaderfix.js,可以直接 Hook 指定类下的所有方法。
2>>Hook/枚举 .so 库 (Native) 方法
frida-trace (官方自带)
②从 Native到 Syscall
1>>常用工具
sktrace功能:
类似 ida 指令 trace 功能
统计寄存器变化,辅助分析,并且可能会有字符串产生
| 层级 | 技术内容 | 难度工具 | 对抗重点 |
|---|---|---|---|
| Java 层 | 业务逻辑、界面、SDK 调用 | Dex2Jar, jadx | 代码混淆、动态加载 |
| Native 层 (.so) | C/C++ 逻辑、加密算法、JNI | IDA Pro, Frida | 代码膨胀、控制流平坦化 (OLLVM) |
| 系统调用层 (Syscall) | read, write, openat, kill |
strace, seccomp |
绕过 libc.so 直接调用内核接口 |
| 内核层 (Kernel) | 驱动程序、内存管理、进程调度 | GDB, KGDB | Root 检测、反调试驱动、内存混淆 |
| 硬件/固件层 (TEE/TrustZone) | 指纹支付、密钥管理、安全启动 | 硬件协议分析 | 受信任执行环境 (隔离空间) |
2>找关键代码
找到关键点后,直接hook对应的方法输出测试,看是否是关键的判断点
①常用工具
jadx、[DIE][https://github.com/horsicq/DIE-engine/releases]
举例
1>冈x的常见解密逻辑
根据你看到的薄弱点(弹窗/日志/标题/……)找到对应的解密逻辑,解密逻辑示例如下:

这是一种基于循环异或(XOR)算法的对称加密
密钥是:byte[] bArr = {78, 101, 116, ??, ??, ??, ??};
ASCII 码解码为:"Net****" (冈yi)
2>打印技巧
1 | // 打印调用栈,看看是谁在调这个解密函数 |
3-so层简单的动态逆向
工具:
1 | sofixer -s soruce.so -o fix.so -m 0x0 -d |
步骤
1>常见问题和知识
1>>常见知识
①DT_SONAME 代表库名
- 在 Android 中,系统加载器(Linker)识别一个库到底叫什么,不是看它的文件名,而是看它 ELF 头部里
DT_SONAME这个字段。

②trace与js逆向里相似
- 可以使用Trace进行汇编的导出,但请注意指令级的 Trace (
traceCode) 颗粒度太细了,分分钟会爆炸。
1 | emulator.getMemory().addModuleListener(new ModuleListener() { |

③常用调用
自己写的汇编(可以替代很多调用)
fopen、open 打开文件
strstr(查找子串)、strcmp字符串对比
memcmp、内存对比
pthread_create(创建检测线程)
SVC #0、exit (退出)
2>>常见问题
①配环境
One.配置启动环境(如 libc.so 或 libdl.so)


so层的实现方法也可以问ai,但是可能要改的方法名有很多,unidbg实现方法的接口如下:unidbg-android/src/main/java/com/github/unidbg/Jni.java
Two.配置缺乏的java环境

下面是问的ai给出的实现方法
| 模拟项目 | Java 实现方式 | 解决的问题 |
|---|---|---|
| 上下文 (Context) | 继承 AbstractJni 并重写 callObjectMethodV |
getContext(), getPackageName(), getAssets() |
| 签名校验 | 模拟 getPackageInfo 返回 Signature |
绕过 native 层对 App 签名的哈希校验。 |
| 设备 ID | 模拟 Settings.Secure.getString |
获取 android_id, imei 等设备唯一标识。 |
| 网络状态 | 模拟 ConnectivityManager |
检测是否连网、是否使用代理(反调试)。 |
| 多线程/Handler | 实现 Looper 或 Thread 相关 JNI |
解决部分加固混淆库对异步任务的依赖。 |
2>记录难点
是应该“欺骗过程”让他自以为正常,还是“修正结果”强行抹平伤痕
1>>检查正常运行的同时检查环境
so层可能会效验的对象
| 校验对象 | 校验方式 | 目的 |
|---|---|---|
| 代码段 (.text) | 计算特定内存区域的 CRC32 或 MD5 | 防止你修改汇编指令(比如把 BNE 改成 BEQ) |
| 导入表 (GOT) | 检查偏移量是否指向非标准的地址 | 防止你使用 Inline Hook(Hook 之后地址会跳到你的代码区) |
| 符号表 | 检查特定的导出符号是否被抹除 | 防止被静态分析工具轻易识别 |
| 文件头 (ELF Header) | 检查 e_entry 等字段 |
防止文件被重新脱壳或重打包 |
Ⅰ.自校验与反调试逻辑
①检查文件强制一致
1 | [File Fake] 拦截到 maps 读取: /proc/self/maps |
1 | private String generateMockMaps() { |
②分析伪代码
1 | // 假设 sub_E30B0 是底层处理函数 |
③补全环境
Ⅱ.尝试更改退出逻辑
①内存强制一致
导入java代码里面找到的关键的libxxx.so,强制对其.ELF 魔数校验(memcmp 返回 0 表示两段内存完全一致,也报错)
1 | [libc Monitor] memcmp 调用 | 长度: 4 | LR: libsecexe.so!0xe4410 |
报错如下:

ida.pro查找对应的地址分析汇编得知如下:
“内存指纹”:

做一个循环,次数是 64次(CMP X19, #0x40,0x40 等于 64)。
- **
BLR X3**:这里的X3存放的就是memcmp的地址。它在循环调用memcmp。 - 两次关键比对:
- **第一处
CBNZ W0, loc_E4430**:如果memcmp返回非 0(不相等),就跳走。 - **第二处
CBZ W0, loc_E4414**:如果memcmp返回 0(相等),就跳到loc_E4414。
- **第一处
- 返回值意义:
- 跳转到
loc_E4414:你会看到MOV W0, #1。在 C 语言里,返回 1 通常代表“校验失败/发现异常”。 - 末尾的
MOV W0, #0:只有完整跑完 64 次循环且没有触发跳转,才会执行到这里,代表“校验通过/安全”。
- 跳转到
②退出强制拦截
1 | // 5. 监听 exit (反调试暴毙点) - 强行续命版 |
会遇到”寄存器污染”技术,就是上述的内存检查*64没有正常通过,就会返回一个异常值,虽然routineAddr == 0 拦截,但会导致非法内存读取
3>实际操作
| 特性 | resolve (IOResolver 接口) | addModuleListener (监听器) |
|---|---|---|
| 触发时机 | 当 SO 运行中执行 open 系统调用时触发。 |
当 .so 文件被加载进内存、还没运行前触发。 |
| 层级 | 系统级 (System Call Level)。 | 加载级 (Linker Level)。 |
| 主要功能 | 欺骗:告诉 SO 文件在本地哪里(文件重定向)。 | 修改:在代码执行前进行 Hook、Patch(改汇编)。 |
| 生效范围 | 全局,只要是打开文件的操作都会走这里。 | 仅限指定的模块加载时触发。 |
①直接重定向,给我一种透明代理的感觉
1 | var dummy_func = Memory.alloc(Process.pageSize); |
②hook—java会报hook异常,但直接hook系统调用无异常
1 | frida -Uf xxx.app.com -l do_so_hook.js |
③启动前hook异常,完全启动后hook正常
操作:
1 | // 延迟 5 秒(或者你认为 App 完全加载后的时间) |
注意:
如果一个空的js进行hook还会被退出的话需要伪装一下手机的环境了,大概率可能被壳找到了frida的特征
3>>构建脚本
问文本对话型的ai即可