Eswlnk Blog Eswlnk Blog
  • 资源
    • 精彩视频
    • 破解专区
      • WHMCS
      • WordPress主题
      • WordPress插件
    • 其他分享
    • 极惠VPS
    • PDF资源
  • 关于我
    • 论文阅读
    • 关于本站
    • 通知
    • 左邻右舍
    • 玩物志趣
    • 日志
    • 专题
  • 热议话题
    • 游戏资讯
  • 红黑
    • 渗透分析
    • 攻防对抗
    • 代码发布
  • 自主研发
    • 知识库
    • 插件
      • ToolBox
      • HotSpot AI 热点创作
    • 区块
    • 快乐屋
    • 卡密
  • 乱步
    • 文章榜单
    • 热门标签
  • 问答中心反馈
  • 注册
  • 登录
首页 › 通知 › 安卓破解逆向入门教程 | 轻松学习如何逆向工程并破解安卓应用的方法与技巧

安卓破解逆向入门教程 | 轻松学习如何逆向工程并破解安卓应用的方法与技巧

Eswlnk的头像
Eswlnk
2023-10-05 22:47:26
安卓破解逆向入门教程 | 轻松学习如何逆向工程并破解安卓应用的方法与技巧-Eswlnk Blog
智能摘要 AI
该教程介绍了利用逆向工程技术,结合Frida和IDA脚本,对安卓应用程序进行破解的过程。主要内容包括: 1. **课程目标**:学习如何使用逆向工程技巧及Frida-Native-Hook和IDA脚本破解安卓应用。 2. **工具**:使用教程Demo、jadx-gui、VS Code等工具。 3. **基础概念**:介绍了Process、Module和Memory的基本概念及其API,包括如何获取进程信息、枚举模块和内存操作。 4. **枚举导入导出表**:讲解了导出表和导入表的作用,并展示了如何使用代码枚举它们。 5. **基础Hook打印**:学习了如何使用Frida对Native函数进行基础Hook,包括处理整数型、布尔值类型、char类型和字符串类型。 6. **修改Hook**:展示了如何修改函数的参数和返回值,包括整数型和字符串类型的修改

一、课程目标

在这个教程中,我们将学习如何使用逆向工程技巧和方法,以及借助 Frida-Native-Hook 和 IDA 脚本来破解安卓应用程序。

二、工具

在本教程中,我们将使用以下工具:

  1. 教程 Demo(更新)
  2. jadx-gui
  3. VS Code
安卓破解逆向入门教程 | 轻松学习如何逆向工程并破解安卓应用的方法与技巧-Eswlnk Blog

三、课程内容

1. 基础概念

1.1 Process、Module、Memory 基础

  • Process
    • Process 对象代表当前被 Hook 的进程,能获取进程的信息,枚举模块,枚举范围等。
    API含义Process.id返回附加目标进程的 PIDProcess.isDebuggerAttached()检测当前是否对目标程序已经附加Process.enumerateModules()枚举当前加载的模块,返回模块对象的数组Process.enumerateThreads()枚举当前所有的线程,返回包含 id、state、context 等属性的对象数组
  • Module
    • Module 对象代表一个加载到进程的模块(例如,在 Windows 上的 DLL,或在 Linux/Android 上的 .so 文件),能查询模块的信息,如模块的基址、名称、导入 / 导出的函数等。
    API含义Module.load()加载指定 so 文件,返回一个 Module 对象Module.enumerateImports()枚举所有 Import 库函数,返回 Module 数组对象Module.enumerateExports()枚举所有 Export 库函数,返回 Module 数组对象Module.enumerateSymbols()枚举所有 Symbol 库函数,返回 Module 数组对象Module.findExportByName(name)寻找指定 so 中 export 库中的函数地址Module.getExportByName(name)获取指定 so 中 export 库中的函数地址Module.findBaseAddress(name)返回 so 的基地址
  • Memory
    • Memory 是一个工具对象,提供直接读取和修改进程内存的功能,能够读取特定地址的值、写入数据、分配内存等。
    方法功能Memory.copy()复制内存Memory.scan()搜索内存中特定模式的数据Memory.scanSync()同上,但返回多个匹配的数据Memory.alloc()在目标进程的堆上申请指定大小的内存,返回一个 NativePointerMemory.writeByteArray()将字节数组写入一个指定内存Memory.readByteArray读取内存

