def _searchOpcode(self, opcode): r = Ropper() gadgets = [] for section in self._binaries[0].executableSections: vaddr = section.virtualAddress gadgets.extend(r.searchOpcode(self._binaries[0],opcode=opcode,disass=True)) if len(gadgets) > 0: return gadgets[0] else: raise RopChainError('Cannot create gadget for opcode: %s' % opcode)
def _searchOpcode(self, opcode): r = Ropper() gadgets = [] for section in self._binaries[0].executableSections: vaddr = section.virtualAddress gadgets.extend(r.searchOpcode(self._binaries[0],opcode=opcode,disass=True)) if len(gadgets) > 0: return gadgets[0] else: raise RopChainError('Cannot create gadget for opcode: %x' % opcode)
def _searchOpcode(self, opcode): r = Ropper() gadgets = [] for binary in self._binaries: for section in binary.executableSections: vaddr = section.virtualAddress gadgets.extend(r.searchOpcode(binary,opcode=opcode,disass=True)) if len(gadgets) > 0: self._usedBinaries.append((gadgets[0].fileName, gadgets[0]._section)) return gadgets[0] else: raise RopChainError('Cannot create gadget for opcode: %s' % opcode)
def _searchOpcode(self, opcode): r = Ropper() gadgets = [] for binary in self._binaries: for section in binary.executableSections: vaddr = section.virtualAddress gadgets.extend( r.searchOpcode(binary, opcode=opcode, disass=True)) if len(gadgets) > 0: self._usedBinaries.append( (gadgets[0].fileName, gadgets[0]._section)) return gadgets[0] else: raise RopChainError('Cannot create gadget for opcode: %s' % opcode)
def _searchOpcode(self, opcode): r = Ropper() gadgets = [] for binary in self._binaries: for section in binary.executableSections: vaddr = section.virtualAddress gadgets.extend(r.searchOpcode(binary,opcode=opcode,disass=True)) if len(gadgets) > 0: for gadget in gadgets: if not gadget: continue if not self.containsBadbytes(gadget.IMAGE_BASES.get(gadget.fileName,0) + gadget.lines[0][0]): self._updateUsedBinaries(gadget) return gadget else: raise RopChainError('Cannot create gadget for opcode: %s' % opcode)
def test_opcode_failures(self): r = Ropper() if version_info.major == 3 and version_info.minor >= 2: # Wrong question mark position with self.assertRaisesRegex( RopperError, 'A \? for the highest 4 bit of a byte is not supported.*'): r.searchOpcode(self.file, 'ff?4') # Wrong lengh with self.assertRaisesRegex( RopperError, 'The length of the opcode has to be a multiple of two'): r.searchOpcode(self.file, 'ff4') # Unallowed character with self.assertRaisesRegex(RopperError, 'Invalid characters in opcode string'): r.searchOpcode(self.file, 'ff4r') else: # Wrong question mark position with self.assertRaisesRegexp( RopperError, 'A \? for the highest 4 bit of a byte is not supported.*'): r.searchOpcode(self.file, 'ff?4') # Wrong lengh with self.assertRaisesRegexp( RopperError, 'The length of the opcode has to be a multiple of two'): r.searchOpcode(self.file, 'ff4') # Unallowed character with self.assertRaisesRegexp( RopperError, 'Invalid characters in opcode string'): r.searchOpcode(self.file, 'ff4r')
def __searchOpcode(self, opcode): r = Ropper(self.__cprinter) gadgets = r.searchOpcode(self.binary,opcode) self.__printGadgets(gadgets, header='Opcode')
def __searchOpcode(self, opcode): r = Ropper(self.__searchGadgetCallback) gadgets = r.searchOpcode(self.binary,opcode) self.__printGadgets(gadgets, header='Opcode')
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)
def test_opcode_failures(self): r = Ropper() if version_info.major == 3 and version_info.minor >= 2: # Wrong question mark position with self.assertRaisesRegex(RopperError, "A \? for the highest 4 bit of a byte is not supported.*"): r.searchOpcode(self.file, "ff?4") # Wrong lengh with self.assertRaisesRegex(RopperError, "The length of the opcode has to be a multiple of two"): r.searchOpcode(self.file, "ff4") # Unallowed character with self.assertRaisesRegex(RopperError, "Invalid characters in opcode string"): r.searchOpcode(self.file, "ff4r") else: # Wrong question mark position with self.assertRaisesRegexp(RopperError, "A \? for the highest 4 bit of a byte is not supported.*"): r.searchOpcode(self.file, "ff?4") # Wrong lengh with self.assertRaisesRegexp(RopperError, "The length of the opcode has to be a multiple of two"): r.searchOpcode(self.file, "ff4") # Unallowed character with self.assertRaisesRegexp(RopperError, "Invalid characters in opcode string"): r.searchOpcode(self.file, "ff4r")