frida-java-bridge 6.1.0 → 6.1.1

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.js CHANGED
@@ -233,7 +233,7 @@ class Runtime {
233
233
 
234
234
  const visitClassLoaders = api['art::ClassLinker::VisitClassLoaders'];
235
235
  if (visitClassLoaders === undefined) {
236
- throw new Error('This API is only available on Nougat and above');
236
+ throw new Error('This API is only available on Android >= 7.0');
237
237
  }
238
238
 
239
239
  const ClassLoader = factory.use('java.lang.ClassLoader');
package/lib/android.js CHANGED
@@ -4,6 +4,7 @@ const {
4
4
  jvmtiCapabilities,
5
5
  EnvJvmti
6
6
  } = require('./jvmti');
7
+ const { parseInstructionsAt } = require('./machine-code');
7
8
  const memoize = require('./memoize');
8
9
  const { checkJniResult, JNI_OK } = require('./result');
9
10
  const VM = require('./vm');
@@ -661,25 +662,12 @@ const instrumentationOffsetParsers = {
661
662
  };
662
663
 
663
664
  function tryDetectInstrumentationOffset (api) {
664
- let cur = api['art::Runtime::DeoptimizeBootImage'];
665
- if (cur === undefined) {
665
+ const impl = api['art::Runtime::DeoptimizeBootImage'];
666
+ if (impl === undefined) {
666
667
  return null;
667
668
  }
668
669
 
669
- const tryParse = instrumentationOffsetParsers[Process.arch];
670
-
671
- for (let i = 0; i !== 30; i++) {
672
- const insn = Instruction.parse(cur);
673
-
674
- const offset = tryParse(insn);
675
- if (offset !== null) {
676
- return offset;
677
- }
678
-
679
- cur = insn.next;
680
- }
681
-
682
- return null;
670
+ return parseInstructionsAt(impl, instrumentationOffsetParsers[Process.arch], { limit: 30 });
683
671
  }
684
672
 
685
673
  function parsex86InstrumentationOffset (insn) {
@@ -748,27 +736,17 @@ const jniIdsIndirectionOffsetParsers = {
748
736
  };
749
737
 
750
738
  function tryDetectJniIdsIndirectionOffset () {
751
- let cur = Module.findExportByName('libart.so', '_ZN3art7Runtime12SetJniIdTypeENS_9JniIdTypeE');
752
- if (cur === null) {
739
+ const impl = Module.findExportByName('libart.so', '_ZN3art7Runtime12SetJniIdTypeENS_9JniIdTypeE');
740
+ if (impl === null) {
753
741
  return null;
754
742
  }
755
743
 
756
- const tryParse = jniIdsIndirectionOffsetParsers[Process.arch];
757
-
758
- let prevInsn = null;
759
- for (let i = 0; i !== 20; i++) {
760
- const insn = Instruction.parse(cur);
761
-
762
- const offset = tryParse(insn, prevInsn);
763
- if (offset !== null) {
764
- return offset;
765
- }
766
-
767
- cur = insn.next;
768
- prevInsn = insn;
744
+ const offset = parseInstructionsAt(impl, jniIdsIndirectionOffsetParsers[Process.arch], { limit: 20 });
745
+ if (offset === null) {
746
+ throw new Error('Unable to determine Runtime.jni_ids_indirection_ offset');
769
747
  }
770
748
 
771
- throw new Error('Unable to determine Runtime.jni_ids_indirection_ offset');
749
+ return offset;
772
750
  }
773
751
 
774
752
  function parsex86JniIdsIndirectionOffset (insn) {
@@ -1979,31 +1957,29 @@ function validateGetOatQuickMethodHeaderInlinedMatchArm ({ address, size }) {
1979
1957
  targetWhenRuntimeMethod = targetWhenFalse;
1980
1958
  }
1981
1959
 
1982
- let cursor = targetWhenRegularMethod.or(1);
1983
- for (let i = 0; i !== 3; i++) {
1984
- const insn = Instruction.parse(cursor);
1985
- cursor = insn.next;
1960
+ return parseInstructionsAt(targetWhenRegularMethod.or(1), tryParse, { limit: 3 });
1986
1961
 
1962
+ function tryParse (insn) {
1987
1963
  const { mnemonic } = insn;
1988
1964
  if (!(mnemonic === 'ldr' || mnemonic === 'ldr.w')) {
1989
- continue;
1965
+ return null;
1990
1966
  }
1991
1967
 
1992
1968
  const { base, disp } = insn.operands[1].value;
1993
- if (base === methodReg && disp === 0x14) {
1994
- return {
1995
- methodReg,
1996
- scratchReg,
1997
- target: {
1998
- whenTrue: targetWhenTrue,
1999
- whenRegularMethod: targetWhenRegularMethod,
2000
- whenRuntimeMethod: targetWhenRuntimeMethod
2001
- }
2002
- };
1969
+ if (!(base === methodReg && disp === 0x14)) {
1970
+ return null;
2003
1971
  }
2004
- }
2005
1972
 
2006
- return null;
1973
+ return {
1974
+ methodReg,
1975
+ scratchReg,
1976
+ target: {
1977
+ whenTrue: targetWhenTrue,
1978
+ whenRegularMethod: targetWhenRegularMethod,
1979
+ whenRuntimeMethod: targetWhenRuntimeMethod
1980
+ }
1981
+ };
1982
+ }
2007
1983
  }
2008
1984
 
2009
1985
  function validateGetOatQuickMethodHeaderInlinedMatchArm64 ({ address, size }) {
@@ -2024,30 +2000,28 @@ function validateGetOatQuickMethodHeaderInlinedMatchArm64 ({ address, size }) {
2024
2000
  targetWhenRuntimeMethod = targetWhenFalse;
2025
2001
  }
2026
2002
 
2027
- let cursor = targetWhenRegularMethod;
2028
- for (let i = 0; i !== 3; i++) {
2029
- const insn = Instruction.parse(cursor);
2030
- cursor = insn.next;
2003
+ return parseInstructionsAt(targetWhenRegularMethod, tryParse, { limit: 3 });
2031
2004
 
2005
+ function tryParse (insn) {
2032
2006
  if (insn.mnemonic !== 'ldr') {
2033
- continue;
2007
+ return null;
2034
2008
  }
2035
2009
 
2036
2010
  const { base, disp } = insn.operands[1].value;
2037
- if (base === methodReg && disp === 0x18) {
2038
- return {
2039
- methodReg,
2040
- scratchReg,
2041
- target: {
2042
- whenTrue: targetWhenTrue,
2043
- whenRegularMethod: targetWhenRegularMethod,
2044
- whenRuntimeMethod: targetWhenRuntimeMethod
2045
- }
2046
- };
2011
+ if (!(base === methodReg && disp === 0x18)) {
2012
+ return null;
2047
2013
  }
2048
- }
2049
2014
 
2050
- return null;
2015
+ return {
2016
+ methodReg,
2017
+ scratchReg,
2018
+ target: {
2019
+ whenTrue: targetWhenTrue,
2020
+ whenRegularMethod: targetWhenRegularMethod,
2021
+ whenRuntimeMethod: targetWhenRuntimeMethod
2022
+ }
2023
+ };
2024
+ }
2051
2025
  }
2052
2026
 
2053
2027
  function maybeInstrumentGetOatQuickMethodHeaderInlineCopies () {
@@ -3559,6 +3533,10 @@ function deoptimizeEverything (vm, env) {
3559
3533
  function deoptimizeBootImage (vm, env) {
3560
3534
  const api = getApi();
3561
3535
 
3536
+ if (getAndroidApiLevel() < 26) {
3537
+ throw new Error('This API is only available on Android >= 8.0');
3538
+ }
3539
+
3562
3540
  withRunnableArtThread(vm, env, thread => {
3563
3541
  api['art::Runtime::DeoptimizeBootImage'](api.artRuntime);
3564
3542
  });
@@ -3568,7 +3546,7 @@ function requestDeoptimization (vm, env, kind, method) {
3568
3546
  const api = getApi();
3569
3547
 
3570
3548
  if (getAndroidApiLevel() < 24) {
3571
- throw new Error('This API is only available on Nougat and above');
3549
+ throw new Error('This API is only available on Android >= 7.0');
3572
3550
  }
3573
3551
 
3574
3552
  withRunnableArtThread(vm, env, thread => {
package/lib/jvm.js CHANGED
@@ -3,6 +3,7 @@ const {
3
3
  jvmtiCapabilities,
4
4
  EnvJvmti
5
5
  } = require('./jvmti');
6
+ const { parseInstructionsAt } = require('./machine-code');
6
7
  const memoize = require('./memoize');
7
8
  const { checkJniResult } = require('./result');
8
9
  const VM = require('./vm');
@@ -22,6 +23,7 @@ const nativeFunctionOptions = {
22
23
  };
23
24
 
24
25
  const getJvmMethodSpec = memoize(_getJvmMethodSpec);
26
+ const getJvmInstanceKlassSpec = memoize(_getJvmInstanceKlassSpec);
25
27
  const getJvmThreadSpec = memoize(_getJvmThreadSpec);
26
28
 
27
29
  let cachedApi = null;
@@ -57,6 +59,9 @@ function _getApi () {
57
59
  _ZN6Method4sizeEb: ['Method::size', 'int', ['int']],
58
60
  _ZN6Method19set_native_functionEPhb: ['Method::set_native_function', 'void', ['pointer', 'pointer', 'int']],
59
61
  _ZN6Method21clear_native_functionEv: ['Method::clear_native_function', 'void', ['pointer']],
62
+ // JDK >= 17
63
+ _ZN6Method24restore_unshareable_infoEP10JavaThread: ['Method::restore_unshareable_info', 'void', ['pointer', 'pointer']],
64
+ // JDK < 17
60
65
  _ZN6Method24restore_unshareable_infoEP6Thread: ['Method::restore_unshareable_info', 'void', ['pointer', 'pointer']],
61
66
  _ZN6Method10jmethod_idEv: ['Method::jmethod_id', 'pointer', ['pointer']],
62
67
  _ZN6Method10clear_codeEv: function (address) {
@@ -73,8 +78,6 @@ function _getApi () {
73
78
  };
74
79
  },
75
80
 
76
- _ZNK5Klass15start_of_vtableEv: ['Klass::start_of_vtable', 'pointer', ['pointer']],
77
- _ZNK13InstanceKlass6vtableEv: ['InstanceKlass::vtable', 'pointer', ['pointer']],
78
81
  // JDK >= 13
79
82
  _ZN18VM_RedefineClasses19mark_dependent_codeEP13InstanceKlass: ['VM_RedefineClasses::mark_dependent_code', 'void', ['pointer', 'pointer']],
80
83
  _ZN18VM_RedefineClasses20flush_dependent_codeEv: ['VM_RedefineClasses::flush_dependent_code', 'void', []],
@@ -157,6 +160,16 @@ function _getApi () {
157
160
  _ZNK18VM_RedefineClasses14print_on_errorEP12outputStream: function (address) {
158
161
  this.redefineClassesOnError = address;
159
162
  },
163
+
164
+ // JDK >= 17
165
+ _ZN13InstanceKlass33create_new_default_vtable_indicesEiP10JavaThread: function (address) {
166
+ this.createNewDefaultVtableIndices = address;
167
+ },
168
+ // JDK < 17
169
+ _ZN13InstanceKlass33create_new_default_vtable_indicesEiP6Thread: function (address) {
170
+ this.createNewDefaultVtableIndices = address;
171
+ },
172
+
160
173
  _ZN19Abstract_VM_Version19jre_release_versionEv: function (address) {
161
174
  const getVersion = new NativeFunction(address, 'pointer', [], nativeFunctionOptions);
162
175
  const versionS = getVersion().readCString();
@@ -167,6 +180,7 @@ function _getApi () {
167
180
  : parseInt(versionS.slice(0, 2), 10);
168
181
  this.versionS = versionS;
169
182
  },
183
+
170
184
  _ZN14NMethodSweeper11_traversalsE: function (address) {
171
185
  this.traversals = address;
172
186
  },
@@ -178,36 +192,41 @@ function _getApi () {
178
192
  }
179
193
  },
180
194
  optionals: [
195
+ '_ZN6Method24restore_unshareable_infoEP10JavaThread',
196
+ '_ZN6Method24restore_unshareable_infoEP6Thread',
197
+ '_ZN6Method10clear_codeEv',
198
+ '_ZN6Method10clear_codeEb',
199
+
181
200
  '_ZN18VM_RedefineClasses19mark_dependent_codeEP13InstanceKlass',
182
201
  '_ZN18VM_RedefineClasses20flush_dependent_codeEv',
183
202
  '_ZN18VM_RedefineClasses20flush_dependent_codeEP13InstanceKlassP6Thread',
184
203
  '_ZN18VM_RedefineClasses20flush_dependent_codeE19instanceKlassHandleP6Thread',
185
204
 
186
- '_ZNK5Klass15start_of_vtableEv',
187
- '_ZNK13InstanceKlass6vtableEv',
188
-
189
205
  '_ZN19ResolvedMethodTable21adjust_method_entriesEPb',
190
206
  '_ZN15MemberNameTable21adjust_method_entriesEP13InstanceKlassPb',
191
207
 
192
208
  '_ZN17ConstantPoolCache21adjust_method_entriesEPb',
193
209
  '_ZN17ConstantPoolCache21adjust_method_entriesEP13InstanceKlassPb',
194
210
 
211
+ '_ZN20ClassLoaderDataGraph22clean_deallocate_listsEb',
212
+
213
+ '_ZN10JavaThread27thread_from_jni_environmentEP7JNIEnv_',
214
+
215
+ '_ZN14NMethodSweeper11force_sweepEv',
216
+ '_ZN14NMethodSweeper17sweep_in_progressEv',
217
+
195
218
  '_ZN18VM_RedefineClasses14_the_class_oopE',
196
219
  '_ZN18VM_RedefineClasses10_the_classE',
197
220
  '_ZN18VM_RedefineClasses25AdjustCpoolCacheAndVtable8do_klassEP5Klass',
198
221
  '_ZN18VM_RedefineClasses22AdjustAndCleanMetadata8do_klassEP5Klass',
199
-
200
222
  '_ZN18VM_RedefineClassesD0Ev',
201
223
  '_ZN18VM_RedefineClassesD1Ev',
202
224
  '_ZNK18VM_RedefineClasses14print_on_errorEP12outputStream',
203
225
 
204
- '_ZN6Method10clear_codeEv',
205
- '_ZN6Method10clear_codeEb',
226
+ '_ZN13InstanceKlass33create_new_default_vtable_indicesEiP10JavaThread',
227
+ '_ZN13InstanceKlass33create_new_default_vtable_indicesEiP6Thread',
206
228
 
207
- '_ZN20ClassLoaderDataGraph22clean_deallocate_listsEb',
208
- '_ZN14NMethodSweeper11force_sweepEv',
209
- '_ZN14NMethodSweeper21_sweep_fractions_leftE',
210
- '_ZN14NMethodSweeper17sweep_in_progressEv'
229
+ '_ZN14NMethodSweeper21_sweep_fractions_leftE'
211
230
  ]
212
231
  }];
213
232
 
@@ -292,6 +311,10 @@ function _getApi () {
292
311
 
293
312
  temporaryApi.jvmti = getEnvJvmti(temporaryApi);
294
313
 
314
+ if (temporaryApi['JavaThread::thread_from_jni_environment'] === undefined) {
315
+ temporaryApi['JavaThread::thread_from_jni_environment'] = makeThreadFromJniHelper(temporaryApi);
316
+ }
317
+
295
318
  return temporaryApi;
296
319
  }
297
320
 
@@ -315,6 +338,44 @@ function getEnvJvmti (api) {
315
338
  return env;
316
339
  }
317
340
 
341
+ const threadOffsetParsers = {
342
+ x64: parseX64ThreadOffset
343
+ };
344
+
345
+ function makeThreadFromJniHelper (api) {
346
+ let offset = null;
347
+
348
+ const tryParse = threadOffsetParsers[Process.arch];
349
+ if (tryParse !== undefined) {
350
+ const vm = new VM(api);
351
+ const findClassImpl = vm.perform(env => env.handle.readPointer().add(6 * pointerSize).readPointer());
352
+ offset = parseInstructionsAt(findClassImpl, tryParse, { limit: 10 });
353
+ }
354
+
355
+ if (offset === null) {
356
+ return () => {
357
+ throw new Error('Unable to make thread_from_jni_environment() helper for the current architecture');
358
+ };
359
+ }
360
+
361
+ return env => {
362
+ return env.add(offset);
363
+ };
364
+ }
365
+
366
+ function parseX64ThreadOffset (insn) {
367
+ if (insn.mnemonic !== 'lea') {
368
+ return null;
369
+ }
370
+
371
+ const { base, disp } = insn.operands[1].value;
372
+ if (!(base === 'rdi' && disp < 0)) {
373
+ return null;
374
+ }
375
+
376
+ return disp;
377
+ }
378
+
318
379
  function ensureClassInitialized (env, classRef) {
319
380
  }
320
381
 
@@ -489,13 +550,15 @@ function withJvmThread (fn, fnPrologue, fnEpilogue) {
489
550
  const doIt = new NativeCallback(fn, 'void', ['pointer']);
490
551
  vtableDup.add(doItOffset).writePointer(doIt);
491
552
 
553
+ let prologue = null;
492
554
  if (fnPrologue !== undefined) {
493
- const prologue = new NativeCallback(fnPrologue, 'int', ['pointer']);
555
+ prologue = new NativeCallback(fnPrologue, 'int', ['pointer']);
494
556
  vtableDup.add(prologueOffset).writePointer(prologue);
495
557
  }
496
558
 
559
+ let epilogue = null;
497
560
  if (fnEpilogue !== undefined) {
498
- const epilogue = new NativeCallback(fnEpilogue, 'void', ['pointer']);
561
+ epilogue = new NativeCallback(fnEpilogue, 'void', ['pointer']);
499
562
  vtableDup.add(epilogueOffset).writePointer(epilogue);
500
563
  }
501
564
 
@@ -686,24 +749,19 @@ function readJvmMethod (method, constMethod, constMethodSize) {
686
749
  const instanceKlass = constantPool.add(spec.constantPool.instanceKlassOffset).readPointer();
687
750
  const cache = constantPool.add(spec.constantPool.cacheOffset).readPointer();
688
751
 
689
- if (spec.instanceKlass === undefined) {
690
- const klassVtable = api['InstanceKlass::vtable'](instanceKlass);
691
- const vtableOffset = klassVtable.add(pointerSize).readS32();
692
- const klassSpec = getJvmKlassSpec(vtableOffset);
693
- spec.instanceKlass = klassSpec;
694
- }
752
+ const instanceKlassSpec = getJvmInstanceKlassSpec();
695
753
 
696
- const methods = instanceKlass.add(spec.instanceKlass.methodsOffset).readPointer();
754
+ const methods = instanceKlass.add(instanceKlassSpec.methodsOffset).readPointer();
697
755
  const methodsCount = methods.readS32();
698
756
  const methodsArray = methods.add(pointerSize);
699
757
  const methodIndex = constMethod.add(spec.constMethod.methodIdnumOffset).readU16();
700
758
  const vtableIndexPtr = method.add(spec.method.vtableIndexOffset);
701
759
  const vtableIndex = vtableIndexPtr.readS32();
702
- const vtable = instanceKlass.add(spec.instanceKlass.vtableOffset);
703
- const oopMapCache = instanceKlass.add(spec.instanceKlass.oopMapCacheOffset).readPointer();
760
+ const vtable = instanceKlass.add(instanceKlassSpec.vtableOffset);
761
+ const oopMapCache = instanceKlass.add(instanceKlassSpec.oopMapCacheOffset).readPointer();
704
762
 
705
763
  const memberNames = (api.version >= 10)
706
- ? instanceKlass.add(spec.instanceKlass.memberNamesOffset).readPointer()
764
+ ? instanceKlass.add(instanceKlassSpec.memberNamesOffset).readPointer()
707
765
  : NULL;
708
766
 
709
767
  return {
@@ -741,39 +799,48 @@ function revertJvmMethod (method) {
741
799
 
742
800
  function _getJvmMethodSpec () {
743
801
  const api = getApi();
802
+ const { version } = api;
744
803
 
745
- const adapterInConstMethod = (api.version > 8) ? 1 : 0;
804
+ let adapterHandlerLocation;
805
+ if (version >= 17) {
806
+ adapterHandlerLocation = 'method:early';
807
+ } else if (version >= 9 && version <= 16) {
808
+ adapterHandlerLocation = 'const-method';
809
+ } else {
810
+ adapterHandlerLocation = 'method:late';
811
+ }
746
812
 
747
813
  const isNative = 1;
748
814
  const methodSize = api['Method::size'](isNative) * pointerSize;
749
815
  const constMethodOffset = pointerSize;
750
816
  const methodDataOffset = 2 * pointerSize;
751
817
  const methodCountersOffset = 3 * pointerSize;
752
- const accessFlagsOffset = 4 * pointerSize;
818
+ const adapterInMethodEarlyOffset = 4 * pointerSize;
819
+ const adapterInMethodEarlySize = (adapterHandlerLocation === 'method:early') ? pointerSize : 0;
820
+ const accessFlagsOffset = adapterInMethodEarlyOffset + adapterInMethodEarlySize;
753
821
  const vtableIndexOffset = accessFlagsOffset + 4;
754
- const i2iEntryOffset = vtableIndexOffset + 4 + pointerSize;
822
+ const i2iEntryOffset = vtableIndexOffset + 4 + 8;
823
+ const adapterInMethodLateOffset = i2iEntryOffset + pointerSize;
824
+ const adapterInMethodOffset = (adapterInMethodEarlySize !== 0) ? adapterInMethodEarlyOffset : adapterInMethodLateOffset;
755
825
  const nativeFunctionOffset = methodSize - 2 * pointerSize;
756
826
  const signatureHandlerOffset = methodSize - pointerSize;
757
827
 
758
- const constantPoolOffset = pointerSize;
759
- const stackmapDataOffset = 2 * pointerSize;
760
- const constMethodSizeOffset = (3 + adapterInConstMethod) * pointerSize;
828
+ const constantPoolOffset = 8;
829
+ const stackmapDataOffset = constantPoolOffset + pointerSize;
830
+ const adapterInConstMethodOffset = stackmapDataOffset + pointerSize;
831
+ const adapterInConstMethodSize = (adapterHandlerLocation === 'const-method') ? pointerSize : 0;
832
+ const constMethodSizeOffset = adapterInConstMethodOffset + adapterInConstMethodSize;
761
833
  const methodIdnumOffset = constMethodSizeOffset + 0xe;
762
834
 
763
835
  const cacheOffset = 2 * pointerSize;
764
836
  const instanceKlassOffset = 3 * pointerSize;
765
- let klassSpec;
766
- if ('Klass::start_of_vtable' in api) {
767
- const vtableOffset = api['Klass::start_of_vtable'](NULL).toInt32();
768
- klassSpec = getJvmKlassSpec(vtableOffset);
769
- }
770
837
 
771
- const getAdapterPointer = adapterInConstMethod
838
+ const getAdapterPointer = (adapterInConstMethodSize !== 0)
772
839
  ? function (method, constMethod) {
773
- return constMethod.add(constantPoolOffset + 2 * pointerSize);
840
+ return constMethod.add(adapterInConstMethodOffset);
774
841
  }
775
842
  : function (method, constMethod) {
776
- return method.add(i2iEntryOffset + pointerSize);
843
+ return method.add(adapterInMethodOffset);
777
844
  };
778
845
 
779
846
  return {
@@ -798,15 +865,28 @@ function _getJvmMethodSpec () {
798
865
  constantPool: {
799
866
  cacheOffset,
800
867
  instanceKlassOffset
801
- },
802
- instanceKlass: klassSpec
868
+ }
803
869
  };
804
870
  }
805
871
 
806
- function getJvmKlassSpec (vtableOffset) {
807
- const { version: jvmVersion } = getApi();
872
+ const vtableOffsetParsers = {
873
+ x64: parseX64VTableOffset
874
+ };
875
+
876
+ function _getJvmInstanceKlassSpec () {
877
+ const { version: jvmVersion, createNewDefaultVtableIndices } = getApi();
878
+
879
+ const tryParse = vtableOffsetParsers[Process.arch];
880
+ if (tryParse === undefined) {
881
+ throw new Error(`Missing vtable offset parser for ${Process.arch}`);
882
+ }
808
883
 
809
- const oopMultiplier = (jvmVersion >= 10 && jvmVersion <= 11) ? 17 : 18;
884
+ const vtableOffset = parseInstructionsAt(createNewDefaultVtableIndices, tryParse, { limit: 32 });
885
+ if (vtableOffset === null) {
886
+ throw new Error('Unable to deduce vtable offset');
887
+ }
888
+
889
+ const oopMultiplier = ((jvmVersion >= 10 && jvmVersion <= 11) || jvmVersion >= 15) ? 17 : 18;
810
890
 
811
891
  const methodsOffset = vtableOffset - (7 * pointerSize);
812
892
  const memberNamesOffset = vtableOffset - (17 * pointerSize);
@@ -820,6 +900,31 @@ function getJvmKlassSpec (vtableOffset) {
820
900
  };
821
901
  }
822
902
 
903
+ function parseX64VTableOffset (insn) {
904
+ if (insn.mnemonic !== 'mov') {
905
+ return null;
906
+ }
907
+
908
+ const dst = insn.operands[0];
909
+ if (dst.type !== 'mem') {
910
+ return null;
911
+ }
912
+
913
+ const { value: dstValue } = dst;
914
+ if (dstValue.scale !== 1) {
915
+ return null;
916
+ }
917
+
918
+ const { disp } = dstValue;
919
+ if (disp < 0x100) {
920
+ return null;
921
+ }
922
+
923
+ const defaultVtableIndicesOffset = disp;
924
+
925
+ return defaultVtableIndicesOffset + 16;
926
+ }
927
+
823
928
  function deoptimizeEverything (vm, env) {
824
929
  }
825
930
 
@@ -0,0 +1,22 @@
1
+ function parseInstructionsAt (address, tryParse, { limit }) {
2
+ let cursor = address;
3
+ let prevInsn = null;
4
+
5
+ for (let i = 0; i !== limit; i++) {
6
+ const insn = Instruction.parse(cursor);
7
+
8
+ const value = tryParse(insn, prevInsn);
9
+ if (value !== null) {
10
+ return value;
11
+ }
12
+
13
+ cursor = insn.next;
14
+ prevInsn = insn;
15
+ }
16
+
17
+ return null;
18
+ }
19
+
20
+ module.exports = {
21
+ parseInstructionsAt
22
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frida-java-bridge",
3
- "version": "6.1.0",
3
+ "version": "6.1.1",
4
4
  "description": "Java runtime interop from Frida",
5
5
  "main": "index.js",
6
6
  "files": [