安卓逆向 frida编译调试、框架学习

admin 2025年5月24日16:14:54评论1 views字数 8845阅读29分29秒阅读模式

0x00 搞清楚Fri.da和Objection的区别

表格一 frida&objection

安卓逆向  frida编译调试、框架学习

表格中跨平台支持解释:Frida的跨平台支持中提到的Windows平台的使用,这里的Windows平台使用是可以通过Frida直接对Windows系统的程序进行调试,使用macOS和Windows作为例子来说有两个连接方式:1.在Windows上运行frida-server使用macOS进行连接。

运行frida-server

确保 Windows 和 macOS 在同一个网络中。

获取 Windows 的 IP 地址(在 Windows 上运行 ipconfig)。

在 macOS 上使用 Frida 客户端连接到 Windows:

frida -H <Windows IP> -n <进程名>

连接成功后,在 macOS 上编写和加载 JavaScript 脚本,对 Windows 上的目标进程进行 Hook 和调试。

2.在windows上运行frida-server并调试本地进程

运行frida-server

frida -n <进程名>

连接成功后,直接在 Windows 上编写和加载 JavaScript 脚本,对本地进程进行 Hook 和调试。

表格二

安卓逆向  frida编译调试、框架学习

0x01 frida的JavaScript脚本

表格一中提到的javascript脚本,Frida可以通过javascript脚本hook应用程序的函数,拦截函数的输入参数、返回值以及执行流程。

1.hook函数

修改函数行为(如绕过验证、修改返回值)。

监控函数的调用频率和参数值。

分析加密算法、网络请求等关键逻辑。

Interceptor.attach(Module.findExportByName("libc.so""strcmp"), {onEnterfunction(args) {        console.log("strcmp called with:", args[0].readCString(), args[1].readCString());},onLeavefunction(retval) {        console.log("strcmp returned:", retval);}});

2. 动态修改内存

通过 JavaScript 脚本,Frida 可以读取和修改目标进程的内存数据。

修改内存中的变量值或字符串。

绕过某些内存中的校验逻辑。

动态篡改应用的行为。

var ptr = Module.findBaseAddress("libnative.so").add(0x1234);Memory.writeUtf8String(ptr, "new_value");//Module.findBaseAddress是Frida提供的一个函数 找到libnative.so库在内存中的基地址,在基地址的基础上加上偏移量0x1234,//将字符串"new_value"写入到指定的内存地址ptr

3. 调用函数

通过 JavaScript 脚本直接调用目标应用程序中的函数

触发特定功能以测试其行为。

调用未导出的函数或私有方法。

var func = new NativeFunction(Module.findExportByName("libnative.so""my_function"), 'int', ['int']);//查找 libnative.so 库中名为 my_function 的函数的地址。Module.findExportByName根据模块名(libnative.so)和函数名(my_function)查找该函数在内存中的地址//'int'->my_function返回一个整数, ['int']->表示 my_function 接受一个整数参数。var result = func(123);//调用 my_function 并传入参数 123console.log("Function returned:", result);

4. 监控和拦截系统调用

Frida 可以监控目标应用程序与操作系统之间的交互,如文件读写、网络请求等。

分析应用程序的文件操作行为。

拦截网络请求,查看或修改请求数据。

var openPtr = Module.findExportByName(null"open");//open 是标准库函数(通常由 libc.so 提供),用于打开文件Interceptor.attach(openPtr, {    onEnterfunction(args) {    //onEnter:在函数调用时触发。        console.log("Opening file:", args[0].readCString());    },    onLeavefunction(retval) {    //onLeave:在函数返回时触发        console.log("File opened with fd:", retval);    }});

open函数的原型int open(const char *pathname, int flags, mode_t mode);

args[0] 是第一个参数 pathname,表示要打开的文件路径。

args[1] 是第二个参数 flags,表示打开文件的标志。

args[2] 是第三个参数 mode,表示文件的权限模式(如果创建文件)

5.动态加载和卸载模块

Frida 可以在运行时加载或卸载目标应用程序中的模块(如 SO 文件)。

分析特定模块的功能。

绕过某些模块的加载校验。

var module = Process.findModuleByName("libnative.so");[/font]console.log("Module base address:"module.base);

这个功能对我来说比较抽象,具体的场景是在目标应用程序在运行时加载的某些模块(插件,广告SDK,加密库),例如一些恶意软件可能会在运行时动态加载加密模块来隐藏行为。

举例:某个程序加密库在加载之后解密数据,此时就要hook掉解密函数来获取解密后的内容

