入门Frida
安装
需要python环境pip install frida-tools
终端输入该命令即可完成安装
注入方式
frida -l xx.js 进程ID|进程名|-F
注入到现有进程(时机较晚)
frida -l xx.js -f 文件目录 --no-pause
创建进程后注入(时机较早)
延迟注入可使用js代码实现
1 | setTimeout(函数,延时毫秒) |
Android
Hook Java
Hook java层首先需要被包裹在Java.perform(function(){})
中,当需要调用Java类时使用Java.use('类名')
来调用其中$init
表示构造函数,$new
表示实例化对象.overload('type')
表示重载函数成员方法和成员属性名字相同时默认hook成员方法,如需hook成员属性在成员属性前加“_”来表示
主动调用函数
- 静态调用
- 使用Java.use().class.implementation=function(){hook代码}
- 动态调用
- 使用choose(class,callback)其中callback有两个属性
- onMatch:function(instance),onMatch表示进入hook,instance表示在内存中找到的实例
- onComplete:function(),表示完成hook
- 使用choose(class,callback)其中callback有两个属性
hook参数&返回值
部分情况下直接打印返回值并不能直观的体现需要通过类型转换得到需要的数据,如DumpHex,可以通过$className
得到class的属性后在转换(可能会得到undefind),如果为Json类的可以直接用JSON.Stringify()
转换成字符串
hook被混淆的方法
有些被混淆方法名可能是不可视的字符如༒
如果以这个字符命名的函数是合法的但是又有可能因为字符集的原因看不到函数名,这就要将其编码打印出来再通过打印的字符来调用此方法
1 | Java.perform( |
类型转换
Java.cast(arg,type)强转类型
调用DEX类
如果有现成的安卓源码可以将其编译后解压apk得到class.dex,使用Java.openClassFile('dex路径').lord()
加载dex类
注册java类
如果不想调用dex,可以将java代码翻译成js代码用
1 | Java.registerClass({ |
打印堆栈
调用安卓自带的API实现打印堆栈
1 | function showStacks() { |
rpc远程调用
frida支持在js代码中使用rpc.exports关键字对js函数进行导出,导出方法可在python代码中通过script.exports.导出符号()进行调用
1 | function Hook10(){ |
通过python调用
1 | import frida |
Hook Nagtive
判断指令集
可以利用IDA 判断来Thumb指令集和Arm 指令集
- IDA - Options - General - number of opcode bytes - 设置为 4
- 查看 IDA VIew 中 opcode 的长度, 如果出现 2 个字节和 4 个字节的, 说明为 thumb 指令集
- 如果都是 4 个字节的, 说明是 arm 指令集
- 在 Thumb 指令集下, inline hook 的偏移地址需要进行 +1 操作
hook so 函数
hook so 函数首先需要知道该函数所在的内存地址,通过Module.findExportByName(moduleName|null, exportName)
获取模块基址后加上偏移得到函数地址,用Interceptor.attrach(addr,callbcak)
hook函数的返回值&参数。
callback有一下两个属性onEnter:function(arg)
可以在这里修改arg参数的值onLeave:function(retvalue)
在这里修改函数的返回值注意:需要用retvalue.replace()来修改返回值
将so函数注册到js中
new Nativefunction(addr,retType,[argsType])
- address : 函数地址
- returnType : 指定返回类型
- argTypes : 数组指定参数类型
- 类型可选: void, pointer, int, uint, long, ulong, char, uchar, float, double, int8, uint8, int16, int32, uint32, int64, uint64; 参照函数所需的 type 来定义即可;
参数内容需要开辟空间,注意类型,若无参数argType填[]
即可
配合Interceptor.replace(ptr,new NativeCallback(function(){}),retType,[argsType])
实现主动调用修改函数参数返回值
工具&插件
objection的使用
objection实现Java层hook everywhere,内存漫游,内存搜索,来达到快速逆向的目的
objection -g [packageName] explore
打开交互界面调试该应用
命令 | 说明 |
---|---|
memory list modules | 枚举当前进程模块 |
memory list exports [lib_name] | 查看指定模块的导出函数 |
memory list exports libart.so —json /root/libart.json | 将结果保存到json文件中 |
memory search —string —offsets-only | 搜索内存 |
search instances search instances com.xx.xx.class | 堆内存中搜索指定类的实例, 可以获取该类的实例id |
android heap execute [ins_id] [func_name] | 直接调用指定实例下的方法 |
android heap execute [ins_id] | 自定义frida脚本, 执行实例的方法 |
android root disable | 尝试关闭app的root检测 |
android root simulate | 尝试模拟root环境 |
android ui screenshot [image.png] | 截图 |
android ui FLAG_SECURE false | 设置FLAG_SECURE权限 |
android hooking list classes | 列出内存中所有的类 |
android hooking search classes [search_name] | 在内存中所有已加载的类中搜索包含特定关键词的类 |
android hooking search methods [search_name] | 在内存中所有已加载的方法中搜索包含特定关键词的方法 |
android hooking generate simple [class_name] | 生成hook代码 |
android hooking watch class_method com.xxx.xxx.methodName —dump-args —dump-backtrace —dump-return | hook指定方法, 如果有重载会hook所有重载,如果有疑问可以看—dump-args : 打印参数—dump-backtrace : 打印调用栈—dump-return : 打印返回值 |
android hooking watch class com.xxx.xxx | hook指定类, 会打印该类下的所有调用 |
android hooking set return_value com.xxx.xxx.methodName false | 设置返回值(只支持bool类型) |
android hooking list activities | 枚举activity |
android intent launch_activity [activity_class] | 启动activity |
android hooking list services | 枚举services |
android intent launch_service [services_class] | 启动services |
jobs list | 查看任务列表 |
job kill [id] | 删除任务 |
android sslpinning disable | 关闭ssl校验 |
help android clipboard | 获取Android剪贴板服务上的句柄并每5秒轮询一次用于数据。 如果发现新数据,与之前的调查不同,则该数据将被转储到屏幕上。 |
help android shell_exec [command] | 执行命令 |
frida-trace的使用
frida-trace是一个动态跟踪函数调用的工具
1 | 用法:frida-trace[选项]target |
frida-gadget
Windows
Ios
frida进阶
Stlker
socket
anti-frida
检测方案
文件名检测
端口检测
线程检测
Maps记录检测
TraceId检测
内存检测
前两种检测很简单就可以过掉,修改文件名/端口即可
其他具体问题具体分析
定位检测so的位置
Android调用so库会使用dlopen函数,只需要hook这个函数,断在哪个so,就是那个so
安卓使用
System.loadLibrary("xxx")
加载so函数,而它的上层函数是loadLibrary0()
,再往上追可以发现是doload()
返回方法netiveload()
跟进去JVM_NativeLoad
最终发现是dlopen()
frida-trace -U -f 包名 -i android_dlopen_ext
分析、还原动态注册函数
打开 idapro 载入so选择导出函数,找到JNI_Onload
还原伪c,修改函数参数类型JNIEnv*
,或者在GetEnv()
第二个参数修改成JNIEnv*
修改后识别出函数名寻找RegisterNatives()
第三个参数即为动态注册的函数