2. 枚举导入导出表

  • 导出表(Export Table):列出了库中可以被其他程序或库访问的所有公开函数和符号的名称。
  • 导入表(Import Table):列出了库需要从其他库中调用的函数和符号的名称。
<span role="button" tabindex="0" data-code="function hookTest1() { Java.perform(function() { // 打印导入表 var imports = Module.enumerateImports("lib52pojie.so"); for (var i = 0; i < imports.length; i++) { if (imports[i].name == "vip") { console.log(JSON.stringify(imports[i])); // 通过 JSON.stringify 打印 object 数据 console.log(imports[i].address); } } // 打印导出表 var exports = Module.enumerateExports("lib52pojie.so"); for (var i = 0; i
function hookTest1() {
    Java.perform(function() {
        // 打印导入表
        var imports = Module.enumerateImports("lib52pojie.so");
        for (var i = 0; i < imports.length; i++) {
            if (imports[i].name == "vip") {
                console.log(JSON.stringify(imports[i])); // 通过 JSON.stringify 打印 object 数据
                console.log(imports[i].address);
            }
        }
        // 打印导出表
        var exports = Module.enumerateExports("lib52pojie.so");
        for (var i = 0; i < exports.length; i++) {
            console.log(JSON.stringify(exports[i]));
        }
    });
}

3. Native 函数的基础 Hook 打印

在本节中,我们将学习如何使用 Frida 对 Native 函数进行基础的 Hook,包括整数型、布尔值类型、char 类型和字符串类型。

3.1 整数型、布尔值类型、char 类型

function hookTest2() {
    Java.perform(function() {
        // 根据导出函数名打印地址
        var helloAddr = Module.findExportByName("lib52pojie.so", "Java_com_zj_wuaipojie_util_SecurityUtil_checkVip");
        console.log(helloAddr);
        if (helloAddr != null) {
            Interceptor.attach(helloAddr, {
                // onEnter 里可以打印和修改参数
                onEnter: function(args) { // args 传入参数
                    console.log(args[0]); // 打印第一个参数的值
                    console.log(this.context.x1); // 打印寄存器内容
                    console.log(args[1].toInt32()); // toInt32()转十进制
                    console.log(args[2].readCString()); // 读取字符串 char 类型
                    console.log(hexdump(args[2])); // 内存 dump
                },
                // onLeave 里可以打印和修改返回值
                onLeave: function(retval) { // retval 返回值
                    console.log(retval);
                    console.log("retval", retval.toInt32());
                }
            })
        }
    })
}

3.2 字符串类型

function hookTest2() {
    Java.perform(function() {
        // 根据导出函数名打印地址
        var helloAddr = Module.findExportByName("lib52pojie.so", "Java_com_zj_wuaipojie_util_SecurityUtil_vipLevel");
        if (helloAddr != null) {
            Interceptor.attach(helloAddr, {
                // onEnter 里可以打印和修改参数
                onEnter: function(args) { // args 传入参数
                    // 方法一
                    var jString = Java.cast(args[2], Java.use('java.lang.String'));
                    console.log("参数:", jString.toString());
                    // 方法二
                    var JNIEnv = Java.vm.getEnv();
                    var originalStrPtr = JNIEnv.getStringUtfChars(args[2], null).readCString();
                    console.log("参数:", originalStrPtr);
                },
                // onLeave 里可以打印和修改返回值
                onLeave: function(retval) { // retval 返回值
                    var returnedJString = Java.cast(retval, Java.use('java.lang.String'));
                    console.log("返回值:", returnedJString.toString());
                }
            })
        }
    })
}

4. Native 函数的基础 Hook 修改

