-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
174 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Load | ||
|
||
File -> Run Script | ||
|
||
|
||
# Logging | ||
|
||
``` | ||
[+] plugin start, bv=<BinaryView: '/root/jni_helper/assets/lib/arm64-v8a/libdemoc.so', len 0x2a88> | ||
[+] init_header done. | ||
[+] fix 0x3708 JNI_OnLoad -> jint(JavaVM* vm, void* reserved) | ||
[+] fix 0x4980 JNI_OnUnload -> void(JavaVM* vm, void* reserved) | ||
[+] fix 0x5388 Java_com_evilpan_demoapk_FacadeC_testStatic -> jint(JNIEnv* env, jclass clazz, jint a1) | ||
[+] fix 0x5044 Java_com_evilpan_demoapk_FacadeC_stringFromJNI -> jstring(JNIEnv* env, jobject thiz) | ||
[+] fix 0x5916 Java_com_evilpan_demoapk_FacadeC_testArray -> void(JNIEnv* env, jobject thiz, jintArray a1) | ||
[+] fix 0x5468 Java_com_evilpan_demoapk_FacadeC_testClass -> jint(JNIEnv* env, jobject thiz, jobject a1) | ||
[+] fix 0x5144 Java_com_evilpan_demoapk_FacadeC_testOverload__ -> jint(JNIEnv* env, jobject thiz) | ||
[+] fix 0x5220 Java_com_evilpan_demoapk_FacadeC_testOverload__I -> jint(JNIEnv* env, jobject thiz, jint a1) | ||
[+] fix 0x5300 Java_com_evilpan_demoapk_FacadeC_testOverload__JFD -> jint(JNIEnv* env, jobject thiz, jlong a1, jfloat a2, jdouble a3) | ||
``` | ||
|
||
High Level IL: | ||
|
||
Before => | ||
|
||
![b1][b1] | ||
|
||
After => | ||
|
||
![b3][b3] | ||
|
||
Pseudo C: | ||
|
||
Before => | ||
|
||
![b2][b2] | ||
|
||
After => | ||
|
||
![b4][b4] | ||
|
||
|
||
[b1]: https://i-blog.csdnimg.cn/direct/1a68a50684ef4151a7c6b7442599f295.png | ||
[b2]: https://i-blog.csdnimg.cn/direct/56fb96fdf46a42b8ad5a79367df0b78f.png | ||
[b3]: https://i-blog.csdnimg.cn/direct/6de69105b83c4a9197cbad513ed4fe94.png | ||
[b4]: https://i-blog.csdnimg.cn/direct/58a77ec9f9a54e86871b5325ab5f1333.png |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import json | ||
import os | ||
import binaryninja | ||
from binaryninja.interaction import ( | ||
OpenFileNameField, | ||
get_form_input, | ||
show_message_box, | ||
) | ||
|
||
def log(msg, *args, **kwargs): | ||
print("[+]", msg, *args, **kwargs) | ||
|
||
class JNIHelper: | ||
|
||
def __init__(self): | ||
self.jni_header = "" | ||
|
||
def start(self): | ||
if not self.init_header(): | ||
return | ||
self.apply_signatures() | ||
|
||
def init_header(self): | ||
options = ["-fdeclspec"] | ||
jni_file = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "headers", "jni.h") | ||
if not os.path.exists(jni_file): | ||
jni_file = self.choose_file("jni.h not found, choose one") | ||
if jni_file is None: | ||
return | ||
with open(jni_file, 'r') as f: | ||
self.jni_header = f.read() | ||
pr = self.parse_source(self.jni_header, "jni.h") | ||
if not pr: | ||
return False | ||
log("init_header done.") | ||
return True | ||
|
||
def parse_source(self, source, name="<source>"): | ||
options = ["-fdeclspec"] | ||
result, errors = TypeParser.default.parse_types_from_source( | ||
source, name, bv.platform, | ||
options=options | ||
) | ||
if result is None: | ||
log("parse error:") | ||
for err in errors: | ||
log(err, end='') | ||
return None | ||
return result | ||
|
||
def choose_file(self, desc, title="File"): | ||
fd = OpenFileNameField(desc) | ||
if get_form_input([fd], title): | ||
return fd.result | ||
return None | ||
|
||
def apply_signatures(self): | ||
file = self.choose_file("signature.json from extract_jni.py") | ||
if not file: | ||
return | ||
with open(file, 'r') as f: | ||
meta = json.load(f) | ||
jni_ext = self.jni_header + "\n" | ||
func_map = {} | ||
for cls, methods in meta["dexInfo"].items(): | ||
for method in methods: | ||
mangle = method["mangle"] | ||
found = bv.get_functions_by_name(mangle) | ||
if not found: | ||
continue | ||
func = found[0] | ||
func_map[mangle] = func | ||
# skip those already defined | ||
ret = method["ret"] | ||
args = ",".join(method["args"]) | ||
line = f"{ret} {mangle}({args})" | ||
if cls == "__COMMON__": | ||
continue | ||
jni_ext += line + ";\n" | ||
pr = self.parse_source(jni_ext, "jni_ext.h") | ||
if pr is None: | ||
return | ||
for pt in pr.types: | ||
bv.define_user_type(pt.name, pt.type) | ||
for pf in pr.functions: | ||
if pf.name not in func_map: | ||
continue | ||
func = func_map[pf.name] | ||
log(f"fix 0x{func.start} {pf.name} -> {pf.type}") | ||
func.type = pf.type | ||
func.reanalyze() | ||
|
||
|
||
log(f"plugin start, bv={bv}") | ||
jh = JNIHelper() | ||
jh.start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters