def test_jmpreg(self): ropper = Ropper() regs=['rax'] gadgets = ropper.searchJmpReg(self.file, regs) gadget = gadgets[0] self.assertEqual(len(gadgets), 4) self.assertEqual(gadget.lines[0][0], 0x19bb) regs=['rcx','rax'] gadgets = ropper.searchJmpReg(self.file, regs) self.assertEqual(len(gadgets), 7) self.assertEqual(gadget.imageBase, 0x100000000) self.file.imageBase = 0x0 Gadget.IMAGE_BASES[self.file.checksum] = self.file.imageBase self.assertEqual(gadget.imageBase, 0x0) self.file.imageBase = None Gadget.IMAGE_BASES[self.file.checksum] = self.file.imageBase self.assertEqual(gadget.imageBase, 0x100000000) with self.assertRaises(RopperError): regs=['invalid'] ropper.searchJmpReg(self.file, regs)
def test_jmpreg(self): ropper = Ropper() regs=['rsp'] gadgets = ropper.searchJmpReg(self.file, regs) gadget = gadgets[0] self.assertEqual(len(gadgets), 18) self.assertEqual(gadget.lines[0][0], 0xb1c7) regs=['rsp','rax'] gadgets = ropper.searchJmpReg(self.file, regs) self.assertEqual(len(gadgets), 25) self.assertEqual(gadget.imageBase, 0x400000) self.file.imageBase = 0x0 Gadget.IMAGE_BASES[self.file.fileName] = self.file.imageBase self.assertEqual(gadget.imageBase, 0x0) self.file.imageBase = None Gadget.IMAGE_BASES[self.file.fileName] = self.file.imageBase self.assertEqual(gadget.imageBase, 0x400000) with self.assertRaises(RopperError): regs=['invalid'] ropper.searchJmpReg(self.file, regs)
def test_jmpreg(self): ropper = Ropper() regs = ["rsp"] gadgets = ropper.searchJmpReg(self.file, regs) gadget = gadgets[0] self.assertEqual(len(gadgets), 3) self.assertEqual(gadget.lines[0][0], 0x37DD) regs = ["rsp", "rax"] gadgets = ropper.searchJmpReg(self.file, regs) self.assertEqual(len(gadgets), 15) self.assertEqual(gadget.imageBase, 0x4AD00000) self.file.imageBase = 0x0 self.assertEqual(gadget.imageBase, 0x0) self.file.imageBase = None self.assertEqual(gadget.imageBase, 0x4AD00000)
def test_badbytes(self): r = Ropper() badbytes = 'adfd' gadgets = r.searchGadgets(self.file) gadgets = ropper.filterBadBytes(gadgets, badbytes) gadget = gadgets[0] self.assertNotEqual(gadget.lines[0][0], 0x1adfd) badbytes = '52f8' gadgets = r.searchPopPopRet(self.file) gadgets = ropper.filterBadBytes(gadgets, badbytes) self.assertNotEqual(gadgets[0].lines[0][0], 0x52f8) badbytes = 'b1c7' gadgets = r.searchJmpReg(self.file, ['rsp']) gadgets = ropper.filterBadBytes(gadgets, badbytes) gadget = gadgets[0] self.assertNotEqual(gadget.lines[0][0], 0xb1c7) with self.assertRaises(RopperError): badbytes = 'b1c' gadgets = ropper.filterBadBytes(gadgets, badbytes) with self.assertRaises(RopperError): badbytes = 'qwer' gadgets = ropper.filterBadBytes(gadgets, badbytes)
def test_badbytes(self): r = Ropper() badbytes = "adfd" gadgets = r.searchGadgets(self.file) gadgets = ropper.filterBadBytes(gadgets, badbytes) gadget = gadgets[0] self.assertNotEqual(gadget.lines[0][0], 0x1ADFD) badbytes = "52f8" gadgets = r.searchPopPopRet(self.file) gadgets = ropper.filterBadBytes(gadgets, badbytes) self.assertNotEqual(gadgets[0].lines[0][0], 0x52F8) badbytes = "b1c7" gadgets = r.searchJmpReg(self.file, ["rsp"]) gadgets = ropper.filterBadBytes(gadgets, badbytes) gadget = gadgets[0] self.assertNotEqual(gadget.lines[0][0], 0xB1C7) with self.assertRaises(RopperError): badbytes = "b1c" gadgets = ropper.filterBadBytes(gadgets, badbytes) with self.assertRaises(RopperError): badbytes = "qwer" gadgets = ropper.filterBadBytes(gadgets, badbytes)
def test_jmpreg(self): ropper = Ropper() regs = ['rsp'] gadgets = ropper.searchJmpReg(self.file, regs) gadget = gadgets[0] self.assertEqual(len(gadgets), 3) self.assertEqual(gadget.lines[0][0], 0x37dd) regs = ['rsp', 'rax'] gadgets = ropper.searchJmpReg(self.file, regs) self.assertEqual(len(gadgets), 15) self.assertEqual(gadget.imageBase, 0x4ad00000) self.file.imageBase = 0x0 self.assertEqual(gadget.imageBase, 0x0) self.file.imageBase = None self.assertEqual(gadget.imageBase, 0x4ad00000)
def test_jmpreg_pe(self): ropper = Ropper() regs=['esp'] gadgets = ropper.searchJmpReg(self.file, regs) gadget = gadgets[0] self.assertEqual(len(gadgets), 1) self.assertEqual(gadget.lines[0][0], 0xc797) regs=['esp','eax'] gadgets = ropper.searchJmpReg(self.file, regs) self.assertEqual(len(gadgets), 13) self.assertEqual(gadget.imageBase, 0x4ad00000) self.file.imageBase = 0x0 self.assertEqual(gadget.imageBase, 0x0) self.file.imageBase = None self.assertEqual(gadget.imageBase, 0x4ad00000)
def test_jmpreg(self): ropper = Ropper() regs=['rsp'] gadgets = ropper.searchJmpReg(self.file, regs) gadget = gadgets[0] self.assertEqual(len(gadgets), 3) self.assertEqual(gadget.lines[0][0], 0x37dd) regs=['rsp','rax'] gadgets = ropper.searchJmpReg(self.file, regs) self.assertEqual(len(gadgets), 15) self.assertEqual(gadget.imageBase, 0x4ad00000) self.file.imageBase = 0x0 Gadget.IMAGE_BASES[self.file.fileName] = self.file.imageBase self.assertEqual(gadget.imageBase, 0x0) self.file.imageBase = None Gadget.IMAGE_BASES[self.file.fileName] = self.file.imageBase self.assertEqual(gadget.imageBase, 0x4ad00000)
def test_jmpreg(self): ropper = Ropper() regs = ["rsp"] gadgets = ropper.searchJmpReg(self.file, regs) gadget = gadgets[0] self.assertEqual(len(gadgets), 18) self.assertEqual(gadget.lines[0][0], 0xB1C7) regs = ["rsp", "rax"] gadgets = ropper.searchJmpReg(self.file, regs) self.assertEqual(len(gadgets), 25) self.assertEqual(gadget.imageBase, 0x400000) self.file.imageBase = 0x0 self.assertEqual(gadget.imageBase, 0x0) self.file.imageBase = None self.assertEqual(gadget.imageBase, 0x400000) with self.assertRaises(RopperError): regs = ["invalid"] ropper.searchJmpReg(self.file, regs)
def test_jmpreg(self): ropper = Ropper() regs=['esp'] gadgets = ropper.searchJmpReg(self.file, regs) gadget = gadgets[0] self.assertEqual(len(gadgets), 10) self.assertEqual(gadget.lines[0][0], 0xc63) self.assertEqual(gadget.imageBase, 0x8048000) self.file.imageBase = 0x0 self.assertEqual(gadget.imageBase, 0x0) self.file.imageBase = None self.assertEqual(gadget.imageBase, 0x8048000)
def test_jmpreg_pe(self): ropper = Ropper() regs = ['esp'] gadgets = ropper.searchJmpReg(self.file, regs) gadget = gadgets[0] self.assertEqual(len(gadgets), 1) self.assertEqual(gadget.lines[0][0], 0xc797) regs = ['esp', 'eax'] gadgets = ropper.searchJmpReg(self.file, regs) self.assertEqual(len(gadgets), 13) self.assertEqual(gadget.imageBase, 0x4ad00000) self.file.imageBase = 0x0 Gadget.IMAGE_BASES[self.file.fileName] = self.file.imageBase self.assertEqual(gadget.imageBase, 0x0) self.file.imageBase = None Gadget.IMAGE_BASES[self.file.fileName] = self.file.imageBase self.assertEqual(gadget.imageBase, 0x4ad00000)
def _createJmp(self, reg=['esp']): r = Ropper() gadgets = [] for binary in self._binaries: for section in binary.executableSections: vaddr = section.virtualAddress gadgets.extend(r.searchJmpReg(binary, reg)) if len(gadgets) > 0: self._updateUsedBinaries(gadget[0]) return self._printRopInstruction(gadgets[0]) else: return None
def _createJmp(self, reg=['rsp']): r = Ropper() gadgets = [] for section in self._binaries[0].executableSections: vaddr = section.virtualAddress gadgets.extend(r.searchJmpReg(self._binaries[0], reg)) if len(gadgets) > 0: if (gadgets[0].fileName, gadgets[0].section) not in self._usedBinaries: self._usedBinaries.append( (gadgets[0].fileName, gadgets[0].section)) return self._printRopInstruction(gadgets[0]) else: return None
def _createJmp(self, reg=['rsp']): r = Ropper() gadgets = [] for section in self._binaries[0].executableSections: vaddr = section.virtualAddress gadgets.extend(r.searchJmpReg(self._binaries[0],reg)) if len(gadgets) > 0: if (gadgets[0]._binary, gadgets[0]._section) not in self._usedBinaries: self._usedBinaries.append((gadgets[0]._binary, gadgets[0]._section)) return self._printRopInstruction(gadgets[0]) else: return None
def _createJmp(self, reg=['esp']): r = Ropper() gadgets = [] for binary in self._binaries: for section in binary.executableSections: vaddr = section.offset gadgets.extend( r.searchJmpReg(binary,reg)) if len(gadgets) > 0: self._updateUsedBinaries(gadgets[0]) return gadgets[0] else: return None
def _createJmp(self, reg=['esp']): r = Ropper() gadgets = [] for binary in self._binaries: for section in binary.executableSections: vaddr = section.offset gadgets.extend( r.searchJmpReg(binary,reg)) if len(gadgets) > 0: self._updateUsedBinaries(gadget[0]) return gadgets[0] else: return None
def _createJmp(self, reg=['esp']): r = Ropper() gadgets = [] for binary in self._binaries: for section in binary.executableSections: vaddr = section.offset gadgets.extend(r.searchJmpReg(self._binaries[0], reg)) if len(gadgets) > 0: if (gadgets[0]._binary, gadgets[0]._section) not in self._usedBinaries: self._usedBinaries.append( (gadgets[0]._binary, gadgets[0]._section)) return gadgets[0] else: return None
def _createJmp(self, reg=['esp']): r = Ropper() gadgets = [] for binary in self._binaries: for section in binary.executableSections: vaddr = section.virtualAddress gadgets.extend( r.searchJmpReg(binary,reg)) if len(gadgets) > 0: self._updateUsedBinaries(gadgets[0]) return self._printRopInstruction(gadgets[0]) else: return None
def _createJmp(self, reg=['esp']): r = Ropper() gadgets = [] for section in self._binaries[0].executableSections: vaddr = section.offset gadgets.extend( r.searchJmpReg(self._binaries[0],reg)) if len(gadgets) > 0: if (gadgets[0]._binary, gadgets[0]._section) not in self._usedBinaries: self._usedBinaries.append((gadgets[0]._binary, gadgets[0]._section)) return gadgets[0] else: return ''
def test_jmpreg(self): ropper = Ropper() regs=['esp'] with self.assertRaises(NotSupportedError): gadgets = ropper.searchJmpReg(self.file, regs)
def test_jmpreg(self): ropper = Ropper() regs = ['esp'] with self.assertRaises(NotSupportedError): gadgets = ropper.searchJmpReg(self.file, regs)
def __searchJmpReg(self, regs): r = Ropper() regs = regs.split(',') gadgets = r.searchJmpReg(self.binary,regs) gadgets = ropper.filterBadBytes(gadgets, self.__options.badbytes) self.__printGadgets(gadgets, header='JMP Instructions')
class RopperService(object): ROPPER_FOLDER = os.path.expanduser('~') + os.path.sep + ".ropper/" CACHE_FOLDER = os.path.expanduser('~') + os.path.sep + ".ropper/cache/" CACHE_FILE_COUNT = 16 def __init__(self, options={}, callbacks=None): super(RopperService, self).__init__() self.__options = Options(options, self.__optionChanged) if callbacks and hasattr(callbacks, '__gadgetSearchProgress__'): self.__ropper = Ropper(callback=callbacks.__gadgetSearchProgress__) else: self.__ropper = Ropper() self.__files = [] self.__callbacks = callbacks if self.__options.color: cstr.COLOR = self.__options.color Gadget.DETAILED = self.__options.detailed @property def ropper(self): return self.__ropper @property def options(self): return self.__options @property def files(self): return list(self.__files) def __optionChanged(self, option, oldvalue, newvalue): if hasattr(self, '_%s_changed' % option): func = getattr(self, '_%s_changed' % option) func(newvalue) def __prepareGadgets(self, file, gadgets, type=None): gadgets = self.__filterBadBytes(gadgets) gadgets = self.__filterCfg(file, gadgets, type) if not self.__options.all: callback = None if self.__callbacks and hasattr(self.__callbacks, '__deleteDoubleGadgetsProgress__'): callback = self.__callbacks.__deleteDoubleGadgetsProgress__ gadgets = deleteDuplicates(gadgets, callback) return gadgets def __filterBadBytes(self, gadgets): if self.__options.badbytes: callback = None if self.__callbacks and hasattr(self.__callbacks, '__filterBadBytesGadgetsProgress__'): callback = self.__callbacks.__filterBadBytesGadgetsProgress__ gadgets = filterBadBytes(gadgets, self.options.badbytes, callback) return gadgets def __filterCfg(self, file, gadgets, type): if self.__options.cfg_only and type==Type.PE: callback = None if self.__callbacks and hasattr(self.__callbacks, '__filterCfgGadgetsProgress__'): callback = self.__callbacks.__filterCfgGadgetsProgress__ gadgets = cfgFilterGadgets(file.loader, gadgets, callback) return gadgets def __getCacheFileName(self, file): return "%s_%s_%d_%s_%d" % (file.loader.checksum, str(file.arch), self.options.inst_count,str(self.options.type), sys.version_info.major) def __saveCache(self, file): cache_file = None try: temp = RopperService.CACHE_FOLDER if not os.path.exists(temp): os.makedirs(temp) cache_file = temp + os.path.sep + self.__getCacheFileName(file) count = RopperService.CACHE_FILE_COUNT if len(file.allGadgets) > 1000: if os.path.exists(cache_file): os.remove(cache_file) length = len(file.allGadgets) step = int(length / count) for i in range(count-1): gadgets = file.allGadgets[i*step: (i+1)*step] with open(cache_file+'_%d' % (i+1),'wb') as f: f.write(encode(repr(gadgets).encode('ascii'),'zip')) gadgets = file.allGadgets[(count-1)*step:] with open(cache_file+'_%d' % (count),'wb') as f: f.write(encode(repr(gadgets).encode('ascii'),'zip')) return with open(cache_file,'wb') as f: f.write(encode(repr(file.allGadgets).encode('ascii'),'zip')) except BaseException as e: print(e) if cache_file: for i in range(1, RopperService.CACHE_FILE_COUNT+1): if os.path.exists(cache_file+'_%d' % i): os.remove(cache_file+'_%d' % i) def __loadCachePerProcess(self, fqueue, gqueue): nan=0 while True: cacheFileName = fqueue.get() if cacheFileName is None: fqueue.task_done() break if os.path.exists(cacheFileName): with open(cacheFileName,'rb') as f: data = f.read() gqueue.put(eval(decode(data,'zip'))) else: gqueue.put([]) fqueue.task_done() def __loadCache(self, file): mp = False nan= 0 processes = [] single = False cache_file = None try: temp = RopperService.CACHE_FOLDER cache_file = temp + os.path.sep + self.__getCacheFileName(file) if not os.path.exists(cache_file): if not os.path.exists(cache_file+'_%d' % 1): return else: mp = True and multiprocessing.cpu_count()>1 else: single = True if self.__callbacks and hasattr(self.__callbacks, '__message__'): self.__callbacks.__message__('Load gadgets from cache') if self.__callbacks and hasattr(self.__callbacks, '__gadgetSearchProgress__'): self.__callbacks.__gadgetSearchProgress__(None, [], 0) if not mp: all_gadgets = [] if single: with open(cache_file,'rb') as f: data = f.read() all_gadgets.extend(eval(decode(data,'zip'))) if self.__callbacks and hasattr(self.__callbacks, '__gadgetSearchProgress__'): self.__callbacks.__gadgetSearchProgress__(None, all_gadgets, 1.0) else: for i in range(1,RopperService.CACHE_FILE_COUNT+1): if os.path.exists(cache_file+'_%d' % i): with open(cache_file+'_%d' % i,'rb') as f: data = f.read() all_gadgets.extend(eval(decode(data,'zip'))) if self.__callbacks and hasattr(self.__callbacks, '__gadgetSearchProgress__'): self.__callbacks.__gadgetSearchProgress__(None, all_gadgets, float(i)/RopperService.CACHE_FILE_COUNT) return all_gadgets else: count = min(multiprocessing.cpu_count(),RopperService.CACHE_FILE_COUNT) gqueue = multiprocessing.Queue() fqueue = multiprocessing.JoinableQueue() for i in range(1,RopperService.CACHE_FILE_COUNT+1): fqueue.put(cache_file+'_%d' % i) all_gadgets = [] for i in range(count): p=multiprocessing.Process(target=self.__loadCachePerProcess, args=(fqueue, gqueue)) p.start() processes.append(p) for i in range(count): fqueue.put(None) for i in range(RopperService.CACHE_FILE_COUNT): gadgets = gqueue.get() all_gadgets.extend(gadgets) if self.__callbacks and hasattr(self.__callbacks, '__gadgetSearchProgress__'): self.__callbacks.__gadgetSearchProgress__(None, all_gadgets, float(i+1)/RopperService.CACHE_FILE_COUNT) return sorted(all_gadgets, key=Gadget.simpleInstructionString) except KeyboardInterrupt: if mp: for p in processes: if p and p.is_alive(): p.terminate() except BaseException as e: if mp: for p in processes: if p and p.is_alive(): p.terminate() if cache_file: for i in range(1,RopperService.CACHE_FILE_COUNT+1): if os.path.exists(cache_file+'_%d' % i): os.remove(cache_file+'_%d' % i) def _badbytes_changed(self, value): for f in self.__files: if f.loaded: f.gadgets = self.__prepareGadgets(f, f.allGadgets, f.type) def _all_changed(self, value): for f in self.__files: if f.loaded: f.gadgets = self.__prepareGadgets(f, f.allGadgets, f.type) def _color_changed(self, value): cstr.COLOR = value def _detailed_changed(self, value): Gadget.DETAILED = value def _cfg_only_changed(self, value): for f in self.__files: if f.loaded and f.type == Type.PE: f.gadgets = self.__prepareGadgets(f, f.allGadgets, f.type) def _type_changed(self, value): for f in self.__files: if f.loaded: self.loadGadgetsFor(f.name) def _inst_count_changed(self, value): for f in self.__files: if f.loaded: self.loadGadgetsFor(f.name) def _getFileFor(self, name): for file in self.__files: if file.loader.fileName == name: return file return None def clearCache(self): temp = RopperService.CACHE_FOLDER if os.path.exists(temp): import shutil shutil.rmtree(temp) def getFileFor(self, name): return self._getFileFor(name) def addFile(self, name, bytes=None, arch=None, raw=False): if self._getFileFor(name): raise RopperError('file is already added: %s' % name) if arch: arch=getArchitecture(arch) loader = Loader.open(name, bytes=bytes, raw=raw, arch=arch) file = FileContainer(loader) self.__files.append(file) def removeFile(self, name): for idx, fc in enumerate(self.__files): if fc.loader.fileName == name: del self.__files[idx] def asm(self, code, arch='x86', format='hex'): if format not in ('hex', 'string', 'raw'): raise RopperError('Invalid format: %s\n Valid formats are: hex, string, raw' % format) format = Format.HEX if format=='hex' else Format.STRING if format=='string' else Format.RAW return self.ropper.assemble(code, arch=getArchitecture(arch), format=format) def disasm(self, opcode, arch='x86'): return self.ropper.disassemble(opcode, arch=getArchitecture(arch)) def searchPopPopRet(self, name=None): to_return = {} if not name: for file in self.__files: to_return[file.loader.fileName] = self.__ropper.searchPopPopRet(file.loader) else: fc = self._getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) to_return[name] = self.__ropper.searchPopPopRet(fc.loader) return self.__filterBadBytes(to_return) def searchJmpReg(self, regs=['esp'],name=None): to_return = {} if not name: for file in self.__files: to_return[file.loader.fileName] = self.__ropper.searchJmpReg(file.loader, regs) else: fc = self._getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) to_return[name] = self.__ropper.searchJmpReg(fc.loader, regs) return self.__filterBadBytes(to_return) def searchOpcode(self, opcode, name=None): to_return = {} if not name: for file in self.__files: to_return[file.loader.fileName] = self.__ropper.searchOpcode(file.loader, opcode) else: fc = self.getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) to_return[name] = self.__ropper.searchOpcode(fc.loader, opcode) return self.__filterBadBytes(to_return) def searchInstructions(self, code, name=None): to_return = {} if not name: for file in self.__files: to_return[file.loader.fileName] = self.__ropper.searchInstructions(file.loader, code) else: fc = self.getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) to_return[name] = self.__ropper.searchInstructions(fc.loader, code) return self.__filterBadBytes(to_return) def analyseGadgets(self, fileObject): gadgets = fileObject.gadgets analyser = Analyser() cb = None lg = len(gadgets) if self.__callbacks and hasattr(self.__callbacks, '__analyseGadgetsProgress__'): cb = self.__callbacks.__analyseGadgetsProgress__ for i,g in enumerate(gadgets): g.info = analyser.analyse(g) if cb: cb(g, float(i)/lg) if cb: cb(None, 1.0) self.__saveCache(fileObject) fileObject.analysed = True def loadGadgetsFor(self, name=None): def load_gadgets(f): gtype = None cache = False Gadget.IMAGE_BASES[f.loader.checksum] = f.loader.imageBase if self.options.type == 'rop': gtype = GadgetType.ROP elif self.options.type == 'jop': gtype = GadgetType.JOP elif self.options.type == 'sys': gtype = GadgetType.SYS elif self.options.type == 'all': gtype = GadgetType.ALL f.allGadgets = self.__loadCache(f) if f.allGadgets == None: cache = True f.allGadgets = self.__ropper.searchGadgets(f.loader, instructionCount=self.options.inst_count, gtype=gtype) if cache: self.__saveCache(f) f.gadgets = self.__prepareGadgets(f, f.allGadgets, f.type) f.analysed = f.gadgets[0].info is not None if len(f.gadgets) > 0 else False #self._analyseGadgets(f.gadgets) if name is None: for fc in self.__files: load_gadgets(fc) else: for fc in self.__files: if fc.loader.fileName == name: load_gadgets(fc) def printGadgetsFor(self, name=None): def print_gadgets(f): print(f.loader.fileName) for g in f.gadgets: if self.options.detailed: print(g) else: print(g.simpleString()) if name is None: for f in self.__files: print_gadgets(f) else: for f in self.__files: if f.loader.fileName == name: print_gadgets(f) def searchString(self, string='', name=None): def search(f, string): data = [] if not string or string == '[ -~]{2}[ -~]*': string = '[ -~]{2}[ -~]*' else: string = f.arch.searcher.prepareFilter(string) sections = list(f.dataSections) string = string.encode('ascii') # python 3 compatibility for section in sections: b = bytes(bytearray(section.bytes)) for match in re.finditer(string, b): vaddr = f.imageBase + section.offset if f.imageBase != None else section.virtualAddress data.append( (match.start() + vaddr , match.group())) return data to_return = {} if not name: for file in self.__files: to_return[file.loader.fileName] = search(file.loader, string) else: fc = self._getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) to_return[name] = search(fc.loader, string) return to_return def search(self, search, quality=None, name=None): if name: fc = self._getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) s = fc.loader.arch.searcher for gadget in s.search(fc.gadgets, search, quality): yield(fc.name, gadget) else: for fc in self.__files: s = fc.loader.arch.searcher for gadget in s.search(fc.gadgets, search, quality): yield(fc.name, gadget) def semanticSearch(self, search, stableRegs=[], name=None): count = 0 if name: fc = self._getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) s = fc.loader.arch.searcher for gadget in s.semanticSearch(fc.gadgets, search, self.options.inst_count, stableRegs): if self.options.count_of_findings == 0 or self.options.count_of_findings > count: yield(fc.name, gadget) else: break count += 1 self.__saveCache(fc) else: for fc in self.__files: s = fc.loader.arch.searcher for gadget in s.semanticSearch(fc.gadgets, search, self.options.inst_count, stableRegs): if self.options.count_of_findings == 0 or self.options.count_of_findings > count: yield(fc.name, gadget) else: break count += 1 self.__saveCache(fc) def searchdict(self, search, quality=None, name=None): to_return = {} for file, gadget in self.search(search, quality, name): l = to_return.get(file) if not l: l = [] to_return[file] = l l.append(gadget) return to_return def disassAddress(self, name, address, length): fc = self.getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) eSections = fc.loader.executableSections for section in eSections: if section.virtualAddress <= address and section.virtualAddress + section.size > address: ropper = Ropper() g = ropper.disassembleAddress(section, fc.loader, address, address - (fc.loader.imageBase+section.offset), length) if not g: raise RopperError('Cannot disassemble address: %s' % toHex(address)) if length < 0: length = length * -1 return g.disassemblyString() return '' def createRopChain(self, chain, arch, options={}): callback = None if self.__callbacks and hasattr(self.__callbacks, '__ropchainMessages__'): callback = self.__callbacks.__ropchainMessages__ b = [] gadgets = {} for binary in self.__files: if str(binary.arch) == arch: gadgets[binary.loader] = binary.gadgets b.append(binary.loader) generator = RopChain.get(b, gadgets, chain, callback, unhexlify(self.options.badbytes)) if not generator: raise RopperError('%s does not have support for %s chain generation at the moment. Its a future feature.' % (self.files[0].loader.arch.__class__.__name__, chain)) return generator.create(options) def setImageBaseFor(self, name, imagebase): file = self._getFileFor(name) if not file: raise RopperError('No such file opened: %s' % name) file.loader.imageBase = imagebase Gadget.IMAGE_BASES[file.loader.checksum] = file.loader.imageBase if file.loaded and (self.options.badbytes or self.options.cfg_only and file.type == Type.PE): file.gadgets = self.__prepareGadgets(file, file.allGadgets, file.type) def setArchitectureFor(self, name, arch): file = self.getFileFor(name) if not file: raise RopperError('No such file opened: %s' % name) file.loader.arch = getArchitecture(arch) if file.loaded: self.loadGadgetsFor(name) def _setGadgets(self, name, gadgets): fc = self.getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) fc.allGadgets = gadgets fc.gadgets = self.__prepareGadgets(fc, fc.allGadgets, fc.type)
class RopperService(object): ROPPER_FOLDER = os.path.expanduser('~') + os.path.sep + ".ropper/" CACHE_FOLDER = os.path.expanduser('~') + os.path.sep + ".ropper/cache/" CACHE_FILE_COUNT = 16 def __init__(self, options={}, callbacks=None): super(RopperService, self).__init__() self.__options = Options(options, self.__optionChanged) if callbacks and hasattr(callbacks, '__gadgetSearchProgress__'): self.__ropper = Ropper(callback=callbacks.__gadgetSearchProgress__) else: self.__ropper = Ropper() self.__files = [] self.__callbacks = callbacks if self.__options.color: cstr.COLOR = self.__options.color Gadget.DETAILED = self.__options.detailed @property def ropper(self): return self.__ropper @property def options(self): return self.__options @property def files(self): return list(self.__files) def __optionChanged(self, option, oldvalue, newvalue): if hasattr(self, '_%s_changed' % option): func = getattr(self, '_%s_changed' % option) func(newvalue) def __prepareGadgets(self, file, gadgets, type=None): gadgets = self.__filterBadBytes(gadgets) gadgets = self.__filterCfg(file, gadgets, type) if not self.__options.all: callback = None if self.__callbacks and hasattr(self.__callbacks, '__deleteDoubleGadgetsProgress__'): callback = self.__callbacks.__deleteDoubleGadgetsProgress__ gadgets = deleteDuplicates(gadgets, callback) return gadgets def __filterBadBytes(self, gadgets): if self.__options.badbytes: callback = None if self.__callbacks and hasattr(self.__callbacks, '__filterBadBytesGadgetsProgress__'): callback = self.__callbacks.__filterBadBytesGadgetsProgress__ gadgets = filterBadBytes(gadgets, self.options.badbytes, callback) return gadgets def __filterCfg(self, file, gadgets, type): if self.__options.cfg_only and type==Type.PE: callback = None if self.__callbacks and hasattr(self.__callbacks, '__filterCfgGadgetsProgress__'): callback = self.__callbacks.__filterCfgGadgetsProgress__ gadgets = cfgFilterGadgets(file.loader, gadgets, callback) return gadgets def __getCacheFileName(self, file): return "%s_%s_%d_%s_%d" % (file.loader.checksum, str(file.arch), self.options.inst_count,str(self.options.type), sys.version_info.major) def __saveCache(self, file): cache_file = None try: temp = RopperService.CACHE_FOLDER if not os.path.exists(temp): os.makedirs(temp) cache_file = temp + os.path.sep + self.__getCacheFileName(file) count = RopperService.CACHE_FILE_COUNT if not isWindows() and len(file.allGadgets) > 1000: if os.path.exists(cache_file): os.remove(cache_file) length = len(file.allGadgets) step = int(length / count) for i in range(count-1): gadgets = file.allGadgets[i*step: (i+1)*step] with open(cache_file+'_%d' % (i+1),'wb') as f: f.write(encode(repr(gadgets).encode('ascii'),'zip')) gadgets = file.allGadgets[(count-1)*step:] with open(cache_file+'_%d' % (count),'wb') as f: f.write(encode(repr(gadgets).encode('ascii'),'zip')) return with open(cache_file,'wb') as f: f.write(encode(repr(file.allGadgets).encode('ascii'),'zip')) except BaseException as e: print(e) if cache_file: for i in range(1, RopperService.CACHE_FILE_COUNT+1): if os.path.exists(cache_file+'_%d' % i): os.remove(cache_file+'_%d' % i) def __loadCachePerProcess(self, fqueue, gqueue): nan=0 while True: cacheFileName = fqueue.get() if cacheFileName is None: fqueue.task_done() break if os.path.exists(cacheFileName): with open(cacheFileName,'rb') as f: data = f.read() gqueue.put(eval(decode(data,'zip'))) else: gqueue.put([]) fqueue.task_done() def __loadCache(self, file): mp = False nan= 0 processes = [] single = False cache_file = None try: temp = RopperService.CACHE_FOLDER cache_file = temp + os.path.sep + self.__getCacheFileName(file) if not os.path.exists(cache_file): if not os.path.exists(cache_file+'_%d' % 1): return else: if isWindows(): raise RopperError('Cache has to be cleared.') mp = True and multiprocessing.cpu_count()>1 else: single = True if self.__callbacks and hasattr(self.__callbacks, '__message__'): self.__callbacks.__message__('Load gadgets from cache') if self.__callbacks and hasattr(self.__callbacks, '__gadgetSearchProgress__'): self.__callbacks.__gadgetSearchProgress__(None, [], 0) if not mp: all_gadgets = [] if single: with open(cache_file,'rb') as f: data = f.read() all_gadgets.extend(eval(decode(data,'zip'))) if self.__callbacks and hasattr(self.__callbacks, '__gadgetSearchProgress__'): self.__callbacks.__gadgetSearchProgress__(None, all_gadgets, 1.0) else: for i in range(1,RopperService.CACHE_FILE_COUNT+1): if os.path.exists(cache_file+'_%d' % i): with open(cache_file+'_%d' % i,'rb') as f: data = f.read() all_gadgets.extend(eval(decode(data,'zip'))) if self.__callbacks and hasattr(self.__callbacks, '__gadgetSearchProgress__'): self.__callbacks.__gadgetSearchProgress__(None, all_gadgets, float(i)/RopperService.CACHE_FILE_COUNT) return all_gadgets else: count = min(multiprocessing.cpu_count(),RopperService.CACHE_FILE_COUNT) gqueue = multiprocessing.Queue() fqueue = multiprocessing.JoinableQueue() for i in range(1,RopperService.CACHE_FILE_COUNT+1): fqueue.put(cache_file+'_%d' % i) all_gadgets = [] for i in range(count): p=multiprocessing.Process(target=self.__loadCachePerProcess, args=(fqueue, gqueue)) p.start() processes.append(p) for i in range(count): fqueue.put(None) for i in range(RopperService.CACHE_FILE_COUNT): gadgets = gqueue.get() all_gadgets.extend(gadgets) if self.__callbacks and hasattr(self.__callbacks, '__gadgetSearchProgress__'): self.__callbacks.__gadgetSearchProgress__(None, all_gadgets, float(i+1)/RopperService.CACHE_FILE_COUNT) return sorted(all_gadgets, key=Gadget.simpleInstructionString) except KeyboardInterrupt: if mp: for p in processes: if p and p.is_alive(): p.terminate() except BaseException as e: if mp: for p in processes: if p and p.is_alive(): p.terminate() if cache_file: for i in range(1,RopperService.CACHE_FILE_COUNT+1): if os.path.exists(cache_file+'_%d' % i): os.remove(cache_file+'_%d' % i) def _badbytes_changed(self, value): for f in self.__files: if f.loaded: f.gadgets = self.__prepareGadgets(f, f.allGadgets, f.type) def _all_changed(self, value): for f in self.__files: if f.loaded: f.gadgets = self.__prepareGadgets(f, f.allGadgets, f.type) def _color_changed(self, value): cstr.COLOR = value def _detailed_changed(self, value): Gadget.DETAILED = value def _cfg_only_changed(self, value): for f in self.__files: if f.loaded and f.type == Type.PE: f.gadgets = self.__prepareGadgets(f, f.allGadgets, f.type) def _type_changed(self, value): for f in self.__files: if f.loaded: self.loadGadgetsFor(f.name) def _inst_count_changed(self, value): for f in self.__files: if f.loaded: self.loadGadgetsFor(f.name) def _getFileFor(self, name): for file in self.__files: if file.loader.fileName == name: return file return None def clearCache(self): temp = RopperService.CACHE_FOLDER if os.path.exists(temp): import shutil shutil.rmtree(temp) def getFileFor(self, name): return self._getFileFor(name) def addFile(self, name, bytes=None, arch=None, raw=False): if self._getFileFor(name): raise RopperError('file is already added: %s' % name) if arch: arch=getArchitecture(arch) loader = Loader.open(name, bytes=bytes, raw=raw, arch=arch) file = FileContainer(loader) self.__files.append(file) def removeFile(self, name): for idx, fc in enumerate(self.__files): if fc.loader.fileName == name: del self.__files[idx] def asm(self, code, arch='x86', format='hex'): if format not in ('hex', 'string', 'raw'): raise RopperError('Invalid format: %s\n Valid formats are: hex, string, raw' % format) format = Format.HEX if format=='hex' else Format.STRING if format=='string' else Format.RAW return self.ropper.assemble(code, arch=getArchitecture(arch), format=format) def disasm(self, opcode, arch='x86'): return self.ropper.disassemble(opcode, arch=getArchitecture(arch)) def searchPopPopRet(self, name=None): to_return = {} if not name: for file in self.__files: to_return[file.loader.fileName] = self.__ropper.searchPopPopRet(file.loader) else: fc = self._getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) to_return[name] = self.__ropper.searchPopPopRet(fc.loader) return self.__filterBadBytes(to_return) def searchJmpReg(self, regs=['esp'],name=None): to_return = {} if not name: for file in self.__files: to_return[file.loader.fileName] = self.__ropper.searchJmpReg(file.loader, regs) else: fc = self._getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) to_return[name] = self.__ropper.searchJmpReg(fc.loader, regs) return self.__filterBadBytes(to_return) def searchOpcode(self, opcode, name=None): to_return = {} if not name: for file in self.__files: to_return[file.loader.fileName] = self.__ropper.searchOpcode(file.loader, opcode) else: fc = self.getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) to_return[name] = self.__ropper.searchOpcode(fc.loader, opcode) return self.__filterBadBytes(to_return) def searchInstructions(self, code, name=None): to_return = {} if not name: for file in self.__files: to_return[file.loader.fileName] = self.__ropper.searchInstructions(file.loader, code) else: fc = self.getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) to_return[name] = self.__ropper.searchInstructions(fc.loader, code) return self.__filterBadBytes(to_return) def analyseGadgets(self, fileObject): gadgets = fileObject.gadgets analyser = Analyser() cb = None lg = len(gadgets) if self.__callbacks and hasattr(self.__callbacks, '__analyseGadgetsProgress__'): cb = self.__callbacks.__analyseGadgetsProgress__ for i,g in enumerate(gadgets): g.info = analyser.analyse(g) if cb: cb(g, float(i)/lg) if cb: cb(None, 1.0) self.__saveCache(fileObject) fileObject.analysed = True def loadGadgetsFor(self, name=None): def load_gadgets(f): gtype = None cache = False Gadget.IMAGE_BASES[f.loader.checksum] = f.loader.imageBase if self.options.type == 'rop': gtype = GadgetType.ROP elif self.options.type == 'jop': gtype = GadgetType.JOP elif self.options.type == 'sys': gtype = GadgetType.SYS elif self.options.type == 'all': gtype = GadgetType.ALL f.allGadgets = self.__loadCache(f) if f.allGadgets == None: cache = True f.allGadgets = self.__ropper.searchGadgets(f.loader, instructionCount=self.options.inst_count, gtype=gtype) if cache: self.__saveCache(f) f.gadgets = self.__prepareGadgets(f, f.allGadgets, f.type) f.analysed = f.gadgets[0].info is not None if len(f.gadgets) > 0 else False #self._analyseGadgets(f.gadgets) if name is None: for fc in self.__files: load_gadgets(fc) else: for fc in self.__files: if fc.loader.fileName == name: load_gadgets(fc) def printGadgetsFor(self, name=None): def print_gadgets(f): print(f.loader.fileName) for g in f.gadgets: if self.options.detailed: print(g) else: print(g.simpleString()) if name is None: for f in self.__files: print_gadgets(f) else: for f in self.__files: if f.loader.fileName == name: print_gadgets(f) def searchString(self, string='', name=None): def search(f, string): data = [] if not string or string == '[ -~]{2}[ -~]*': string = '[ -~]{2}[ -~]*' else: string = f.arch.searcher.prepareFilter(string) sections = list(f.dataSections) string = string.encode('ascii') # python 3 compatibility for section in sections: b = bytes(bytearray(section.bytes)) for match in re.finditer(string, b): vaddr = f.imageBase + section.offset if f.imageBase != None else section.virtualAddress data.append( (match.start() + vaddr , match.group())) return data to_return = {} if not name: for file in self.__files: to_return[file.loader.fileName] = search(file.loader, string) else: fc = self._getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) to_return[name] = search(fc.loader, string) return to_return def search(self, search, quality=None, name=None): if name: fc = self._getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) s = fc.loader.arch.searcher for gadget in s.search(fc.gadgets, search, quality): yield(fc.name, gadget) else: for fc in self.__files: s = fc.loader.arch.searcher for gadget in s.search(fc.gadgets, search, quality): yield(fc.name, gadget) def semanticSearch(self, search, stableRegs=[], name=None): count = 0 if name: fc = self._getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) s = fc.loader.arch.searcher for gadget in s.semanticSearch(fc.gadgets, search, self.options.inst_count, stableRegs): if self.options.count_of_findings == 0 or self.options.count_of_findings > count: yield(fc.name, gadget) else: break count += 1 self.__saveCache(fc) else: for fc in self.__files: s = fc.loader.arch.searcher for gadget in s.semanticSearch(fc.gadgets, search, self.options.inst_count, stableRegs): if self.options.count_of_findings == 0 or self.options.count_of_findings > count: yield(fc.name, gadget) else: break count += 1 self.__saveCache(fc) def searchdict(self, search, quality=None, name=None): to_return = {} for file, gadget in self.search(search, quality, name): l = to_return.get(file) if not l: l = [] to_return[file] = l l.append(gadget) return to_return def disassAddress(self, name, address, length): fc = self.getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) eSections = fc.loader.executableSections for section in eSections: if section.virtualAddress <= address and section.virtualAddress + section.size > address: ropper = Ropper() g = ropper.disassembleAddress(section, fc.loader, address, address - (fc.loader.imageBase+section.offset), length) if not g: raise RopperError('Cannot disassemble address: %s' % toHex(address)) if length < 0: length = length * -1 return g.disassemblyString() return '' def createRopChain(self, chain, arch, options={}): callback = None if self.__callbacks and hasattr(self.__callbacks, '__ropchainMessages__'): callback = self.__callbacks.__ropchainMessages__ b = [] gadgets = {} for binary in self.__files: if str(binary.arch) == arch: gadgets[binary.loader] = binary.gadgets b.append(binary.loader) generator = RopChain.get(b, gadgets, chain, callback, unhexlify(self.options.badbytes)) if not generator: raise RopperError('%s does not have support for %s chain generation at the moment. Its a future feature.' % (self.files[0].loader.arch.__class__.__name__, chain)) return generator.create(options) def setImageBaseFor(self, name, imagebase): file = self._getFileFor(name) if not file: raise RopperError('No such file opened: %s' % name) file.loader.imageBase = imagebase Gadget.IMAGE_BASES[file.loader.checksum] = file.loader.imageBase if file.loaded and (self.options.badbytes or self.options.cfg_only and file.type == Type.PE): file.gadgets = self.__prepareGadgets(file, file.allGadgets, file.type) def setArchitectureFor(self, name, arch): file = self.getFileFor(name) if not file: raise RopperError('No such file opened: %s' % name) file.loader.arch = getArchitecture(arch) if file.loaded: self.loadGadgetsFor(name) def _setGadgets(self, name, gadgets): fc = self.getFileFor(name) if not fc: raise RopperError('No such file opened: %s' % name) fc.allGadgets = gadgets fc.gadgets = self.__prepareGadgets(fc, fc.allGadgets, fc.type)