From 0102391670f4996d4b2b9b81495087c628c17a0e Mon Sep 17 00:00:00 2001 From: iddoeldor Date: Wed, 4 Nov 2020 11:04:58 +0200 Subject: [PATCH] Create FridaCodeGenerator.py --- scripts/FridaCodeGenerator.py | 148 ++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 scripts/FridaCodeGenerator.py diff --git a/scripts/FridaCodeGenerator.py b/scripts/FridaCodeGenerator.py new file mode 100644 index 0000000..b377b5c --- /dev/null +++ b/scripts/FridaCodeGenerator.py @@ -0,0 +1,148 @@ +#?shortcut=Mod1+Shift+Z +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from com.pnfsoftware.jeb.client.api import IScript +from com.pnfsoftware.jeb.core import RuntimeProjectUtil +from com.pnfsoftware.jeb.core.units.code.android import IDexUnit +from subprocess import Popen, PIPE + + +def arg_format(i): + return 'arg_%d' % i + + +def generate_body_code(types, retval, method_name, orig_method_name, class_name): + body_code = "\n\tconsole.log('[{}#{}] ' + JSON.strigify({{\n\t".format( + FridaCodeGenerator.to_canonical_name(class_name), method_name) + for i, typ in enumerate(types): + body_code += '\t{}: {}, // {}\n\t'.format('a%d' % i, arg_format(i), typ) + + if retval != 'void': + body_code = '\n\tvar retval = this.{}.apply(this, arguments);{}\tretv: retval\n\t}});'.format( + orig_method_name, body_code) + else: + body_code += '}});\n\tthis.{}.apply(this, arguments);'.format(method_name) + + return body_code + '\n' + + +class JavaMethod(object): + def __init__(self): + self.class_name = None + self.class_orig_name = None + self.name = None + self.orig_name = None + self.arg = [] + self.retType = None + + def get_parameters(self): + return self.arg + + def get_return_type(self): + return self.retType + + def get_name(self): + return self.name + + def get_orig_name(self): + return self.orig_name + + def get_class_orig_name(self): + return self.class_orig_name + + def get_class_name(self): + return self.class_name + + def __str__(self): + return 'JavaMethod[name: %s, orig_name: %s, args: %s, return type: %s]' % ( + self.name, self.orig_name, self.arg, self.retType) + + +class FridaCodeGenerator(IScript): + + @staticmethod + def to_canonical_name(mname): + mname = mname.replace('/', '.') + return { + 'C': 'char', + 'I': 'int', + 'B': 'byte', + 'Z': 'boolean', + 'F': 'float', + 'D': 'double', + 'S': 'short', + 'J': 'long', + 'V': 'void', + 'L': mname[1:-1], + '[': mname + }[mname[0]] + + def run(self, ctx): + project = ctx.getEnginesContext().getProjects()[0] # Get current project(IRuntimeProject) + self.dexunit = RuntimeProjectUtil.findUnitsByType(project, IDexUnit, False)[0] # Get dex context, needs >=V2.2.1 + try: + self.current_unit = ctx.getFocusedView().getActiveFragment().getUnit() # Get current Source Tab in Focus + java_class = self.current_unit.getClassElement().getName() + current_addr = ctx.getFocusedView().getActiveFragment().getActiveAddress() + m = FridaCodeGenerator.get_decompiled_method(self.dexunit, current_addr, java_class) + method_name = m.get_name() + class_name = FridaCodeGenerator.to_canonical_name(m.get_class_orig_name()) + return_type = FridaCodeGenerator.to_canonical_name(str(m.get_return_type())) + if method_name == '': + raise Exception('Class initializer') + args_code = ', '.join([arg_format(i) for i in range(len(m.get_parameters()))]) + + if method_name == '': method_name = '$init' + + types = [FridaCodeGenerator.to_canonical_name(param) for param in m.get_parameters()] + # TODO get original type class names + type_code = ', '.join(["'{0}'".format(t) for t in types]) + body_code = generate_body_code(types, return_type, method_name, m.get_orig_name(), m.get_class_name()) + hook = "Java.use('{class_name}').{method}.overload({sig}).implementation = function({args}) {{{body}}}".format( + class_name=class_name, + method=m.get_orig_name() if method_name != '$init' else method_name, + sig=type_code, + args=args_code, + body=body_code + ) + print(hook) + # copy to system's clipboard + Popen(['xclip', '-sel', 'c', '-i'], stdin=PIPE).communicate(input=(hook.encode())) + except Exception as e: + print(e) + ctx.displayMessageBox(None, 'Place the cursor in the function you want to generate the Frida code', None, None) + + @staticmethod + def get_decompiled_method(dex, addr, class_orig_name): + method_info = JavaMethod() + method_info.orig_name = dex.getMethod(addr).getName(False) + msig = addr.split('+')[0] + infos = str(msig).split('->') + if len(infos) == 2: + method_info.class_name = infos[0] + method_info.class_orig_name = class_orig_name + if len(infos[1].split('(')) == 2: + method_info.name = infos[1].split('(')[0] + if len(infos[1].split(')')) == 2: + method_info.retType = infos[1].split(')')[1] + if len(infos[1].split('(')) == 2 and len(infos[1].split(')')) == 2: + args = infos[1].split('(')[-1].split(')')[0] + while args: + if args[0] in ['C', 'I', 'B', 'Z', 'F', 'D', 'S', 'J', 'V']: + method_info.arg.append(str(args[0])) + args = args[1:] + elif args[0] == '[': + if args[1] == 'L': + offset = args.find(';') + method_info.arg.append(str(args[0:offset + 1])) + args = args[offset + 1:] + else: + method_info.arg.append(str(args[0:2])) + args = args[2:] + elif args[0] == 'L': + offset = args.find(";") + method_info.arg.append(str(args[0:offset + 1])) + args = args[offset + 1:] + print(method_info) + return method_info