Ejemplo n.º 1
0
    def check_file(self, filename):
        self.current_file = filename

        pyew = CPyew(batch=True, plugins=True)
        pyew.codeanalysis = True
        pyew.deepcodeanalysis = self.deep

        try:
            pyew.loadFile(filename)
        except:
            raise Exception("Error loading file: %s" % str(sys.exc_info()[1]))

        if pyew.format not in ["PE", "ELF", "BOOT", "BIOS"]:
            sys.stderr.write("[INFO] Ignoring non supported executable file\n")
            sys.stderr.flush()
            return

        program_stats = pyew.program_stats
        md5_hash = md5(pyew.getBuffer()).hexdigest()
        if self.check_or_update(md5_hash, program_stats):
            print "[OK] Test %s (%s)" % (filename, md5_hash)
        else:
            msg = "[FAILED] *** Test %s (%s)"
            print msg % (filename, md5_hash)
            self.show_reason(program_stats)
Ejemplo n.º 2
0
  def check_file(self, filename):
    self.current_file = filename

    pyew = CPyew(batch=True, plugins=True)
    pyew.codeanalysis = True
    pyew.deepcodeanalysis = self.deep

    try:
      pyew.loadFile(filename)
    except:
      raise Exception("Error loading file: %s" % str(sys.exc_info()[1]))

    if pyew.format not in ["PE", "ELF", "BOOT", "BIOS"]:
      sys.stderr.write("[INFO] Ignoring non supported executable file\n")
      sys.stderr.flush()
      return

    program_stats = pyew.program_stats
    md5_hash = md5(pyew.getBuffer()).hexdigest()
    if self.check_or_update(md5_hash, program_stats):
      print "[OK] Test %s (%s)"  % (filename, md5_hash)
    else:
      msg = "[FAILED] *** Test %s (%s)"
      print msg  % (filename, md5_hash)
      self.show_reason(program_stats)
Ejemplo n.º 3
0
	def processFile(self, filename):
		print "[+] Analyzing file %s" % filename
		pyew = CPyew(batch=True)
		pyew.deepcodeanalysis = self.deep
		pyew.analysis_timeout = 0
		pyew.loadFile(filename)

		if pyew.format in ["PE", "ELF"]:
			hash = sha256(pyew.getBuffer()).hexdigest()
			self.data.append({hash:pyew})
		else:
			print "Not a PE/ELF file"
Ejemplo n.º 4
0
    def processFile(self, filename):
        #print "[+] Analyzing file %s" % filename
        pyew = CPyew(batch=True)
        pyew.deepcodeanalysis = self.deep
        pyew.analysis_timeout = 0
        pyew.loadFile(filename)

        if pyew.format in ["PE", "ELF"]:
            hash = sha256(pyew.getBuffer()).hexdigest()
            self.data.append({hash: pyew})
        else:
            sys.stderr.writelines("Not a PE/ELF file")
            sys.stderr.flush()
Ejemplo n.º 5
0
 def processFile(self, filename):
     sys.stderr.write("[+] Analyzing file %s\n" % filename)
     sys.stderr.flush()
     pyew = CPyew(batch=True)
     pyew.deepcodeanalysis = self.deep
     pyew.analysis_timeout = 0
     pyew.loadFile(filename)
     
     if pyew.format in ["PE", "ELF"]:
         hash = sha256(pyew.getBuffer()).hexdigest()
         self.data.append({hash:pyew})
     else:
         sys.stderr.writelines("Not a PE/ELF file")
         sys.stderr.flush()
Ejemplo n.º 6
0
class Core():

    def __init__(self, case, deep_anal, progress_bar=None):

        self.low_case = case
        self.deep_anal = deep_anal
        self.progress_bar = progress_bar

        self.fulldasm = ''
        self.text_dasm = ''     # Dasm of the .text section
        self.pythondasm = ''
        self.fullhex = ''
        self.fullstr = ''
        self.allstrings = ''
        self.allfuncs = []
        self.allsections = []
        self.execsections = []
        self.sections_size = []
        self.sections_lines = []
        self.allimports = {}
        self.allexports = []
        self.fileinfo = ''
        self.pdfinfo = ''
        self.alllinks = []
        self.parsed_links = {'remotes':[], 'locals':[]}
        self.links_struct = []
        self.url_headers = {}
        self.url_cookies = []
        self.http_dot = ''
        self.checked_urls = []
        self.bad_urls = []
        self.cmd = ''
        self.last_cmd = ''
        self.corename = 'pyew'

        self.core = CPyew()
        if os.getenv("PYEW_DEBUG"):
            self.core.debug=True
        else:
            self.core.debug = False

        self.backend = 'pyew'

        self.core.offset = 0
        self.core.previousoffset = []
        if self.deep_anal:
            self.core.deepcodeanalysis = True

        if self.low_case:
           self.core.case = 'low'
        self.core.physical = False
        self.core.virtual = True

    def clean_fullvars(self):
        self.fulldasm = ''
        self.text_dasm = ''     # Dasm of the .text section
        self.pythondasm = ''
        self.fullhex = ''
        self.fullstr = ''
        self.allstrings = ''
        self.allfuncs = []
        self.allsections = []
        self.execsections = []
        self.sections_size = []
        self.sections_lines = []
        self.allimports = {}
        self.allexports = []
        self.fileinfo = ''
        self.pdfinfo = ''
        self.alllinks = []
        self.parsed_links = {'remotes':[], 'locals':[]}
        self.links_struct = []
        self.url_headers = {}
        self.url_cookies = []
        self.http_dot = ''
        self.checked_urls = []
        self.bad_urls = []
        self.cmd = ''
        self.last_cmd = ''

    def set_options(self, low_case, deep_anal, progress_bar):
        if deep_anal:
            self.core.deepcodeanalysis = True
        else:
            self.core.deepcodeanalysis = False

        if low_case:
            self.core.case = 'low'
        else:
            self.core.case = 'high'

        self.progress_bar = progress_bar

    def load_file(self, file):
        self.update_progress_bar("Loading file", 0.1)
        # Set default file format to raw
        self.core.format = 'raw'

        self.core.loadFile(file, "rb")

        # Add global object's references for easier usage
        self.pe = self.core.pe
        self.elf = self.core.elf

        # Check if file name is an URL, pyew stores it as 'raw'
        self.is_url(file)

        if self.core.format in ["PE", "ELF"]:
            self.saveAndCompareInDatabase(self.core)
        elif self.core.format in ["PDF"]:
            import ui.plugins.pdfinfo as pdfinfo
            self.pdfinfo = pdfinfo.get_pdfinfo(file)
        elif self.core.format in ['URL']:
            #print "URL! We've got URL!"
            self.search_http_src()
            self.parse_http_locals()
            self.get_headers_cookies()
        elif self.core.format in ["raw"]:
            #print "We've got RAW!"
            self.core.format = 'Plain Text'

        #self.core.bsize = self.core.maxsize
        self.core.seek(0)

    def is_url(self, file):
        #print "Checking if is URL..."
        self.filename = file
        if self.filename.lower().startswith("http://") or \
           self.filename.lower().startswith("https://") or \
           self.filename.lower().startswith("ftp://"):
            self.core.format = 'URL'

    def get_strings(self):
        if not self.allstrings:
            self.update_progress_bar("Getting strings", 0.6)
            self.allstrings = self.core.strings(self.core.buf)
            strings = ''
            FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
            for element in self.allstrings:
                for key in element.keys():
                    strings += "0x%08x:\t%s\n" % (key, element[key].translate(FILTER))
            self.allstrings = strings
        return self.allstrings

    def get_functions(self):
        if not self.allfuncs:
            self.update_progress_bar("Getting functions", 0.8)
            for func in self.core.functions:
                 #print "0x%08x" % (func)
                 self.allfuncs.append(self.core.names[func])
        return self.allfuncs

    def get_hexdump(self):
        self.update_progress_bar("Getting hexdump", 0.75)
        hexdump = self.core.hexdump(self.core.buf, self.core.hexcolumns, baseoffset=self.core.offset, bsize=self.core.bsize)
        return hexdump

    def get_full_hexdump(self):
        if self.fullhex == '':
            self.update_progress_bar("Getting full hexdump", 0.5)
            self.core.bsize = self.core.maxsize
            self.core.seek(0)
            hexdump = self.core.hexdump(self.core.buf, self.core.hexcolumns, baseoffset=0, bsize=self.core.bsize)
            self.fullhex = hexdump
        self.core.bsize = 512
        return self.fullhex

    def get_dasm(self):
        self.update_progress_bar("Getting dasm",0.25)
        dis = self.core.disassemble(self.core.buf, self.core.processor, self.core.type, self.core.lines, self.core.bsize, baseoffset=self.core.offset)
        return dis

    def get_text_dasm(self):
        self.core.bsize = self.core.maxsize

        base_percent = 0.3
        step = 0.01

        #self.seek(0)
        if not self.text_dasm:
            #self.update_progress_bar("Getting text dasm",base_percent)
            percent = base_percent
            self.core.lines = 100*100
            if self.core.format == 'PE':
                #dasm = ''
                for section in self.execsections:
                    percent += step
                    # Let's store text section information
                    #print hex(self.core.pe.OPTIONAL_HEADER.ImageBase + section.VirtualAddress)
                    #self.update_progress_bar("Reading assembler for section %s..." % section[0][0], percent)
                    self.text_rsize = section[1]
                    self.text_address = section[2]
                    self.seek(self.text_address)
                    dis = self.core.disassemble(self.core.buf, self.core.processor, self.core.type, self.core.lines, self.text_rsize, baseoffset=self.text_address)
                    self.sections_lines.append( len(dis.split('\n')) )
                    self.text_dasm += ';; ------------------------\n;; Section: %s\n;; ------------------------\n' % section[0][0]
                    self.text_dasm += dis
                    #print "OK"
                    if percent == base_percent + step * 10:
                        percent -= step
                self.sections_lines.append(sum(self.sections_lines))
            elif self.core.format == 'ELF':
                for section in self.execsections:
                    percent += step
                    #print "\t* Let's get the dasm for %s..." % section[0][0],
                    #self.update_progress_bar("Reading assembler for section %s..." % section[0][0], percent)
                    # Let's store text section information
                    self.text_rsize = section[1]
                    self.text_address = section[2]
                    self.seek(self.text_address)
                    dis = self.core.disassemble(self.core.buf, self.core.processor, self.core.type, self.core.lines, self.text_rsize, baseoffset=self.text_address)
                    self.sections_lines.append( len(dis.split('\n')) )
                    self.text_dasm += ';; ------------------------\n;; Section: %s\n;; ------------------------\n' % section[0]
                    self.text_dasm += dis
                    #print "OK"
                    if percent == base_percent + step * 10:
                        percent -= step
                self.sections_lines.append(sum(self.sections_lines))
        self.core.bsize = 512
        self.core.lines = 40
        #return self.text_dasm, self.sections_lines, self.text_address, self.text_rsize
        return self.text_dasm

    def get_text_dasm_through_queue(self, queue, event):
        queue.put(self.get_text_dasm())
        event.set()

    def get_fulldasm(self):
        #self.update_progress_bar("Getting text dasm", 0.3)
        self.core.bsize = self.core.maxsize
        self.seek(0)
        if not self.fulldasm:
            self.core.lines = 100*100
            dis = self.core.disassemble(self.core.buf, self.core.processor, self.core.type, self.core.lines, self.core.bsize, baseoffset=self.core.offset)
            self.fulldasm = dis
        self.core.bsize = 512
        self.core.lines = 40
        return self.fulldasm

    def get_fulldasm_through_queue(self, queue, event):
        queue.put(self.get_fulldasm())
        event.set()

    def seek(self, pos):
        data = ''
        if pos > self.core.maxsize:
            data = 'End of file reached'
            self.core.offset = self.core.maxsize
        elif pos < 0:
            data = 'Begin of file reached'
            self.core.offset = 0
        else:
            self.core.offset = pos
        if len(self.core.previousoffset) > 0:
            if self.core.previousoffset[ len(self.core.previousoffset)-1 ] != self.core.offset:
                self.core.previousoffset.append(self.core.offset)
        else:
            self.core.previousoffset.append(self.core.offset)
        
        self.core.f.seek(self.core.offset)
        self.core.buf = self.core.f.read(self.core.bsize)

        return data

    def move(self, direction, output):

        #self.core.bsize = 512
        self.cmd = direction
        limit = ''

        if len(self.core.previousoffset) > 0:
            if self.core.previousoffset[ len(self.core.previousoffset)-1 ] != self.core.offset:
                self.core.previousoffset.append(self.core.offset)
        else:
            self.core.previousoffset.append(self.core.offset)
        
#        va = None
#        if self.core.virtual:
#            va = self.core.getVirtualAddressFromOffset(self.core.offset)
#        
#        if va:
#            prompt = "[0x%08x:0x%08x]> " % (self.core.offset, va)
#        else:
#            prompt = "[0x%08x]> " % self.core.offset

        if self.cmd == "b":
            tmp = self.core.previousoffset.pop()
            
            if len(self.core.previousoffset) > 0:
                tmp = self.core.previousoffset[ len(self.core.previousoffset)-1 ]
            else:
                tmp = 0
                
            self.core.offset = tmp
            self.core.lastasmoffset = tmp

            limit = self.seek(tmp)

        elif self.cmd == "b" and self.last_cmd == "b":
            if len(self.core.previousoffset) < 2:
                return
            
            tmp = self.core.previousoffset.pop()
            tmp = self.core.previousoffset[ len(self.core.previousoffset)-1 ]

            limit = self.seek(tmp)

        elif output == 'disassembly':
            self.core.offset = self.core.lastasmoffset

            self.core.seek(self.core.offset)
#            if last_cmd.isdigit():
#                last_cmd = "c"

        else:
            self.core.offset = self.core.offset + self.core.bsize
            limit = self.seek(self.core.offset)

        self.cmd = self.last_cmd

        if not limit:
            if output == 'hexadecimal':
                data = self.get_hexdump()
            else:
                data = self.get_dasm()
            return data
        else:
            print limit
            return

    def get_python_dasm(self):
        if not self.pythondasm:
            try:
                import dis
                self.core.lines = 100*100
                self.pythondasm = dis.dis(self.core.buf)
            except:
                pass
        return self.pythondasm

    def get_repr(self):
        if not self.fullstr:
            self.update_progress_bar("Getting string representation", 0.65)
            self.fullstr = repr(self.core.buf)
        return self.fullstr

    def get_sections(self):
        self.update_progress_bar("Getting sections", 0.15)
        if self.core.format == 'PE':
            #import pefile
            #image_flags = self.core.pe.retrieve_flags(pefile.SECTION_CHARACTERISTICS, 'IMAGE_SCN_')
            if self.allsections == []:
                for section in self.pe.sections:
                    if section.__dict__.get('IMAGE_SCN_MEM_EXECUTE', False):
                        self.execsections.append([section.Name.split('\x00'[0]), section.SizeOfRawData, section.VirtualAddress])
                    self.sections_size.append(section.SizeOfRawData)
                    self.allsections.append( [section.Name.split('\x00')[0], hex(section.VirtualAddress), hex(section.Misc_VirtualSize), hex(section.SizeOfRawData)] )
#                    print "  ", section.Name, hex(section.VirtualAddress), hex(section.Misc_VirtualSize), section.SizeOfRawData
        elif self.core.format == 'ELF':
            if self.allsections == []:
                for section in self.core.elf.secnames:
                    if self.core.elf.secnames[section].sh_flags == 6:
                        self.execsections.append([self.core.elf.secnames[section].getName(), self.core.elf.secnames[section].sh_size, self.core.elf.secnames[section].sh_offset])
                    self.sections_size.append(self.core.elf.secnames[section].sh_size)
                    self.allsections.append( [self.core.elf.secnames[section].getName(), "0x%08x" % (self.core.elf.secnames[section].sh_addr), "N/A", "N/A"] )

        return self.allsections

    def get_imports(self):
        try:
            if not self.allimports:
                if self.core.format == "PE":
                    for entry in self.pe.DIRECTORY_ENTRY_IMPORT:
#                        print entry.dll
                        self.allimports[entry.dll] = []
                        for imp in entry.imports:
                            self.allimports[entry.dll].append( [hex(imp.address), imp.name] )
#                            print '\t', hex(imp.address), imp.name
            return self.allimports
#            print self.allimports
        except:
            self.allimports.append(['No imports found', ''])
            print 'No imports found'

    def get_exports(self):
        try:
            if not self.allexports:
                if self.core.format == "PE":
                    for exp in self.pe.DIRECTORY_ENTRY_EXPORT.symbols:
#                        print hex(self.core.pe.OPTIONAL_HEADER.ImageBase + exp.address), exp.name, exp.ordinal
                        self.allexports.append( [hex(self.core.pe.OPTIONAL_HEADER.ImageBase + exp.address), exp.name, str(exp.ordinal), ''] )
#            print self.allexports
            return self.allexports
        except:
            self.allexports.append(['No exports found', '', '', ''])

            print 'No exports found'
            return self.allexports

    def get_virtual_address(self):
        if  self.core.format in ["PE"]:
            x = self.pe.OPTIONAL_HEADER.AddressOfEntryPoint
            for s in self.pe.sections:
                if x >= s.VirtualAddress and x <= s.VirtualAddress + s.SizeOfRawData:
                    break
    
            x = x - s.VirtualAddress
            x += s.PointerToRawData
            ep = x
#            print "Entry Point at 0x%x" % x
            try:
#                print "Virtual Address is 0x%0x" % (self.pe.OPTIONAL_HEADER.ImageBase + self.pe.get_rva_from_offset(x))
                va = self.pe.OPTIONAL_HEADER.ImageBase + self.pe.get_rva_from_offset(x)
                self.offset = x
                self.ep = x
            except:
                print sys.exc_info()[1]
    
            return hex(va), hex(ep)

    def get_file_info(self):
        self.update_progress_bar("Getting additional file info", 0.9)
        if self.core.format in ["PE"]:
            # pyew.filename        : /home/hteso/Pocs/MRxNet/mrxnet.sys
            # pyew.format          : PE
            # pyew.maxfilesize     : 1073741824
            # pyew.maxsize         : 17400
            # pyew.type            : 32
            # pyew.processor       : intel
            vaddress, ep  = self.get_virtual_address()
            self.fileinfo = {'name':self.core.filename, 'format':self.core.format, 'size':self.core.maxsize, 'processor':self.core.processor, 'type':self.core.type, 'va':vaddress, 'ep':ep}
    #        print self.fileinfo
        elif self.core.format in ["ELF"]:
            self.fileinfo = {'name':self.core.filename, 'format':self.core.format, 'size':self.core.maxsize, 'processor':self.core.processor, 'type':self.core.type}
        elif self.core.format in ["PDF"]:
            self.fileinfo = {'name':self.core.filename, 'format':self.core.format, 'size':self.core.maxsize, 'processor':self.core.processor, 'type':self.core.type}
        # I plan to add more content here soon so I keep it separated
        elif self.core.format in ['URL']:
            self.fileinfo = {'name':self.core.filename, 'format':self.core.format, 'size':self.core.maxsize}
        else:
            self.fileinfo = {'name':self.core.filename, 'format':self.core.format, 'size':self.core.maxsize}

        return self.fileinfo

    def get_pdf_info(self):
        return self.pdfinfo

    def get_pdf_streams(self):
        import ui.plugins.pdfinfo as pdfinfo
        self.streams = pdfinfo.pdfStream(self.core)
        return self.streams

    def get_callgraph(self):
        self.update_progress_bar("Loading callgraph", 0.4)
        import ui.plugins.cgraph as cgraph
        dot_code = cgraph.showCallGraph(self.core)
        return dot_code

    def get_urls(self):
        import ui.plugins.url as url
        urls = url.extract(self.core)
        return urls

    def check_urls(self):
        import ui.plugins.url as url
        checked_urls = url.check(self.core)
        self.checked_urls = checked_urls

    def bad_urls(self):
        import ui.plugins.url as url
        bad_urls = url.check_bad(self.core)
        self.bad_urls = bad_urls

    def sendto_vt(self):
        import ui.plugins.virustotal as virustotal
        vt_results = virustotal.search_vt(self.core)
        return vt_results

    def execute_plugin(self, plugin):
        plg = plugin.split(" ")
        if len(plg) == 1:
            self.core.plugins[plg[0]](self.core)
        else:
            self.core.plugins[plg[0]](self.core, plg[1:])

    def get_packers(self):
        import ui.plugins.packer as packer
        packers = packer.search_packer(self.core)
        return packers

    def dosearch(self, data, type):
        # search types: s, u, r, o, i, x

        results = self.core.dosearch(self.core.f, type, data, offset=self.core.offset, cols=64, doprint=False)
        return results

    def search_http_src(self):
        self.update_progress_bar("Parsing HTTP source", 0.2)
        srcs = self.core.dosearch(self.core.f, 's', 'src="', offset=self.core.offset, cols=100, doprint=False)
        hrefs = self.core.dosearch(self.core.f, 's', 'href="', offset=self.core.offset, cols=100, doprint=False)
        results = srcs + hrefs
        for element in results:
            link = element.values()[0].split('"')[1]
            if link.startswith('http://') or link.startswith('https://') and link != '':
                self.parsed_links['remotes'].append(link)
            else:
                if link != '':
                   self.parsed_links['locals'].append(link)

    # Parse http resources to create graph
    def parse_http_locals(self):
        self.update_progress_bar("Extracting source links", 0.3)
        for element in self.parsed_links['locals']:
            element = element.strip(' ').split('/')
            if len(element) > 1:
                try:
                    root = next(s for s in element if s)
                    root_index = element.index(root)
                    self.links_struct.append( {root:element[root_index + 1:]} )
                except:
                    pass
            elif len(element) == 1:
                self.links_struct.append( {element[0]:['']} )
        import ui.generate_dot as gendot
        self.http_dot = gendot.generate_dot(self.links_struct, self.core.filename)

    def get_headers_cookies(self):
        self.update_progress_bar("Extracting headres and cookies", 0.4)
        urlopen = urllib2.urlopen
        cj = cookielib.LWPCookieJar()
        Request = urllib2.Request

        if cj != None:
            if cookielib:
                opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
                urllib2.install_opener(opener)
        
        theurl = self.core.filename
        txdata = None
        txheaders =  {'User-agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'}

        req = Request(theurl, txdata, txheaders)
        handle = urlopen(req)

#        print 'Here are the headers of the page :'
        self.url_headers = dict(handle.info())

#        print 'These are the cookies we have received so far :'
        ns_headers = handle.headers.getheaders("Set-Cookie")
        attrs_set = cookielib.parse_ns_headers(ns_headers)
        self.url_cookies = cj._normalized_cookie_tuples(attrs_set)

        parser = html_parser.MyHTMLParser()
        data = handle.read()
        parser.print_contents(data)
        self.scripts = parser.scripts
        self.comments = parser.comments
        self.forms = parser.forms

    def get_file_text(self):
        self.update_progress_bar("Getting plain text", 0.3)
        file = open(self.core.filename, 'rb')
        data = file.read()
        file.close()

        return data

    def saveAndCompareInDatabase(self, pyew):
        db = sqlite3.connect(DATABASE_PATH)
        self.createSchema(db)
        cur = db.cursor()
        bcontinue = True
        
        try:
            buf = self.core.getBuffer()
            amd5 = md5(buf).hexdigest()
            name = self.core.filename
            sql = """ select * from samples where md5 = ? """
            cur.execute(sql, (amd5, ))
            
            for row in cur.fetchall():
                if row[4] != name:
                    print "NOTICE: File was previously analyzed (%s)" % row[4]
                    print
                bcontinue = False
            cur.close()
            
            if bcontinue:
                self.saveSample(db, pyew, buf, amd5)
        except:
            print sys.exc_info()[1]
            raise

    def saveSample(self, db, pyew, buf, amd5):
        try:
            asha1 = sha1(buf).hexdigest()
            asha256 = sha256(buf).hexdigest()
            name = self.core.filename
            format = self.core.format
            
            cur = db.cursor()
            sql = """ insert into samples (md5, sha1, sha256, filename, type)
                                   values (?, ?, ?, ?, ?)"""
            cur.execute(sql, (amd5, asha1, asha256, name, format))
            rid = cur.lastrowid
            
            sql = """ insert into function_stats (sample_id, addr, nodes, edges, cc)
                                          values (?, ?, ?, ?, ?) """
            for f in self.core.function_stats:
                addr = "0x%08x" % f
                nodes, edges, cc = self.core.function_stats[f]
                cur.execute(sql, (rid, addr, nodes, edges, cc))
            
            sql = """ insert into antidebugs (sample_id, addr, mnemonic) values (?, ?, ?) """
            for antidbg in self.core.antidebug:
                addr, mnem = antidbg
                addr = "0x%08x" % addr
                cur.execute(sql, (rid, addr, mnem))
            
            db.commit()
        except:
            print sys.exc_info()[1]
            pass

    def createSchema(self, db):
        try:
            sql = """create table samples (id integer not null primary key,
                                           md5, sha1, sha256, filename, type)"""
            db.execute(sql)
            
            sql = """create table function_stats (
                            id integer not null primary key,
                            sample_id, addr, nodes, edges, cc)"""
            db.execute(sql)
            
            sql = """create table antidebugs (
                            id integer not null primary key,
                            sample_id, addr, mnemonic
                            )"""
            db.execute(sql)
        except:
            pass

    def update_progress_bar(self, text, percent):
        """ Easy function to clean up the event queue and force a repaint. """
        import ui.core_functions

        if not self.progress_bar:
            return
        self.progress_bar.set_fraction(percent)
        self.progress_bar.set_text(text)
        ui.core_functions.repaint()
Ejemplo n.º 7
0
def main(filename):
    pyew = CPyew()
    thread = threading.Thread(target=pyew.thread_UpdateComment)
    thread.start()

    if os.getenv("PYEW_DEBUG"):
        pyew.debug = True
    else:
        pyew.debug = False

    pyew.loadFile(filename, "rb")

    if pyew.format in ["PE", "ELF"]:
        saveAndCompareInDatabase(pyew)

    pyew.offset = 0
    print pyew.hexdump(pyew.buf, pyew.hexcolumns)

    oldpyew = None
    cmd = ""
    last_cmd = ""
    pyew.previousoffset = []

    # Add global object's references for easier usage
    pe = pyew.pe
    elf = pyew.elf

    # Set AutoCompletion
    setupAutoCompletion(pyew)

    # Check if there is runme.py file
    if os.path.exists('runme.py'):
        f = open('runme.py', 'r')
        commands = f.readlines()
        f.close()

    while 1:
        try:
            last_cmd = cmd
            
            if len(pyew.previousoffset) > 0:
                if pyew.previousoffset[len(pyew.previousoffset)-1] != pyew.offset:
                    pyew.previousoffset.append(pyew.offset)
            else:
                pyew.previousoffset.append(pyew.offset)
            
            va = None
            if pyew.virtual:
                va = pyew.getVirtualAddressFromOffset(pyew.offset)
            
            if va:
                prompt = "[0x%08x:0x%08x]> " % (pyew.offset, va)
            else:
                prompt = "[0x%08x]> " % pyew.offset
            
            try:
                cmd = commands[0].rstrip()
                commands.pop(0)
            except:
                cmd = raw_input(prompt)
            
            if cmd in ["", "b"] and (last_cmd in ["b", "x", "c", "d", "dump", "hexdump", "u", "p", "r", "buf"] or last_cmd.isdigit()):
                if cmd == "b":
                    tmp = pyew.previousoffset.pop()
                    
                    if len(pyew.previousoffset) > 0:
                        tmp = pyew.previousoffset[len(pyew.previousoffset)-1]
                    else:
                        tmp = 0
                        
                    pyew.offset = tmp
                    pyew.lastasmoffset = tmp
                    pyew.seek(tmp)
                    if last_cmd.isdigit():
                        last_cmd = "c"
                    
                elif cmd == "b" and last_cmd == "b":
                    if len(pyew.previousoffset) < 2:
                        continue
                    
                    tmp = pyew.previousoffset.pop()
                    tmp = pyew.previousoffset[len(pyew.previousoffset)-1]
                    pyew.seek(tmp)
                    continue
                elif last_cmd in ["c", "u"] or last_cmd.isdigit():
                    pyew.offset = pyew.lastasmoffset
                    pyew.seek(pyew.offset)
                    if last_cmd.isdigit():
                        last_cmd = "c"
                else:
                    pyew.offset = pyew.offset+pyew.bsize
                    pyew.seek(pyew.offset)
                cmd = last_cmd
        except EOFError:
            break
        except KeyboardInterrupt:
            break
        
        try:
            if cmd.strip(" ") == "":
                continue
            
            if cmd.lower() in ["exit", "quit", "q"]:
                break
            elif cmd.lower() in ["a", "anal"]:
                pyew.findFunctions(pyew.processor)
                print
            elif cmd.lower() in ["x", "d", "dump", "hexdump"]:
                print pyew.hexdump(pyew.buf, pyew.hexcolumns, baseoffset=pyew.offset)
            elif cmd.split(" ")[0] in ["s", "seek"]:
                data = cmd.split(" ")
                if len(data) > 1:
                    if data[1].lower() in ["ep", "entrypoint"]:
                        if pyew.ep:
                            pyew.offset = pyew.ep
                    else:
                        pyew.names.has_key(data[1].lower())
                        
                        if data[1].lower()[0] in ["+", "-"]:
                            pyew.offset += int(data[1])
                        elif data[1].lower().startswith("0x"):
                            pyew.offset = int(data[1], 16)
                        elif data[1] in pyew.names.values():
                            for x in pyew.names:
                                if pyew.names[x] == data[1]:
                                    pyew.offset = x
                                    break
                        else:
                            pyew.offset = int(data[1])
                        
                pyew.seek(pyew.offset)
            elif cmd.split(" ")[0] in ["label"]: 
                data = cmd.split(" ")
                if len(data) > 2:
                    if data[1].isdigit():
                        pyew.customizeComment[int(data[1])] = data[2]
                    elif data[1][:2].lower() =="0x":
                        try:
                            pyew.customizeComment[int(data[1],16)] = data[2]
                        except:
                            print "Error"

                        
            elif cmd.lower().split(" ")[0] in ["c", "u"]:
                data = cmd.lower().split(" ")
                if len(data) > 1:
                    if not data[1].startswith("/"):
                        type = int(data[1])
                        dis = pyew.disassemble(pyew.buf, pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=pyew.offset)
                        print dis
                    else:
                        cmd = data[1:]
                        if len(cmd) > 1:
                            ret = pyew.dosearch(pyew.f, cmd[0][1:2], cmd[1], cols=60, doprint=False, offset=pyew.offset)
                        else:
                            ret = pyew.dosearch(pyew.f, cmd[0][1:2], "", cols=60, doprint=False, offset=pyew.offset)
                        
                        for x in ret:
                            dis = pyew.disassemble(x.values()[0], pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=x.keys()[0])
                            print dis
                else:
                    dis = pyew.disassemble(pyew.buf, pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=pyew.offset)
                    print dis
            elif cmd.isdigit() and int(cmd) < len(pyew.calls)+1 and int(cmd) > 0:
                pyew.offset = pyew.calls[int(cmd)-1]
                pyew.seek(pyew.offset)
                dis = pyew.disassemble(pyew.buf, pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=pyew.offset)
                print dis
            elif cmd == "buf":
                lines = 0
                line = ""
                for c in pyew.buf:
                    line += c
                    if len(line) == pyew.hexcolumns:
                        print repr(line)
                        line = ""
                
                if line != "":
                    print repr(line)
            elif cmd == "byte":
                lines = 0
                line = ""
                for c in pyew.buf:
                    line += "0x%x, " % ord(c)
                    if len(line) >= pyew.hexcolumns / (1.00/4.00):
                        print line
                        line = ""
                
                if line != "":
                    print "%s" % line
            elif cmd.lower().split(" ")[0] in ["r", "repr"]:
                print repr(pyew.buf)
            elif cmd.lower().split(" ")[0] in ["p"]:
                print pyew.buf
            elif cmd.lower() in ["settings", "options"]:
                pyew.showSettings()
            elif cmd.startswith("/"):
                ret = pyew.dosearch(pyew.f, cmd[1:2], cmd[3:], cols=60, offset=pyew.offset)
            elif cmd.lower() in ["?", "help"]:
                showHelp(pyew)
            elif cmd.lower() in ["imports"]:
                if pyew.format == "PE":
                    for entry in pyew.pe.DIRECTORY_ENTRY_IMPORT:
                        print entry.dll
                        for imp in entry.imports:
                            print '\t', hex(imp.address), imp.name
                elif pyew.format == "ELF":
                    for x in pyew.elf.relocs:
                        print x
            elif cmd.lower() in ["exports"]:
                if pyew.format == "PE":
                    for exp in pyew.pe.DIRECTORY_ENTRY_EXPORT.symbols:
                        print hex(pyew.pe.OPTIONAL_HEADER.ImageBase + exp.address), exp.name, exp.ordinal
                elif pyew.format == "ELF":
                    print "Not yet implemented"
            elif cmd.lower() in ["sections"]:
                if pyew.format == "PE":
                    for x in pyew.pe.sections:
                        print x
                elif pyew.format == "ELF":
                    for x in pyew.elf.secnames:
                        print pyew.elf.secnames[x]
            elif cmd.lower() in ["elf", "pe"]:
                if cmd.lower() == "elf":
                    print pyew.elf
                else:
                    print pyew.pe
            elif cmd.lower() == "g":
                if cmd == "g":
                    pyew.offset = 0
                else:
                    pyew.offset = pyew.maxsize - pyew.bsize
                    if pyew.offset < 0:
                        pyew.offset = pyew.maxsize - 32
                pyew.seek(pyew.offset)
            elif cmd in ["-", "+"]:
                if cmd == "+":
                    pyew.offset += pyew.bsize
                else:
                    pyew.offset -= pyew.bsize
                pyew.seek(pyew.offset)
            elif pyew.plugins.has_key(cmd.split(" ")[0]):
                plg = cmd.split(" ")
                if len(plg) == 1:
                    pyew.plugins[plg[0]](pyew)
                else:
                    pyew.plugins[plg[0]](pyew, plg[1:])
            elif cmd.lower().split(" ")[0] in ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]:
                func = eval(cmd)
                print "%s: %s" % (cmd, func(pyew.getBuffer()).hexdigest())
            elif cmd.startswith("!"):
                os.system(cmd[1:])
            elif cmd == "ret" and oldpyew is not None:
                pyew = oldpyew
                pyew.seek(pyew.offset)
                oldpyew = None
            elif cmd == "file":
                oldpyew = pyew
                del pyew
                pyew = CPyew()
                buf = oldpyew.getBytes(oldpyew.offset, oldpyew.maxsize)
                pyew.loadFromBuffer(buf, oldpyew.filename + "[embed]")
            elif cmd == "interact":
                code.interact(local=locals())
            elif cmd == "edit":
                pyew.f.close()
                pyew.f = open(filename, "r+wb")
                pyew.seek(0)
            elif cmd.split(" ")[0] in ["ls"]:
                data = cmd.split(" ")
                if len(data) == 2:
                    #print "parsing script file:", data[1]
                    f = open('scripts/' + data[1], 'r')
                    commands = f.readlines()
                    f.close()
                else:
                    scripts = os.listdir('scripts/')
                    print "Scripts available:"
                    for script in scripts:
                        print "\t", script
            elif cmd.split(" ")[0] in ["wx", "wa"]:
                if cmd.split(" ")[0] == "wx":
                    data = unhexlify(cmd.split(" ")[1])
                else:
                    data = cmd.split(" ")[1]
                
                pyew.f.seek(pyew.offset)
                pyew.f.write(data)
                pyew.seek(pyew.offset)
            else:
                if cmd.find("=") > -1 or cmd.startswith("print") or cmd.startswith("import "):
                    exec(cmd)
                else:
                    x = eval(cmd)
                    if "hexdigest" in dir(x):
                        print "%s: %s" % (cmd, x.hexdigest())
                    else:
                        pprint.pprint(x)
        except:
            print "Error:", sys.exc_info()[1]
            if pyew.debug:
                raise

    # main loop break here!
    pyew.quitFlag = True
    thread.join()
Ejemplo n.º 8
0
def main(filename):
    pyew = CPyew()
    if os.getenv("PYEW_DEBUG"):
        pyew.debug=True
    else:
        pyew.debug = False

    pyew.loadFile(filename, "rb")

    if pyew.format in ["PE", "ELF"]:
        saveAndCompareInDatabase(pyew)

    pyew.offset = 0
    print pyew.hexdump(pyew.buf, pyew.hexcolumns)

    oldpyew = None
    cmd = ""
    last_cmd = ""
    pyew.previousoffset = []

    # Add global object's references for easier usage
    pe = pyew.pe
    elf = pyew.elf

    # Set AutoCompletion
    setupAutoCompletion(pyew)

    # Check if there is runme.py file
    if os.path.exists('runme.py'):
        f = open('runme.py', 'r')
        commands = f.readlines()
        f.close()

    while 1:
        try:
            last_cmd = cmd
            
            if len(pyew.previousoffset) > 0:
                if pyew.previousoffset[len(pyew.previousoffset)-1] != pyew.offset:
                    pyew.previousoffset.append(pyew.offset)
            else:
                pyew.previousoffset.append(pyew.offset)
            
            va = None
            if pyew.virtual:
                va = pyew.getVirtualAddressFromOffset(pyew.offset)
            
            if va:
                prompt = "[0x%08x:0x%08x]> " % (pyew.offset, va)
            else:
                prompt = "[0x%08x]> " % pyew.offset
            
            try:
                cmd = commands[0].rstrip()
                commands.pop(0)
            except:
                cmd = raw_input(prompt)
            
            if cmd in ["", "b"] and (last_cmd in ["b", "x", "c", "d", "dump", "hexdump", "dis", "pd", "p", "r", "buf"] or last_cmd.isdigit()):
                if cmd == "b":
                    tmp = pyew.previousoffset.pop()
                    
                    if len(pyew.previousoffset) > 0:
                        tmp = pyew.previousoffset[len(pyew.previousoffset)-1]
                    else:
                        tmp = 0
                        
                    pyew.offset = tmp
                    pyew.lastasmoffset = tmp
                    pyew.seek(tmp)
                    if last_cmd.isdigit():
                        last_cmd = "c"
                    
                elif cmd == "b" and last_cmd == "b":
                    if len(pyew.previousoffset) < 2:
                        continue
                    
                    tmp = pyew.previousoffset.pop()
                    tmp = pyew.previousoffset[len(pyew.previousoffset)-1]
                    pyew.seek(tmp)
                    continue
                elif last_cmd in ["c", "d", "pd"] or last_cmd.isdigit():
                    pyew.offset = pyew.lastasmoffset
                    pyew.seek(pyew.offset)
                    if last_cmd.isdigit():
                        last_cmd = "c"
                else:
                    pyew.offset = pyew.offset+pyew.bsize
                    pyew.seek(pyew.offset)
                cmd = last_cmd
        except EOFError:
            break
        except KeyboardInterrupt:
            break
        
        try:
            if cmd.strip(" ") == "":
                continue
            
            if cmd.lower() in ["exit", "quit", "q"]:
                break
            elif cmd.lower() in ["a", "anal"]:
                pyew.findFunctions(pyew.processor)
                print
            elif cmd.lower() in ["x", "dump", "hexdump"]:
                print pyew.hexdump(pyew.buf, pyew.hexcolumns, baseoffset=pyew.offset)
            elif cmd.split(" ")[0] in ["s", "seek"]:
                data = cmd.split(" ")
                if len(data) > 1:
                    if data[1].lower() in ["ep", "entrypoint"]:
                        if pyew.ep:
                            pyew.offset = pyew.ep
                    else:
                        pyew.names.has_key(data[1].lower())
                        
                        if data[1].lower()[0] in ["+", "-"]:
                            pyew.offset += int(data[1])
                        elif data[1].lower().startswith("0x"):
                            pyew.offset = int(data[1], 16)
                        elif data[1] in pyew.names.values():
                            for x in pyew.names:
                                if pyew.names[x] == data[1]:
                                    pyew.offset = x
                                    break
                        else:
                            pyew.offset = int(data[1])
                        
                pyew.seek(pyew.offset)
            elif cmd.lower().split(" ")[0] in ["c", "d", "dis", "pd"]:
                data = cmd.lower().split(" ")
                if len(data) > 1:
                    if not data[1].startswith("/"):
                        type = int(data[1])
                        dis = pyew.disassemble(pyew.buf, pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=pyew.offset)
                        print dis
                    else:
                        cmd = data[1:]
                        if len(cmd) > 1:
                            ret = pyew.dosearch(pyew.f, cmd[0][1:2], cmd[1], cols=60, doprint=False, offset=pyew.offset)
                        else:
                            ret = pyew.dosearch(pyew.f, cmd[0][1:2], "", cols=60, doprint=False, offset=pyew.offset)
                        
                        for x in ret:
                            dis = pyew.disassemble(x.values()[0], pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=x.keys()[0])
                            print dis
                else:
                    dis = pyew.disassemble(pyew.buf, pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=pyew.offset)
                    print dis
            elif cmd.isdigit() and int(cmd) < len(pyew.calls)+1 and int(cmd) > 0:
                pyew.offset = pyew.calls[int(cmd)-1]
                pyew.seek(pyew.offset)
                dis = pyew.disassemble(pyew.buf, pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=pyew.offset)
                print dis
            elif cmd == "buf":
                lines = 0
                line = ""
                for c in pyew.buf:
                    line += c
                    if len(line) == pyew.hexcolumns:
                        print repr(line)
                        line = ""
                
                if line != "":
                    print repr(line)
            elif cmd == "byte":
                lines = 0
                line = ""
                for c in pyew.buf:
                    line += "0x%x, " % ord(c)
                    if len(line) >= pyew.hexcolumns / (1.00/4.00):
                        print line
                        line = ""
                
                if line != "":
                    print "%s" % line
            elif cmd.lower().split(" ")[0] in ["r", "repr"]:
                print repr(pyew.buf)
            elif cmd.lower().split(" ")[0] in ["p"]:
                print pyew.buf
            elif cmd.lower() in ["settings", "options"]:
                pyew.showSettings()
            elif cmd.startswith("/"):
                ret = pyew.dosearch(pyew.f, cmd[1:2], cmd[3:], cols=60, offset=pyew.offset)
            elif cmd.lower() in ["?", "help"]:
                showHelp(pyew)
            elif cmd.lower() in ["imports"]:
                if pyew.format == "PE":
                    for entry in pyew.pe.DIRECTORY_ENTRY_IMPORT:
                        print entry.dll
                        for imp in entry.imports:
                            print '\t', hex(imp.address), imp.name
                elif pyew.format == "ELF":
                    for x in pyew.elf.relocs:
                        print x
            elif cmd.lower() in ["exports"]:
                if pyew.format == "PE":
                    for exp in pyew.pe.DIRECTORY_ENTRY_EXPORT.symbols:
                        print hex(pyew.pe.OPTIONAL_HEADER.ImageBase + exp.address), exp.name, exp.ordinal
                elif pyew.format == "ELF":
                    print "Not yet implemented"
            elif cmd.lower() in ["sections"]:
                if pyew.format == "PE":
                    for x in pyew.pe.sections:
                        print x
                elif pyew.format == "ELF":
                    for x in pyew.elf.secnames:
                        print pyew.elf.secnames[x]
            elif cmd.lower() in ["elf", "pe"]:
                if cmd.lower() == "elf":
                    print pyew.elf
                else:
                    print pyew.pe
            elif cmd.lower() == "g":
                if cmd == "g":
                    pyew.offset = 0
                else:
                    pyew.offset = pyew.maxsize - pyew.bsize
                    if pyew.offset < 0:
                        pyew.offset = pyew.maxsize - 32
                pyew.seek(pyew.offset)
            elif cmd in ["-", "+"]:
                if cmd == "+":
                    pyew.offset += pyew.bsize
                else:
                    pyew.offset -= pyew.bsize
                pyew.seek(pyew.offset)
            elif pyew.plugins.has_key(cmd.split(" ")[0]):
                plg = cmd.split(" ")
                if len(plg) == 1:
                    pyew.plugins[plg[0]](pyew)
                else:
                    pyew.plugins[plg[0]](pyew, plg[1:])
            elif cmd.lower().split(" ")[0] in ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]:
                func = eval(cmd)
                print "%s: %s" % (cmd, func(pyew.getBuffer()).hexdigest())
            elif cmd.startswith("!"):
                os.system(cmd[1:])
            elif cmd == "ret" and oldpyew is not None:
                pyew = oldpyew
                pyew.seek(pyew.offset)
                oldpyew = None
            elif cmd == "file":
                oldpyew = pyew
                del pyew
                pyew = CPyew()
                buf = oldpyew.getBytes(oldpyew.offset, oldpyew.maxsize)
                pyew.loadFromBuffer(buf, oldpyew.filename + "[embed]")
            elif cmd == "interact":
                code.interact(local=locals())
            elif cmd == "edit":
                pyew.f.close()
                pyew.f = open(filename, "r+wb")
                pyew.seek(0)
            elif cmd.split(" ")[0] in ["ls"]:
                data = cmd.split(" ")
                if len(data) == 2:
                    #print "parsing script file:", data[1]
                    f = open('scripts/' + data[1], 'r')
                    commands = f.readlines()
                    f.close()
                else:
                    scripts = os.listdir('scripts/')
                    print "Scripts available:"
                    for script in scripts:
                        print "\t", script
            elif cmd.split(" ")[0] in ["wx", "wa"]:
                if cmd.split(" ")[0] == "wx":
                    data = unhexlify(cmd.split(" ")[1])
                else:
                    data = cmd.split(" ")[1]
                
                pyew.f.seek(pyew.offset)
                pyew.f.write(data)
                pyew.seek(pyew.offset)
            else:
                if cmd.find("=") > -1 or cmd.startswith("print") or cmd.startswith("import "):
                    exec(cmd)
                else:
                    x = eval(cmd)
                    if "hexdigest" in dir(x):
                        print "%s: %s" % (cmd, x.hexdigest())
                    else:
                        pprint.pprint(x)
        except:
            print "Error:", sys.exc_info()[1]
            if pyew.debug:
                raise
