Frida 初步使用和逆向
FRIDA
Frida是一个动态代码插桩工具,主要用于执行动态分析。它允许你在程序运行时注入自己的代码或监控执行流程。使用该工具可以实现对应用程序的Hook,监控和修改函数调用和消息传递。
- 适用平台:支持Windows、
macOS、Linux、iOS和Android等多个平台。 - 使用场景:逆向工程、安全评估、
开发与调试等。 - 核心组件:包括一个
核心库以及多个语言绑定(如Python、Node.js)。
案例
0x01 frida_example_1.0.apk

使用frida hook
frida-ps -U -a 查看包名
frida -U -f 包名 -l hook.js
hook.js源码如下:
// 定义主要用于hook Java层代码的函数
function hook_java() {
// 使用Java.perform执行hook
Java.perform(function () {
// 获取LoginActivity,并打印以便调试
var LoginActivity = Java.use("com.example.androiddemo.Activity.LoginActivity");
console.log(LoginActivity);
// 修改LoginActivity类中的a方法实现
LoginActivity.a.overload('java.lang.String', 'java.lang.String').implementation = function (str, str2) {
// 在内部,首先调用原始方法并保存结果
var result = this.a(str, str2);
// 打印调用参数和结果
console.log("LoginActivity.a:", str, str2, result);
// 返回原始方法的结果
return result;
};
// 获取FridaActivity1类引用并打印
var FridaActivity1 = Java.use("com.example.androiddemo.Activity.FridaActivity1");
console.log(FridaActivity1);
// 修改FridaActivity1类a方法的实现,这里没有调用原始函数,而是直接返回固定字符串
FridaActivity1.a.implementation = function (barr) {
// 打印方法被调用的信息
console.log("FridaActivity1.a");
// 返回固定的字符串
return "R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL=";
};
// 表明hook_java函数已经被调用
console.log("hook_java");
});
}
// 定义函数,用于主动调用FridaActivity2中的方法
function call_FridaActivity2() {
// 使用Java.perform执行主动调用
Java.perform(function () {
// 获取FridaActivity2类引用
var FridaActivity2 = Java.use("com.example.androiddemo.Activity.FridaActivity2");
// 主动调用FridaActivity2中的setStatic_bool_var静态方法
FridaActivity2.setStatic_bool_var();
// 选择FridaActivity2实例,并修改实例变量
Java.choose("com.example.androiddemo.Activity.FridaActivity2", {
onMatch: function (instance) {
// 修改实例变量bool_var值
instance.setBool_var();
},
onComplete: function () {
// 选择完成时的回调
}
});
});
}
// 定义函数,用于主动调用FridaActivity3,并修改其成员变量
function call_FridaActivity3() {
// 使用Java.perform执行主动调用
Java.perform(function () {
// 获取FridaActivity3类引用
var FridaActivity3 = Java.use("com.example.androiddemo.Activity.FridaActivity3");
// 修改FridaActivity3的静态成员变量static_bool_var的值
FridaActivity3.static_bool_var.value = true;
// 打印修改后的值以确认
console.log(FridaActivity3.static_bool_var.value);
// 选择FridaActivity3的实例,并修改它们的成员变量值
Java.choose("com.example.androiddemo.Activity.FridaActivity3", {
onMatch: function (instance) {
// 修改非静态成员变量的值
instance.bool_var.value = true;
// 修改名称冲突的成员变量值
instance._same_name_bool_var.value = true;
// 打印出修改后的值
console.log(instance.bool_var.value, instance._same_name_bool_var.value);
},
onComplete: function () {
// 选择完成回调
}
});
});
}
// 定义函数,用于hook FridaActivity4中的InnerClasses内部类的多个方法
function hook_InnerClasses() {
Java.perform(function () {
// 获取InnerClasses类引用,并打印
var InnerClasses = Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses");
console.log(InnerClasses);
// 修改InnerClasses类中的check方法,始终返回true,共有6个check方法
InnerClasses.check1.implementation = function () { return true; };
InnerClasses.check2.implementation = function () { return true; };
InnerClasses.check3.implementation = function () { return true; };
InnerClasses.check4.implementation = function () { return true; };
InnerClasses.check5.implementation = function () { return true; };
InnerClasses.check6.implementation = function () { return true; };
});
}
// 定义函数,用于hook InnerClasses类的所有方法,并返回true
function hook_mul_function() {
Java.perform(function () {
// 指定需要hook的类的名称
var class_name = "com.example.androiddemo.Activity.FridaActivity4$InnerClasses";
// 获取类引用
var InnerClasses = Java.use(class_name);
// 获取InnerClasses类声明的所有方法
var all_methods = InnerClasses.class.getDeclaredMethods();
// 遍历所有方法
for (var i = 0; i < all_methods.length; i++) {
// 获取单个方法的引用
var method = (all_methods[i]);
// 将方法转化为字符串
var methodStr = method.toString();
// 获取方法名
var substring = methodStr.substr(methodStr.indexOf(class_name) + class_name.length + 1);
var methodname = substring.substr(0, substring.indexOf("("));
// 打印方法名称
console.log(methodname);
// 修改对应方法的实现,始终返回true
InnerClasses[methodname].implementation = function () {
console.log("hook_mul_function:", this);
return true;
}
}
});
}
// 定义函数用于hook动态加载的dex文件内的类和方法
function hook_dyn_dex() {
Java.perform(function () {
// 获取FridaActivity5类引用
var FridaActivity5 = Java.use("com.example.androiddemo.Activity.FridaActivity5");
// 选择FridaActivity5的实例,并打印动态dex类的名称
Java.choose("com.example.androiddemo.Activity.FridaActivity5", {
onMatch: function (instance) {
// 打印动态加载的dex的类名
console.log(instance.getDynamicDexCheck().$className);
}, onComplete: function () {
// 选择完成回调
}
});
// 枚举类加载器,寻找包含DynamicCheck类的类加载器
Java.enumerateClassLoaders({
onMatch: function (loader) {
try {
// 如果找到了DynamicCheck类,则切换loader为当前类加载器
if (loader.findClass("com.example.androiddemo.Dynamic.DynamicCheck")) {
console.log(loader);
Java.classFactory.loader = loader;
}
} catch (error) {
// 捕获异常
}
}, onComplete: function () {
// 枚举完成回调
}
});
// 获取动态加载的DynamicCheck类
var DynamicCheck = Java.use("com.example.androiddemo.Dynamic.DynamicCheck");
// 打印以便调试
console.log(DynamicCheck);
// 修改DynamicCheck类中的check方法实现,始终返回true
DynamicCheck.check.implementation = function () {
console.log("DynamicCheck.check");
return true;
}
});
}
// 定义函数用于hook FridaActivity6内的Frida6Class0、Frida6Class1和Frida6Class2类的check方法
function hook_FridaActivity6() {
Java.perform(function () {
// 修改Frida6Class0类的check方法,始终返回true
var Frida6Class0 = Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class0");
Frida6Class0.check.implementation = function () {
return true;
};
// 修改Frida6Class1类的check方法,始终返回true
var Frida6Class1 = Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class1");
Frida6Class1.check.implementation = function () {
return true;
};
// 修改Frida6Class2类的check方法,始终返回true
var Frida6Class2 = Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class2");
Frida6Class2.check.implementation = function () {
return true;
};
});
}
// 定义函数用于枚举并hook FridaActivity6包下所有类的check方法
function hook_mul_class() {
Java.perform(function () {
// 枚举已加载的类
Java.enumerateLoadedClasses({
onMatch: function (name, handle) {
// 如果是FridaActivity6包下的类,则hook它的check方法
if (name.indexOf("com.example.androiddemo.Activity.Frida6") >= 0) {
console.log(name);
var fridaclass6 = Java.use(name);
fridaclass6.check.implementation = function () {
console.log("frida 6 check:", this);
return true;
};
}
}, onComplete: function () {
// 枚举完成回调
}
})
});
}
// 定义主函数,开始执行hook_java
function main() {
hook_java();
}
// 使用setImmediate,保证main函数在Frida环境准备完毕后执行
setImmediate(main);
step
-
0x01 - 反编译分析静态代码,编写
hook.js脚本- 使用适当的反编译工具(如
apktool、jadx或dex2jar等),对目标APK进行反编译,从而获取到代码的结构和逻辑。 - 通过阅读代码了解程序的工作流程、准确定位需要
hook的方法。 - 结合Frida的API编写脚本
hook.js,实现对特定方法的拦截和修改。
- 使用适当的反编译工具(如
-
0x02 - 提升编码能力,解决遇到的挑战
- 深化对
JavaScript的理解,学习更多关于Frida脚本编写的技巧。 - 学会阅读和理解
Frida的错误信息,提升debug能力。 - 持续编码,对遇到的困难时刻保持好奇心,逐个击破在
hook过程中遇到的关卡。
- 深化对
-
0x03 - 耐心与细节关注,确保功能实现的稳定性
- 实现功能时保持耐心,不要急于求成,理解每一行
hook代码的含义及对应的影响。 - 注重脚本的稳健性和异常处理,确保在不同条件下脚本都能正常工作。
- 重视对
hook代码测试的全面性,包括边界情况和潜在的性能问题。
- 实现功能时保持耐心,不要急于求成,理解每一行
-
0x04 - 学习移动安全和系统内置安全机制
- 深入了解
Android和iOS操作系统的安全特性,例如沙箱、权限模型、签名机制等。 - 学习如何绕过或者利用这些安全机制来实现更高级的
hook技术。
- 深入了解
-
0x05 - 熟悉Frida的高级用法
- 除了基本的
hook,还可以学习Frida用于内存操作、模块枚举、动态分析等高级功能。 - 了解如何结合其他工具,例如
Objection或Radare2,以丰富动态分析的过程。
- 除了基本的
-
0x06 - 融会贯通,实践复杂案例
- 将学过的理论知识应用到更复杂的案例分析之中,比如加固过的或者有反调试机制的
APP。 - 运用
创造性思维,開发自定义的Frida模块或插件,以解决特定分析问题。
- 将学过的理论知识应用到更复杂的案例分析之中,比如加固过的或者有反调试机制的
QA
-
adb如何把字符串复制到模拟器中?通过
adb (Android Debug Bridge)将字符串复制到安卓模拟器中,可以使用以下方式:
使用adb shell input text命令:
sh
adb shell input text '你的字符串'
请确保你的字符串中没有空格。如果需要输入空格,可以使用%s来代表空格。例如,要输入Hello World,使用以下命令:
sh
adb shell input text 'Hello%sWorld'
借助剪贴板 (API Level 11 及以上):
sh
adb shell am broadcast -a clipper.set -e text '你的字符串'
注意:上述方法需要你的设备上有一个名为clipper的应用,该应用可以响应clipper.set的广播并更新剪贴板内容。如果你没有安装类似功能的应用,你需要自己开发或安装一个。
以上是将字符串发送到模拟器的两种方式,具体使用哪一种取决于你具体的需求以及安卓模拟器上的环境配置。如果你在执行这些命令的时候遇到任何问题,确保你的adb环境配置正确,并且你的设备已经连接到了adb。