├── .gitignore ├── Au3 ├── bindiffer.au3 ├── bindiffer_template.au3 └── test.au3 ├── IDAScripts ├── exit.py ├── idbsave.template ├── run_binDiff.py └── run_binDiff.template ├── Lib ├── __init__.py ├── __init__.pyc ├── autodiff.py ├── bindiffer.py ├── bindiffer.pyc ├── pairFinder.py ├── pairFinder.pyc ├── unpacker.py ├── unpacker.pyc ├── utils.py └── utils.pyc ├── Modules ├── __init__.py ├── any.py ├── any.pyc ├── flash.py ├── flash.pyc ├── module.py └── module.pyc ├── README.txt ├── agent.py ├── agent.pyproj ├── bin └── MsiX.exe ├── config.py ├── config.pyc ├── logger.py └── logger.pyc /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | test.py 3 | .pyc 4 | -------------------------------------------------------------------------------- /Au3/bindiffer.au3: -------------------------------------------------------------------------------- 1 | #include 2 | $old_db = "t:\tmp\GDI32DEMO\old\SP3QFE\gdi32.idb" 3 | $bd_db = "t:\tmp\GDI32DEMO\gdi32_vs_gdi32.BinDiff" 4 | $exit_script = "t:\projects\Cisco\Code\AutoDiff\AutoDiff\agent\IDAScripts\exit.py" 5 | 6 | WinWait("zynamics BinDiff 4.0.0") 7 | WinActivate("zynamics BinDiff 4.0.0") 8 | send("{ENTER}") 9 | WinWait("Select Database") 10 | sleep(1000) 11 | send($old_db) 12 | send("{ENTER}") 13 | WinWaitClose("zynamics BinDiff 4.0.0") 14 | send("{CTRLDOWN}") 15 | send("6") 16 | send("{CTRLUP}") 17 | WinWait("zynamics BinDiff 4.0.0") 18 | send("{DOWN}") 19 | send("{DOWN}") 20 | send("{DOWN}") 21 | send("{DOWN}") 22 | send("{ENTER}") 23 | WinWait("Save Results As") 24 | sleep(1000) 25 | send($bd_db) 26 | send("{ENTER}") 27 | sleep(2000) 28 | WinWaitActive("zynamics BinDiff 4.0.0") 29 | send("{DOWN}") 30 | send("{DOWN}") 31 | send("{ENTER}") 32 | send("{ALTDOWN}") 33 | send("{F7}") 34 | send("{ALTUP}") 35 | sleep(1000) 36 | send($exit_script) 37 | send("{ENTER}") 38 | sleep(1000) -------------------------------------------------------------------------------- /Au3/bindiffer_template.au3: -------------------------------------------------------------------------------- 1 | #include 2 | $old_db = "***OLD_IDB***" 3 | $bd_db = "***BD_DB***" 4 | $exit_script = "***EXIT_SCRIPT***" 5 | 6 | WinWait("zynamics BinDiff 4.0.0") 7 | WinActivate("zynamics BinDiff 4.0.0") 8 | send("{ENTER}") 9 | WinWait("Select Database") 10 | sleep(1000) 11 | send($old_db) 12 | send("{ENTER}") 13 | WinWaitClose("zynamics BinDiff 4.0.0") 14 | send("{CTRLDOWN}") 15 | send("6") 16 | send("{CTRLUP}") 17 | WinWait("zynamics BinDiff 4.0.0") 18 | send("{DOWN}") 19 | send("{DOWN}") 20 | send("{DOWN}") 21 | send("{DOWN}") 22 | send("{ENTER}") 23 | WinWait("Save Results As") 24 | sleep(1000) 25 | send($bd_db) 26 | send("{ENTER}") 27 | sleep(2000) 28 | WinWaitActive("zynamics BinDiff 4.0.0") 29 | send("{DOWN}") 30 | send("{DOWN}") 31 | send("{ENTER}") 32 | send("{ALTDOWN}") 33 | send("{F7}") 34 | send("{ALTUP}") 35 | sleep(1000) 36 | send($exit_script) 37 | send("{ENTER}") 38 | sleep(1000) -------------------------------------------------------------------------------- /Au3/test.au3: -------------------------------------------------------------------------------- 1 | $old_db = "t:\projects\Cisco\Code\AutoDiff\samples\GDI\old\gdi32.idb" 2 | $bd_db = "t:\projects\Cisco\Code\AutoDiff\samples\GDI\gdi32_vs_gdi32.BinDiff" 3 | $exit_script = "t:\projects\Cisco\Code\AutoDiff\AutoDiff\agent\IDAScripts\exit.py" 4 | 5 | WinWait("zynamics BinDiff 4.0.0") 6 | send("{ENTER}") 7 | ConsoleWrite("Waiting for database window") 8 | WinWait("Select Database") 9 | sleep(1000) 10 | send($old_db) 11 | -------------------------------------------------------------------------------- /IDAScripts/exit.py: -------------------------------------------------------------------------------- 1 | from idaapi import * 2 | from idautils import * 3 | 4 | 5 | if __name__ == '__main__': 6 | Exit(0) -------------------------------------------------------------------------------- /IDAScripts/idbsave.template: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from idaapi import * 4 | from idautils import * 5 | import idc 6 | 7 | output = r'***OUT***' 8 | 9 | if __name__ == '__main__': 10 | autoWait() 11 | save_database(output, False) 12 | 13 | Exit(0) 14 | -------------------------------------------------------------------------------- /IDAScripts/run_binDiff.py: -------------------------------------------------------------------------------- 1 | from idaapi import * 2 | from idautils import * 3 | 4 | import subprocess 5 | import time 6 | 7 | if __name__ == '__main__': 8 | autoWait() 9 | subprocess.Popen([r"c:\Program Files (x86)\AutoIt3\AutoIt3_x64.exe", r"t:\projects\Cisco\Code\AutoDiff\AutoDiff\agent\Au3\bindiffer.au3"]) 10 | plugin = load_plugin(r"d:\IDA_6.6\plugins\zynamics_bindiff_4_0.plw") 11 | print run_plugin(plugin, 0) 12 | -------------------------------------------------------------------------------- /IDAScripts/run_binDiff.template: -------------------------------------------------------------------------------- 1 | from idaapi import * 2 | from idautils import * 3 | 4 | import subprocess 5 | import time 6 | 7 | if __name__ == '__main__': 8 | autoWait() 9 | subprocess.Popen([r"***AUTOIT_PATH***", r"***AUTOIT_SCRIPT***"]) 10 | plugin = load_plugin(r"***BINDIFF_PLUGIN***") 11 | print run_plugin(plugin, 0) 12 | -------------------------------------------------------------------------------- /Lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/Lib/__init__.py -------------------------------------------------------------------------------- /Lib/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/Lib/__init__.pyc -------------------------------------------------------------------------------- /Lib/autodiff.py: -------------------------------------------------------------------------------- 1 | from config import Config 2 | import os 3 | import subprocess 4 | import sqlite3 5 | 6 | class AutoDiff(object): 7 | """description of class""" 8 | def run(self,primaryIDB,secondaryIDB,binDiffFilePath): 9 | 10 | self.__setArch(primaryIDB) 11 | autoDiffParams = "{autoDiffPath} -f 1 -b \"{binDiffFilePath}\" -d \"{idb2}\" -a".format( 12 | autoDiffPath = Config.AUTODIFF_PATH, 13 | binDiffFilePath = binDiffFilePath, 14 | idb2 = secondaryIDB 15 | ) 16 | if subprocess.call([self.__IDA_PATH,"-A","-S" + autoDiffParams,primaryIDB]) != 0: 17 | print "Could not unpack exe" 18 | return False 19 | return True 20 | 21 | def __setArch(self,filePath): 22 | path,ext = os.path.splitext(filePath) 23 | if ext == ".i64": #PE+ (x64) 24 | self.__IDA_PATH = Config.IDA_PATH.replace("idaq.exe","idaq64.exe") 25 | else: 26 | #PE (x86) 27 | self.__IDA_PATH = Config.IDA_PATH 28 | 29 | def getResult(self,binDiffFilePath): 30 | db = sqlite3.connect(binDiffFilePath) 31 | db.row_factory = sqlite3.Row 32 | sqlChangedFunctions = "SELECT count(*) FROM function WHERE similarity < 1.0" 33 | 34 | sqlSanitizedFunctions = """ 35 | SELECT count(*) 36 | FROM function as f 37 | WHERE similarity < 1.0 AND f.id IN (SELECT func_id FROM sanitizer_summary) 38 | """ 39 | sqlSafeIntCount = """ 40 | SELECT count(*) FROM sf_summary 41 | """ 42 | sqlReMatched = """ 43 | SELECT count(*) FROM rematcher_summary 44 | """ 45 | row = db.execute(sqlChangedFunctions).fetchone() 46 | changedFunctionsCount = int(row[0]) 47 | row = db.execute(sqlSanitizedFunctions).fetchone() 48 | sanitizedFunctionsCount = int(row[0]) 49 | row = db.execute(sqlSafeIntCount).fetchone() 50 | safeIntCount = int(row[0]) 51 | row = db.execute(sqlReMatched).fetchone() 52 | reMatchedCount = int(row[0]) 53 | db.close() 54 | return (changedFunctionsCount - (sanitizedFunctionsCount + safeIntCount + reMatchedCount)) -------------------------------------------------------------------------------- /Lib/bindiffer.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import os 3 | from config import Config 4 | import sqlite3 5 | import win32file 6 | import pefile 7 | 8 | class Bindiffer(object): 9 | 10 | def __init__(self,patchDir): 11 | self.__newIDBPath = None 12 | self.__oldIDBPath = None 13 | self.__binDiffFilePath = None 14 | self.__patchDir = patchDir 15 | self.__IDA_PATH = "" #depends on file arch it gonna change 16 | self.__BINDIFF_PLUGIN = "" 17 | self.__IDBEXT = "" 18 | self.__archFlag = False 19 | self.__initPaths() 20 | 21 | def createIDB(self,filePath): 22 | self.__setArch(filePath) 23 | subprocess.check_output([self.__IDA_PATH, '-B', '-A', filePath]) 24 | #replace extension 25 | path, ext = os.path.splitext(filePath) 26 | return path + self.__IDBEXT 27 | 28 | def runBinDiff(self,newIDB,oldIDB): 29 | #create .binDiff file name 30 | self.__initBinDiffFile(newIDB,oldIDB) 31 | self.__makeBinDiffScript() 32 | self.__makeBinDiffAu3(oldIDB) 33 | subprocess.call([self.__IDA_PATH, '-S"%s"' % (self.__scriptBinDiffPath), newIDB]) 34 | 35 | def getResult(self): 36 | db = sqlite3.connect(self.__binDiffFilePath) 37 | db.row_factory = sqlite3.Row 38 | result = db.execute("select count(*) as amount from function where similarity < 1.0 order by similarity").fetchall() 39 | db.close() 40 | result = result[0] 41 | return result["amount"] 42 | 43 | def getBinDiffFilePath(self): 44 | return self.__binDiffFilePath 45 | 46 | """ 47 | Helpers 48 | """ 49 | 50 | def __initPaths(self): 51 | #IDAScripts 52 | self.__idaScriptsPath = os.path.join(Config.AGENT_LOCATION,"IDAScripts") 53 | self.__templateBinDiffPath = os.path.join(self.__idaScriptsPath,"run_binDiff.template") 54 | self.__scriptBinDiffPath = os.path.join(self.__idaScriptsPath,"run_binDiff.py") 55 | #Au3 - AutoIt 56 | self.__au3Path = os.path.join(Config.AGENT_LOCATION,"Au3") 57 | self.__au3BinDiffTemplate = os.path.join(self.__au3Path,"bindiffer_template.au3") 58 | self.__au3BinDiffPath = os.path.join(self.__au3Path,"bindiffer.au3") 59 | 60 | 61 | def __initBinDiffFile(self,newIDB,oldIDB): 62 | path, file = os.path.split(newIDB) 63 | newName, ext = os.path.splitext(file) 64 | path, file = os.path.split(oldIDB) 65 | oldName, ext = os.path.splitext(file) 66 | self.__binDiffFileName = "%s_vs_%s.BinDiff" % (newName,oldName) 67 | self.__binDiffFilePath = os.path.join(self.__patchDir,self.__binDiffFileName) 68 | 69 | def __makeBinDiffScript(self): 70 | with file(self.__templateBinDiffPath,'r') as f: 71 | template = f.read() 72 | 73 | with file(self.__scriptBinDiffPath,'w') as f: 74 | template = template.replace("***AUTOIT_PATH***",Config.AUTOIT_PATH) 75 | template = template.replace("***AUTOIT_SCRIPT***",self.__au3BinDiffPath) 76 | template = template.replace("***BINDIFF_PLUGIN***",self.__BINDIFF_PLUGIN) 77 | f.write(template) 78 | 79 | def __makeBinDiffAu3(self,oldIDB): 80 | with file(self.__au3BinDiffTemplate,'r') as f: 81 | template = f.read() 82 | 83 | with file(self.__au3BinDiffPath,'w') as f: 84 | template = template.replace("***OLD_IDB***",oldIDB) 85 | template = template.replace("***BD_DB***",self.__binDiffFilePath) 86 | template = template.replace("***EXIT_SCRIPT***",os.path.join(self.__idaScriptsPath,"exit.py")) 87 | f.write(template) 88 | 89 | def __setArch(self,filePath): 90 | if not self.__archFlag: 91 | self.__archFlag = True 92 | else: 93 | return 94 | 95 | pe = pefile.PE(filePath,fast_load = True) 96 | if pe.OPTIONAL_HEADER.Magic == 0x20b: #PE+ (x64) 97 | self.__IDA_PATH = Config.IDA_PATH.replace("idaq.exe","idaq64.exe") 98 | self.__BINDIFF_PLUGIN = Config.BINDIFF_PLUGIN.replace("zynamics_bindiff_4_0.plw","zynamics_bindiff_4_0.p64") 99 | self.__IDBEXT = ".i64" 100 | else: 101 | #PE (x86) 102 | self.__IDA_PATH = Config.IDA_PATH 103 | self.__BINDIFF_PLUGIN = Config.BINDIFF_PLUGIN 104 | self.__IDBEXT = ".idb" 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /Lib/bindiffer.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/Lib/bindiffer.pyc -------------------------------------------------------------------------------- /Lib/pairFinder.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import hashlib 4 | from logger import Logger 5 | 6 | class PairFinder(object): 7 | def __init__(self): 8 | self.__pairs = [] 9 | self.__newFilesList = [] 10 | self.__oldFilesList = [] 11 | self.__specifiedFiles = [] 12 | self.__specifiedExtensions = [] 13 | 14 | def addSpecifiedFiles(self,files): 15 | """ 16 | File name can be defined as regex formula. 17 | """ 18 | if not isinstance(files,list): 19 | raise Exception("Files need to be passed as list type") 20 | self.__specifiedFiles += files 21 | 22 | def addSpecifiedExtensions(self,extensions): 23 | if not isinstance(extensions,list): 24 | raise Exception("Extensions need to be passed as list type") 25 | 26 | def collectFiles(self,newFiles,oldFiles): 27 | self.__pairs = [] 28 | self.__newFilesList = [] 29 | self.__oldFilesList = [] 30 | 31 | for root, dirs, files in os.walk(newFiles): 32 | for f in files: 33 | self.__newFilesList.append( os.path.join(root,f) ) 34 | 35 | for root, dirs, files in os.walk(oldFiles): 36 | for f in files: 37 | self.__oldFilesList.append( os.path.join(root,f) ) 38 | 39 | print "Old files:" 40 | print "\n".join(self.__oldFilesList) 41 | print "" 42 | print "New files:" 43 | print "\n".join(self.__newFilesList) 44 | 45 | def getPairs(self): 46 | if len(self.__pairs): 47 | return self.__pairs 48 | return self.__findPairs() 49 | 50 | def getFiles(self): 51 | return {"new": self.__newFilesList,"old": self.__oldFilesList} 52 | 53 | 54 | def __compare(self,newFile,oldFile): 55 | """ 56 | Returns True if file are the same and False in other way. 57 | """ 58 | #TODO : add comparing by size first ???? 59 | with file(newFile,'rb') as f: 60 | newHash = hashlib.sha1(f.read()).hexdigest() 61 | 62 | with file(oldFile,'rb') as f: 63 | oldHash = hashlib.sha1(f.read()).hexdigest() 64 | 65 | return newHash == oldHash 66 | 67 | def __findPairs(self): 68 | """ 69 | Generic pair finder 70 | """ 71 | for oldFile in self.__oldFilesList: 72 | pattern = None 73 | if len(self.__specifiedExtensions): 74 | name , ext = os.path.splitext(old) 75 | if not ext in self.__specifiedExtensions: 76 | continue 77 | 78 | old = os.path.split(oldFile)[1] 79 | if len(self.__specifiedFiles): 80 | for specifiedFile in self.__specifiedFiles: 81 | if re.match(specifiedFile,old): 82 | pattern = specifiedFile 83 | if pattern == None: 84 | continue 85 | 86 | for newFile in self.__newFilesList: 87 | new = os.path.split(newFile)[1] 88 | if pattern: 89 | if re.match(pattern,new): 90 | Logger.log("There is new pair:") 91 | Logger.log("Old : %s" % old) 92 | Logger.log("New : %s" % new) 93 | self.__pairs.append({"new" : {"name": new, "path": newFile},"old":{"name": old, "path": oldFile} } ) 94 | elif old == new: 95 | if self.__compare(newFile,oldFile): 96 | print "Files are the same!!!" 97 | Logger.log("There is new pair:") 98 | Logger.log("Old : %s" % old) 99 | Logger.log("New : %s" % new) 100 | self.__pairs.append( ({"name": new, "path": newFile},{"name": old, "path": oldFile} ) ) 101 | return self.__pairs -------------------------------------------------------------------------------- /Lib/pairFinder.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/Lib/pairFinder.pyc -------------------------------------------------------------------------------- /Lib/unpacker.py: -------------------------------------------------------------------------------- 1 | import zipfile 2 | import subprocess 3 | import os 4 | from config import Config 5 | 6 | class Unpacker(object): 7 | 8 | def __init__(self): 9 | self.__handlers = {".msi":self.__msiHandler, 10 | ".msu":self.__msuHandler, 11 | ".zip":self.__zipHandler, 12 | ".msp":self.__mspHandler, 13 | ".exe":self.__exeHandler, 14 | ".cab":self.__cabHandler 15 | } 16 | 17 | def unpack(self,filePath,extractDir,type = "auto"): 18 | if type == "auto": 19 | name,ext = os.path.splitext(filePath) 20 | else: 21 | ext = type 22 | self.__handlers[ext](filePath,extractDir) 23 | 24 | def __msiHandler(self,filePath,targetDir): 25 | """ 26 | Usage: MsiX.exe [/out ] [/ext] 27 | 28 | file - Path to an MSI, MSM, MSP, or PCP file. 29 | out - Extract streams and storages to the directory. 30 | ext - Append appropriate extensions to output files. 31 | """ 32 | msiXPath = os.path.join(Config.AGENT_LOCATION,"bin","MsiX.exe") 33 | if subprocess.call([msiXPath, filePath, "/out",targetDir]) != 0: 34 | print "Could not unpack msu" 35 | return False 36 | 37 | def __msuHandler(self,filePath,targetDir): 38 | ''' 39 | expand -F:* update.msu C: 40 | cd 41 | expand -F:* update.cab C: 42 | ''' 43 | 44 | print "Expanding", filePath, "to", targetDir 45 | 46 | if subprocess.call(['expand', '-F:*', filePath, targetDir]) != 0: 47 | print "Could not unpack msu" 48 | return False 49 | 50 | os.chdir(targetDir) 51 | 52 | garbage, cabname = os.path.split(filePath) 53 | cabname, ext = os.path.splitext(cabname) 54 | cabname = cabname + '.cab' 55 | os.path.join(targetDir, cabname) 56 | 57 | print "Expanding", cabname, "to", targetDir 58 | 59 | if subprocess.call(['expand', '-F:*', cabname, targetDir]) != 0: 60 | print "Could not unpack cab" 61 | return False 62 | 63 | return True 64 | 65 | def __zipHandler(self,filePath,extractDir): 66 | with zipfile.ZipFile(filePath) as zf: 67 | zf.extractall(extractDir) 68 | 69 | def __mspHandler(self,filePath,extractDir): 70 | """ 71 | Usage: MsiX.exe [/out ] [/ext] 72 | 73 | file - Path to an MSI, MSM, MSP, or PCP file. 74 | out - Extract streams and storages to the directory. 75 | ext - Append appropriate extensions to output files. 76 | """ 77 | msiXPath = os.path.join(Config.AGENT_LOCATION,"bin","MsiX.exe") 78 | if subprocess.call([msiXPath, filePath, "/out",extractDir]) != 0: 79 | print "Could not unpack msu" 80 | return False 81 | 82 | #some cab can be there o_0 83 | 84 | return True 85 | 86 | def __exeHandler(self,filePath,extractDir): 87 | if subprocess.call([filePath,"/quiet","/extract:" + extractDir]) != 0: 88 | print "Could not unpack exe" 89 | return False 90 | return True 91 | 92 | def __cabHandler(self,filePath,extractDir): 93 | print "Expanding", filePath, "to", extractDir 94 | 95 | if subprocess.call(['expand', '-F:*', filePath, extractDir]) != 0: 96 | print "Could not unpack cab" 97 | return False 98 | return True 99 | -------------------------------------------------------------------------------- /Lib/unpacker.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/Lib/unpacker.pyc -------------------------------------------------------------------------------- /Lib/utils.py: -------------------------------------------------------------------------------- 1 | import urllib2 2 | from urlparse import urlparse 3 | import os 4 | 5 | class Utils(object): 6 | @staticmethod 7 | def downloadPatch(url,directory): 8 | try: 9 | urlObject = urlparse(url) 10 | fileName = os.path.basename(urlObject.path) 11 | dst = os.path.join(directory,fileName) 12 | fileContent = urllib2.urlopen(url).read() 13 | with file(dst,'wb') as f: 14 | f.write(fileContent) 15 | return dst 16 | except Exception as e: 17 | print e.message 18 | return None 19 | 20 | 21 | -------------------------------------------------------------------------------- /Lib/utils.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/Lib/utils.pyc -------------------------------------------------------------------------------- /Modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/Modules/__init__.py -------------------------------------------------------------------------------- /Modules/any.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | from module import Module 3 | from Lib.utils import Utils 4 | import os 5 | from config import Config 6 | from logger import * 7 | 8 | class CAny(Thread,Module): 9 | def __init__(self): 10 | Thread.__init__(self) 11 | Module.__init__(self) 12 | 13 | def run(self): 14 | #download files 15 | if Config.DEBUG: 16 | downloadNew = r"d:\download\tmp\Windows6.0-KB2957689-x86.msu" 17 | downloadOld = r"d:\download\tmp\Windows6.0-KB2936068-x86.msu" 18 | else: 19 | Logger.remoteLog("Downloading new package from : %s" % self._task["url_new"],self._task["name"]) 20 | downloadNew = Utils.downloadPatch(self._task["url_new"],self._downloadDir) 21 | Logger.remoteLog("Downloading old package from : %s" % self._task["url_old"],self._task["name"]) 22 | downloadOld = Utils.downloadPatch(self._task["url_old"],self._downloadDir) 23 | #unpack them 24 | Logger.remoteLog("Unpackign new to : %s" % self._newDir,self._task["name"]) 25 | self._unpacker.unpack(downloadNew,self._newDir) 26 | Logger.remoteLog("Unpackign old to : %s" % self._newDir,self._task["name"]) 27 | self._unpacker.unpack(downloadOld,self._oldDir) 28 | #find proper pairs 29 | #self._pairFinder.addSpecifiedExtensions([".exe",".dll"]) # better even without this cos there can be files like in MS14-028 30 | #self.pairFinder.addSpecifiedFiles(["mshtml.dll"]) 31 | Logger.remoteLog("Starting collecting files...",self._task["name"]) 32 | self.pairFinder.collectFiles(self._newDir,self._oldDir) 33 | Logger.remoteLog("Sending file list...",self._task["name"]) 34 | self._sendFileList( self.pairFinder.getFiles() ) 35 | Logger.remoteLog("File list should be ready to review",self._task["name"]) 36 | if self._task["mode"] == "auto": 37 | pairs = self.pairFinder.getPairs() 38 | for pair in pairs: 39 | newIDB = self._binDiffer.createIDB(pair["new"]["path"]) 40 | oldIDB = self._binDiffer.createIDB(pair["old"]["path"]) 41 | #run BinDiff 42 | self._binDiffer.runBinDiff(newIDB,oldIDB) 43 | -------------------------------------------------------------------------------- /Modules/any.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/Modules/any.pyc -------------------------------------------------------------------------------- /Modules/flash.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | from module import Module 3 | from Lib.utils import Utils 4 | from logger import Logger 5 | import os 6 | import win32api 7 | 8 | class CFlash(Thread,Module): 9 | 10 | def run(self): 11 | print "Running Flash module" 12 | downloadNew = Utils.downloadPatch(self._task["url_new"],self._downloadDir) 13 | downloadOld = Utils.downloadPatch(self._task["url_old"],self._downloadDir) 14 | self._unpacker.unpack(downloadNew,self._newDir) 15 | self._unpacker.unpack(downloadOld,self._oldDir) 16 | newFlashInstaller = getFlashInstaller(self._newDir) 17 | oldFlashInstaller = getFlashInstaller(self._oldDir) 18 | Logger.log("Time to uninstall existing flash...") 19 | #uninstall first whatever is installed there 20 | Logger.log(oldFlashInstaller) 21 | subprocess.check_output([oldFlashInstaller,"-uninstall"]) 22 | Logger.log("Install old version...") 23 | #install old version 24 | subprocess.check_output([oldFlashInstaller,"-install"]) 25 | #collect files 26 | newFlashPath = os.path.join(DOWNLOAD_PATH,"new_flash") 27 | oldFlashPath = os.path.join(DOWNLOAD_PATH,"old_flash") 28 | Logger.log("Copy files..") 29 | try: 30 | shutil.rmtree(oldFlashPath, ignore_errors = True) 31 | except Exception as e: 32 | print e.message 33 | shutil.copytree(getFlashDirectory(),oldFlashPath) 34 | subprocess.check_output([oldFlashInstaller,"-uninstall"]) 35 | #install new version 36 | subprocess.check_output([newFlashInstaller,"-install"]) 37 | try: 38 | shutil.rmtree(newFlashPath, ignore_errors = True) 39 | except Exception as e: 40 | print e.message 41 | shutil.copytree(getFlashDirectory(),newFlashPath) 42 | self.pairFinder.addSpecifiedFiles(["^NPSWF32_"]) 43 | self.pairFinder.collectFiles(self._newDir,self._oldDir) 44 | pairs = self.pairFinder.getPairs() 45 | for pair in pairs: 46 | newIDB = self._binDiffer.createIDB(pair["new"]["path"]) 47 | oldIDB = self._binDiffer.createIDB(pair["old"]["path"]) 48 | #run BinDiff 49 | self._binDiffer.runBinDiff(newIDB,oldIDB) 50 | 51 | 52 | def is64Bits(): 53 | #under windows 54 | return os.environ.has_key("ProgramFiles(x86)") 55 | 56 | def getFlashDirectory(): 57 | #create flash path 58 | flashPath = win32api.GetWindowsDirectory() 59 | system32 = "SysWOW64" if is64Bits() else "system32" 60 | flashPath = os.path.join(flashPath,system32,"Macromed\\Flash") 61 | Logger.log(flashPath) 62 | return flashPath 63 | 64 | def getFlashInstaller(installerDir): 65 | installerDir = os.path.join(installerDir,"*","*.exe") 66 | files = glob.glob(installerDir) 67 | for f in files: 68 | if f.find("_debug") == -1 and f.find("_winax") == - 1 and f.find("uninstall_") == -1: 69 | return f 70 | -------------------------------------------------------------------------------- /Modules/flash.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/Modules/flash.pyc -------------------------------------------------------------------------------- /Modules/module.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | from Lib.unpacker import Unpacker 4 | from config import Config 5 | from Lib.pairFinder import PairFinder 6 | from Lib.bindiffer import Bindiffer 7 | import urllib 8 | import urllib2 9 | import json 10 | 11 | class Module(object): 12 | def __init__(self): 13 | #support classes 14 | self._unpacker = Unpacker() 15 | self.pairFinder = PairFinder() 16 | 17 | def initialize(self,workDir,task): 18 | self._workDir = workDir 19 | self._task = task 20 | #create necessary paths 21 | self._patchDir = os.path.join(workDir,task["name"]) 22 | self._downloadDir = os.path.join(self._patchDir,"download") 23 | self._newDir = os.path.join(self._patchDir,"new") 24 | self._oldDir = os.path.join(self._patchDir,"old") 25 | #create dirs 26 | shutil.rmtree(self._patchDir,ignore_errors = True) 27 | os.mkdir(self._patchDir) 28 | os.mkdir(self._downloadDir) 29 | os.mkdir(self._newDir) 30 | os.mkdir(self._oldDir) 31 | self._binDiffer = Bindiffer(self._patchDir) 32 | 33 | def getPatchDir(self): 34 | return self._patchDir 35 | 36 | def _sendFileList(self,files): 37 | try: 38 | #just add task_name == task_id to files 39 | postData = {} 40 | postData["task_name"] = self._task["name"]; 41 | postData["files"] = json.dumps(files) 42 | postData = urllib.urlencode( postData ) 43 | urllib2.urlopen("%s/Storage/saveFilesList" % Config.HOST, postData) 44 | except Exception as e: 45 | print e.message -------------------------------------------------------------------------------- /Modules/module.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/Modules/module.pyc -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | [*] Agent privilages on Windows 7 2 | Agent to work correctly when he is runned on Win7 u need to execute him with High privilages or just turn off UAC. 3 | 4 | More info in AutoDiffWeb documentation -------------------------------------------------------------------------------- /agent.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | import time 3 | import urllib2 4 | import urllib 5 | import os 6 | import json 7 | from config import * 8 | 9 | from logger import * 10 | Logger.init(Logger.CONSOLE) 11 | Logger.setLogUrl("http://autodiff.localdomain.com:7777/Logger/addLog") 12 | 13 | from Lib.unpacker import Unpacker 14 | from Lib.pairFinder import PairFinder 15 | from Lib.bindiffer import Bindiffer 16 | from Lib.autodiff import AutoDiff 17 | from Modules.any import * 18 | from Modules.flash import * 19 | import traceback 20 | 21 | class CAgent(Thread): 22 | def __init__(self): 23 | Thread.__init__(self) 24 | self.__busy = False 25 | #safe in somehow here runned tasks and their ID's ? 26 | self.__tasks = [] 27 | #commands handlers 28 | self.__handlers = { 29 | "getTask" : self.__getTask, 30 | "diffFiles" : self.__diffFiles, 31 | "diffStop" : self.__nop, 32 | "unpack" : self.__unpack 33 | } 34 | 35 | #TODO: add auto modules loader 36 | self.__modules = {"any": CAny(), 37 | "flash": CFlash(), 38 | "IE": CAny() 39 | } 40 | #additional initialization 41 | self.__modules["IE"].pairFinder.addSpecifiedFiles(["mshtml.dll"]) 42 | 43 | """ 44 | Dispatch routine 45 | """ 46 | def run(self): 47 | Logger.log("Waiting for task....") 48 | while True: 49 | command = self.getCommand() 50 | if not self.__busy and isinstance(command,dict): 51 | print command 52 | #self.__busy = True 53 | #dispatch command 54 | self.__handlers[command["command"]](command["params"]) 55 | 56 | time.sleep(1) 57 | 58 | def getCommand(self): 59 | try: 60 | data = urllib.urlencode( {"id": self.getAgentID()} ) 61 | result = urllib2.urlopen("%s/Command/getCommand" % Config.HOST, data).read() 62 | return json.loads(result) 63 | except Exception as e: 64 | return [] 65 | 66 | 67 | """ 68 | Handlers 69 | """ 70 | def __getTask(self,task_name): 71 | task = [] 72 | try: 73 | Logger.remoteLog("Starting working on task : ===[[ %s ]]===" % task_name,task_name) 74 | data = urllib.urlencode( {"agent_id": self.getAgentID(), 75 | "task_name" : task_name 76 | } ) 77 | result = urllib2.urlopen("%s/Task/getTaskByName" % Config.HOST, data).read() 78 | task = json.loads(result) 79 | #depends on product type launch different module to handle this pair of patches 80 | module = self.__modules[task["product"]]; 81 | module.initialize(Config.WORK_DIR,task) 82 | module.run() 83 | except Exception as e: 84 | print e.message 85 | print traceback.print_exc() 86 | 87 | def __unpack(self,params): 88 | try: 89 | params = json.loads(params) 90 | #get file objects 91 | if params.has_key("newID"): 92 | #action for new files package 93 | data = urllib.urlencode( {"id": params["newID"], 94 | "task_name" : params["task_name"] 95 | } ) 96 | result = urllib2.urlopen("%s/Storage/getFileByIdAPI" % Config.HOST, data).read() 97 | newFile = json.loads(result) 98 | #time for unpacking 99 | unpacker = Unpacker() 100 | dir = os.path.split(newFile["filePath"])[0] 101 | unpacker.unpack(newFile["filePath"],dir,params["type"]) 102 | 103 | if params.has_key("oldID"): 104 | #action for new files package 105 | data = urllib.urlencode( {"id": params["oldID"], 106 | "task_name" : params["task_name"] 107 | } ) 108 | result = urllib2.urlopen("%s/Storage/getFileByIdAPI" % Config.HOST, data).read() 109 | oldFile = json.loads(result) 110 | #time for unpacking 111 | unpacker = Unpacker() 112 | dir = os.path.split(oldFile["filePath"])[0] 113 | unpacker.unpack(oldFile["filePath"],dir,params["type"]) 114 | 115 | #let's re-scan files dir and save them again 116 | pairFinder = PairFinder() 117 | newDir = self.getFilesDir(params["task_name"],"new") 118 | oldDir = self.getFilesDir(params["task_name"],"old") 119 | pairFinder.collectFiles(newDir,oldDir) 120 | self.sendFileList(params["task_name"],pairFinder.getFiles()) 121 | 122 | except Exception as e: 123 | print e.message 124 | 125 | def __diffFiles(self,id): 126 | data = urllib.urlencode( {"id": id} ) 127 | result = urllib2.urlopen("%s/Diff/getDiff" % Config.HOST, data).read() 128 | diff = json.loads(result) 129 | Logger.remoteLog("Start diffing : %s" % diff["diff_name"],diff["task_name"]) 130 | 131 | binDiffer = Bindiffer(self.getTaskDir(diff["task_name"])) 132 | Logger.remoteLog("Create first IDB for : %s" % diff["newID"]["filePath"],diff["task_name"]) 133 | newIDB = binDiffer.createIDB(diff["newID"]["filePath"]) 134 | Logger.remoteLog("Create second IDB for : %s" % diff["oldID"]["filePath"],diff["task_name"]) 135 | oldIDB = binDiffer.createIDB(diff["oldID"]["filePath"]) 136 | #run BinDiff 137 | Logger.remoteLog("Run Zynamics BinDiff engine",diff["task_name"]) 138 | binDiffer.runBinDiff(newIDB,oldIDB) 139 | result = binDiffer.getResult() 140 | self.sendDiffResult(diff["task_name"],id,result); 141 | #Logger.remoteLog("Run AutoDiff.py engine",diff["task_name"]) 142 | #autoDiffEngine = AutoDiff() 143 | #autoDiffEngine.run(newIDB,oldIDB,binDiffer.getBinDiffFilePath()) 144 | #self.sendDiffResult(diff["task_name"],id,result); 145 | Logger.remoteLog("Diffing is DONE",diff["task_name"]) 146 | 147 | def __nop(self,params): 148 | pass 149 | 150 | """ 151 | Helpers 152 | """ 153 | def getAgentID(self): 154 | return os.getenv("COMPUTERNAME") 155 | 156 | def getTaskDir(self,task_name): 157 | return os.path.join(Config.WORK_DIR,task_name) 158 | 159 | def getFilesDir(self,task_name,name): 160 | return os.path.join(self.getTaskDir(task_name),name) 161 | 162 | def sendFileList(self,task_name,files): 163 | try: 164 | #just add task_name == task_id to files 165 | print "sendFile" 166 | postData = {} 167 | postData["task_name"] = task_name 168 | postData["files"] = json.dumps(files) 169 | postData = urllib.urlencode( postData ) 170 | urllib2.urlopen("%s/Storage/saveFilesList" % Config.HOST, postData) 171 | except Exception as e: 172 | print e.message 173 | 174 | def sendDiffResult(self,task_name,diff_id,result): 175 | postData = {"id": diff_id, 176 | "result": result, 177 | "task_name" : task_name 178 | } 179 | try: 180 | postData = urllib.urlencode(postData) 181 | urllib2.urlopen("%s/Diff/saveResults" % Config.HOST, postData) 182 | except Exception as e: 183 | print e.message 184 | 185 | if __name__ == "__main__": 186 | Logger.log("Launching agent") 187 | agent = CAgent() 188 | agent.start() -------------------------------------------------------------------------------- /agent.pyproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | 2.0 6 | {cd435f2f-4ff1-4336-9b1a-f8669596c4dc} 7 | . 8 | agent.py 9 | 10 | 11 | . 12 | . 13 | agent 14 | agent 15 | 16 | 17 | true 18 | false 19 | 20 | 21 | true 22 | false 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | Code 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | Code 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | Content 57 | 58 | 59 | Content 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /bin/MsiX.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/bin/MsiX.exe -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | class Config(object): 2 | 3 | HOST = "http://autodiff.localdomain.com:7777" 4 | AGENT_LOCATION = r"t:\projects\Cisco\Code\AutoDiff\AutoDiff\agent" 5 | WORK_DIR = r"t:\tmp" 6 | DEBUG = False 7 | IDA_PATH = r"d:\IDA_6.6\idaq.exe" 8 | BINDIFF_PLUGIN = r"d:\IDA_6.6\plugins\zynamics_bindiff_4_0.plw" 9 | AUTOIT_PATH = "c:\\Program Files (x86)\\AutoIt3\\AutoIt3_x64.exe" 10 | AUTODIFF_PATH = r"t:\projects\Cisco\Code\AutoDiff\AutoDiff\AutoDiff\AutoDiff.py" -------------------------------------------------------------------------------- /config.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/config.pyc -------------------------------------------------------------------------------- /logger.py: -------------------------------------------------------------------------------- 1 | import win32console 2 | import urllib2 3 | import urllib 4 | #TODO add somewhere free console 5 | 6 | class Logger(object): 7 | 8 | """ 9 | Available logging modes 10 | """ 11 | NONE = -1 12 | CONSOLE = 0 13 | FILE = 1 14 | BOTH = 2 15 | CMD = 3 16 | REMOTE = 4 17 | 18 | def __init__(self): 19 | pass 20 | 21 | @classmethod 22 | def init(cls,type = NONE): 23 | 24 | cls.__handlers = {cls.NONE : cls.__noneHandler, 25 | cls.CONSOLE : cls.__consoleHandler, 26 | cls.CMD : cls.__cmdHandler, 27 | cls.FILE : cls.__fileHandler 28 | } 29 | 30 | cls.__handler = cls.__handlers[type] 31 | cls.__cmdBuffer = None 32 | cls.__logFile = None 33 | cls.__logUrl = None 34 | pass 35 | 36 | @classmethod 37 | def log(cls,msg): 38 | msg += "\n" 39 | cls.__handler(msg) 40 | pass 41 | 42 | @classmethod 43 | def remoteLog(cls,msg,task_name): 44 | msg += "\n" 45 | if cls.__logUrl == None: 46 | cls.__consoleHandler(msg) 47 | else: 48 | formData = urllib.urlencode({"data":msg, "task_name" : task_name}) 49 | urllib2.urlopen(cls.__logUrl,formData) 50 | 51 | @classmethod 52 | def setLoggerType(cls,type): 53 | cls.__handler = cls.__handlers[type] 54 | 55 | @classmethod 56 | def setLogFile(cls,logFile): 57 | cls.__logFile = logFile 58 | @classmethod 59 | def setLogUrl(cls,url): 60 | cls.__logUrl = url 61 | 62 | """ 63 | Handlers 64 | """ 65 | @classmethod 66 | def __noneHandler(cls,msg): 67 | pass 68 | 69 | @classmethod 70 | def __consoleHandler(cls,msg): 71 | print msg 72 | 73 | @classmethod 74 | def __cmdHandler(cls,msg): 75 | if cls.__cmdBuffer == None: 76 | win32console.AllocConsole() 77 | cls.__cmdBuffer = win32console.CreateConsoleScreenBuffer() 78 | cls.__cmdBuffer.SetConsoleActiveScreenBuffer() 79 | cls.__cmdBuffer.WriteConsole(msg) 80 | 81 | @classmethod 82 | def __fileHandler(cls,msg): 83 | if cls.__logFile == None: 84 | cls.__logFile = "log.txt" 85 | with open(cls.__logFile,'a+') as f: 86 | f.write(msg) -------------------------------------------------------------------------------- /logger.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewall/AutoDiffAgent/7715bcbf99e5f3d66f53cb324bbd7cbb962a9a9b/logger.pyc --------------------------------------------------------------------------------