Advertisement
opexxx

fint.py

Aug 18th, 2014
350
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.20 KB | None | 0 0
  1. #!/opt/local/bin/python
  2. # coding: utf-8
  3. """
  4. fint.py - v0.1 - 2012.03.15
  5. Author : Jan Goebel - goebel@pi-one.net
  6. Licence : GPL v2
  7. Example Usage:
  8. # To find an executable that was compiled on a certain date
  9. python fint.py -m /path/to/search/ --compileTime 2012:03:25 -f *.exe
  10. # To find files with a certain size in bytes +- a variation of 10 bytes
  11. python fint.py -m /path/to/search/ --size 8109 --sizeVariation 10
  12. """
  13. ############################################################################
  14. # General Information
  15. ############################################################################
  16. __author__ = "jan goebel (goebel@pi-one.net)"
  17. __version__ = "0.1"
  18. ############################################################################
  19. # Imports
  20. ############################################################################
  21. import sys
  22. import os
  23. import argparse
  24. import hashlib
  25. import fnmatch
  26. import time
  27. import struct
  28. ############################################################################
  29. class pefile:
  30. """
  31. read headers of a PE file
  32. """
  33. def __init__(self, fn):
  34. self.filename = fn
  35. def checkFile(self):
  36. self.filecontent = None
  37. self.filelength = None
  38. self.readFileContent()
  39. self.peHeader = None
  40. if self.filelength>64:
  41. self.msdosDict = {}
  42. self.msdosHeader = self.filecontent[:64]
  43. if self.msdosHeader[0:2]==b'MZ':
  44. self.readMSDOSHeader(self.msdosHeader)
  45. else:
  46. #print("file too small")
  47. return False
  48. try:
  49. PESignature = self.filecontent[self.msdosDict['15_pPEHeader']:self.msdosDict['15_pPEHeader']+4]
  50. except:
  51. #print("no PE file!")
  52. return False
  53. else:
  54. if PESignature == '\x50\x45\x00\x00':
  55. self.peHeader = self.filecontent[self.msdosDict['15_pPEHeader']+4:self.msdosDict['15_pPEHeader']+4+20]
  56. self.peDict = {}
  57. self.readPEHeader(self.peHeader)
  58. self.peoptDict = {}
  59. self.peOptionalHeader = self.filecontent[self.msdosDict['15_pPEHeader']+4+20:self.msdosDict['15_pPEHeader']+4+20+self.peDict['06_sizeoptheader']]
  60. self.readPEOptHeader(self.peOptionalHeader)
  61. return True
  62. else:
  63. return False
  64. def readFileContent(self):
  65. """
  66. read entire file
  67. """
  68. fp = open(self.filename, 'rb')
  69. self.filecontent = fp.read()
  70. fp.close()
  71. self.filelength = len(self.filecontent)
  72. def readPEOptHeader(self, peOptionalHeader):
  73. self.peoptDict['01_optionalHeaderMagic'] = peOptionalHeader[0:2]
  74. if self.peoptDict['01_optionalHeaderMagic']=='\x0b\x01':
  75. self.peoptDict['01_optionalHeaderMagic']='PE32'
  76. elif self.peoptDict['01_optionalHeaderMagic']=='\x0b\x02':
  77. self.peoptDict['01_optionalHeaderMagic']='PE32+'
  78. self.peoptDict['02_majorlnkv'] = struct.unpack('b', peOptionalHeader[2])[0]
  79. self.peoptDict['03_minorlnkv'] = struct.unpack('b', peOptionalHeader[3])[0]
  80. self.peoptDict['04_codesize'] = struct.unpack('i', peOptionalHeader[4:8])[0]
  81. self.peoptDict['05_initsize'] = struct.unpack('i', peOptionalHeader[8:12])[0]
  82. self.peoptDict['06_uninitsize'] = struct.unpack('i', peOptionalHeader[12:16])[0]
  83. self.peoptDict['07_entrypoint'] = struct.unpack('i', peOptionalHeader[16:20])[0]
  84. self.peoptDict['08_baseofcode'] = struct.unpack('i', peOptionalHeader[20:24])[0]
  85. self.peoptDict['09_baseofdata'] = struct.unpack('i', peOptionalHeader[24:28])[0]
  86. self.peoptDict['10_imagebase'] = struct.unpack('i', peOptionalHeader[28:32])[0]
  87. self.peoptDict['11_sectionalignment'] = struct.unpack('i', peOptionalHeader[32:36])[0]
  88. self.peoptDict['12_filealignment'] = struct.unpack('I', peOptionalHeader[36:40])[0]
  89. self.peoptDict['13_majorop'] = struct.unpack('h', peOptionalHeader[40:42])[0]
  90. self.peoptDict['14_minorop'] = struct.unpack('h', peOptionalHeader[42:44])[0]
  91. self.peoptDict['15_majorimage'] = struct.unpack('h', peOptionalHeader[44:46])[0]
  92. self.peoptDict['16_minorimage'] = struct.unpack('h', peOptionalHeader[46:48])[0]
  93. self.peoptDict['17_majorsubver'] = struct.unpack('h', peOptionalHeader[48:50])[0]
  94. self.peoptDict['18_minorsubver'] = struct.unpack('h', peOptionalHeader[50:52])[0]
  95. self.peoptDict['19_win32verval'] = struct.unpack('i', peOptionalHeader[52:56])[0]
  96. self.peoptDict['20_sizeofimage'] = struct.unpack('i', peOptionalHeader[56:60])[0]
  97. self.peoptDict['21_sizeofheaders'] = struct.unpack('i', peOptionalHeader[60:64])[0]
  98. self.peoptDict['22_checksum'] = struct.unpack('i', peOptionalHeader[64:68])[0]
  99. self.peoptDict['23_subsystem'] = struct.unpack('h', peOptionalHeader[68:70])[0]
  100. self.peoptDict['24_DllCharacteristics'] = bin(int(hex(struct.unpack('h', peOptionalHeader[70:72])[0]), 16))[2:]
  101. self.peoptDict['25_SizeOfStackReserve'] = struct.unpack('i', peOptionalHeader[72:76])[0]
  102. self.peoptDict['26_SizeOfStackCommit'] = struct.unpack('i', peOptionalHeader[76:80])[0]
  103. self.peoptDict['27_SizeOfHeapReserve'] = struct.unpack('i', peOptionalHeader[80:84])[0]
  104. self.peoptDict['28_SizeOfHeapCommit'] = struct.unpack('i', peOptionalHeader[84:88])[0]
  105. self.peoptDict['29_loaderflags'] = struct.unpack('I', peOptionalHeader[88:92])[0]
  106. self.peoptDict['30_NumberOfRvaAndSizes'] = struct.unpack('I', peOptionalHeader[92:96])[0]
  107. self.peoptDict['31_imageDataDirectory'] = {}
  108. def readPEHeader(self, peHeader):
  109. self.peDict['01_machine'] = peHeader[0:2].encode('hex')
  110. if self.peDict['01_machine'] == '4c01':
  111. self.peDict['01_machine'] = "i386"
  112. self.peDict['02_numberofsections'] = struct.unpack('h', peHeader[2:4])[0]
  113. self.peDict['03_timedatestamp'] = struct.unpack('i', peHeader[4:8])[0]
  114. self.peDict['04_pSymbolTable'] = struct.unpack('I', peHeader[8:12])[0]
  115. self.peDict['05_numSymbols'] = struct.unpack('I', peHeader[12:16])[0]
  116. self.peDict['06_sizeoptheader'] = struct.unpack('h', peHeader[16:18])[0]
  117. self.peDict['07_chars'] = bin(int(hex(struct.unpack('H', peHeader[18:20])[0]), 16))
  118. def readMSDOSHeader(self, msdosHeader):
  119. self.msdosDict['01_magicnumber'] = struct.unpack('H', msdosHeader[0:2])[0]
  120. self.msdosDict['02_bytesLastPage'] = struct.unpack('H', msdosHeader[2:4])[0]
  121. self.msdosDict['03_pagesInFile'] = struct.unpack('H', msdosHeader[4:6])[0]
  122. self.msdosDict['04_numRelocs'] = struct.unpack('H', msdosHeader[6:8])[0]
  123. self.msdosDict['05_paragraphs'] = struct.unpack('H', msdosHeader[8:10])[0]
  124. self.msdosDict['06_minpara'] = struct.unpack('H', msdosHeader[10:12])[0]
  125. self.msdosDict['07_maxpara'] = struct.unpack('H', msdosHeader[12:14])[0]
  126. self.msdosDict['08_stackmod'] = struct.unpack('H', msdosHeader[14:16])[0]
  127. self.msdosDict['09_spregister'] = struct.unpack('H', msdosHeader[16:18])[0]
  128. self.msdosDict['10_chksum'] = struct.unpack('H', msdosHeader[18:20])[0]
  129. self.msdosDict['11_ipregister'] = struct.unpack('H', msdosHeader[20:22])[0]
  130. self.msdosDict['12_codemod'] = struct.unpack('H', msdosHeader[22:24])[0]
  131. self.msdosDict['13_offsetfirstreloc'] = struct.unpack('H', msdosHeader[24:26])[0]
  132. self.msdosDict['14_overlaynum'] = struct.unpack('H', msdosHeader[26:28])[0]
  133. self.msdosDict['15_pPEHeader'] = struct.unpack('I', msdosHeader[60:64])[0]
  134. ############################################################################
  135. class fparser:
  136. """
  137. parse filesystem and find certain files
  138. """
  139. def __init__(self):
  140. self.running = True
  141. def quit(self):
  142. self.running = False
  143. def run(self, args):
  144. startDir = args.mountpoint
  145. print "Starting at directory: %s" % (startDir)
  146. depth = int(args.depth)
  147. if depth != -1:
  148. print "Directory depth: %s" % (depth)
  149. else:
  150. print "Directory depth: %s (unlimited)" % (depth)
  151. fileFilter = args.filter
  152. print "Filtering files: %s" % (fileFilter)
  153. resultSet = self.search(startDir, depth, fileFilter, args)
  154. return None
  155. def processFile(self, root, fn, md5):
  156. cpath = os.path.join(root, fn)
  157. h = hashlib.sha256()
  158. with open(cpath, 'rb') as f:
  159. for chunk in iter(lambda: f.read(8192), ''):
  160. h.update(chunk)
  161. sha256 = h.hexdigest()
  162. extension = os.path.splitext(cpath)[1][1:]
  163. stats = os.stat(cpath)
  164. size = int(stats.st_size)
  165. atime = int(stats.st_atime)
  166. mtime = int(stats.st_mtime)
  167. ctime = int(stats.st_ctime)
  168. pe = pefile(cpath)
  169. peRes = pe.checkFile()
  170. if peRes:
  171. compileTime = pe.peDict['03_timedatestamp']
  172. else:
  173. compileTime = 0
  174. return [root, fn, extension, size, md5, sha256, atime, mtime, ctime, compileTime]
  175. def checkItem(self, item, args):
  176. resVal = False
  177. """ consider size only """
  178. if args.size!=0 and args.md5=='None' and args.compileTime=='None':
  179. if args.size == item[3] or (args.size-args.sizeVariation <= item[3] <= args.size+args.sizeVariation):
  180. resVal = True
  181. """ consider size and md5 """
  182. if args.size!=0 and args.md5!='None' and args.compileTime=='None':
  183. if args.size == item[3] or (args.size-args.sizeVariation <= item[3] <= args.size+args.sizeVariation) and args.md5 == item[4]:
  184. resVal = True
  185. """ consider size and md5 and compileTime """
  186. if args.size!=0 and args.md5!='None' and args.compileTime!='None':
  187. tobj = time.gmtime(item[9])
  188. cobj = args.compileTime.split(':')
  189. if args.size == item[3] or (args.size-args.sizeVariation <= item[3] <= args.size+args.sizeVariation) and args.md5 == item[4] and int(tobj.tm_year) == int(cobj[0]) and int(tobj.tm_mon) == int(cobj[1]) and int(tobj.tm_mday) == int(cobj[2]):
  190. resVal = True
  191. """ consider size and compileTime """
  192. if args.size!=0 and args.md5=='None' and args.compileTime!='None':
  193. tobj = time.gmtime(item[9])
  194. cobj = args.compileTime.split(':')
  195. if args.size == item[3] or (args.size-args.sizeVariation <= item[3] <= args.size+args.sizeVariation) and int(tobj.tm_year) == int(cobj[0]) and int(tobj.tm_mon) == int(cobj[1]) and int(tobj.tm_mday) == int(cobj[2]):
  196. resVal = True
  197. """ consider md5 and compileTime """
  198. if args.size==0 and args.md5=='None' and args.compileTime!='None':
  199. tobj = time.gmtime(item[9])
  200. cobj = args.compileTime.split(':')
  201. if int(tobj.tm_year) == int(cobj[0]) and int(tobj.tm_mon) == int(cobj[1]) and int(tobj.tm_mday) == int(cobj[2]):
  202. resVal = True
  203. """ consider compileTime only """
  204. if args.size==0 and args.md5=='None' and args.compileTime!='None':
  205. tobj = time.gmtime(item[9])
  206. cobj = args.compileTime.split(':')
  207. if int(tobj.tm_year) == int(cobj[0]) and int(tobj.tm_mon) == int(cobj[1]) and int(tobj.tm_mday) == int(cobj[2]):
  208. resVal = True
  209. """ consider compileYear only """
  210. if args.size==0 and args.md5=='None' and args.compileTime=='None' and args.compileYear!='None' and args.compileMonth=='None':
  211. tobj = time.gmtime(item[9])
  212. cobj = args.compileYear
  213. if int(tobj.tm_year) == int(cobj):
  214. resVal = True
  215. """ consider compileMonth only """
  216. if args.size==0 and args.md5=='None' and args.compileTime=='None' and args.compileYear=='None' and args.compileMonth!='None':
  217. tobj = time.gmtime(item[9])
  218. cobj = args.compileMonth
  219. if int(tobj.tm_mon) == int(cobj):
  220. resVal = True
  221. """ consider compileMonth and compileYear only """
  222. if args.size==0 and args.md5=='None' and args.compileTime=='None' and args.compileYear!='None' and args.compileMonth!='None':
  223. tobj = time.gmtime(item[9])
  224. if int(tobj.tm_mon) == int(args.compileMonth) and int(tobj.tm_year) == int(args.compileYear):
  225. resVal = True
  226. """ consider md5 only """
  227. if args.size==0 and args.md5!='None' and args.compileTime=='None' and args.compileMonth=='None':
  228. if args.md5 == item[4]:
  229. resVal = True
  230. """ no specific filters then display all """
  231. if args.size==0 and args.md5=='None' and args.compileTime=='None' and args.compileYear=='None' and args.compileMonth=='None':
  232. resVal = True
  233. return resVal
  234. def search(self, startDir, depth, fileFilter, args):
  235. """
  236. recursively traverse thru the filesystem
  237. """
  238. resultSet = []
  239. curDepth = 0
  240. startDepth = startDir.count(os.sep)
  241. for root, dirs, files in os.walk(startDir):
  242. if not self.running:
  243. break
  244. curDepth = root.count(os.sep) - startDepth
  245. if depth>=0 and curDepth>=depth:
  246. dirs[:] = []
  247. for fn in files:
  248. if fnmatch.fnmatch(fn, fileFilter):
  249. h = hashlib.md5()
  250. try:
  251. with open(os.path.join(root, fn),'rb') as f:
  252. for chunk in iter(lambda: f.read(8192), ''):
  253. h.update(chunk)
  254. fingerprint = h.hexdigest()
  255. except IOError, e:
  256. fingerprint = None
  257. #if fingerprint in hashList:
  258. item = self.processFile(root, fn, fingerprint)
  259. res = self.checkItem( item, args )
  260. if res:
  261. resultSet.append( item )
  262. ### path filename md5fingerprint
  263. print "\t %s" % (item)
  264. del h
  265. return resultSet
  266. ############################################################################
  267. if __name__ == '__main__':
  268. """ set working directory """
  269. workdir = sys.path[0]
  270. os.chdir(workdir)
  271. """ parse arguments """
  272. parser = argparse.ArgumentParser(description='find interesting files')
  273. parser.add_argument('-d', '--depth', type=int, default=-1, help='traverse directories to depth (default: no limit)')
  274. parser.add_argument('-m', '--mountpoint', required=True, help='starting directory of search')
  275. parser.add_argument('-f', '--filter', default='*.*', help='file filter ("*.*", "*.exe", ...)')
  276. parser.add_argument('-s', '--size', type=int, default=0, help='search for files of certain size (bytes)')
  277. parser.add_argument('--sizeVariation', type=int, default=0, help='file size may vary by certain number of bytes')
  278. parser.add_argument('--md5', default='None', help='search for files with md5 fingerprint')
  279. parser.add_argument('--compileTime', default='None', help='search for files compiled on date (year:month:day)')
  280. parser.add_argument('--compileYear', default='None', help='search for files compiled on year')
  281. parser.add_argument('--compileMonth', default='None', help='search for files compiled on month')
  282. args = parser.parse_args()
  283. """ set absolute search path """
  284. searchPath = os.path.abspath( args.mountpoint )
  285. if not os.path.exists(searchPath):
  286. print "mountpoint does not exist!"
  287. sys.exit(255)
  288. args.mountpoint = searchPath
  289. print args
  290. """ create parser """
  291. p = fparser()
  292. p.run(args)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement