frida-java-bridge 5.1.0 → 5.3.0

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.js CHANGED
@@ -5,6 +5,7 @@ const {
5
5
  withRunnableArtThread,
6
6
  makeArtClassVisitor,
7
7
  makeArtClassLoaderVisitor,
8
+ backtrace,
8
9
  deoptimizeEverything,
9
10
  deoptimizeBootImage,
10
11
  deoptimizeMethod
@@ -478,6 +479,10 @@ class Runtime {
478
479
  return this.classFactory.array(type, elements);
479
480
  }
480
481
 
482
+ backtrace (options) {
483
+ return backtrace(this.vm, options);
484
+ }
485
+
481
486
  // Reference: http://stackoverflow.com/questions/2848575/how-to-detect-ui-thread-on-android
482
487
  isMainThread () {
483
488
  const Looper = this.classFactory.use('android.os.Looper');
@@ -0,0 +1,33 @@
1
+ export function getApi(): Api;
2
+ export function withRunnableArtThread(vm: VM, env: Env, callback: (thread: Thread) => void): void;
3
+ export function translateMethod(methodId: NativePointerValue): NativePointer;
4
+
5
+ export class ArtStackVisitor {
6
+ constructor(thread: Thread, context: Context, walkKind: WalkKind, numFrames?: number, checkSuspended?: boolean);
7
+ walkStack(includeTransitions?: boolean): void;
8
+ getMethod(): ArtMethod | null;
9
+ getCurrentQuickFramePc(): NativePointer;
10
+ getCurrentQuickFrame(): NativePointer;
11
+ getCurrentShadowFrame(): NativePointer;
12
+ describeLocation(): string;
13
+ getCurrentOatQuickMethodHeader(): NativePointer;
14
+ getCurrentQuickFrameInfo(): QuickFrameInfo;
15
+ }
16
+
17
+ export type WalkKind = "include-inlined-frames" | "skip-inlined-frames";
18
+
19
+ export interface ArtMethod extends ObjectWrapper {
20
+ prettyMethod(withSignature?: boolean): string;
21
+ }
22
+
23
+ export interface QuickFrameInfo {
24
+ frameSizeInBytes: number;
25
+ coreSpillMask: number;
26
+ fpSpillMask: number;
27
+ }
28
+
29
+ export type Api = any;
30
+ export type VM = any;
31
+ export type Env = any;
32
+ export type Thread = any;
33
+ export type Context = any;
package/lib/android.js CHANGED
@@ -285,7 +285,9 @@ function _getApi () {
285
285
 
286
286
  // Android >= 11
287
287
  _ZN3art3jni12JniIdManager14DecodeMethodIdEP10_jmethodID: ['art::jni::JniIdManager::DecodeMethodId', 'pointer', ['pointer', 'pointer']],
288
- _ZN3art11interpreter18GetNterpEntryPointEv: ['art::interpreter::GetNterpEntryPoint', 'pointer', []]
288
+ _ZN3art11interpreter18GetNterpEntryPointEv: ['art::interpreter::GetNterpEntryPoint', 'pointer', []],
289
+
290
+ _ZN3art7Monitor17TranslateLocationEPNS_9ArtMethodEjPPKcPi: ['art::Monitor::TranslateLocation', 'void', ['pointer', 'uint32', 'pointer', 'pointer']]
289
291
  },
290
292
  variables: {
291
293
  _ZN3art3Dbg9gRegistryE: function (address) {
@@ -337,7 +339,8 @@ function _getApi () {
337
339
  '_ZN3art3Dbg20ManageDeoptimizationEv',
338
340
  '_ZN3art3Dbg9gRegistryE',
339
341
  '_ZN3art3jni12JniIdManager14DecodeMethodIdEP10_jmethodID',
340
- '_ZN3art11interpreter18GetNterpEntryPointEv'
342
+ '_ZN3art11interpreter18GetNterpEntryPointEv',
343
+ '_ZN3art7Monitor17TranslateLocationEPNS_9ArtMethodEjPPKcPi'
341
344
  ]
342
345
  }]
343
346
  : [{
@@ -1541,7 +1544,7 @@ set_replacement_method (gpointer original_method,
1541
1544
  g_mutex_lock (&lock);
1542
1545
 
1543
1546
  g_hash_table_insert (methods, original_method, replacement_method);
1544
- g_hash_table_add (replacements, replacement_method);
1547
+ g_hash_table_insert (replacements, replacement_method, original_method);
1545
1548
 
1546
1549
  g_mutex_unlock (&lock);
1547
1550
  }
@@ -1563,6 +1566,20 @@ delete_replacement_method (gpointer original_method)
1563
1566
  g_mutex_unlock (&lock);
1564
1567
  }
1565
1568
 
1569
+ gpointer
1570
+ translate_method (gpointer method)
1571
+ {
1572
+ gpointer translated_method;
1573
+
1574
+ g_mutex_lock (&lock);
1575
+
1576
+ translated_method = g_hash_table_lookup (replacements, method);
1577
+
1578
+ g_mutex_unlock (&lock);
1579
+
1580
+ return (translated_method != NULL) ? translated_method : method;
1581
+ }
1582
+
1566
1583
  gpointer
1567
1584
  find_replacement_method_from_quick_code (gpointer method,
1568
1585
  gpointer thread)
@@ -1691,6 +1708,7 @@ on_leave_gc_concurrent_copying_copying_phase (GumInvocationContext * ic)
1691
1708
  get: new NativeFunction(cm.get_replacement_method, 'pointer', ['pointer'], fastOptions),
1692
1709
  set: new NativeFunction(cm.set_replacement_method, 'void', ['pointer', 'pointer'], fastOptions),
1693
1710
  delete: new NativeFunction(cm.delete_replacement_method, 'void', ['pointer'], fastOptions),
1711
+ translate: new NativeFunction(cm.translate_method, 'pointer', ['pointer'], fastOptions),
1694
1712
  findReplacementFromQuickCode: cm.find_replacement_method_from_quick_code
1695
1713
  },
1696
1714
  getOatQuickMethodHeaderImpl,
@@ -1793,6 +1811,93 @@ function makeMethodMangler (methodId) {
1793
1811
  return new MethodMangler(methodId);
1794
1812
  }
1795
1813
 
1814
+ function translateMethod (methodId) {
1815
+ return artController.replacedMethods.translate(methodId);
1816
+ }
1817
+
1818
+ class BacktraceVisitor extends ArtStackVisitor {
1819
+ constructor (thread, limit) {
1820
+ const api = getApi();
1821
+
1822
+ super(thread, api['art::Thread::GetLongJumpContext'](thread), 'include-inlined-frames');
1823
+
1824
+ this.frames = [];
1825
+ this.limit = limit;
1826
+
1827
+ this._translateLocation = api['art::Monitor::TranslateLocation'];
1828
+ }
1829
+
1830
+ visitFrame () {
1831
+ this._collectFrame(this.describeLocation());
1832
+
1833
+ return this.frames.length < this.limit;
1834
+ }
1835
+
1836
+ _collectFrame (location) {
1837
+ if (location === 'upcall') {
1838
+ return;
1839
+ }
1840
+
1841
+ const tokens = location.split(/['"]/, 3);
1842
+ const rawMethodSignature = tokens[1];
1843
+ if (rawMethodSignature.startsWith('<')) {
1844
+ return;
1845
+ }
1846
+ const details = tokens[2];
1847
+
1848
+ const separatorIndex = rawMethodSignature.indexOf(' ');
1849
+ const returnType = rawMethodSignature.substring(0, separatorIndex);
1850
+ const rest = rawMethodSignature.substring(separatorIndex + 1);
1851
+ const argsStartIndex = rest.indexOf('(');
1852
+ const argsEndIndex = rest.indexOf(')', argsStartIndex + 1);
1853
+ const rawArgumentTypes = rest.substring(argsStartIndex + 1, argsEndIndex);
1854
+ const argumentTypes = (rawArgumentTypes !== '') ? rawArgumentTypes.split(', ') : [];
1855
+
1856
+ const classAndMethodName = rest.substring(0, argsStartIndex);
1857
+ const methodNameStartIndex = classAndMethodName.lastIndexOf('.');
1858
+ const className = classAndMethodName.substring(0, methodNameStartIndex);
1859
+ const methodName = classAndMethodName.substring(methodNameStartIndex + 1);
1860
+ let dexPc = parseInt(details.substring(13), 16);
1861
+
1862
+ const actualMethod = this.getMethod();
1863
+ const translatedMethod = translateMethod(actualMethod);
1864
+ if (!translatedMethod.equals(actualMethod)) {
1865
+ dexPc = 0;
1866
+ }
1867
+ const fileNamePtr = Memory.alloc(16);
1868
+ const lineNumberPtr = fileNamePtr.add(8);
1869
+ this._translateLocation(translatedMethod, dexPc, fileNamePtr, lineNumberPtr);
1870
+ const fileName = fileNamePtr.readPointer().readUtf8String();
1871
+ const lineNumber = lineNumberPtr.readS32();
1872
+
1873
+ this.frames.push({
1874
+ method: {
1875
+ handle: translatedMethod,
1876
+ name: methodName,
1877
+ returnType,
1878
+ argumentTypes
1879
+ },
1880
+ className,
1881
+ fileName,
1882
+ lineNumber
1883
+ });
1884
+ }
1885
+ }
1886
+
1887
+ function backtrace (vm, options = {}) {
1888
+ const { limit = 16 } = options;
1889
+
1890
+ let frames = null;
1891
+
1892
+ withRunnableArtThread(vm, vm.getEnv(), thread => {
1893
+ const visitor = new BacktraceVisitor(thread, limit);
1894
+ visitor.walkStack(true);
1895
+ frames = visitor.frames;
1896
+ });
1897
+
1898
+ return frames;
1899
+ }
1900
+
1796
1901
  function revertGlobalPatches () {
1797
1902
  patchedClasses.forEach(entry => {
1798
1903
  entry.vtablePtr.writePointer(entry.vtable);
@@ -4045,6 +4150,8 @@ module.exports = {
4045
4150
  ArtStackVisitor,
4046
4151
  ArtMethod,
4047
4152
  makeMethodMangler,
4153
+ translateMethod,
4154
+ backtrace,
4048
4155
  revertGlobalPatches,
4049
4156
  deoptimizeEverything,
4050
4157
  deoptimizeBootImage,
package/lib/jvm.js CHANGED
@@ -811,8 +811,8 @@ function _getJvmMethodSpec () {
811
811
 
812
812
  const getAdapterPointer = adapterInConstMethod
813
813
  ? function (method, constMethod) {
814
- return constMethod.add(constantPoolOffset + 2 * pointerSize);
815
- }
814
+ return constMethod.add(constantPoolOffset + 2 * pointerSize);
815
+ }
816
816
  : function (method, constMethod) {
817
817
  return method.add(i2iEntryOffset + pointerSize);
818
818
  };
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "frida-java-bridge",
3
- "version": "5.1.0",
3
+ "version": "5.3.0",
4
4
  "description": "Java runtime interop from Frida",
5
5
  "main": "index.js",
6
6
  "files": [
7
7
  "/index.js",
8
- "/lib/**/*.js"
8
+ "/lib/**/*.js",
9
+ "/lib/**/*.d.ts"
9
10
  ],
10
11
  "repository": {
11
12
  "type": "git",