吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 16044|回复: 103
收起左侧

[Android 原创] 《安卓逆向这档事》十五、是时候学习一下Frida一把梭了(下)

  [复制链接]
正己 发表于 2023-10-2 23:19
本帖最后由 正己 于 2023-10-10 19:10 编辑

一、课程目标

1.了解Frida-Native-Hook
2.借助ida脚本实现一键式hook

二、工具

1.教程Demo(更新)
2.jadx-gui
3.VS Code

三、课程内容

1.Process、Module、Memory基础

1.Process

Process 对象代表当前被Hook的进程,能获取进程的信息,枚举模块,枚举范围等

API 含义
Process.id 返回附加目标进程的 PID
Process.isDebuggerAttached() 检测当前是否对目标程序已经附加
Process.enumerateModules() 枚举当前加载的模块,返回模块对象的数组
Process.enumerateThreads() 枚举当前所有的线程,返回包含 id, state, context 等属性的对象数组

2.Module

Module 对象代表一个加载到进程的模块(例如,在 Windows 上的 DLL,或在 Linux/Android 上的 .so 文件),能查询模块的信息,如模块的基址、名称、导入/导出的函数等

API 含义
Module.load() 加载指定so文件,返回一个Module对象
enumerateImports() 枚举所有Import库函数,返回Module数组对象
enumerateExports() 枚举所有Export库函数,返回Module数组对象
enumerateSymbols() 枚举所有Symbol库函数,返回Module数组对象
Module.findExportByName(exportName)、Module.getExportByName(exportName) 寻找指定so中export库中的函数地址
Module.findBaseAddress(name)、Module.getBaseAddress(name) 返回so的基地址

3.Memory

Memory是一个工具对象,提供直接读取和修改进程内存的功能,能够读取特定地址的值、写入数据、分配内存等

方法 功能
Memory.copy() 复制内存
Memory.scan() 搜索内存中特定模式的数据
Memory.scanSync() 同上,但返回多个匹配的数据
Memory.alloc() 在目标进程的堆上申请指定大小的内存,返回一个NativePointer
Memory.writeByteArray() 将字节数组写入一个指定内存
Memory.readByteArray 读取内存

2.枚举导入导出表

  1. 导出表(Export Table):列出了库中可以被其他程序或库访问的所有公开函数和符号的名称。
  2. 导入表(Import Table):列出了库需要从其他库中调用的函数和符号的名称。

简而言之,导出表告诉其他程序:“这些是我提供的功能。”,而导入表则表示:“这些是我需要的功能。”。

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打印

  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是Frida里的一个拦截器
            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());
                }
            })
        }
    })
    }
  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修改

  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());
                }
            })
        }
    })
    }
  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基址的获取方式

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

6.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){  //retval返回值
                    console.log(retval.toInt32());
                }
            })
        }
    })
}

函数地址计算

  1. 安卓里一般32 位的 so 中都是thumb指令,64 位的 so 中都是arm指令
  2. 通过IDA里的opcode bytes来判断,arm 指令为 4 个字节(options -> general -> Number of opcode bytes (non-graph)  输入4)
  3. thumb 指令,函数地址计算方式: so 基址 + 函数在 so 中的偏移 + 1
    arm 指令,函数地址计算方式: so 基址 + 函数在 so 中的偏移

7.Hook_dlopen

dlopen源码
android_dlopen_ext源码

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

图片
IDA&Frida 学习

五、答疑

待更新

六、视频及课件地址

百度云
阿里云
哔哩哔哩
开源项目地址
PS:解压密码都是52pj,阿里云由于不能分享压缩包,所以下载exe文件,双击自解压

七、其他章节

《安卓逆向这档事》一、模拟器环境搭建
《安卓逆向这档事》二、初识APK文件结构、双开、汉化、基础修改
《安卓逆向这档事》三、初识smail,vip终结者
《安卓逆向这档事》四、恭喜你获得广告&弹窗静默卡
《安卓逆向这档事》五、1000-7=?&动态调试&Log插桩
《安卓逆向这档事》六、校验的N次方-签名校验对抗、PM代{过}{滤}理、IO重定向
《安卓逆向这档事》七、Sorry,会Hook真的可以为所欲为-Xposed快速上手(上)模块编写,常用Api
《安卓逆向这档事》八、Sorry,会Hook真的可以为所欲为-xposed快速上手(下)快速hook
《安卓逆向这档事》九、密码学基础、算法自吐、非标准加密对抗
《安卓逆向这档事》十、不是我说,有了IDA还要什么女朋友?
《安卓逆向这档事》十二、大佬帮我分析一下
《安卓逆向这档事》番外实战篇1-某电影视全家桶
《安卓逆向这档事》十三、是时候学习一下Frida一把梭了(上)
《安卓逆向这档事》十四、是时候学习一下Frida一把梭了(中)

八、参考文档

FRIDA-API使用篇:rpc、Process、Module、Memory使用方法及示例
IDA&Frida 学习
Frida Hook 常用函数、java 层 hook、so 层 hook、RPC、群控



