frida-java-bridge 7.0.3 → 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 CHANGED
@@ -956,43 +956,131 @@ function tryGetArtClassLinkerSpec (runtime, runtimeSpec) {
956
956
  }
957
957
 
958
958
  export function getArtClassSpec (vm) {
959
- let apiLevel;
960
- try {
961
- apiLevel = getAndroidApiLevel();
962
- } catch (e) {
963
- return null;
964
- }
959
+ const MAX_OFFSET = 0x100;
965
960
 
966
- if (apiLevel >= 34) {
967
- return {
968
- offset: {
969
- ifields: 0x28,
970
- methods: 0x28 + 0x8,
971
- sfields: 0,
972
- copiedMethodsOffset: 0x6c,
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
- } else if (apiLevel >= 26) {
976
- return {
977
- offset: {
978
- ifields: 0x28,
979
- methods: 0x28 + 0x8,
980
- sfields: 0x28 + 0x10,
981
- copiedMethodsOffset: 0x74,
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
- } else if (apiLevel >= 24) {
985
- return {
986
- offset: {
987
- ifields: 0x38,
988
- methods: 0x38 + 0x8,
989
- sfields: 0x38 + 0x10,
990
- copiedMethodsOffset: 0x7c,
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
- } else {
994
- return null;
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) {
@@ -899,7 +899,7 @@ Object.defineProperties(Wrapper.prototype, {
899
899
  $alloc: {
900
900
  enumerable: true,
901
901
  get () {
902
- return this[Symbol.for('$alloc')];
902
+ return this[Symbol.for('alloc')];
903
903
  }
904
904
  },
905
905
  [Symbol.for('init')]: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frida-java-bridge",
3
- "version": "7.0.3",
3
+ "version": "7.0.5",
4
4
  "description": "Java runtime interop from Frida",
5
5
  "keywords": [
6
6
  "frida-gum",