├── LICENSE ├── README.md └── samples ├── 11 IDexUnit-DEX Class.py ├── 12 IDexUnit-Field Method .py ├── 13 IDexUnit-SingleMethod.py ├── 14 IDexUnit-Insn.py ├── 15 IDexUnit-BasicBlock.py ├── 16 IDexUnit-CFG.py ├── 21 IDexDecompilerUnit-decompile.py ├── 31 IJavaSourceUnit-DisplayAstTree.py ├── 32 IJavaSourceUnit-IJavaIf.py ├── 33 IJavaSourceUnit-IJavaCall.py ├── 34 IJavaSourceUnit-IJavaTry.py ├── 35 IJavaSourceUnit-IJavaFor.py ├── 41 INativeCodeUnit-Function.py ├── 42 INativeCodeUnit-Insn.py ├── 43 INativeCodeUnit-BasicBlock.py ├── 44 INativeCodeUnit-CFG.py ├── 51 INativeSourceUnit-DisplayAstTree.py ├── 52 INativeSourceUnit-ICIfStm.py ├── 61 Dex-QUERY_XREFS.py ├── 62 Native-Callees Callers.py ├── 63 Native-CrossReference.py └── 64 Native-Contain.py /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2020, aichibocai 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jeb_script 2 | 一些常用的基础的代码分析操作,可用于反混淆/路径分析/代码定位等 3 | 4 | 5 | https://bbs.pediy.com/thread-263011.htm 6 | 7 | https://bbs.pediy.com/thread-263012.htm 8 | -------------------------------------------------------------------------------- /samples/11 IDexUnit-DEX Class.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IScript, IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject, ILiveArtifact, IEnginesContext 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDexDecompilerUnit 6 | 7 | # 访问DEX与Class 8 | def Test(ctx): 9 | assert isinstance(ctx,IClientContext) 10 | input_path = r"D:\tmp\2\project\about_dex_diff\code\taobao\taobao.apk" 11 | sign = "Lcom/taobao/android/diva/core/BitmapProvider;" 12 | 13 | # JEB打开APK 14 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 15 | 16 | # 获取JEB加载的项目实例 17 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 18 | 19 | # 访问DEX(DEX被合并,产生了一个虚拟DEX单元) 20 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit) 21 | 22 | # 访问DEX中Class 23 | cls = dexUnit.getClass(sign) 24 | print ">>> ",cls.getSignature() 25 | 26 | # 输出 27 | # >>> Lcom/taobao/android/diva/core/BitmapProvider; -------------------------------------------------------------------------------- /samples/12 IDexUnit-Field Method .py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IScript, IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject, ILiveArtifact, IEnginesContext 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDexDecompilerUnit 6 | from com.pnfsoftware.jeb.core.units.code.android.dex import IDexClass, IDexField, IDexMethod 7 | 8 | 9 | # 遍历Field / Method 10 | def Test(ctx): 11 | assert isinstance(ctx,IClientContext) 12 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.apk" 13 | sign = "Lcom/BestCalculatorCN/MyCalculator;" 14 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 15 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 16 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit) 17 | dexClass = dexUnit.getClass(sign); assert isinstance(dexClass,IDexClass) 18 | 19 | # 遍历属性 20 | for field in dexClass.getFields(): 21 | assert isinstance(field,IDexField) 22 | print ">>> ",field.getSignature() 23 | print "----" 24 | 25 | # 遍历方法 26 | for method in dexClass.getMethods(): 27 | assert isinstance(method,IDexMethod) 28 | print ">>> ",method.getSignature() 29 | 30 | # 输出 31 | # >>> Lcom/BestCalculatorCN/MyCalculator;->()V 32 | # >>> Lcom/BestCalculatorCN/MyCalculator;->a(Ljava/lang/String;)D 33 | # >>> Lcom/BestCalculatorCN/MyCalculator;->a(Lcom/BestCalculatorCN/MyCalculator;)Ljava/lang/String; 34 | # >>> Lcom/BestCalculatorCN/MyCalculator;->a(Lcom/BestCalculatorCN/MyCalculator;D)V 35 | # >>> Lcom/BestCalculatorCN/MyCalculator;->a(Lcom/BestCalculatorCN/MyCalculator;Lcom/BestCalculatorCN/ar;)V -------------------------------------------------------------------------------- /samples/13 IDexUnit-SingleMethod.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit 6 | 7 | 8 | # 访问某个Method 9 | def Test(ctx): 10 | assert isinstance(ctx,IClientContext) 11 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.apk" 12 | method_sign = "Lnet/cavas/show/af;->a(Lorg/apache/http/client/HttpClient;Ljava/util/Queue;)V" 13 | 14 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 15 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 16 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit) 17 | 18 | # 某方法内容 19 | method = dexUnit.getMethod(method_sign) 20 | print "-----------------------------------------------" 21 | print "1 ClassType >>> ",method.getClassType() 22 | print "2 ReturnType >>> ",method.getReturnType() 23 | print "3 getName >>> ",method.getName() 24 | print "4 getSignature >>> ",method.getSignature() 25 | print "5 getParameterTypes >>> " 26 | for parm in method.getParameterTypes(): 27 | print ">>> ",parm 28 | print "6 isInternal >>> ",method.isInternal() 29 | print "7 isArtificial >>> ",method.isArtificial() 30 | print "-----------------------------------------------" 31 | 32 | # 输出 33 | # ----------------------------------------------- 34 | # 1 ClassType >>> Type:#237,name=af,address=Lnet/cavas/show/af; 35 | # 2 ReturnType >>> Type:#341,name=V,address=V 36 | # 3 getName >>> a 37 | # 4 getSignature >>> Lnet/cavas/show/af;->a(Lorg/apache/http/client/HttpClient;Ljava/util/Queue;)V 38 | # 5 getParameterTypes >>> 39 | # >>> Type:#325,name=HttpClient,address=Lorg/apache/http/client/HttpClient; 40 | # >>> Type:#216,name=Queue,address=Ljava/util/Queue; 41 | # 6 isInternal >>> True 42 | # 7 isArtificial >>> False 43 | # ----------------------------------------------- -------------------------------------------------------------------------------- /samples/14 IDexUnit-Insn.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code import IFlowInformation, IEntryPointDescription 6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit 7 | from com.pnfsoftware.jeb.core.units.code.android.dex import IDexMethod, IDexClass, IDexMethodData, IDexCodeItem, \ 8 | IDalvikInstruction 9 | 10 | # 访问指令 11 | def Test(ctx): 12 | assert isinstance(ctx,IClientContext) 13 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.dex" 14 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 15 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 16 | sign = "Lcom/BestCalculatorCN/MyCalculator;" 17 | sign2 = "Lnet/cavas/show/af;->a(Lorg/apache/http/client/HttpClient;Ljava/util/Queue;)V" 18 | 19 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit); 20 | clz = dexUnit.getClass(sign); assert isinstance(clz,IDexClass); 21 | method = dexUnit.getMethod(sign2); assert isinstance(method,IDexMethod) 22 | dexMethodData = method.getData(); assert isinstance(dexMethodData,IDexMethodData) 23 | dexCodeItem= dexMethodData.getCodeItem(); assert isinstance(dexCodeItem,IDexCodeItem) 24 | 25 | # 方法的指令序列信息 26 | print "1 RegisterCount >>> ", dexCodeItem.getRegisterCount() 27 | print "2 InputArgumentCount >>> ", dexCodeItem.getInputArgumentCount() 28 | print "3 OutputArgumentCount >>> ", dexCodeItem.getOutputArgumentCount() 29 | print "4 ExceptionItems >>> ", dexCodeItem.getExceptionItems() 30 | print "5 InstructionsOffset >>> ", dexCodeItem.getInstructionsOffset() 31 | print "6 InstructionsSize >>> ", dexCodeItem.getInstructionsSize() 32 | print "7 isCompleteBytecode >>> ", dexCodeItem.isCompleteBytecode() 33 | 34 | # DVM单个指令信息 35 | print "8 Instructions:", 36 | print 37 | for idx,insn in enumerate(dexCodeItem.getInstructions()): 38 | assert isinstance(insn,IDalvikInstruction) 39 | print insn 40 | print idx,"(01) getCode >>> ",insn.getCode() # 二进制 41 | print idx,"(02) getOpcode >>> ",insn.getOpcode() # 操作码 42 | print idx,"(03) getParameters:" # 指令操作数 43 | for a,b in enumerate(insn.getParameters()): 44 | print "<",a,">",b.getType(),b.getValue() 45 | print idx,"(04) getParameterFirstIndexType >>> ",insn.getParameterFirstIndexType()# 指令索引参数 池类型 46 | print idx,"(05) getParameterSecondIndexType >>> ",insn.getParameterSecondIndexType() 47 | print idx,"(06) isPseudoInstruction >>> ",insn.isPseudoInstruction() # 伪指令 48 | print idx,"(07) isSwitch >>> ",insn.isSwitch() 49 | print idx,"(08) isArray >>> ",insn.isArray() 50 | print idx,"(99) getSwitchData >>> ",insn.getSwitchData() 51 | print idx,"(10) getArrayData >>> ",insn.getArrayData() 52 | 53 | print idx,"(11) getProcessorMode >>> ",insn.getProcessorMode() # 处理模式 54 | print idx,"(12) getSize >>> ",insn.getSize() # 指令size 55 | print idx,"(13) getPrefix >>> ",insn.getPrefix() # 指令可选前缀 56 | print idx,"(14) getMnemonic >>> ",insn.getMnemonic() # 助记符 57 | print idx,"(15) getOperands >>> ",insn.getOperands() # 操作数列表 58 | print idx,"(16) canThrow >>> ",insn.canThrow() # 指令是否可以引发异常 59 | print idx,"(17) isConditional >>> ",insn.isConditional() # 条件执行 60 | print("") 61 | 62 | # 指令是否中断了执行流 63 | print idx,"(18) getBreakingFlow:" 64 | iflowInformation = insn.getBreakingFlow(); assert isinstance(iflowInformation,IFlowInformation) 65 | print "BreakingFlow.isBroken >>> ",iflowInformation.isBroken() # 确定此对象是否包含流信息 66 | print "BreakingFlow.isBrokenUnknown >>> ",iflowInformation.isBrokenUnknown() # 确定此对象是否包含流信息,但没有已知的目标 67 | print "BreakingFlow.isBrokenKnown >>> ",iflowInformation.isBrokenKnown() # 确定此对象是否包含流信息,目标已知 68 | print "BreakingFlow.mustComputeFallThrough >>> ",iflowInformation.mustComputeFallThrough() # 指示流信息是否包含一个直达地址 69 | print "BreakingFlow.getDelaySlotCount >>> ",iflowInformation.getDelaySlotCount() # 获取延迟槽中的指令数 70 | print "BreakingFlow.getTargets:" 71 | if iflowInformation.getTargets() is not None: 72 | for a,b in enumerate(iflowInformation.getTargets()): 73 | assert isinstance(b,IEntryPointDescription) 74 | print "<",a,">","BreakingFlow.getMode >>> ",b.getMode() 75 | print "<",a,">","BreakingFlow.isUnknownAddress >>> ",b.isUnknownAddress() 76 | print "<",a,">","BreakingFlow.getAddress >>> ",b.getAddress() 77 | print("") 78 | 79 | # 指令是否分支(或调用)到子例程(和18一样的代码) 80 | print idx,"(19) getRoutineCall:" 81 | iflowInformation = insn.getRoutineCall(); assert isinstance(iflowInformation,IFlowInformation) 82 | print "RoutineCall.isBroken >>> ",iflowInformation.isBroken() 83 | print "RoutineCall.isBrokenUnknown >>> ",iflowInformation.isBrokenUnknown() 84 | print "RoutineCall.isBrokenKnown >>> ",iflowInformation.isBrokenKnown() 85 | print "RoutineCall.mustComputeFallThrough >>> ",iflowInformation.mustComputeFallThrough() 86 | print "RoutineCall.getDelaySlotCount >>> ",iflowInformation.getDelaySlotCount() 87 | print "RoutineCall.getTargets:" 88 | if iflowInformation.getTargets() is not None: 89 | for a,b in enumerate(iflowInformation.getTargets()): 90 | assert isinstance(b,IEntryPointDescription) 91 | print "<",a,">","RoutineCall.getMode >>> ",b.getMode() 92 | print "<",a,">","RoutineCall.isUnknownAddress >>> ",b.isUnknownAddress() 93 | print "<",a,">","RoutineCall.getAddress >>> ",b.getAddress() 94 | print("") 95 | 96 | # 确定一条指令,是否间接分支(调用)子例程(和18一样的代码) 97 | print idx,"(20) getIndirectRoutineCall:" 98 | iflowInformation = insn.getIndirectRoutineCall(); assert isinstance(iflowInformation,IFlowInformation) 99 | print "IndirectRoutineCall.isBroken >>> ",iflowInformation.isBroken() 100 | print "IndirectRoutineCall.isBrokenUnknown >>> ",iflowInformation.isBrokenUnknown() 101 | print "IndirectRoutineCall.isBrokenKnown >>> ",iflowInformation.isBrokenKnown() 102 | print "IndirectRoutineCall.mustComputeFallThrough >>> ",iflowInformation.mustComputeFallThrough() 103 | print "IndirectRoutineCall.getDelaySlotCount >>> ",iflowInformation.getDelaySlotCount() 104 | print "IndirectRoutineCall.getTargets:" 105 | if iflowInformation.getTargets() is not None: 106 | for a,b in enumerate(iflowInformation.getTargets()): 107 | assert isinstance(b,IEntryPointDescription) 108 | print "<",a,">","IndirectRoutineCall.getMode >>> ",b.getMode() 109 | print "<",a,">","IndirectRoutineCall.isUnknownAddress >>> ",b.isUnknownAddress() 110 | print "<",a,">","IndirectRoutineCall.getAddress >>> ",b.getAddress() 111 | print("") 112 | print("----------------------------------------------------------------------------") 113 | break 114 | # 输出 115 | # 1 RegisterCount >>> 8 116 | # 2 InputArgumentCount >>> 3 117 | # 3 OutputArgumentCount >>> 3 118 | # 4 ExceptionItems >>> [try=[52h-9Ah[ handlers=[9Ch:324, B2h:165, AEh:X], try=[9Eh-ACh[ handlers=[AEh:X], try=[B4h-C2h[ handlers=[AEh:X]] 119 | # 5 InstructionsOffset >>> 66644 120 | # 6 InstructionsSize >>> 196 121 | # 7 isCompleteBytecode >>> True 122 | # 8 Instructions: 123 | # invoke-interface 124 | # 0 (01) getCode >>> array('b', [114, 16, 116, 2, 7, 0]) 125 | # 0 (02) getOpcode >>> 114 126 | # 0 (03) getParameters: 127 | # < 0 > 2 628 128 | # < 1 > 0 7 129 | # 0 (04) getParameterFirstIndexType >>> 19 130 | # 0 (05) getParameterSecondIndexType >>> 0 131 | # 0 (06) isPseudoInstruction >>> False 132 | # 0 (07) isSwitch >>> False 133 | # 0 (08) isArray >>> False 134 | # 0 (99) getSwitchData >>> None 135 | # 0 (10) getArrayData >>> None 136 | # 0 (11) getProcessorMode >>> 0 137 | # 0 (12) getSize >>> 6 138 | # 0 (13) getPrefix >>> None 139 | # 0 (14) getMnemonic >>> invoke-interface 140 | # 0 (15) getOperands >>> array(com.pnfsoftware.jebglobal.hy, [t=2,v=628, t=0,v=7]) 141 | # 0 (16) canThrow >>> True 142 | # 0 (17) isConditional >>> False 143 | 144 | # 0 (18) getBreakingFlow: 145 | # BreakingFlow.isBroken >>> False 146 | # BreakingFlow.isBrokenUnknown >>> False 147 | # BreakingFlow.isBrokenKnown >>> False 148 | # BreakingFlow.mustComputeFallThrough >>> False 149 | # BreakingFlow.getDelaySlotCount >>> 0 150 | # BreakingFlow.getTargets: 151 | 152 | # 0 (19) getRoutineCall: 153 | # RoutineCall.isBroken >>> False 154 | # RoutineCall.isBrokenUnknown >>> False 155 | # RoutineCall.isBrokenKnown >>> False 156 | # RoutineCall.mustComputeFallThrough >>> False 157 | # RoutineCall.getDelaySlotCount >>> 0 158 | # RoutineCall.getTargets: 159 | 160 | # 0 (20) getIndirectRoutineCall: 161 | # IndirectRoutineCall.isBroken >>> False 162 | # IndirectRoutineCall.isBrokenUnknown >>> False 163 | # IndirectRoutineCall.isBrokenKnown >>> False 164 | # IndirectRoutineCall.mustComputeFallThrough >>> False 165 | # IndirectRoutineCall.getDelaySlotCount >>> 0 166 | # IndirectRoutineCall.getTargets: 167 | # ---------------------------------------------------------------------------- -------------------------------------------------------------------------------- /samples/15 IDexUnit-BasicBlock.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit 6 | from com.pnfsoftware.jeb.core.units.code.android.controlflow import BasicBlock 7 | from com.pnfsoftware.jeb.core.units.code.android.dex import IDexMethodData, IDexCodeItem, IDalvikInstruction, IDexMethod 8 | 9 | 10 | # 访问基本块 11 | def Test(ctx): 12 | assert isinstance(ctx,IClientContext) 13 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.dex" 14 | sign = "Lnet/cavas/show/aa;->compare(Ljava/lang/Object;Ljava/lang/Object;)I" 15 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 16 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 17 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit); 18 | method = dexUnit.getMethod(sign); assert isinstance(method,IDexMethod) 19 | dexMethodData = method.getData(); assert isinstance(dexMethodData,IDexMethodData) 20 | dexCodeItem= dexMethodData.getCodeItem(); assert isinstance(dexCodeItem,IDexCodeItem) 21 | 22 | # 指令序列 23 | print("-------------------------------------") 24 | for idx,insn in enumerate(dexCodeItem.getInstructions()): 25 | assert isinstance(insn,IDalvikInstruction) 26 | print(idx,hex(insn.getOffset()),insn.getMnemonic()) 27 | 28 | # 控制流图 29 | print("-------------------------------------") 30 | cfg = dexCodeItem.getControlFlowGraph() 31 | print(cfg) 32 | 33 | # 基本块信息 34 | print("-------------------------------------") 35 | blockList = cfg.getBlocks() 36 | for block in blockList: 37 | assert isinstance(block,BasicBlock) 38 | print "01 getFirstAddress >>> ", hex(block.getFirstAddress()) # 入口指令偏移 39 | print "02 getEndAddress >>> ", hex(block.getEndAddress()) # 出口指令偏移 40 | print "03 getLast >>> ", block.getLast() # 最后一条指令 41 | print "04 getLastAddress >>> ", hex(block.getLastAddress()) # 最后一条指令偏移 42 | print "05 size >>> ", block.size() # 指令条数 43 | print "06 getInstructions >>> ", block.getInstructions() # 指令序列 44 | 45 | print "07 allinsize >>> ", block.allinsize() # 前驱个数 46 | print "08 insize >>> ", block.insize() # 规则前驱个数 47 | print "09 irrinsize >>> ", block.irrinsize() # 不规则前驱个数 48 | 49 | print "10 alloutsize >>> ", block.alloutsize() # 后继个数 50 | print "11 outsize >>> ", block.outsize() # 规则后继个数 51 | print "12 irroutsize >>> ", block.irroutsize() # 不规则后继个数 52 | 53 | print "13 getAllInputBlocks >>> ", block.getAllInputBlocks() # 所有前驱块 54 | print "14 getInputBlocks >>> ", block.getInputBlocks() # 常规前驱块 55 | print "15 getIrregularInputBlocks >>> ", block.getIrregularInputBlocks() # 不规则前驱块 56 | 57 | print "16 getAllOutputBlocks >>> ", block.getAllOutputBlocks() # 所有后继块 58 | print "17 getOutputBlocks >>> ", block.getOutputBlocks() # 常规后继块 59 | print "18 getIrregularOutputBlocks >>> ", block.getIrregularOutputBlocks() # 不规则后继块 60 | 61 | print block.getAddress() 62 | print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") 63 | 64 | # 输出 65 | # ------------------------------------- 66 | # (0, '0x0L', u'check-cast') 67 | # (1, '0x4L', u'check-cast') 68 | # (2, '0x8L', u'iget') 69 | # (3, '0xcL', u'iget') 70 | # (4, '0x10L', u'if-ge') 71 | # (5, '0x14L', u'const/4') 72 | # (6, '0x16L', u'return') 73 | # (7, '0x18L', u'iget') 74 | # (8, '0x1cL', u'iget') 75 | # (9, '0x20L', u'if-le') 76 | # (10, '0x24L', u'const/4') 77 | # (11, '0x26L', u'goto') 78 | # (12, '0x28L', u'const/4') 79 | # (13, '0x2aL', u'goto') 80 | # ------------------------------------- 81 | # CFG(6): (0-10,5), (14-14,1), (16-16,1), (18-20,3), (24-26,2), (28-2A,2) 82 | # ------------------------------------- 83 | # 01 getFirstAddress >>> 0x0L 84 | # 02 getEndAddress >>> 0x14L 85 | # 03 getLast >>> if-ge 86 | # 04 getLastAddress >>> 0x10L 87 | # 05 size >>> 5 88 | # 06 getInstructions >>> [check-cast, check-cast, iget, iget, if-ge] 89 | # 07 allinsize >>> 0 90 | # 08 insize >>> 0 91 | # 09 irrinsize >>> 0 92 | # 10 alloutsize >>> 2 93 | # 11 outsize >>> 2 94 | # 12 irroutsize >>> 0 95 | # 13 getAllInputBlocks >>> [] 96 | # 14 getInputBlocks >>> [] 97 | # 15 getIrregularInputBlocks >>> [] 98 | # 16 getAllOutputBlocks >>> [(14-14,1), (18-20,3)] 99 | # 17 getOutputBlocks >>> [(14-14,1), (18-20,3)] 100 | # 18 getIrregularOutputBlocks >>> [] 101 | # 0 102 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 103 | # 01 getFirstAddress >>> 0x14L 104 | # 02 getEndAddress >>> 0x16L 105 | # 03 getLast >>> const/4 106 | # 04 getLastAddress >>> 0x14L 107 | # 05 size >>> 1 108 | # 06 getInstructions >>> [const/4] 109 | # 07 allinsize >>> 1 110 | # 08 insize >>> 1 111 | # 09 irrinsize >>> 0 112 | # 10 alloutsize >>> 1 113 | # 11 outsize >>> 1 114 | # 12 irroutsize >>> 0 115 | # 13 getAllInputBlocks >>> [(0-10,5)] 116 | # 14 getInputBlocks >>> [(0-10,5)] 117 | # 15 getIrregularInputBlocks >>> [] 118 | # 16 getAllOutputBlocks >>> [(16-16,1)] 119 | # 17 getOutputBlocks >>> [(16-16,1)] 120 | # 18 getIrregularOutputBlocks >>> [] 121 | # 20 122 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 123 | # 01 getFirstAddress >>> 0x16L 124 | # 02 getEndAddress >>> 0x18L 125 | # 03 getLast >>> return 126 | # 04 getLastAddress >>> 0x16L 127 | # 05 size >>> 1 128 | # 06 getInstructions >>> [return] 129 | # 07 allinsize >>> 3 130 | # 08 insize >>> 3 131 | # 09 irrinsize >>> 0 132 | # 10 alloutsize >>> 0 133 | # 11 outsize >>> 0 134 | # 12 irroutsize >>> 0 135 | # 13 getAllInputBlocks >>> [(28-2A,2), (24-26,2), (14-14,1)] 136 | # 14 getInputBlocks >>> [(28-2A,2), (24-26,2), (14-14,1)] 137 | # 15 getIrregularInputBlocks >>> [] 138 | # 16 getAllOutputBlocks >>> [] 139 | # 17 getOutputBlocks >>> [] 140 | # 18 getIrregularOutputBlocks >>> [] 141 | # 22 142 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 143 | # 01 getFirstAddress >>> 0x18L 144 | # 02 getEndAddress >>> 0x24L 145 | # 03 getLast >>> if-le 146 | # 04 getLastAddress >>> 0x20L 147 | # 05 size >>> 3 148 | # 06 getInstructions >>> [iget, iget, if-le] 149 | # 07 allinsize >>> 1 150 | # 08 insize >>> 1 151 | # 09 irrinsize >>> 0 152 | # 10 alloutsize >>> 2 153 | # 11 outsize >>> 2 154 | # 12 irroutsize >>> 0 155 | # 13 getAllInputBlocks >>> [(0-10,5)] 156 | # 14 getInputBlocks >>> [(0-10,5)] 157 | # 15 getIrregularInputBlocks >>> [] 158 | # 16 getAllOutputBlocks >>> [(24-26,2), (28-2A,2)] 159 | # 17 getOutputBlocks >>> [(24-26,2), (28-2A,2)] 160 | # 18 getIrregularOutputBlocks >>> [] 161 | # 24 162 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 163 | # 01 getFirstAddress >>> 0x24L 164 | # 02 getEndAddress >>> 0x28L 165 | # 03 getLast >>> goto 166 | # 04 getLastAddress >>> 0x26L 167 | # 05 size >>> 2 168 | # 06 getInstructions >>> [const/4, goto] 169 | # 07 allinsize >>> 1 170 | # 08 insize >>> 1 171 | # 09 irrinsize >>> 0 172 | # 10 alloutsize >>> 1 173 | # 11 outsize >>> 1 174 | # 12 irroutsize >>> 0 175 | # 13 getAllInputBlocks >>> [(18-20,3)] 176 | # 14 getInputBlocks >>> [(18-20,3)] 177 | # 15 getIrregularInputBlocks >>> [] 178 | # 16 getAllOutputBlocks >>> [(16-16,1)] 179 | # 17 getOutputBlocks >>> [(16-16,1)] 180 | # 18 getIrregularOutputBlocks >>> [] 181 | # 36 182 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 183 | # 01 getFirstAddress >>> 0x28L 184 | # 02 getEndAddress >>> 0x2cL 185 | # 03 getLast >>> goto 186 | # 04 getLastAddress >>> 0x2aL 187 | # 05 size >>> 2 188 | # 06 getInstructions >>> [const/4, goto] 189 | # 07 allinsize >>> 1 190 | # 08 insize >>> 1 191 | # 09 irrinsize >>> 0 192 | # 10 alloutsize >>> 1 193 | # 11 outsize >>> 1 194 | # 12 irroutsize >>> 0 195 | # 13 getAllInputBlocks >>> [(18-20,3)] 196 | # 14 getInputBlocks >>> [(18-20,3)] 197 | # 15 getIrregularInputBlocks >>> [] 198 | # 16 getAllOutputBlocks >>> [(16-16,1)] 199 | # 17 getOutputBlocks >>> [(16-16,1)] 200 | # 18 getIrregularOutputBlocks >>> [] 201 | # 40 202 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 203 | # Done. 204 | 205 | 206 | 207 | # 方法指令 208 | # .method public final volatile bridge synthetic compare(Object, Object)I 209 | # .registers 5 210 | # 00000000 check-cast p1, b 211 | # 00000004 check-cast p2, b 212 | # 00000008 iget v0, p1, b->o:I 213 | # 0000000C iget v1, p2, b->o:I 214 | # 00000010 if-ge v0, v1, :18 215 | # :14 216 | # 00000014 const/4 v0, 1 217 | # :16 218 | # 00000016 return v0 219 | # :18 220 | # 00000018 iget v0, p1, b->o:I 221 | # 0000001C iget v1, p2, b->o:I 222 | # 00000020 if-le v0, v1, :28 # 1111111111 223 | # :24 224 | # 00000024 const/4 v0, -1 225 | # 00000026 goto :16 226 | # :28 227 | # 00000028 const/4 v0, 0 228 | # 0000002A goto :16 229 | # .end method -------------------------------------------------------------------------------- /samples/16 IDexUnit-CFG.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit 6 | from com.pnfsoftware.jeb.core.units.code.android.dex import IDexMethodData, IDexCodeItem, IDexMethod 7 | 8 | # 访问CFG 9 | def Test(ctx): 10 | assert isinstance(ctx,IClientContext) 11 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.dex" 12 | sign = "Lnet/cavas/show/aa;->compare(Ljava/lang/Object;Ljava/lang/Object;)I" 13 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 14 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 15 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit); 16 | method = dexUnit.getMethod(sign); assert isinstance(method,IDexMethod) 17 | dexMethodData = method.getData(); assert isinstance(dexMethodData,IDexMethodData) 18 | dexCodeItem= dexMethodData.getCodeItem(); assert isinstance(dexCodeItem,IDexCodeItem) 19 | 20 | # 控制流图 21 | print("-------------------------------------") 22 | cfg = dexCodeItem.getControlFlowGraph() 23 | print "01 Block >>> ",cfg.getBlocks() # 基本快列表 24 | print "02 size >>> ",cfg.size() # 块个数 25 | print "03 hasExit >>> ",cfg.hasExit() # 是否有出口 26 | print "04 getEntryBlock >>> ",cfg.getEntryBlock() # 入口块 27 | print "05 getExitBlocks >>> ",cfg.getExitBlocks() # 出口块(不唯一) 28 | print "06 getLast >>> ",cfg.getLast() # 最后一个块 29 | print "07 getAddressBlockMap >>> ",cfg.getAddressBlockMap() # map<偏移地址,块> 30 | print "08 getEndAddress >>> ",hex(cfg.getEndAddress()) # 结尾指令地址 31 | print "09 formatEdges >>> ",cfg.formatEdges() # 输出边(字符串) 32 | 33 | # print " >>> ",cfg.doDataFlowAnalysis() # 执行数据流分析 34 | # print " >>> ",cfg.getUseDefChains() # UD 35 | # print " >>> ",cfg.getDefUseChains() # DU 36 | # print " >>> ",cfg.getFullDefUseChains() # FDU 37 | # print " >>> ",cfg.getFullUseDefChains() # FUD 38 | 39 | 40 | # 输出 41 | # 01 Block >>> [(0-10,5), (14-14,1), (16-16,1), (18-20,3), (24-26,2), (28-2A,2)] 42 | # 02 size >>> 6 43 | # 03 hasExit >>> True 44 | # 04 getEntryBlock >>> (0-10,5) 45 | # 05 getExitBlocks >>> [(16-16,1)] 46 | # 06 getLast >>> (28-2A,2) 47 | # 07 getAddressBlockMap >>> {0L: (0-10,5), 20L: (14-14,1), 22L: (16-16,1), 24L: (18-20,3), 36L: (24-26,2), 40L: (28-2A,2)} 48 | # 08 getEndAddress >>> 0x2cL 49 | # 09 formatEdges >>> (EDGES: 0->14, 0->18, 14->16, 18->24, 18->28, 24->16, 28->16) 50 | # Done. 51 | 52 | 53 | # 方法指令 54 | # .method public final volatile bridge synthetic compare(Object, Object)I 55 | # .registers 5 56 | # 00000000 check-cast p1, b 57 | # 00000004 check-cast p2, b 58 | # 00000008 iget v0, p1, b->o:I 59 | # 0000000C iget v1, p2, b->o:I 60 | # 00000010 if-ge v0, v1, :18 61 | # :14 62 | # 00000014 const/4 v0, 1 63 | # :16 64 | # 00000016 return v0 65 | # :18 66 | # 00000018 iget v0, p1, b->o:I 67 | # 0000001C iget v1, p2, b->o:I 68 | # 00000020 if-le v0, v1, :28 # 1111111111 69 | # :24 70 | # 00000024 const/4 v0, -1 71 | # 00000026 goto :16 72 | # :28 73 | # 00000028 const/4 v0, 0 74 | # 0000002A goto :16 75 | # .end method -------------------------------------------------------------------------------- /samples/21 IDexDecompilerUnit-decompile.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code import DecompilationOptions, IDecompilerUnit, DecompilationContext 6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDexDecompilerUnit 7 | from com.pnfsoftware.jeb.core.util import DecompilerHelper 8 | 9 | # F5反编译Class 10 | def Test(ctx): 11 | assert isinstance(ctx,IClientContext) 12 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.dex" 13 | sign = "Lnet/cavas/show/aa;" 14 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 15 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 16 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit) 17 | 18 | dexDecompilerUnit = DecompilerHelper.getDecompiler(dexUnit); assert isinstance(dexDecompilerUnit,IDexDecompilerUnit) 19 | opt = DecompilationOptions.Builder().newInstance().flags(IDecompilerUnit.FLAG_NO_DEFERRED_DECOMPILATION).build() 20 | bool = dexDecompilerUnit.decompileAllClasses(DecompilationContext(opt)) 21 | text = dexDecompilerUnit.getDecompiledClassText(sign) 22 | print("-------------------------------------") 23 | print text 24 | print("-------------------------------------") 25 | 26 | # 输出 27 | ''' 28 | package net.cavas.show; 29 | 30 | import java.util.Comparator; 31 | import net.cavas.show.a.b; 32 | 33 | final class aa implements Comparator { 34 | final x a; 35 | 36 | aa(x arg1) { 37 | this.a = arg1; 38 | super(); 39 | } 40 | 41 | @Override 42 | public final int compare(Object arg3, Object arg4) { 43 | b v3 = (b)arg3; 44 | b v4 = (b)arg4; 45 | if(v3.o < v4.o) { 46 | return 1; 47 | } 48 | return v3.o <= v4.o ? 0 : -1; 49 | } 50 | } 51 | ''' -------------------------------------------------------------------------------- /samples/31 IJavaSourceUnit-DisplayAstTree.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code import IDecompilerUnit, DecompilationOptions, DecompilationContext 6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDexDecompilerUnit 7 | from com.pnfsoftware.jeb.core.units.code.java import IJavaMethod 8 | from com.pnfsoftware.jeb.core.util import DecompilerHelper 9 | 10 | def displayTree(e, level=0): 11 | dispatch(e,level) 12 | if e: 13 | elts = e.getSubElements() 14 | for e in elts: 15 | displayTree(e, level+1) 16 | 17 | def dispatch(ele,level): 18 | print(level,"<",ele.getElementType(),"> >>>",ele) 19 | 20 | # 输出语法树内容 21 | def Test(ctx): 22 | assert isinstance(ctx,IClientContext) 23 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.dex" 24 | sign = "Lcom/BestCalculatorCN/MyCalculator;->m(Lcom/BestCalculatorCN/MyCalculator;)Z" 25 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 26 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 27 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit) 28 | 29 | # 发现使用DecompilationContext时,才能出现javablock,不然block为0,没有进行解析 30 | dexDecompilerUnit = DecompilerHelper.getDecompiler(dexUnit); assert isinstance(dexDecompilerUnit,IDexDecompilerUnit) 31 | opt = DecompilationOptions.Builder().newInstance().flags(IDecompilerUnit.FLAG_NO_DEFERRED_DECOMPILATION).build() 32 | bool = dexDecompilerUnit.decompileAllClasses(DecompilationContext(opt)) 33 | print(bool) 34 | javaMethod = dexDecompilerUnit.getMethod(sign,False); assert isinstance(javaMethod,IJavaMethod) 35 | displayTree(javaMethod) 36 | 37 | 38 | # 方法原型 39 | ''' 40 | static boolean m(MyCalculator arg5) { 41 | int v2 = arg5.S.length(); 42 | int v1; 43 | for(v1 = 0; true; ++v1) { 44 | if(v1 >= v2) { 45 | return false; 46 | } 47 | 48 | if(arg5.S.charAt(v1) == 120) { 49 | return true; 50 | } 51 | } 52 | } 53 | ''' 54 | 55 | # 输出 56 | # True 57 | # (0, '<', Method, '> >>>', method:com.BestCalculatorCN.MyCalculator.m) 58 | # (1, '<', Definition, '> >>>', com.BestCalculatorCN.MyCalculator arg5) 59 | # (2, '<', Identifier, '> >>>', arg5) 60 | # (1, '<', Block, '> >>>', int v2 = length(arg5.S) 61 | # int v1 62 | # For@665729435 63 | # ) 64 | # (2, '<', Assignment, '> >>>', int v2 = length(arg5.S)) 65 | # (3, '<', Definition, '> >>>', int v2) 66 | # (4, '<', Identifier, '> >>>', v2) 67 | # (3, '<', Call, '> >>>', length(arg5.S)) 68 | # (4, '<', InstanceField, '> >>>', arg5.S) 69 | # (5, '<', Identifier, '> >>>', arg5) 70 | # (2, '<', Definition, '> >>>', int v1) 71 | # (3, '<', Identifier, '> >>>', v1) 72 | # (2, '<', For, '> >>>', For@665729435) 73 | # (3, '<', Assignment, '> >>>', v1 = 0(int)) 74 | # (4, '<', Identifier, '> >>>', v1) 75 | # (4, '<', Constant, '> >>>', 0(int)) 76 | # (3, '<', Predicate, '> >>>', (true)) 77 | # (4, '<', Constant, '> >>>', true) 78 | # (3, '<', Assignment, '> >>>', ++v1) 79 | # (4, '<', Identifier, '> >>>', v1) 80 | # (3, '<', Block, '> >>>', If@549618061 81 | # If@-1864570085 82 | # ) 83 | # (4, '<', If, '> >>>', If@549618061) 84 | # (5, '<', Predicate, '> >>>', (v1, >=, v2)) 85 | # (6, '<', Identifier, '> >>>', v1) 86 | # (6, '<', Identifier, '> >>>', v2) 87 | # (5, '<', Block, '> >>>', return false 88 | # ) 89 | # (6, '<', Return, '> >>>', return false) 90 | # (7, '<', Constant, '> >>>', false) 91 | # (4, '<', If, '> >>>', If@-1864570085) 92 | # (5, '<', Predicate, '> >>>', (charAt(arg5.S, v1), ==, 0x78(int))) 93 | # (6, '<', Call, '> >>>', charAt(arg5.S, v1)) 94 | # (7, '<', InstanceField, '> >>>', arg5.S) 95 | # (8, '<', Identifier, '> >>>', arg5) 96 | # (7, '<', Identifier, '> >>>', v1) 97 | # (6, '<', Constant, '> >>>', 0x78(int)) 98 | # (5, '<', Block, '> >>>', return true 99 | # ) 100 | # (6, '<', Return, '> >>>', return true) 101 | # (7, '<', Constant, '> >>>', true) -------------------------------------------------------------------------------- /samples/32 IJavaSourceUnit-IJavaIf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code import IDecompilerUnit, DecompilationOptions, DecompilationContext 6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDexDecompilerUnit 7 | from com.pnfsoftware.jeb.core.units.code.java import IJavaMethod, IJavaDefinition, IJavaIdentifier, \ 8 | IJavaBlock, IJavaIf 9 | from com.pnfsoftware.jeb.core.util import DecompilerHelper 10 | 11 | def displayTree(e, level=0): 12 | dispatch(e,level) 13 | if e: 14 | elts = e.getSubElements() 15 | for e in elts: 16 | displayTree(e, level+1) 17 | 18 | def dispatch(ele,level): 19 | if isinstance(ele,IJavaIf): 20 | # if分支个数 21 | if ele.size()>1: 22 | print ele.getPhysicalOffset() 23 | 24 | # if第1个分支的语句序列(类型为IJavaBlock) 25 | print "01 getBranchBody(0) >>>",ele.getBranchBody(0) 26 | 27 | # if第2个分支的语句序列 28 | print "02 getBranchBody(1) >>>",ele.getBranchBody(1) 29 | 30 | # 获取if第1个分支的谓词(类型为IJavaPredicate,继承接口IJavaArithmeticExpression) 31 | print "03 getBranchPredicate(0) >>>",ele.getBranchPredicate(0) 32 | 33 | # 获取if第2个分支的谓词(类型为IJavaPredicate,继承接口IJavaArithmeticExpression) 34 | print "04 getBranchPredicate(1) >>>",ele.getBranchPredicate(1) 35 | 36 | # 谓词的右值/左值/运算符 37 | print "05 getRight() >>>",ele.getBranchPredicate(1).getRight() 38 | print "06 getLeft() >>>",ele.getBranchPredicate(1).getLeft() 39 | print "07 getOperator() >>>",ele.getBranchPredicate(1).getOperator() 40 | 41 | # 谓词的右值/左值的类型 42 | print "08 Right Element Type >>> ",ele.getBranchPredicate(1).getRight().getElementType() 43 | print "09 Left Element Type >>> ",ele.getBranchPredicate(1).getLeft().getElementType() 44 | 45 | # 谓词的左值是一个类属性,看一下他的完整签名 46 | print "10 field sign >>> ",ele.getBranchPredicate(1).getLeft().getFieldSignature() 47 | 48 | # 谓词的运算符提供的一些方法 49 | print "11 getOperatorType >>> ",ele.getBranchPredicate(1).getOperator().getOperatorType() 50 | print "12 isArithmetic >>> ",ele.getBranchPredicate(1).getOperator().isArithmetic() 51 | print "13 isBinary >>> ",ele.getBranchPredicate(1).getOperator().isBinary() 52 | print "14 isCast >>> ",ele.getBranchPredicate(1).getOperator().isCast() 53 | print "15 isLogical >>> ",ele.getBranchPredicate(1).getOperator().isLogical() 54 | print "16 isUnary >>> ",ele.getBranchPredicate(1).getOperator().isUnary() 55 | print "17 toString >>> ",ele.getBranchPredicate(1).getOperator().toString() 56 | print("--------------") 57 | pass 58 | else: 59 | pass 60 | 61 | 62 | # IJavaIf 63 | def Test(ctx): 64 | assert isinstance(ctx,IClientContext) 65 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.dex" 66 | sign = "Lnet/cavas/show/bl;->handleMessage(Landroid/os/Message;)V" 67 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 68 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 69 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit) 70 | dexDecompilerUnit = DecompilerHelper.getDecompiler(dexUnit); assert isinstance(dexDecompilerUnit,IDexDecompilerUnit) 71 | opt = DecompilationOptions.Builder().newInstance().flags(IDecompilerUnit.FLAG_NO_DEFERRED_DECOMPILATION).build() 72 | bool = dexDecompilerUnit.decompileAllClasses(DecompilationContext(opt)) 73 | print(bool) 74 | javaMethod = dexDecompilerUnit.getMethod(sign,False); assert isinstance(javaMethod,IJavaMethod) 75 | print("---------------- tree ----------------") 76 | displayTree(javaMethod) 77 | 78 | 79 | # 被解析的目标代码: 80 | ''' 81 | if(this.a.f.o == 0) { 82 | this.a.b.a(0, v0.d); 83 | } 84 | else if(this.a.f.o == 2) { 85 | this.a.b.a(1, v0.d); 86 | } 87 | ''' 88 | 89 | 90 | # 输出 91 | # 01 getBranchBody(0) >>> a(this.a.b, 0(int), v0.d) 92 | # 02 getBranchBody(1) >>> a(this.a.b, 1(int), v0.d) 93 | # 03 getBranchPredicate(0) >>> (this.a.f.o, ==, 0(int)) 94 | # 04 getBranchPredicate(1) >>> (this.a.f.o, ==, 2(int)) 95 | # 05 getRight() >>> 2(int) 96 | # 06 getLeft() >>> this.a.f.o 97 | # 07 getOperator() >>> == 98 | # 08 Right Element Type >>> Constant 99 | # 09 Left Element Type >>> InstanceField 100 | # 10 field sign >>> Lnet/cavas/show/a/b;->o:I 101 | # 11 getOperatorType >>> EQ 102 | # 12 isArithmetic >>> False 103 | # 13 isBinary >>> True 104 | # 14 isCast >>> False 105 | # 15 isLogical >>> True 106 | # 16 isUnary >>> False 107 | # 17 toString >>> == -------------------------------------------------------------------------------- /samples/33 IJavaSourceUnit-IJavaCall.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code import IDecompilerUnit, DecompilationOptions, DecompilationContext 6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDexDecompilerUnit 7 | from com.pnfsoftware.jeb.core.units.code.java import IJavaMethod,IJavaCall 8 | from com.pnfsoftware.jeb.core.util import DecompilerHelper 9 | 10 | def displayTree(e, level=0): 11 | dispatch(e,level) 12 | if e: 13 | elts = e.getSubElements() 14 | for e in elts: 15 | displayTree(e, level+1) 16 | 17 | def dispatch(ele,level): 18 | if isinstance(ele,IJavaCall): 19 | if ele.getMethodName() == "equalsIgnoreCase": 20 | print "1 getPhysicalOffset() >>> ",ele.getPhysicalOffset() 21 | print "2 getCallType() >>> ",ele.getCallType() # REGULAR 0;SUPER 1;LAMBDA 2;STATIC 3; 22 | print "3 isSuperCall() >>> ",ele.isSuperCall() 23 | print "4 isCustomCall() >>> ",ele.isCustomCall() 24 | print "5 isStaticCall() >>> ",ele.isStaticCall() 25 | print "6 getMethod() >>> ",ele.getMethod() 26 | print "7 getMethodName() >>> ",ele.getMethodName() 27 | print "8 getMethodSignature() >>> ",ele.getMethodSignature() 28 | print "9 getArguments() >>> ",ele.getArguments() 29 | print "10 getArguments()[0] >>> ",ele.getArguments()[0].getElementType() 30 | print "11 getArguments()[1] >>> ",ele.getArguments()[1].getElementType() 31 | exit(0) 32 | pass 33 | else: 34 | pass 35 | 36 | 37 | # IJavaCall 38 | def Test(ctx): 39 | assert isinstance(ctx,IClientContext) 40 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.dex" 41 | sign = "Lnet/cavas/show/bl;->handleMessage(Landroid/os/Message;)V" 42 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 43 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 44 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit) 45 | dexDecompilerUnit = DecompilerHelper.getDecompiler(dexUnit); assert isinstance(dexDecompilerUnit,IDexDecompilerUnit) 46 | opt = DecompilationOptions.Builder().newInstance().flags(IDecompilerUnit.FLAG_NO_DEFERRED_DECOMPILATION).build() 47 | bool = dexDecompilerUnit.decompileAllClasses(DecompilationContext(opt)) 48 | print(bool) 49 | javaMethod = dexDecompilerUnit.getMethod(sign,False); assert isinstance(javaMethod,IJavaMethod) 50 | print("---------------- tree ----------------") 51 | displayTree(javaMethod) 52 | 53 | 54 | # 目标代码 55 | # "null".equalsIgnoreCase(v0.b.trim()) 56 | 57 | 58 | ''' 59 | 输出 60 | ---------------- tree ---------------- 61 | 1 getPhysicalOffset() >>> 130 62 | 2 getCallType() >>> 0 63 | 3 isSuperCall() >>> False 64 | 4 isCustomCall() >>> False 65 | 5 isStaticCall() >>> False 66 | 6 getMethod() >>> method:java.lang.String.equalsIgnoreCase 67 | 7 getMethodName() >>> equalsIgnoreCase 68 | 8 getMethodSignature() >>> Ljava/lang/String;->equalsIgnoreCase(Ljava/lang/String;)Z 69 | 9 getArguments() >>> ["null", trim(v0.b)] 70 | 10 getArguments()[0] >>> Constant 71 | 11 getArguments()[1] >>> Call 72 | ''' -------------------------------------------------------------------------------- /samples/34 IJavaSourceUnit-IJavaTry.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code import IDecompilerUnit, DecompilationOptions, DecompilationContext 6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDexDecompilerUnit 7 | from com.pnfsoftware.jeb.core.units.code.java import IJavaMethod, IJavaTry 8 | from com.pnfsoftware.jeb.core.util import DecompilerHelper 9 | 10 | def displayTree(e, level=0): 11 | dispatch(e,level) 12 | if e: 13 | elts = e.getSubElements() 14 | for e in elts: 15 | displayTree(e, level+1) 16 | 17 | def dispatch(ele,level): 18 | if isinstance(ele,IJavaTry): 19 | print "---------- try body start -----------" 20 | print ele.getTryBody() # try块语句序列 21 | print "---------- try body end -------------" 22 | print "CatchCount >>> " , ele.getCatchCount() # catch块个数 23 | for idx in range(ele.getCatchCount()): 24 | print "" 25 | print "" 26 | print "---------- catch body start -----------",idx 27 | print "Type >>> ",ele.getCatchType(idx) # catch块括号内异常类型 28 | print "Identifier >>> ",ele.getCatchIdentifier(idx) # catch块括号内标识符 29 | print "catch body >>> " 30 | print ele.getCatchBody(idx) # catch块语句序列 31 | print "---------- catch body end -------------",idx 32 | print "" 33 | print "" 34 | print "finally body >>>",ele.getFinallyBody() # final块语句序列 35 | exit(0) 36 | pass 37 | else: 38 | pass 39 | 40 | # IJavaTry 41 | def Test(ctx): 42 | assert isinstance(ctx,IClientContext) 43 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.dex" 44 | sign = "Lnet/cavas/show/af;->a(Lorg/apache/http/client/HttpClient;Ljava/util/Queue;)V" 45 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 46 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 47 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit) 48 | dexDecompilerUnit = DecompilerHelper.getDecompiler(dexUnit); assert isinstance(dexDecompilerUnit,IDexDecompilerUnit) 49 | opt = DecompilationOptions.Builder().newInstance().flags(IDecompilerUnit.FLAG_NO_DEFERRED_DECOMPILATION).build() 50 | bool = dexDecompilerUnit.decompileAllClasses(DecompilationContext(opt)) 51 | print(bool) 52 | javaMethod = dexDecompilerUnit.getMethod(sign,False); assert isinstance(javaMethod,IJavaMethod) 53 | print("---------------- tree ----------------") 54 | displayTree(javaMethod) 55 | 56 | 57 | ''' 58 | 目标代码: 59 | final class af implements Runnable { 60 | private void a(HttpClient arg6, Queue arg7) { 61 | String v0 = (String)arg7.poll(); 62 | if(this.b != null && v0 != null) { 63 | HttpPost v1 = new HttpPost(this.b.replace(" ", "%20")); 64 | v1.setEntity(new EntityTemplate(new ag(this, v0))); 65 | try { 66 | HttpResponse v0_4 = arg6.execute(((HttpUriRequest)v1)); 67 | c.a("offer", Integer.valueOf(v0_4.getStatusLine().getStatusCode())); 68 | if(v0_4.getStatusLine().getStatusCode() == 200) { 69 | this.a(arg6, arg7); 70 | return; 71 | } 72 | } 73 | catch(ClientProtocolException v0_3) { 74 | try { 75 | c.c(d.a, "Caught ClientProtocolException in PingUrlRunnable"); 76 | return; 77 | label_35: 78 | c.c(d.a, "Caught IOException in PingUrlRunnable"); 79 | return; 80 | } 81 | catch(Throwable v0_1) { 82 | throw v0_1; 83 | } 84 | } 85 | catch(IOException v0_2) { 86 | goto label_35; 87 | return; 88 | } 89 | catch(Throwable v0_1) { 90 | throw v0_1; 91 | } 92 | } 93 | } 94 | } 95 | ''' 96 | 97 | 98 | 99 | ''' 100 | 输出: 101 | True 102 | ---------------- tree ---------------- 103 | 104 | ---------- try body start ----------- 105 | org.apache.http.HttpResponse v0_4 = execute(arg6, ((org.apache.http.client.methods.HttpUriRequest), v1)) 106 | a("offer", valueOf(getStatusCode(getStatusLine(v0_4)))) 107 | If@-2003461530 108 | ---------- try body end ------------- 109 | 110 | 111 | CatchCount >>> 3 112 | ---------- catch body start ----------- 0 113 | Type >>> org.apache.http.client.ClientProtocolException 114 | Identifier >>> v0_3 115 | catch body >>> 116 | Try@1198833152 117 | ---------- catch body end ------------- 0 118 | 119 | 120 | ---------- catch body start ----------- 1 121 | Type >>> java.io.IOException 122 | Identifier >>> v0_2 123 | catch body >>> 124 | goto label_35 125 | return 126 | ---------- catch body end ------------- 1 127 | 128 | 129 | ---------- catch body start ----------- 2 130 | Type >>> java.lang.Throwable 131 | Identifier >>> v0_1 132 | catch body >>> 133 | throw v0_1 134 | ---------- catch body end ------------- 2 135 | finally body >>> None 136 | ''' -------------------------------------------------------------------------------- /samples/35 IJavaSourceUnit-IJavaFor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit 5 | from com.pnfsoftware.jeb.core.units.code import IDecompilerUnit, DecompilationOptions, DecompilationContext 6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDexDecompilerUnit 7 | from com.pnfsoftware.jeb.core.units.code.java import IJavaMethod,IJavaFor 8 | from com.pnfsoftware.jeb.core.util import DecompilerHelper 9 | 10 | def displayTree(e, level=0): 11 | dispatch(e,level) 12 | if e: 13 | elts = e.getSubElements() 14 | for e in elts: 15 | displayTree(e, level+1) 16 | 17 | def dispatch(ele,level): 18 | if isinstance(ele,IJavaFor): 19 | # 初始化语句 20 | print "1 Initializer >>> ",ele.getInitializer(),ele.getInitializer().getElementType() 21 | 22 | # 循环谓词 23 | print "2 Predicate >>> ",ele.getPredicate(),ele.getPredicate().getElementType() 24 | 25 | # 迭代后语句 26 | print "3 PostStatement >>> ",ele.getPostStatement(),ele.getPostStatement().getElementType() 27 | 28 | # 循环体 29 | print "4 Body >>> " 30 | print ele.getBody() 31 | pass 32 | else: 33 | pass 34 | 35 | 36 | # IJavaFor 37 | def Test(ctx): 38 | assert isinstance(ctx,IClientContext) 39 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.dex" 40 | sign = "Lcom/BestCalculatorCN/MyCalculator;->m(Lcom/BestCalculatorCN/MyCalculator;)Z" 41 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 42 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 43 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit) 44 | dexDecompilerUnit = DecompilerHelper.getDecompiler(dexUnit); assert isinstance(dexDecompilerUnit,IDexDecompilerUnit) 45 | opt = DecompilationOptions.Builder().newInstance().flags(IDecompilerUnit.FLAG_NO_DEFERRED_DECOMPILATION).build() 46 | bool = dexDecompilerUnit.decompileAllClasses(DecompilationContext(opt)) 47 | print(bool) 48 | javaMethod = dexDecompilerUnit.getMethod(sign,False); assert isinstance(javaMethod,IJavaMethod) 49 | print("---------------- tree ----------------") 50 | displayTree(javaMethod) 51 | 52 | 53 | ''' 54 | 目标代码: 55 | static boolean m(MyCalculator arg5) { 56 | int v2 = arg5.S.length(); 57 | int v1; 58 | for(v1 = 0; true; ++v1) { 59 | if(v1 >= v2) { 60 | return false; 61 | } 62 | 63 | if(arg5.S.charAt(v1) == 120) { 64 | return true; 65 | } 66 | } 67 | } 68 | ''' 69 | 70 | 71 | ''' 72 | 输出 73 | True 74 | ---------------- tree ---------------- 75 | 1 Initializer >>> v1 = 0(int) Assignment 76 | 2 Predicate >>> (true) Predicate 77 | 3 PostStatement >>> ++v1 Assignment 78 | 4 Body >>> 79 | If@496760551 80 | If@1458799117 81 | ''' -------------------------------------------------------------------------------- /samples/41 INativeCodeUnit-Function.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit, INativeCodeUnit 5 | from com.pnfsoftware.jeb.core.units.code.asm.items import INativeMethodItem 6 | 7 | 8 | # 遍历函数 9 | def Test(ctx): 10 | assert isinstance(ctx,IClientContext) 11 | input_path = r"D:\tmp\2\project\about_dex_diff\code\xmly\libFace3D.so" 12 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 13 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 14 | nativeCodeUnit = prj.findUnit(INativeCodeUnit); assert isinstance(nativeCodeUnit,INativeCodeUnit) 15 | bool = nativeCodeUnit.process() 16 | 17 | # Methods 18 | methodList = nativeCodeUnit.getMethods() 19 | for idx,method in enumerate(methodList): 20 | assert isinstance(method,INativeMethodItem) 21 | print "-------------------------------" 22 | print " >>> ",idx,method.getItemId() 23 | print " >>> ",idx,method.getSignature() 24 | 25 | # InternalMethods 26 | internalMethodlist = nativeCodeUnit.getInternalMethods() 27 | for idx,method in enumerate(internalMethodlist): 28 | assert isinstance(method,INativeMethodItem) 29 | print "-------------------------------" 30 | print " >>> ",idx,method.getItemId() 31 | print " >>> ",idx,method.getSignature() 32 | 33 | ''' 34 | 输出: 35 | 36 | ...... 37 | ------------------------------- 38 | >>> 718 -8718968878589278991 39 | >>> 718 libunwind::UnwindCursor::getInfoFromEHABISection 40 | ------------------------------- 41 | >>> 719 -8718968878589279141 42 | >>> 719 std::__ndk1::__upper_bound&, libunwind::EHABISectionIterator, unsigned int> 43 | ------------------------------- 44 | >>> 720 -8718968878589279140 45 | >>> 720 sub_1A124 46 | ...... 47 | 48 | ''' -------------------------------------------------------------------------------- /samples/42 INativeCodeUnit-Insn.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit, INativeCodeUnit 5 | from com.pnfsoftware.jeb.core.units.code import IInstruction 6 | from com.pnfsoftware.jeb.core.units.code.asm.items import INativeMethodItem 7 | 8 | # 指令信息 9 | def Test(ctx): 10 | assert isinstance(ctx,IClientContext) 11 | input_path = r"D:\tmp\2\project\about_dex_diff\code\xmly\libFace3D.so" 12 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 13 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 14 | nativeCodeUnit = prj.findUnit(INativeCodeUnit); assert isinstance(nativeCodeUnit,INativeCodeUnit) 15 | bool = nativeCodeUnit.process() 16 | 17 | # method 18 | method = nativeCodeUnit.getMethod("sub_11110"); assert isinstance(method,INativeMethodItem) 19 | 20 | # insn 21 | insnlist = method.getInstructions() 22 | for insn in insnlist: 23 | assert isinstance(insn,IInstruction) 24 | print " >>> ",insn.getMnemonic() 25 | print " >>> ",insn.getProcessorMode() 26 | print " >>> ",insn.getSize() 27 | print " >>> ",insn.getCode() 28 | print " >>> ",insn.getPrefix() 29 | print " >>> ",insn.getMnemonic() 30 | print " >>> ",insn.getOperands() 31 | print " >>> ",insn.canThrow() 32 | print " >>> ",insn.isConditional() 33 | print "-------------------------" 34 | 35 | 36 | ''' 37 | 输出: 38 | >>> PUSH 39 | >>> 16 40 | >>> 2 41 | >>> array('b', [-48, -75]) 42 | >>> None 43 | >>> PUSH 44 | >>> array(com.pnfsoftware.jebglobal.WX, [{R4, R6, R7, LR}]) 45 | >>> False 46 | >>> False 47 | ------------------------- 48 | >>> ADD 49 | >>> 16 50 | >>> 2 51 | >>> array('b', [2, -81]) 52 | >>> None 53 | >>> ADD 54 | >>> array(com.pnfsoftware.jebglobal.WX, [R7, SP, #8]) 55 | >>> False 56 | >>> False 57 | ------------------------- 58 | >>> MOV 59 | >>> 16 60 | >>> 2 61 | >>> array('b', [4, 70]) 62 | >>> None 63 | >>> MOV 64 | >>> array(com.pnfsoftware.jebglobal.WX, [R4, R0]) 65 | >>> False 66 | >>> False 67 | ------------------------- 68 | >>> LDR 69 | >>> 16 70 | >>> 2 71 | >>> array('b', [64, 106]) 72 | >>> None 73 | >>> LDR 74 | >>> array(com.pnfsoftware.jebglobal.WX, [R0, [R0, #24h]]) 75 | >>> False 76 | >>> False 77 | ------------------------- 78 | ...... 79 | 80 | ''' -------------------------------------------------------------------------------- /samples/43 INativeCodeUnit-BasicBlock.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit, INativeCodeUnit 5 | from com.pnfsoftware.jeb.core.units.code.asm.cfg import BasicBlock 6 | from com.pnfsoftware.jeb.core.units.code.asm.items import INativeMethodItem 7 | 8 | 9 | # 基本块信息 10 | def Test(ctx): 11 | assert isinstance(ctx,IClientContext) 12 | input_path = r"D:\tmp\2\project\about_dex_diff\code\xmly\libFace3D.so" 13 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 14 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 15 | nativeCodeUnit = prj.findUnit(INativeCodeUnit); assert isinstance(nativeCodeUnit,INativeCodeUnit) 16 | bool = nativeCodeUnit.process() 17 | 18 | # method 19 | method = nativeCodeUnit.getMethod("sub_11110"); assert isinstance(method,INativeMethodItem) 20 | 21 | # block 22 | nativeMethodDataItem = method.getData() 23 | if nativeMethodDataItem is not None: 24 | cfg = nativeMethodDataItem.getCFG() 25 | blockList = cfg.getBlocks() 26 | for block in blockList: 27 | assert isinstance(block,BasicBlock) 28 | print "01 getFirstAddress >>> ", hex(block.getFirstAddress()) # 入口指令偏移 29 | print "02 getEndAddress >>> ", hex(block.getEndAddress()) # 出口指令偏移 30 | print "03 getLast >>> ", block.getLast() # 最后一条指令 31 | print "04 getLastAddress >>> ", hex(block.getLastAddress()) # 最后一条指令偏移 32 | print "05 size >>> ", block.size() # 指令条数 33 | print "06 getInstructions >>> ", block.getInstructions() # 指令序列 34 | 35 | print "07 allinsize >>> ", block.allinsize() # 前驱个数 36 | print "08 insize >>> ", block.insize() # 规则前驱个数 37 | print "09 irrinsize >>> ", block.irrinsize() # 不规则前驱个数 38 | 39 | print "10 alloutsize >>> ", block.alloutsize() # 后继个数 40 | print "11 outsize >>> ", block.outsize() # 规则后继个数 41 | print "12 irroutsize >>> ", block.irroutsize() # 不规则后继个数 42 | 43 | print "13 getAllInputBlocks >>> ", block.getAllInputBlocks() # 所有前驱块 44 | print "14 getInputBlocks >>> ", block.getInputBlocks() # 常规前驱块 45 | print "15 getIrregularInputBlocks >>> ", block.getIrregularInputBlocks() # 不规则前驱块 46 | 47 | print "16 getAllOutputBlocks >>> ", block.getAllOutputBlocks() # 所有后继块 48 | print "17 getOutputBlocks >>> ", block.getOutputBlocks() # 常规后继块 49 | print "18 getIrregularOutputBlocks >>> ", block.getIrregularOutputBlocks() # 不规则后继块 50 | 51 | print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") 52 | 53 | 54 | ''' 55 | 01 getFirstAddress >>> 0x11110L 56 | 02 getEndAddress >>> 0x1111aL 57 | 03 getLast >>> (80B1) CBZ R0, 24h 58 | 04 getLastAddress >>> 0x11118L 59 | 05 size >>> 5 60 | 06 getInstructions >>> [(D0B5) PUSH {R4, R6, R7, LR}, (02AF) ADD R7, SP, #8, (0446) MOV R4, R0, (406A) LDR R0, [R0, #24h], (80B1) CBZ R0, 24h] 61 | 07 allinsize >>> 0 62 | 08 insize >>> 0 63 | 09 irrinsize >>> 0 64 | 10 alloutsize >>> 2 65 | 11 outsize >>> 2 66 | 12 irroutsize >>> 0 67 | 13 getAllInputBlocks >>> [] 68 | 14 getInputBlocks >>> [] 69 | 15 getIrregularInputBlocks >>> [] 70 | 16 getAllOutputBlocks >>> [1113Ch(6), 1111Ah(2)] 71 | 17 getOutputBlocks >>> [1113Ch(6), 1111Ah(2)] 72 | 18 getIrregularOutputBlocks >>> [] 73 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 74 | 01 getFirstAddress >>> 0x1111aL 75 | 02 getEndAddress >>> 0x11120L 76 | 03 getLast >>> (BFF35B8F) DMB ISH 77 | 04 getLastAddress >>> 0x1111cL 78 | 05 size >>> 2 79 | 06 getInstructions >>> [(0C30) ADDS R0, #0Ch, (BFF35B8F) DMB ISH] 80 | 07 allinsize >>> 1 81 | 08 insize >>> 1 82 | 09 irrinsize >>> 0 83 | 10 alloutsize >>> 1 84 | 11 outsize >>> 1 85 | 12 irroutsize >>> 0 86 | 13 getAllInputBlocks >>> [11110h(5)] 87 | 14 getInputBlocks >>> [11110h(5)] 88 | 15 getIrregularInputBlocks >>> [] 89 | 16 getAllOutputBlocks >>> [11120h(5)] 90 | 17 getOutputBlocks >>> [11120h(5)] 91 | 18 getIrregularOutputBlocks >>> [] 92 | ...... 93 | 94 | ''' -------------------------------------------------------------------------------- /samples/44 INativeCodeUnit-CFG.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit, INativeCodeUnit 5 | from com.pnfsoftware.jeb.core.units.code.asm.cfg import BasicBlock 6 | from com.pnfsoftware.jeb.core.units.code.asm.items import INativeMethodItem 7 | 8 | # CFG信息 9 | def Test(ctx): 10 | assert isinstance(ctx,IClientContext) 11 | input_path = r"D:\tmp\2\project\about_dex_diff\code\xmly\libFace3D.so" 12 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 13 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 14 | nativeCodeUnit = prj.findUnit(INativeCodeUnit); assert isinstance(nativeCodeUnit,INativeCodeUnit) 15 | bool = nativeCodeUnit.process() 16 | 17 | # method 18 | method = nativeCodeUnit.getMethod("sub_11110"); assert isinstance(method,INativeMethodItem) 19 | 20 | # CFG 21 | nativeMethodDataItem = method.getData() 22 | if nativeMethodDataItem is not None: 23 | cfg = nativeMethodDataItem.getCFG() 24 | print "01 Block >>> ",cfg.getBlocks() # 基本快列表 25 | print "02 size >>> ",cfg.size() # 块个数 26 | print "03 hasExit >>> ",cfg.hasExit() # 是否有出口 27 | print "04 getEntryBlock >>> ",cfg.getEntryBlock() # 入口块 28 | print "05 getExitBlocks >>> ",cfg.getExitBlocks() # 出口块(不唯一) 29 | print "07 getAddressBlockMap >>> ",cfg.getAddressBlockMap() # map<偏移地址,块> 30 | print "08 getEndAddress >>> ",hex(cfg.getEndAddress()) # 结尾指令地址 31 | print "09 doDataFlowAnalysis >>> ",cfg.doDataFlowAnalysis() # 执行数据流分析 32 | 33 | 34 | ''' 35 | 输出: 36 | 01 Block >>> [11110h(5), 1111Ah(2), 11120h(5), 1112Eh(5), 1113Ch(6), 1114Ch(3), 11154h(3), 1115Ah(1)] 02 size >>> 8 37 | 03 hasExit >>> True 38 | 04 getEntryBlock >>> 11110h(5) 39 | 05 getExitBlocks >>> [1115Ah(1)] 40 | 07 getAddressBlockMap >>> {69904L: 11110h(5), 69920L: 11120h(5), 69972L: 11154h(3), 69914L: 1111Ah(2), 69978L: 1115Ah(1), 69948L: 1113Ch(6), 69964L: 1114Ch(3), 69934L: 1112Eh(5)} 41 | 08 getEndAddress >>> 0x1115cL 42 | 09 doDataFlowAnalysis >>> None 43 | Done. 44 | ''' -------------------------------------------------------------------------------- /samples/51 INativeSourceUnit-DisplayAstTree.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit, INativeCodeUnit 5 | from com.pnfsoftware.jeb.core.units.code.asm.decompiler import INativeDecompilerUnit, INativeSourceUnit 6 | from com.pnfsoftware.jeb.core.util import DecompilerHelper 7 | 8 | def displayTree(e, level=0): 9 | dispatch(e,level) 10 | if e: 11 | elts = e.getSubElements() 12 | for e in elts: 13 | displayTree(e, level+1) 14 | 15 | def dispatch(ele,level): 16 | print(level,"<",ele.getElementType(),"> >>>") 17 | print(ele) 18 | print("----------------------------------------") 19 | 20 | # 输出语法树 21 | def Test(ctx): 22 | assert isinstance(ctx,IClientContext) 23 | input_path = r"D:\tmp\2\project\about_dex_diff\code\xmly\libFace3D.so" 24 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 25 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 26 | 27 | # 获取INativeCodeUnit并执行解析 28 | nativeCodeUnit = prj.findUnit(INativeCodeUnit); assert isinstance(nativeCodeUnit,INativeCodeUnit) 29 | bool = nativeCodeUnit.process() 30 | 31 | # 获取INativeDecompilerUnit并执行解析 32 | nativeDecompilerUnit = DecompilerHelper.getDecompiler(nativeCodeUnit); assert isinstance(nativeDecompilerUnit,INativeDecompilerUnit) 33 | bool = nativeDecompilerUnit.process() 34 | 35 | # 获取函数对应顶层ICElement 36 | nativeSourceUnit = nativeDecompilerUnit.decompile("sub_11110"); assert isinstance(nativeSourceUnit,INativeSourceUnit) 37 | rootElement = nativeSourceUnit.getRootElement() 38 | # print rootElement 39 | 40 | # 输出 41 | displayTree(rootElement,0) 42 | 43 | ''' 44 | 输出 45 | ---------------------------------------- 46 | (1, '<', Definition, '> >>>') 47 | unsigned int param0 48 | ---------------------------------------- 49 | (1, '<', Block, '> >>>') 50 | { 51 | unsigned int v0; 52 | unsigned int v1 = param0; 53 | param0 = *(param0 + 36); 54 | if(param0 != 0) { 55 | param0 += 12; 56 | DMB(); 57 | v0 = *param0; 58 | *param0 = v0 - 1; 59 | DMB(); 60 | if(v0 == 1) { 61 | _ptr_cv::Mat::deallocate(); 62 | } 63 | } 64 | v0 = 0; 65 | *(v1 + 16) = 0; 66 | *(v1 + 20) = 0; 67 | *(v1 + 24) = 0; 68 | *(v1 + 28) = 0; 69 | *(v1 + 36) = 0; 70 | while(*(v1 + 4) > ((int)v0)) { 71 | *(v0 * 4 + *(v1 + 40)) = 0; 72 | ++v0; 73 | } 74 | return 0; 75 | } 76 | ---------------------------------------- 77 | (2, '<', Definition, '> >>>') 78 | unsigned int v0 79 | ---------------------------------------- 80 | (2, '<', Assignment, '> >>>') 81 | unsigned int v1 = param0 82 | ---------------------------------------- 83 | (3, '<', Definition, '> >>>') 84 | unsigned int v1 85 | ---------------------------------------- 86 | (3, '<', Identifier, '> >>>') 87 | param0 88 | ---------------------------------------- 89 | (2, '<', Assignment, '> >>>') 90 | param0 = *(param0 + 36) 91 | ---------------------------------------- 92 | (3, '<', Identifier, '> >>>') 93 | param0 94 | ---------------------------------------- 95 | (3, '<', Operation, '> >>>') 96 | * param0 + 36 97 | ---------------------------------------- 98 | (4, '<', Operation, '> >>>') 99 | param0 + 36 100 | ...... 101 | 102 | ''' -------------------------------------------------------------------------------- /samples/52 INativeSourceUnit-ICIfStm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit, INativeCodeUnit 5 | from com.pnfsoftware.jeb.core.units.code.asm.decompiler import INativeDecompilerUnit, INativeSourceUnit 6 | from com.pnfsoftware.jeb.core.units.code.asm.decompiler.ast import ICMethod, ICIfStm 7 | from com.pnfsoftware.jeb.core.util import DecompilerHelper 8 | 9 | def displayTree(e, level=0): 10 | dispatch(e,level) 11 | if e: 12 | elts = e.getSubElements() 13 | for e in elts: 14 | displayTree(e, level+1) 15 | pass 16 | 17 | def dispatch(ele,level): 18 | if isinstance(ele,ICIfStm): 19 | # 分支代码序列(ICBlock) 20 | print "level:",level," ","BranchBody(0) >>> " 21 | print ele.getBranchBody(0) 22 | 23 | # if括号中的谓词 24 | print "BranchPredicate(0) >>> " 25 | print ele.getBranchPredicate(0) 26 | print "-----------------------" 27 | pass 28 | 29 | # 语法树元素ifelse 30 | def Test(ctx): 31 | assert isinstance(ctx,IClientContext) 32 | input_path = r"D:\tmp\2\project\about_dex_diff\code\xmly\libFace3D.so" 33 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 34 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 35 | 36 | # 获取INativeCodeUnit并执行解析 37 | nativeCodeUnit = prj.findUnit(INativeCodeUnit); assert isinstance(nativeCodeUnit,INativeCodeUnit) 38 | bool = nativeCodeUnit.process() 39 | 40 | # 获取INativeDecompilerUnit并执行解析 41 | nativeDecompilerUnit = DecompilerHelper.getDecompiler(nativeCodeUnit); assert isinstance(nativeDecompilerUnit,INativeDecompilerUnit) 42 | bool = nativeDecompilerUnit.process() 43 | 44 | # 获取函数对应顶层ICElement 45 | nativeSourceUnit = nativeDecompilerUnit.decompile("sub_11110"); assert isinstance(nativeSourceUnit,INativeSourceUnit) 46 | rootElement = nativeSourceUnit.getRootElement() 47 | 48 | # 输出全部(F5反编译效果) 49 | # print rootElement 50 | 51 | # 输出抽象语法树元素 52 | displayTree(rootElement,0) 53 | 54 | ''' 55 | level: 2 BranchBody(0) >>> 56 | { 57 | param0 += 12; 58 | DMB(); 59 | v0 = *param0; 60 | *param0 = v0 - 1; 61 | DMB(); 62 | if(v0 == 1) { 63 | _ptr_cv::Mat::deallocate(); 64 | } 65 | } 66 | BranchPredicate(0) >>> 67 | param0 != 0 68 | ----------------------- 69 | level: 4 BranchBody(0) >>> 70 | { 71 | _ptr_cv::Mat::deallocate(); 72 | } 73 | BranchPredicate(0) >>> 74 | v0 == 1 75 | ----------------------- 76 | ''' -------------------------------------------------------------------------------- /samples/61 Dex-QUERY_XREFS.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.actions import ActionXrefsData, Actions, ActionContext 5 | from com.pnfsoftware.jeb.core.units import IUnit 6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit 7 | from com.pnfsoftware.jeb.core.units.code.android.dex import IDexMethod, IDexClass 8 | 9 | def Test(ctx): 10 | assert isinstance(ctx,IClientContext) 11 | input_path = r"D:\tmp\2\project\about_dex_diff\code\jsq\jsq.dex" 12 | class_sign = "Lcom/BestCalculatorCN/MyCalculator;" 13 | method_sign = "Lcom/BestCalculatorCN/MyCalculator;->b(Lcom/BestCalculatorCN/MyCalculator;Ljava/lang/String;)V" 14 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 15 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 16 | dexUnit = prj.findUnit(IDexUnit); assert isinstance(dexUnit,IDexUnit) 17 | clz = dexUnit.getClass(class_sign); assert isinstance(clz,IDexClass) 18 | method = dexUnit.getMethod(method_sign); assert isinstance(method,IDexMethod) 19 | 20 | # 1 查询某method交叉引用列表 21 | # 使用(unit,操作,地址,itemid)来创建一个context对象,提供给JEB引擎,用于后续执行 22 | print "------------------------------------------------" 23 | actionXrefsData = ActionXrefsData() 24 | actionContext = ActionContext(dexUnit, Actions.QUERY_XREFS, method.getItemId(), None) 25 | if unit.prepareExecution(actionContext,actionXrefsData): 26 | for xref_addr in actionXrefsData.getAddresses(): 27 | print xref_addr 28 | 29 | # 2 查询整个class的交叉引用列表 30 | print "------------------------------------------------" 31 | actionXrefsData = ActionXrefsData() 32 | actionContext = ActionContext(dexUnit, Actions.QUERY_XREFS, clz.getItemId(), None) 33 | if unit.prepareExecution(actionContext,actionXrefsData): 34 | for idx,xref_addr in enumerate(actionXrefsData.getAddresses()): 35 | print idx,xref_addr -------------------------------------------------------------------------------- /samples/62 Native-Callees Callers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit, INativeCodeUnit 5 | from com.pnfsoftware.jeb.core.units.code.asm.analyzer import INativeCodeAnalyzer, INativeCodeModel, IReferenceManager, ICallGraphManager, ICallGraph, CallGraphVertex 6 | from com.pnfsoftware.jeb.core.units.code.asm.items import INativeMethodItem 7 | 8 | 9 | # callees/callers 调用与被调用信息 10 | def Test(ctx): 11 | assert isinstance(ctx,IClientContext) 12 | input_path = r"D:\tmp\2\project\about_dex_diff\code\xmly\libFace3D.so" 13 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 14 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 15 | 16 | # 获取INativeCodeUnit并执行解析 17 | nativeCodeUnit = prj.findUnit(INativeCodeUnit); assert isinstance(nativeCodeUnit,INativeCodeUnit) 18 | bool = nativeCodeUnit.process() 19 | 20 | # 获取INativeCodeAnalyzer,获取INativeCodeModel 21 | nativeCodeAnalyzer = nativeCodeUnit.getCodeAnalyzer(); assert isinstance(nativeCodeAnalyzer,INativeCodeAnalyzer) 22 | nativeCodeAnalyzer.analyze() 23 | nativeCodeModel = nativeCodeAnalyzer.getModel(); assert isinstance(nativeCodeModel,INativeCodeModel) 24 | 25 | # 获取ICallGraph 26 | callGraph = nativeCodeModel.getCallGraphManager().getGlobalCallGraph(); assert isinstance(callGraph,ICallGraph) 27 | 28 | # 函数 29 | funcName = "libunwind::LocalAddressSpace::findFunctionName" 30 | nativeMethodItem = nativeCodeUnit.getMethod(funcName); assert isinstance(nativeMethodItem,INativeMethodItem) 31 | print ">>> funcAddr:",hex(nativeMethodItem.getRoutineAddress()) 32 | 33 | # callees 目标函数调用了谁 34 | callGraphVertexList = callGraph.getCallees(nativeMethodItem,False) 35 | for callGraphVertex in callGraphVertexList: 36 | assert isinstance(callGraphVertex,CallGraphVertex) 37 | print ">>> Callee:",hex(callGraphVertex.getInternalAddress().getAddress()) 38 | 39 | # callers 目标函数被谁调用 40 | callerList = callGraph.getCallers(nativeMethodItem,False) 41 | for caller in callerList: 42 | print ">>> Callers:",hex(caller) 43 | 44 | # >>> funcAddr: 0x19a1cL 45 | # >>> Callee: 0xabfcL 46 | # >>> Callee: 0xac08L 47 | # >>> Callee: 0x9cc0L 48 | # >>> Callers: 0x196b2L -------------------------------------------------------------------------------- /samples/63 Native-CrossReference.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit, INativeCodeUnit 5 | from com.pnfsoftware.jeb.core.units.code import EntryPointDescription 6 | from com.pnfsoftware.jeb.core.units.code.asm.analyzer import INativeCodeAnalyzer, INativeCodeModel, IReferenceManager, ICallGraphManager, ICallGraph, CallGraphVertex 7 | from com.pnfsoftware.jeb.core.units.code.asm.items import INativeMethodItem 8 | 9 | 10 | # 原生库交叉引用信息 11 | def Test(ctx): 12 | assert isinstance(ctx,IClientContext) 13 | input_path = r"D:\tmp\2\project\about_dex_diff\code\xmly\libFace3D.so" 14 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 15 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 16 | 17 | # 获取INativeCodeUnit并执行解析 18 | nativeCodeUnit = prj.findUnit(INativeCodeUnit); assert isinstance(nativeCodeUnit,INativeCodeUnit) 19 | bool = nativeCodeUnit.process() 20 | 21 | # 获取INativeCodeAnalyzer,获取INativeCodeModel 22 | nativeCodeAnalyzer = nativeCodeUnit.getCodeAnalyzer(); assert isinstance(nativeCodeAnalyzer,INativeCodeAnalyzer) 23 | nativeCodeAnalyzer.analyze() 24 | nativeCodeModel = nativeCodeAnalyzer.getModel(); assert isinstance(nativeCodeModel,INativeCodeModel) 25 | 26 | # 获取一个函数入口指令地址的交叉引用列表 27 | funcName = "libunwind::LocalAddressSpace::findFunctionName" 28 | funcAddr = nativeCodeUnit.getMethod(funcName).getRoutineAddress() 29 | print ">>> funcAddr:",hex(funcAddr) 30 | referenceManager = nativeCodeModel.getReferenceManager() 31 | referenceList = referenceManager.getReferencesToTarget(funcAddr) 32 | print ">>> funcAddr referenceList:",referenceList 33 | 34 | # 获取一个基本块入口指令地址的交叉引用列表 35 | referenceList = referenceManager.getReferencesToTarget(0x19A5E) 36 | print ">>> block referenceList:",referenceList 37 | 38 | # >>> funcAddr: 0x19a1cL 39 | # >>> funcAddr referenceList: [196B2h] 40 | # >>> block referenceList: [19A3Ch, 19A40h] -------------------------------------------------------------------------------- /samples/64 Native-Contain.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from com.pnfsoftware.jeb.client.api import IClientContext 3 | from com.pnfsoftware.jeb.core import IRuntimeProject 4 | from com.pnfsoftware.jeb.core.units import IUnit, INativeCodeUnit 5 | from com.pnfsoftware.jeb.core.units.code import EntryPointDescription 6 | from com.pnfsoftware.jeb.core.units.code.asm.analyzer import INativeCodeAnalyzer, INativeCodeModel, IReferenceManager, ICallGraphManager, ICallGraph, CallGraphVertex 7 | from com.pnfsoftware.jeb.core.units.code.asm.items import INativeMethodItem 8 | 9 | 10 | def Test(ctx): 11 | assert isinstance(ctx,IClientContext) 12 | input_path = r"D:\tmp\2\project\about_dex_diff\code\xmly\libFace3D.so" 13 | unit = ctx.open(input_path); assert isinstance(unit,IUnit) 14 | prj = ctx.getMainProject(); assert isinstance(prj,IRuntimeProject) 15 | 16 | # 获取INativeCodeUnit并执行解析 17 | nativeCodeUnit = prj.findUnit(INativeCodeUnit); assert isinstance(nativeCodeUnit,INativeCodeUnit) 18 | bool = nativeCodeUnit.process() 19 | 20 | # 获取INativeCodeAnalyzer,获取INativeCodeModel 21 | nativeCodeAnalyzer = nativeCodeUnit.getCodeAnalyzer(); assert isinstance(nativeCodeAnalyzer,INativeCodeAnalyzer) 22 | nativeCodeAnalyzer.analyze() 23 | nativeCodeModel = nativeCodeAnalyzer.getModel(); assert isinstance(nativeCodeModel,INativeCodeModel) 24 | 25 | # 返回该地址所在函数的首地址 26 | print "-------------------" 27 | r = nativeCodeModel.getContainedRoutineAddresses(0x19A60) 28 | print ">>> ",hex(r[0]) 29 | 30 | # 返回该地址所在基本块 31 | print "-------------------" 32 | r = nativeCodeModel.getBasicBlockHeader(0x19A60) 33 | for insn in r.getInstructions(): 34 | print ">>> ",insn.getMnemonic() 35 | 36 | # ------------------- 37 | # >>> 0x19a1cL 38 | # ------------------- 39 | # >>> LDR 40 | # >>> LDR 41 | # >>> SUBS 42 | # >>> ITTT 43 | # >>> ADDEQ 44 | # >>> POPEQ 45 | # >>> POPEQ --------------------------------------------------------------------------------