Frida Javascript api #Stalker (中文版)

原文链接: https://frida.re/docs/javascript-api/#stalker
欢迎加入 Frida 交流群: 1049977261

Stalker

  • Stalker.exclude(range):
    将指定的内存范围 range 标记为被排除的状态, range 对象包含 basesize 属性 - 类似于 Process.getModuleByName() 返回的对象.

    这意味着 Stalker (潜行者) 将不会跟踪执行这个范围内的指令调用. 您将因此可以观察或者修改传入的参数以及返回的结果, 但不会看到指令之间发生了什么.

    这对提升性能以及降噪很有用.

  • Stalker.follow([threadId, options]):
    开始跟踪 threadId 对应的线程, 如果省略则跟踪当前线程, 可选的 options 可用于开启事件.

    例如:

const mainThread = Process.enumerateThreads()[0];

Stalker.follow(mainThread.id, {
  events: {
    call: true, // 调用指令

    // 其他事件:
    ret: false, // 返回指令
    exec: false, // 全部指令:不推荐, 因为数据量过大
    block: false, // 已计算的块: 粗略执行轨迹
    compile: false // 已编译的块: 对覆盖率很有用
  },

  //
  // 仅指定以下两个回调之一. (见下方的备注.)
  //

  //
  // onReceive: 伴随 `events` 一起被调用. `events` 包含一个或多个
  //            GumEvent 结构. 关于格式的细节请参考 `gumevent.h`
  //            您需要使用 `Stalker.parse()` 来解释其中的数据.
  //
  //onReceive: function (events) {
  //},
  //

  //
  // onCallSummary: 伴随 `summary` 一起被调用. `summary` 是一个由调用的
  //                对象地址作为键, 当前时间窗口内调用次数为值构成的键值对对象.
  //                通常情况下您应当实现这个方法而不是 `onReceive()`, 例如:
  //                当您只想知道哪些目标被调用, 以及被调用了多少次, 但不关心
  //                调用的顺序时.
  //
  onCallSummary: function (summary) {
  },

  //
  // 进阶用例:  这里展示了您应当如何插入您自己的 StalkerTransformer.
  //            您所提供的方法将在 Stalker 想要重新编译即将被已跟踪的线程
  //            执行的一个基础代码块时被同步调用.
  //
  //transform: function (iterator) {
  //  var instruction = iterator.next();
  //
  //  var startAddress = instruction.address;
  //  var isAppCode = startAddress.compare(appStart) >= 0 &&
  //      startAddress.compare(appEnd) === -1;
  //
  //  do {
  //    if (isAppCode && instruction.mnemonic === 'ret') {
  //      iterator.putCmpRegI32('eax', 60);
  //      iterator.putJccShortLabel('jb', 'nope', 'no-hint');
  //
  //      iterator.putCmpRegI32('eax', 90);
  //      iterator.putJccShortLabel('ja', 'nope', 'no-hint');
  //
  //      iterator.putCallout(onMatch);
  //
  //      iterator.putLabel('nope');
  //    }
  //
  //    iterator.keep();
  //  } while ((instruction = iterator.next()) !== null);
  //},
  //
  // 默认的实现为:
  //
  //   while (iterator.next() !== null)
  //     iterator.keep();
  //
  // 上面的示例展示了您可以插入您自己的代码到应用内存范围内被跟踪的线程的
  // 每一个 `ret` 指令前. 它插入的代码检查了 `eax` 寄存器是否包含一个 60
  // 到 90 之间的值, 并插入了一个同步的回调, 每当出现这种情况时便调用 JavaScript
  // 回调. 这个回调接受一个参数, 这个参数给与您接触 CPU 寄存器, 并修改它
  // 的值的能力.
  //
  // function onMatch (context) {
  //   console.log('Match! pc=' + context.pc +
  //       ' rax=' + context.rax.toInt32());
  // }
  //
  // 请注意, 不调用 keep() 将导致指令被遗弃, 这使得您在必要时完全替换特定的
  // 指令成为了可能.
  //

  //
  // 想要更好的性能? 试着在 C 中书写回调:
  //
  // /*
  //  * const cm = new CModule(\`
  //  *
  //  * #include <gum/gumstalker.h>
  //  *
  //  * static void on_ret (GumCpuContext * cpu_context,
  //  *     gpointer user_data);
  //  *
  //  * void
  //  * transform (GumStalkerIterator * iterator,
  //  *            GumStalkerWriter * output,
  //  *            gpointer user_data)
  //  * {
  //  *   cs_insn * insn;
  //  *
  //  *   while (gum_stalker_iterator_next (iterator, &insn))
  //  *   {
  //  *     if (insn->id == X86_INS_RET)
  //  *     {
  //  *       gum_x86_writer_put_nop (output);
  //  *       gum_stalker_iterator_put_callout (iterator,
  //  *           on_ret, NULL, NULL);
  //  *     }
  //  *
  //  *     gum_stalker_iterator_keep (iterator);
  //  *   }
  //  * }
  //  *
  //  * static void
  //  * on_ret (GumCpuContext * cpu_context,
  //  *         gpointer user_data)
  //  * {
  //  *   printf ("on_ret!\n");
  //  * }
  //  *
  //  * `);
  //  */
  //
  //transform: cm.transform,
  //data: ptr(1337) /* user_data */
  //
  // 您也可以使用一个混合的方案, 并且只在 C 中书写部分回调.
  //
});
性能方面的注意事项

