frida主動調用函數
除了使用frida進行hook, 很多場景我們需要用frida主動調用app的java方法和so方法。
因為hook大多數時候只能被動的等待觸發,如果函數一直不觸發咋辦,你就干等着嗎。所以主動調用要靈活的多。
大家好,我是王鐵頭 一個乙方安全公司搬磚的菜雞
持續更新移動安全,iot安全,編譯原理相關原創視頻文章
更多frida調用app方法 frida rpc視頻演示:[https://space.bilibili.com/430241559]
frida主動調用方法分類
frida主動調用分為下面幾種情況
- frida 主動調用java類方法 (靜態java方法)
- frida 主動調用native類方法 (靜態native方法)
- frida 主動調用對象的java方法
- frida 主動調用對象的native方法
- frida 主動調用so方法
這里把類方法和對象方法區分開是因為。
類方法可以直接調用 對象方法必須要有對象
區別在於有沒有static這個關鍵字
有static關鍵字就是靜態方法 沒有static就是對象方法
這里獲取對象的方法有兩個
- 直接獲取內存中已經有的對象
- 自己 創建(new)一個
好 下面演示一下5種方式的具體調用代碼
1. frida主動調用類方法(java靜態方法)代碼
要調用的函數聲明如下
public static String enc(String str_data, int n_conunt)
可以看到這個函數是有static關鍵字的 所以是個類方法(靜態方法)
調用格式:
類名引用.方法名(參數,...)
主動調用代碼
function call_enc(str_data, n_cnt)
{
//這里寫函數對應的類名
var str_cls_name = "com.wangtietou.test_rpc_all.Test_Enc_Dec";
//返回值
var str_ret = null;
Java.perform(function ()
{
//打log方便調試
console.log("===========>on enc");
// 獲取類
var obj = Java.use(str_cls_name);
//調用類方法 因為這里是靜態方法 所以可以直接調用
str_ret = obj.enc(str_data, n_cnt);
//打印結果 方便調試
console.log("enc result: " + str_ret);
});
return str_ret;
}
2. frida 主動調用native類方法 (靜態native方法)代碼
要調用的函數聲明如下
public static native String c_enc(String str_data)
可以看到這個函數是有static關鍵字的 所以是個類方法(靜態方法)這里有native 關鍵字 所以是個靜態的c方法
調用格式:
類名引用.方法名(參數,...)
主動調用代碼
function call_c_enc(str_data)
{
//這里寫函數對應的類名
var str_cls_name = "com.wangtietou.test_rpc_all.Test_Enc_Dec";
//返回值
var str_ret = null;
Java.perform(function ()
{
//打log方便調試
console.log("===========>on enc");
// 獲取類
var obj = Java.use(str_cls_name);
//調用類方法 因為這里是靜態方法 所以可以直接調用
str_ret = obj.c_enc(str_data);
//打印結果 方便調試
console.log("enc result: " + str_ret);
});
return str_ret;
}
3.frida 主動調用對象的java方法
要調用的函數聲明如下
public String enc(String str_data)
可以看到這個函數是沒有有static關鍵字的 所以是個對象方法(實例方法)
主動調用有2種方式
- 直接獲取內存中已存在的對象(建議使用)
- 自己創建一個新對象
因為運行過程中對象的成員的值可能已經發生了變化,所以如果重新創建一個對象,新對象的值還是初始值,在調用算法或者函數的時候,可能會產生影響。
所以這里建議直接獲取內存中已經有的對象
舉個例子 A對象有個成員 m_a 初始值是3
在app運行過程中,被設置成了666
在調用 A對象算法的時候 m_a參與了運算
666這個值可能才是算法需要的合法的值。
如果創建一個新對象A1,那么m_a的值是3
這時候調用算法 那么因為m_a的改變 很可能返回一個錯誤的值
調用格式
1.instance.方法名(參數,...) //直接獲取已有對象
2.類名引用.方法名(參數,...) //新創建的對象
1) 直接獲取內存中對象主動調用
這里介紹一個frida的api
//從內存中(堆)直接搜索已存在的對象
Java.choose('xxx.xxx.xxx ', //這里寫類名
{
//onMatch 匹配到對象執行的回調函數
onMatch: function (instance)
{
},
//堆中搜索完成后執行的回調函數
onComplete: function ()
{
}
});
主動調用代碼
function call_enc(str_data)
{
//這里寫函數對應的類名
var str_cls_name = "com.wangtietou.test_rpc_all.Test_Enc_Dec";
//返回值
var str_ret = null;
Java.perform(function ()
{
Java.choose(str_cls_name,
{
onMatch: function (instance)
{
//調試用
console.log("onMatch ");
//直接調用對象的函數 instance是找到的對象
str_ret = instance.enc(str_data);
},
onComplete: function ()
{
}
});
});
console.log("enc result: " + str_ret);
return str_ret;
}
2) 創建一個新對象 主動調用代碼
這里要用frida創建對象的語法 $new()
//獲取類的引用
var cls = Java.use('這里寫類名');
//調用構造函數 創建新對象 這里注意參數
var obj = cls.$new();
這里$new()是調用類的構造函數 新建一個對象
這里注意兩點
- 如果沒有構造函數 或者 構造函數沒有參數 這里直接寫$new()
- 如果構造函數有參數,那么一定要填參數 $new(參數,...)
創建一個對象 主動調用代碼
function call_enc(str_data)
{
//這里寫函數對應的類名
var str_cls_name = "com.wangtietou.test_rpc_all.Test_Enc_Dec";
//返回值
var str_ret = null;
Java.perform(function ()
{
//獲取類的引用
var cls = Java.use(str_cls_name);
//調用構造函數 創建新對象 這里注意參數
var obj = cls.$new();
//調用新對象的對象方法 enc
str_ret = obj.enc(str_data);
});
console.log("enc result: " + str_ret);
return str_ret;
}
4.frida 主動調用對象的native方法
要調用的函數聲明如下
public native String enc(String str_data, int n_num)
可以看到這個函數是沒有有static關鍵字的 所以是個對象方法(實例方法)
主動調用有2種方式
- 直接獲取內存中已存在的對象(建議使用)
- 自己創建一個新對象
建議直接獲取內存中已經有的對象
調用格式
1.instance.方法名(參數,...) //直接獲取已有對象
2.類名引用.方法名(參數,...) //新創建的對象
1) 直接獲取內存中對象主動調用
主動調用代碼
function call_enc(str_data, n_num)
{
//這里寫函數對應的類名
var str_cls_name = "com.wangtietou.test_rpc_all.Test_Enc_Dec";
//返回值
var str_ret = null;
Java.perform(function ()
{
Java.choose(str_cls_name,
{
onMatch: function (instance)
{
//調試用
console.log("onMatch ");
//直接調用對象的函數 instance是找到的對象
str_ret = instance.enc(str_data, n_num);
},
onComplete: function ()
{
}
});
});
console.log("enc result: " + str_ret);
return str_ret;
}
2) 創建一個新對象 主動調用代碼
function call_enc(str_data, n_num)
{
//這里寫函數對應的類名
var str_cls_name = "com.wangtietou.test_rpc_all.Test_Enc_Dec";
//返回值
var str_ret = null;
Java.perform(function ()
{
//獲取類的引用
var cls = Java.use(str_cls_name);
//調用構造函數 創建新對象 這里注意參數
var obj = cls.$new();
//調用新對象的對象方法 enc
str_ret = obj.enc(str_data, n_num);
});
console.log("enc result: " + str_ret);
return str_ret;
}
5 frida 主動調用so方法
so層函數聲明
char* c_enc_2(char* p_str_data, int n_num)
這里介紹一個frida用於調用c層函數的API
NativeFunction(address, returnType, argTypes[, abi])
1)address:要hook的函數地址
2)returnType:返回值類型
3)argTypes[, abi]: 參數類型 這里參數可以是多個
frida NativeFunction支持的類型
這里參數有兩個 一個是 char* 一個是int
大家可以看上面的圖 NativeFunction是支持int這個類型的
但是沒有char* 對於指針一系列的參數 我們可以用 pointer表示 所以這里的返回值類型就是 'pointer',
參數類型是['pointer', 'int']
注意 JavaScript 是沒有char* 這個類型的,所以要通過frida的api去模擬 這里Memory.allocUtf8String()申請空間 存入支付串 模擬char*
function test_c(str_data, n_num)
{
var str_name_so = "libnative-lib.so"; //要hook的so名
var str_name_func = "c_enc_2"; //要hook的函數名
//獲取函數的地址
var n_addr_func = Module.findExportByName(str_name_so , str_name_func);
console.log("func addr is ---" + n_addr_func);
//定義NativeFunction 等下要調用
var func_c_enc = new NativeFunction(n_addr_func , 'pointer', ['pointer', 'int']);
//調用frida的api申請空間 填入字符串 模擬char*
var str_data_arg = Memory.allocUtf8String(str_data);
//調用so層的c函數
var p_str_ret = func_c_enc(str_data_arg, n_num);
//讀取字符串
var str_ret = Memory.readCString(p_str_ret);
return str_ret;
}
持續更新移動安全,iot安全,編譯原理相關原創視頻文章
更多frida調用app方法 frida rpc視頻演示:[https://space.bilibili.com/430241559]
相關資料關注公眾號 回復rpc進行下載: