def main(filename=None): if filename is None: filename = fileopenbox(msg="Select PDF file", default="*.pdf", filetypes=["*.pdf"]) if filename is None: return pyew = CPyew(batch=True) pyew.loadFile(filename) streams = pyew.plugins["pdfilter"](pyew, doprint=True) if len(streams) == 0: msgbox(title="PDF Streams",msg="No encoded streams found") l = [] l.append("About PDF Streams Viewer") l.append("See all streams (both encoded and unencoded)") for x in streams: l.append("Stream %d encoded with %s" % (x, streams[x])) l.append("Quit") while 1: c = choicebox(msg="Select one stream to view it decoded", title="Stream Viewer", choices=l) if c is None: break elif c.lower() == "quit": break elif c.lower().startswith("about"): msgbox(title="About PDF Streams Viewer", msg="Example usage of the Pyew APIs to see PDF streams. Written by Joxean Koret") elif c.lower().startswith("see all"): pyew.plugins["pdfview"](pyew, doprint=False, stream_id=-1) else: stream_id = int(c.split(" ")[1]) pyew.plugins["pdfview"](pyew, stream_id=stream_id)
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 checkMebroot(path): pyew = CPyew(batch=True) pyew.codeanalysis = True try: pyew.loadFile(path) except: print "ERROR loading file %s" % path return if pyew.format == "PE": # Get 6 bytes at offset 0xB8 if pyew.getBytes(0xB8, 6) != "Rich;\x2E": return printData(pyew, path, "Mebroot downloader") print
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)
def checkAntidebug(path): t = time.time() pyew = CPyew(batch=True) pyew.codeanalysis = True try: pyew.loadFile(path) except KeyboardInterrupt: print "Abort" sys.exit(0) except: print "ERROR loading file %s" % path return if pyew.format not in ["PE", "ELF"]: return if len(pyew.antidebug) > 0: print printData(pyew, path, pyew.antidebug) print "Time to analyze %f" % (time.time() - t) print
def checkMnemonics(path): pyew = CPyew(batch=True) pyew.codeanalysis = True try: pyew.loadFile(path) except: print "ERROR loading file %s" % path return # Is it a PE file? if pyew.format == "PE": # The most common x86 mnemonics commons = ["PUSH", "MOV", "SUB", "ADD", "LEA", "CALL", "JMP", "JZ", "JNZ", \ "OR", "XOR", "NOT", "POP", "AND", "TEST", "JL", "JG", "JE", \ "JLE", "CMP", "LEAVE", "RET", "NOP", "PUSHF", "POPF", "INC", \ "INT 3", "DEC", "PUSHA", "POPA"] try: # Get the 30 first mnemonics mnems = pyew.GetMnems(pyew.ep, 30) except: print "ERROR scanning file %s" % path return ret = [] for x in mnems: if x not in commons and x not in ret: ret.append(x) if len(ret) > 0: printData(pyew, path, "Uncommon mnemonics") print "Mnemonics:", ",".join(ret) print # Seek to the entry point pyew.seek(pyew.ep) # Hexdump the first 64 bytes at the entry point print pyew.hexdump(pyew.buf, length=16, bsize=64)
def entryPointCalls(path): pyew = CPyew(batch=True) pyew.codeanalysis = True try: pyew.loadFile(path) except KeyboardInterrupt: print "Abort" sys.exit(0) except: print "ERROR loading file %s" % path return if pyew.format != "PE": return calls = [] # Get the disassembl of the first 100 lines l = pyew.disasm(pyew.ep, processor=pyew.processor, type=pyew.type, lines=100, bsize=1600) for i in l: mnem = str(i.mnemonic) # Is it a direct or indirect jump or call? if mnem == "CALL" or mnem.startswith("J") or mnem.startswith("LOOP"): operands = str(i.operands).replace("[", "").replace("]", "") try: if pyew.imports.has_key(int(operands, 16)): x = pyew.imports[int(operands, 16)] if x not in calls: calls.append(x) except: pass if len(calls) > 0: printData(pyew, path, "Library calls at Entry Point") print "Library Calls:", ",".join(calls) print
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 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()
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"
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()
# Configure some stuff... wine = '/path/to/wine' sigcheck = '/path/to/sigcheck.exe' subfile = '/path/to/hachoir-subfile' # These get passed to PEScanner yrules = 'apt1.yara' peid = 'userdb.txt' clamscan_path = '/path/to/clamscan' # Sanity check just to make sure it's a legit PE file before trying to analyze try: pe = pefile.PE(file) except Exception, msg: print msg sys.exit() # will this exit everything if there's a directory being analyzed? pyew = CPyew() if args['verbose'] == True: verb = True else: verb = False def header(msg): return msg + "\n" + ("=" * 90) def subTitle(msg): return "\n" + msg + "\n" + ("-" * 40) def q(s): quote = "\"" s = quote + s + quote
def analyse(self, path): filename = path t = time.time() buf = open(filename, "rb").read() sha1_hash = sha1(buf).hexdigest() if self.file_exists(sha1_hash): log("Already existing file %s..." % sha1_hash) return ANALYSIS_ALREADY pyew = CPyew(batch=True) pyew.analysis_timeout = 300 pyew.codeanalysis = True pyew.deepcodeanalysis = True try: pyew.loadFile(path) load_error = False except KeyboardInterrupt: log("Abort") return ANALYSIS_FAILED except: log("ERROR loading file %s" % path) load_error = True if not load_error: if pyew.format not in ["PE", "ELF", "bootsector"]: if pyew.format not in ["PDF", "OLE2"]: log("Not a known executable/document format") load_error = True if load_error: return ANALYSIS_FAILED primes = [] total_functions = len(pyew.function_stats) if not load_error and total_functions > 0: nodes = [] edges = [] ccs = [] callgraph = 1 for x in pyew.function_stats: nodes.append(pyew.function_stats[x][0]) edges.append(pyew.function_stats[x][1]) cc = pyew.function_stats[x][2] ccs.append(cc) prime = self.primes_table[cc] callgraph *= prime primes.append(prime) avg_nodes = abs(sum(nodes) / total_functions) avg_edges = abs(sum(edges) / total_functions) avg_ccs = abs(sum(ccs) / total_functions) elif load_error: total_functions = avg_nodes = avg_edges = avg_ccs = -1 callgraph = -1 msg = "%d-%d-%d-%d" % (total_functions, avg_nodes, avg_edges, avg_ccs) log("File analysed %s, callgraph signature %s" % (msg, callgraph)) log("Time to analyze %f" % (time.time() - t)) callgraph = str(callgraph) primes = ",".join(map(str, primes)) desc = self.get_description(buf) self.db.insert("samples", filename=filename, callgraph=callgraph, \ hash=sha1_hash, total_functions=total_functions, \ format=pyew.format, primes=primes, description=desc,\ analysis_date=time.asctime()) return ANALYSIS_SUCCESS
from pyew_core import CPyew sys.path.append("plugins") #import diagrams #import easygui #import graphs #import ole2 #import OleFileIO_PL #import packer #import pdf #import pdfid_PL #import shellcode #import threatexpert #import url #import virustotal #import vmdetect #import xdot filename = sys.argv[1] pyew = CPyew(batch=True) pyew.loadFile(filename, "rb") pyew.offset = 0 #pyew.pe.header for addr in pyew.basic_blocks.keys(): print addr
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
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()
import os, sys from pyew_core import CPyew sys.path.append("plugins") #import diagrams #import easygui #import graphs #import ole2 #import OleFileIO_PL #import packer #import pdf #import pdfid_PL #import shellcode #import threatexpert #import url #import virustotal #import vmdetect #import xdot filename = sys.argv[1] pyew = CPyew(batch=True) pyew.loadFile(filename, "rb") pyew.offset = 0 #pyew.pe.header for addr in pyew.basic_blocks.keys(): print addr
import sys from pyew_core import CPyew pyew = CPyew(batch=True) pyew.codeanalysis = True pyew.loadFile('/home/versa/malware1') #pyew.loadFromBuffer('/home/versa/malware1') print pyew.antidebug check = pyew.plugins["url"](pyew) pyew.plugins["sc"](pyew) pyew.plugins["packer"](pyew)
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
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()
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
from pyew_core import CPyew import sys import hashlib pyew = CPyew(batch=True) pyew.codeanalysis = True pyew.deepcodeanalysis = True path = sys.argv[1] print path d = open(path, 'rb').read() md5 = hashlib.md5(d).hexdigest() whitelist = set() pyew.loadFile(path) print 'loaded', len(pyew.functions), 'function' for offset, function in pyew.functions.iteritems(): whitelist.add(offset) for basic_block in function.basic_blocks: for instruction in basic_block.instructions: if instruction.mnemonic == 'CALL': whitelist.add(int(instruction.offset + instruction.size)) f = open(md5, 'w') f.write(path + '\n') for offset in sorted(whitelist): f.write('%d - %x\n' % (offset, offset)) f.close()