Frida腳本使用
準備工作
Frida
在這里對Frida進行了簡單的介紹。
設備
設備: Android 10 ROOT
PC: Ubuntu18.04
Python切換
有些時候,需要使用Python的2.x版本,而有些時候又需要使用python的3.x版本,這個時候就需要能夠靈活設置python版本 使用下面的命令設置Python2是默認:
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 100
使用下面的命令設置Python3是默認
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 150
使用 sudo update-alternatives--config python
命令切換到制定的版本

由于Frida建議使用Python3.x,因此這里切換到3的版本。在二進制漏洞中,exploit使用的基本都是Python2.7。
Frida腳本
FRIDA腳本就是利用FRIDA動態(tài)插樁框架,使用FRIDA導出的API和方法,對內存空間里的對象方法進行監(jiān)視、修改或者替換的一段代碼。FRIDA的API是使用JavaScript實現(xiàn)的,所以我們可以充分利用JS的匿名函數(shù)的優(yōu)勢、以及大量的hook和回調函數(shù)的API。
Hello world
Hello world經(jīng)典的入門程序,frida版本的來一個。
setTimeout(function (){
Java.perform(function (){
? ?console.log("Hello world");
});
});
使用的API
setTimeout(func, delay[, ...parameters]): call func after delay milliseconds, optionally passing it one or more parameters. Returns an id that can be passed to clearTimeout to cancel it.
clearTimeout(id): cancel id returned by call to setTimeout.
Java.perform(fn): ensure that the current thread is attached to the VM and call fn. (This isn’t necessary in callbacks from Java.) Will defer calling fn if the app’s class loader is not available yet. Use Java.performNow() if access to the app’s classes is not needed.
console.log(line), console.warn(line), console.error(line): write line to the console of your Frida-based application.
JavaScript匿名函數(shù)
匿名函數(shù):就是沒有函數(shù)名的函數(shù)。這怎么可能,一個函數(shù)居然沒有函數(shù)名,但JavaScript就是支持這種語法的,這和Java等編譯型語言又很大的區(qū)別。匿名函數(shù)最大的用途是創(chuàng)建閉包。閉包是JavaScript的精髓,后續(xù)會專門講解。
<script>
? var fun = ?function (){
? ? ? ?alert("歡迎關注我的微信公眾號:無情劍客")
}
? ?fun();
</script>

運行程序
通過前面的分析,可知這個程序最終調用 console.log("Hello world");
在手機端開啟frida-server.

然后在PC端運行下面的命令:
frida -U -l hello.js android.process.media
運行后的結果如下

枚舉所有的類
setTimeout(function (){
Java.perform(function (){
? ? ?console.log("n[*] enumerating classes...");
Java.enumerateLoadedClasses({
? ? ? ?onMatch: function(_className){
? ? ? ? ?console.log("[*] found instance of '"+_className+"'");
},
? ? ? ?onComplete: function(){
? ? ? ? ?console.log("[*] class enuemration complete");
}
});
});
});
其中: Java.enumerateLoadedClasses(callbacks): enumerate classes loaded right now, where callbacks is an object specifying:
-
onMatch: function (name, handle): called for each loaded class with name that may be passed to use() to get a JavaScript wrapper. You may also Java.cast() the handle to java.lang.Class.
-
onComplete: function (): called when all classes have been enumerated.
運行js代碼,同上,結果如下

枚舉藍牙類和實例
setTimeout(function (){
Java.perform(function (){
? ? ?console.log("n[*] enumerating classes...");
Java.enumerateLoadedClasses({
? ? ? ?onMatch: function(_className){
if(_className.split(".")[1] == bluetooth){
? ? ? ? ? ? ?console.log("[*] found instance of '"+_className+"'");
}
},
? ? ? ?onComplete: function(){
? ? ? ? ?console.log("[*] class enuemration complete");
}
});
});
});
運行后,可以看出有關bluetooth相關的類和實例都被枚舉出來了。

選定"android.bluetooth.BluetoothDevice",獲取peer device的實例信息。
Java.choose("android.bluetooth.BluetoothDevice",{
? ? ? ?onMatch: function (instance){
? ? ? ? ?console.log("[*] "+" android.bluetooth.BluetoothDevice instance found"+" :=> '"+instance+"'");
//這里是類型轉化的用法
//console.log(Java.cast(instance,Java.use("android.bluetooth.BluetoothDevice") ).getName());
? ? ? ? ?console.log(instance.getName());
// ?bluetoothDeviceInfo(instance);
},
? ? ? ?onComplete: function() { console.log("[*] -----");}
});
其中: Java.choose(className, callbacks): enumerate live instances of the className class by scanning the Java heap, where callbacks is an object specifying:
onMatch: function (instance): called with each live instance found with a ready-to-use instance just as if you would have called Java.cast() with a raw handle to this particular instance. This function may return the string stop to cancel the enumeration early.
onComplete: function (): called when all instances have been enumerated
運行腳本,打印出peer device的名字和地址。
frida -U -l hello.js com.android.bluetooth