Ejemplo n.º 9
0
class CPatcher:
    def __init__(self, binary, sc, out):
        self.binary = binary
        self.sc = sc
        self.out = out
        self.pyew = CPyew(False, False)

        self.sc_buf = None

    def loadFiles(self):
        try:
            self.pyew.deepcodeanalysis = False
            print "[+] Loading and analysing file %s" % self.binary
            self.pyew.loadFile(self.binary)
        except:
            print "[!] Error loading binary file:", sys.exc_info()[1]
            return False

        try:
            self.sc_buf = open(self.sc, "rb").read()
        except:
            print "[!] Error reading shellcode file:", sys.exc_info()[1]
            return False

        if self.pyew.format not in ["PE", "ELF"]:
            print "[!] Format %s not supported" % self.pyew.format
            return False

        print "[i] Total of %d function(s) found in %s file" % (len(
            self.pyew.functions), self.pyew.format)
        print "[i] Entry point function %s at 0x%08x" % (
            self.pyew.names[self.pyew.ep], self.pyew.ep)
        return True

    def internalPatch(self, off):
        """ Patch at offset 'off' with the contents of the shellcode """
        buf = self.pyew.getBuffer()
        out_buf = buf[:off] + self.sc_buf + buf[off + len(self.sc_buf):]

        # Adjust section's privileges for PE files
        if self.pyew.format == "PE":
            pe = pefile.PE(data=out_buf)
            IMAGE_SCN_MEM_READWRITEEXEC = 0xe0000000L
            for section in pe.sections:
                if off >= section.PointerToRawData and off <= section.PointerToRawData + section.SizeOfRawData:
                    print "[+] Patching section %s" % section.Name
                    section.Characteristics |= IMAGE_SCN_MEM_READWRITEEXEC

        try:
            print "[+] Writing output file %s" % self.out
            if self.pyew.format != "PE":
                f = open(self.out, "wb")
                f.write(out_buf)
                f.close()
            else:
                pe.write(self.out)
            return True
        except:
            print "[!] Error writing output file", sys.exc_info()[1]
            return False

    def findFunctionAndPatch(self):
        """ Find a random function called from the entry point to patch """
        g = self.pyew.callgraph
        funcs = g.nodes()
        ep = g.node(self.pyew.names[self.pyew.ep])

        while 1:
            f = random.choice(funcs)
            if f == ep:
                continue
            path = g.searchPath(ep, f)
            if path is not None:
                f = self.pyew.getFunction(f.name)
                print "[i] Function at offset 0x%08x will be patched" % f
                break

        return self.internalPatch(f)

    def patch(self):
        if self.loadFiles():
            return self.findFunctionAndPatch()
        return False