免费评分

参与人数 53威望 +1 吾爱币 +76 热心值 +49 收起 理由
paddling + 1 + 1 我很赞同!
疯神爱慕 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
X1a0 + 1 + 1 用心讨论,共获提升!
LCSZY + 1 谢谢@Thanks!
wangchuan1 + 1 + 1 谢谢@Thanks!
Ty007 + 1 + 1 谢谢@Thanks!
Bienaoing + 1 谢谢@Thanks!
Puremilk + 1 + 1 用心讨论,共获提升!
AIQ + 1 + 1 我很赞同!
smfc + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
woyucheng + 1 + 1 谢谢@Thanks!
losser + 1 + 1 我很赞同!
sogaha + 1 + 1 热心回复!
JaniQuiz + 1 + 1 用心讨论,共获提升!
z1018889697 + 1 + 1 谢谢@Thanks!
moyinya + 1 + 1 谢谢@Thanks!
x229827570 + 1 + 1 谢谢@Thanks!
zhang19960210 + 1 + 1 热心回复!
多幸运遇见baby + 1 + 1 谢谢@Thanks!
MFC + 1 + 1 谢谢@Thanks!
月清晖 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
hongmengshikong + 1 + 1 谢谢@Thanks!
风子09 + 1 + 1 我很赞同!
jobs_steven + 1 + 1 用心讨论,共获提升!
w220913 + 1 + 1 我很赞同!
小宝贝233 + 1 + 1 谢谢@Thanks!
Jianguan12345 + 1 + 1 我很赞同!
JIAN_ + 1 用心讨论,共获提升!
debug_cat + 2 + 1 谢谢@Thanks!
小菜鸟一枚 + 1 + 1 用心讨论,共获提升!
ghyfxy + 1 + 1 虽然我看不懂,但我必须支持这种分享,现在都TM的知识收费了。
demimule + 1 谢谢@Thanks!
Courser + 1 + 1 谢谢@Thanks!
twodoors + 1 谢谢@Thanks!
世忘nb + 1 + 1 我很赞同!
wystudio + 2 + 1 用心讨论,共获提升!
hanghaidongchen + 1 + 1 正好需要这个
Chenda1 + 1 + 1 我很赞同!
sxhytds + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
vaycore + 1 谢谢@Thanks!
hbqjxhw + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
我是不会改名的 + 4 + 1 谢谢@Thanks!
芽衣 + 1 + 1 用心讨论,共获提升!
BonnieRan + 1 + 1 谢谢@Thanks!
zhangxu888 + 1 + 1 我很赞同!
为之奈何? + 1 + 1 我很赞同!
owouwu + 1 + 1 谢谢@Thanks!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
wenrow + 1 + 1 用心讨论,共获提升!
D小小贱 + 3 + 1 谢谢@Thanks!
風信子 + 1 + 1 用心讨论,共获提升!
布拉格灬征战 + 1 + 1 热心回复!
hrh123 + 1 + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 正己 发表于 2023-10-2 23:20
卡个一周年,视频剪辑中,路过的师傅帮忙点个star
开源项目地址
笨笨家的唯一 发表于 2024-4-8 18:14
本帖最后由 笨笨家的唯一 于 2024-4-8 19:33 编辑
正己 发表于 2023-12-15 12:15
你要先判断是64位还是32位的架构,然后用ida去查看真实的地址,你那边不一定是和我一致的

大佬,我也遇到了他说的问题,hook checkVip时报错,hook其他两个不报错。我找了另一个样本来试也是,模拟器hook不上,报错,但是换真机(安卓7安装不了教程Demo)就可以了。这个要怎么解决。

这里多嘴说一句,大佬在视频中用的真机,地址偏移量没有问题,用模拟器的小可爱要注意,看地址偏移量要把教程Demo中【lib\x86】文件夹下的【lib52pojie.so】丢进IDA,然后查看函数的偏移量,比如教程中的【Java_com_zj_wuaipojie_util_SecurityUtil_diamondNum】偏移量是【0000A2A0        】
D小小贱 发表于 2023-10-3 00:19
SuperMelon 发表于 2023-10-3 00:20
大佬牛逼,辛苦了,希望有一些范例看看什麽地方用得着

点评

范例参考视频教程哦  详情 回复 发表于 2023-10-3 09:47
小肥元 发表于 2023-10-3 07:53
基础贴很重要
BonnieRan 发表于 2023-10-3 09:11
看完文章 坐等视频,
xiaobaixuepj 发表于 2023-10-3 09:32
感谢分享
 楼主| 正己 发表于 2023-10-3 09:47
SuperMelon 发表于 2023-10-3 00:20
大佬牛逼,辛苦了,希望有一些范例看看什麽地方用得着

范例参考视频教程哦
222shuai 发表于 2023-10-3 15:12
感谢分享
zhangxiaosi 发表于 2023-10-3 17:41
感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-27 19:36

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表