枚舉所有方法
? ? ?function enumMethods(targetClass)
{
? ? ? ? ? ?var hook = Java.use(targetClass);
? ? ? ? ? ?var ownMethods = hook.class.getDeclaredMethods();
? ? ? ? ? ?hook.$dispose;
return ownMethods;
}
? ? ? ?var a = enumMethods("android.bluetooth.BluetoothDevice")
? ? ? ?a.forEach(function(s) {
? ? ? ? ? ?console.log(s);
});
其中: Java.use(className): dynamically get a JavaScript wrapper for className that you can instantiate objects from by calling $new() on it to invoke a constructor. Call $dispose() on an instance to clean it up explicitly (or wait for the JavaScript object to get garbage-collected, or script to get unloaded). Static and non-static methods are available, and you can even replace a method implementation and throw an exception from it:
Java.perform(function () {
?var Activity = Java.use('android.app.Activity');
?var Exception = Java.use('java.lang.Exception');
Activity.onResume.implementation = function () {
throw Exception.$new('Oh noes!');
};
});
使用下面的命令運行腳本,枚舉android.bluetooth.BluetoothDevice聲明的所有方法。
frida -U -l hello.js com.android.bluetooth

通過frida hook就能夠對想要hook的方法進行控制了。這里舉一個簡單的例子,我想讓所有的getName()都返回"Redmi"。
setTimeout(function (){
Java.perform(function (){
? ? ?console.log("n[*] enumerating classes...");
? ? ? ?var targetClass = Java.use("android.bluetooth.BluetoothDevice");
? ? ? ?targetClass.getName.implementation=function(){
? ? ? ? ? ? ?var x = this.getName();
return 'Redmi';
}
Java.choose("android.bluetooth.BluetoothDevice",{
? ? ? ?onMatch: function (instance){
? ? ? ? ?console.log("[*] "+" android.bluetooth.BluetoothDevice instance found"+" :=> '"+instance+"'");
// ? console.log(Java.cast(instance,Java.use("android.bluetooth.BluetoothDevice") ).getName());
? ? ? ? ?console.log(instance.getName());
// ?bluetoothDeviceInfo(instance);
},
? ? ? ?onComplete: function() { console.log("[*] -----");}
});
});
});
或者
import frida,sys
def on_message(message, data):
if message['type'] == 'send':
? ? ? ?print(" {0}".format(message['payload']))
else:
? ? ? ?print(message)
pass
session = frida.get_usb_device().attach("com.android.bluetooth")
jscode = """
if(Java.available){
Java.perform(function(){
? ? ? ?var targetClass = Java.use("android.bluetooth.BluetoothDevice");
? ? ? ?targetClass.getName.implementation=function(){
? ? ? ? ? ? ?x = this.getName();
? ? ? ? ? ? ?sned(x);
return 'Redmi';
}
});
}
"""
script = session.create_script(jscode)
script.on("message", on_message)
print(' Start attach')
script.load()
sys.stdin.read()
前者的運行結果:

微信運動的步數(shù),支付寶的總金額等都可以用類似的方式進行修改。
完整的代碼
setTimeout(function (){
Java.perform(function (){
? ? ?console.log("n[*] enumerating classes...");
Java.enumerateLoadedClasses({
? ? ? ?onMatch: function(_className){
if(_className.split(".")[1] == "bluetooth"){
? ? ? ? ? ? ?console.log("[*] found instance of '"+_className+"'");
}
},
? ? ? ?onComplete: function(){
? ? ? ? ?console.log("[*] class enuemration complete");
}
});
Java.choose("android.bluetooth.BluetoothDevice",{
? ? ? ?onMatch: function (instance){
? ? ? ? ?console.log("[*] "+" android.bluetooth.BluetoothDevice instance found"+" :=> '"+instance+"'");
// ? console.log(Java.cast(instance,Java.use("android.bluetooth.BluetoothDevice") ).getName());
? ? ? ? ?console.log(instance.getName());
// ?bluetoothDeviceInfo(instance);
},
? ? ? ?onComplete: function() { console.log("[*] -----");}
});
? ? ?function enumMethods(targetClass)
{
? ? ? ? ? ?var hook = Java.use(targetClass);
? ? ? ? ? ?var ownMethods = hook.class.getDeclaredMethods();
? ? ? ? ? ?hook.$dispose;
return ownMethods;
}
? ? ? ?var a = enumMethods("android.bluetooth.BluetoothDevice")
? ? ? ?a.forEach(function(s) {
? ? ? ? ? ?console.log(s);
});
});
});
參考
https://frida.re/docs/javascript-api/
公眾號
更多Frida相關的文章,歡迎關注我的公眾號:無情劍客。
?