Frida 環境部署及使用
目錄
Frida 環境部署
Frida
是一款基於 Python + JavaScript
的 Hook
與除錯框架
Frida大致原理是手機端安裝一個server程式,然後把手機端的埠轉到PC端,PC端寫python指令碼進行通訊,而python指令碼中需要hook的程式碼採用javascript語言。
官方文件:https://frida.re/docs/javascript-api/#java-cast
安裝:
pip install frida
pip install frida-tools
服務端配置
在https://github.com/frida/frida/releases下載對應平臺的服務端
frida-server-12.11.12-android-arm64.xz
然後解壓,移動到Android裝置
adb
下載地址
https://developer.android.google.cn/studio/releases/platform-tools
然後配置環境變數
adb push frida-server-12.5.7-android-x86 /data/local/tmp/ adb shell cd /data/local/tmp/ chmod 777 frida-server-12.11.12-android-arm64
然後啟動執行,轉發埠
./frida-server-12.11.12-android-arm64
adb forward tcp:27042 tcp:27042
基本執行
檢視連線到的裝置
frida-ls-devices
Id Type Name
---------------- ------ ------------
local local Local System
ENU7N15A30003435 usb Nexus 6P
socket remote Local Socket
檢視裝置上的程序資訊
frida-ps -U
使用
import frida
import sys
def on_message(message , data):
if message["type"] == "send":
print("[*] {0}".format(message['payload']))
else:
print(message)
jscode_signature = """
Java.perform(function(){
var TestSig = Java.use('com.yaotong.crackme.MainActivity');
TestSig.securityCheck.implementation = function(str){
send('I am here');
return true;
};
});
"""
# 查詢USB裝置並附加到目標程序
process = frida.get_remote_device().attach('com.yaotong.crackme')
# 在目標程序裡建立指令碼
script = process.create_script(jscode_signature)
# 註冊訊息回撥
script.on("message", on_message)
print('[*] Runing CTF')
# 載入建立好的javascript指令碼
script.load()
# 讀取系統輸入
sys.stdin.read()
載入類
Java.use方法用於宣告一個Java類,在用一個Java類之前首先得宣告。比如宣告一個String類,要指定完整的類名:
var StringClass=Java.use("java.lang.String");
修改函式的實現
修改一個函式的實現是逆向除錯中相當有用的。修改一個函式的實現後,如果這個函式被呼叫,我們的Javascript程式碼裡的函式實現也會被呼叫
函式引數型別表示
不同的引數型別都有自己的表示方法
- 對於基本型別,直接用它在Java中的表示方法就可以了,不用改變,例如:
- int
- short
- char
- byte
- boolean
- float
- double
- long
- 基本型別陣列,用左中括號接上基本型別的縮寫
基本型別縮寫表示表:
基本型別 | 縮寫 |
---|---|
boolean | Z |
byte | B |
char | C |
double | D |
float | F |
int | I |
long | J |
short | S |
例如:int[]
型別,在過載時要寫成[I
- 任意類,直接寫完整類名即可
例如:java.lang.String
- 物件陣列,用左中括號接上完整類名再接上分號
例如:[java.lang.String;
帶引數的建構函式
修改引數為byte[]型別的建構函式的實現
ClassName.$init.overload('[B').implementation=function(param){
//do something
}
注:ClassName是使用Java.use定義的類;param是可以在函式體中訪問的引數
修改多引數的建構函式的實現
ClassName.$init.overload('[B','int','int').implementation=function(param1,param2,param3){
//do something
}
無引數建構函式
ClassName.$init.overload().implementation=function(){
//do something
}
呼叫原建構函式
ClassName.$init.overload().implementation=function(){
//do something
this.$init();
//do something
}
注意:當建構函式(函式)有多種過載形式,比如一個類中有兩個形式的func:
void func()
和void func(int)
,要加上overload來對函式進行過載,否則可以省略overload
一般函式
修改函式名為func,引數為byte[]型別的函式的實現
ClassName.func.overload('[B').implementation=function(param){
//do something
//return ...
}
無引數的函式
ClassName.func.overload().implementation=function(){
//do something
}
注: 在修改函式實現時,如果原函式有返回值,那麼我們在實現時也要返回合適的值
ClassName.func.overload().implementation=function(){
//do something
return this.func();
}
呼叫函式
和Java一樣,建立類例項就是呼叫建構函式,而在這裡用$new
表示一個建構函式。
var ClassName=Java.use("com.luoye.test.ClassName");
var instance = ClassName.$new();
例項化以後呼叫其他函式
var ClassName=Java.use("com.luoye.test.ClassName");
var instance = ClassName.$new();
instance.func();
型別轉換
用Java.cast
方法來對一個物件進行型別轉換,如將variable
轉換成java.lang.String
:
var StringClass=Java.use("java.lang.String");
var NewTypeClass=Java.cast(variable,StringClass);
Java.available欄位
這個欄位標記Java虛擬機器(例如: Dalvik 或者 ART)是否已載入, 操作Java任何東西的之前,要確認這個值是否為true
Java.perform方法
Java.perform(fn)在Javascript程式碼成功被附加到目標程序時呼叫,我們核心的程式碼要在裡面寫。格式:
Java.perform(function(){
//do something...
});
var classnames = java.enumerateLoadeClassesSync();
for (var i=0; i<classnames.length; i++){
send('class name:'+classnames[i]);
# jscode = """
# Java.perform(function (){
# var v = Java.androidVersion;
# send('version:'+v);
# //var classnames = Java.enumerateLoadedClassesSync();
# //for (var i=0; i<classnames.length; i++){
# // send('class name:'+classnames[i]);
# //}
# });
"""