frida-java-bridge 7.0.9 → 7.0.11
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/lib/android.js +90 -2
- package/lib/class-model.js +72 -15
- package/package.json +1 -1
package/lib/android.js
CHANGED
|
@@ -586,8 +586,7 @@ export function ensureClassInitialized (env, classRef) {
|
|
|
586
586
|
return;
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
-
env.
|
|
590
|
-
env.exceptionClear();
|
|
589
|
+
env.getClassName(classRef);
|
|
591
590
|
}
|
|
592
591
|
|
|
593
592
|
function getArtVMSpec (api) {
|
|
@@ -1866,6 +1865,31 @@ set_replacement_method (gpointer original_method,
|
|
|
1866
1865
|
g_mutex_unlock (&lock);
|
|
1867
1866
|
}
|
|
1868
1867
|
|
|
1868
|
+
void
|
|
1869
|
+
synchronize_replacement_methods (guint quick_code_offset,
|
|
1870
|
+
void * nterp_entrypoint,
|
|
1871
|
+
void * quick_to_interpreter_bridge)
|
|
1872
|
+
{
|
|
1873
|
+
GHashTableIter iter;
|
|
1874
|
+
gpointer hooked_method, replacement_method;
|
|
1875
|
+
|
|
1876
|
+
g_mutex_lock (&lock);
|
|
1877
|
+
|
|
1878
|
+
g_hash_table_iter_init (&iter, methods);
|
|
1879
|
+
while (g_hash_table_iter_next (&iter, &hooked_method, &replacement_method))
|
|
1880
|
+
{
|
|
1881
|
+
void ** quick_code;
|
|
1882
|
+
|
|
1883
|
+
*((uint32_t *) replacement_method) = *((uint32_t *) hooked_method);
|
|
1884
|
+
|
|
1885
|
+
quick_code = hooked_method + quick_code_offset;
|
|
1886
|
+
if (*quick_code == nterp_entrypoint)
|
|
1887
|
+
*quick_code = quick_to_interpreter_bridge;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
g_mutex_unlock (&lock);
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1869
1893
|
void
|
|
1870
1894
|
delete_replacement_method (gpointer original_method)
|
|
1871
1895
|
{
|
|
@@ -2024,6 +2048,7 @@ on_leave_gc_concurrent_copying_copying_phase (GumInvocationContext * ic)
|
|
|
2024
2048
|
isReplacement: new NativeFunction(cm.is_replacement_method, 'bool', ['pointer'], fastOptions),
|
|
2025
2049
|
get: new NativeFunction(cm.get_replacement_method, 'pointer', ['pointer'], fastOptions),
|
|
2026
2050
|
set: new NativeFunction(cm.set_replacement_method, 'void', ['pointer', 'pointer'], fastOptions),
|
|
2051
|
+
synchronize: new NativeFunction(cm.synchronize_replacement_methods, 'void', ['uint', 'pointer', 'pointer'], fastOptions),
|
|
2027
2052
|
delete: new NativeFunction(cm.delete_replacement_method, 'void', ['pointer'], fastOptions),
|
|
2028
2053
|
translate: new NativeFunction(cm.translate_method, 'pointer', ['pointer'], fastOptions),
|
|
2029
2054
|
findReplacementFromQuickCode: cm.find_replacement_method_from_quick_code
|
|
@@ -2057,6 +2082,8 @@ function ensureArtKnowsHowToHandleMethodInstrumentation (vm) {
|
|
|
2057
2082
|
|
|
2058
2083
|
instrumentArtQuickEntrypoints(vm);
|
|
2059
2084
|
instrumentArtMethodInvocationFromInterpreter();
|
|
2085
|
+
instrumentArtGarbageCollection();
|
|
2086
|
+
instrumentArtFixupStaticTrampolines();
|
|
2060
2087
|
}
|
|
2061
2088
|
|
|
2062
2089
|
function instrumentArtQuickEntrypoints (vm) {
|
|
@@ -2108,6 +2135,52 @@ function instrumentArtMethodInvocationFromInterpreter () {
|
|
|
2108
2135
|
}
|
|
2109
2136
|
}
|
|
2110
2137
|
|
|
2138
|
+
function instrumentArtGarbageCollection () {
|
|
2139
|
+
const api = getApi();
|
|
2140
|
+
const art = api.module;
|
|
2141
|
+
|
|
2142
|
+
const gc = art.findSymbolByName('_ZN3art2gc4Heap22CollectGarbageInternalENS0_9collector6GcTypeENS0_7GcCauseEbj');
|
|
2143
|
+
if (gc === null) {
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
const { artNterpEntryPoint, artQuickToInterpreterBridge } = api;
|
|
2148
|
+
const quickCodeOffset = getArtMethodSpec(api.vm).offset.quickCode;
|
|
2149
|
+
Interceptor.attach(gc, {
|
|
2150
|
+
onLeave () {
|
|
2151
|
+
artController.replacedMethods.synchronize(quickCodeOffset, artNterpEntryPoint, artQuickToInterpreterBridge);
|
|
2152
|
+
}
|
|
2153
|
+
});
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
function instrumentArtFixupStaticTrampolines () {
|
|
2157
|
+
const patterns = [
|
|
2158
|
+
['_ZN3art11ClassLinker26VisiblyInitializedCallback22MarkVisiblyInitializedEPNS_6ThreadE', 'e90340f8 : ff0ff0ff'],
|
|
2159
|
+
['_ZN3art11ClassLinker26VisiblyInitializedCallback29AdjustThreadVisibilityCounterEPNS_6ThreadEl', '7f0f00f9 : 1ffcffff'],
|
|
2160
|
+
];
|
|
2161
|
+
const api = getApi();
|
|
2162
|
+
const art = api.module;
|
|
2163
|
+
for (const [name, pattern] of patterns) {
|
|
2164
|
+
const base = art.findSymbolByName(name);
|
|
2165
|
+
if (base === null) {
|
|
2166
|
+
continue;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
const matches = Memory.scanSync(base, 8192, pattern);
|
|
2170
|
+
if (matches.length === 0) {
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
const { artNterpEntryPoint, artQuickToInterpreterBridge } = api;
|
|
2175
|
+
const quickCodeOffset = getArtMethodSpec(api.vm).offset.quickCode;
|
|
2176
|
+
Interceptor.attach(matches[0].address, function () {
|
|
2177
|
+
artController.replacedMethods.synchronize(quickCodeOffset, artNterpEntryPoint, artQuickToInterpreterBridge);
|
|
2178
|
+
});
|
|
2179
|
+
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2111
2184
|
function ensureArtKnowsHowToHandleReplacementMethods (vm) {
|
|
2112
2185
|
if (taughtArtAboutReplacementMethods) {
|
|
2113
2186
|
return;
|
|
@@ -2218,6 +2291,21 @@ const artGetOatQuickMethodHeaderInlinedCopyHandler = {
|
|
|
2218
2291
|
offset: 1,
|
|
2219
2292
|
validateMatch: validateGetOatQuickMethodHeaderInlinedMatchArm64
|
|
2220
2293
|
},
|
|
2294
|
+
{
|
|
2295
|
+
pattern: [
|
|
2296
|
+
/* e8 */ '0a 40 b9', // ldr w8, [x?, #0x8]
|
|
2297
|
+
'1f 05 00 31', // cmn w8, #0x1
|
|
2298
|
+
'40 01 00 54', // b.eq <target>
|
|
2299
|
+
'00 0e 40 f9', // ldr x?, [x?, #0x18]
|
|
2300
|
+
':',
|
|
2301
|
+
/* 00 */ 'fc ff ff',
|
|
2302
|
+
'1f fc ff ff',
|
|
2303
|
+
'1f 00 00 ff',
|
|
2304
|
+
'00 fc ff ff'
|
|
2305
|
+
],
|
|
2306
|
+
offset: 1,
|
|
2307
|
+
validateMatch: validateGetOatQuickMethodHeaderInlinedMatchArm64
|
|
2308
|
+
},
|
|
2221
2309
|
{
|
|
2222
2310
|
pattern: [
|
|
2223
2311
|
/* e8 */ '0a 40 b9', // ldr w8, [x23, #0x8]
|
package/lib/class-model.js
CHANGED
|
@@ -85,6 +85,7 @@ struct _JavaFieldApi
|
|
|
85
85
|
|
|
86
86
|
struct _JavaApi
|
|
87
87
|
{
|
|
88
|
+
jvmtiEnv * jvmti;
|
|
88
89
|
JavaClassApi clazz;
|
|
89
90
|
JavaMethodApi method;
|
|
90
91
|
JavaFieldApi field;
|
|
@@ -235,6 +236,7 @@ model_new (jclass class_handle,
|
|
|
235
236
|
{
|
|
236
237
|
Model * model;
|
|
237
238
|
GHashTable * members;
|
|
239
|
+
jvmtiEnv * jvmti = java_api.jvmti;
|
|
238
240
|
gpointer * funcs = env->functions;
|
|
239
241
|
jmethodID (* from_reflected_method) (JNIEnv *, jobject) = funcs[7];
|
|
240
242
|
jfieldID (* from_reflected_field) (JNIEnv *, jobject) = funcs[8];
|
|
@@ -254,7 +256,52 @@ model_new (jclass class_handle,
|
|
|
254
256
|
members = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
255
257
|
model->members = members;
|
|
256
258
|
|
|
257
|
-
if (
|
|
259
|
+
if (jvmti != NULL)
|
|
260
|
+
{
|
|
261
|
+
gpointer * jf = jvmti->functions - 1;
|
|
262
|
+
jvmtiError (* deallocate) (jvmtiEnv *, void * mem) = jf[47];
|
|
263
|
+
jvmtiError (* get_class_methods) (jvmtiEnv *, jclass, jint *, jmethodID **) = jf[52];
|
|
264
|
+
jvmtiError (* get_class_fields) (jvmtiEnv *, jclass, jint *, jfieldID **) = jf[53];
|
|
265
|
+
jvmtiError (* get_field_name) (jvmtiEnv *, jclass, jfieldID, char **, char **, char **) = jf[60];
|
|
266
|
+
jvmtiError (* get_field_modifiers) (jvmtiEnv *, jclass, jfieldID, jint *) = jf[62];
|
|
267
|
+
jvmtiError (* get_method_name) (jvmtiEnv *, jmethodID, char **, char **, char **) = jf[64];
|
|
268
|
+
jvmtiError (* get_method_modifiers) (jvmtiEnv *, jmethodID, jint *) = jf[66];
|
|
269
|
+
jint method_count;
|
|
270
|
+
jmethodID * methods;
|
|
271
|
+
jint field_count;
|
|
272
|
+
jfieldID * fields;
|
|
273
|
+
char * name;
|
|
274
|
+
jint modifiers;
|
|
275
|
+
|
|
276
|
+
get_class_methods (jvmti, class_handle, &method_count, &methods);
|
|
277
|
+
for (i = 0; i != method_count; i++)
|
|
278
|
+
{
|
|
279
|
+
jmethodID method = methods[i];
|
|
280
|
+
|
|
281
|
+
get_method_name (jvmti, method, &name, NULL, NULL);
|
|
282
|
+
get_method_modifiers (jvmti, method, &modifiers);
|
|
283
|
+
|
|
284
|
+
model_add_method (model, name, method, modifiers);
|
|
285
|
+
|
|
286
|
+
deallocate (jvmti, name);
|
|
287
|
+
}
|
|
288
|
+
deallocate (jvmti, methods);
|
|
289
|
+
|
|
290
|
+
get_class_fields (jvmti, class_handle, &field_count, &fields);
|
|
291
|
+
for (i = 0; i != field_count; i++)
|
|
292
|
+
{
|
|
293
|
+
jfieldID field = fields[i];
|
|
294
|
+
|
|
295
|
+
get_field_name (jvmti, class_handle, field, &name, NULL, NULL);
|
|
296
|
+
get_field_modifiers (jvmti, class_handle, field, &modifiers);
|
|
297
|
+
|
|
298
|
+
model_add_field (model, name, field, modifiers);
|
|
299
|
+
|
|
300
|
+
deallocate (jvmti, name);
|
|
301
|
+
}
|
|
302
|
+
deallocate (jvmti, fields);
|
|
303
|
+
}
|
|
304
|
+
else if (art_api.available)
|
|
258
305
|
{
|
|
259
306
|
gpointer elements;
|
|
260
307
|
guint n, i;
|
|
@@ -702,8 +749,7 @@ enumerate_methods_jvm (const gchar * class_query,
|
|
|
702
749
|
jboolean include_signature,
|
|
703
750
|
jboolean ignore_case,
|
|
704
751
|
jboolean skip_system_classes,
|
|
705
|
-
JNIEnv * env
|
|
706
|
-
jvmtiEnv * jvmti)
|
|
752
|
+
JNIEnv * env)
|
|
707
753
|
{
|
|
708
754
|
gchar * result;
|
|
709
755
|
GPatternSpec * class_pattern, * method_pattern;
|
|
@@ -712,6 +758,7 @@ enumerate_methods_jvm (const gchar * class_query,
|
|
|
712
758
|
jobject (* new_global_ref) (JNIEnv *, jobject) = ef[21];
|
|
713
759
|
void (* delete_local_ref) (JNIEnv *, jobject) = ef[23];
|
|
714
760
|
jboolean (* is_same_object) (JNIEnv *, jobject, jobject) = ef[24];
|
|
761
|
+
jvmtiEnv * jvmti = java_api.jvmti;
|
|
715
762
|
gpointer * jf = jvmti->functions - 1;
|
|
716
763
|
jvmtiError (* deallocate) (jvmtiEnv *, void * mem) = jf[47];
|
|
717
764
|
jvmtiError (* get_class_signature) (jvmtiEnv *, jclass, char **, char **) = jf[48];
|
|
@@ -1207,10 +1254,10 @@ export default class Model {
|
|
|
1207
1254
|
}
|
|
1208
1255
|
|
|
1209
1256
|
let result;
|
|
1210
|
-
if (api.
|
|
1257
|
+
if (api.jvmti !== null) {
|
|
1211
1258
|
const json = cm.enumerateMethodsJvm(classQuery, methodQuery,
|
|
1212
1259
|
boolToNative(includeSignature), boolToNative(ignoreCase), boolToNative(skipSystemClasses),
|
|
1213
|
-
env
|
|
1260
|
+
env);
|
|
1214
1261
|
try {
|
|
1215
1262
|
result = JSON.parse(json.readUtf8String())
|
|
1216
1263
|
.map(group => {
|
|
@@ -1273,11 +1320,14 @@ function ensureInitialized (env) {
|
|
|
1273
1320
|
}
|
|
1274
1321
|
|
|
1275
1322
|
function compileModule (env) {
|
|
1323
|
+
const api = getApi();
|
|
1324
|
+
const { jvmti } = api;
|
|
1325
|
+
|
|
1276
1326
|
const { pointerSize } = Process;
|
|
1277
1327
|
|
|
1278
1328
|
const lockSize = 8;
|
|
1279
1329
|
const modelsSize = pointerSize;
|
|
1280
|
-
const javaApiSize =
|
|
1330
|
+
const javaApiSize = 7 * pointerSize;
|
|
1281
1331
|
const artApiSize = (10 * 4) + (5 * pointerSize);
|
|
1282
1332
|
|
|
1283
1333
|
const dataSize = lockSize + modelsSize + javaApiSize + artApiSize;
|
|
@@ -1293,6 +1343,7 @@ function compileModule (env) {
|
|
|
1293
1343
|
const field = env.javaLangReflectField();
|
|
1294
1344
|
let j = javaApi;
|
|
1295
1345
|
[
|
|
1346
|
+
jvmti,
|
|
1296
1347
|
getDeclaredMethods, getDeclaredFields,
|
|
1297
1348
|
method.getName, method.getModifiers,
|
|
1298
1349
|
field.getName, field.getModifiers
|
|
@@ -1303,16 +1354,22 @@ function compileModule (env) {
|
|
|
1303
1354
|
|
|
1304
1355
|
const artApi = javaApi.add(javaApiSize);
|
|
1305
1356
|
const { vm } = env;
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1357
|
+
if (api.flavor === 'art') {
|
|
1358
|
+
let artClassOffsets;
|
|
1359
|
+
if (jvmti !== null) {
|
|
1360
|
+
artClassOffsets = [0, 0, 0, 0];
|
|
1361
|
+
} else {
|
|
1362
|
+
const c = getArtClassSpec(vm).offset;
|
|
1363
|
+
artClassOffsets = [c.ifields, c.methods, c.sfields, c.copiedMethodsOffset];
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1309
1366
|
const m = getArtMethodSpec(vm);
|
|
1310
1367
|
const f = getArtFieldSpec(vm);
|
|
1311
1368
|
|
|
1312
1369
|
let s = artApi;
|
|
1313
1370
|
[
|
|
1314
1371
|
1,
|
|
1315
|
-
|
|
1372
|
+
...artClassOffsets,
|
|
1316
1373
|
m.size, m.offset.accessFlags,
|
|
1317
1374
|
f.size, f.offset.accessFlags,
|
|
1318
1375
|
0xffffffff
|
|
@@ -1321,7 +1378,6 @@ function compileModule (env) {
|
|
|
1321
1378
|
s = s.writeUInt(value).add(4);
|
|
1322
1379
|
});
|
|
1323
1380
|
|
|
1324
|
-
const api = getApi();
|
|
1325
1381
|
[
|
|
1326
1382
|
api.artClassLinker.address,
|
|
1327
1383
|
api['art::ClassLinker::VisitClasses'],
|
|
@@ -1349,7 +1405,6 @@ function compileModule (env) {
|
|
|
1349
1405
|
|
|
1350
1406
|
return {
|
|
1351
1407
|
handle: cm,
|
|
1352
|
-
mode: (artClass !== null) ? 'full' : 'basic',
|
|
1353
1408
|
new: new NativeFunction(cm.model_new, 'pointer', ['pointer', 'pointer', 'pointer'], reentrantOptions),
|
|
1354
1409
|
has: new NativeFunction(cm.model_has, 'bool', ['pointer', 'pointer'], fastOptions),
|
|
1355
1410
|
find: new NativeFunction(cm.model_find, 'pointer', ['pointer', 'pointer'], fastOptions),
|
|
@@ -1357,17 +1412,19 @@ function compileModule (env) {
|
|
|
1357
1412
|
enumerateMethodsArt: new NativeFunction(cm.enumerate_methods_art, 'pointer', ['pointer', 'pointer', 'bool', 'bool', 'bool'],
|
|
1358
1413
|
reentrantOptions),
|
|
1359
1414
|
enumerateMethodsJvm: new NativeFunction(cm.enumerate_methods_jvm, 'pointer', ['pointer', 'pointer', 'bool', 'bool', 'bool',
|
|
1360
|
-
'pointer'
|
|
1415
|
+
'pointer'], reentrantOptions),
|
|
1361
1416
|
dealloc: new NativeFunction(cm.dealloc, 'void', ['pointer'], fastOptions)
|
|
1362
1417
|
};
|
|
1363
1418
|
}
|
|
1364
1419
|
|
|
1365
1420
|
function makeHandleUnwrapper (cm, vm) {
|
|
1366
|
-
|
|
1421
|
+
const api = getApi();
|
|
1422
|
+
|
|
1423
|
+
if (api.flavor !== 'art') {
|
|
1367
1424
|
return nullUnwrap;
|
|
1368
1425
|
}
|
|
1369
1426
|
|
|
1370
|
-
const decodeGlobal =
|
|
1427
|
+
const decodeGlobal = api['art::JavaVMExt::DecodeGlobal'];
|
|
1371
1428
|
|
|
1372
1429
|
return function (handle, env, fn) {
|
|
1373
1430
|
let result;
|