huan / sidecar

Easily hook/call binary functions using ES6 class with TypeScript annotation (Powered by Frida)
https://npmjs.com/package/sidecar
Apache License 2.0
47 stars 7 forks source link

The Interceptor attached to a NativeCallback will not be triggered in another Interceptor `onEnter` function #9

Open huan opened 3 years ago

huan commented 3 years ago

This week I ran into an issue that the onEnter has not been triggered with the Interceptor.attach().

The following is the source code. It's quite straightforward:

  1. create a NativeCallback(mtNativeCallback) then create a NativeFunction(mtNativeFunction) to call it.
  2. create a Interceptor.attach() to address 0x121f, and invoke mtNativeFunction in its onEnter callback.
  3. create another Interceptor.attach() to ptr mtNativeCallback, and print SUCCEDD when it was invoked.
/**
 * Hook -> mtNativeCallback
 *  MT Sidecar Agent Helper
 */
const mtNativeCallback = new NativeCallback(() => {}, 'void', ['pointer'])
const mtNativeFunction = new NativeFunction(mtNativeCallback, 'void', ['pointer'])

Interceptor.attach(
  sidecarModuleBaseAddress.add(0x121f),
  {
    onEnter: args => mtNativeFunction(args[0])
  }
)

Interceptor.attach(
  mtNativeCallback,
  {
    onEnter: args => console.log('SUCCEED!')
  }
)

However, the above code does not work:

  1. the first interceptor to 0x121f works without any problem
  2. the native callback has been called successfully
  3. the second interceptor to mtNativeCallback is NOT called. (???)

1 & 2 is good but 3 makes no sense because it should work.

Workaround

After investigating a lot with Frida, the following workaround works:

  1. use a setImmediate to put the mtNativeFunction() call to the next event loop
Interceptor.attach(
  sidecarModuleBaseAddress.add(0x121f),
  {
-     onEnter: args => mtNativeFunction(args[0])
+     onEnter: args => {
+        * Huan(202107):
+        *  1. We MUST use `setImmediate()` for calling `mtNativeFunction(arg0),
+        *    or the hook to mtNativeCallback will not be triggered. (???)
+        *  2. `args` MUST be saved to arg0 so that it can be access in the `setImmediate`
+        */
+       const arg0 = args[0]
+       setImmediate(() => mtNativeFunction(arg0))
    }
  }
)

Link to frida#1774, Need to be investigated.