Skip to content

Hook 引擎 agent/src/android/hooking.ts ​

hooking.ts 是 Android 平台最核心的模块之一,提供 Java 类枚举、方法枚举与重载解析、方法监听(watch)、返回值篡改、当前 Activity/Service/Receiver 枚举等能力。它是 android hooking 命令族在 Agent 侧的全部实现。

📋 模块概览 ​

项目值
文件路径agent/src/android/hooking.ts
平台Android
导出 RPCandroidHookingGetClassMethods、androidHookingGetClassMethodsOverloads、androidHookingGetClasses、androidHookingGetClassLoaders、androidHookingGetCurrentActivity、androidHookingListActivities、androidHookingListBroadcastReceivers、androidHookingListServices、androidHookingSetMethodReturn、androidHookingWatch、androidHookingEnumerate、androidHookingLazyWatchForPattern
依赖lib/color.ts、lib/jobs.ts、android/lib/interfaces.ts、android/lib/libjava.ts、android/lib/types.ts、frida-java-bridge

🎯 解决的问题 ​

  • 枚举已加载的 Java 类与 ClassLoader,定位目标类。
  • 按"类.方法"或正则模式批量 Hook 方法,记录参数/返回值/调用栈。
  • 篡改布尔方法返回值(绕过 root/jailbreak 检测的常用手段)。
  • 列出 App 当前注册的 Activity / Service / BroadcastReceiver。
  • 支持"懒监听":类还没加载时定时轮询,加载后再 Hook。

🏗️ 导出的 RPC 方法 ​

RPC 名说明
androidHookingGetClassesJava.enumerateLoadedClassesSync()
androidHookingGetClassLoadersJava.enumerateClassLoaders
androidHookingGetClassMethods(className)getDeclaredMethods().toGenericString()
androidHookingGetClassMethodsOverloads(className, allowList, loader)解析每个方法的所有 overload 的 arg/return 类型
androidHookingGetCurrentActivity从 ActivityThread.mActivities 找未 paused 的 Activity
androidHookingListActivitiesPackageManager.getPackageInfo(GET_ACTIVITIES)
androidHookingListServicesmLoadedApk.mServices + GET_SERVICES
androidHookingListBroadcastReceiversmLoadedApk.mReceivers + GET_RECEIVERS
androidHookingWatch(pattern, args, bt, ret)按类或正则 watch
androidHookingEnumerate(query)Java.enumerateMethods
androidHookingLazyWatchForPattern(...)5 秒轮询直到类加载再 watch
androidHookingSetMethodReturn(fqClazz, filterOverload, ret)篡改返回值

rpc.androidHookingWatch — 监听方法 ​

源码:agent/src/android/hooking.ts:258

按 pattern 类型分流:不含 ! 视为类名(watch 整个类),含 ! 视为正则(Java.enumerateMethods 后逐方法 watch):

ts
// agent/src/android/hooking.ts:262-294
const patternType = getPatternType(pattern);
if (patternType === PatternType.Klass) {
  const job = new jobs.Job(jobs.identifier(), `watch-class for: ${pattern}`);
  const w = watchClass(pattern, job, dargs, dbt, dret);
  jobs.add(job);
  return w;
}
// PatternType.Regex
const job = new jobs.Job(jobs.identifier(), `watch-pattern for: ${pattern}`);
jobs.add(job);
return new Promise((resolve, reject) => {
  javaEnumerate(pattern).then((matches) => {
    matches.forEach((match) => {
      match.classes.forEach((klass) => {
        klass.methods.forEach((method) => {
          watchMethod(`${klass.name}.${method}`, job, dargs, dbt, dret);
        });
      });
    });
    resolve();
  }).catch(reject);
});

watchMethod — 单方法 Hook ​

源码:agent/src/android/hooking.ts:342

对每个 overload 替换 implementation,按标志位 dump 参数/调用栈/返回值:

ts
// agent/src/android/hooking.ts:359-408
targetClass[method].overloads.forEach((m: any) => {
  const calleeArgTypes = m.argumentTypes.map((arg) => arg.className);
  send(`Watching ${clazz}.${method}(${calleeArgTypes.join(", ")})`);
  m.implementation = function () {
    send(`[${job.identifier}] Called ${clazz}.${m.methodName}(${calleeArgTypes.join(", ")})`);
    if (dbt) {
      send(`[${job.identifier}] Backtrace:\n\t` +
        throwable.$new().getStackTrace().map((t) => t.toString() + "\n\t").join(""));
    }
    if (dargs && calleeArgTypes.length > 0) {
      const argValues = [];
      for (const h of arguments) argValues.push((h || "(none)").toString());
      send(`[${job.identifier}] Arguments ${clazz}.${m.methodName}(${argValues.join(", ")})`);
    }
    const retVal = m.apply(this, arguments);   // 调原方法
    if (dret) {
      send(`[${job.identifier}] Return Value: ${((retVal || "(none)").toString())}`);
    }
    return retVal;
  };
  job.addImplementation(m);   // 供 jobsKill 还原
});

