示例#1
0
    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)
示例#2
0
    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)
示例#3
0
 def test_ppr(self):
     ropper = Ropper()
     
     gadgets = ropper.searchPopPopRet(self.file)
     
     self.assertEqual(len(gadgets), 109)
     self.assertEqual(gadgets[0].lines[0][0], 0x444a)
示例#4
0
    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)
示例#5
0
    def test_ppr(self):
        ropper = Ropper()

        with self.assertRaises(NotSupportedError):
            gadgets = ropper.searchPopPopRet(self.file)
示例#6
0
 def __searchPopPopRet(self):
     r = Ropper(self.__cprinter)
     pprs = r.searchPopPopRet(self.binary)
     pprs = ropper.filterBadBytes(pprs, self.__options.badbytes)
     self.__printGadgets(pprs, header='POP;POP;RET Instructions')
示例#7
0
 def __searchPopPopRet(self):
     r = Ropper(self.__searchGadgetCallback)
     pprs = r.searchPopPopRet(self.binary)
     pprs = ropper.filterBadBytes(pprs, self.__options.badbytes)
     self.__printGadgets(pprs, header='POP;POP;RET Instructions')
示例#8
0
 def test_ppr(self):
     ropper = Ropper()
     
     with self.assertRaises(NotSupportedError):
         gadgets = ropper.searchPopPopRet(self.file)
示例#9
0
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)
示例#10
0
文件: service.py 项目: sashs/Ropper
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)