在本节中,我们将学习如何修改 Native 函数的参数和返回值,包括整数型和字符串类型的修改。

4.1 整数型修改

function hookTest3() {
    Java.perform(function() {
        // 根据导出函数名打印地址
        var helloAddr = Module.findExportByName("lib52pojie.so", "Java_com_zj_wuaipojie_util_SecurityUtil_checkVip");
        console.log(helloAddr);
        if (helloAddr != null) {
            Interceptor.attach(helloAddr, {
                onEnter: function(args) { // args 参数
                    args[0] = ptr(1000); // 第一个参数修改为整数 1000,先转为指针再赋值
                    console.log(args[0]);
                },
                onLeave: function(retval) { // retval 返回值
                    retval.replace(20000); // 返回值修改
                    console.log("retval", retval.toInt32());
                }
            })
        }
    })
}

4.2 字符串类型修改

function hookTest2() {
    Java.perform(function() {
        // 根据导出函数名打印地址
        var helloAddr = Module.findExportByName("lib52pojie.so", "Java_com_zj_wuaipojie_util_SecurityUtil_vipLevel");
        if (helloAddr != null) {
            Interceptor.attach(helloAddr, {
                // onEnter 里可以打印和修改参数
                onEnter: function(args) { // args 传入参数
                    var JNIEnv = Java.vm.getEnv();
                    var originalStrPtr = JNIEnv.getStringUtfChars(args[2], null).readCString();
                    console.log("参数:", originalStrPtr);
                    var modifiedContent = "至尊";
                    var newJString = JNIEnv.newStringUtf(modifiedContent);
                    args[2] = newJString;
                },
                // onLeave 里可以打印和修改返回值
                onLeave: function(retval) { // retval 返回值
                    var returnedJString = Java.cast(retval, Java.use('java.lang.String'));
                    console.log("返回值:", returnedJString.toString());
                    var JNIEnv = Java.vm.getEnv();
                    var modifiedContent = "无敌";
                    var newJString = JNIEnv.newStringUtf(modifiedContent);
                    retval.replace(newJString);
                }
            })
        }
    })
}

5. SO 基址的获取方式

获取 SO 基址的几种方式:

var moduleAddr1 = Process.findModuleByName("lib52pojie.so").base; var moduleAddr2 = Process.getModuleByName("lib52pojie.so").base; var moduleAddr3 = Module.findBaseAddress("lib52pojie.so");

6. Hook 未导出函数与函数地址计算

在本节中,我们将学习如何 Hook 未导出函数以及如何计算函数地址。

function hookTest6() {
    Java.perform(function() {
        // 根据导出函数名打印基址
        var soAddr = Module.findBaseAddress("lib52pojie.so");
        console.log(soAddr);
        var funcaddr = soAddr.add(0x1071C);  
        console.log(funcaddr);
        if (funcaddr != null) {
            Interceptor.attach(funcaddr, {
                onEnter: function(args) {
                    // args 参数
                },
                onLeave: function(retval) {
                    console.log(retval.toInt32());
                }
            })
        }
    })
}

函数地址计算

在安卓中,通常 32 位的 SO 中使用 thumb 指令,64 位的 SO 中使用 arm 指令。通过 IDA 中的 opcode bytes 来判断,arm 指令为 4 个字节 (Options -> General -> Number of opcode bytes (non-graph) 输入 4)。对于 thumb 指令,函数地址计算方式为:SO 基址 + 函数在 SO 中的偏移 + 1,而 arm 指令的计算方式为:SO 基址 + 函数在 SO 中的偏移。

7. Hook_dlopen

function hook_dlopen() {
    var dlopen = Module.findExportByName(null, "dlopen");
    Interceptor.attach(dlopen, {
        onEnter: function(args) {
            var so_name = args[0].readCString();
            if (so_name.indexOf("lib52pojie.so") >= 0) this.call_hook = true;
        },
        onLeave: function(retval) {
            if (this.call_hook) hookTest2();
        }
    });

    // 高版本 Android 系统使用 android_dlopen_ext
    var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
    Interceptor.attach(android_dlopen_ext, {
        onEnter: function(args) {
            var so_name = args[0].readCString();
            if (so_name.indexOf("lib52pojie.so") >= 0) this.call_hook = true;
        },
        onLeave: function(retval) {
            if (this.call_hook) hookTest2();
        }
    });
}

