Skip to content

Hooking 控制 agent/src/ios/hooking.ts ​

hooking.ts 在 iOS 目标进程里枚举 ObjC 类与方法、按模式搜索选择子、Hook 类或方法并 dump 参数/返回值/回溯、强制改写方法返回值。它支撑 objection 的 ios hooking 全部子命令,是 iOS 动态分析的主力模块。

📋 模块概览 ​

项目值
文件路径agent/src/ios/hooking.ts
平台iOS
导出 RPCiosHookingGetClasses、iosHookingGetClassMethods、iosHookingWatch、iosHookingSearch、iosHookingSetReturnValue
依赖ios/lib/libobjc.ts、lib/color.ts、lib/jobs.ts

🎯 解决的问题 ​

  • 列出当前进程加载的全部 ObjC 类与某类的方法(可选是否含父类方法)。
  • 用 ApiResolver('objc') 按 glob 模式搜索选择子,定位要 Hook 的方法。
  • Hook 整个类或单个方法,按需 dump 参数、回溯、返回值。
  • 强制把某 BOOL 方法的返回值改成 true/false,绕过越狱检测、Root 检测等开关。

🏗️ 导出的 RPC 方法 ​

RPC 名说明
iosHookingGetClasses返回 ObjC.classes 全部类
iosHookingGetClassMethods返回类方法列表,includeParents 控制是否含父类方法
iosHookingWatchHook 类或选择子,按 dargs/dbt/dret/dparents 控制输出
iosHookingSearch按 pattern 搜索 ObjC 选择子
iosHookingSetReturnValue强制覆盖方法返回值为 true/false

rpc.iosHookingWatch — Hook 类或方法 ​

源码:agent/src/ios/hooking.ts:35

watch 建一个 ios-watch 任务,根据 pattern 是否含 [ 判断是选择子模式还是类名:含 [ 则用 ApiResolver 展开所有匹配方法逐个 watchMethod,否则调 watchClass:

ts
// agent/src/ios/hooking.ts:44-56
const isPattern = patternOrClass.includes('[');
if (isPattern === true) {
  const matches = objcEnumerate(patternOrClass);
  matches.forEach((match: ApiResolverMatch) => {
    watchMethod(match.name, job, dargs, dbt, dret);
  });
  return;
}
watchClass(patternOrClass, job, dargs, dbt, dret, watchParents);

watchClass 根据 parents 决定遍历 $methods 还是 $ownMethods,拼成 -[Class method] 选择子交给 watchMethod(:71-76)。

watchMethod — 拦截单个选择子 ​

源码:agent/src/ios/hooking.ts:80

用 ApiResolver('objc') 解析选择子地址,Interceptor.attach 挂上。onEnter 统计参数个数(按 : 数量),打印调用与 receiver $kind/$superClass;按 dbt 打回溯、按 dargs dump 参数(args[0]=self, args[1]=selector, args[2+]=实参):

ts
// agent/src/ios/hooking.ts:139-151
if (dargs && argumentCount > 0) {
  const methodSplit = ObjC.selectorAsString(args[1]).split(":").filter((val) => val);
  const r = methodSplit.map((argName, position) => {
    const t = new ObjC.Object(args[position + 2]);
    return `${argName}: ${c.greenBright(`${t}`)}`;
  });
  send(...`Argument dump: [${c.green(receiver.$className)} ${r.join(" ")}]`);
}

onLeave 按 dret 打印返回值(:157-161),InvocationListener 加入任务。

rpc.iosHookingSetReturnValue — 改写返回值 ​

源码:agent/src/ios/hooking.ts:167

TRUE = 0x1、FALSE = 0x0。ApiResolver 解析选择子,onLeave 比较当前返回值,不同则 retval.replace:

ts
// agent/src/ios/hooking.ts:202-216
const watchInvocation: InvocationListener = Interceptor.attach(matchedMethod.address, {
  onLeave: (retval) => {
    switch (returnValue) {
      case true:
        if (retval.equals(TRUE)) { return; }
        retval.replace(TRUE);
        break;
      case false:
        if (retval.equals(FALSE)) { return; }
        retval.replace(FALSE);
        break;
    }
  },
});

rpc.iosHookingSearch — 选择子搜索 ​

源码:agent/src/ios/hooking.ts:27

不含 [ 时自动补成 *[*<pattern>* *] 通配模式,再 objcEnumerate:

ts
// agent/src/ios/hooking.ts:29-32
if (!patternOrClass.includes('[')) patternOrClass = `*[*${patternOrClass}* *]`;
return objcEnumerate(patternOrClass);

⚙️ 实现要点 ​

  • ApiResolver('objc'):Frida 提供的 ObjC 选择子解析器,支持 glob,watchMethod 与 search 都经 objcEnumerate(:23-25)。
  • 参数偏移 +2:ObjC 方法 args[0]=self、args[1]=selector、args[2+]= 实参,dump 参数时按 position + 2 取(:149)。
  • 多匹配告警:resolved.length > 1 时发警告但只 Hook 第一个(:101-103,源码注释 TODO 待正确循环 glob)。
  • 任务分组:watch 把多个 watchMethod 的 InvocationListener 收进同一 ios-watch 任务,便于 ios hooking list 统一管理。

🔍 源码索引 ​

符号位置
getClassesagent/src/ios/hooking.ts:6
getClassMethodsagent/src/ios/hooking.ts:10
objcEnumerateagent/src/ios/hooking.ts:23
searchagent/src/ios/hooking.ts:27
watchagent/src/ios/hooking.ts:35
watchClassagent/src/ios/hooking.ts:59
watchMethodagent/src/ios/hooking.ts:80
setMethodReturnagent/src/ios/hooking.ts:167

🔗 相关文档 ​

基于 GPL-3.0-or-later 许可发布