"Fossies" - the Fresh Open Source Software Archive

Member "volatility-2.6.1/volatility/plugins/overlays/windows/pe_vtypes.py" (18 Dec 2018, 41579 Bytes) of package /linux/misc/volatility-2.6.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "pe_vtypes.py" see the Fossies "Dox" file reference documentation.

    1 # Volatility
    2 # Copyright (c) 2008-2013 Volatility Foundation
    3 #
    4 # This file is part of Volatility.
    5 #
    6 # Volatility is free software; you can redistribute it and/or modify
    7 # it under the terms of the GNU General Public License Version 2 as
    8 # published by the Free Software Foundation.  You may not use, modify or
    9 # distribute this program under any other version of the GNU General
   10 # Public License.
   11 #
   12 # Volatility is distributed in the hope that it will be useful,
   13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15 # GNU General Public License for more details.
   16 #
   17 # You should have received a copy of the GNU General Public License
   18 # along with Volatility.  If not, see <http://www.gnu.org/licenses/>.
   19 #
   20 
   21 import struct
   22 import volatility.exceptions as exceptions
   23 import volatility.obj as obj
   24 import volatility.debug as debug
   25 import volatility.addrspace as addrspace
   26 
   27 pe_vtypes = {
   28     '_IMAGE_EXPORT_DIRECTORY': [ 0x28, {
   29     'Base': [ 0x10, ['unsigned int']],
   30     'NumberOfFunctions': [ 0x14, ['unsigned int']],
   31     'NumberOfNames': [ 0x18, ['unsigned int']],
   32     'AddressOfFunctions': [ 0x1C, ['unsigned int']],
   33     'AddressOfNames': [ 0x20, ['unsigned int']],
   34     'AddressOfNameOrdinals': [ 0x24, ['unsigned int']],
   35     }],
   36     '_IMAGE_IMPORT_DESCRIPTOR': [ 0x14, {
   37     # 0 for terminating null import descriptor
   38     'OriginalFirstThunk': [ 0x0, ['unsigned int']],
   39     'TimeDateStamp': [ 0x4, ['unsigned int']],
   40     'ForwarderChain': [ 0x8, ['unsigned int']],
   41     'Name': [ 0xC, ['unsigned int']],
   42     # If bound this has actual addresses
   43     'FirstThunk': [ 0x10, ['unsigned int']],
   44     }],
   45     '_IMAGE_THUNK_DATA' : [ 0x4, {
   46     # Fake member for testing if the highest bit is set
   47     'OrdinalBit' : [ 0x0, ['BitField', dict(start_bit = 31, end_bit = 32)]],
   48     'Function' : [ 0x0, ['pointer', ['void']]],
   49     'Ordinal' : [ 0x0, ['unsigned long']],
   50     'AddressOfData' : [ 0x0, ['unsigned int']],
   51     'ForwarderString' : [ 0x0, ['unsigned int']],
   52     }],
   53     '_IMAGE_IMPORT_BY_NAME' : [ None, {
   54     'Hint' : [ 0x0, ['unsigned short']],
   55     'Name' : [ 0x2, ['String', dict(length = 128)]],
   56     }],
   57     '_IMAGE_RESOURCE_DIRECTORY' : [ 0x12, {
   58       'Characteristics' : [ 0x0, ['unsigned long']],
   59       'Timestamp' : [ 0x4, ['unsigned long']],
   60       'MajorVersion': [ 0x8, ['unsigned short']],
   61       'Minorversion': [ 0xa, ['unsigned short']],
   62       'NamedEntriesCount': [ 0xc, ['unsigned short']],
   63       'IdEntriesCount': [0xe, ['unsigned short']],
   64       'Entries': [0x10, ['array', lambda x: x.NamedEntriesCount + x.IdEntriesCount, ['_IMAGE_RESOURCE_DIRECTORY_ENTRY']]],
   65     } ],
   66     '_IMAGE_RESOURCE_DIRECTORY_ENTRY': [0x8, {
   67       'Name' : [ 0x0, ['unsigned long']],
   68       'DataOffset' : [ 0x4, ['unsigned long']],
   69     } ],
   70     '_IMAGE_RESOURCE_DATA_ENTRY' : [0x10, {
   71       'DataOffset' : [0x0, ['unsigned long']],
   72       'Size' : [0x4, ['unsigned long']],
   73       'CodePage' : [0x8, ['unsigned long']],
   74       'Reserved' : [0xc, ['unsigned long']],
   75     } ],
   76     '_IMAGE_RESOURCE_DIR_STRING_U' : [0x4, {
   77       'Length': [0x0, ['unsigned short']],
   78       'Value' : [0x2, ['array', lambda x: x.Length, ['unsigned short']]],
   79     } ],
   80     '_VS_VERSION_INFO' : [0x26, {
   81       'Length': [0x0, ['unsigned short']],
   82       'ValueLength': [0x2, ['unsigned short']],
   83       'Type': [0x4, ['unsigned short']],
   84       'Key': [0x6, ['array', len("VS_VERSION_INFO "), ['unsigned short']]],
   85       'FileInfo': [lambda x: (((x.Key.obj_offset + x.Key.size() + 3) / 4) * 4), ['_VS_FIXEDFILEINFO']],
   86     } ],
   87     'VerStruct' : [0x26, {
   88       'Length': [0x0, ['unsigned short']],
   89       'ValueLength': [0x2, ['unsigned short']],
   90       'Type': [0x4, ['unsigned short']],
   91       'Key': [0x6, ['array', 260, ['unsigned short']]],
   92     } ],
   93     '_VS_FIXEDFILEINFO': [0x34, {
   94       'Signature': [0x0, ['unsigned long']],
   95       'StructVer': [0x4, ['unsigned long']],
   96       'FileVerMS': [0x8, ['unsigned long']],
   97       'FileVerLS': [0xC, ['unsigned long']],
   98       'ProdVerMS': [0x10, ['unsigned long']],
   99       'ProdVerLS': [0x14, ['unsigned long']],
  100       'FileFlagsMask': [0x18, ['unsigned long']],
  101       'FileFlags': [0x1C, ['unsigned long']],
  102       'FileOS': [0x20, ['Enumeration', {'choices': {
  103         0x0: 'Unknown',
  104         0x10000: 'DOS',
  105         0x20000: 'OS/2 16-bit',
  106         0x30000: 'OS/2 32-bit',
  107         0x40000: 'Windows NT',
  108         0x1: 'Windows 16-bit',
  109         0x2: 'Presentation Manager 16-bit',
  110         0x3: 'Presentation Manager 32-bit',
  111         0x4: 'Windows 32-bit',
  112         0x10001: 'Windows 16-bit running on DOS',
  113         0x10004: 'Windows 32-bit running on DOS',
  114         0x20002: 'Presentation Manager running on OS/2 (16-bit)',
  115         0x30003: 'Presentation Manager running on OS/2 (32-bit)',
  116         0x40004: 'Windows NT',
  117                                                       }} ]],
  118       'FileType': [0x24, ['Enumeration', {'choices': {
  119         0x0: 'Unknown',
  120         0x1: 'Application',
  121         0x2: 'Dynamic Link Library',
  122         0x3: 'Driver',
  123         0x4: 'Font',
  124         0x5: 'Virtual Device',
  125         0x7: 'Static Library',
  126                                                       }} ]],
  127       'FileSubType': [0x28, ['unsigned long']],
  128       'FileDate': [0x2C, ['WinTimeStamp']],
  129     } ],
  130     
  131   '_IMAGE_OPTIONAL_HEADER32' : [ 0xe0, {
  132     'Magic' : [ 0x0, ['unsigned short']],
  133     'MajorLinkerVersion' : [ 0x2, ['unsigned char']],
  134     'MinorLinkerVersion' : [ 0x3, ['unsigned char']],
  135     'SizeOfCode' : [ 0x4, ['unsigned long']],
  136     'SizeOfInitializedData' : [ 0x8, ['unsigned long']],
  137     'SizeOfUninitializedData' : [ 0xc, ['unsigned long']],
  138     'AddressOfEntryPoint' : [ 0x10, ['unsigned long']],
  139     'BaseOfCode' : [ 0x14, ['unsigned long']],
  140     'BaseOfData' : [ 0x18, ['unsigned long']],
  141     'ImageBase' : [ 0x1c, ['unsigned long']],
  142     'SectionAlignment' : [ 0x20, ['unsigned long']],
  143     'FileAlignment' : [ 0x24, ['unsigned long']],
  144     'MajorOperatingSystemVersion' : [ 0x28, ['unsigned short']],
  145     'MinorOperatingSystemVersion' : [ 0x2a, ['unsigned short']],
  146     'MajorImageVersion' : [ 0x2c, ['unsigned short']],
  147     'MinorImageVersion' : [ 0x2e, ['unsigned short']],
  148     'MajorSubsystemVersion' : [ 0x30, ['unsigned short']],
  149     'MinorSubsystemVersion' : [ 0x32, ['unsigned short']],
  150     'Win32VersionValue' : [ 0x34, ['unsigned long']],
  151     'SizeOfImage' : [ 0x38, ['unsigned long']],
  152     'SizeOfHeaders' : [ 0x3c, ['unsigned long']],
  153     'CheckSum' : [ 0x40, ['unsigned long']],
  154     'Subsystem' : [ 0x44, ['unsigned short']],
  155     'DllCharacteristics' : [ 0x46, ['unsigned short']],
  156     'SizeOfStackReserve' : [ 0x48, ['unsigned long']],
  157     'SizeOfStackCommit' : [ 0x4c, ['unsigned long']],
  158     'SizeOfHeapReserve' : [ 0x50, ['unsigned long']],
  159     'SizeOfHeapCommit' : [ 0x54, ['unsigned long']],
  160     'LoaderFlags' : [ 0x58, ['unsigned long']],
  161     'NumberOfRvaAndSizes' : [ 0x5c, ['unsigned long']],
  162     'DataDirectory' : [ 0x60, ['array', 16, ['_IMAGE_DATA_DIRECTORY']]],
  163     } ],
  164 }
  165 
  166 pe_vtypes_64 = {
  167     '_IMAGE_THUNK_DATA' : [ 0x8, {
  168     # Fake member for testing if the highest bit is set
  169     'OrdinalBit' : [ 0x0, ['BitField', dict(start_bit = 63, end_bit = 64)]],
  170     'Function' : [ 0x0, ['pointer64', ['void']]],
  171     'Ordinal' : [ 0x0, ['unsigned long long']],
  172     'AddressOfData' : [ 0x0, ['unsigned long long']],
  173     'ForwarderString' : [ 0x0, ['unsigned long long']],
  174     }],
  175 }
  176 
  177 resource_types = {
  178      'RT_CURSOR'       : 1,
  179      'RT_BITMAP'       : 2,
  180      'RT_ICON'         : 3,
  181      'RT_MENU'         : 4,
  182      'RT_DIALOG'       : 5,
  183      'RT_STRING'       : 6,
  184      'RT_FONTDIR'      : 7,
  185      'RT_FONT'         : 8,
  186      'RT_ACCELERATOR'  : 9,
  187      'RT_RCDATA'       : 10,
  188      'RT_MESSAGETABLE' : 11,
  189      'RT_GROUP_CURSOR' : 12,
  190      'RT_GROUP_ICON'   : 14,
  191      'RT_VERSION'      : 16,
  192      'RT_DLGINCLUDE'   : 17,
  193      'RT_PLUGPLAY'     : 19,
  194      'RT_VXD'          : 20,
  195      'RT_ANICURSOR'    : 21,
  196      'RT_ANIICON'      : 22,
  197      'RT_HTML'         : 23,
  198 }
  199 
  200 IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b
  201 IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
  202 
  203 class _IMAGE_EXPORT_DIRECTORY(obj.CType):
  204     """Class for PE export directory"""
  205 
  206     def valid(self, nt_header):
  207         """
  208         Check the sanity of export table fields.
  209 
  210         The RVAs cannot be larger than the module size. The function
  211         and name counts cannot be larger than 32K. 
  212         """
  213         try:
  214             return (self.AddressOfFunctions < nt_header.OptionalHeader.SizeOfImage and
  215                     self.AddressOfNameOrdinals < nt_header.OptionalHeader.SizeOfImage and
  216                     self.AddressOfNames < nt_header.OptionalHeader.SizeOfImage and
  217                     self.NumberOfFunctions < 0x7FFF and
  218                     self.NumberOfNames < 0x7FFF)
  219         except obj.InvalidOffsetError:
  220             return False
  221 
  222     def _name(self, name_rva):
  223         """
  224         Return a String object for the function name.
  225 
  226         Names are truncated at 128 characters although its possible 
  227         they may be longer. Thus, infrequently a function name will
  228         be missing some data. However, that's better than hard-coding
  229         a larger value which frequently causes us to cross page 
  230         boundaries and return a NoneObject anyway.  
  231         """
  232         return obj.Object("String",
  233                       offset = self.obj_parent.DllBase + name_rva,
  234                       vm = self.obj_native_vm, length = 128)
  235 
  236     def _exported_functions(self):
  237         """
  238         Generator for exported functions.
  239 
  240         @return: tuple (Ordinal, FunctionRVA, Name)
  241 
  242         Ordinal is an integer and should never be None. If the function 
  243         is forwarded, FunctionRVA is None. Otherwise, FunctionRVA is an
  244         RVA to the function's code (relative to module base). Name is a
  245         String containing the exported function's name. If the Name is 
  246         paged, it will be None. If the function is forwarded, Name is the
  247         forwarded function name including the DLL (ntdll.EtwLogTraceEvent). 
  248         """
  249 
  250         mod_base = self.obj_parent.DllBase
  251         exp_dir = self.obj_parent.export_dir()
  252 
  253         # PE files with a large number of functions will have arrays
  254         # that spans multiple pages. Thus the first entries may be valid, 
  255         # last entries may be valid, but middle entries may be invalid
  256         # (paged). In the various checks below, we test for None (paged)
  257         # and zero (non-paged but invalid RVA). 
  258 
  259         # Array of RVAs to function code 
  260         address_of_functions = obj.Object('Array',
  261                                     offset = mod_base + self.AddressOfFunctions,
  262                                     targetType = 'unsigned int',
  263                                     count = self.NumberOfFunctions,
  264                                     vm = self.obj_native_vm)
  265         # Array of RVAs to function names 
  266         address_of_names = obj.Object('Array',
  267                                     offset = mod_base + self.AddressOfNames,
  268                                     targetType = 'unsigned int',
  269                                     count = self.NumberOfNames,
  270                                     vm = self.obj_native_vm)
  271         # Array of RVAs to function ordinals 
  272         address_of_name_ordinals = obj.Object('Array',
  273                                     offset = mod_base + self.AddressOfNameOrdinals,
  274                                     targetType = 'unsigned short',
  275                                     count = self.NumberOfNames,
  276                                     vm = self.obj_native_vm)
  277 
  278         # When functions are exported by Name, it will increase
  279         # NumberOfNames by 1 and NumberOfFunctions by 1. When 
  280         # functions are exported by Ordinal, only the NumberOfFunctions
  281         # will increase. First we enum functions exported by Name 
  282         # and track their corresponding Ordinals, so that when we enum
  283         # functions exported by Ordinal only, we don't duplicate. 
  284 
  285         seen_ordinals = []
  286 
  287         # Handle functions exported by name *and* ordinal 
  288         for i in range(self.NumberOfNames):
  289 
  290             name_rva = address_of_names[i]
  291             ordinal = address_of_name_ordinals[i]
  292 
  293             if name_rva in (0, None):
  294                 continue
  295 
  296             # Check the sanity of ordinal values before using it as an index
  297             if ordinal == None or ordinal >= self.NumberOfFunctions:
  298                 continue
  299 
  300             func_rva = address_of_functions[ordinal]
  301 
  302             if func_rva in (0, None):
  303                 continue
  304 
  305             # Handle forwarded exports. If the function's RVA is inside the exports 
  306             # section (as given by the VirtualAddress and Size fields in the 
  307             # DataDirectory), the symbol is forwarded. Return the name of the 
  308             # forwarded function and None as the function address. 
  309 
  310             if (func_rva >= exp_dir.VirtualAddress and
  311                     func_rva < exp_dir.VirtualAddress + exp_dir.Size):
  312                 n = self._name(func_rva)
  313                 f = obj.NoneObject("Ordinal function {0} in module {1} forwards to {2}".format(
  314                                    ordinal, str(self.obj_parent.BaseDllName or ''), n))
  315             else:
  316                 n = self._name(name_rva)
  317                 f = func_rva
  318 
  319             # Add the ordinal base and save it 
  320             ordinal += self.Base
  321             seen_ordinals.append(ordinal)
  322 
  323             yield ordinal, f, n
  324 
  325         # Handle functions exported by ordinal only 
  326         for i in range(self.NumberOfFunctions):
  327 
  328             ordinal = self.Base + i
  329 
  330             # Skip functions already enumberated above 
  331             if ordinal not in seen_ordinals:
  332 
  333                 func_rva = address_of_functions[i]
  334 
  335                 if func_rva in (0, None):
  336                     continue
  337 
  338                 seen_ordinals.append(ordinal)
  339 
  340                 # There is no name RVA 
  341                 yield ordinal, func_rva, obj.NoneObject("Name RVA not accessible")
  342 
  343 class _IMAGE_IMPORT_DESCRIPTOR(obj.CType):
  344     """Handles IID entries for imported functions"""
  345 
  346     def valid(self, nt_header):
  347         """Check the validity of some fields"""
  348         try:
  349             return (self.OriginalFirstThunk != 0 and
  350                     self.OriginalFirstThunk < nt_header.OptionalHeader.SizeOfImage and
  351                     self.FirstThunk != 0 and
  352                     self.FirstThunk < nt_header.OptionalHeader.SizeOfImage and
  353                     self.Name < nt_header.OptionalHeader.SizeOfImage)
  354         except obj.InvalidOffsetError:
  355             return False
  356 
  357     def _name(self, name_rva):
  358         """Return a String object for the name at the given RVA"""
  359 
  360         return obj.Object("String",
  361                       offset = self.obj_parent.DllBase + name_rva,
  362                       vm = self.obj_native_vm, length = 128)
  363 
  364     def dll_name(self):
  365         """Returns the name of the DLL for this IID"""
  366         return self._name(self.Name)
  367 
  368     def _imported_functions(self):
  369         """
  370         Generator for imported functions. 
  371 
  372         @return: tuple (Ordinal, FunctionVA, Name)
  373 
  374         If the function is imported by ordinal, then Ordinal is the 
  375         ordinal value and Name is None. 
  376 
  377         If the function is imported by name, then Ordinal is the
  378         hint and Name is the imported function name (or None if its
  379         paged). 
  380 
  381         FunctionVA is the virtual address of the imported function,
  382         as applied to the IAT by the Windows loader. If the FirstThunk
  383         is paged, then FunctionVA will be None. 
  384         """
  385 
  386         i = 0
  387         while 1:
  388             thunk = obj.Object('_IMAGE_THUNK_DATA',
  389                        offset = self.obj_parent.DllBase + self.OriginalFirstThunk +
  390                        i * self.obj_vm.profile.get_obj_size('_IMAGE_THUNK_DATA'),
  391                        vm = self.obj_native_vm)
  392 
  393             # We've reached the end when the element is zero 
  394             if thunk == None or thunk.AddressOfData == 0:
  395                 break
  396 
  397             o = obj.NoneObject("Ordinal not accessible?")
  398             n = obj.NoneObject("Imported by ordinal?")
  399             f = obj.NoneObject("FirstThunk not accessible")
  400 
  401             # If the highest bit (32 for x86 and 64 for x64) is set, the function is 
  402             # imported by ordinal and the lowest 16-bits contain the ordinal value. 
  403             # Otherwise, the lowest bits (0-31 for x86 and 0-63 for x64) contain an 
  404             # RVA to an _IMAGE_IMPORT_BY_NAME struct. 
  405             if thunk.OrdinalBit == 1:
  406                 o = thunk.Ordinal & 0xFFFF
  407             else:
  408                 iibn = obj.Object("_IMAGE_IMPORT_BY_NAME",
  409                                   offset = self.obj_parent.DllBase +
  410                                   thunk.AddressOfData,
  411                                   vm = self.obj_native_vm)
  412                 o = iibn.Hint
  413                 n = iibn.Name
  414 
  415             # See if the import is bound (i.e. resolved)
  416             first_thunk = obj.Object('_IMAGE_THUNK_DATA',
  417                             offset = self.obj_parent.DllBase + self.FirstThunk +
  418                             i * self.obj_vm.profile.get_obj_size('_IMAGE_THUNK_DATA'),
  419                             vm = self.obj_native_vm)
  420             if first_thunk:
  421                 f = first_thunk.Function.v()
  422 
  423             yield o, f, str(n or '')
  424             i += 1
  425 
  426     def is_list_end(self):
  427         """Returns True if we've reached the list end"""
  428         data = self.obj_vm.zread(
  429                         self.obj_offset,
  430                         self.obj_vm.profile.get_obj_size('_IMAGE_IMPORT_DESCRIPTOR')
  431                         )
  432         return data.count(chr(0)) == len(data)
  433 
  434 class _LDR_DATA_TABLE_ENTRY(obj.CType):
  435     """
  436     Class for PE file / modules
  437 
  438     If these classes are instantiated by _EPROCESS.list_*_modules() 
  439     then its guaranteed to be in the process address space. 
  440 
  441     FIXME: If these classes are found by modscan, ensure we can
  442     dereference properly with obj_native_vm. 
  443     """
  444     
  445     def load_time(self):
  446         if hasattr(self, "LoadTime"):
  447             return str(self.LoadTime)
  448         else:
  449             return ""
  450 
  451     @property
  452     def LoadCount(self):
  453         # prior to windows 8 / server 2012
  454         try:
  455             return self.m("LoadCount")
  456         except AttributeError:
  457             pass
  458 
  459         # windows 8 / server 2012 and later
  460         try:
  461             return self.ObsoleteLoadCount
  462         except AttributeError:
  463             pass
  464 
  465         return obj.NoneObject("No load count")
  466 
  467     def _nt_header(self):
  468         """Return the _IMAGE_NT_HEADERS object"""
  469 
  470         try:
  471             dos_header = obj.Object("_IMAGE_DOS_HEADER", offset = self.DllBase,
  472                                     vm = self.obj_native_vm)
  473             
  474             return dos_header.get_nt_header()
  475         except ValueError:
  476             return obj.NoneObject("Failed initial sanity checks")
  477         except exceptions.SanityCheckException:
  478             return obj.NoneObject("Failed initial sanity checks. Try -u or --unsafe")
  479 
  480     def _directory(self, dir_index):
  481         """Return the requested IMAGE_DATA_DIRECTORY"""
  482 
  483         nt_header = self._nt_header()
  484         if nt_header == None:
  485             raise ValueError('No directory index {0}'.format(dir_index))
  486 
  487         data_dir = nt_header.OptionalHeader.DataDirectory[dir_index]
  488         if data_dir == None:
  489             raise ValueError('No directory index {0}'.format(dir_index))
  490 
  491         # Make sure the directory exists 
  492         if data_dir.VirtualAddress == 0 or data_dir.Size == 0:
  493             raise ValueError('No directory index {0}'.format(dir_index))
  494 
  495         # Make sure the directory VA and Size are sane 
  496         if data_dir.VirtualAddress + data_dir.Size > nt_header.OptionalHeader.SizeOfImage:
  497             raise ValueError('Invalid directory for index {0}'.format(dir_index))
  498 
  499         return data_dir
  500 
  501     def export_dir(self):
  502         """Return the IMAGE_DATA_DIRECTORY for exports"""
  503         return self._directory(0) # DIRECTORY_ENTRY_EXPORT
  504 
  505     def import_dir(self):
  506         """Return the IMAGE_DATA_DIRECTORY for imports"""
  507         return self._directory(1) # DIRECTORY_ENTRY_IMPORT
  508 
  509     def debug_dir(self):
  510         """Return the IMAGE_DEBUG_DIRECTORY for debug info"""
  511         return self._directory(6) # IMAGE_DEBUG_DIRECTORY
  512 
  513     def security_dir(self):
  514         """Return the IMAGE_SECURITY_DIRECTORY"""
  515         return self._directory(4) # IMAGE_DIRECTORY_ENTRY_SECURITY
  516 
  517     def get_debug_directory(self):
  518         """Return the debug directory object for this PE"""
  519         
  520         try:
  521             data_dir = self.debug_dir()
  522         except ValueError, why:
  523             return obj.NoneObject(str(why))
  524 
  525         return obj.Object("_IMAGE_DEBUG_DIRECTORY", 
  526                           offset = self.DllBase + data_dir.VirtualAddress, 
  527                           vm = self.obj_native_vm)
  528 
  529     def getprocaddress(self, func):
  530         """Return the RVA of func"""
  531         for _, f, n in self.exports():
  532             if str(n or '') == func:
  533                 return f
  534         return None
  535 
  536     def imports(self):
  537         """
  538         Generator for the PE's imported functions.
  539 
  540         The _DIRECTORY_ENTRY_IMPORT.VirtualAddress points to an array 
  541         of _IMAGE_IMPORT_DESCRIPTOR structures. The end is reached when 
  542         the IID structure is all zeros. 
  543         """
  544 
  545         try:
  546             data_dir = self.import_dir()
  547         except ValueError, why:
  548             raise StopIteration(why)
  549 
  550         i = 0
  551 
  552         desc_size = self.obj_vm.profile.get_obj_size('_IMAGE_IMPORT_DESCRIPTOR')
  553 
  554         while 1:
  555             desc = obj.Object('_IMAGE_IMPORT_DESCRIPTOR',
  556                       vm = self.obj_native_vm,
  557                       offset = self.DllBase + data_dir.VirtualAddress + (i * desc_size),
  558                       parent = self)
  559 
  560             # Stop if the IID is paged or all zeros
  561             if desc == None or desc.is_list_end():
  562                 break
  563 
  564             # Stop if the IID contains invalid fields 
  565             if not desc.valid(self._nt_header()):
  566                 break
  567 
  568             dll_name = desc.dll_name()
  569 
  570             for o, f, n in desc._imported_functions():
  571                 yield dll_name, o, f, n
  572 
  573             i += 1
  574 
  575     def exports(self):
  576         """Generator for the PE's exported functions"""
  577 
  578         try:
  579             data_dir = self.export_dir()
  580         except ValueError, why:
  581             raise StopIteration(why)
  582 
  583         expdir = obj.Object('_IMAGE_EXPORT_DIRECTORY',
  584                             offset = self.DllBase + data_dir.VirtualAddress,
  585                             vm = self.obj_native_vm,
  586                             parent = self)
  587 
  588         if expdir.valid(self._nt_header()):
  589             # Ordinal, Function RVA, and Name Object 
  590 
  591             for o, f, n in expdir._exported_functions():
  592                 yield o, f, n
  593 
  594 class _IMAGE_DOS_HEADER(obj.CType):
  595     """DOS header"""
  596 
  597     def get_nt_header(self):
  598         """Get the NT header"""
  599 
  600         if self.e_magic != 0x5a4d:
  601             raise ValueError('e_magic {0:04X} is not a valid DOS signature.'.format(self.e_magic))
  602 
  603         nt_header = obj.Object("_IMAGE_NT_HEADERS",
  604                           offset = self.e_lfanew + self.obj_offset,
  605                           vm = self.obj_vm,
  606                           native_vm = self.obj_native_vm)
  607 
  608         if nt_header.Signature != 0x4550:
  609             raise ValueError('NT header signature {0:04X} is not a valid'.format(nt_header.Signature))
  610 
  611         return nt_header
  612 
  613     def get_version_info(self):
  614         """Get the _VS_VERSION_INFO structure"""
  615 
  616         try:
  617             nt_header = self.get_nt_header()
  618         except ValueError, ve:
  619             return obj.NoneObject("PE file failed initial sanity checks: {0}".format(ve))
  620 
  621         try:
  622             unsafe = self.obj_vm.get_config().UNSAFE
  623         except AttributeError:
  624             unsafe = False
  625 
  626         for sect in nt_header.get_sections(unsafe):
  627             if str(sect.Name) == '.rsrc':
  628                 root = obj.Object("_IMAGE_RESOURCE_DIRECTORY", self.obj_offset + sect.VirtualAddress, self.obj_vm)
  629                 for rname, rentry, rdata in root.get_entries():
  630                     # We're a VERSION resource and we have subelements
  631                     if rname == resource_types['RT_VERSION'] and rentry:
  632                         for sname, sentry, sdata in rdata.get_entries():
  633                             # We're the single sub element of the VERSION
  634                             if sname == 1 and sentry:
  635                                 # Get the string tables
  636                                 for _stname, stentry, stdata in sdata.get_entries():
  637                                     if not stentry:
  638                                         return obj.Object("_VS_VERSION_INFO", offset = (stdata.DataOffset + self.obj_offset), vm = self.obj_vm)
  639 
  640         return obj.NoneObject("Cannot find a _VS_VERSION_INFO structure")
  641 
  642     def get_code(self, data_start, data_size, offset):
  643         """Returns a single section of re-created data from a file image"""
  644         first_block = 0x1000 - data_start % 0x1000
  645         full_blocks = ((data_size + (data_start % 0x1000)) / 0x1000) - 1
  646         left_over = (data_size + data_start) % 0x1000
  647 
  648         code = ""
  649 
  650         # Deal with reads that are smaller than a block
  651         if data_size < first_block:
  652             data_read = self.obj_vm.zread(data_start, data_size)
  653             code += data_read
  654             return (offset, code)
  655 
  656         data_read = self.obj_vm.zread(data_start, first_block)
  657         code += data_read
  658 
  659         # The middle part of the read
  660         new_vaddr = data_start + first_block
  661 
  662         for _i in range(0, full_blocks):
  663             data_read = self.obj_vm.zread(new_vaddr, 0x1000)
  664             code += data_read
  665             new_vaddr = new_vaddr + 0x1000
  666 
  667         # The last part of the read
  668         if left_over > 0:
  669             data_read = self.obj_vm.zread(new_vaddr, left_over)
  670             code += data_read
  671         return (offset, code)
  672 
  673     def round(self, addr, align, up = False):
  674         """Rounds down an address based on an alignment"""
  675         if addr % align == 0:
  676             return addr
  677         else:
  678             if up:
  679                 return (addr + (align - (addr % align)))
  680             return (addr - (addr % align))
  681 
  682     def _get_image_exe(self, unsafe, fix):
  683     
  684         nt_header = self.get_nt_header()
  685         soh = nt_header.OptionalHeader.SizeOfHeaders
  686         header = self.obj_vm.zread(self.obj_offset, soh)
  687         if fix:
  688             header = self._fix_header_image_base(header, nt_header)
  689         yield (0, header)
  690 
  691         fa = nt_header.OptionalHeader.FileAlignment
  692         for sect in nt_header.get_sections(unsafe):
  693             foa = self.round(sect.PointerToRawData, fa)
  694             if foa != sect.PointerToRawData:
  695                 debug.warning("Section start on disk not aligned to file alignment.\n")
  696                 debug.warning("Adjusted section start from {0} to {1}.\n".format(sect.PointerToRawData, foa))
  697             yield self.get_code(sect.VirtualAddress + self.obj_offset,
  698                                 sect.SizeOfRawData, foa)
  699 
  700     def replace_header_field(self, sect, header, item, value):
  701         """Replaces a field in a sector header"""
  702         field_size = item.size()
  703         start = item.obj_offset - sect.obj_offset
  704         end = start + field_size
  705         newval = struct.pack(item.format_string, int(value))
  706         result = header[:start] + newval + header[end:]
  707         return result
  708 
  709     def _fix_header_image_base(self, header, nt_header):
  710         """
  711         returns a modified header buffer with the image base changed to the
  712         provided base address
  713         """        
  714 
  715         opthdr = nt_header.OptionalHeader
  716         
  717         if opthdr.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC:
  718             if opthdr.obj_vm.profile.metadata.get("memory_model") == "64bit":
  719                 opthdr = opthdr.cast("_IMAGE_OPTIONAL_HEADER32")
  720         
  721         imb_offs = opthdr.ImageBase.obj_offset - self.obj_offset      
  722         imb = opthdr.ImageBase
  723         newval = struct.pack(imb.format_string, int(self.obj_offset))
  724         return header[:imb_offs] + newval + header[imb_offs+imb.size():]
  725 
  726     def _get_image_mem(self, unsafe, fix):
  727 
  728         nt_header = self.get_nt_header()
  729 
  730         sa = nt_header.OptionalHeader.SectionAlignment
  731         shs = self.obj_vm.profile.get_obj_size('_IMAGE_SECTION_HEADER')
  732 
  733         offset, data = self.get_code(self.obj_offset, nt_header.OptionalHeader.SizeOfImage, 0)
  734         if fix:
  735             data = self._fix_header_image_base(data, nt_header)
  736 
  737         yield offset, data
  738 
  739         prevsect = None
  740         sect_sizes = []
  741         for sect in nt_header.get_sections(unsafe):
  742             if prevsect is not None:
  743                 sect_sizes.append(sect.VirtualAddress - prevsect.VirtualAddress)
  744             prevsect = sect
  745         if prevsect is not None:
  746             sect_sizes.append(self.round(prevsect.Misc.VirtualSize, sa, up = True))
  747 
  748         counter = 0
  749         start_addr = nt_header.FileHeader.SizeOfOptionalHeader + (nt_header.OptionalHeader.obj_offset - self.obj_offset)
  750         for sect in nt_header.get_sections(unsafe):
  751             sectheader = self.obj_vm.read(sect.obj_offset, shs)
  752             
  753             if not sectheader:
  754                 break
  755             
  756             # Change the PointerToRawData
  757             sectheader = self.replace_header_field(sect, sectheader, sect.PointerToRawData, sect.VirtualAddress)
  758             sectheader = self.replace_header_field(sect, sectheader, sect.SizeOfRawData, sect_sizes[counter])
  759             sectheader = self.replace_header_field(sect, sectheader, sect.Misc.VirtualSize, sect_sizes[counter])
  760 
  761             yield (start_addr + (counter * shs), sectheader)
  762             counter += 1
  763 
  764     def get_image(self, unsafe = False, memory = False, fix = False):
  765 
  766         if memory:
  767             return self._get_image_mem(unsafe, fix)
  768         else:
  769             return self._get_image_exe(unsafe, fix)
  770 
  771 class _IMAGE_NT_HEADERS64(obj.CType):
  772     @property
  773     def OptionalHeader(self):
  774         ret = self.m("OptionalHeader")
  775 
  776         if self.obj_vm.profile.get_obj_size("address") == 8 and self.FileHeader.Machine == 0x014c: # 32bit exe
  777             ret = ret.cast("_IMAGE_OPTIONAL_HEADER32") 
  778 
  779         return ret
  780 
  781 class _IMAGE_NT_HEADERS(obj.CType):
  782     """PE header"""
  783 
  784     @property
  785     def OptionalHeader(self):
  786         ret = self.m("OptionalHeader")
  787         if self.obj_vm.profile.get_obj_size("address") == 8 and self.FileHeader.Machine == 0x014c: # 32bit exe
  788             ret = ret.cast("_IMAGE_OPTIONAL_HEADER32") 
  789         
  790         return ret
  791 
  792     def get_sections(self, unsafe = False):
  793         """Get the PE sections"""
  794         sect_size = self.obj_vm.profile.get_obj_size("_IMAGE_SECTION_HEADER")
  795         start_addr = self.FileHeader.SizeOfOptionalHeader + self.OptionalHeader.obj_offset
  796 
  797         for i in range(self.FileHeader.NumberOfSections):
  798             s_addr = start_addr + (i * sect_size)
  799             sect = obj.Object("_IMAGE_SECTION_HEADER", offset = s_addr, vm = self.obj_vm,
  800                               parent = self, native_vm = self.obj_native_vm)
  801                               
  802             ## deal with swapped sections...
  803             if not sect:
  804                 continue
  805                               
  806             if not unsafe:
  807                 sect.sanity_check_section()
  808             yield sect
  809 
  810 class _IMAGE_SECTION_HEADER(obj.CType):
  811     """PE section"""
  812 
  813     def sanity_check_section(self):
  814         """Sanity checks address boundaries"""
  815         # Note: all addresses here are RVAs
  816         image_size = self.obj_parent.OptionalHeader.SizeOfImage
  817         if self.VirtualAddress > image_size:
  818             raise exceptions.SanityCheckException('VirtualAddress {0:08x} is past the end of image.'.format(self.VirtualAddress))
  819         if self.Misc.VirtualSize > image_size:
  820             raise exceptions.SanityCheckException('VirtualSize {0:08x} is larger than image size.'.format(self.Misc.VirtualSize))
  821         if self.SizeOfRawData > image_size:
  822             raise exceptions.SanityCheckException('SizeOfRawData {0:08x} is larger than image size.'.format(self.SizeOfRawData))
  823 
  824 class VerStruct(obj.CType):
  825     """Generic Version Structure"""
  826 
  827     def _determine_key(self, findend = False):
  828         """Determines the string value for or end location of the key"""
  829         if self.Key != None:
  830             name = None
  831             for n in self.Key:
  832                 if n == None:
  833                     return n
  834                 # If the letter's valid, then deal with it
  835                 if n == 0:
  836                     if findend:
  837                         return n.obj_offset + n.size()
  838                     name = self.obj_vm.read(self.Key.obj_offset, n.obj_offset - self.Key.obj_offset).decode("utf16", "ignore").encode("ascii", 'backslashreplace')
  839                     break
  840             return name
  841         return self.Key
  842 
  843     def get_key(self):
  844         """Returns the VerStruct Name"""
  845         return self._determine_key()
  846 
  847     def offset_pad(self, offset):
  848         """Pads an offset to a 32-bit alignment"""
  849         return (((offset + 3) / 4) * 4)
  850 
  851     def get_children(self):
  852         """Returns the available children"""
  853         offset = self.offset_pad(self._determine_key(True))
  854         if self.ValueLength > 0:
  855             # Nasty hardcoding unicode (length*2) length in here, 
  856             # but what else can we do?
  857             return self.obj_vm.read(offset, self.ValueLength * 2)
  858         else:
  859             return self._recurse_children(offset)
  860 
  861     def _recurse_children(self, offset):
  862         """Recurses thorugh the available children"""
  863         while offset < self.obj_offset + self.Length:
  864             item = obj.Object("VerStruct", offset = offset, vm = self.obj_vm, parent = self)
  865             if item.Length < 1 or item.get_key() == None:
  866                 raise StopIteration("Could not recover a key for a child at offset {0}".format(item.obj_offset))
  867             yield item.get_key(), item.get_children()
  868             offset = self.offset_pad(offset + item.Length)
  869         raise StopIteration("No children")
  870 
  871     def display_unicode(self, string):
  872         """Renders a UTF16 string"""
  873         if string is None:
  874             return ''
  875         return string.decode("utf16", "ignore").encode("ascii", 'backslashreplace')
  876 
  877     def get_file_strings(self):
  878 
  879         for name, children in self.get_children():
  880             if name == 'StringFileInfo':
  881                 for _codepage, strings in children:
  882                     for string, value in strings:
  883                         # Make sure value isn't a generator, and we've a subtree to deal with
  884                         if isinstance(value, type(strings)):
  885                             debug.debug("  {0} : Subtrees not yet implemented\n".format(string))
  886                         else:
  887                             yield string, self.display_unicode(value)
  888 
  889 class _VS_VERSION_INFO(VerStruct):
  890     """Version Information"""
  891 
  892     def get_children(self):
  893         """Recurses through the children of a Version Info records"""
  894         if not self.FileInfo:
  895             raise StopIteration("No children")
  896         offset = self.offset_pad(self.FileInfo.obj_offset + self.ValueLength)
  897         return self._recurse_children(offset)
  898 
  899 class _VS_FIXEDFILEINFO(obj.CType):
  900     """Fixed (language and codepage independent) information"""
  901 
  902     def file_version(self):
  903         """Returns the file version"""
  904         return self.get_version(self.FileVerMS) + "." + self.get_version(self.FileVerLS)
  905 
  906     def product_version(self):
  907         """Returns the product version"""
  908         return self.get_version(self.ProdVerMS) + "." + self.get_version(self.ProdVerLS)
  909 
  910     def get_version(self, value):
  911         """Returns a version in four parts"""
  912         version = []
  913         for i in range(2):
  914             version = [(value >> (i * 16)) & 0xFFFF] + version
  915         return '.'.join([str(x) for x in version])
  916 
  917     def file_type(self):
  918         """Returns the type of the file"""
  919         ftype = str(self.FileType)
  920         choices = None
  921         if self.FileType == 'Driver':
  922             choices = {
  923                        0x0: 'Unknown',
  924                        0x1: 'Printer',
  925                        0x2: 'Keyboard',
  926                        0x3: 'Language',
  927                        0x4: 'Display',
  928                        0x5: 'Mouse',
  929                        0x6: 'Network',
  930                        0x7: 'System',
  931                        0x8: 'Installable',
  932                        0x9: 'Sound',
  933                        0xA: 'Comms',
  934                        0xB: 'Input Method',
  935                        0xC: 'Versioned Printer',
  936                        }
  937         elif self.FileType == 'Font':
  938             choices = {
  939                        0x1: 'Raster',
  940                        0x2: 'Vector',
  941                        0x3: 'Truetype',
  942                        }
  943         if choices != None:
  944             subtype = obj.Object('Enumeration', 0x28, vm = self.obj_vm, parent = self, choices = choices)
  945             ftype += " (" + str(subtype) + ")"
  946 
  947         return ftype
  948 
  949     def flags(self):
  950         """Returns the file's flags"""
  951         data = struct.pack('=I', self.FileFlags & self.FileFlagsMask)
  952         addr_space = addrspace.BufferAddressSpace(self.obj_vm.get_config(), 0, data)
  953         bitmap = {'Debug': 0,
  954                   'Prerelease': 1,
  955                   'Patched': 2,
  956                   'Private Build': 3,
  957                   'Info Inferred': 4,
  958                   'Special Build' : 5,
  959                  }
  960         return obj.Object('Flags', offset = 0, vm = addr_space, bitmap = bitmap)
  961 
  962     def v(self):
  963         """Returns the value of the structure"""
  964         val = ("File version    : {0}\n" +
  965                "Product version : {1}\n" +
  966                "Flags           : {2}\n" +
  967                "OS              : {3}\n" +
  968                "File Type       : {4}\n" +
  969                "File Date       : {5}").format(self.file_version(), self.product_version(),
  970                                                  self.flags(), self.FileOS, self.file_type(), self.FileDate or '')
  971         return val
  972 
  973 class _IMAGE_RESOURCE_DIR_STRING_U(obj.CType):
  974     """Handles Unicode-esque strings in IMAGE_RESOURCE_DIRECTORY structures"""
  975     # This is very similar to a UNICODE object, perhaps they should be merged somehow?
  976     def v(self):
  977         """Value function for _IMAGE_RESOURCE_DIR_STRING_U"""
  978         try:
  979             length = self.Length.v()
  980             if length > 1024:
  981                 length = 0
  982             data = self.obj_vm.read(self.Value.obj_offset, length)
  983             return data.decode("utf16", "ignore").encode("ascii", 'backslashreplace')
  984         except Exception, _e:
  985             return ''
  986 
  987 class _IMAGE_RESOURCE_DIRECTORY(obj.CType):
  988     """Handles Directory Entries"""
  989     def __init__(self, theType = None, offset = None, vm = None, parent = None, *args, **kwargs):
  990         self.sectoffset = offset
  991         obj.CType.__init__(self, theType = theType, offset = offset, vm = vm, parent = parent, *args, **kwargs)
  992 
  993     def get_entries(self):
  994         """Gets a tree of the entries from the top level IRD"""
  995 
  996         if self.NamedEntriesCount + self.IdEntriesCount > 4096:
  997             return
  998  
  999         for irde in self.Entries:
 1000             if irde != None:
 1001                 if irde.Name & 0x80000000:
 1002                     # Points to a Name object
 1003                     name = obj.Object("_IMAGE_RESOURCE_DIR_STRING_U", (irde.Name & 0x7FFFFFFF) + self.sectoffset, vm = self.obj_vm, parent = irde)
 1004                 else:
 1005                     name = int(irde.Name)
 1006                 if irde.DataOffset & 0x80000000:
 1007                     # We're another DIRECTORY
 1008                     retobj = obj.Object("_IMAGE_RESOURCE_DIRECTORY", (irde.DataOffset & 0x7FFFFFFF) + self.sectoffset, vm = self.obj_vm, parent = irde)
 1009                     retobj.sectoffset = self.sectoffset
 1010                 else:
 1011                     # We're a DATA_ENTRY
 1012                     retobj = obj.Object("_IMAGE_RESOURCE_DATA_ENTRY", irde.DataOffset + self.sectoffset, vm = self.obj_vm, parent = irde)
 1013                 yield (name, bool(irde.DataOffset & 0x80000000), retobj)
 1014 
 1015 class WinPEVTypes(obj.ProfileModification):
 1016     before = ['WindowsOverlay']
 1017     conditions = {'os': lambda x : x == 'windows'}
 1018     def modification(self, profile):
 1019         profile.vtypes.update(pe_vtypes)
 1020 
 1021 class WinPEx64VTypes(obj.ProfileModification):
 1022     before = ['WinPEVTypes']
 1023     conditions = {'os': lambda x : x == 'windows',
 1024                   'memory_model': lambda x: x == '64bit'}
 1025     def modification(self, profile):
 1026         profile.vtypes.update(pe_vtypes_64)
 1027 
 1028 class WinPEObjectClasses(obj.ProfileModification):
 1029     before = ['WindowsOverlay']
 1030     conditions = {'os': lambda x : x == 'windows'}
 1031     def modification(self, profile):
 1032         profile.object_classes.update({
 1033             '_IMAGE_EXPORT_DIRECTORY': _IMAGE_EXPORT_DIRECTORY,
 1034             '_IMAGE_IMPORT_DESCRIPTOR': _IMAGE_IMPORT_DESCRIPTOR,
 1035             '_LDR_DATA_TABLE_ENTRY': _LDR_DATA_TABLE_ENTRY,
 1036             '_IMAGE_DOS_HEADER': _IMAGE_DOS_HEADER,
 1037             '_IMAGE_NT_HEADERS': _IMAGE_NT_HEADERS,
 1038             '_IMAGE_NT_HEADERS64': _IMAGE_NT_HEADERS64,
 1039             '_IMAGE_SECTION_HEADER': _IMAGE_SECTION_HEADER,
 1040             '_IMAGE_RESOURCE_DIRECTORY': _IMAGE_RESOURCE_DIRECTORY,
 1041             '_IMAGE_RESOURCE_DIR_STRING_U': _IMAGE_RESOURCE_DIR_STRING_U,
 1042             '_VS_FIXEDFILEINFO': _VS_FIXEDFILEINFO,
 1043             '_VS_VERSION_INFO': _VS_VERSION_INFO,
 1044             'VerStruct': VerStruct,
 1045             })