Advertisement
AndrewHaxalot

pyew.py

Dec 20th, 2013
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 19.35 KB | None | 0 0
  1. #!/usr/bin/python
  2. # -*- coding: latin-1 -*-
  3.  
  4. """
  5. Pyew! A Python Tool like the populars *iew
  6.  
  7. Copyright (C) 2009, Joxean Koret
  8.  
  9. This program is free software: you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation, either version 2 of the License, or
  12. (at your option) any later version.
  13.  
  14. This program is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. GNU General Public License for more details.
  18.  
  19. You should have received a copy of the GNU General Public License
  20. along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21.  
  22. """
  23.  
  24. import os
  25. import sys
  26. import code
  27. import pprint
  28. import sqlite3
  29. import StringIO
  30.  
  31. from binascii import unhexlify
  32. from hashlib import md5, sha1, sha224, sha256, sha384, sha512, new as hashlib_new
  33. from config import PLUGINS_PATH, DATABASE_PATH
  34.  
  35. try:
  36.     import psyco
  37.     psyco.log()
  38.     psyco.full()
  39. except ImportError:
  40.     pass
  41.  
  42. try:
  43.     import readline
  44.    
  45.     histfile = os.path.join(os.environ["HOME"], ".pyew")
  46.     try:
  47.         readline.read_history_file(histfile)
  48.     except IOError:
  49.         pass
  50.     import atexit
  51.     atexit.register(readline.write_history_file, histfile)
  52. except:
  53.     pass
  54.  
  55. try:
  56.     import pefile
  57.     hasPefile = True
  58. except ImportError:
  59.     hasPefile = False
  60.    
  61. try:
  62.     from Elf import Elf
  63.     hasElf = True
  64. except ImportError:
  65.     hasElf = False
  66.  
  67. from pyew_core import CPyew
  68.  
  69. PROGRAM="PYEW! A Python tool like radare or *iew"
  70. VERSION=0x01020000
  71. HUMAN_VERSION="1.2.0.0"
  72.  
  73. def showHelp(pyew):
  74.     print PROGRAM, "0x%x" % VERSION, "(%s)" % HUMAN_VERSION
  75.     print
  76.     print "Commands:"
  77.     print
  78.     print "?/help                            Show this help"
  79.     print "x/dump/hexdump                    Show hexadecimal dump"
  80.     print "s/seek                            Seek to a new offset"
  81.     print "b                                 Return to previous offset"
  82.     print "g/G                               Goto BOF (g) or EOF (G)"
  83.     print "+/-                               Go forward/backward one block (specified by pyew.bsize)"
  84.     print "c/d/dis/pd                        Show disassembly"
  85.     print "a                                 Do code analysis"
  86.     print "r/repr                            Show string representation"
  87.     print "ls                                List scripts available or launch one if used with an argument"
  88.     print "p                                 Print the buffer"
  89.     print "buf                               Print as a python buffer"
  90.     print "byte                              Print as a C byte array"
  91.     print "/x expr                           Search hexadecimal string"
  92.     print "/s expr                           Search strings"
  93.     print "/i expr                           Search string ignoring case"
  94.     print "/r expr                           Search regular expression"
  95.     print "/u expr                           Search unicode expression"
  96.     print "/U expr                           Search unicode expression ignoring case"
  97.     print "edit                              Reopen the file for reading and writting"
  98.     print "wx data                           Write hexadecimal data to file"
  99.     print "wa data                           Write ASCII data to file"
  100.     print "file                              Load as new file the buffer from the current offset"
  101.     print "ret                               Return to the original file (use after 'file')"
  102.     print "interact                          Open an interactive Python console"
  103.     print
  104.     print "Cryptographic functions: md5, sha1, sha224, sha256, sha384, sha512"
  105.     print
  106.     print "Examples:"
  107.     print "[0x0]> md5"
  108.     print "md5: d37b6d42a04cbc04cb2988ed947a5b0d"
  109.     print "[0x0]> md5(pyew.buf[0:7])"
  110.     print "581fd4acfc2214aa246f0b47c8ae8a4e"
  111.     print "[0x0]> md5(pyew.buf[15:35])"
  112.     print "a73b2882dd918070c6e8dfd9081fb600"
  113.     print
  114.     if pyew.pe:
  115.         print "PE specific commands:"
  116.         print
  117.         print "imports                           Show the import table"
  118.         print "exports                           Show the export table (if any)"
  119.         print
  120.  
  121.     print "Current configuration options:"
  122.     print
  123.     pyew.showSettings()
  124.     print
  125.     print "Any other expression will be evaled as a Python expression"
  126.     print
  127.  
  128. def createSchema(db):
  129.     try:
  130.         sql = """create table samples (id integer not null primary key,
  131.                                       md5, sha1, sha256, filename, type)"""
  132.         db.execute(sql)
  133.        
  134.         sql = """create table function_stats (
  135.                        id integer not null primary key,
  136.                        sample_id, addr, nodes, edges, cc)"""
  137.         db.execute(sql)
  138.        
  139.         sql = """create table antidebugs (
  140.                        id integer not null primary key,
  141.                        sample_id, addr, mnemonic
  142.                        )"""
  143.         db.execute(sql)
  144.     except:
  145.         pass
  146.  
  147. def saveSample(db, pyew, buf, amd5):
  148.     try:
  149.         asha1 = sha1(buf).hexdigest()
  150.         asha256 = sha256(buf).hexdigest()
  151.         name = pyew.filename
  152.         format = pyew.format
  153.        
  154.         cur = db.cursor()
  155.         sql = """ insert into samples (md5, sha1, sha256, filename, type)
  156.                               values (?, ?, ?, ?, ?)"""
  157.         cur.execute(sql, (amd5, asha1, asha256, name, format))
  158.         rid = cur.lastrowid
  159.        
  160.         sql = """ insert into function_stats (sample_id, addr, nodes, edges, cc)
  161.                                      values (?, ?, ?, ?, ?) """
  162.         for f in pyew.function_stats:
  163.             addr = "0x%08x" % f
  164.             nodes, edges, cc = pyew.function_stats[f]
  165.             cur.execute(sql, (rid, addr, nodes, edges, cc))
  166.        
  167.         sql = """ insert into antidebugs (sample_id, addr, mnemonic) values (?, ?, ?) """
  168.         for antidbg in pyew.antidebug:
  169.             addr, mnem = antidbg
  170.             addr = "0x%08x" % addr
  171.             cur.execute(sql, (rid, addr, mnem))
  172.        
  173.         db.commit()
  174.     except:
  175.         print sys.exc_info()[1]
  176.         pass
  177.  
  178. def saveAndCompareInDatabase(pyew):
  179.     db = sqlite3.connect(DATABASE_PATH)
  180.     createSchema(db)
  181.     cur = db.cursor()
  182.     bcontinue = True
  183.    
  184.     try:
  185.         buf = pyew.getBuffer()
  186.         amd5 = md5(buf).hexdigest()
  187.         name = pyew.filename
  188.         sql = """ select * from samples where md5 = ? """
  189.         cur.execute(sql, (amd5, ))
  190.        
  191.         for row in cur.fetchall():
  192.             if row[4] != name:
  193.                 print "NOTICE: File was previously analyzed (%s)" % row[4]
  194.                 print
  195.             bcontinue = False
  196.         cur.close()
  197.        
  198.         if bcontinue:
  199.             saveSample(db, pyew, buf, amd5)
  200.     except:
  201.         print sys.exc_info()[1]
  202.         raise
  203.  
  204. def setupAutoCompletion(pyew):
  205.  
  206.     # Settings
  207.     commands = {"pyew": pyew}
  208.     # Plugins
  209.     for plugin in pyew.plugins:
  210.         commands[plugin.ljust(8)] = 0
  211.     # Crypto
  212.     cryptos = ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]
  213.     for crypto in cryptos:
  214.         commands[crypto] = 0
  215.  
  216.     try:
  217.         import rlcompleter
  218.        
  219.         readline.set_completer(rlcompleter.Completer(commands).complete)
  220.         readline.parse_and_bind("tab: complete")
  221.     except:
  222.         pass
  223.  
  224.  
  225. def main(filename):
  226.     pyew = CPyew()
  227.     if os.getenv("PYEW_DEBUG"):
  228.         pyew.debug=True
  229.     else:
  230.         pyew.debug = False
  231.  
  232.     pyew.loadFile(filename, "rb")
  233.  
  234.     if pyew.format in ["PE", "ELF"]:
  235.         saveAndCompareInDatabase(pyew)
  236.  
  237.     pyew.offset = 0
  238.     print pyew.hexdump(pyew.buf, pyew.hexcolumns)
  239.  
  240.     oldpyew = None
  241.     cmd = ""
  242.     last_cmd = ""
  243.     pyew.previousoffset = []
  244.  
  245.     # Add global object's references for easier usage
  246.     pe = pyew.pe
  247.     elf = pyew.elf
  248.  
  249.     # Set AutoCompletion
  250.     setupAutoCompletion(pyew)
  251.  
  252.     # Check if there is runme.py file
  253.     if os.path.exists('runme.py'):
  254.         f = open('runme.py', 'r')
  255.         commands = f.readlines()
  256.         f.close()
  257.  
  258.     while 1:
  259.         try:
  260.             last_cmd = cmd
  261.            
  262.             if len(pyew.previousoffset) > 0:
  263.                 if pyew.previousoffset[len(pyew.previousoffset)-1] != pyew.offset:
  264.                     pyew.previousoffset.append(pyew.offset)
  265.             else:
  266.                 pyew.previousoffset.append(pyew.offset)
  267.            
  268.             va = None
  269.             if pyew.virtual:
  270.                 va = pyew.getVirtualAddressFromOffset(pyew.offset)
  271.            
  272.             if va:
  273.                 prompt = "[0x%08x:0x%08x]> " % (pyew.offset, va)
  274.             else:
  275.                 prompt = "[0x%08x]> " % pyew.offset
  276.            
  277.             try:
  278.                 cmd = commands[0].rstrip()
  279.                 commands.pop(0)
  280.             except:
  281.                 cmd = raw_input(prompt)
  282.            
  283.             if cmd in ["", "b"] and (last_cmd in ["b", "x", "c", "d", "dump", "hexdump", "dis", "pd", "p", "r", "buf"] or last_cmd.isdigit()):
  284.                 if cmd == "b":
  285.                     tmp = pyew.previousoffset.pop()
  286.                    
  287.                     if len(pyew.previousoffset) > 0:
  288.                         tmp = pyew.previousoffset[len(pyew.previousoffset)-1]
  289.                     else:
  290.                         tmp = 0
  291.                        
  292.                     pyew.offset = tmp
  293.                     pyew.lastasmoffset = tmp
  294.                     pyew.seek(tmp)
  295.                     if last_cmd.isdigit():
  296.                         last_cmd = "c"
  297.                    
  298.                 elif cmd == "b" and last_cmd == "b":
  299.                     if len(pyew.previousoffset) < 2:
  300.                         continue
  301.                    
  302.                     tmp = pyew.previousoffset.pop()
  303.                     tmp = pyew.previousoffset[len(pyew.previousoffset)-1]
  304.                     pyew.seek(tmp)
  305.                     continue
  306.                 elif last_cmd in ["c", "d", "pd"] or last_cmd.isdigit():
  307.                     pyew.offset = pyew.lastasmoffset
  308.                     pyew.seek(pyew.offset)
  309.                     if last_cmd.isdigit():
  310.                         last_cmd = "c"
  311.                 else:
  312.                     pyew.offset = pyew.offset+pyew.bsize
  313.                     pyew.seek(pyew.offset)
  314.                 cmd = last_cmd
  315.         except EOFError:
  316.             break
  317.         except KeyboardInterrupt:
  318.             break
  319.        
  320.         try:
  321.             if cmd.strip(" ") == "":
  322.                 continue
  323.            
  324.             if cmd.lower() in ["exit", "quit", "q"]:
  325.                 break
  326.             elif cmd.lower() in ["a", "anal"]:
  327.                 pyew.findFunctions(pyew.processor)
  328.                 print
  329.             elif cmd.lower() in ["x", "dump", "hexdump"]:
  330.                 print pyew.hexdump(pyew.buf, pyew.hexcolumns, baseoffset=pyew.offset)
  331.             elif cmd.split(" ")[0] in ["s", "seek"]:
  332.                 data = cmd.split(" ")
  333.                 if len(data) > 1:
  334.                     if data[1].lower() in ["ep", "entrypoint"]:
  335.                         if pyew.ep:
  336.                             pyew.offset = pyew.ep
  337.                     else:
  338.                         pyew.names.has_key(data[1].lower())
  339.                        
  340.                         if data[1].lower()[0] in ["+", "-"]:
  341.                             pyew.offset += int(data[1])
  342.                         elif data[1].lower().startswith("0x"):
  343.                             pyew.offset = int(data[1], 16)
  344.                         elif data[1] in pyew.names.values():
  345.                             for x in pyew.names:
  346.                                 if pyew.names[x] == data[1]:
  347.                                     pyew.offset = x
  348.                                     break
  349.                         else:
  350.                             pyew.offset = int(data[1])
  351.                        
  352.                 pyew.seek(pyew.offset)
  353.             elif cmd.lower().split(" ")[0] in ["c", "d", "dis", "pd"]:
  354.                 data = cmd.lower().split(" ")
  355.                 if len(data) > 1:
  356.                     if not data[1].startswith("/"):
  357.                         type = int(data[1])
  358.                         dis = pyew.disassemble(pyew.buf, pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=pyew.offset)
  359.                         print dis
  360.                     else:
  361.                         cmd = data[1:]
  362.                         if len(cmd) > 1:
  363.                             ret = pyew.dosearch(pyew.f, cmd[0][1:2], cmd[1], cols=60, doprint=False, offset=pyew.offset)
  364.                         else:
  365.                             ret = pyew.dosearch(pyew.f, cmd[0][1:2], "", cols=60, doprint=False, offset=pyew.offset)
  366.                        
  367.                         for x in ret:
  368.                             dis = pyew.disassemble(x.values()[0], pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=x.keys()[0])
  369.                             print dis
  370.                 else:
  371.                     dis = pyew.disassemble(pyew.buf, pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=pyew.offset)
  372.                     print dis
  373.             elif cmd.isdigit() and int(cmd) < len(pyew.calls)+1 and int(cmd) > 0:
  374.                 pyew.offset = pyew.calls[int(cmd)-1]
  375.                 pyew.seek(pyew.offset)
  376.                 dis = pyew.disassemble(pyew.buf, pyew.processor, pyew.type, pyew.lines, pyew.bsize, baseoffset=pyew.offset)
  377.                 print dis
  378.             elif cmd == "buf":
  379.                 lines = 0
  380.                 line = ""
  381.                 for c in pyew.buf:
  382.                     line += c
  383.                     if len(line) == pyew.hexcolumns:
  384.                         print repr(line)
  385.                         line = ""
  386.                
  387.                 if line != "":
  388.                     print repr(line)
  389.             elif cmd == "byte":
  390.                 lines = 0
  391.                 line = ""
  392.                 for c in pyew.buf:
  393.                     line += "0x%x, " % ord(c)
  394.                     if len(line) >= pyew.hexcolumns / (1.00/4.00):
  395.                         print line
  396.                         line = ""
  397.                
  398.                 if line != "":
  399.                     print "%s" % line
  400.             elif cmd.lower().split(" ")[0] in ["r", "repr"]:
  401.                 print repr(pyew.buf)
  402.             elif cmd.lower().split(" ")[0] in ["p"]:
  403.                 print pyew.buf
  404.             elif cmd.lower() in ["settings", "options"]:
  405.                 pyew.showSettings()
  406.             elif cmd.startswith("/"):
  407.                 ret = pyew.dosearch(pyew.f, cmd[1:2], cmd[3:], cols=60, offset=pyew.offset)
  408.             elif cmd.lower() in ["?", "help"]:
  409.                 showHelp(pyew)
  410.             elif cmd.lower() in ["imports"]:
  411.                 if pyew.format == "PE":
  412.                     for entry in pyew.pe.DIRECTORY_ENTRY_IMPORT:
  413.                         print entry.dll
  414.                         for imp in entry.imports:
  415.                             print '\t', hex(imp.address), imp.name
  416.                 elif pyew.format == "ELF":
  417.                     for x in pyew.elf.relocs:
  418.                         print x
  419.             elif cmd.lower() in ["exports"]:
  420.                 if pyew.format == "PE":
  421.                     for exp in pyew.pe.DIRECTORY_ENTRY_EXPORT.symbols:
  422.                         print hex(pyew.pe.OPTIONAL_HEADER.ImageBase + exp.address), exp.name, exp.ordinal
  423.                 elif pyew.format == "ELF":
  424.                     print "Not yet implemented"
  425.             elif cmd.lower() in ["sections"]:
  426.                 if pyew.format == "PE":
  427.                     for x in pyew.pe.sections:
  428.                         print x
  429.                 elif pyew.format == "ELF":
  430.                     for x in pyew.elf.secnames:
  431.                         print pyew.elf.secnames[x]
  432.             elif cmd.lower() in ["elf", "pe"]:
  433.                 if cmd.lower() == "elf":
  434.                     print pyew.elf
  435.                 else:
  436.                     print pyew.pe
  437.             elif cmd.lower() == "g":
  438.                 if cmd == "g":
  439.                     pyew.offset = 0
  440.                 else:
  441.                     pyew.offset = pyew.maxsize - pyew.bsize
  442.                     if pyew.offset < 0:
  443.                         pyew.offset = pyew.maxsize - 32
  444.                 pyew.seek(pyew.offset)
  445.             elif cmd in ["-", "+"]:
  446.                 if cmd == "+":
  447.                     pyew.offset += pyew.bsize
  448.                 else:
  449.                     pyew.offset -= pyew.bsize
  450.                 pyew.seek(pyew.offset)
  451.             elif pyew.plugins.has_key(cmd.split(" ")[0]):
  452.                 plg = cmd.split(" ")
  453.                 if len(plg) == 1:
  454.                     pyew.plugins[plg[0]](pyew)
  455.                 else:
  456.                     pyew.plugins[plg[0]](pyew, plg[1:])
  457.             elif cmd.lower().split(" ")[0] in ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]:
  458.                 func = eval(cmd)
  459.                 print "%s: %s" % (cmd, func(pyew.getBuffer()).hexdigest())
  460.             elif cmd.startswith("!"):
  461.                 os.system(cmd[1:])
  462.             elif cmd == "ret" and oldpyew is not None:
  463.                 pyew = oldpyew
  464.                 pyew.seek(pyew.offset)
  465.                 oldpyew = None
  466.             elif cmd == "file":
  467.                 oldpyew = pyew
  468.                 del pyew
  469.                 pyew = CPyew()
  470.                 buf = oldpyew.getBytes(oldpyew.offset, oldpyew.maxsize)
  471.                 pyew.loadFromBuffer(buf, oldpyew.filename + "[embed]")
  472.             elif cmd == "interact":
  473.                 code.interact(local=locals())
  474.             elif cmd == "edit":
  475.                 pyew.f.close()
  476.                 pyew.f = open(filename, "r+wb")
  477.                 pyew.seek(0)
  478.             elif cmd.split(" ")[0] in ["ls"]:
  479.                 data = cmd.split(" ")
  480.                 if len(data) == 2:
  481.                     #print "parsing script file:", data[1]
  482.                     f = open('scripts/' + data[1], 'r')
  483.                     commands = f.readlines()
  484.                     f.close()
  485.                 else:
  486.                     scripts = os.listdir('scripts/')
  487.                     print "Scripts available:"
  488.                     for script in scripts:
  489.                         print "\t", script
  490.             elif cmd.split(" ")[0] in ["wx", "wa"]:
  491.                 if cmd.split(" ")[0] == "wx":
  492.                     data = unhexlify(cmd.split(" ")[1])
  493.                 else:
  494.                     data = cmd.split(" ")[1]
  495.                
  496.                 pyew.f.seek(pyew.offset)
  497.                 pyew.f.write(data)
  498.                 pyew.seek(pyew.offset)
  499.             else:
  500.                 if cmd.find("=") > -1 or cmd.startswith("print") or cmd.startswith("import "):
  501.                     exec(cmd)
  502.                 else:
  503.                     x = eval(cmd)
  504.                     if "hexdigest" in dir(x):
  505.                         print "%s: %s" % (cmd, x.hexdigest())
  506.                     else:
  507.                         pprint.pprint(x)
  508.         except:
  509.             print "Error:", sys.exc_info()[1]
  510.             if pyew.debug:
  511.                 raise
  512.  
  513. def mainBatch(directory):
  514.     pass
  515.  
  516. def usage():
  517.     print "%s Version 0x%08x (%s)" % (PROGRAM, VERSION, HUMAN_VERSION)
  518.     print
  519.     print "Usage:", sys.argv[0], "<filename>"
  520.  
  521. if __name__ == "__main__":
  522.     if len(sys.argv) == 1:
  523.         usage()
  524.     else:
  525.         main(sys.argv[1])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement