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 +5 -0
- package/lib/android.d.ts +33 -0
- package/lib/android.js +110 -3
- package/lib/jvm.js +2 -2
- package/package.json +3 -2
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');
|
package/lib/android.d.ts
ADDED
|
@@ -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
|
-
|
|
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
|
-
|
|
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.
|
|
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",
|