Frida坑太多了,16总是卡死设备,要注意的事项也许多,由于Frida十分不稳定,这儿比较主张运用frida15.2.2版本
通常来说, 咱们运用以下办法就能够正常拿到变量成果
/*
* 1.确定要Hook的函数
* 原函数:
* status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t deviceType,
* audio_policy_dev_state_t state,
* const char *device_address,
* const char *device_name,
* audio_format_t encodedFormat)
*
* 2.上面类型过于复杂,这儿咱们直接拿IDA检查函数对应的伪代码分析
* IDA伪代码:
* // attributes: thunk
* __int64 __fastcall android::AudioPolicyManager::setDeviceConnectionStateInt(int a1, int a2, int a3, char *a4)
* {
* return _ZN7android18AudioPolicyManager27setDeviceConnectionStateIntEj24audio_policy_dev_state_tPKcS3_14audio_format_t(
* a1,
* a2,
* a3,
* a4);
* }
*
* 3.从成果看IDA的伪代码参数是不正确的,所以咱们不要太相信IDA的伪代码成果,但咱们大致能够推断出5个参数的类型应该是
* int, int, char*, char*, int(估测,前4个参数基本是对的),知道具体参数类型后,接下来就方便读取参数值了
*/
//1.加载so文件
console.log("Loading Module => " + "libaudiopolicymanagerdefault.so");
let soModule = Process.getModuleByName("libaudiopolicymanagerdefault.so");
//2.定位Native函数
let funcName = soModule.getExportByName(
"_ZN7android18AudioPolicyManager27setDeviceConnectionStateIntEj24audio_policy_dev_state_tPKcS3_14audio_format_t"
);
//3.Hook并打印参数
Interceptor.attach(funcName, {
onEnter: function (args) {
//要注意,现在依据测验,变量索引从1开端传递(怀疑0或许是什么目标,如jniEnv,1开端才是真实的参数)
console.log("===============setDeviceConnectionStateInt===================");
console.log("deviceType:" + args[1].readInt());
console.log("deviceState:" + args[2].readInt());
console.log("deviceAddress:" + args[3].readCString());
console.log("deviceName:" + args[4].readCString());
console.log("encodedFormat:" + args[5].readInt());
},
onLeave: function (retval) {
console.log("retval:" + retval);
},
});
不过不出意外的话,或许会出现报错,提示地址无法拜访(问询GPT提示args或许不是简单的整数类型,那会不会是址类型的参数?假如是地址,咱们这么直接拿不就是错的吗?试图以变量的办法拜访地址)
Error: access violation accessing 0x4000000
at <anonymous> (frida/runtime/core.js:141)
at onEnter (agent/index.ts:312)
Error: access violation accessing 0x82000000
at <anonymous> (frida/runtime/core.js:141)
at onEnter (agent/index.ts:312)
试了很久,找到解决方案
//1.加载so文件
console.log("Loading Module => " + "libaudiopolicymanagerdefault.so");
let soModule = Process.getModuleByName("libaudiopolicymanagerdefault.so");
//2.定位Native函数
let funcName = soModule.getExportByName(
"_ZN7android18AudioPolicyManager27setDeviceConnectionStateIntEj24audio_policy_dev_state_tPKcS3_14audio_format_t"
);
//3.Hook并打印参数
Interceptor.attach(funcName, {
onEnter: function (args) {
//运用Memory作为中介,读取地址里的参数(现在不知道什么原因,但确实能够了)
console.log("===============setDeviceConnectionStateInt===================");
var arg1Pointer: NativePointer = Memory.alloc(4);
var arg2Pointer: NativePointer = Memory.alloc(4);
var arg5Pointer: NativePointer = Memory.alloc(4);
arg1Pointer.writePointer(args[1]);
arg2Pointer.writePointer(args[2]);
arg5Pointer.writePointer(args[5]);
console.log("deviceType:" + arg1Pointer.readInt());
console.log("deviceState:" + arg2Pointer.readInt());
console.log("device_address:" + args[3].readCString());
console.log("device_name:" + args[4].readCString());
console.log("encodedFormat:" + arg5Pointer.readInt());
},
onLeave: function (retval) {
console.log("retval:" + retval);
},
});
运转成果,测验参数完全正确
===============setDeviceConnectionStateInt===================
deviceType:-2113929216
deviceState:1
device_address:card=1;device=0;
device_name:USB-Audio - 1080P USB Camera
encodedFormat:0
retval:0x0
其它运用技巧
1.传值和替换返回值
1.需求传值到onLeave中, 咱们能够在onEnter中运用this.variable = value的办法传递和拜访
2.替换函数返回值retval.replace(要替换的成果)
2.Hook原Native办法,并依据参数决定是否调用原函数
已踩坑:第一个参数切记运用指针,或许是JNIEnv指针,即便你看过源码是一个空参数办法,也需求声明一个指针
//1.加载so文件
console.log("Loading Module => " + "libaudiopolicymanagerdefault.so");
let soModule = Process.getModuleByName("libaudiopolicymanagerdefault.so");
//2.定位Native函数
let funcName = soModule.getExportByName( "_ZN7android18AudioPolicyManager27setDeviceConnectionStateIntEj24audio_policy_dev_state_tPKcS3_14audio_format_t"
);
//3.依据原函数地址构建NativeFunction(这儿要写在Interceptor.replace之前,留给之后调用)
//**要点,请注意第一个参数或许是一个指针,所以用pointer,不用pointer后边或许出现莫名奇妙的问题,比如地址无法拜访之类的**
let nativeFunction = new NativeFunction(funcName, "int", ["pointer", "int", "int", "pointer", "pointer", "int"]);
//4.替换原函数
Interceptor.replace(
funcName,
new NativeCallback(
function (arg1: any, deviceType: any, deviceState: any, deviceAddress: any, deviceName: any, encodedFormat: any) {
console.log("===============setDeviceConnectionStateInt(Replacement)===================");
console.log("arg1:" + arg1);
console.log("deviceType:" + deviceType);
console.log("deviceState:" + deviceState);
console.log("deviceAddress:" + deviceAddress.readCString());
console.log("deviceName:" + deviceName.readCString());
console.log("encodedFormat:" + encodedFormat);
//5.依据条件,是否调用原函数
if (deviceType !== -2113929216) {
//这一段或许会报错:access violation accessing 0x835a168,不明白为什么,可是看日志办法有又调用到了
let original = nativeFunction(arg1, deviceType, 0, deviceAddress, deviceName, 0);
console.error("原函数返回值:" + original);
return original;
}
return 0;
},
"int",
["pointer", "int", "int", "pointer", "pointer", "int"]
)
);
3.依据模块和函数称号查找函数列表
/**
* 依据模块和函数称号查找函数列表
* @param module so模块
* @param funcName 函数称号
* @returns 函数列表
*/
function findFuncByModule(module: Module, funcName: string) {
let moduleResult: any = [];
module.enumerateExports().forEach(function (exp) {
if (exp.name.indexOf(funcName) != -1) {
moduleResult.push(exp);
}
});
return moduleResult;
}
let soModule = Process.getModuleByName("libaudiopolicymanagerdefault.so");
findFuncByModule(soModule, "setDeviceConnectionState").forEach(function (exp:any) {
console.log("name:" + exp.name + " type:" + exp.type + " address:" + exp.address);
});
4.假如native办法的参数是指针类型的,获取这个指针的数据
Interceptor.replace(
setEngineDeviceConnectionStateFun,
new NativeCallback(
function (arg1: any, device: any, state: any) {
console.log("===============setEngineDeviceConnectionState(Replacement)===================");
console.log("arg1:" + arg1);
console.log("device:" + device);
console.log("state:" + state);
//device其实就是参数目标的开始地址,想要得到目标内数据,咱们有必要知道数据类型,以及偏移,知道了之后,咱们加上开始地址的偏移就能够得到参数内容
var idOffset = parseInt(device + "", 16) + 98;
var tagOffset = parseInt(device + "", 16) + 320;
var idOffsetAddr = "0x" + "" + idOffset.toString(16);
var tagOffsetAddr = "0x" + "" + tagOffset.toString(16);
console.log("device目标地址 => " + device + ", device.id值 => " + ptr(idOffsetAddr).readUInt());
console.log("device目标地址 => " + device + ", device.deviceTag值 => " + ptr(tagOffsetAddr).readCString());
let original = setEngineDeviceConnectionState(arg1, arg2, arg3);
console.log("original:" + original);
},
"void",
["pointer", "pointer", "int"]
)
);
文章如有错请指导,后续学到新的知识会再持续补充…