@@ -44,7 +44,6 @@ const artThreadStateTransitions = {};
44
44
let cachedApi = null ;
45
45
let thunkPage = null ;
46
46
let thunkOffset = 0 ;
47
- const hookedArtMethods = new Set ( ) ;
48
47
let taughtArtAboutHookedMethods = false ;
49
48
let jdwpSession = null ;
50
49
let socketpair = null ;
@@ -1075,14 +1074,19 @@ function makeThunk (size, write) {
1075
1074
}
1076
1075
1077
1076
function notifyArtMethodHooked ( method ) {
1078
- hookedArtMethods . add ( method . toString ( ) ) ;
1079
-
1080
1077
ensureArtKnowsHowToHandleHookedMethods ( ) ;
1081
1078
}
1082
1079
1083
- function notifyArtMethodReverted ( method ) {
1084
- hookedArtMethods . delete ( method . toString ( ) ) ;
1085
- }
1080
+ const LIBFFI_CLOSURE_MAGIC_X64 = uint64 ( '0xfffffffff9158d4c' ) ;
1081
+ const LIBFFI_CLOSURE_MAGIC_ARM = uint64 ( '0xe51ff004e24fc008' ) ;
1082
+ const LIBFFI_CLOSURE_MAGIC_ARM64 = uint64 ( '0x10fffff158000090' ) ;
1083
+
1084
+ const libffiClosureEntrypointParsers = {
1085
+ ia32 : parseLibffiClosureEntrypointForIA32 ,
1086
+ x64 : parseLibffiClosureEntrypointForX64 ,
1087
+ arm : parseLibffiClosureEntrypointForArm ,
1088
+ arm64 : parseLibffiClosureEntrypointForArm64 ,
1089
+ } ;
1086
1090
1087
1091
const goqmhFilterFuncGenerators = {
1088
1092
ia32 : makeGoqmhFilterFuncForIA32 ,
@@ -1098,6 +1102,8 @@ function ensureArtKnowsHowToHandleHookedMethods () {
1098
1102
taughtArtAboutHookedMethods = true ;
1099
1103
1100
1104
const api = getApi ( ) ;
1105
+ const methodOffsets = getArtMethodSpec ( api . vm ) . offset ;
1106
+ const jniCodeOffset = methodOffsets . jniCode ;
1101
1107
1102
1108
const getOatQuickMethodHeaderImpl = Module . findExportByName ( 'libart.so' ,
1103
1109
( pointerSize === 4 )
@@ -1111,21 +1117,72 @@ function ensureArtKnowsHowToHandleHookedMethods () {
1111
1117
1112
1118
const original = new NativeFunction ( getOatQuickMethodHeaderImpl , ...signature ) ;
1113
1119
1120
+ const arch = Process . arch ;
1121
+ const parseClosure = libffiClosureEntrypointParsers [ arch ] ;
1122
+ const fridaLibffiClosureEntrypoint = parseClosure ( new NativeCallback ( ( ) => { } , 'void' , [ ] ) ) ;
1123
+
1114
1124
const replacement = new NativeCallback ( function ( method , pc ) {
1115
- const isHookedMethod = hookedArtMethods . has ( method . toString ( ) ) ;
1125
+ const jniImpl = method . add ( jniCodeOffset ) . readPointer ( ) ;
1126
+ const entrypoint = parseClosure ( jniImpl ) ;
1127
+ const isHookedMethod = entrypoint . equals ( fridaLibffiClosureEntrypoint ) ;
1116
1128
if ( isHookedMethod ) {
1117
1129
return NULL ;
1118
1130
}
1119
1131
1120
1132
return original ( method , pc ) ;
1121
1133
} , ...signature ) ;
1122
1134
1123
- const generateFilterFunc = goqmhFilterFuncGenerators [ Process . arch ] ;
1124
- const filter = generateFilterFunc ( original , replacement , getArtMethodSpec ( api . vm ) . offset . quickCode ,
1135
+ const generateFilterFunc = goqmhFilterFuncGenerators [ arch ] ;
1136
+ const filter = generateFilterFunc ( original , replacement , methodOffsets . quickCode ,
1125
1137
api . artQuickGenericJniTrampoline ) ;
1126
1138
filter . _replacement = replacement ;
1127
1139
1128
- Interceptor . replace ( original , filter ) ;
1140
+ try {
1141
+ Interceptor . replace ( original , filter ) ;
1142
+ } catch ( e ) {
1143
+ /*
1144
+ * Already replaced by another script. For now we count on the other script
1145
+ * not getting unloaded before ours.
1146
+ */
1147
+ }
1148
+ }
1149
+
1150
+ function parseLibffiClosureEntrypointForIA32 ( closure ) {
1151
+ if ( closure . readU8 ( ) !== 0xb8 || closure . add ( 5 ) . readU8 ( ) !== 0xe9 ) {
1152
+ return NULL ;
1153
+ }
1154
+
1155
+ const offset = closure . add ( 6 ) . readS32 ( ) ;
1156
+
1157
+ return closure . add ( 10 ) . add ( offset ) ;
1158
+ }
1159
+
1160
+ function parseLibffiClosureEntrypointForX64 ( closure ) {
1161
+ if ( ! closure . readU64 ( ) . equals ( LIBFFI_CLOSURE_MAGIC_X64 ) ) {
1162
+ return NULL ;
1163
+ }
1164
+
1165
+ if ( closure . add ( 8 ) . readU8 ( ) !== 0x25 || closure . add ( 9 ) . readS32 ( ) !== 3 ) {
1166
+ return NULL ;
1167
+ }
1168
+
1169
+ return closure . add ( 16 ) . readPointer ( ) ;
1170
+ }
1171
+
1172
+ function parseLibffiClosureEntrypointForArm ( closure ) {
1173
+ if ( ! closure . readU64 ( ) . equals ( LIBFFI_CLOSURE_MAGIC_ARM ) ) {
1174
+ return NULL ;
1175
+ }
1176
+
1177
+ return closure . add ( 8 ) . readPointer ( ) ;
1178
+ }
1179
+
1180
+ function parseLibffiClosureEntrypointForArm64 ( closure ) {
1181
+ if ( ! closure . readU64 ( ) . equals ( LIBFFI_CLOSURE_MAGIC_ARM64 ) ) {
1182
+ return NULL ;
1183
+ }
1184
+
1185
+ return closure . add ( 16 ) . readPointer ( ) ;
1129
1186
}
1130
1187
1131
1188
function makeGoqmhFilterFuncForIA32 ( original , replacement , quickCodeOffset , quickJniTrampoline ) {
@@ -2366,7 +2423,6 @@ module.exports = {
2366
2423
ArtStackVisitor,
2367
2424
ArtMethod,
2368
2425
notifyArtMethodHooked,
2369
- notifyArtMethodReverted,
2370
2426
cloneArtMethod,
2371
2427
HandleVector,
2372
2428
deoptimizeEverything
0 commit comments