8. 借助 IDA 脚本实现一键式 hook

安卓破解逆向入门教程 | 轻松学习如何逆向工程并破解安卓应用的方法与技巧-Eswlnk Blog

这就是本次安卓破解逆向入门教程的全部内容。希望你能够通过这些技巧和工具,更深入地了解如何逆向工程和破解安卓应用程序。如果你有任何问题或疑问,欢迎留言讨论!

本站默认网盘访问密码:1166
本站默认网盘访问密码:1166
声明:本站原创文章文字版权归本站所有,转载务必注明作者和出处;本站转载文章仅仅代表原作者观点,不代表本站立场,图文版权归原作者所有。如有侵权,请联系我们删除。
APK函数安卓破解网络安全
0
0
Eswlnk的头像
Eswlnk
一个有点倒霉的研究牲站长
赞赏
来访者请看这里,网盘密码更换提醒!
上一篇
李克强同志逝世
下一篇

评论 (0)

请登录以参与评论
现在登录
    发表评论

猜你喜欢

  • 「漏洞资讯」CVE-2025-12914:宝塔面板曝出注入漏洞
  • 漏洞资讯:Ollama 未授权访问漏洞分析与防护指南
  • 「攻防对抗」利用 fastjson 原生反序列化与动态代理突破安全限制
  • 「攻防对抗」从上传漏洞到Getshell | 一次完整的渗透过程
  • 「日志记录」从零起步揭开路由器漏洞挖掘的面纱
Eswlnk的头像

Eswlnk

一个有点倒霉的研究牲站长
1108
文章
319
评论
679
获赞

随便看看

关于某个采集插件的破解(Crack)
2023-02-02 16:11:48
「技术教程」Nestjs 与Prisma打包部署
2024-01-17 0:54:16
百度又又又开始整治搜索结果啦!
2023-07-04 1:32:30

文章目录

专题展示

WordPress53

工程实践37

热门标签

360 AI API CDN java linux Nginx PDF PHP python SEO Windows WordPress 云服务器 云服务器知识 代码 免费 安全 安卓 工具 开发日志 微信 微软 手机 插件 攻防 攻防对抗 教程 日志 渗透分析 源码 漏洞 电脑 破解 系统 编程 网站优化 网络 网络安全 脚本 苹果 谷歌 软件 运维 逆向
  • 首页
  • 知识库
  • 地图
Copyright © 2023-2025 Eswlnk Blog. Designed by XiaoWu.
本站CDN由 壹盾安全 提供高防CDN安全防护服务
蜀ICP备20002650号-10
页面生成用时 0.751 秒   |  SQL查询 41 次
本站勉强运行:
友情链接: Eswlnk Blog 网站渗透 倦意博客 特资啦!个人资源分享站 祭夜博客 iBAAO壹宝头条
  • WordPress142
  • 网络安全64
  • 漏洞52
  • 软件52
  • 安全48
现在登录
  • 资源
    • 精彩视频
    • 破解专区
      • WHMCS
      • WordPress主题
      • WordPress插件
    • 其他分享
    • 极惠VPS
    • PDF资源
  • 关于我
    • 论文阅读
    • 关于本站
    • 通知
    • 左邻右舍
    • 玩物志趣
    • 日志
    • 专题
  • 热议话题
    • 游戏资讯
  • 红黑
    • 渗透分析
    • 攻防对抗
    • 代码发布
  • 自主研发
    • 知识库
    • 插件
      • ToolBox
      • HotSpot AI 热点创作
    • 区块
    • 快乐屋
    • 卡密
  • 乱步
    • 文章榜单
    • 热门标签
  • 问答中心反馈