def run(self, ctx): OUTDIR = IO.expandPath('~/JEB_PROJECT_BINARY_EXTRACTED') prj = ctx.getMainProject() print('=> Dumping binary units of project to directory: %s' % OUTDIR) for art in prj.getLiveArtifacts(): for unit in art.getUnits(): self.checkUnit(unit, OUTDIR + '/' + art.getArtifact().getName())
def checkUnit(self, unit, basename, level=0): basename2 = basename+'/'+unit.getName() unitsize = -1 if isinstance(unit, IBinaryUnit): unitinput = unit.getInput() print('Creating dir: %s' % basename) if not os.path.exists(basename): os.makedirs(basename) try: print('Writing file: %s (%db)' % (basename2, unitinput.getCurrentSize())) f = File(basename2) data = IO.readInputStream(unitinput.getStream()) IO.writeFile(f, data, 0, len(data)) except Exception as e: print('An error occurred: %s' % e) basename2 = basename2 + '_sub' # recurse over children units for c in unit.getChildren(): self.checkUnit(c, basename2, level + 1)
def decompileCodeUnit(self, codeUnit): # make sure the code unit is processed if not codeUnit.isProcessed(): if not codeUnit.process(): print('The code unit cannot be processed!') return decomp = DecompilerHelper.getDecompiler(codeUnit) if not decomp: print('There is no decompiler available for code unit %s' % codeUnit) return outdir = os.path.join(self.outputDir, codeUnit.getName() + '_decompiled') print('Output folder: %s' % outdir) if self.decompileNative and isinstance(codeUnit, INativeCodeUnit): for m in codeUnit.getMethods(): a = m.getAddress() print('Decompiling: %s' % a) srcUnit = decomp.decompile(a) if srcUnit: self.exportSourceUnit(srcUnit, outdir) elif self.decompileDex and isinstance(codeUnit, IDexUnit): exp = DexDecompilerExporter(decomp) exp.setOutputFolder(IO.createFolder(outdir)) # limit to 1 minute max per method exp.setMethodTimeout(1 * 60000) # limit to 15 minutes (total) exp.setTotalTimeout(15 * 60000) # set a callback to output real-time information about what's being decompiled from com.pnfsoftware.jeb.util.base import ProgressCallbackAdapter class DecompCallback(ProgressCallbackAdapter): def message(__self__, msg): print(msg) exp.setCallback(DecompCallback()) # decompile & export if not exp.export(): cnt = len(exp.getErrors()) i = 1 for sig, err in exp.getErrors().items(): print('%d/%d DECOMPILATION ERROR: METHOD %s: %s' % (i, cnt, sig, err)) i += 1
def decompileCodeUnit(self, codeUnit): # make sure the code unit is processed if not codeUnit.isProcessed(): if not codeUnit.process(): print('The code unit cannot be processed!') return decomp = DecompilerHelper.getDecompiler(codeUnit) if not decomp: print('There is no decompiler available for code unit %s' % codeUnit) return outdir = os.path.join(self.outputDir, codeUnit.getName() + '_decompiled') print('Output folder: %s' % outdir ) # created only if necessary, i.e. some contents was exported if not ( (isinstance(codeUnit, INativeCodeUnit) and self.decompileNative) or (isinstance(codeUnit, IDexUnit) and self.decompileDex)): print('Skipping code unit: %s' % UnitUtil.buildFullyQualifiedUnitPath(codeUnit)) return # DecompilerExporter object exp = decomp.getExporter() exp.setOutputFolder(IO.createFolder(outdir)) # limit to 1 minute max per method exp.setMethodTimeout(1 * 60000) # limit to 15 minutes (total) exp.setTotalTimeout(15 * 60000) # set a callback to output real-time information about what's being decompiled class DecompCallback(ProgressCallbackAdapter): def message(self, msg): print('%d/%d: %s' % (self.getCurrent(), self.getTotal(), msg)) exp.setCallback(DecompCallback()) # decompile & export if not exp.export(): cnt = len(exp.getErrors()) i = 1 for sig, err in exp.getErrors().items(): print('%d/%d DECOMPILATION ERROR: METHOD %s: %s' % (i, cnt, sig, err)) i += 1
def run(self, ctx): self.ctx = ctx engctx = ctx.getEnginesContext() if not engctx: print('Back-end engines not initialized') return projects = engctx.getProjects() if not projects: print('There is no opened project') return OUTDIR = IO.expandPath('~/JEB_PROJECT_BINARY_EXTRACTED') prj = projects[0] print('=> Dumping binary units of project to directory: %s' % OUTDIR) for art in prj.getLiveArtifacts(): for unit in art.getUnits(): self.checkUnit(unit, OUTDIR+'/'+art.getArtifact().getName())
def run(self, ctx): # retrieve RTTI unit prj = ctx.getMainProject() if not prj: print('Need a project') return units = prj.findUnits(IBinaryUnit) if not units or len(units) == 0: print('Need RTTI unit') return rttiUnit = None for unit in units: if unit.getName() == 'run-time type information': rttiUnit = unit if not rttiUnit: print('Need RTTI unit') data = IO.readInputStream(rttiUnit.getInput().getStream()) rttiText = ''.join(chr(c) for c in data) # parsing g = Digraph.create() curId = 0 classToId = dict() virtualEdges = list() # [[childId, parentId]] lines = rttiText.splitlines()[2:] # skip header for line in lines: line = line.strip()[:-1] # beautify if not line.startswith('class'): continue classes = line.split(CLASS_SEPARATOR) if len(classes) > 2: print('error: malformed line (%s)' % line) continue # register base class id baseClassName = classes[0][6:] if IGNORE_STD and baseClassName.startswith('std::'): continue if baseClassName not in classToId.keys(): g.v(curId, None, baseClassName) classToId[baseClassName] = curId curId += 1 print('baseClassName=%s' % baseClassName) # add edges for each parent, if any if len(classes) == 1: continue for parent in classes[1].split(PARENT_SEPARATOR): parentStr = parent.split() if len(parentStr) < 2: print('error: malformed line (%s)' % line) continue isPublic = parentStr[0] == 'public' isVirtual = parentStr[1] == 'virtual' parentStartIndex = 7 if isPublic else 8 parentStartIndex += 8 if isVirtual else 0 parentName = parent[parentStartIndex:] print(' parentName=%s, isPublic = %d, isVirtual = %d' % (parentName, isPublic, isVirtual)) if parentName not in classToId.keys(): g.v(curId, None, parentName) classToId[parentName] = curId curId += 1 g.e(classToId[baseClassName], classToId[parentName]) if isVirtual: virtualEdges.append( [classToId[baseClassName], classToId[parentName]]) class Ext(GraphDialogExtensions): def getEdgeStyle(self, vertexId0, vertexId1): if [vertexId0, vertexId1] in virtualEdges: # dashed edges to represent virtual inheritance return EdgeStyle.DASHED return EdgeStyle.SOLID def getVertexShape(self, vertexId): return VertexShape.SQUARE_FILLED g.done() ctx.displayGraph('RTTI Class Relationship Graph', g, Ext())