内容简介:FRIDA 实用手册本文目的是作为工具类文章,收集整理了一些 FRIDA 的使用技巧和用例,方便同学们在开发使用过程中开袋即食。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);
就先整理这么多,日后再追加。欢迎大佬们追加分享和指正错误。
本文作者:星均
本文为云栖社区原创内容,未经允许不得转载。
以上所述就是小编给大家介绍的《FRIDA 实用手册》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- MySQL™ 参考手册(关于本手册)
- LLVM 程序员手册 —— LLVM 4.0 文档(非常非常完整的手册)
- [译]Python手册——模块
- Axure函数使用手册
- 线上故障处理手册
- OpenSSH 实践手册
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。