FRIDA 实用手册

FRIDA 实用手册

本文目的是作为工具类文章,收集整理了一些 FRIDA 的使用技巧和用例,方便同学们在开发使用过程中开袋即食。

frida 的基础教程可以直接参看官网说明。

Python 部分

JS 中文支持

使用 codecs.open(scriptpath, "r", "utf-8") 打开文件读取 js 即可。

获取指定 UID 设备

device = frida.get_device_manager().get_device("094fdb0a0b0df7f8")

获取远程设备

mgr = frida.get_device_manager()

device = mgr.add_remote_device("30.137.25.128:13355")

启动调试进程

pid = device.spawn([packename])

process = device.attach(pid)

script = process.create_script(jscode)

script.on(‘message’, on_message)

script.load()

device.resume(pid)

python 与 js 交互的官方示例

from future
import print_function

import frida

import sys

session = frida.attach("hello")

script = session.create_script("""

Interceptor.attach(ptr("%s"), {

onEnter: function(args) {
    send(args[0].toString());
    var op = recv('input', function(value) {
        args[0] = ptr(value.payload);
    });
    op.wait();
}

});

""" % int(sys.argv[1], 16))

def on_message(message, data):

print(message)
val = int(message['payload'], 16)
script.post({'type': 'input', 'payload': str(val * 2)})

script.on(‘message’, on_message)

script.load()

sys.stdin.read()

从 bytecode 加载脚本

- coding: utf-8 -

from future
import print_function

import frida

system_session = frida.attach(0)

bytecode = system_session.compile_script(name="bytecode-example", source="""/

‘use strict';

rpc.exports = {

listThreads: function () {

return Process.enumerateThreadsSync();

}

};

""")

session = frida.attach("Twitter")

script = session.create_script_from_bytes(bytecode)

script.load()

api = script.exports

这里的 list_threads 是 listThreads 驼峰命名法自动转换后的结果,由 rpc exports 功能导出给 python 调用

print("api.list_threads() =>", api.list_threads())

JS 部分

hook Android 短信发送 SendDataMessage

function hook_sms() {

var SmsManager = Java.use('android.telephony.SmsManager');
SmsManager.sendDataMessage.implementation = function (
    destinationAddress, scAddress, destinationPort, data, sentIntent, deliveryIntent) {
    console.log("sendDataMessage destinationAddress: " + destinationAddress + " port: " + destinationPort);
    showStacks();
    this.sendDataMessage(destinationAddress, scAddress, destinationPort, data, sentIntent, deliveryIntent);
}

}

定时执行函数

setTimeout 延迟执行一次

setTimeout(funcA, 15000);

setInterval 间隔循环执行

var id_ = setInterval(funcB, 15000);

clearInterval(id_); // 终止

bin array 转字符串

function bin2String(array) {

if (null == array) {
    return "null";
}
var result = "";
try {
    var String_java = Java.use('java.lang.String');
    result = String_java.$new(array);
}
catch (e) {
    dmLogout("== use bin2String_2 ==");
    result = bin2String_2(array);
}

return result;

}

function bin2String_2(array) {

var result = "";
try {
    var tmp = 0;
    for (var i = 0; i < array.length; i++) {
        tmp = parseInt(array[i]);
        if ( tmp == 0xc0
            || (tmp < 32 && tmp != 10)
            || tmp > 126 )  {
            return result;
        }  // 不是可见字符就返回了, 换行符除外
        result += String.fromCharCode(parseInt(array[i].toString(2), 2));
    }
}
catch (e) {
    console.log(e);
}
return result;

}

自己封装输出函数加入线程ID 和时间

function getFormatDate() {

var date = new Date();
var month = date.getMonth() + 1;
var strDate = date.getDate();
if (month >= 1 && month <= 9) {
    month = "0" + month;
}
if (strDate >= 0 && strDate <= 9) {
    strDate = "0" + strDate;
}
var currentDate = date.getFullYear() + "-" + month + "-" + strDate
        + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
return currentDate;

}

function dmLogout(str) {

var threadid = Process.getCurrentThreadId();
console.log("["+threadid+"][" + getFormatDate() + "]" + str);

}

打印 Android Java 层堆栈

var showStacks = function () {

Java.perform(function () {
    dmLogout(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));  // 打印堆栈
});

}

TracerPid fgets 反调试

var anti_fgets = function () {

dmLogout("anti_fgets");
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");
        // dmLogout("tracerpid replaced: " + Memory.readUtf8String(buffer));
    }
    return retval;
}, 'pointer', ['pointer', 'int', 'pointer']));

};

