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"]
  )
);

文章如有错请指导,后续学到新的知识会再持续补充…