├── FastFrida.py ├── FastXposed.py ├── GotoClass.py ├── img ├── 1.png ├── 2.png └── 3.png └── readme.md /FastFrida.py: -------------------------------------------------------------------------------- 1 | # author: LeadroyaL 2 | 3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext 4 | from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit 5 | 6 | FMT = """Java.use("{class_name}") 7 | .{method_name} 8 | .overload({param_list}) 9 | .implementation = function (this, ...args) {{ // for javascript 10 | // .implementation = function (this: Java.Wrapper, ...args: any[]) {{ // for typescript 11 | console.log("before hooked {method_sig}"); 12 | let ret = this.{method_name}({args_list}); 13 | console.log("after hooked {method_sig}"); 14 | return ret; 15 | }};""" 16 | 17 | 18 | class FastFrida(IScript): 19 | def run(self, ctx): 20 | if not isinstance(ctx, IGraphicalClientContext): 21 | print ('This script must be run within a graphical client') 22 | return 23 | if not isinstance(ctx.getFocusedView().getActiveFragment().getUnit(), IJavaSourceUnit): 24 | print ('This script must be run within IJavaSourceUnit') 25 | return 26 | sig = ctx.getFocusedView().getActiveFragment().getActiveAddress() 27 | clz, method = sig.split("->") 28 | assert isinstance(clz, unicode) 29 | assert isinstance(method, unicode) 30 | params = self.split(method[method.index('(') + 1:method.index(')')]) 31 | print FMT.format( 32 | class_name=clz[1:-1].replace('/', '.'), 33 | method_name=method[0:method.index('(')], 34 | method_sig=sig, 35 | param_list=','.join([self.toFrida(x) for x in params]), 36 | args_list=self.gen_args(params)) 37 | 38 | def gen_args(self, params): 39 | return ','.join(['args[%d]' % i for i in range(len(params))]) 40 | 41 | def toFrida(self, param): 42 | # input: [I, return: "[I" 43 | # input: [Ljava/lang/String; return: "[Ljava.lang.String;" 44 | if param[0] == '[': 45 | return '"' + param.replace('/', '.') + '"' 46 | # input: Ljava/lang/String; return: "java.lang.String" 47 | # input: I, return: "int" 48 | else: 49 | if param[-1] == ';': 50 | return '"' + param[1:-1].replace('/', '.') + '"' 51 | else: 52 | return '"' + self.basicTypeMap[param[0]] + '"' 53 | 54 | basicTypeMap = {'C': u'char', 55 | 'B': u'byte', 56 | 'D': u'double', 57 | 'F': u'float', 58 | 'I': u'int', 59 | 'J': u'long', 60 | 'L': u'ClassName', 61 | 'S': u'short', 62 | 'Z': u'boolean', 63 | '[': u'Reference', 64 | } 65 | 66 | def split(self, params): 67 | ret = [] 68 | offset = 0 69 | length = len(params) 70 | while offset < length: 71 | startIdx = offset 72 | while params[offset] == '[': 73 | offset += 1 74 | char = params[offset] 75 | if char == 'L': 76 | end = params.index(';', offset) 77 | ret.append(params[startIdx: end + 1]) 78 | offset = end 79 | elif char in self.basicTypeMap: 80 | ret.append(params[startIdx: offset + 1]) 81 | offset += 1 82 | return ret 83 | -------------------------------------------------------------------------------- /FastXposed.py: -------------------------------------------------------------------------------- 1 | # author: LeadroyaL 2 | 3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext 4 | from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit 5 | 6 | FMT_NO_PARAMS = """XposedHelpers.findAndHookMethod("%s", classLoader, "%s", new XC_MethodHook() { 7 | @Override 8 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 9 | super.beforeHookedMethod(param); 10 | } 11 | @Override 12 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 13 | super.afterHookedMethod(param); 14 | } 15 | });""" 16 | 17 | FMT_WITH_PARAMS = """XposedHelpers.findAndHookMethod("%s", classLoader, "%s", %s, new XC_MethodHook() { 18 | @Override 19 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 20 | super.beforeHookedMethod(param); 21 | } 22 | @Override 23 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 24 | super.afterHookedMethod(param); 25 | } 26 | });""" 27 | 28 | 29 | class FastXposed(IScript): 30 | def run(self, ctx): 31 | if not isinstance(ctx, IGraphicalClientContext): 32 | print ('This script must be run within a graphical client') 33 | return 34 | if not isinstance(ctx.getFocusedView().getActiveFragment().getUnit(), IJavaSourceUnit): 35 | print ('This script must be run within IJavaSourceUnit') 36 | return 37 | sig = ctx.getFocusedView().getActiveFragment().getActiveAddress() 38 | clz, method = sig.split("->") 39 | assert isinstance(method, unicode) 40 | methodName = method[0:method.index('(')] 41 | params = self.split(method[method.index('(') + 1:method.index(')')]) 42 | if len(params) == 0: 43 | print FMT_NO_PARAMS % ( 44 | clz[1:-1].replace('/', '.'), 45 | methodName) 46 | else: 47 | print FMT_WITH_PARAMS % ( 48 | clz[1:-1].replace('/', '.'), methodName, 49 | ','.join([self.toXposed(x) for x in params])) 50 | 51 | def toXposed(self, param): 52 | depth = 0 53 | while param[depth] == '[': 54 | depth += 1 55 | # input: Ljava/lang/String; return: "java.lang.String" 56 | # input: [Ljava/lang/String; return: "java.lang.String[]" 57 | if param[-1] == ';': 58 | return '"' + param[depth + 1:-1].replace('/', '.') + "[]" * depth + '"' 59 | # input: I, return: int.class 60 | # input: [I, return: int[].class 61 | else: 62 | return self.basicTypeMap[param[depth]] + "[]" * depth + ".class" 63 | 64 | basicTypeMap = {'C': u'char', 65 | 'B': u'byte', 66 | 'D': u'double', 67 | 'F': u'float', 68 | 'I': u'int', 69 | 'J': u'long', 70 | 'L': u'ClassName', 71 | 'S': u'short', 72 | 'Z': u'boolean', 73 | '[': u'Reference', 74 | } 75 | 76 | def split(self, params): 77 | ret = [] 78 | offset = 0 79 | length = len(params) 80 | while offset < length: 81 | startIdx = offset 82 | while params[offset] == '[': 83 | offset += 1 84 | char = params[offset] 85 | if char == 'L': 86 | end = params.index(';', offset) 87 | ret.append(params[startIdx: end + 1]) 88 | offset = end 89 | elif char in self.basicTypeMap: 90 | ret.append(params[startIdx: offset + 1]) 91 | offset += 1 92 | return ret 93 | -------------------------------------------------------------------------------- /GotoClass.py: -------------------------------------------------------------------------------- 1 | # author = LeadroyaL 2 | 3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext, IUnitView, IUnitFragment 4 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IApkUnit 5 | from com.pnfsoftware.jeb.core.units.code.android.dex import IDexClass 6 | 7 | class GotoClass(IScript): 8 | def run(self, ctx): 9 | if not isinstance(ctx, IGraphicalClientContext): 10 | print ('This script must be run within a graphical client') 11 | return 12 | 13 | apk = None 14 | for u in ctx.getEnginesContext().getProject(0).getLiveArtifact(0).getUnits(): 15 | if isinstance(u, IApkUnit): 16 | apk = u 17 | break 18 | if not apk: 19 | print('APK unit not found') 20 | return 21 | # auto completed with focusText 22 | focusText = ctx.getFocusedView().getActiveFragment().getActiveItemAsText() 23 | className = ctx.displayQuestionBox("ClassName", 24 | "input class name(eg. com.test.classname, Lcom/test/classname;):", 25 | focusText) 26 | if not className: 27 | print ('Please input classname') 28 | return 29 | 30 | self.goto(ctx, apk, className) 31 | 32 | print ('Run script finished') 33 | 34 | def goto(self, ctx, apk, className): 35 | assert isinstance(apk, IApkUnit) 36 | dexUnit = None 37 | dexClass = None 38 | if className[0] == 'L' and className[-1] == ';': 39 | genericName = className 40 | else: 41 | genericName = 'L' + className.replace('.', '/') + ';' 42 | for u in apk.getChildren(): 43 | if isinstance(u, IDexUnit): 44 | dexClass = u.getClass(genericName) 45 | if dexClass: 46 | dexUnit = u 47 | print ("FIND %s AT %s" % (genericName, u.getName())) 48 | break 49 | 50 | if not dexClass or not dexUnit: 51 | print("CANNOT FIND %s" % genericName) 52 | return 53 | 54 | assert isinstance(dexClass, IDexClass) 55 | assert isinstance(dexUnit, IDexUnit) 56 | 57 | # open disasembly view 58 | if not ctx.openView(dexUnit): 59 | print("open disasembly fail") 60 | return 61 | 62 | # focus it 63 | disasmFragment = None 64 | for view in ctx.getViews(): 65 | assert isinstance(view, IUnitView) 66 | if view.getUnit() == dexUnit: 67 | for fragment in view.getFragments(): 68 | if view.getFragmentLabel(fragment) == 'Disassembly': 69 | view.setFocus() 70 | view.setActiveFragment(fragment) 71 | disasmFragment = fragment 72 | 73 | if not disasmFragment: 74 | print ('Disassembly fragment for %s not found' % dexUnit.getName()) 75 | return 76 | 77 | assert isinstance(disasmFragment, IUnitFragment) 78 | disasmFragment.setActiveAddress(genericName) 79 | -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeadroyaL/JebScript/93514527f3b3afc8bd1c76eae30237ae216217ce/img/1.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeadroyaL/JebScript/93514527f3b3afc8bd1c76eae30237ae216217ce/img/2.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeadroyaL/JebScript/93514527f3b3afc8bd1c76eae30237ae216217ce/img/3.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## GotoClass 2 | 3 | 背景:JEB2自带的'J'和JEB3自带的'G'不大好用,有两个不好用的地方 4 | 5 | 1. 一定要在对应的那个 `Disassembly` 里按下快捷键,尤其是multi-dex可能需要挨个翻 6 | 2. 一定要输入 `Lxxx/xxx/xxx;` 格式的类名 7 | 8 | 用途: 9 | 10 | 1. 输入两种格式的类名,都可以跳到对应 `Disassembly` 界面的位置,一键运行。 11 | 2. 在任意界面尝试调用 script,默认输入是当前 focus 的内容。有时可以省去输入,例如从 Manifest 跳转到实现时。 12 | 13 | ![](img/1.png) 14 | 15 | ## FastXposed / FastFrida 16 | 17 | 背景:Xposed/Frida手抄一遍太麻烦。 18 | 19 | 用途:光标锁定到要Xposed的函数上,执行脚本,从输出框复制文本即可。 20 | 21 | ![](img/2.png) 22 | 23 | ![](img/3.png) 24 | 25 | ## 其他人写的有用的工具 26 | 27 | [https://raw.githubusercontent.com/S3cuRiTy-Er1C/JebScripts](https://raw.githubusercontent.com/S3cuRiTy-Er1C/JebScripts) 通过sourceInfo恢复类名,兼容jeb2和jeb3的API 28 | --------------------------------------------------------------------------------