反调试时读取 LR 寄存器溯源

var anti_antiDebug = function() {

var funcPtr = null;

 funcPtr = Module.findExportByName("xxxx.so", "p57F7418DCD0C22CD8909F9B22F0991D3");

dmLogout("anti_antiDebug " + funcPtr);
Interceptor.replace(funcPtr, new NativeCallback(function (pathPtr, flags) {
    dmLogout("anti ddddddddddddddebug LR: " + this.context.lr);
    return 0;
}, 'int', ['int', 'int']));

};

hook JNI API NewStringUTF

function hook_native_newString() {

var env = Java.vm.getEnv();
var handlePointer = Memory.readPointer(env.handle);
dmLogout("env handle: " + handlePointer);
var NewStringUTFPtr = Memory.readPointer(handlePointer.add(0x29C));
dmLogout("NewStringUTFPtr addr: " + NewStringUTFPtr);
Interceptor.attach(NewStringUTFPtr, {
    onEnter: function (args) {
        ...
    }
});

}

hook JNI API GetStringUTFChars

function hook_native_GetStringUTFChars() {

var env = Java.vm.getEnv();
var handlePointer = Memory.readPointer(env.handle);
dmLogout("env handle: " + handlePointer);
var GetStringUTFCharsPtr = Memory.readPointer(handlePointer.add(0x2A4));
dmLogout("GetStringUTFCharsPtr addr: " + GetStringUTFCharsPtr);
Interceptor.attach(GetStringUTFCharsPtr, {
    onEnter: function (args) {
        var str = "";
        Java.perform(function () {
            str = Java.cast(args[1], Java.use('java.lang.String'));
        });
        dmLogout("GetStringUTFChars: " + str);
        if (str.indexOf("linkData:") > -1) {    // 设置过滤条件
            dmLogout("========== found linkData LR: " + this.context.lr + "  ==========");
        }
    }
});

};

循环输出参数的值

Interceptor.attach(Module.findExportByName("libc.so", "strcat"), {

onEnter: function (args) {
    for (var i = 0; i < args.length; i ++) {
        dmLogout("strcat args[" + i + "](" + ptr(args[i]) + "): " + Memory.readUtf8String(args[i]));
    }
}

});

hook Android URI 打印堆栈

var hook_uri = function() {

// coord: (7520,0,19) | addr: Ljava/net/URI;->parseURI(Ljava/lang/String;Z)V | loc: ?
var uri = Java.use('java.net.URI');
uri.parseURI.implementation = function (a1, a2) {
    a1 = a1.replace("xxxx.com", "yyyy.com");

    dmLogout("uri: " + a1);
    showStacks();
    return this.parseURI(a1, a2);
}

}

hook KXmlSerializer 拼装内容

function hook_xml() {

var xmlSerializer = Java.use('org.kxml2.io.KXmlSerializer');    // org.xmlpull.v1.XmlSerializer
xmlSerializer.text.overload('java.lang.String').implementation = function (text) {
    dmLogout("xtext: " + text);
    if ("GPRS" == text) {
        dmLogout("======>>> found GPRS");
        showStacks();
    }
    return this.text(text);
}

}

hook Android Log 输出

function hook_log() {

dmLogout(TAG, "do hook log");
var Log = Java.use('android.util.Log');
Log.v.overload('java.lang.String', 'java.lang.String').implementation = function (tag, content) {
    dmLogout(tag + " v", content);
};
Log.d.overload('java.lang.String', 'java.lang.String').implementation = function (tag, content) {
    dmLogout(tag + " d", content);
};
Log.w.overload('java.lang.String', 'java.lang.String').implementation = function (tag, content) {
    dmLogout(tag + " w", content);
};
Log.i.overload('java.lang.String', 'java.lang.String').implementation = function (tag, content) {
    dmLogout(tag + " i", content);
};
Log.e.overload('java.lang.String', 'java.lang.String').implementation = function (tag, content) {
    dmLogout(tag + " e", content);
};

}

native 主动调用

var friendlyFunctionName = new NativeFunction(friendlyFunctionPtr, ‘void’, [‘pointer’, ‘pointer’]);

var returnValue = Memory.alloc(sizeOfLargeObject);

friendlyFunctionName(returnValue, param1);

就先整理这么多,日后再追加。欢迎大佬们追加分享和指正错误。

本文作者:星均

阅读原文

本文为栖社区原创内容,未经允许不得转载。

原文 

https://segmentfault.com/a/1190000018153596

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » FRIDA 实用手册

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址