Skip to content

Commit 7c0fe1e

Browse files
committed
Added support for intercepting GetJavaVM, support for outputing arguments in jvalue arrays and a version command line option
1 parent d148011 commit 7c0fe1e

File tree

5 files changed

+83
-21
lines changed

5 files changed

+83
-21
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# jnitrace Change Log
22

3+
## 1.3.0
4+
- Added a command argument to get the version of jnitrace
5+
- jnitrace now intercepts calls to GetJavaVM, returning a shadowJavaVM
6+
- Added support for extracting arguments stored in jvalue arrays
7+
38
## 1.2.1
4-
- Bug fix so more than CallStaticObjectMethod was intercepted
9+
- Bug fix - CallStaticObjectMethod was the only va args method intercepted
510

611
## 1.2.0
712
- Added arm64 architecture support

jnitrace/jnitrace.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99
import hexdump
1010

1111
from pkg_resources import resource_string
12+
from pkg_resources import require
1213

1314
from colorama import Fore, Style, init
1415

1516

17+
__version__ = require("jnitrace")[0].version
18+
1619
init()
1720

1821
PALETTE = [
@@ -224,7 +227,7 @@ def on_message(self, message, data):
224227

225228
for i, _ in enumerate(jni_args):
226229
arg_type = method["args"][i]
227-
if arg_type in ["va_list", "..."]:
230+
if arg_type in ["va_list", "...", "jvalue*"]:
228231
add_java_args = True
229232
break
230233

@@ -285,6 +288,9 @@ def _parse_args():
285288
help="Print contents of argument.")
286289
parser.add_argument("-p", "--process", required=True,
287290
help="The name of the process to trace.")
291+
parser.add_argument("-v", "--version", action='version',
292+
version="%(prog)s " + __version__,
293+
help="Show the installed version of jnitrace.")
288294
return parser.parse_args()
289295

290296
def main():

jnitrace/src/jni/jni_env_interceptor.js

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ function JNIEnvInterceptor(references, threads, transport) {
66
this.references = references;
77
this.threads = threads;
88
this.transport = transport;
9+
10+
this.javaVMInterceptor = NULL;
911
}
1012

1113
JNIEnvInterceptor.prototype.shadowJNIEnv = null;
@@ -43,7 +45,24 @@ JNIEnvInterceptor.prototype.createJNIIntercept = function(id, methodAddr) {
4345

4446
var ret = nativeFunction.apply(null, localArgs);
4547

46-
self.transport.trace(method, localArgs, ret, this.context);
48+
var add = null;
49+
50+
if (method.args[method.args.length - 1] === "jvalue*") {
51+
add = self.methods[ptr(localArgs[2])].javaParams;
52+
var jvalues = ptr(localArgs[method.args.length - 1]);
53+
localArgs = localArgs.slice(0, -1);
54+
55+
for (var i = 0; i < add.length; i++) {
56+
var val = NULL;
57+
var type = Types.convertNativeJTypeToFridaType(add[i]);
58+
59+
var val = self.readValue(jvalues.add(8 * i), type);
60+
61+
localArgs.push(val);
62+
}
63+
}
64+
65+
self.transport.trace(method, localArgs, ret, this.context, add);
4766

4867
if (method.name === "GetMethodID" ||
4968
method.name === "GetStaticMethodID") {
@@ -68,6 +87,20 @@ JNIEnvInterceptor.prototype.createJNIIntercept = function(id, methodAddr) {
6887
fridaTypes.ret = Types.convertNativeJTypeToFridaType(jTypeRet);
6988

7089
self.methods[ret] = fridaTypes;
90+
} else if (method.name === "GetJavaVM") {
91+
var javaVM = NULL;
92+
93+
if (ret === 0) {
94+
self.threads.setJavaVM(Memory.readPointer(localArgs[1]));
95+
}
96+
97+
if (!self.javaVMInterceptor.isInitialised()) {
98+
javaVM = self.javaVMInterceptor.create();
99+
} else {
100+
javaVM = self.javaVMInterceptor.get();
101+
}
102+
103+
Memory.writePointer(localArgs[1], javaVM);
71104
} else if (method.name === "RegisterNatives") {
72105
var methods = localArgs[2];
73106
var size = localArgs[3];
@@ -213,26 +246,10 @@ JNIEnvInterceptor.prototype.createJNIVaListIntercept =
213246
self.setUpVaListArgExtract(vaList);
214247

215248
for (var i = 0; i < method.params.length; i++) {
216-
var val = NULL;
217249
var currentPtr = self.extractVaListArgValue(method, i);
218250

219-
if (method.params[i] === "char") {
220-
val = Memory.readS8(currentPtr);
221-
} else if (method.params[i] === "int16") {
222-
val = Memory.readS16(currentPtr);
223-
} else if (method.params[i] === "uint16") {
224-
val = Memory.readU16(currentPtr);
225-
} else if (method.params[i] === "int") {
226-
val = Memory.readS32(currentPtr);
227-
} else if (method.params[i] === "int64") {
228-
val = Memory.readS64(currentPtr);
229-
} else if (method.params[i] === "float") {
230-
val = Memory.readDouble(currentPtr);
231-
} else if (method.params[i] === "double") {
232-
val = Memory.readDouble(currentPtr);
233-
}
251+
var val = self.readValue(currentPtr, method.params[i], true);
234252

235-
//TODO - needs to use jtype
236253
this.args.push(val);
237254
}
238255

@@ -279,6 +296,38 @@ JNIEnvInterceptor.prototype.createJNIVaListIntercept =
279296
return methodAddr;
280297
}
281298

299+
JNIEnvInterceptor.prototype.readValue = function(currentPtr, type, extend) {
300+
var val = NULL;
301+
302+
if (type === "char") {
303+
val = Memory.readS8(currentPtr);
304+
} else if (type === "int16") {
305+
val = Memory.readS16(currentPtr);
306+
} else if (type === "uint16") {
307+
val = Memory.readU16(currentPtr);
308+
} else if (type === "int") {
309+
val = Memory.readS32(currentPtr);
310+
} else if (type === "int64") {
311+
val = Memory.readS64(currentPtr);
312+
} else if (type === "float") {
313+
if (extend) {
314+
val = Memory.readDouble(currentPtr);
315+
} else {
316+
val = Memory.readFloat(currentPtr);
317+
}
318+
} else if (type === "double") {
319+
val = Memory.readDouble(currentPtr);
320+
} else if (type === "pointer") {
321+
val = Memory.readPointer(currentPtr);
322+
}
323+
324+
return val;
325+
}
326+
327+
JNIEnvInterceptor.prototype.setJavaVMInterceptor = function(javaVMInterceptor) {
328+
this.javaVMInterceptor = javaVMInterceptor;
329+
}
330+
282331
JNIEnvInterceptor.prototype.create = function() {
283332
var threadId = Process.getCurrentThreadId();
284333
var jniEnv = this.threads.getJNIEnv(threadId);

jnitrace/src/main.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ var javaVMInterceptor = new JavaVMInterceptor(
3939
jniEnvInterceptor
4040
);
4141

42+
jniEnvInterceptor.setJavaVMInterceptor(javaVMInterceptor);
43+
4244
var libsToTrack = ['*'];
4345
var trackedLibs = {};
4446
var libBlacklist = {};

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
setup(
1010
name='jnitrace',
11-
version='1.2.1',
11+
version='1.3.0',
1212
description='A tool for tracing use of the JNI in Android apps',
1313
long_description=long_description,
1414
long_description_content_type='text/markdown',

0 commit comments

Comments
 (0)