var module = Process.findModuleByName("libcrypto.so");if (module) {    var decryptFunc = Module.findExportByName("libcrypto.so""decrypt");    Interceptor.attach(decryptFunc, {        onEnterfunction(args) {            console.log("Decrypting data:", args[0].readCString());        },        onLeavefunction(retval) {            console.log("Decrypted data:", retval.readCString());        }    });}

其他功能:应用程序支持插件或扩展功能,通过动态模块来实现,就要分析插件的导出函数和调用逻辑;检测恶意行为,检测模块的加载行为,用户不知情的情况下加载恶意模块来窃取数据;加载大量模块,导致内存占用过高或启动速度变慢的情况。

6.调试和日志记录

Frida 的 JavaScript 脚本可以用于动态调试和记录应用程序的运行状态。

打印函数调用栈。

记录关键变量的值。

跟踪应用程序的执行流程。

console.log("Current thread ID:"Process.getCurrentThreadId());console.log("Backtrace:"Thread.backtrace(this.contextBacktracer.ACCURATE));

7.绕过反调试和检测

Frida 的 JavaScript 脚本可以用于绕过应用程序中的反调试机制。

修改反调试标志位。

Hook 反调试函数,使其失效。

var ptracePtr = Module.findExportByName(null"ptrace");Interceptor.replace(ptracePtr, new NativeCallback(function() {    console.log("ptrace called, bypassing...");    return 0;}, 'int', []));

8. 自动化测试和分析

Frida 的 JavaScript 脚本可以用于自动化测试和分析应用程序的行为。

批量测试函数的输入输出。

自动化分析应用程序的逻辑。

function testFunction(input) {    var func = new NativeFunction(Module.findExportByName("libnative.so""my_function"), 'int', ['int']);    var result = func(input);    console.log("Input:", input, "Output:", result);}for (var i = 0; i < 10; i++) {    testFunction(i);}

0x02 Hook脚本

先搞清楚的是frida的JavaScript脚本是指使用Frida的JavaScript API编写的脚本,实现的功能:hook函数、读取和修改内存、调用native函数、动态调试。

hook脚本是frida的javascript脚本的一个子集,专门hook目标函数:拦截函数调用、修改函数行为、监控函数调用。

安卓逆向  frida编译调试、框架学习

hook脚本经典结构

