前言
Frida是個(gè)輕量級(jí)別的hook框架,是Python API磕潮,但JavaScript調(diào)試邏輯,它既可以hook java層也可以hook native層
Frida的核心是用C編寫(xiě)的翠胰,并將Google的V8引擎注入到目標(biāo)進(jìn)程中,在這些進(jìn)程中自脯,JS可以完全訪問(wèn)內(nèi)存之景,掛鉤函數(shù)甚至調(diào)用進(jìn)程內(nèi)的本機(jī)函數(shù)來(lái)執(zhí)行。
使用Python和JS可以使用無(wú)風(fēng)險(xiǎn)的API進(jìn)行快速開(kāi)發(fā)膏潮。Frida可以幫助您輕松捕獲JS中的錯(cuò)誤并為您提供異常而不是崩潰锻狗。
環(huán)境
Android4.4.4
Nexus5手機(jī)(ARM)
frida12.11.18
python3.6
安裝
首先使用pip安裝frida和frida-tools模塊
pip install frida
pip install frida-tools
我這里使用PyCharm安裝
下載frida-server,官方下載地址https://github.com/frida/frida/releases焕参,這里注意下載的版本應(yīng)該和上面安裝的frida版本一致轻纪。
在adb shell中查看cpu的架構(gòu)
getprop ro.product.cpu.abi
所以我們下載這個(gè)版本
下載后解壓重命名為frida-server 并push到手機(jī)上。
進(jìn)入root權(quán)限叠纷,給其權(quán)限并運(yùn)行,手機(jī)會(huì)重啟
然后把端口轉(zhuǎn)發(fā)到PC端:
adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043
到這里我們就把通信的手機(jī)端工作做完了
java層Hook
我們要做事情
1.hook類的普通方法
2.hook類的構(gòu)造方法
3.構(gòu)造和修改自定義類型對(duì)象和屬性
先寫(xiě)一個(gè)目標(biāo)app
添加SharkUtils和Student兩個(gè)類
SharkUtils.java
package com.shark.fridatarget;
public class SharkUtils {
public static String getPwd(String info) {
return info + "shark";
}
public static String getPwd() {
return "shark";
}
public static Student getStu() {
return new Student("fujie", 100);
}
public static int getStuScore(Student student) {
return student.getScore();
}
}
Student.java
package com.shark.fridatarget;
public class Student {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public String name;
public int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
}
MainActivity.java
package com.shark.fridatarget;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
TextView textView;
TextView textView2;
TextView textView3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.test);
Student student = SharkUtils.getStu();
textView.setText("姓名:" + student.getName() + "------分?jǐn)?shù):" + student.getScore());
textView2 = findViewById(R.id.test2);
textView2.setText("password:"+SharkUtils.getPwd("123456"));
textView3 = findViewById(R.id.test3);
textView3.setText("getStuScore:"+SharkUtils.getStuScore(student));
}
}
app就是調(diào)用SharkUtils的方法刻帚,然后將返回的信息輸出到控件上
運(yùn)行如下
現(xiàn)在就來(lái)編寫(xiě)Hook代碼
import frida # 導(dǎo)入frida模塊
import sys # 導(dǎo)入sys模塊
jscode = """ //從此處開(kāi)始定義用來(lái)Hook的javascript代碼
Java.perform(function(){
var student = Java.use('com.shark.fridatarget.Student'); //獲得Student類
var sharkUtils = Java.use('com.shark.fridatarget.SharkUtils'); //獲得SharkUtils類
var clazz = Java.use('java.lang.Class'); //獲得Class類
//Hook普通方法
sharkUtils.getPwd.overload("java.lang.String").implementation = function(info){
//方式一獲取參數(shù)
send("getPwd1:"+info);
//方式二獲取參數(shù)
send("getPwd2:"+arguments[0]);
return this.getPwd("shark"); //劫持返回值,修改為我們想要返回的字符串
}
//Hook Student的構(gòu)造函數(shù)$init涩嚣,用js自己實(shí)現(xiàn)
student.$init.overload("java.lang.String","int").implementation = function(name,score){
send('Statr! Hook!'); //發(fā)送信息崇众,用于回調(diào)python中的函數(shù)
return this.$init("shark",99); //調(diào)用原來(lái)的初始化方法
}
//構(gòu)造和修改自定義類型對(duì)象和屬性
sharkUtils.getStuScore.overload("com.shark.fridatarget.Student").implementation = function(student){
send('student:'+student);
//使用方法得到屬性
var score = student.getScore();
send('student score:'+score);
//直接得到屬性
var score2 = student.score;
send('student score2:'+score);
//構(gòu)造一個(gè)新的student對(duì)象
var new_stu = student.$new("shark chilli",55);
//將com.shark.fridatarget.Student轉(zhuǎn)化java.lang.Class
var scorc_field = Java.cast(student.getClass(),clazz).getDeclaredField("score");
//這里就是普通的反射了
scorc_field.setAccessible(true);
send('reflect scorc_field:'+scorc_field.get(student));
scorc_field.setInt(student,999);
return student.getScore();
}
});
"""
def on_message(message, data): # js中執(zhí)行send函數(shù)后要回調(diào)的函數(shù)
print(message)
# 得到設(shè)備并劫持進(jìn)程com.shark.fridatarget(
# 該開(kāi)始用get_usb_device函數(shù)用來(lái)獲取設(shè)備,但是一直報(bào)錯(cuò)找不到設(shè)備缓艳,改用get_remote_device函數(shù)即可解決這個(gè)問(wèn)題)
process = frida.get_remote_device().attach('com.shark.fridatarget')
script = process.create_script(jscode) # 創(chuàng)建js腳本
script.on('message', on_message) # 加載回調(diào)函數(shù),也就是js中執(zhí)行send函數(shù)規(guī)定要執(zhí)行的python函數(shù)
script.load() # 加載腳本
sys.stdin.read()
這段代碼就是hook的整體邏輯使用get_remote_device來(lái)獲取到設(shè)備看峻,然后調(diào)用attach附加到app上阶淘,所以這里必須要在手機(jī)上打開(kāi)這個(gè)應(yīng)用。否則會(huì)找不到互妓。然后創(chuàng)建js腳本溪窒,加載回調(diào)函數(shù)就是我們自己定義的on_message函數(shù),這樣js中調(diào)用send就調(diào)用了我們的on_message函數(shù)了冯勉。下面就是加載腳本了澈蚌。
Java.perform(function(){
...
});
我們的hook邏輯都寫(xiě)在上面的js代碼中
使用Java.use獲得類的類型
Hook普通方法,直接使用要hook的方法名灼狰,overload是確認(rèn)方法重載的宛瞄。
上面看到想要獲得參數(shù)有兩種方式,一是在方法上定義參數(shù)名即可交胚。二是通過(guò)隱含的arguments變量獲取份汗。
this指針就是被hook的對(duì)象盈电,想要修改返回值可以直接使用return
Hook構(gòu)造方法東西其實(shí)都一樣,就是調(diào)用構(gòu)造方法的時(shí)候使用$init
構(gòu)造和修改自定義類型對(duì)象和屬性杯活,想new一個(gè)類的實(shí)例使用的是$new匆帚。其他的代碼和java中的反射大同小異。注意一下的是要使用反射操作這個(gè)student實(shí)例前需要使用cast轉(zhuǎn)化成java.lang.Class
運(yùn)行
引用
Frida hook入門
Android逆向之旅—Hook神器家族的Frida工具使用詳解
frida入門總結(jié)