rpc.androidHookingSetMethodReturn — 篡改返回值 ​

源码:agent/src/android/hooking.ts:535

ts
// agent/src/android/hooking.ts:550-575
targetClazz[method].overloads.forEach((m: any) => {
  const calleeArgTypes = m.argumentTypes.map((arg) => arg.className);
  if (filterOverload != null && calleeArgTypes.join(",") !== filterOverload) return;
  m.implementation = function () {
    let retVal = m.apply(this, arguments);
    if (retVal !== newRet) {
      send(`[${job.identifier}] Return value was not ${newRet}, setting to ${newRet}.`);
      retVal = newRet;
    }
    return retVal;
  };
  job.addImplementation(m);
});

rpc.androidHookingGetCurrentActivity — 当前 Activity ​

源码:agent/src/android/hooking.ts:421

ts
// agent/src/android/hooking.ts:427-448
const activityThread = Java.use("android.app.ActivityThread");
const activity = Java.use("android.app.Activity");
const activityClientRecord = Java.use("android.app.ActivityThread$ActivityClientRecord");
const currentActivityThread = activityThread.currentActivityThread();
const activityRecords = currentActivityThread.mActivities.value.values().toArray();
for (const i of activityRecords) {
  const activityRecord = Java.cast(i, activityClientRecord);
  if (!activityRecord.paused.value) {
    currentActivity = Java.cast(activityRecord.activity.value, activity);
    break;
  }
}

⚙️ 实现要点 ​

  • PatternType 判定:pattern.indexOf('!') !== -1 为正则,否则为类名(:65-71)。正则需 *class*!* 格式喂给 Java.enumerateMethods(:127)。
  • 方法名清洗:watchClass 把 public static void com.foo.Bar.doIt(Canvas) 清洗成 doIt,去掉泛型/throws/作用域/类名/签名(:301-319)。
  • ClassLoader 透明化:getClassHandle/getClassHandleWithLoaderClassName(:157-208)遍历所有 ClassLoader 用 Java.ClassFactory.get(loader).use(name) 取类,解决多 ClassLoader App 找不到类的问题。
  • overload 过滤:setReturnValue 用 calleeArgTypes.join(",") !== filterOverload 跳过非目标 overload(:555)。
  • ClassNotFoundError 检测:(err).stack 含 java.lang.ClassNotFoundException 时静默返回,避免噪音(:27-30)。
  • Job 注册:每个 watch / setReturn 都建 Job 并 job.addImplementation(m),使 jobsKill 能把 implementation = null 还原(lib/jobs.ts:59-67)。
  • 懒监听:lazyWatchForPattern 用 setInterval 5 秒轮询 javaEnumerate,找到后 watchMatches 并 clearInterval(:107-122)。

📐 watch 流程 ​

🔍 源码索引 ​

符号位置
PatternType enumagent/src/android/hooking.ts:22
isClassNotFoundErroragent/src/android/hooking.ts:27
splitClassMethodagent/src/android/hooking.ts:32
getClassesagent/src/android/hooking.ts:42
getClassLoadersagent/src/android/hooking.ts:48
getPatternTypeagent/src/android/hooking.ts:65
lazyWatchForPatternagent/src/android/hooking.ts:73
javaEnumerateagent/src/android/hooking.ts:124
getClassMethodsagent/src/android/hooking.ts:135
getClassHandleagent/src/android/hooking.ts:157
getClassHandleWithLoaderClassNameagent/src/android/hooking.ts:182
getClassMethodsOverloadsagent/src/android/hooking.ts:210
watchagent/src/android/hooking.ts:258
watchClassagent/src/android/hooking.ts:296
watchMethodagent/src/android/hooking.ts:342
getCurrentActivityagent/src/android/hooking.ts:421
getActivitiesagent/src/android/hooking.ts:457
getServicesagent/src/android/hooking.ts:472
getBroadcastReceiversagent/src/android/hooking.ts:502
setReturnValueagent/src/android/hooking.ts:535

🔗 相关文档 ​

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