frida是有效的插桩工具。
插桩技术
插桩技术是指将额外的代码注入程序中以收集运行时的信息,可分为两种:
(1)源代码插桩[Source Code Instrumentation(SCI)]:额外代码注入到程序源代码中。
(2)二进制插桩(Binary Instrumentation):额外代码注入到二进制可执行文件中。
●静态二进制插桩[Static Binary Instrumentation(SBI)]:在程序执行前插入额外的代码和数据,生成一个永久改变的可执行文件。
●动态二进制插桩[Dynamic Binary Instrumentation(DBI)]:在程序运行时实时地插入额外代码和数据,对可执行文件没有任何永久改变
frida自带的Messages机制与进程交互,模板
import frida, sys
//hook代码,采用javascript编写
jscode = """
//javascript代码,重点
"""
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
process = frida.get_usb_device().attach('应用完整包名')
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()
Android例子
例子APK 提取码: uba5。
Java层hook
Frida的Java层重要函数
1)使用java平台--->Java.perform(function () {}
2)获取Java类:动态获取JavaScript包装器 --->Java.use(className)
3)当我们获取到Java类之后,我们直通过接 <wrapper>.<method>.implementations = function() {}的方式来hook wrapper类的method方法,不管是实例方法还是静态方法都可以。
因为Frida的hook主要是python框架,但运行的却是js脚本,这里我将其些分开,方便调用。
创建exp.js
console.log("[*] Java Starting script");
Java.perform(function() {
var dexclassLoader= Java.use('ese.xposedtest.MainActivity');
//外部类 的OutClass方法 修改返回值
dexclassLoader.OutClass.implementation = function () {
var ret = this.OutClass();
console.log('Done:' + JSON.stringify(ret));
return "Frida "+ret;
}
//内部类
var dexclassLoader1= Java.use('ese.xposedtest.MainActivity$inClasse');
//打印参数 的formInclass方法 参数随意修改了
dexclassLoader1.formInclass.implementation = function()
{
var arg0 = arguments[0];
var arg1 = arguments[1];
send("params1: "+arg0+" params2: "+arg1);
return this.formInclass(1,"Frida");
}
});
使用模板调用js代码demo.py
import frida, sys
import io
#python2.7
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
def run(pkg):
jscode = io.open('hooks.js','r',encoding= 'utf8').read()
device = frida.get_usb_device(timeout=5)
pid = device.spawn(pkg)
session = device.attach(pid)
script = session.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()
def main(argv):
if len(argv) != 2:
print("must input two arg")
print("For exanple: python demo.py packName")
else:
run(argv[1])
if __name__ == "__main__":
main(sys.argv)
简单编写一个自动启动Frida_Service的脚本startFridaService.py
# -*- coding: utf-8 -*-
# python2.7
import sys
import subprocess
forward1 = "adb forward tcp:27042 tcp:27042"
forward2 = "adb forward tcp:27043 tcp:27043"
cmd = ["adb shell","su","cd /data/local/tmp","./frida-server64"]
def Forward1():
s = subprocess.Popen(str(forward1+"\r\n"), stderr=subprocess.PIPE, stdin=subprocess.PIPE,stdout=subprocess.PIPE, shell=True)
stderrinfo, stdoutinfo = s.communicate()
return s.returncode
def Forward2():
s = subprocess.Popen(str(forward2+"\r\n"), stderr=subprocess.PIPE, stdin=subprocess.PIPE,stdout=subprocess.PIPE, shell=True)
stderrinfo, stdoutinfo = s.communicate()
return s.returncode
def Run():
s = subprocess.Popen(str(cmd[0]+"\r\n"), stderr=subprocess.PIPE, stdin=subprocess.PIPE,stdout=subprocess.PIPE, shell=True)
for i in range(1,len(cmd)):
s.stdin.write(str(cmd[i]+"\r\n"))
s.stdin.flush()
stderrinfo, stdoutinfo = s.communicate()
return s.returncode
if __name__ == "__main__":
Forward1()
print("adb forward tcp:27042 tcp:27042")
Forward2()
print("adb forward tcp:27043 tcp:27043")
print("Android server--->./frida-server64")
print("success-->frida-ps -R")
Run()
python2.7下运行
1、一个cmd运行
python startFridaService.py
2、一个cmd查看frida服务器是否允许成功
frida-ps -U
3、运行需要hook的app,然后运行frida hook脚本
python demo.py packName
注意:
如果需要hook有3个名为myMethod的方法怎么办?
1 )不需要参数
2 )需要两个字节数组
3 )需要应用程序的上下文和布尔值
我们需要用到 overload
// If two methods of a class have the same name
// you need to use 'overload'
myClass.myMethod.overload().implementation = function(){
// do sth
}
myClass.myMethod.overload("[B", "[B").implementation = function(param1, param2) {
// do sth
}
myClass.myMethod.overload("android.context.Context", "boolean").implementation = function(param1, param2){
// do sth
}
这样我们就可以hook到需要的方法。例如:
hook导出函数exp.js
console.log("[*] Java Starting script");
Java.perform(function() {
//hook 类
var dexclassLoader = Java.use('com.sitech.appdev.threedes.ThreeDesSecretLib');
console.log('Done:' + JSON.stringify("dexclassLoader -----> ok"));
//hook encrypt 方法 这里多个encrypt方法,选择用overload重载
dexclassLoader.encrypt.overload('java.lang.String').implementation = function (param1) {
//进入 encrypt方法 输出传入 参数
console.log('Done:' + JSON.stringify("encrypt before------> "+param1));
//保存第一次传如的参数
var barparam1 = param1;
//运行 encrypt方法 得到运行结果 输出结果
var ret = this.encrypt(param1);
console.log('Done:' + JSON.stringify("encrypt after-------> "+ret));
//最后 继续运行encrypt 方法
return this.encrypt(barparam1);
}
});
结果:
so层hook
hook导出函数exp2.js
setImmediate(function() {
console.log("[*] Native Starting script");
var nativePointer = Module.findExportByName("libnative-lib.so","Java_ese_xposedtest_MainActivity_stringFromJNI");
send("nativePointer--->"+nativePointer);
Interceptor.attach(nativePointer,{
onEnter:function(args){
console.log("ok");
send("Sart arg-->"+args[0]+" "+args[1]);
},
onLeave:function(retval){
send("return value:"+retval);
}
});
})
技巧
bytes ---> string
function bin2string(array){
var result = "";
for(var i = 0; i < array.length; ++i){
result+= (String.fromCharCode(array[i]));
}
return result;
}
objection
参考: https://bbs.pediy.com/thread-229657.htm
参考: https://blog.csdn.net/jiangwei0910410003/article/details/80372118