首页 > 编程语言 >r0tracer 源码分析

r0tracer 源码分析

时间:2023-04-16 16:22:29浏览次数:59  
标签:分析 function console hook 源码 r0tracer var output concat

使用方法

修改r0tracer.js文件最底部处的代码,开启某一个Hook模式。

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");        
    })
}

三种hook方式
一 hook 已知的类
traceClass("javax.crypto.Cipher")
二 hook 关键字(黑白名单,前面时要寻找的关键字,后面时忽略的关键字)
hook("javax.crypto.Cipher", "$")
三 hook 关键字(黑白名单 + 第三个参数 关键类,前面时要寻找的关键字,后面时忽略的关键字)
报某个类找不到时,将某个类名填写到第三个参数
hook("com.roysue.check"," ","com.roysue.xxx")

第三种是因为可能某个类不在当前classloader中,需要遍历所有classloader去寻找

执行命令
frida -U -f com.xxx.xxx -l r0tracer.js --no-pause -o saveLog5.txt

源码解读

核心方法

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 ...")
}
  1. 如果填了关键方法, 回去遍历所有的classloader,并将当前使用的classloader设置为包含目标类的classloader
  2. 遍历这个classloader所有的类,满足黑白名单的情况下,将类名推入targetClasses
  3. 执行traceClass
function traceClass(targetClass) {
    //Java.use是新建一个对象哈,大家还记得么?
    var hook = Java.use(targetClass);
    //利用反射的方式,拿到当前类的所有方法
    var methods = hook.class.getDeclaredMethods();    
    //建完对象之后记得将对象释放掉哈
    hook.$dispose;
    //将方法名保存到数组中
    var parsedMethods = [];
......
    methods.forEach(function (method) {
        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);
    });
......
}

这里是找到targetClass下所有的方法和构造方法,对每个方法都执行traceMethod

function 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);
    if(!hook[targetMethod]){
        return;
    }
    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;
        }
    }
}

在这里打印类的成员的值,和追踪方法的入参和出参的值,并打印出调用堆栈

开源项目地址:
https://github.com/r0ysue/r0tracer

标签:分析,function,console,hook,源码,r0tracer,var,output,concat
From: https://www.cnblogs.com/gradyblog/p/17323477.html

相关文章

  • eureka源码简单剖析-服务端(服务接口暴露策略)
    下面来看下服务接口暴露的策略。其中服务端使用了Jersey框架,而Jersey框架是一个发布restful风格接口的框架,类似我们使用的springmvc, 然后下面看下jersey部分    以上就是服务接口暴露的相关策略部分......
  • 范数经典问题的推导与分析
    本文将主要围绕范数的经典问题进行推导、分析。LASSO问题推导​ 问题定义:\(\underset{x}{\min}||y-X\beta||_2^2+\tau||\beta||_\mathcal{A}\)​ 问题推导:​ 0、上述问题是典型的无约束问题,可以通过变量替换的思想进行处理。​ 1、令\(z=X\beta\),上述问题更新为\(g(u)=\min_......
  • 高通量测序的数据处理与分析指北(二)-宏基因组篇
    宏基因组篇前言之前的一篇文章已经从生物实验的角度讲述了高通量测序的原理,这篇文章旨在介绍宏基因组二代测序数据的处理方式及其原理。在正文开始之前,我们先来认识一下什么是宏基因组。以我的理解,宏基因组就是某环境中所有生物的基因组的合集,这个环境可以是下水道,河流等自然环......
  • Visual Studio Code开发常用的工具栏选项,查看源码技巧以及【vscode常用的快捷键】
    一、开发常用的工具栏选项1、当前打开的文件快速在左侧资源树中定位:其实打开了当前的文件已经有在左侧资源树木定位了,只是颜色比较浅2、打开太多文件的时候,可以关闭3、设置查看当前类或文件的结构OUTLINE相当于idea查看当前类或接口的结构Structure二、查看......
  • OPCUA实践之winnt服务源码分享
    前言孔乙己显出极高兴的样子,将两个指头的长指甲敲着柜台,点头说:“对呀,对呀!......OPCUA,你用过么?”大家好,我是44岁的大龄程序员码农阿峰。离开上一个项目近半年了,这时当时在项目做的3个winnt服务,算是OPCUA的初次使用,代码并没有什么出彩的地方,却是能正常运行,而且工作了近1年的时......
  • 《需求工程—软件建模与分析》1
    功能需求中按抽象层次的高低分为业务需求、用户需求、系统需求。业务需求是系统的目标,用户需求是系统的任务,系统需求是系统的行为。 对于非功能需求,我们很难在系统完成之前清晰地看到,很多时候是在系统完成之后才会发现非功能需求。在解决系统成功或失败的因素中,非功能需求与功......
  • 深度分析Palantir的投资价值,Palantir2023年将实现强劲反弹?
    在本文中,猛兽财经将通过对Palantir的股票关键指标、商业模式、盈利能力、影响Palantir2023年股价的关键利好因素等方面,对Palantir进行全面、深度的分析。Palantir股票的关键指标自从Palantir(PLTR)的股价在2021年1月25日大幅上涨至35.18美元后,其股价就开始下跌,并在2022年底下跌到了......
  • 使用stanza完成自然语言分析处理任务
    安装stanza直接使用pip命令即可安装stanzapackagepipinstallstanza构建管道stanza中的管道用于构建NLP任务的模型加载序列、文本处理序列。需要注意,当本地不存在指定的Processor模型时,Pipeline对象会执行一个自动下载程序,将模型下载到本地。Pipeline的初始化示例import......
  • javascript常用的循环对比及性能分析
    结论:js中的for循环只有在处理百万条数据以上才会展示出他的强大性能,和看出明显优势,但是在百万条数据往下甚至到个位数的数据量通常都是for和while还有do...while不相上下,反而后两者更加优势明显下面是测试耗时截图(在不同浏览器也会有所不同,我这是Chrome版本111.0.5563.149)......
  • 技术人员创业的第一步分析
    概述:看完了本文,基本上可以了解确认自己所掌握的技术是否适合创业,如果不适合,不如找个大公司长期停留,也挺好的,免得折腾!————————————————————前几天和一个朋友聊天,聊到了创业的公司和技术的问题,突然意识到创业中有一个关键性的问题,那就是技术成果的可复制性对是否......