frida-java-bridge 7.0.7 → 7.0.9

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) {
@@ -312,6 +314,7 @@ function _getApi () {
312
314
 
313
315
  // Android >= 11
314
316
  _ZN3art3jni12JniIdManager14DecodeMethodIdEP10_jmethodID: ['art::jni::JniIdManager::DecodeMethodId', 'pointer', ['pointer', 'pointer']],
317
+ _ZN3art3jni12JniIdManager13DecodeFieldIdEP9_jfieldID: ['art::jni::JniIdManager::DecodeFieldId', 'pointer', ['pointer', 'pointer']],
315
318
  _ZN3art11interpreter18GetNterpEntryPointEv: ['art::interpreter::GetNterpEntryPoint', 'pointer', []],
316
319
 
317
320
  _ZN3art7Monitor17TranslateLocationEPNS_9ArtMethodEjPPKcPi: ['art::Monitor::TranslateLocation', 'void', ['pointer', 'uint32', 'pointer', 'pointer']]
@@ -351,6 +354,7 @@ function _getApi () {
351
354
  '_ZNK3art12StackVisitor9GetMethodEv',
352
355
  '_ZNK3art12StackVisitor16DescribeLocationEv',
353
356
  '_ZNK3art12StackVisitor24GetCurrentQuickFrameInfoEv',
357
+ '_ZN3art7Context6CreateEv',
354
358
  '_ZN3art6Thread18GetLongJumpContextEv',
355
359
  '_ZN3art6mirror5Class13GetDescriptorEPNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE',
356
360
  '_ZN3art6mirror5Class11GetLocationEv',
@@ -370,6 +374,7 @@ function _getApi () {
370
374
  '_ZN3art3Dbg20ManageDeoptimizationEv',
371
375
  '_ZN3art3Dbg9gRegistryE',
372
376
  '_ZN3art3jni12JniIdManager14DecodeMethodIdEP10_jmethodID',
377
+ '_ZN3art3jni12JniIdManager13DecodeFieldIdEP9_jfieldID',
373
378
  '_ZN3art11interpreter18GetNterpEntryPointEv',
374
379
  '_ZN3art7Monitor17TranslateLocationEPNS_9ArtMethodEjPPKcPi'
375
380
  ])
@@ -459,6 +464,11 @@ function _getApi () {
459
464
  const instrumentationOffset = runtimeOffset.instrumentation;
460
465
  temporaryApi.artInstrumentation = (instrumentationOffset !== null) ? artRuntime.add(instrumentationOffset) : null;
461
466
 
467
+ const instrumentationIsPointer = getArtApexVersion() >= 360_000_000;
468
+ if (instrumentationIsPointer && temporaryApi.artInstrumentation != null) {
469
+ temporaryApi.artInstrumentation = temporaryApi.artInstrumentation.readPointer();
470
+ }
471
+
462
472
  temporaryApi.artHeap = artRuntime.add(runtimeOffset.heap).readPointer();
463
473
  temporaryApi.artThreadList = artRuntime.add(runtimeOffset.threadList).readPointer();
464
474
 
@@ -689,7 +699,11 @@ function _getArtRuntimeSpec (api) {
689
699
  throw new Error('Unable to determine Runtime field offsets');
690
700
  }
691
701
 
692
- spec.offset.instrumentation = tryDetectInstrumentationOffset(api);
702
+ const instrumentationIsPointer = getArtApexVersion() >= 360_000_000;
703
+ spec.offset.instrumentation = instrumentationIsPointer
704
+ ? tryDetectInstrumentationPointer(api)
705
+ : tryDetectInstrumentationOffset(api);
706
+
693
707
  spec.offset.jniIdsIndirection = tryDetectJniIdsIndirectionOffset(api);
694
708
 
695
709
  return spec;
@@ -769,6 +783,78 @@ function parseArm64InstrumentationOffset (insn) {
769
783
  return offset;
770
784
  }
771
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
+
772
858
  const jniIdsIndirectionOffsetParsers = {
773
859
  ia32: parsex86JniIdsIndirectionOffset,
774
860
  x64: parsex86JniIdsIndirectionOffset,
@@ -1024,8 +1110,8 @@ export function getArtClassSpec (vm) {
1024
1110
  object = getApi()['art::JavaVMExt::DecodeGlobal'](vm, thread, clazzRef);
1025
1111
  });
1026
1112
 
1027
- const fieldInstance = env.getFieldId(clazzRef, 'name', 'Ljava/lang/String;');
1028
- const fieldStatic = env.getStaticFieldId(clazzRef, 'MAX_PRIORITY', 'I');
1113
+ const fieldInstance = unwrapFieldId(env.getFieldId(clazzRef, 'name', 'Ljava/lang/String;'));
1114
+ const fieldStatic = unwrapFieldId(env.getStaticFieldId(clazzRef, 'MAX_PRIORITY', 'I'));
1029
1115
 
1030
1116
  let offsetStatic = -1;
1031
1117
  let offsetInstance = -1;
@@ -1044,7 +1130,7 @@ export function getArtClassSpec (vm) {
1044
1130
  const ifieldOffset = offsetInstance;
1045
1131
 
1046
1132
  let offsetMethods = -1;
1047
- const methodInstance = env.getMethodId(clazzRef, 'getName', '()Ljava/lang/String;');
1133
+ const methodInstance = unwrapMethodId(env.getMethodId(clazzRef, 'getName', '()Ljava/lang/String;'));
1048
1134
  for (let offset = 0; offset !== MAX_OFFSET; offset += 4) {
1049
1135
  if (offsetMethods === -1 && hasEntry(object, offset, methodInstance, mInfo)) {
1050
1136
  offsetMethods = offset;
@@ -1362,6 +1448,39 @@ function _getAndroidApiLevel () {
1362
1448
  return parseInt(getAndroidSystemProperty('ro.build.version.sdk'), 10);
1363
1449
  }
1364
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
+
1365
1484
  let systemPropertyGet = null;
1366
1485
  const PROP_VALUE_MAX = 92;
1367
1486
 
@@ -2532,7 +2651,7 @@ extern GumTlsKey current_backtrace;
2532
2651
 
2533
2652
  extern void (* perform_art_thread_state_transition) (JNIEnv * env);
2534
2653
 
2535
- extern ArtContext * art_thread_get_long_jump_context (ArtThread * thread);
2654
+ extern ArtContext * art_make_context (ArtThread * thread);
2536
2655
 
2537
2656
  extern void art_stack_visitor_init (ArtStackVisitor * visitor, ArtThread * thread, void * context, StackWalkKind walk_kind,
2538
2657
  size_t num_frames, bool check_suspended);
@@ -2598,7 +2717,7 @@ _on_thread_state_transition_complete (ArtThread * thread)
2598
2717
  },
2599
2718
  };
2600
2719
 
2601
- context = art_thread_get_long_jump_context (thread);
2720
+ context = art_make_context (thread);
2602
2721
 
2603
2722
  art_stack_visitor_init (&visitor, thread, context, STACK_WALK_SKIP_INLINED_FRAMES, 0, true);
2604
2723
  visitor.vtable = &visitor.vtable_storage;
@@ -2883,7 +3002,7 @@ std_string_get_data (StdString * str)
2883
3002
  `, {
2884
3003
  current_backtrace: Memory.alloc(Process.pointerSize),
2885
3004
  perform_art_thread_state_transition: performImpl,
2886
- art_thread_get_long_jump_context: api['art::Thread::GetLongJumpContext'],
3005
+ art_make_context: api['art::Thread::GetLongJumpContext'] ?? api['art::Context::Create'],
2887
3006
  art_stack_visitor_init: api['art::StackVisitor::StackVisitor'],
2888
3007
  art_stack_visitor_walk_stack: api['art::StackVisitor::WalkStack'],
2889
3008
  art_stack_visitor_get_method: api['art::StackVisitor::GetMethod'],
@@ -2959,6 +3078,14 @@ export function revertGlobalPatches () {
2959
3078
  }
2960
3079
 
2961
3080
  function unwrapMethodId (methodId) {
3081
+ return unwrapGenericId(methodId, 'art::jni::JniIdManager::DecodeMethodId');
3082
+ }
3083
+
3084
+ function unwrapFieldId (fieldId) {
3085
+ return unwrapGenericId(fieldId, 'art::jni::JniIdManager::DecodeFieldId');
3086
+ }
3087
+
3088
+ function unwrapGenericId (genericId, apiMethod) {
2962
3089
  const api = getApi();
2963
3090
 
2964
3091
  const runtimeOffset = getArtRuntimeSpec(api).offset;
@@ -2972,11 +3099,11 @@ function unwrapMethodId (methodId) {
2972
3099
 
2973
3100
  if (jniIdsIndirection !== kPointer) {
2974
3101
  const jniIdManager = runtime.add(jniIdManagerOffset).readPointer();
2975
- return api['art::jni::JniIdManager::DecodeMethodId'](jniIdManager, methodId);
3102
+ return api[apiMethod](jniIdManager, genericId);
2976
3103
  }
2977
3104
  }
2978
3105
 
2979
- return methodId;
3106
+ return genericId;
2980
3107
  }
2981
3108
 
2982
3109
  const artQuickCodeReplacementTrampolineWriters = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frida-java-bridge",
3
- "version": "7.0.7",
3
+ "version": "7.0.9",
4
4
  "description": "Java runtime interop from Frida",
5
5
  "keywords": [
6
6
  "frida-gum",