frida-java-bridge 7.0.4 → 7.0.5
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 +119 -31
- package/package.json +1 -1
package/lib/android.js
CHANGED
|
@@ -956,43 +956,131 @@ function tryGetArtClassLinkerSpec (runtime, runtimeSpec) {
|
|
|
956
956
|
}
|
|
957
957
|
|
|
958
958
|
export function getArtClassSpec (vm) {
|
|
959
|
-
|
|
960
|
-
try {
|
|
961
|
-
apiLevel = getAndroidApiLevel();
|
|
962
|
-
} catch (e) {
|
|
963
|
-
return null;
|
|
964
|
-
}
|
|
959
|
+
const MAX_OFFSET = 0x100;
|
|
965
960
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
961
|
+
let spec = null;
|
|
962
|
+
|
|
963
|
+
vm.perform(env => {
|
|
964
|
+
const fieldSpec = getArtFieldSpec(vm);
|
|
965
|
+
const methodSpec = getArtMethodSpec(vm);
|
|
966
|
+
|
|
967
|
+
const fInfo = {
|
|
968
|
+
artArrayLengthSize: 4,
|
|
969
|
+
artArrayEntrySize: fieldSpec.size,
|
|
970
|
+
// java/lang/Integer has 11 fields on Android 16.
|
|
971
|
+
artArrayMax: 20
|
|
974
972
|
};
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
973
|
+
|
|
974
|
+
const mInfo = {
|
|
975
|
+
artArrayLengthSize: pointerSize,
|
|
976
|
+
artArrayEntrySize: methodSpec.size,
|
|
977
|
+
// java/lang/Integer has 66 methods on Android 16.
|
|
978
|
+
artArrayMax: 100
|
|
979
|
+
};
|
|
980
|
+
|
|
981
|
+
const readArtArray = (objectBase, fieldOffset, lengthSize) => {
|
|
982
|
+
const header = objectBase.add(fieldOffset).readPointer();
|
|
983
|
+
if (header.isNull()) {
|
|
984
|
+
return null;
|
|
982
985
|
}
|
|
986
|
+
|
|
987
|
+
const length = (lengthSize === 4) ? header.readU32() : header.readU64().valueOf();
|
|
988
|
+
if (length === 0) {
|
|
989
|
+
return null;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
return {
|
|
993
|
+
length,
|
|
994
|
+
data: header.add(lengthSize)
|
|
995
|
+
};
|
|
983
996
|
};
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
997
|
+
|
|
998
|
+
const hasEntry = (objectBase, offset, needle, info) => {
|
|
999
|
+
try {
|
|
1000
|
+
const artArray = readArtArray(objectBase, offset, info.artArrayLengthSize);
|
|
1001
|
+
if (artArray === null) {
|
|
1002
|
+
return false;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
for (let i = 0; i !== Math.min(artArray.length, info.artArrayMax); i++) {
|
|
1006
|
+
const fieldPtr = artArray.data.add(i * info.artArrayEntrySize);
|
|
1007
|
+
if (fieldPtr.equals(needle)) {
|
|
1008
|
+
return true;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
} catch {
|
|
991
1012
|
}
|
|
1013
|
+
|
|
1014
|
+
return false;
|
|
992
1015
|
};
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1016
|
+
|
|
1017
|
+
const clazz = env.findClass('java/lang/Integer');
|
|
1018
|
+
const clazzRef = env.newGlobalRef(clazz);
|
|
1019
|
+
|
|
1020
|
+
try {
|
|
1021
|
+
let object;
|
|
1022
|
+
withRunnableArtThread(vm, env, thread => {
|
|
1023
|
+
object = getApi()['art::JavaVMExt::DecodeGlobal'](vm, thread, clazzRef);
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
const fieldInstance = env.getFieldId(clazzRef, 'value', 'I');
|
|
1027
|
+
const fieldStatic = env.getStaticFieldId(clazzRef, 'TYPE', 'Ljava/lang/Class;');
|
|
1028
|
+
|
|
1029
|
+
let offsetStatic = -1;
|
|
1030
|
+
let offsetInstance = -1;
|
|
1031
|
+
for (let offset = 0; offset !== MAX_OFFSET; offset += 4) {
|
|
1032
|
+
if (offsetStatic === -1 && hasEntry(object, offset, fieldStatic, fInfo)) {
|
|
1033
|
+
offsetStatic = offset;
|
|
1034
|
+
}
|
|
1035
|
+
if (offsetInstance === -1 && hasEntry(object, offset, fieldInstance, fInfo)) {
|
|
1036
|
+
offsetInstance = offset;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
if (offsetInstance === -1 || offsetStatic === -1) {
|
|
1040
|
+
throw new Error('Unable to find fields in java/lang/Integer; please file a bug');
|
|
1041
|
+
}
|
|
1042
|
+
const sfieldOffset = (offsetInstance !== offsetStatic) ? offsetStatic : 0;
|
|
1043
|
+
const ifieldOffset = offsetInstance;
|
|
1044
|
+
|
|
1045
|
+
let offsetMethods = -1;
|
|
1046
|
+
const methodInstance = env.getMethodId(clazzRef, 'intValue', '()I');
|
|
1047
|
+
for (let offset = 0; offset !== MAX_OFFSET; offset += 4) {
|
|
1048
|
+
if (offsetMethods === -1 && hasEntry(object, offset, methodInstance, mInfo)) {
|
|
1049
|
+
offsetMethods = offset;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
if (offsetMethods === -1) {
|
|
1053
|
+
throw new Error('Unable to find methods in java/lang/Integer; please file a bug');
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
let offsetCopiedMethods = -1;
|
|
1057
|
+
const methodsArray = readArtArray(object, offsetMethods, mInfo.artArrayLengthSize);
|
|
1058
|
+
const methodsArraySize = methodsArray.length;
|
|
1059
|
+
for (let offset = offsetMethods; offset !== MAX_OFFSET; offset += 4) {
|
|
1060
|
+
if (object.add(offset).readU16() === methodsArraySize) {
|
|
1061
|
+
offsetCopiedMethods = offset;
|
|
1062
|
+
break;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
if (offsetCopiedMethods === -1) {
|
|
1066
|
+
throw new Error('Unable to find copied methods in java/lang/Integer; please file a bug');
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
spec = {
|
|
1070
|
+
offset: {
|
|
1071
|
+
ifields: ifieldOffset,
|
|
1072
|
+
methods: offsetMethods,
|
|
1073
|
+
sfields: sfieldOffset,
|
|
1074
|
+
copiedMethodsOffset: offsetCopiedMethods,
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
} finally {
|
|
1078
|
+
env.deleteLocalRef(clazz);
|
|
1079
|
+
env.deleteGlobalRef(clazzRef);
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
return spec;
|
|
996
1084
|
}
|
|
997
1085
|
|
|
998
1086
|
function _getArtMethodSpec (vm) {
|