Guest User

Untitled

a guest
Oct 16th, 2018
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.07 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """ peEvade
  4.  
  5. TEMPLATE Description
  6.  
  7. Author: marpie (marpie@a12d404.net)
  8.  
  9. Last Update: 20120531
  10. Created: 20120530
  11.  
  12. """
  13. # Imports
  14. import struct
  15. import os.path
  16.  
  17.  
  18. # Version Information
  19. __version__ = "0.0.1"
  20. __program__ = "peEvade v" + __version__
  21. __author__ = "marpie"
  22. __email__ = "marpie+peEvade@a12d404.net"
  23. __license__ = "BSD License"
  24. __copyright__ = "Copyright 2011, a12d404.net"
  25. __status__ = "Prototype" # ("Prototype", "Development", "Testing", "Production")
  26.  
  27. #SCRIPT_PATH = os.path.dirname( os.path.realpath( __file__ ) )
  28.  
  29.  
  30. POINTER_SIZE = 4
  31.  
  32. IMAGE_ORDINAL_FLAG_64 = 0x8000000000000000
  33. IMAGE_ORDINAL_FLAG_32 = 0x80000000
  34.  
  35. IMAGE_DOS_SIGNATURE = 0x5A4D # MZ
  36. IMAGE_NT_SIGNATURE = 0x00004550 # PE00
  37.  
  38. IMAGE_DIRECTORY_ENTRY_EXPORT = 0
  39. IMAGE_DIRECTORY_ENTRY_IMPORT = 1
  40. IMAGE_DIRECTORY_ENTRY_RESOURCE = 2
  41. IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3
  42. IMAGE_DIRECTORY_ENTRY_SECURITY = 4
  43. IMAGE_DIRECTORY_ENTRY_BASERELOC = 5
  44. IMAGE_DIRECTORY_ENTRY_DEBUG = 6
  45. IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7
  46. IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8
  47. IMAGE_DIRECTORY_ENTRY_TLS = 9
  48. IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10
  49. IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11
  50. IMAGE_DIRECTORY_ENTRY_IAT = 12
  51.  
  52.  
  53. #############################################################################
  54. # Helper functions
  55.  
  56.  
  57. def getString(data):
  58. res = ""
  59. pos = 0
  60. while ord(data[pos]) <> 0x00:
  61. res += data[pos]
  62. pos += 1
  63. return res
  64.  
  65.  
  66. #############################################################################
  67. # Windows DEFs
  68.  
  69. class IMAGE_DOS_HEADER(object):
  70. def __init__(self, raw_data):
  71. self.e_magic, \
  72. self.e_cblp, \
  73. self.e_cp, \
  74. self.e_crlc, \
  75. self.e_cparhdr, \
  76. self.e_minalloc, \
  77. self.e_maxalloc, \
  78. self.e_ss, \
  79. self.e_sp, \
  80. self.e_csum, \
  81. self.e_ip, \
  82. self.e_cs, \
  83. self.e_lfarlc, \
  84. self.e_ovno = struct.unpack('<HHHHHHHHHHHHHH', raw_data[:28])
  85.  
  86. from_pos = struct.calcsize('<HHHHHHHHHHHHHH')+8
  87. to_pos = from_pos+struct.calcsize('<HH')
  88.  
  89. self.e_oemid, self.e_oeminfo = struct.unpack('<HH', raw_data[from_pos:to_pos])
  90.  
  91. from_pos = to_pos + 20
  92. to_pos = from_pos + struct.calcsize('<L')
  93. self.e_lfanew = struct.unpack('<L', raw_data[from_pos:to_pos])[0]
  94. self.__size = to_pos+4
  95.  
  96. def size(self):
  97. return self.__size
  98.  
  99. def valid(self):
  100. return self.e_magic == IMAGE_DOS_SIGNATURE
  101.  
  102.  
  103. class IMAGE_FILE_HEADER(object):
  104. HDR_DEF = r'<HHLLLHH'
  105. def __init__(self, raw_data):
  106. self.__size = struct.calcsize(self.HDR_DEF)
  107. self.Machine, \
  108. self.NumberOfSections, \
  109. self.TimeDateStamp, \
  110. self.PointerToSymbolTable, \
  111. self.NumberOfSymbols, \
  112. self.SizeOfOptionalHeader, \
  113. self.Characteristics = struct.unpack(self.HDR_DEF, raw_data[:self.__size])
  114.  
  115. def size(self):
  116. return self.__size
  117.  
  118.  
  119. class IMAGE_DATA_DIRECTORY(object):
  120. SIZE = 8
  121. def __init__(self, raw_data):
  122. self.VirtualAddress, self.Size = struct.unpack('<LL', raw_data[:self.SIZE])
  123.  
  124. def size(self):
  125. return self.SIZE
  126.  
  127.  
  128. class IMAGE_OPTIONAL_HEADER(object):
  129. HDR_DEF = r'<HBBLLLLLLLLLHHHHHHLLLLHHLLLLLL'
  130. def __init__(self, raw_data):
  131. self.__size = struct.calcsize(self.HDR_DEF)
  132. self.Magic, \
  133. self.MajorLinkerVersion, \
  134. self.MinorLinkerVersion, \
  135. self.SizeOfCode, \
  136. self.SizeOfInitializedData, \
  137. self.SizeOfUninitializedData, \
  138. self.AddressOfEntryPoint, \
  139. self.BaseOfCode, \
  140. self.BaseOfData, \
  141. self.ImageBase, \
  142. self.SectionAlignment, \
  143. self.FileAlignment, \
  144. self.MajorOperatingSystemVersion, \
  145. self.MinorOperatingSystemVersion, \
  146. self.MajorImageVersion, \
  147. self.MinorImageVersion, \
  148. self.MajorSubsystemVersion, \
  149. self.MinorSubsystemVersion, \
  150. self.Win32VersionValue, \
  151. self.SizeOfImage, \
  152. self.SizeOfHeaders, \
  153. self.CheckSum, \
  154. self.Subsystem, \
  155. self.DllCharacteristics, \
  156. self.SizeOfStackReserve, \
  157. self.SizeOfStackCommit, \
  158. self.SizeOfHeapReserve, \
  159. self.SizeOfHeapCommit, \
  160. self.LoaderFlags, \
  161. self.NumberOfRvaAndSizes = struct.unpack(self.HDR_DEF, raw_data[:self.__size])
  162. self.DataDirectory = []
  163. for i in xrange(0, self.NumberOfRvaAndSizes):
  164. self.DataDirectory.append(IMAGE_DATA_DIRECTORY(raw_data[self.__size:]))
  165. self.__size += 8
  166.  
  167. def size(self):
  168. return self.__size
  169.  
  170. def getDataDirectory(self, directory_idx):
  171. if len(self.DataDirectory) < directory_idx:
  172. return None
  173. return self.DataDirectory[directory_idx]
  174.  
  175.  
  176. class IMAGE_NT_HEADERS(object):
  177. def __init__(self, raw_data):
  178. self.Signature = struct.unpack('<L', raw_data[:4])[0]
  179. self.FileHeader = IMAGE_FILE_HEADER(raw_data[4:])
  180. self.OptionalHeader = IMAGE_OPTIONAL_HEADER(raw_data[self.FileHeader.size()+4:])
  181. self.__size = 4+self.FileHeader.size()+self.OptionalHeader.size()
  182.  
  183. def size(self):
  184. return self.__size
  185.  
  186. def valid(self):
  187. return (self.Signature == IMAGE_NT_SIGNATURE) and \
  188. (self.OptionalHeader.size() == self.FileHeader.SizeOfOptionalHeader)
  189.  
  190.  
  191. class IMAGE_IMPORT_DESCRIPTOR(object):
  192. HDR_DEF = r'<LLLLL'
  193. def __init__(self, raw_data):
  194. self.__size = struct.calcsize(self.HDR_DEF)
  195. self.Characteristics, \
  196. self.TimeDateStamp, \
  197. self.ForwarderChain, \
  198. self.Name, \
  199. self.FirstThunk = struct.unpack(self.HDR_DEF, raw_data[:self.__size])
  200. self.OriginalFirstThunk = self.Characteristics
  201.  
  202. def size(self):
  203. return self.__size
  204.  
  205.  
  206. class IMAGE_IMPORT_BY_NAME(object):
  207. def __init__(self, raw_data):
  208. self.Hint = struct.unpack('<H', raw_data[:2])
  209. self.Name = getString(raw_data[2:])
  210.  
  211.  
  212. class IMAGE_THUNK_DATA(object):
  213. def __init__(self, raw_data):
  214. self.__size = 4
  215. self.ForwarderString = struct.unpack('<L', raw_data[:self.__size])[0]
  216. self.Function = self.ForwarderString
  217. self.Ordinal = self.ForwarderString
  218. self.AddressOfData = self.ForwarderString
  219.  
  220.  
  221. class IMAGE_SECTION_HEADER(object):
  222. def __init__(self, raw_data, rawIndex):
  223. self.Name = getString(raw_data[:8])
  224. self.rawIndex = rawIndex
  225. self.__size = struct.calcsize('<LLLLLLHHL')+8
  226. self.PhysicalAddress, \
  227. self.VirtualAddress, \
  228. self.SizeOfRawData, \
  229. self.PointerToRawData, \
  230. self.PointerToRelocations, \
  231. self.PointerToLinenumbers, \
  232. self.NumberOfRelocations, \
  233. self.NumberOfLinenumbers, \
  234. self.Characteristics = struct.unpack('<LLLLLLHHL', raw_data[8:self.__size])
  235. self.VirtualSize = self.PhysicalAddress
  236.  
  237. def size(self):
  238. return self.__size
  239.  
  240.  
  241. #############################################################################
  242. # PE file format parsing classes
  243.  
  244.  
  245. class Lib(object):
  246. """ Lib represents one PE-Import-Dictionary-Entry. """
  247. def __init__(self, pe, importDescriptor):
  248. self.__pe = pe
  249. self.__importDescriptor = importDescriptor
  250. self.name = getString(self.__pe.imageByRva(importDescriptor.Name))
  251. self.functions = []
  252. for function in self.__parseFunctions():
  253. self.functions.append(function)
  254.  
  255. def __repr__(self):
  256. return self.__str__()
  257.  
  258. def __str__(self):
  259. fmtd = ""
  260. for func in self.functions:
  261. if type(func) == str:
  262. fmtd += "\t" + func + "\n"
  263. else:
  264. fmtd += "\tOrdinal: " + str(func) + "\n"
  265. return "Library: " + self.name + "\n" + fmtd
  266.  
  267. def valid(self):
  268. return (self.__importDescriptor.Name != 0) and (self.name != "")
  269.  
  270. def __parseFunctions(self):
  271. ptrFirstThunk = self.__importDescriptor.FirstThunk
  272. ptrThunkRef = self.__importDescriptor.OriginalFirstThunk
  273. if ptrThunkRef == 0:
  274. ptrThunkRef = ptrFirstThunk
  275. while True:
  276. thunkRef = IMAGE_THUNK_DATA(self.__pe.imageByRva(ptrThunkRef))
  277. if thunkRef.AddressOfData == 0:
  278. break
  279.  
  280. if thunkRef.Ordinal & IMAGE_ORDINAL_FLAG_32:
  281. importName = thunkRef.Ordinal & 0xffff
  282. else:
  283. importName = IMAGE_IMPORT_BY_NAME(self.__pe.imageByRva(thunkRef.AddressOfData)).Name
  284. if not importName:
  285. break
  286. ptrFirstThunk += POINTER_SIZE
  287. ptrThunkRef += POINTER_SIZE
  288. yield importName
  289.  
  290.  
  291.  
  292. class PE(object):
  293. """
  294. PE implements all functions needed to parse the PE file format.
  295.  
  296. The implementation is *incomplete* and only written to parse
  297. the imports to generate the fasm template file.
  298.  
  299. """
  300. def __init__(self, raw_data):
  301. self.pe_image = raw_data
  302.  
  303. try:
  304. self.dos_hdr = IMAGE_DOS_HEADER(self.pe_image)
  305. self.pe_hdr = IMAGE_NT_HEADERS(self.pe_image[self.dos_hdr.e_lfanew:])
  306. except:
  307. raise TypeError
  308.  
  309. if not (self.dos_hdr.valid() and self.pe_hdr.valid()):
  310. raise TypeError
  311.  
  312. self.__sections = None
  313. self.__imports = None
  314.  
  315. def __iterateDescriptors(self, directory):
  316. adr = self.rva2ptr(directory.VirtualAddress)
  317. while True:
  318. importDescriptor = IMAGE_IMPORT_DESCRIPTOR(self.pe_image[adr:])
  319. if importDescriptor.Name == 0:
  320. break
  321. lib = Lib(self, importDescriptor)
  322. if not lib.valid():
  323. break
  324. yield lib
  325. adr += importDescriptor.size()
  326.  
  327. def parseSections(self):
  328. """ parseSections tries to parse all sections of the PE file. """
  329. if self.__sections != None:
  330. return self.__sections
  331. self.__sections = []
  332. ptr = self.dos_hdr.e_lfanew + self.pe_hdr.size()
  333. for idx in xrange(0, self.pe_hdr.FileHeader.NumberOfSections):
  334. section = IMAGE_SECTION_HEADER(self.pe_image[ptr:], ptr)
  335. if section.size() > 0:
  336. self.__sections.append(section)
  337. ptr += section.size()
  338. return self.__sections
  339.  
  340. def dumpSection(self, sectionName, fileName):
  341. section = None
  342. for iSection in self.__sections:
  343. if iSection.Name == sectionName:
  344. section = iSection
  345. if not section:
  346. return None
  347. with open(fileName, 'w') as f:
  348. f.write(self.imageByRva(section.VirtualAddress)[:section.SizeOfRawData])
  349. return True
  350.  
  351. def parseImports(self):
  352. """ parseImports builds a list of all static imports. """
  353. if self.__imports != None:
  354. return self.__imports
  355.  
  356. self.__imports = []
  357. directory = self.pe_hdr.OptionalHeader.getDataDirectory(IMAGE_DIRECTORY_ENTRY_IMPORT)
  358. if not directory:
  359. return None
  360. if not self.parseSections():
  361. return None
  362. if directory.VirtualAddress == 0:
  363. return None
  364. for lib in self.__iterateDescriptors(directory):
  365. self.__imports.append(lib)
  366. return self.__imports
  367.  
  368. def getCurrentSectionHeader(self, rva):
  369. """
  370. getCurrentSectionHeader returns the section that rva
  371. belongs to or None.
  372.  
  373. """
  374. for section in self.__sections:
  375. if (rva >= section.VirtualAddress) and \
  376. (rva < (section.VirtualAddress + section.VirtualSize)):
  377. return section
  378. return None
  379.  
  380. def imageByRva(self, rva):
  381. """
  382. imageByRva returns the PE-Image beginning at the file
  383. position that rva belongs to.
  384.  
  385. """
  386. ptr = self.rva2ptr(rva)
  387. if not ptr:
  388. return None
  389. return self.pe_image[ptr:]
  390.  
  391. def rva2ptr(self, rva):
  392. """
  393. rva2ptr returns the position in the PE-Image (on disk)
  394. that rva belongs to.
  395.  
  396. """
  397. sectionHeader = self.getCurrentSectionHeader(rva)
  398. if not sectionHeader:
  399. return None
  400. diff = sectionHeader.VirtualAddress - sectionHeader.PointerToRawData
  401. return rva-diff
  402.  
  403.  
  404. #############################################################################
  405. # fasm template
  406.  
  407. FASM_TEMPLATE = r"""format PE GUI 4.0 at 0x00200000
  408. entry start
  409.  
  410. include 'win32a.inc'
  411.  
  412. section '.code' code readable executable
  413.  
  414. code_start:
  415. file "code_section.bin"
  416.  
  417. proc start
  418. invoke MessageBoxA,0,_beginMsg,_caption,MB_ICONINFORMATION+MB_OK
  419. jmp code_start
  420. invoke MessageBoxA,0,_doneMsg,_caption,MB_ICONINFORMATION+MB_OK
  421. .exit:
  422. invoke ExitProcess, 0
  423.  
  424. .unreachable:
  425. jmp .exit
  426. %%fake_imports%%
  427.  
  428. endp
  429.  
  430. section '.data' data readable
  431.  
  432. _beginMsg db 'Start',0
  433. _doneMsg db 'Start',0
  434. _caption db 'peEvade TEMPLATE',0
  435.  
  436. section '.idata' import data readable
  437.  
  438. %%imports%%
  439.  
  440. """
  441.  
  442. class FasmSection(object):
  443. def __init__(self, name, attributes):
  444. self.name = name
  445. self.attributes = attributes
  446.  
  447. def __str__(self):
  448. return "section '" + self.name + "' " + ' '.join(self.attributes)
  449.  
  450. class FasmTemplate(object):
  451. def __init__(self):
  452. self.__libs = {}
  453. self.__sections = []
  454.  
  455. def addLib(self, lib):
  456. lib_name = os.path.splitext(os.path.basename(lib.name))[0].lower()
  457. self.__libs[lib_name] = lib
  458.  
  459. def addSection(self, name, attributes):
  460. self.__sections.append(FasmSection(name, attributes))
  461.  
  462. def __repr__(self):
  463. return str(self)
  464.  
  465. def __str__(self):
  466. fake_imports, imports = self.__prepareImports()
  467. template = FASM_TEMPLATE.replace("%%fake_imports%%", fake_imports)
  468. template = template.replace("%%imports%%", imports)
  469. return template
  470.  
  471. def __prepareImports(self):
  472. outStr = "\nlibrary "
  473. first = True
  474. for lib_name, lib in self.__libs.items():
  475. if not first:
  476. outStr += ",\\\n "
  477. else:
  478. first = False
  479. outStr += "%s,'%s'" % (lib_name, lib.name)
  480. outStr += "\n\n"
  481.  
  482. fake_imports = ""
  483. for lib_name, lib in self.__libs.items():
  484. outStr += "import " + lib_name
  485. for func in lib.functions:
  486. outStr += ",\\\n " + func + ",'" + func + "'"
  487. fake_imports += "\n invoke " + func
  488. outStr += "\n\n"
  489.  
  490. return (fake_imports, outStr,)
  491.  
  492.  
  493. #############################################################################
  494. # Main
  495.  
  496. def main(argv):
  497. with open(argv[1], 'rb') as f:
  498. pe_image = f.read()
  499.  
  500. template = FasmTemplate()
  501.  
  502. pe = PE(pe_image)
  503.  
  504. for lib in pe.parseImports():
  505. template.addLib(lib)
  506.  
  507. pe.dumpSection(".code", "code_section.bin")
  508.  
  509. print(template)
  510.  
  511. return True
  512.  
  513.  
  514. #############################################################################
  515.  
  516.  
  517. if __name__ == "__main__":
  518. import sys
  519. #print( __doc__ )
  520. sys.exit( not main( sys.argv ) )
Add Comment
Please, Sign In to add comment