文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

frida工具Jnitrace | Objection | r0tracer

2023-08-16 16:48

关注

pip install objection

pip install jnitrace

要求是frida版本大于14点多,目前推荐使用 14.2.18

Frida Version : pip install frida==14.2.18

Jnitrace:

JNItrace是一个基于Frida框架的Hook jni方法的库。https://github.com/chame1eon/jnitrace

直接按照上面的pip安装。

jnitrace -l xxx.so 包名 --ignore-vm

注意:
在这里插入图片描述
如果出现这种错误就是用了面具的隐藏 hide ;

Spawn模式及 jnitrace 都是需要关闭面具隐藏( Magisk Hide )
在这里插入图片描述
不得不说 这真的是个神器。

另外博主有一些笔记,记录如下,方便后续观看:

加密函数定位:

jni| unicorn | androidemu | frida_hook

https://codeooo.blog.csdn.net/article/details/127105204
https://github.com/lasting-yang/frida_hook_libart.git

dump 脚本修复加密so

https://github.com/lasting-yang/frida_dump

frida hook模板:

so :https://codeooo.blog.csdn.net/article/details/122124012

java:

https://codeooo.blog.csdn.net/article/details/120025814

遍历so方法:

https://codeooo.blog.csdn.net/article/details/120033269

hook 常见算法

https://codeooo.blog.csdn.net/article/details/120025814

r0tracer:

安卓Java层多功能追踪脚本

AKA:精简版 objection + Wallbreaker

比objection增加延时spawn
比objection增加批量hook类\方法\构造函数
Wallbreaker在frida14上还是一直崩
比Wallbreaker增加hook看instance的fields
inspectObject函数可以单独拿出去使用

使用方法:
修改r0tracer.js文件最底部处的代码,开启某一个Hook模式。
在这里插入图片描述

