【问题标题】:How to print called functions in android?如何在android中打印调用的函数?
【发布时间】:2019-08-13 18:14:31
【问题描述】:

我在 APK 上使用 frida,我试图打印出正在调用的函数,尤其是发送给它的参数。我的环境设置正确,因为我可以打印出类,并根据文档执行各种操作。

这是我找到的最接近的: https://codeshare.frida.re/@razaina/get-a-stack-trace-in-your-hook/

但是代码给出了错误(ThreadDef undefined 等等)

而 frida 文档并没有帮助我达到我想要的目标。

有什么指导吗?建议?帮忙?

【问题讨论】:

    标签: frida


    【解决方案1】:

    codeshare@razaina 的代码有可以轻松修复的错误 (threadef != ThreadDef)

    var printBacktrace = function () {
        Java.perform(function() {
            var JLog = Java.use('android.util.Log'), JException = Java.use('java.lang.Exception');
            // getting stacktrace by throwing an exception
            console.warn(JLog.getStackTraceString(JException.$new()));
        });
    };
    

    只要打电话给printBacktrace(),你就想看看是谁调用了你的钩子函数。

    如果你想钩住Java类的所有方法你可以使用这个sn-p;

    
    var 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",
        Light: {
            Black: "0;11", Blue: "4;11", Cyan: "6;11", Gray: "7;01", Green: "2;11", Purple: "5;11", Red: "1;11", Yellow: "3;11"
        }
    };
    
    /**
     *
     * @param input. 
     *      If an object is passed it will print as json 
     * @param kwargs  options map {
     *     -l level: string;   log/warn/error
     *     -i indent: boolean;     print JSON prettify
     *     -c color: @see ColorMap
     * }
     */
    var LOG = function (input, kwargs) {
        kwargs = kwargs || {};
        var logLevel = kwargs['l'] || 'log', colorPrefix = '\x1b[3', colorSuffix = 'm';
        if (typeof input === 'object')
            input = JSON.stringify(input, null, kwargs['i'] ? 2 : null);
        if (kwargs['c'])
            input = colorPrefix + kwargs['c'] + colorSuffix + input + Color.RESET;
        console[logLevel](input);
    };
    
    var printBacktrace = function () {
        Java.perform(function() {
            var android_util_Log = Java.use('android.util.Log'), java_lang_Exception = Java.use('java.lang.Exception');
            // getting stacktrace by throwing an exception
            LOG(android_util_Log.getStackTraceString(java_lang_Exception.$new()), { c: Color.Gray });
        });
    };
    
    function traceClass(targetClass) {
        var hook;
        try {
            hook = Java.use(targetClass);
        } catch (e) {
            console.error("trace class failed", e);
            return;
        }
    
        var methods = hook.class.getDeclaredMethods();
        hook.$dispose();
    
        var parsedMethods = [];
        methods.forEach(function (method) {
            var methodStr = method.toString();
            var methodReplace = methodStr.replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1];
             parsedMethods.push(methodReplace);
        });
    
        uniqBy(parsedMethods, JSON.stringify).forEach(function (targetMethod) {
            traceMethod(targetClass + '.' + targetMethod);
        });
    }
    
    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);
        var overloadCount = hook[targetMethod].overloads.length;
    
        LOG({ tracing: targetClassMethod, overloaded: overloadCount }, { c: Color.Green });
    
        for (var i = 0; i < overloadCount; i++) {
            hook[targetMethod].overloads[i].implementation = function () {
                var log = { '#': targetClassMethod, args: [] };
    
                for (var j = 0; j < arguments.length; j++) {
                    var arg = arguments[j];
                    // quick&dirty fix for java.io.StringWriter char[].toString() impl because frida prints [object Object]
                    if (j === 0 && arguments[j]) {
                        if (arguments[j].toString() === '[object Object]') {
                            var s = [];
                            for (var k = 0, l = arguments[j].length; k < l; k++) {
                                s.push(arguments[j][k]);
                            }
                            arg = s.join('');
                        }
                    }
                    log.args.push({ i: j, o: arg, s: arg ? arg.toString(): 'null'});
                }
    
                var retval;
                try {
                    retval = this[targetMethod].apply(this, arguments); // might crash (Frida bug?)
                    log.returns = { val: retval, str: retval ? retval.toString() : null };
                } catch (e) {
                    console.error(e);
                }
                LOG(log, { c: Color.Blue });
                return retval;
            }
        }
    }
    
    // remove duplicates from array
    function uniqBy(array, key) {
        var seen = {};
        return array.filter(function (item) {
            var k = key(item);
            return seen.hasOwnProperty(k) ? false : (seen[k] = true);
        });
    }
    
    
    var Main = function() {
        Java.perform(function () { // avoid java.lang.ClassNotFoundException
            [
                // "java.io.File",
                'java.net.Socket',
                'com.package.MyCustomClass'
            ].forEach(traceClass);
    
        });
    };
    
    Java.perform(Main);
    

    【讨论】:

    • 非常有用,但是如果输入 args 有数据缓冲区,那么它很慢,可能是由于 arg 转储将数据数组转换为大字符串,我们如何避免这种情况只打印一个信息,例如仅打印缓冲区长度。
    猜你喜欢
    • 1970-01-01
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-03
    • 2012-01-09
    • 1970-01-01
    相关资源
    最近更新 更多