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
關閉防火牆
adb shell
su
setenforce 0
使用
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...
});