var isLite = false;var ByPassTracerPid = function () {    var fgetsPtr = Module.findExportByName("libc.so", "fgets");    var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']);    Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) {        var retval = fgets(buffer, size, fp);        var bufstr = Memory.readUtf8String(buffer);        if (bufstr.indexOf("TracerPid:") > -1) {            Memory.writeUtf8String(buffer, "TracerPid:\t0");            console.log("tracerpid replaced: " + Memory.readUtf8String(buffer));        }        return retval;    }, 'pointer', ['pointer', 'int', 'pointer']));};setImmediate(ByPassTracerPid);(function(){    let Color = {RESET: "\x1b[39;49;00m", Black: "0;01", Blue: "4;01", Cyan: "6;01", Gray: "7;11", "Green": "2;01", Purple: "5;01", Red: "1;01", Yellow: "3;01"};    let LightColor = {RESET: "\x1b[39;49;00m", Black: "0;11", Blue: "4;11", Cyan: "6;11", Gray: "7;01", "Green": "2;11", Purple: "5;11", Red: "1;11", Yellow: "3;11"};        var colorPrefix = '\x1b[3', colorSuffix = 'm'    for (let c in Color){        if (c  == "RESET") continue;        console[c] = function(message){            console.log(colorPrefix + Color[c] + colorSuffix + message + Color.RESET);        }        console["Light" + c] = function(message){            console.log(colorPrefix + LightColor[c] + colorSuffix + message + Color.RESET);        }    }})();function uniqBy(array, key) {    var seen = {};    return array.filter(function (item) {        var k = key(item);        return seen.hasOwnProperty(k) ? false : (seen[k] = true);    });}function hasOwnProperty(obj, name) {    try {        return obj.hasOwnProperty(name) || name in obj;    } catch (e) {        return obj.hasOwnProperty(name);    }}function getHandle(object) {    if (hasOwnProperty(object, '$handle')) {        if (object.$handle != undefined) {            return object.$handle;        }    }    if (hasOwnProperty(object, '$h')) {        if (object.$h != undefined) {            return object.$h;        }    }    return null;}//查看域值function inspectObject(obj, input) {    var isInstance = false;    var obj_class = null;    if (getHandle(obj) === null) {        obj_class = obj.class;    } else {        var Class = Java.use("java.lang.Class");        obj_class = Java.cast(obj.getClass(), Class);        isInstance = true;    }    input = input.concat("Inspecting Fields: => ", isInstance, " => ", obj_class.toString());    input = input.concat("\r\n")    var fields = obj_class.getDeclaredFields();    for (var i in fields) {        if (isInstance || Boolean(fields[i].toString().indexOf("static ") >= 0)) {            // output = output.concat("\t\t static static static " + fields[i].toString());            var className = obj_class.toString().trim().split(" ")[1];            // console.Red("className is => ",className);            var fieldName = fields[i].toString().split(className.concat(".")).pop();            var fieldType = fields[i].toString().split(" ").slice(-2)[0];            var fieldValue = undefined;            if (!(obj[fieldName] === undefined))                fieldValue = obj[fieldName].value;            input = input.concat(fieldType + " \t" + fieldName + " => ", fieldValue + " => ", JSON.stringify(fieldValue));            input = input.concat("\r\n")        }    }    return input;}// trace单个类的所有静态和实例方法包括构造方法 trace a specific Java Methodfunction traceMethod(targetClassMethod) {    var delim = targetClassMethod.lastIndexOf(".");    if (delim === -1) return;    var targetClass = targetClassMethod.slice(0, delim)    var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length)    var hook = Java.use(targetClass);    var overloadCount = hook[targetMethod].overloads.length;    console.Red("Tracing Method : " + targetClassMethod + " [" + overloadCount + " overload(s)]");    for (var i = 0; i < overloadCount; i++) {        hook[targetMethod].overloads[i].implementation = function () {            //初始化输出            var output = "";            //画个横线            for (var p = 0; p < 100; p++) {                output = output.concat("==");            }            //域值            if (!isLite) { output = inspectObject(this, output); }            //进入函数            output = output.concat("\n*** entered " + targetClassMethod);            output = output.concat("\r\n")            // if (arguments.length) console.Black();            //参数            var retval = this[targetMethod].apply(this, arguments);            if (!isLite) {                for (var j = 0; j < arguments.length; j++) {                    output = output.concat("arg[" + j + "]: " + arguments[j] + " => " + JSON.stringify(arguments[j]));                    output = output.concat("\r\n")                }                //调用栈                output = output.concat(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));                //返回值                output = output.concat("\nretval: " + retval + " => " + JSON.stringify(retval));            }            // inspectObject(this)            //离开函数            output = output.concat("\n*** exiting " + targetClassMethod);            //最终输出            // console.Black(output);            var r = parseInt((Math.random() * 7).toFixed(0));            var i = r;            var printOutput = null;            switch (i) {                case 1:                    printOutput = console.Red;                    break;                case 2:                    printOutput = console.Yellow;                    break;                case 3:                    printOutput = console.Green;                    break;                case 4:                    printOutput = console.Cyan;                    break;                case 5:                    printOutput = console.Blue;                    break;                case 6:                    printOutput = console.Gray;                    break;                default:                    printOutput = console.Purple;            }            printOutput(output);            return retval;        }    }}function traceClass(targetClass) {    //Java.use是新建一个对象哈,大家还记得么?    var hook = Java.use(targetClass);    //利用反射的方式,拿到当前类的所有方法    var methods = hook.class.getDeclaredMethods();        //建完对象之后记得将对象释放掉哈    hook.$dispose;    //将方法名保存到数组中    var parsedMethods = [];    var output = "";        output = output.concat("\tSpec: => \r\n")    methods.forEach(function (method) {        output = output.concat(method.toString())        output = output.concat("\r\n")        parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]);    });    //去掉一些重复的值    var Targets = uniqBy(parsedMethods, JSON.stringify);    // targets = [];    var constructors = hook.class.getDeclaredConstructors();    if (constructors.length > 0) {        constructors.forEach(function (constructor) {            output = output.concat("Tracing ", constructor.toString())            output = output.concat("\r\n")        })        Targets = Targets.concat("$init")    }    //对数组中所有的方法进行hook,    Targets.forEach(function (targetMethod) {        traceMethod(targetClass + "." + targetMethod);    });    //画个横线    for (var p = 0; p < 100; p++) {        output = output.concat("+");    }    console.Green(output);}function hook(white, black, target = null) {    console.Red("start")    if (!(target === null)) {        console.LightGreen("Begin enumerateClassLoaders ...")        Java.enumerateClassLoaders({            onMatch: function (loader) {                try {                    if (loader.findClass(target)) {                        console.Red("Successfully found loader")                        console.Blue(loader);                        Java.classFactory.loader = loader;                        console.Red("Switch Classloader Successfully ! ")                    }                }                catch (error) {                    console.Red(" continuing :" + error)                }            },            onComplete: function () {                console.Red("EnumerateClassloader END")            }        })    }    console.Red("Begin Search Class...")    var targetClasses = new Array();    Java.enumerateLoadedClasses({        onMatch: function (className) {            if (className.toString().toLowerCase().indexOf(white.toLowerCase()) >= 0 &&               (black == null || black == '' || className.toString().toLowerCase().indexOf(black.toLowerCase()) < 0)) {                console.Black("Found Class => " + className)                targetClasses.push(className);                traceClass(className);            }        }, onComplete: function () {            console.Black("Search Class Completed!")        }    })    var output = "On Total Tracing :"+String(targetClasses.length)+" classes :\r\n";    targetClasses.forEach(function(target){        output = output.concat(target);        output = output.concat("\r\n")            })    console.Green(output+"Start Tracing ...")}function main() {    Java.perform(function () {        console.Purple("r0tracer begin ... !")        //0. 增加精简模式,就是以彩虹色只显示进出函数。默认是关闭的,注释此行打开精简模式。        //isLite = true;                //A. 简易trace单个函数        traceClass("javax.crypto.Cipher")        //B. 黑白名单trace多个函数,第一个参数是白名单(包含关键字),第二个参数是黑名单(不包含的关键字)        // hook("javax.crypto.Cipher", "$");        //C. 报某个类找不到时,将某个类名填写到第三个参数,比如找不到com.roysue.check类。(前两个参数依旧是黑白名单)        // hook("com.roysue.check"," ","com.roysue.check");            })}setImmediate(main)//// setTimeout(main, 2000);// 玄之又玄,众妙之门// Frida的崩溃有时候真的是玄学,大项目一崩溃根本不知道是哪里出的问题,这也是小而专的项目也有一丝机会的原因// Frida自身即会经常崩溃,建议多更换Frida(客/服要配套)版本/安卓版本,我自己常用的组合是两部手机,Frida12.8.0全家桶+安卓8.1.0,和Frida14.2.2全家桶+安卓10 

肉佬:https://github.com/r0ysue/r0tracer

推荐使用Frida14版本,并且将日志使用-o参数进行输出保存

frida -U -f com.r0ysue.example -l r0tracer.js --no-pause -o saveLog5.txt

“-f” 为 Spawn模式,去掉"-f" 为Attach模式

Frida版本=<12时,要加上–runtime=v8选项

frida -U com.r0ysue.example -l r0tracer.js --runtime=v8 --no-pause -o
saveLog6.txt

objection:

objection 启动界面:
在这里插入图片描述
使用objection需要在手机上启动frida-sesver,再使用objection注入需要hook的应用

objection -g <包名> explore

下面指令中,有hook类,hook方法,前进程模块,导出函数等

Memory 指令    memory list modules               //枚举当前进程模块    memory list exports [lib_name]    //查看指定模块的导出函数    memory list exports libart.so --json /root/libart.json //将结果保存到json文件中    memory search --string --offsets-only                  //搜索内存android heap 指令    //堆内存中搜索指定类的实例, 可以获取该类的实例id    search instances search instances com.xx.xx.class         //直接调用指定实例下的方法    android heap execute [ins_id] [func_name]         //自定义frida脚本, 执行实例的方法    android heap execute [ins_id]android 指令    android root disable   //尝试关闭app的root检测    android root simulate  //尝试模拟root环境        android ui screenshot [image.png]    //截图    android ui FLAG_SECURE false         //设置FLAG_SECURE权限内存漫游    android hooking list classes    //列出内存中所有的类         //在内存中所有已加载的类中搜索包含特定关键词的类    android hooking search classes [search_name]          //在内存中所有已加载的方法中搜索包含特定关键词的方法    android hooking search methods [search_name]          //直接生成hook代码    android hooking generate simple [class_name]hook 方式        android hooking watch class_method com.xxx.xxx.methodName --dump-args --dump-backtrace --dump-return         //hook指定类, 会打印该类下的所有调用    android hooking watch class com.xxx.xxx         //设置返回值(只支持bool类型)    android hooking set return_value com.xxx.xxx.methodName falseSpawn 方式 Hook    objection -g packageName explore --startup-command '[obejection_command]'activity 和 service 操作    android hooking list activities                   //枚举activity    android intent launch_activity [activity_class]   //启动activity    android hooking list services                     //枚举services    android intent launch_service [services_class]    //启动services任务管理器    jobs list            // 查看任务列表    jobs kill [task_id]  // 关闭任务关闭 app 的 ssl 校验    android sslpinning disable监控系统剪贴板    // 获取Android剪贴板服务上的句柄并每5秒轮询一次用于数据。     // 如果发现新数据,与之前的调查不同,则该数据将被转储到屏幕上。    help android  clipboard执行命令行    help android shell_exec [command]

查看当前可用的activity或者service:

android hooking list activities/services

这个也可以使用adb查看:

(1)查看当前Activity :adb shell "dumpsys window w | grep name="(2)查看当前栈顶的Activity :adb shell "dumpsys activity | grep mFocusedActivity"或者:adb shell dumpsys activity activities | grep mResumedActivity(3)查看当前栈顶的Activity的Fragment :adb shell dumpsys activity 包名

来源地址:https://blog.csdn.net/weixin_38927522/article/details/127120012

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