通过Hook技术拦截App执行逻辑动态调试
逆向App之Hook
上几篇介绍了如何抓包App的网络请求,以及脱壳和反编译App,但是请求返回响应的是加密的,通过反编译代码发现,响应加密密钥是通过加载了本地so文件来返回的,尝试通过在线和Ida反编译so文件,以及新建java项目调用so文件未果,这时可以通过Frida Hook技术来动态劫持代码,来拦截、篡改数据加解密、界面弹窗等逻辑。Frida是一款基于Python和Javascript的Hook框架,可运行在Android、Ios、Linux、Win、Osx等各平台,主要使用动态二进制插桩技术。


Python环境安装
-- 安装python3环境,查看python版本
python --version

Frida安装
安装在Windows等操作系统上。
# 通过python的pip工具安装frida
pip3 install frida
pip3 install frida-tools
# 查看frida版本
frida --version

Frida服务端安装
安装在安卓手机或者模拟器上,需要注意Cpu架构是arm还是x86,通过Adb工具查看系统架构,Adb工具可以单独从官网下载或者直接使用雷电模拟器安装目录下的Adb工具,从Github上下载对应的Frida服务端版本。
# 已连接设备或者模拟器列表
.\adb.exe devices
# adb登录命令行
.\adb.exe shell
# 切换root,可选
su
# 查看cpu类型,或者进入shell之后执行后面的命令
.\adb.exe shell getprop ro.product.cpu.abi
getprop ro.product.cpu.abi
# 推送文件到模拟器
.\adb.exe push frida-server-17.9.7-android-x86_64 /data/local/tmp
# 进入shell刚刚推送的目录
.\adb.exe shell
cd /data/local/tmp
# 修改权限
chmod 777 frida-server-17.9.7-android-x86_64
# 切换到root用户启动,否则注入脚本会报错Failed to spawn: unexpectedly timed out while waiting for app to launch
su
# 启动frida服务端
./frida-server-17.9.7-android-x86_64



在Windows上,再开一个命令行,执行frida-ps -Uai查看Usb设备上所有已安装应用命令查看是否运行正常。

Hook代码
回到引言中的问题,请求返回的内容加密了,但是密钥是通过本地So文件中的方法获取的,那么我们就尝试通过Frida来拦截下NativeEncrypt.getSalt()方法,可以在Jadx上在方法名上右键复制为Frida代码并保存为hook.js文件。


// 注入脚本代码,常规写法,无法Hook
Java.perform(function () {
let NativeEncrypt = Java.use("com.dsdqjx.tvhd.utils.NativeEncrypt");
NativeEncrypt["getSalt"].implementation = function () {
console.log(`NativeEncrypt.getSalt is called`);
let result = this["getSalt"]();
console.log(`NativeEncrypt.getSalt result=${result}`);
return result;
};
});
在Windows上执行frida -U -f com.xytv.tvhd -l .\hook.js命令注入脚本,执行后报错找不到类。

后面发现可能是应用加固的原因,搜索资料说是可以先拿到加载应用本身dex的classloader,再通过这个classloader去找到被加固的类,最后再去Hook对应的方法,修改后的Hook脚本如下。
if(Java.available) {
Java.perform(function(){
var application = Java.use("android.app.Application");
var reflectClass = Java.use("java.lang.Class");
console.log("application: " + application);
application.attach.overload('android.content.Context').implementation = function(context) {
var result = this.attach(context); // 先执行原来的attach方法
var classloader = context.getClassLoader(); // 获取classloader
Java.classFactory.loader = classloader;
//这里能直接使用Java.use,因为java.use会检查在不在perform里面,不在就会失败
var NativeEncrypt = Java.classFactory.use("com.dsdqjx.tvhd.utils.NativeEncrypt");
console.log("NativeEncrypt: " + NativeEncrypt);
NativeEncrypt["getSalt"].overload('java.lang.String').implementation = function () {
let result = this["getSalt"]();
console.log(`com.dsdqjx.tvhd.utils.NativeEncrypt.getSalt result=${result}`);
return result;
}
return result;
}
});
}
在Windows上执行frida -U -f com.xytv.tvhd -l .\hook.js命令注入脚本,执行后还是没有Hook到对应的方法。

经过各种写法的尝试之后,发下如下写法才可以Hook到对应的方法获取密钥,在Windows上执行命令为frida -U -f com.xytv.tvhd -l .\hook.js --pause,且需要手动输入%resume。
if (Java.available) {
Java.perform(function () {
console.log("✅ 启动加固兼容模式");
// 循环查找(每 1 秒查一次,直到找到类)
var timer = setInterval(function () {
try {
var NativeEncrypt = Java.use("com.dsdqjx.tvhd.utils.NativeEncrypt");
NativeEncrypt.getSalt.implementation = function () {
// 获取原始返回值(可选)
var originalSalt = this.getSalt();
console.log("🔐 原始 salt: " + originalSalt);
// 返回你自定义的 salt
//var yourSalt = "abcdefg1234567"; // 你想要的盐值
//console.log("✅ 返回修改后的 salt: " + yourSalt);
return originalSalt;
};
console.log("🎯 所有方法 Hook 成功!");
clearInterval(timer); // 找到就停止
} catch (e) {}
}, 1000);
});
}