Java.perform(function() {    // 1. 获取目标类    var TargetClass = Java.use("com.example.app.TargetClass");    // 2. Hook 目标方法    TargetClass.targetMethod.implementation = function(arg1, arg2) {        // 3. 打印日志        console.log("targetMethod called with:", arg1, arg2);        // 4. 调用原始方法(可选)        var result = this.targetMethod(arg1, arg2);        // 5. 修改返回值(可选)        return result + 1;    };});

1.常见用途

动态调试:打印函数参数和返回值;跟踪程序的执行流程。

绕过验证:修改函数的返回值,绕过登录验证、许可证检查等。

分析加密算法:拦截加密函数的输入和输出,分析其逻辑。

修改应用行为:替换函数的实现,改变应用的行为。

数据监控:记录敏感数据(如密码、密钥等)。

2.应用

应用验证许可证是否有效

Java.perform(function() {    var LicenseManager = Java.use("com.example.app.LicenseManager");    LicenseManager.checkLicense.implementation = function() {        console.log("Bypassing license check...");        return true// 强制返回 true    };});

3.hook脚本的难点

安卓逆向  frida编译调试、框架学习

4. 部分hook脚本

4.1.枚举已加载的类

为什么要枚举已加载的类?   已加载的类通过枚举类名,结合方法名、字段名、调用关系来定位目标,动态分析应用的行为。

目标类名被混淆,就可以先枚举已经加载的类

Java.perform(function() {    Java.enumerateLoadedClasses({onMatchfunction(className) {    //enumerateLoadedClasses获取已加载的类的名称            console.log(className);},onCompletefunction() {}});});

4.2.Hook目标方法

找到目标类com.example.app.MainActivity和方法login

Java.perform(function() {    var MainActivity = Java.use("com.example.app.MainActivity");    MainActivity.login.implementation = function(username, password) {        console.log("Login called with:", username, password);        // 修改返回值        return true;    };});

4.3.监控网络请求

应用实现方式:

1.使用系统apiandroid应用使用系统api:HttpURLConnection、OkHttp、Retrofit 等ios应用使用系统api:NSURLSession、NSURLConnection 等。

2.发送请求:构建请求(url,请求头,请求体),发送请求服务器

3.接收响应,接收服务器返回的响应数据(状态码,响应头,响应体)。

Hook思路:

目标应用使用HttpURLConnection

Java.perform(function() {    var URL = Java.use("java.net.URL");    var HttpURLConnection = Java.use("java.net.HttpURLConnection");    // Hook URL.openConnection    URL.openConnection.overload().implementation = function() {        var connection = this.openConnection();        console.log("URL:"this.toString());        // Hook getInputStream        if (connection.getClass().getName().indexOf("HttpURLConnection") !== -1) {            var httpConnection = Java.cast(connection, HttpURLConnection);            httpConnection.getInputStream.implementation = function() {                console.log("Request Headers:", httpConnection.getRequestProperties());                var inputStream = this.getInputStream();                // 读取响应数据                var response = readInputStream(inputStream);                console.log("Response:", response);                return inputStream;            };        }        return connection;    };    // 读取 InputStream 的工具函数    function readInputStream(inputStream) {        var BufferedReader = Java.use("java.io.BufferedReader");        var InputStreamReader = Java.use("java.io.InputStreamReader");        var StringBuilder = Java.use("java.lang.StringBuilder");        var reader = BufferedReader.$new(InputStreamReader.$new(inputStream));        var builder = StringBuilder.$new();        var line;        while ((line = reader.readLine()) !== null) {            builder.append(line);        }        reader.close();        return builder.toString();    }});

目标应用使用 OkHttp

Java.perform(function() {    var OkHttpClient = Java.use("okhttp3.OkHttpClient");    var Request = Java.use("okhttp3.Request");    var Response = Java.use("okhttp3.Response");    // Hook OkHttpClient.newCall    OkHttpClient.newCall.implementation = function(request) {        console.log("Request URL:", request.url().toString());        console.log("Request Headers:", request.headers().toString());        var response = this.newCall(request).execute();        console.log("Response Code:", response.code());        console.log("Response Body:", response.body().string());        return response;    };});

4.4.绕过 SSL Pinning

SSL pinning (SSL 证书绑定)安全机制,防止中间人攻击,核心是将服务器的SSLTLS证书或公钥硬编码到客户端应用中,客户端与特定的服务器通信,不是与拥有有效证书的服务器通信。

引入机制:

1.证书或公钥绑定,客户端在建立连接,检查服务器返回的证书或公钥是否与硬编码的值匹配

2.防止中间人攻击,攻击者的证书与硬编码值不匹配

实现方式:

1.证书绑定:将服务器的完整证书(通常是 DER 或 PEM 格式)硬编码到客户端应用中。

2.公钥绑定:将服务器的公钥(通常是公钥的哈希值)硬编码到客户端应用中3.证书链绑定:将服务器证书链中的某个中间证书或根证书硬编码到客户端应用中。

绕过方式:

1.修改客户端代码:反编译应用代码,删掉SSL Pinning的实现代码并修改删除

2.使用frida或者objection绕过:

Frida 使用脚本Hook SSL Pinning 相关的函数;

Java.perform(function() {    var X509TrustManager = Java.use("javax.net.ssl.X509TrustManager");    var TrustManager = Java.registerClass({        name"com.example.TrustManager",        implements: [X509TrustManager],        methods: {            checkClientTrusted: function(chain, authType) {},            checkServerTrusted: function(chain, authType{},            getAcceptedIssuers: function() {                return [];            }        }    });    var SSLContext = Java.use("javax.net.ssl.SSLContext");    SSLContext.init.implementation = function(keyManager, trustManager, secureRandom{        this.init(keyManager, [TrustManager.$new()], secureRandom);    };});

使用objection命令:

android sslpinning disable

4.5.动态修改内存

var ptr = Module.findBaseAddress("libnative.so").add(0x1234);Memory.writeUtf8String(ptr, "new_value");

4.6. 处理反调试

目标应用检测Frida,可以hook反调试函数

Java.perform(function() {    var System = Java.use("java.lang.System");    System.getProperty.implementation = function(key) {        if (key === "java.vm.name") {            return "Dalvik"// 伪装成 Dalvik 虚拟机        }        return this.getProperty(key);    };});

· 今 日 推 荐 ·

安卓逆向  frida编译调试、框架学习

本文内容来自网络,如有侵权请联系删除

原文始发于微信公众号(逆向有你):安卓逆向 -- frida编译调试、框架学习

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年5月24日16:14:54
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   安卓逆向 frida编译调试、框架学习https://cn-sec.com/archives/4093996.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息