回调对象对性能有显著的影响. 如果您只需要周期性的调用简介但不关心原始事件, 或者相反, 请确保您忽略您不需要的回调. 例如, 避免将您的逻辑放到 onCallSummary 并且让 onReceive 是一个空回调.
同样请注意可以将 Stalker 与 CModule 结合以使用在 C 中实现的回调.

  • Stalker.unfollow([threadId]): 停止跟踪 threadId 对应的线程, 如果省略, 则停止跟踪当前线程.

  • Stalker.parse(events[, options]): 解析 GumEvent 二进制大型对象, 可选的 options 可用于定制输出格式.

    例如:

  onReceive: function (events) {
    console.log(Stalker.parse(events, {
      annotate: true, // 展示事件类型
      stringify: true
        // 将指针的值格式化为字符串而不是 `NativePointer` 值. 例如: 如果
        // 您只是想把事件通过 `send()` 发送出去而不是在代理侧解析它的话,
        // 这么做就可以占用更少的消耗.
    }));
  },
  • Stalker.flush(): 齐平任何已缓冲的事件.
    当您不想要等到下一次 Stalker.queueDrainInterval 触发时很有用.

  • Stalker.garbageCollect(): 在 Stalker#unfollow 之后的安全位置释放模拟内存. 这在避免刚刚被停止跟踪线程执行它的最后一条指令是出现竞争情况时很有必要.

  • Stalker.addCallProbe(address, callback[, data]):
    address 处的方法被调用时触发 callback, callback 的签名与 Interceptor#attach#onEnter 相同. 返回一个稍后可以传递给 Stalker#removeCallProbe 的 id.

    当然, 您也可以通过 CModule 在 C 语言中实现的 callback, 只需要指明一个 NativePointer 而不是一个方法. 它的签名是:

    • void onCall (GumCallSite * site, gpointer user_data)

    在这种情况下, 第三个可选参数 data 应当是一个 NativePointer, 它的值将作为 user_data 被传入回调中.

  • Stalker.removeCallProbe: 移除一个通过 Stalker#addCallProbe 添加的调用检测器.

  • Stalker.trustThreshold:
    一个整型数字, 指明了一段代码需要被运行多少次才能被假定为可认为是不变的.
    -1 意味着不信任 (慢), 0 意味着在调用时被信任, N 意味着它在执行 N 次以后才获得信任. 默认是 1.

  • Stalker.queueCapacity:
    一个整形数字, 指明了事件队列中事件的容量. 默认是 16384 个事件.

  • Stalker.queueDrainInterval:
    一个整型数字, 指明了每次事件队列发送事件之间的毫秒数. 默认 250 毫秒, 这意味着事件队列每秒发送 4 次事件. 您可以将这个值设为 0 来禁止周期性的发送事件, 取而代之的是当您想要获得事件时调用 Stalker.flush().

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容