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__importprint_functionimportfridaimportsyssession = 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))defon_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__importprint_functionimportfridasystem_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
functionhook_sms(){varSmsManager = 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 间隔循环执行
varid_ = setInterval(funcB,15000);clearInterval(id_);// 终止
bin array 转字符串
functionbin2String(array){if(null== array) {return"null"; }varresult ="";try{varString_java = Java.use('java.lang.String'); result = String_java.$new(array); }catch(e) { dmLogout("== use bin2String_2 =="); result = bin2String_2(array); }returnresult;}functionbin2String_2(array){varresult ="";try{vartmp =0;for(vari =0; i < array.length; i++) { tmp =parseInt(array[i]);if( tmp ==0xc0|| (tmp <32&& tmp !=10) || tmp >126) {returnresult; }// 不是可见字符就返回了, 换行符除外result +=String.fromCharCode(parseInt(array[i].toString(2),2)); } }catch(e) {console.log(e); }returnresult;}
自己封装输出函数加入线程ID 和时间
functiongetFormatDate(){vardate =newDate();varmonth = date.getMonth() +1;varstrDate = date.getDate();if(month >=1&& month <=9) { month ="0"+ month; }if(strDate >=0&& strDate <=9) { strDate ="0"+ strDate; }varcurrentDate = date.getFullYear() +"-"+ month +"-"+ strDate +" "+ date.getHours() +":"+ date.getMinutes() +":"+ date.getSeconds();returncurrentDate;}functiondmLogout(str){varthreadid = Process.getCurrentThreadId();console.log("["+threadid+"]["+ getFormatDate() +"]"+ str);}
打印 Android Java 层堆栈
varshowStacks =function(){ Java.perform(function(){ dmLogout(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));// 打印堆栈});}
TracerPid fgets 反调试
varanti_fgets =function(){ dmLogout("anti_fgets");varfgetsPtr = Module.findExportByName("libc.so","fgets");varfgets =newNativeFunction(fgetsPtr,'pointer', ['pointer','int','pointer']); Interceptor.replace(fgetsPtr,newNativeCallback(function(buffer, size, fp){varretval = fgets(buffer, size, fp);varbufstr = Memory.readUtf8String(buffer);if(bufstr.indexOf("TracerPid:") >-1) { Memory.writeUtf8String(buffer,"TracerPid:\t0");// dmLogout("tracerpid replaced: " + Memory.readUtf8String(buffer));}returnretval; },'pointer', ['pointer','int','pointer']));};
反调试时读取 LR 寄存器溯源
varanti_antiDebug =function(){varfuncPtr =null; funcPtr = Module.findExportByName("xxxx.so","p57F7418DCD0C22CD8909F9B22F0991D3"); dmLogout("anti_antiDebug "+ funcPtr); Interceptor.replace(funcPtr,newNativeCallback(function(pathPtr, flags){ dmLogout("anti ddddddddddddddebug LR: "+this.context.lr);return0; },'int', ['int','int']));};
hook JNI API NewStringUTF
functionhook_native_newString(){varenv = Java.vm.getEnv();varhandlePointer = Memory.readPointer(env.handle); dmLogout("env handle: "+ handlePointer);varNewStringUTFPtr = Memory.readPointer(handlePointer.add(0x29C)); dmLogout("NewStringUTFPtr addr: "+ NewStringUTFPtr); Interceptor.attach(NewStringUTFPtr, { onEnter:function(args){ ... } });}
hook JNI API GetStringUTFChars
functionhook_native_GetStringUTFChars(){varenv = Java.vm.getEnv();varhandlePointer = Memory.readPointer(env.handle); dmLogout("env handle: "+ handlePointer);varGetStringUTFCharsPtr = Memory.readPointer(handlePointer.add(0x2A4)); dmLogout("GetStringUTFCharsPtr addr: "+ GetStringUTFCharsPtr); Interceptor.attach(GetStringUTFCharsPtr, { onEnter:function(args){varstr =""; 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(vari =0; i < args.length; i ++) { dmLogout("strcat args["+ i +"]("+ ptr(args[i]) +"): "+ Memory.readUtf8String(args[i])); } }});
hook Android URI 打印堆栈
varhook_uri =function(){// coord: (7520,0,19) | addr: Ljava/net/URI;->parseURI(Ljava/lang/String;Z)V | loc: ?varuri = Java.use('java.net.URI'); uri.parseURI.implementation =function(a1, a2){ a1 = a1.replace("xxxx.com","yyyy.com"); dmLogout("uri: "+ a1); showStacks();returnthis.parseURI(a1, a2); }}
hook KXmlSerializer 拼装内容
functionhook_xml(){varxmlSerializer = Java.use('org.kxml2.io.KXmlSerializer');// org.xmlpull.v1.XmlSerializerxmlSerializer.text.overload('java.lang.String').implementation =function(text){ dmLogout("xtext: "+ text);if("GPRS"== text) { dmLogout("======>>> found GPRS"); showStacks(); }returnthis.text(text); }}
hook Android Log 输出
functionhook_log(){ dmLogout(TAG,"do hook log");varLog = 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 主动调用
varfriendlyFunctionName =newNativeFunction(friendlyFunctionPtr,'void', ['pointer','pointer']);varreturnValue = Memory.alloc(sizeOfLargeObject);friendlyFunctionName(returnValue, param1);
就先整理这么多,日后再追加。欢迎大佬们追加分享和指正错误。
本文作者:星均
本文为云栖社区原创内容,未经允许不得转载。
网友评论