Ejemplo n.º 10
0
class CPatcher:
  def __init__(self, binary, sc, out):
    self.binary = binary
    self.sc = sc
    self.out = out
    self.pyew = CPyew(False, False)
    
    self.sc_buf = None

  def loadFiles(self):
    try:
      self.pyew.deepcodeanalysis = False
      print "[+] Loading and analysing file %s" % self.binary
      self.pyew.loadFile(self.binary)
    except:
      print "[!] Error loading binary file:", sys.exc_info()[1]
      return False
    
    try:
      self.sc_buf = open(self.sc, "rb").read()
    except:
      print "[!] Error reading shellcode file:", sys.exc_info()[1]
      return False
    
    if self.pyew.format not in ["PE", "ELF"]:
      print "[!] Format %s not supported" % self.pyew.format
      return False
    
    print "[i] Total of %d function(s) found in %s file" % (len(self.pyew.functions), self.pyew.format)
    print "[i] Entry point function %s at 0x%08x" % (self.pyew.names[self.pyew.ep], self.pyew.ep)
    return True

  def internalPatch(self, off):
    """ Patch at offset 'off' with the contents of the shellcode """
    buf = self.pyew.getBuffer()
    out_buf = buf[:off] + self.sc_buf + buf[off+len(self.sc_buf):]
    
    # Adjust section's privileges for PE files
    if self.pyew.format == "PE":
      pe = pefile.PE(data=out_buf)
      IMAGE_SCN_MEM_READWRITEEXEC = 0xe0000000L
      for section in pe.sections:
        if off >= section.PointerToRawData and off <= section.PointerToRawData+section.SizeOfRawData:
          print "[+] Patching section %s" % section.Name
          section.Characteristics |= IMAGE_SCN_MEM_READWRITEEXEC
    
    try:
      print "[+] Writing output file %s" % self.out
      if self.pyew.format != "PE":
        f = open(self.out, "wb")
        f.write(out_buf)
        f.close()
      else:
        pe.write(self.out)
      return True
    except:
      print "[!] Error writing output file", sys.exc_info()[1]
      return False

  def findFunctionAndPatch(self):
    """ Find a random function called from the entry point to patch """
    g = self.pyew.callgraph
    funcs = g.nodes()
    ep = g.node(self.pyew.names[self.pyew.ep])
    
    while 1:
      f = random.choice(funcs)
      if f == ep:
        continue
      path = g.searchPath(ep, f)
      if path is not None:
        f = self.pyew.getFunction(f.name)
        print "[i] Function at offset 0x%08x will be patched" % f
        break
    
    return self.internalPatch(f)

  def patch(self):
    if self.loadFiles():
      return self.findFunctionAndPatch()
    return False