frida-java-bridge 7.0.8 → 7.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -415,11 +415,25 @@ declare module "frida-java-bridge" {
415
415
  [name: string]: any;
416
416
  };
417
417
 
418
- interface MethodDispatcher<Holder extends Members<Holder> = {}> extends Method<Holder> {
418
+ type IsEmptyArray<T extends any[]> = T extends [] ? true : false;
419
+
420
+ type Overload<Identifiers extends Array<string> = [], Types extends Array<any> = [], Return = any> = [Identifiers, Types, Return];
421
+
422
+ type OverloadsMethods<
423
+ Holder extends Members<Holder> = {},
424
+ OLs extends ReadonlyArray<Overload<any, any, any>> = []
425
+ > = {
426
+ [K in keyof OLs]:
427
+ OLs[K] extends Overload<any, infer A extends any[], infer R>
428
+ ? Method<Holder, A, R>
429
+ : never
430
+ };
431
+
432
+ interface MethodDispatcher<Holder extends Members<Holder> = {}, Overloads extends Array<Overload<Array<any>, Array<any>, any>> = []> extends Method<Holder> {
419
433
  /**
420
434
  * Available overloads.
421
435
  */
422
- overloads: Array<Method<Holder>>;
436
+ overloads: IsEmptyArray<Overloads> extends true ? Array<Method<Holder>> : OverloadsMethods<Holder, Overloads>;
423
437
 
424
438
  /**
425
439
  * Obtains a specific overload.
@@ -430,8 +444,8 @@ declare module "frida-java-bridge" {
430
444
  overload(...args: string[]): Method<Holder>;
431
445
  }
432
446
 
433
- interface Method<Holder extends Members<Holder> = {}> {
434
- (...params: any[]): any;
447
+ interface Method<Holder extends Members<Holder> = {}, Params extends any[] = any[], Return = any> {
448
+ (...params: Params): Return;
435
449
 
436
450
  /**
437
451
  * Name of this method.
@@ -458,7 +472,7 @@ declare module "frida-java-bridge" {
458
472
  * replace the original implementation. Assign `null` at a future point
459
473
  * to revert back to the original implementation.
460
474
  */
461
- implementation: MethodImplementation<Holder> | null;
475
+ implementation: MethodImplementation<Holder, Params, Return> | null;
462
476
 
463
477
  /**
464
478
  * Method return type.
@@ -481,10 +495,10 @@ declare module "frida-java-bridge" {
481
495
  * Useful for e.g. setting `traps: "all"` to perform execution tracing
482
496
  * in conjunction with Stalker.
483
497
  */
484
- clone: (options: NativeFunctionOptions) => Method<Holder>;
498
+ clone: (options: NativeFunctionOptions) => Method<Holder, Params, Return>;
485
499
  }
486
500
 
487
- type MethodImplementation<This extends Members<This> = {}> = (this: Wrapper<This>, ...params: any[]) => any;
501
+ type MethodImplementation<This extends Members<This> = {}, Params extends any[] = any[], Return = any> = (this: Wrapper<This>, ...params: Params) => Return;
488
502
 
489
503
  interface Field<Value = any, Holder extends Members<Holder> = {}> {
490
504
  /**
package/lib/android.js CHANGED
@@ -88,6 +88,7 @@ const getArtThreadStateTransitionImpl = memoize(_getArtThreadStateTransitionImpl
88
88
  export const getAndroidVersion = memoize(_getAndroidVersion);
89
89
  const getAndroidCodename = memoize(_getAndroidCodename);
90
90
  export const getAndroidApiLevel = memoize(_getAndroidApiLevel);
91
+ export const getArtApexVersion = memoize(_getArtApexVersion);
91
92
  const getArtQuickFrameInfoGetterThunk = memoize(_getArtQuickFrameInfoGetterThunk);
92
93
 
93
94
  const makeCxxMethodWrapperReturningPointerByValue =
@@ -253,6 +254,7 @@ function _getApi () {
253
254
  this['art::StackVisitor::GetCurrentQuickFrameInfo'] = makeArtQuickFrameInfoGetter(address);
254
255
  },
255
256
 
257
+ _ZN3art7Context6CreateEv: ['art::Context::Create', 'pointer', []],
256
258
  _ZN3art6Thread18GetLongJumpContextEv: ['art::Thread::GetLongJumpContext', 'pointer', ['pointer']],
257
259
 
258
260
  _ZN3art6mirror5Class13GetDescriptorEPNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE: function (address) {
@@ -352,6 +354,7 @@ function _getApi () {
352
354
  '_ZNK3art12StackVisitor9GetMethodEv',
353
355
  '_ZNK3art12StackVisitor16DescribeLocationEv',
354
356
  '_ZNK3art12StackVisitor24GetCurrentQuickFrameInfoEv',
357
+ '_ZN3art7Context6CreateEv',
355
358
  '_ZN3art6Thread18GetLongJumpContextEv',
356
359
  '_ZN3art6mirror5Class13GetDescriptorEPNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE',
357
360
  '_ZN3art6mirror5Class11GetLocationEv',
@@ -461,6 +464,11 @@ function _getApi () {
461
464
  const instrumentationOffset = runtimeOffset.instrumentation;
462
465
  temporaryApi.artInstrumentation = (instrumentationOffset !== null) ? artRuntime.add(instrumentationOffset) : null;
463
466
 
467
+ const instrumentationIsPointer = getArtApexVersion() >= 360_000_000;
468
+ if (instrumentationIsPointer && temporaryApi.artInstrumentation != null) {
469
+ temporaryApi.artInstrumentation = temporaryApi.artInstrumentation.readPointer();
470
+ }
471
+
464
472
  temporaryApi.artHeap = artRuntime.add(runtimeOffset.heap).readPointer();
465
473
  temporaryApi.artThreadList = artRuntime.add(runtimeOffset.threadList).readPointer();
466
474
 
@@ -691,7 +699,11 @@ function _getArtRuntimeSpec (api) {
691
699
  throw new Error('Unable to determine Runtime field offsets');
692
700
  }
693
701
 
694
- spec.offset.instrumentation = tryDetectInstrumentationOffset(api);
702
+ const instrumentationIsPointer = getArtApexVersion() >= 360_000_000;
703
+ spec.offset.instrumentation = instrumentationIsPointer
704
+ ? tryDetectInstrumentationPointer(api)
705
+ : tryDetectInstrumentationOffset(api);
706
+
695
707
  spec.offset.jniIdsIndirection = tryDetectJniIdsIndirectionOffset(api);
696
708
 
697
709
  return spec;
@@ -771,6 +783,78 @@ function parseArm64InstrumentationOffset (insn) {
771
783
  return offset;
772
784
  }
773
785
 
786
+ const instrumentationPointerParser = {
787
+ ia32: parsex86InstrumentationPointer,
788
+ x64: parsex86InstrumentationPointer,
789
+ arm: parseArmInstrumentationPointer,
790
+ arm64: parseArm64InstrumentationPointer
791
+ };
792
+
793
+ function tryDetectInstrumentationPointer (api) {
794
+ const impl = api['art::Runtime::DeoptimizeBootImage'];
795
+ if (impl === undefined) {
796
+ return null;
797
+ }
798
+
799
+ return parseInstructionsAt(impl, instrumentationPointerParser[Process.arch], { limit: 30 });
800
+ }
801
+
802
+ function parsex86InstrumentationPointer (insn) {
803
+ if (insn.mnemonic !== 'mov') {
804
+ return null;
805
+ }
806
+
807
+ const ops = insn.operands;
808
+
809
+ const dst = ops[0];
810
+ if (dst.value !== 'rax') {
811
+ return null;
812
+ }
813
+
814
+ const src = ops[1];
815
+ if (src.type !== 'mem') {
816
+ return null;
817
+ }
818
+
819
+ const mem = src.value;
820
+ if (mem.base !== 'rdi') {
821
+ return null;
822
+ }
823
+
824
+ const offset = mem.disp;
825
+ if (offset < 0x100 || offset > 0x400) {
826
+ return null;
827
+ }
828
+ return offset;
829
+ }
830
+
831
+ function parseArmInstrumentationPointer (insn) {
832
+ return null;
833
+ }
834
+
835
+ function parseArm64InstrumentationPointer (insn) {
836
+ if (insn.mnemonic !== 'ldr') {
837
+ return null;
838
+ }
839
+
840
+ const ops = insn.operands;
841
+
842
+ if (ops[0].value === 'x0') {
843
+ return null;
844
+ }
845
+
846
+ const mem = ops[1].value;
847
+ if (mem.base !== 'x0') {
848
+ return null;
849
+ }
850
+
851
+ const offset = mem.disp;
852
+ if (offset < 0x100 || offset > 0x400) {
853
+ return null;
854
+ }
855
+ return offset;
856
+ }
857
+
774
858
  const jniIdsIndirectionOffsetParsers = {
775
859
  ia32: parsex86JniIdsIndirectionOffset,
776
860
  x64: parsex86JniIdsIndirectionOffset,
@@ -1364,6 +1448,39 @@ function _getAndroidApiLevel () {
1364
1448
  return parseInt(getAndroidSystemProperty('ro.build.version.sdk'), 10);
1365
1449
  }
1366
1450
 
1451
+ function _getArtApexVersion () {
1452
+ try {
1453
+ const mountInfo = File.readAllText('/proc/self/mountinfo');
1454
+
1455
+ let artSource = null;
1456
+ const sourceVersions = new Map();
1457
+ for (const line of mountInfo.trimEnd().split('\n')) {
1458
+ const elements = line.split(' ');
1459
+
1460
+ const mountRoot = elements[4];
1461
+ if (!mountRoot.startsWith('/apex/com.android.art')) {
1462
+ continue;
1463
+ }
1464
+
1465
+ const mountSource = elements[10];
1466
+ if (mountRoot.includes('@')) {
1467
+ sourceVersions.set(mountSource, mountRoot.split('@')[1]);
1468
+ } else {
1469
+ artSource = mountSource;
1470
+ }
1471
+ }
1472
+
1473
+ const strVersion = sourceVersions.get(artSource);
1474
+ return (strVersion !== undefined) ? parseInt(strVersion) : computeArtApexVersionFromApiLevel();
1475
+ } catch {
1476
+ return computeArtApexVersionFromApiLevel();
1477
+ }
1478
+ }
1479
+
1480
+ function computeArtApexVersionFromApiLevel () {
1481
+ return getAndroidApiLevel() * 10_000_000;
1482
+ }
1483
+
1367
1484
  let systemPropertyGet = null;
1368
1485
  const PROP_VALUE_MAX = 92;
1369
1486
 
@@ -1749,6 +1866,31 @@ set_replacement_method (gpointer original_method,
1749
1866
  g_mutex_unlock (&lock);
1750
1867
  }
1751
1868
 
1869
+ void
1870
+ synchronize_replacement_methods (guint quick_code_offset,
1871
+ void * nterp_entrypoint,
1872
+ void * quick_to_interpreter_bridge)
1873
+ {
1874
+ GHashTableIter iter;
1875
+ gpointer hooked_method, replacement_method;
1876
+
1877
+ g_mutex_lock (&lock);
1878
+
1879
+ g_hash_table_iter_init (&iter, methods);
1880
+ while (g_hash_table_iter_next (&iter, &hooked_method, &replacement_method))
1881
+ {
1882
+ void ** quick_code;
1883
+
1884
+ *((uint32_t *) replacement_method) = *((uint32_t *) hooked_method);
1885
+
1886
+ quick_code = hooked_method + quick_code_offset;
1887
+ if (*quick_code == nterp_entrypoint)
1888
+ *quick_code = quick_to_interpreter_bridge;
1889
+ }
1890
+
1891
+ g_mutex_unlock (&lock);
1892
+ }
1893
+
1752
1894
  void
1753
1895
  delete_replacement_method (gpointer original_method)
1754
1896
  {
@@ -1907,6 +2049,7 @@ on_leave_gc_concurrent_copying_copying_phase (GumInvocationContext * ic)
1907
2049
  isReplacement: new NativeFunction(cm.is_replacement_method, 'bool', ['pointer'], fastOptions),
1908
2050
  get: new NativeFunction(cm.get_replacement_method, 'pointer', ['pointer'], fastOptions),
1909
2051
  set: new NativeFunction(cm.set_replacement_method, 'void', ['pointer', 'pointer'], fastOptions),
2052
+ synchronize: new NativeFunction(cm.synchronize_replacement_methods, 'void', ['uint', 'pointer', 'pointer'], fastOptions),
1910
2053
  delete: new NativeFunction(cm.delete_replacement_method, 'void', ['pointer'], fastOptions),
1911
2054
  translate: new NativeFunction(cm.translate_method, 'pointer', ['pointer'], fastOptions),
1912
2055
  findReplacementFromQuickCode: cm.find_replacement_method_from_quick_code
@@ -1940,6 +2083,8 @@ function ensureArtKnowsHowToHandleMethodInstrumentation (vm) {
1940
2083
 
1941
2084
  instrumentArtQuickEntrypoints(vm);
1942
2085
  instrumentArtMethodInvocationFromInterpreter();
2086
+ instrumentArtGarbageCollection();
2087
+ instrumentArtFixupStaticTrampolines();
1943
2088
  }
1944
2089
 
1945
2090
  function instrumentArtQuickEntrypoints (vm) {
@@ -1991,6 +2136,52 @@ function instrumentArtMethodInvocationFromInterpreter () {
1991
2136
  }
1992
2137
  }
1993
2138
 
2139
+ function instrumentArtGarbageCollection () {
2140
+ const api = getApi();
2141
+ const art = api.module;
2142
+
2143
+ const gc = art.findSymbolByName('_ZN3art2gc4Heap22CollectGarbageInternalENS0_9collector6GcTypeENS0_7GcCauseEbj');
2144
+ if (gc === null) {
2145
+ return;
2146
+ }
2147
+
2148
+ const { artNterpEntryPoint, artQuickToInterpreterBridge } = api;
2149
+ const quickCodeOffset = getArtMethodSpec(api.vm).offset.quickCode;
2150
+ Interceptor.attach(gc, {
2151
+ onLeave () {
2152
+ artController.replacedMethods.synchronize(quickCodeOffset, artNterpEntryPoint, artQuickToInterpreterBridge);
2153
+ }
2154
+ });
2155
+ }
2156
+
2157
+ function instrumentArtFixupStaticTrampolines () {
2158
+ const patterns = [
2159
+ ['_ZN3art11ClassLinker26VisiblyInitializedCallback22MarkVisiblyInitializedEPNS_6ThreadE', 'e90340f8 : ff0ff0ff'],
2160
+ ['_ZN3art11ClassLinker26VisiblyInitializedCallback29AdjustThreadVisibilityCounterEPNS_6ThreadEl', '7f0f00f9 : 1ffcffff'],
2161
+ ];
2162
+ const api = getApi();
2163
+ const art = api.module;
2164
+ for (const [name, pattern] of patterns) {
2165
+ const base = art.findSymbolByName(name);
2166
+ if (base === null) {
2167
+ continue;
2168
+ }
2169
+
2170
+ const matches = Memory.scanSync(base, 8192, pattern);
2171
+ if (matches.length === 0) {
2172
+ return;
2173
+ }
2174
+
2175
+ const { artNterpEntryPoint, artQuickToInterpreterBridge } = api;
2176
+ const quickCodeOffset = getArtMethodSpec(api.vm).offset.quickCode;
2177
+ Interceptor.attach(matches[0].address, function () {
2178
+ artController.replacedMethods.synchronize(quickCodeOffset, artNterpEntryPoint, artQuickToInterpreterBridge);
2179
+ });
2180
+
2181
+ return;
2182
+ }
2183
+ }
2184
+
1994
2185
  function ensureArtKnowsHowToHandleReplacementMethods (vm) {
1995
2186
  if (taughtArtAboutReplacementMethods) {
1996
2187
  return;
@@ -2534,7 +2725,7 @@ extern GumTlsKey current_backtrace;
2534
2725
 
2535
2726
  extern void (* perform_art_thread_state_transition) (JNIEnv * env);
2536
2727
 
2537
- extern ArtContext * art_thread_get_long_jump_context (ArtThread * thread);
2728
+ extern ArtContext * art_make_context (ArtThread * thread);
2538
2729
 
2539
2730
  extern void art_stack_visitor_init (ArtStackVisitor * visitor, ArtThread * thread, void * context, StackWalkKind walk_kind,
2540
2731
  size_t num_frames, bool check_suspended);
@@ -2600,7 +2791,7 @@ _on_thread_state_transition_complete (ArtThread * thread)
2600
2791
  },
2601
2792
  };
2602
2793
 
2603
- context = art_thread_get_long_jump_context (thread);
2794
+ context = art_make_context (thread);
2604
2795
 
2605
2796
  art_stack_visitor_init (&visitor, thread, context, STACK_WALK_SKIP_INLINED_FRAMES, 0, true);
2606
2797
  visitor.vtable = &visitor.vtable_storage;
@@ -2885,7 +3076,7 @@ std_string_get_data (StdString * str)
2885
3076
  `, {
2886
3077
  current_backtrace: Memory.alloc(Process.pointerSize),
2887
3078
  perform_art_thread_state_transition: performImpl,
2888
- art_thread_get_long_jump_context: api['art::Thread::GetLongJumpContext'],
3079
+ art_make_context: api['art::Thread::GetLongJumpContext'] ?? api['art::Context::Create'],
2889
3080
  art_stack_visitor_init: api['art::StackVisitor::StackVisitor'],
2890
3081
  art_stack_visitor_walk_stack: api['art::StackVisitor::WalkStack'],
2891
3082
  art_stack_visitor_get_method: api['art::StackVisitor::GetMethod'],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frida-java-bridge",
3
- "version": "7.0.8",
3
+ "version": "7.0.10",
4
4
  "description": "Java runtime interop from Frida",
5
5
  "keywords": [
6
6
  "frida-gum",