文章目錄
- 1 概述
- 2 啟動方式
- 3 Android 常用Hook方法匯總
-
- 3.1 Hook 一般函數---使用implementation
- 3.2 Hook 重載函數---使用overload
- 3.3 Hook 構造函數---使用$init
- 3.4 Hook 生成對象---使用$new
- 3.5 Hook 內部類---使用$
- 3.6 Hook native 函數
- 3.7 Hook 靜態變量(屬性)/參考文章中有反射的方法
- 3.8 打印堆棧
- 3.9 byte轉String
- 3.10 字符串轉Uint8Array
- 3.11 int轉bytes
- 3.12 string轉ArrayBuffer
- 3.13 ArrayBuffer轉String
- 3.14 添加時間戳
- 3.15 byte轉Hex
- 3.16 Hex轉byte
1 概述
在逆向過程中,Frida是非常常用的Hook工具,這個工具在日常使用的過程中,有很多通用方法,這里記錄一下,方便查閱,部分函數使用的時候,可能需要稍微修改一下,本文記錄是Android的方法,不涉及其他的
主要是搬遷的一下參考文章的片段
Android逆向之旅—Hook神器家族的Frida工具使用詳解
Frida官方文檔
看雪 Frida官方手冊 - JavaScript API(篇一)
看雪 Frida官方手冊 - JavaScript API(篇二)
Js中幾種String Byte轉換方法
Frida learn by example
補充一個參考文章–Hook 屬性
2 啟動方式
2.1 使用js腳本啟動
frida -U -l exploit.js -f com.package.name
- 1
其中js腳本的寫作方式如下
setImmediate(function() { //prevent timeout
console.log("[*] Starting script");
Java.perform(function() {
myClass = Java.use("com.package.name.xxActivity");
myClass.implementation = function(v) {
// do sth.
}
})
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
2.2 使用python腳本啟動
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
jscode = """ Java.perform(function () { // Function to hook is defined here var MainActivity = Java.use('com.example.hook.MainActivity'); // hook method is setString MainActivity.setString.implementation = function (str) { // Show a message to know that the function got called send('hook success'); console.log('string is: ' + str)); }; }); """
process = frida.get_usb_device().attach('com.example.hook')
#pid = device.spawn(["com.android.chrome"])
#session = device.attach(pid)
#device.resume(pid)
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Hook Start Running')
script.load()
sys.stdin.read()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
3 Android 常用Hook方法匯總
3.1 Hook 一般函數—使用implementation
var MainActivity = Java.use('ese.xposedtest.MainActivity');
//外部類 修改返回值
MainActivity.OutClass.implementation = function (arg) {
var ret = this.OutClass(arg);
console.log('Done:' + arg);
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
3.2 Hook 重載函數—使用overload
// If two methods of a class have the same name
// you need to use 'overload'
// hook method 1
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 method 2
//待補充
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
3.3 Hook 構造函數—使用$init
// Intercept the initialization of java.lang.Stringbuilder's overloaded constructor.
// Write the partial argument to the console.
const StringBuilder = Java.use('java.lang.StringBuilder');
//We need to overwrite .$init() instead of .$new(), since .$new() = .alloc() + .init()
StringBuilder.$init.overload('java.lang.String').implementation = function (arg) {
var partial = "";
var result = this.$init(arg);
if (arg !== null) {
partial = arg.toString().replace('\n', '').slice(0,10);
}
// console.log('new StringBuilder(java.lang.String); => ' + result)
console.log('new StringBuilder("' + partial + '");')
return result;
}
console.log('[+] new StringBuilder(java.lang.String) hooked');
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
3.4 Hook 生成對象—使用$new
const JavaString = Java.use('java.lang.String');
var exampleString1 = JavaString.$new('Hello World, this is an example string in Java.');
console.log('[+] exampleString1: ' + exampleString1);
- 1
- 2
- 3
3.5 Hook 內部類—使用$
var inInnerClass = Java.use('ese.xposedtest.MainActivity$inInnerClass');
inInnerClass.methodInclass.implementation = function()
{
var arg0 = arguments[0];
var arg1 = arguments[1];
send("params1: "+ arg0 +" params2: " + arg1);
return this.formInclass(1,"Frida");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
3.6 Hook native 函數
Interceptor.attach(Module.findExportByName("xxx.so" , "xxxx"), {
onEnter: function(args) {
send("open(" + Memory.readCString(args[0])+","+args[1]+")");
},
onLeave:function(retval){
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.7 Hook 靜態變量(屬性)/參考文章中有反射的方法
var ah = Java.use("com.ah");
console.log("To Log: " + ah.a.value);
ah.a.value = true;
- 1
- 2
- 3
3.8 打印堆棧
AndroidLog = Java.use("android.util.Log")
AndroidException = Java.use("java.lang.Exception")
function printStackTrace(){
console.log(AndroidLog .getStackTraceString(AndroidException .$new()));
}
- 1
- 2
- 3
- 4
- 5
3.9 byte轉String
function byte2string(array){
var result = "";
for(var i = 0; i < array.length; ++i){
result+= (String.fromCharCode(array[i]));
}
return result;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
3.10 字符串轉Uint8Array
function string2byte(str){
for (var i = 0,arr=[]; i < str.length;i++){
arr.push(str.charCodeAt(i));
}
return new Uint8Array(arr);
}
- 1
- 2
- 3
- 4
- 5
- 6
3.11 int轉bytes
function intTobytes(n) {
var bytes = [];
for (var i = 0; i < 2; i++) {
bytes[i] = n >> (8 - i * 8);
}
return bytes;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.12 string轉ArrayBuffer
function str2arraybuffer(str) {
var buf = new ArrayBuffer(str.length * 2); // 每個字符占用2個字節
var bufView = new Uint16Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.13 ArrayBuffer轉String
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
- 1
- 2
- 3
3.14 添加時間戳
console.log(new Date(new Date().getTime())
- 1
3.15 byte轉Hex
這個非常常用,因為有些byte是沒有辦法轉成string的,只能轉成hex,用來查看
參考文章
function byteToHexString(uint8arr) {
if (!uint8arr) {
return '';
}
var hexStr = '';
for (var i = 0; i < uint8arr.length; i++) {
var hex = (uint8arr[i] & 0xff).toString(16);
hex = (hex.length === 1) ? '0' + hex : hex;
hexStr += hex;
}
return hexStr.toUpperCase();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
3.16 Hex轉byte
function hexStringToByte(str) {
if (!str) {
return new Uint8Array();
}
var a = [];
for (var i = 0, len = str.length; i < len; i+=2) {
a.push(parseInt(str.substr(i,2),16));
}
return new Uint8Array(a);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12