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 +21 -7
- package/lib/android.js +136 -9
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -415,11 +415,25 @@ declare module "frida-java-bridge" {
|
|
|
415
415
|
[name: string]: any;
|
|
416
416
|
};
|
|
417
417
|
|
|
418
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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 *
|
|
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 =
|
|
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
|
-
|
|
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[
|
|
3102
|
+
return api[apiMethod](jniIdManager, genericId);
|
|
2976
3103
|
}
|
|
2977
3104
|
}
|
|
2978
3105
|
|
|
2979
|
-
return
|
|
3106
|
+
return genericId;
|
|
2980
3107
|
}
|
|
2981
3108
|
|
|
2982
3109
|
const artQuickCodeReplacementTrampolineWriters = {
|