Package rekall :: Package plugins :: Package overlays :: Package windows :: Module common
[frames] | no frames]

Source Code for Module rekall.plugins.overlays.windows.common

   1  # Rekall Memory Forensics 
   2  # Copyright (C) 2012 Michael Cohen <scudette@users.sourceforge.net> 
   3  # Copyright (c) 2008 Volatile Systems 
   4  # Copyright (c) 2008 Brendan Dolan-Gavitt <bdolangavitt@wesleyan.edu> 
   5  # Copyright 2014 Google Inc. All Rights Reserved. 
   6  # 
   7  # This program is free software; you can redistribute it and/or modify 
   8  # it under the terms of the GNU General Public License as published by 
   9  # the Free Software Foundation; either version 2 of the License, or (at 
  10  # your option) any later version. 
  11  # 
  12  # This program is distributed in the hope that it will be useful, but 
  13  # WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
  15  # General Public License for more details. 
  16  # 
  17  # You should have received a copy of the GNU General Public License 
  18  # along with this program; if not, write to the Free Software 
  19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
  20  # 
  21   
  22  # pylint: disable=protected-access 
  23   
  24  """Common windows overlays and classes.""" 
  25  import struct 
  26  from itertools import chain 
  27   
  28  from rekall import addrspace 
  29  from rekall import obj 
  30   
  31  from rekall.plugins.overlays.windows import pe_vtypes 
  32  from rekall.plugins.overlays.windows import undocumented 
  33   
  34  from rekall_lib import utils 
  35   
  36   
  37  MM_PROTECTION_ENUM = utils.EnumerationFromDefines(""" 
  38  // 
  39  00098 // Protection Bits part of the internal memory manager Protection Mask, from: 
  40  00099 // http://reactos.org/wiki/Techwiki:Memory_management_in_the_Windows_XP_kernel 
  41  00100 // https://www.reactos.org/wiki/Techwiki:Memory_Protection_constants 
  42  00101 // and public assertions. 
  43  00102 // 
  44  00103 #define MM_ZERO_ACCESS         0 
  45  00104 #define MM_READONLY            1 
  46  00105 #define MM_EXECUTE             2 
  47  00106 #define MM_EXECUTE_READ        3 
  48  00107 #define MM_READWRITE           4 
  49  00108 #define MM_WRITECOPY           5 
  50  00109 #define MM_EXECUTE_READWRITE   6 
  51  00110 #define MM_EXECUTE_WRITECOPY   7 
  52  00111 #define MM_PROTECT_ACCESS      7 
  53  00112 
  54  00113 // 
  55  00114 // These are flags on top of the actual protection mask 
  56  00115 // 
  57  00116 #define MM_NOCACHE            0x08 
  58  00117 #define MM_GUARDPAGE          0x10 
  59  00118 #define MM_WRITECOMBINE       0x18 
  60  00119 #define MM_PROTECT_SPECIAL    0x18 
  61  00120 
  62  00121 // 
  63  00122 // These are special cases 
  64  00123 // 
  65  00124 #define MM_DECOMMIT           (MM_ZERO_ACCESS | MM_GUARDPAGE) 
  66  00125 #define MM_NOACCESS           (MM_ZERO_ACCESS | MM_WRITECOMBINE) 
  67  00126 #define MM_OUTSWAPPED_KSTACK  (MM_EXECUTE_WRITECOPY | MM_WRITECOMBINE) 
  68  00127 #define MM_INVALID_PROTECTION  0xFFFFFFFF 
  69  """) 
  70   
  71   
  72  windows_overlay = { 
  73      '_UNICODE_STRING': [None, { 
  74          'Buffer': [None, ['Pointer', dict( 
  75              target='UnicodeString', 
  76              target_args=dict(length=lambda x: x.Length) 
  77          )]], 
  78      }], 
  79      # Documented at http://www.osronline.com/article.cfm?id=523 
  80      '_RTL_BITMAP': [None, { 
  81          "Buffer": [None, ["Pointer", dict( 
  82              target="String", 
  83              target_args=dict( 
  84                  term=None, 
  85                  length=lambda x: x.SizeOfBitMap / 8 + 1 
  86              ) 
  87          )]], 
  88      }], 
  89      '_UNICODE_STRING32': [8, { 
  90          "Buffer": [4, ['Pointer32', dict( 
  91              target='UnicodeString', 
  92              target_args=dict(length=lambda x: x.Length) 
  93          )]], 
  94          "Length": [0, ["unsigned short", {}]], 
  95          "MaximumLength": [2, ["unsigned short", {}]] 
  96      }], 
  97      '_EPROCESS' : [None, { 
  98          # Some standard fields for windows processes. 
  99          'name': lambda x: x.ImageFileName, 
 100          'pid': lambda x: x.UniqueProcessId, 
 101          'dtb': lambda x: x.Pcb.DirectoryTableBase.v(), 
 102   
 103          'CreateTime' : [None, ['WinFileTime', {}]], 
 104          'ExitTime' : [None, ['WinFileTime', {}]], 
 105          'InheritedFromUniqueProcessId' : [None, ['unsigned int']], 
 106          'ImageFileName' : [None, ['String', dict(length=16)]], 
 107          'UniqueProcessId' : [None, ['unsigned int']], 
 108          'Session': [None, ["Pointer", dict(target="_MM_SESSION_SPACE")]], 
 109          'Token': [None, ["_EX_FAST_REF", dict(target="_TOKEN")]], 
 110          }], 
 111   
 112      '_ETHREAD' : [None, { 
 113          'CreateTime' : [None, ['ThreadCreateTimeStamp', {}]], 
 114          'ExitTime' : [None, ['WinFileTime', {}]], 
 115          }], 
 116   
 117      '_OBJECT_SYMBOLIC_LINK' : [None, { 
 118          'CreationTime' : [None, ['WinFileTime', {}]], 
 119          }], 
 120   
 121      '_KUSER_SHARED_DATA' : [None, { 
 122          'SystemTime' : [None, ['WinFileTime', dict(is_utc=True)]], 
 123   
 124          # When the system license activation must occur. 
 125          'SystemExpirationDate': [None, ['WinFileTime', {}]], 
 126   
 127          "NtSystemRoot": [None, ["UnicodeString"]], 
 128      }], 
 129   
 130      '_KPCR': [None, { 
 131          # The processor block has varying names between windows versions so 
 132          # we just make them synonyms. 
 133          'ProcessorBlock': lambda x: x.m("Prcb") or x.m("PrcbData"), 
 134          'IDT': lambda x: x.m("IDT") or x.m("IdtBase"), 
 135          'GDT': lambda x: x.m("GDT") or x.m("GdtBase"), 
 136          'KdVersionBlock': [None, ['Pointer', dict( 
 137              target='_DBGKD_GET_VERSION64')]], 
 138          }], 
 139   
 140      '_KPRCB': [None, { 
 141          'CurrentThread': [None, ['Pointer', dict( 
 142              target='_ETHREAD')]], 
 143          'IdleThread': [None, ['Pointer', dict( 
 144              target='_ETHREAD')]], 
 145          'NextThread': [None, ['Pointer', dict( 
 146              target='_ETHREAD')]], 
 147          'VendorString': [None, ['String', dict(length=13)]], 
 148   
 149          }], 
 150   
 151      # The DTB is really an array of 2 ULONG_PTR but we only need the first one 
 152      # which is the value loaded into CR3. The second one, according to procobj.c 
 153      # of the wrk-v1.2, contains the PTE that maps something called hyper space. 
 154      '_KPROCESS' : [None, { 
 155          'DirectoryTableBase' : [None, ['address']], 
 156      }], 
 157   
 158      '_HANDLE_TABLE_ENTRY' : [None, { 
 159          'Object' : [None, ['_EX_FAST_REF']], 
 160          }], 
 161   
 162      '_OBJECT_HEADER': [None, { 
 163          'GrantedAccess': lambda x: x.obj_parent.GrantedAccess 
 164          }], 
 165   
 166      '_IMAGE_SECTION_HEADER' : [None, { 
 167          'Name' : [0x0, ['String', dict(length=8)]], 
 168          }], 
 169   
 170      'PO_MEMORY_IMAGE' : [None, { 
 171          'Signature':   [None, ['String', dict(length=4)]], 
 172          'SystemTime' : [None, ['WinFileTime', {}]], 
 173          }], 
 174   
 175      '_DBGKD_GET_VERSION64' : [None, { 
 176          'DebuggerDataList' : [None, ['pointer', ['unsigned long']]], 
 177          }], 
 178   
 179      '_TOKEN' : [None, { 
 180          'UserAndGroups' : [None, ['Pointer', dict( 
 181              target='Array', 
 182              target_args=dict( 
 183                  count=lambda x: x.UserAndGroupCount, 
 184                  target='_SID_AND_ATTRIBUTES' 
 185                  ) 
 186              )]], 
 187          }], 
 188   
 189      '_SID_AND_ATTRIBUTES': [None, { 
 190          'Sid': [None, ['Pointer', dict( 
 191              target='_SID' 
 192              )]], 
 193          }], 
 194   
 195      '_SID' : [None, { 
 196          'SubAuthority' : [None, ['Array', dict( 
 197              count=lambda x: x.SubAuthorityCount, 
 198              target='unsigned long')]], 
 199          }], 
 200   
 201      '_CLIENT_ID': [None, { 
 202          'UniqueProcess' : [None, ['unsigned int']], 
 203          'UniqueThread' : [None, ['unsigned int']], 
 204          }], 
 205   
 206      '_MMVAD': [None, { 
 207          'FirstPrototypePte': [None, ["Pointer", dict( 
 208              target="Array", 
 209              target_args=dict( 
 210                  target="_MMPTE" 
 211                  ) 
 212              )]], 
 213          }], 
 214   
 215      '_MMPFN': [None, { 
 216          # Field moved around from XP and Win10. 
 217          "IsPrototype": lambda x: x.multi_m( 
 218              "u4.PrototypePte", "u3.e1.PrototypePte"), 
 219   
 220          # XP has no priority. 
 221          "Priority": lambda x: x.m("u3.e1.Priority"), 
 222   
 223          "Type": [0, ["ValueEnumeration", dict( 
 224              value=lambda x: x.u3.e1.PageLocation, 
 225              choices={ 
 226                  0: 'Zeroed', 
 227                  1: 'Free', 
 228                  2: 'Standby', 
 229                  3: 'Modified', 
 230                  4: 'ModifiedNoWrite', 
 231                  5: 'Bad', 
 232                  6: 'Active', 
 233                  7: 'Transition' 
 234              } 
 235          )]], 
 236      }], 
 237      "_GUID": [16, { 
 238          "Data4": [8, ["String", dict(length=8, term=None)]], 
 239          "AsString": lambda x: ("%08x-%04x-%04x-%s" % ( 
 240              x.Data1, x.Data2, x.Data3, x.Data4.v().encode('hex'))).upper(), 
 241          }], 
 242   
 243      '_MMVAD_LONG': [None, { 
 244          'FirstPrototypePte': [None, ["Pointer", dict( 
 245              target="Array", 
 246              target_args=dict( 
 247                  target="_MMPTE" 
 248                  ) 
 249              )]], 
 250          }], 
 251   
 252      '_MMVAD_FLAGS': [None, { 
 253          # Vad Protections. Also known as page protections. The 
 254          # _MMVAD_FLAGS.Protection, 3-bits, is an index into 
 255          # nt!MmProtectToValue (the following list). 
 256          'ProtectionEnum': lambda x: x.cast( 
 257              "Enumeration", 
 258              choices={ 
 259                  0: 'NOACCESS', 
 260                  1: 'READONLY', 
 261                  2: 'EXECUTE', 
 262                  3: 'EXECUTE_READ', 
 263                  4: 'READWRITE', 
 264                  5: 'WRITECOPY', 
 265                  6: 'EXECUTE_READWRITE', 
 266                  7: 'EXECUTE_WRITECOPY', 
 267                  8: 'NOACCESS', 
 268                  9: 'NOCACHE | READONLY', 
 269                  10:'NOCACHE | EXECUTE', 
 270                  11:'NOCACHE | EXECUTE_READ', 
 271                  12:'NOCACHE | READWRITE', 
 272                  13:'NOCACHE | WRITECOPY', 
 273                  14:'NOCACHE | EXECUTE_READWRITE', 
 274                  15:'NOCACHE | EXECUTE_WRITECOPY', 
 275                  16:'NOACCESS', 
 276                  17:'GUARD | READONLY', 
 277                  18:'GUARD | EXECUTE', 
 278                  19:'GUARD | EXECUTE_READ', 
 279                  20:'GUARD | READWRITE', 
 280                  21:'GUARD | WRITECOPY', 
 281                  22:'GUARD | EXECUTE_READWRITE', 
 282                  23:'GUARD | EXECUTE_WRITECOPY', 
 283                  24:'NOACCESS', 
 284                  25:'WRITECOMBINE | READONLY', 
 285                  26:'WRITECOMBINE | EXECUTE', 
 286                  27:'WRITECOMBINE | EXECUTE_READ', 
 287                  28:'WRITECOMBINE | READWRITE', 
 288                  29:'WRITECOMBINE | WRITECOPY', 
 289                  30:'WRITECOMBINE | EXECUTE_READWRITE', 
 290                  31:'WRITECOMBINE | EXECUTE_WRITECOPY', 
 291                  }, 
 292              value=x.m("Protection")), 
 293   
 294          # Vad Types. The _MMVAD_SHORT.u.VadFlags (_MMVAD_FLAGS) struct on XP 
 295          # has individual flags, 1-bit each, for these types. The 
 296          # _MMVAD_FLAGS for all OS after XP has a member of the 
 297          # _MMVAD_FLAGS.VadType, 3-bits, which is an index into the following 
 298          # enumeration. 
 299          "VadTypeEnum": lambda x: x.cast( 
 300              "Enumeration", 
 301              choices={ 
 302                  0: 'VadNone', 
 303                  1: 'VadDevicePhysicalMemory', 
 304                  2: 'VadImageMap', 
 305                  3: 'VadAwe', 
 306                  4: 'VadWriteWatch', 
 307                  5: 'VadLargePages', 
 308                  6: 'VadRotatePhysical', 
 309                  7: 'VadLargePageSection', 
 310                  }, 
 311              value=x.m("VadType")), 
 312          }], 
 313   
 314      # The environment is a null termionated _UNICODE_STRING array. Print with 
 315      # list(eprocess.Peb.ProcessParameters.Environment) 
 316      '_RTL_USER_PROCESS_PARAMETERS': [None, { 
 317          'Environment': [None, ['Pointer', dict( 
 318              target='SentinelListArray', 
 319              target_args=dict( 
 320                  target="UnicodeString", 
 321                  ) 
 322              )]], 
 323          }], 
 324   
 325      '_DEVICE_OBJECT': [None, { 
 326          'DeviceType': [None, ['Enumeration', dict(choices={ 
 327              0x00000027 : 'FILE_DEVICE_8042_PORT', 
 328              0x00000032 : 'FILE_DEVICE_ACPI', 
 329              0x00000029 : 'FILE_DEVICE_BATTERY', 
 330              0x00000001 : 'FILE_DEVICE_BEEP', 
 331              0x0000002a : 'FILE_DEVICE_BUS_EXTENDER', 
 332              0x00000002 : 'FILE_DEVICE_CD_ROM', 
 333              0x00000003 : 'FILE_DEVICE_CD_ROM_FILE_SYSTEM', 
 334              0x00000030 : 'FILE_DEVICE_CHANGER', 
 335              0x00000004 : 'FILE_DEVICE_CONTROLLER', 
 336              0x00000005 : 'FILE_DEVICE_DATALINK', 
 337              0x00000006 : 'FILE_DEVICE_DFS', 
 338              0x00000035 : 'FILE_DEVICE_DFS_FILE_SYSTEM', 
 339              0x00000036 : 'FILE_DEVICE_DFS_VOLUME', 
 340              0x00000007 : 'FILE_DEVICE_DISK', 
 341              0x00000008 : 'FILE_DEVICE_DISK_FILE_SYSTEM', 
 342              0x00000033 : 'FILE_DEVICE_DVD', 
 343              0x00000009 : 'FILE_DEVICE_FILE_SYSTEM', 
 344              0x0000003a : 'FILE_DEVICE_FIPS', 
 345              0x00000034 : 'FILE_DEVICE_FULLSCREEN_VIDEO', 
 346              0x0000000a : 'FILE_DEVICE_INPORT_PORT', 
 347              0x0000000b : 'FILE_DEVICE_KEYBOARD', 
 348              0x0000002f : 'FILE_DEVICE_KS', 
 349              0x00000039 : 'FILE_DEVICE_KSEC', 
 350              0x0000000c : 'FILE_DEVICE_MAILSLOT', 
 351              0x0000002d : 'FILE_DEVICE_MASS_STORAGE', 
 352              0x0000000d : 'FILE_DEVICE_MIDI_IN', 
 353              0x0000000e : 'FILE_DEVICE_MIDI_OUT', 
 354              0x0000002b : 'FILE_DEVICE_MODEM', 
 355              0x0000000f : 'FILE_DEVICE_MOUSE', 
 356              0x00000010 : 'FILE_DEVICE_MULTI_UNC_PROVIDER', 
 357              0x00000011 : 'FILE_DEVICE_NAMED_PIPE', 
 358              0x00000012 : 'FILE_DEVICE_NETWORK', 
 359              0x00000013 : 'FILE_DEVICE_NETWORK_BROWSER', 
 360              0x00000014 : 'FILE_DEVICE_NETWORK_FILE_SYSTEM', 
 361              0x00000028 : 'FILE_DEVICE_NETWORK_REDIRECTOR', 
 362              0x00000015 : 'FILE_DEVICE_NULL', 
 363              0x00000016 : 'FILE_DEVICE_PARALLEL_PORT', 
 364              0x00000017 : 'FILE_DEVICE_PHYSICAL_NETCARD', 
 365              0x00000018 : 'FILE_DEVICE_PRINTER', 
 366              0x00000019 : 'FILE_DEVICE_SCANNER', 
 367              0x0000001c : 'FILE_DEVICE_SCREEN', 
 368              0x00000037 : 'FILE_DEVICE_SERENUM', 
 369              0x0000001a : 'FILE_DEVICE_SERIAL_MOUSE_PORT', 
 370              0x0000001b : 'FILE_DEVICE_SERIAL_PORT', 
 371              0x00000031 : 'FILE_DEVICE_SMARTCARD', 
 372              0x0000002e : 'FILE_DEVICE_SMB', 
 373              0x0000001d : 'FILE_DEVICE_SOUND', 
 374              0x0000001e : 'FILE_DEVICE_STREAMS', 
 375              0x0000001f : 'FILE_DEVICE_TAPE', 
 376              0x00000020 : 'FILE_DEVICE_TAPE_FILE_SYSTEM', 
 377              0x00000038 : 'FILE_DEVICE_TERMSRV', 
 378              0x00000021 : 'FILE_DEVICE_TRANSPORT', 
 379              0x00000022 : 'FILE_DEVICE_UNKNOWN', 
 380              0x0000002c : 'FILE_DEVICE_VDM', 
 381              0x00000023 : 'FILE_DEVICE_VIDEO', 
 382              0x00000024 : 'FILE_DEVICE_VIRTUAL_DISK', 
 383              0x00000025 : 'FILE_DEVICE_WAVE_IN', 
 384              0x00000026 : 'FILE_DEVICE_WAVE_OUT', 
 385              })]], 
 386          }], 
 387      '_DRIVER_OBJECT': [None, { 
 388          'MajorFunction': [None, ['IndexedArray', dict( 
 389              index_table={ 
 390                  'IRP_MJ_CREATE': 0, 
 391                  'IRP_MJ_CREATE_NAMED_PIPE': 1, 
 392                  'IRP_MJ_CLOSE': 2, 
 393                  'IRP_MJ_READ': 3, 
 394                  'IRP_MJ_WRITE': 4, 
 395                  'IRP_MJ_QUERY_INFORMATION': 5, 
 396                  'IRP_MJ_SET_INFORMATION': 6, 
 397                  'IRP_MJ_QUERY_EA': 7, 
 398                  'IRP_MJ_SET_EA': 8, 
 399                  'IRP_MJ_FLUSH_BUFFERS': 9, 
 400                  'IRP_MJ_QUERY_VOLUME_INFORMATION': 10, 
 401                  'IRP_MJ_SET_VOLUME_INFORMATION': 11, 
 402                  'IRP_MJ_DIRECTORY_CONTROL': 12, 
 403                  'IRP_MJ_FILE_SYSTEM_CONTROL': 13, 
 404                  'IRP_MJ_DEVICE_CONTROL': 14, 
 405                  'IRP_MJ_INTERNAL_DEVICE_CONTROL': 15, 
 406                  'IRP_MJ_SHUTDOWN': 16, 
 407                  'IRP_MJ_LOCK_CONTROL': 17, 
 408                  'IRP_MJ_CLEANUP': 18, 
 409                  'IRP_MJ_CREATE_MAILSLOT': 19, 
 410                  'IRP_MJ_QUERY_SECURITY': 20, 
 411                  'IRP_MJ_SET_SECURITY': 21, 
 412                  'IRP_MJ_POWER': 22, 
 413                  'IRP_MJ_SYSTEM_CONTROL': 23, 
 414                  'IRP_MJ_DEVICE_CHANGE': 24, 
 415                  'IRP_MJ_QUERY_QUOTA': 25, 
 416                  'IRP_MJ_SET_QUOTA': 26, 
 417                  'IRP_MJ_PNP': 27 
 418                  }, 
 419              target="Pointer", 
 420              target_args=dict(target="Function"), 
 421              )]], 
 422          }], 
 423   
 424      # This defines _PSP_CID_TABLE as an alias for _HANDLE_TABLE. 
 425      "_PSP_CID_TABLE": "_HANDLE_TABLE", 
 426   
 427      "_LDR_DATA_TABLE_ENTRY": [None, { 
 428          "TimeDateStamp": [None, ["WinFileTime"]], 
 429          "LoadReason": lambda x: x.multi_m("LoadReason", "LoadCount") 
 430          }], 
 431   
 432      '_PHYSICAL_MEMORY_DESCRIPTOR' : [None, { 
 433          'Run' : [None, ['Array', dict( 
 434              count=lambda x: x.NumberOfRuns, 
 435              max_count=100, 
 436              target='_PHYSICAL_MEMORY_RUN')]], 
 437          }], 
 438   
 439      '_POOL_HEADER': [None, { 
 440          # Wrap the pool type in an enumeration. 
 441          'PoolType': lambda x: x.cast("Enumeration", 
 442                                       enum_name="_POOL_TYPE", 
 443                                       value=x.m("PoolType")), 
 444          'Tag': lambda x: str(x.PoolTag.cast("String", length=4)), 
 445          }], 
 446   
 447      '_DISPATCHER_HEADER': [None, { 
 448          "Type": [None, ["Enumeration", dict( 
 449              choices=undocumented.ENUMS["_KOBJECTS"], 
 450              target="unsigned char", 
 451              )]], 
 452          }], 
 453   
 454      '_CM_NAME_CONTROL_BLOCK' : [None, { 
 455          'Name' : [None, ['String', dict(length=lambda x: x.NameLength)]], 
 456          }], 
 457   
 458      # Memory manager enums. 
 459      '_MMPTE': [None, { 
 460          "Long": lambda x: x.multi_m("u.VolatileLong", "u.Long").v(), 
 461      }], 
 462   
 463      '_MMPTE_SOFTWARE': [None, { 
 464          "Protection": lambda x: x.cast( 
 465              "Enumeration", 
 466              choices=MM_PROTECTION_ENUM, 
 467              value=x.m("Protection")), 
 468          }], 
 469   
 470      '_MMPTE_PROTOTYPE': [None, { 
 471          "Protection": lambda x: x.cast( 
 472              "Enumeration", 
 473              choices=MM_PROTECTION_ENUM, 
 474              value=x.m("Protection")), 
 475   
 476          "Proto": lambda x: x.cast( 
 477              "Pointer", 
 478              target="_MMPTE", 
 479              value=x.m("ProtoAddress"), 
 480              vm=x.obj_session.GetParameter("default_address_space"), 
 481              ), 
 482          }], 
 483   
 484      '_MMPTE_SUBSECTION': [None, { 
 485          "Protection": lambda x: x.cast( 
 486              "Enumeration", 
 487              choices=MM_PROTECTION_ENUM, 
 488              value=x.m("Protection")), 
 489   
 490          "Subsection": lambda x: x.cast( 
 491              "Pointer", 
 492              target="_SUBSECTION", 
 493              value=x.m("SubsectionAddress"), 
 494              ), 
 495          }], 
 496   
 497      '_MMPTE_TRANSITION': [None, { 
 498          "Protection": lambda x: x.cast( 
 499              "Enumeration", 
 500              choices=MM_PROTECTION_ENUM, 
 501              value=x.m("Protection")), 
 502          }], 
 503   
 504      '_SECTION_OBJECT_POINTERS': [None, { 
 505          'DataSectionObject': [None, ['Pointer', dict( 
 506              target="_CONTROL_AREA" 
 507              )]], 
 508   
 509          'SharedCacheMap': [None, ['Pointer', dict( 
 510              target="_SHARED_CACHE_MAP" 
 511              )]], 
 512   
 513          'ImageSectionObject': [None, ['Pointer', dict( 
 514              target="_CONTROL_AREA" 
 515              )]], 
 516   
 517          }], 
 518   
 519      '_CONTROL_AREA': [None, { 
 520          'FilePointer': lambda x: x.m('FilePointer').dereference_as( 
 521              "_FILE_OBJECT"), 
 522   
 523          # The first subsection immediately follows the control area. 
 524          'FirstSubsection': lambda x: x.cast( 
 525              "_SUBSECTION", offset=x.obj_end), 
 526      }], 
 527   
 528      '_SUBSECTION': [None, { 
 529          'SubsectionBase': [None, ['Pointer', dict( 
 530              target='Array', 
 531              target_args=dict( 
 532                  count=lambda x: x.PtesInSubsection.v(), 
 533                  target='_MMPTE' 
 534              ) 
 535          )]], 
 536      }], 
 537   
 538      '_SHARED_CACHE_MAP': [None, { 
 539          'Vacbs': [None, ['Pointer', dict( 
 540              target="Array", 
 541              target_args=dict( 
 542                  target="Pointer", 
 543                  target_args=dict( 
 544                      target="_VACB" 
 545                  ) 
 546              ) 
 547          )]], 
 548      }], 
 549   
 550      '_VACB_ARRAY_HEADER': [None, { 
 551          'VACBs': lambda x: x.cast( 
 552              "Array", 
 553              offset=x.obj_end, 
 554              target="_VACB", 
 555              count=4095 
 556          ), 
 557      }], 
 558      '_PEB32': [None, { 
 559          "Ldr": [None, ["Pointer32", { 
 560              "target": "_PEB_LDR_DATA32" 
 561          }]] 
 562      }], 
 563      '_PEB_LDR_DATA32': [48, { 
 564          "EntryInProgress": [36, ["Pointer32", { 
 565              "target": "Void" 
 566          }]], 
 567          "InInitializationOrderModuleList": [28, ["LIST_ENTRY32", {}]], 
 568          "InLoadOrderModuleList": [12, ["LIST_ENTRY32", {}]], 
 569          "InMemoryOrderModuleList": [20, ["LIST_ENTRY32", {}]], 
 570          "Initialized": [4, ["unsigned char", {}]], 
 571          "Length": [0, ["unsigned long", {}]], 
 572          "ShutdownInProgress": [40, ["unsigned char", {}]], 
 573          "ShutdownThreadId": [44, ["Pointer32", { 
 574              "target": "Void" 
 575          }]], 
 576          "SsHandle": [8, ["Pointer32", { 
 577              "target": "Void" 
 578          }]] 
 579      }], 
 580      '_LDR_DATA_TABLE_ENTRY32': [76, { 
 581          "InLoadOrderLinks": [0, ["LIST_ENTRY32", {}]], 
 582          "InMemoryOrderLinks": [8, ["LIST_ENTRY32", {}]], 
 583          "InInitializationOrderLinks": [16, ["LIST_ENTRY32", {}]], 
 584          "DllBase": [24, ["Pointer32", { 
 585              "target": "Void" 
 586          }]], 
 587          "EntryPoint": [28, ["Pointer32", { 
 588              "target": "Void" 
 589          }]], 
 590          "SizeOfImage": [32, ["unsigned long", {}]], 
 591          "FullDllName": [36, ["_UNICODE_STRING32", {}]], 
 592          "BaseDllName": [44, ["_UNICODE_STRING32", {}]], 
 593          "Flags": [52, ["unsigned long", {}]], 
 594          "LoadReason": [56, ["unsigned short", {}]], 
 595          "TlsIndex": [58, ["unsigned short", {}]], 
 596          "HashLinks": [60, ["LIST_ENTRY32", {}]], 
 597          "TimeDateStamp": [68, ["unsigned long", {}]], 
 598          "EntryPointActivationContext": [72, ["Pointer32", { 
 599              "target": "_ACTIVATION_CONTEXT" 
 600          }]] 
 601      }] 
 602  } 
 603   
 604  windows_overlay["_RTL_BITMAP_EX"] = windows_overlay["_RTL_BITMAP"] 
605 606 607 -class _LDR_DATA_TABLE_ENTRY(obj.Struct):
608 609 @utils.safe_property
610 - def name(self):
611 return unicode(self.BaseDllName)
612 613 @utils.safe_property
614 - def size(self):
615 return int(self.SizeOfImage)
616 617 @utils.safe_property
618 - def base(self):
619 return int(self.DllBase)
620 621 @utils.safe_property
622 - def filename(self):
623 object_tree_plugin = self.obj_session.plugins.object_tree() 624 return object_tree_plugin.FileNameWithDrive(unicode(self.FullDllName))
625 626 @utils.safe_property
627 - def end(self):
628 """The end address of this module's code in memory.""" 629 return int(self.DllBase) + int(self.SizeOfImage)
630 631 @utils.safe_property
632 - def RSDS(self):
633 helper = pe_vtypes.PE(address_space=self.obj_vm, 634 image_base=self.DllBase, 635 session=self.obj_session) 636 637 return helper.RSDS
638
639 640 -class _UNICODE_STRING(obj.Struct):
641 """Class representing a _UNICODE_STRING 642 643 Adds the following behavior: 644 * The Buffer attribute is presented as a Python string rather 645 than a pointer to an unsigned short. 646 * The __unicode__ method returns the value of the Buffer. 647 """ 648
649 - def v(self, vm=None):
650 length = self.Length.v(vm=vm) 651 if length > 0 and length <= 1024: 652 data = self.Buffer.dereference_as( 653 'UnicodeString', 654 target_args=dict( 655 length=length), 656 vm=vm) 657 return data.v() 658 else: 659 return u''
660
661 - def __nonzero__(self):
662 ## Unicode strings are valid if they point at a valid memory 663 return bool(self.Buffer)
664
665 - def __eq__(self, other):
666 return unicode(self) == utils.SmartUnicode(other)
667
668 - def __unicode__(self):
669 return self.v().strip("\x00") or u""
670
671 - def __repr__(self):
672 value = utils.SmartStr(self) 673 elide = "" 674 if len(value) > 50: 675 elide = "..." 676 value = value[:50] 677 678 return "%s (%s%s)" % (super(_UNICODE_STRING, self).__repr__(), 679 value, elide)
680
681 - def write(self, string):
682 self.Buffer.dereference().write(string) 683 self.Length = len(string) * 2
684
685 -class _LUID(obj.Struct):
686 """A Locally unique identifier.""" 687
688 - def v(self):
689 return (self.HighPart.v() << 32) + self.LowPart.v()
690
691 692 -class _SID(obj.Struct):
693 """SID Structure. 694 695 Ref: 696 http://searchwindowsserver.techtarget.com/feature/The-structure-of-a-SID 697 """ 698
699 - def __unicode__(self):
700 """ 701 Ref: RtlConvertSidToUnicodeString 702 http://doxygen.reactos.org/d9/d9b/lib_2rtl_2sid_8c_source.html 703 """ 704 wcs = "S-1-" 705 706 if (self.IdentifierAuthority.Value[0] == 0 and 707 self.IdentifierAuthority.Value[1] == 0): 708 wcs += "%lu" % ( 709 self.IdentifierAuthority.Value[2] << 24 | 710 self.IdentifierAuthority.Value[3] << 16 | 711 self.IdentifierAuthority.Value[4] << 8 | 712 self.IdentifierAuthority.Value[5]) 713 else: 714 wcs += "0x%02hx%02hx%02hx%02hx%02hx%02hx" % ( 715 self.IdentifierAuthority.Value[0], 716 self.IdentifierAuthority.Value[1], 717 self.IdentifierAuthority.Value[2], 718 self.IdentifierAuthority.Value[3], 719 self.IdentifierAuthority.Value[4], 720 self.IdentifierAuthority.Value[5]) 721 722 for i in self.SubAuthority: 723 wcs += "-%u" % i 724 725 return wcs
726
727 728 -class _EPROCESS(obj.Struct):
729 """ An extensive _EPROCESS with bells and whistles """ 730 731 @utils.safe_property
732 - def address_mode(self):
733 # If this is a Wow64 process, address_mode is 32 bit. 734 if self.IsWow64: 735 return "I386" 736 737 return self.obj_session.profile.metadata("arch")
738
739 - def is_valid(self):
740 """Validate the _EPROCESS.""" 741 pid = self.pid 742 743 # PID must be in a reasonable range. 744 if pid < 0 or pid > 0xFFFF: 745 return False 746 747 # Since we're not validating memory pages anymore it's important 748 # to weed out zero'd structs. 749 if ((pid == 0 or self.CreateTime == 0) and 750 self.ImageFileName not in ("Idle", "System")): 751 return False 752 753 # Dispatch header must be for a process object. 754 if self.Pcb.Header.Type != "ProcessObject": 755 return False 756 757 return True
758 759 @utils.safe_property
760 - def Peb(self):
761 """ Returns a _PEB object which is using the process address space. 762 763 The PEB structure is referencing back into the process address 764 space so we need to switch address spaces when we look at 765 it. This method ensure this happens automatically. 766 """ 767 return self.m("Peb").cast("Pointer", target="_PEB", 768 vm=self.get_process_address_space())
769 770 @utils.safe_property
771 - def Wow64Process(self):
772 return self.m("Wow64Process").cast( 773 "Pointer", target="_PEB32", vm=self.get_process_address_space())
774 775 @utils.safe_property
776 - def IsWow64(self):
777 """Returns True if this is a wow64 process. 778 779 We check for a valid or non zero Wow64Process pointer. 780 781 Possible values: 782 783 32 bit OS: Wow64Process is missing from _EPROCESS and therefore this 784 is not a Wow64 process (but it is 32 bits). 785 64 bit OS but Wow64Process is NULL pointer: Not Wow64 process. 786 64 bit OS and Wow64Process is valid: It is a Wow64 process. 787 """ 788 return bool(self.Wow64Process.v())
789 790 @utils.safe_property
791 - def SessionId(self):
792 """Returns the Session ID of the process""" 793 794 if self.Session.is_valid(): 795 process_space = self.get_process_address_space() 796 if process_space: 797 return self.obj_profile._MM_SESSION_SPACE( 798 offset=self.Session, vm=process_space).SessionId 799 800 return obj.NoneObject("Cannot find process session")
801 802 @utils.safe_property
803 - def FullPath(self):
804 """Return the full path of image loaded. Obtained via the VAD root.""" 805 for vad in self.RealVadRoot.traverse(): 806 if (vad.Start <= self.SectionBaseAddress and 807 vad.End >= self.SectionBaseAddress): 808 809 try: 810 file_obj = vad.ControlArea.FilePointer 811 return file_obj.file_name_with_drive() 812 except AttributeError: 813 continue 814 815 return obj.NoneObject()
816
817 - def __repr__(self):
818 return "%s (pid=%s)" % (super(_EPROCESS, self).__repr__(), self.pid)
819
820 - def get_process_address_space(self):
821 """ Gets a process address space for a task given in _EPROCESS """ 822 directory_table_base = self.Pcb.DirectoryTableBase.v() 823 824 try: 825 process_as = self.obj_vm.__class__( 826 base=self.obj_vm.base, session=self.obj_vm.session, 827 dtb=directory_table_base) 828 except addrspace.ASAssertionError as e: 829 return obj.NoneObject("Unable to get process AS: %s" % e) 830 831 process_as.name = "Process {0}".format(self.UniqueProcessId) 832 833 return process_as
834
835 - def _get_modules(self, the_list, the_type, wow64=False):
836 """Generator for DLLs in one of the 3 PEB lists""" 837 if self.UniqueProcessId and the_list: 838 if wow64: 839 for l in the_list.list_of_type( 840 "_LDR_DATA_TABLE_ENTRY32", the_type): 841 yield l 842 else: 843 for l in the_list.list_of_type( 844 "_LDR_DATA_TABLE_ENTRY", the_type): 845 yield l
846
847 - def get_init_modules(self):
848 return chain( 849 self._get_modules( 850 self.Peb.Ldr.InInitializationOrderModuleList, 851 "InInitializationOrderLinks"), 852 self._get_modules( 853 self.Wow64Process.Ldr.InInitializationOrderModuleList, 854 "InInitializationOrderLinks", wow64=True))
855
856 - def get_mem_modules(self):
857 return chain( 858 self._get_modules( 859 self.Peb.Ldr.InMemoryOrderModuleList, "InMemoryOrderLinks"), 860 self._get_modules( 861 self.Wow64Process.Ldr.InMemoryOrderModuleList, 862 "InMemoryOrderLinks", wow64=True))
863
864 - def get_load_modules(self):
865 return chain( 866 self._get_modules(self.Peb.Ldr.InLoadOrderModuleList, 867 "InLoadOrderLinks"), 868 self._get_modules(self.Wow64Process.Ldr.InLoadOrderModuleList, 869 "InLoadOrderLinks", wow64=True))
870
871 - def get_token(self):
872 """Return the process's TOKEN object if its valid""" 873 874 # The dereference checks if the address is valid 875 # and returns obj.NoneObject if it fails 876 token = self.Token.dereference_as("_TOKEN") 877 878 # This check fails if the above dereference failed 879 # or if any of the _TOKEN specific validity tests failed. 880 if token.is_valid(): 881 return token 882 883 return obj.NoneObject("Cannot get process Token")
884
885 - def ObReferenceObjectByHandle(self, handle, type=None):
886 """Search the object table and retrieve the object by handle. 887 888 Args: 889 handle: The handle we search for. 890 type: The object will be cast to this type. 891 """ 892 for h in self.ObjectTable.handles(): 893 if h.HandleValue == handle: 894 if type is None: 895 return h 896 else: 897 return h.dereference_as(type) 898 899 return obj.NoneObject("Could not find handle in ObjectTable")
900
901 902 -class _MM_SESSION_SPACE(obj.Struct):
903 """Windows separates processes into Sessions. 904 905 Sessions are logically similar groups of processes (e.g. all created as part 906 of the same RDP login). The virtual address space is divided into three main 907 parts: 908 909 - The process range - This memory is unique to each process. 910 911 - The kernel space - all regular kernel memory is mapped into all processes. 912 913 - The session space - This part of the address space is different for each 914 session, but is shared by all processes in the same session. 915 """ 916
917 - def processes(self):
918 """Generator for processes in this session. 919 920 A process is always associated with exactly 921 one session. 922 """ 923 for p in self.ProcessList.list_of_type( 924 "_EPROCESS", "SessionProcessLinks"): 925 yield p
926
927 928 -class _POOL_HEADER(obj.Struct):
929 """Extension to support retrieving allocations inside the pool. 930 931 Ref for windows memory management: 932 http://illmatics.com/Windows%208%20Heap%20Internals.pdf 933 """ 934
935 - def get_rounded_size(self, object_name):
936 """Returns the size of the object accounting for pool alignment.""" 937 size_of_obj = self.obj_profile.get_obj_size(object_name) 938 pool_align = self.obj_profile.get_constant("PoolAlignment") 939 940 # Size is rounded to pool alignment 941 extra = size_of_obj % pool_align 942 if extra: 943 size_of_obj += pool_align - extra 944 945 return size_of_obj
946 947 @utils.safe_property
948 - def size(self):
949 pool_align = self.obj_profile.get_constant("PoolAlignment") 950 return self.BlockSize * pool_align
951
952 - def end(self):
953 return self.obj_offset + self.obj_size
954
955 - def GetObject(self, type=None, freed=True):
956 """Return the first object header found. 957 958 Args: 959 type: If specified we only get the object if it belong to this type. 960 freed: If True we consider also freed objects. 961 """ 962 for item in self.IterObject(type=type, freed=freed): 963 return item 964 965 return obj.NoneObject("No object found.")
966
967 - def IterObject(self, type=None, freed=True):
968 """Gets the _OBJECT_HEADER considering optional headers.""" 969 pool_align = self.obj_profile.get_constant("PoolAlignment") 970 allocation_size = self.BlockSize * pool_align 971 972 # Operate on a cached version of the next page. 973 # We use a temporary buffer for the object to save reads of the image. 974 cached_data = self.obj_vm.read(self.obj_offset + self.obj_size, 975 allocation_size) 976 cached_vm = addrspace.BufferAddressSpace( 977 data=cached_data, session=self.obj_session) 978 979 # We search for the _OBJECT_HEADER.InfoMask in close proximity to our 980 # object. We build a lookup table between the values in the InfoMask and 981 # the minimum distance there is between the start of _OBJECT_HEADER and 982 # the end of _POOL_HEADER. This way we can quickly skip unreasonable 983 # values. 984 985 for i in range(0, allocation_size, pool_align): 986 # Create a test object header from the cached vm to test for 987 # validity. 988 test_object = self.obj_profile._OBJECT_HEADER( 989 offset=i, vm=cached_vm) 990 991 optional_preamble = max(test_object.NameInfoOffset, 992 test_object.HandleInfoOffset, 993 test_object.QuotaInfoOffset) 994 995 # Obviously wrong because we need more space than we have. 996 if optional_preamble > i: 997 continue 998 999 if test_object.is_valid(): 1000 # Test for the type. 1001 if (type is None or 1002 test_object.get_object_type() == type or 1003 # Freed objects have a type pointing to 0xbad0b0b0. 1004 (freed and test_object.Type.v() == 0xbad0b0b0)): 1005 yield self.obj_profile._OBJECT_HEADER( 1006 offset=i + self.obj_offset + self.obj_size, 1007 vm=self.obj_vm, parent=self)
1008 1009 @utils.safe_property
1010 - def FreePool(self):
1011 return self.PoolType.v() == 0
1012 1013 @utils.safe_property
1014 - def NonPagedPool(self):
1015 return str(self.PoolType).startswith("NonPagedPool")
1016 1017 @utils.safe_property
1018 - def PagedPool(self):
1019 return str(self.PoolType).startswith("PagedPool")
1020
1021 - def Body(self, type):
1022 return self.obj_profile.Object(type, offset=self.obj_end, 1023 vm=self.obj_vm)
1024
1025 1026 -class _TOKEN(obj.Struct):
1027 """A class for Tokens""" 1028
1029 - def is_valid(self):
1030 """Override BaseObject.is_valid with some additional 1031 checks specific to _TOKEN objects.""" 1032 return (super(_TOKEN, self).is_valid() and 1033 self.TokenInUse in (0, 1) and self.SessionId < 10)
1034
1035 - def get_sids(self):
1036 """Generator for process SID strings""" 1037 if self.UserAndGroupCount < 0xFFFF: 1038 for sa in self.UserAndGroups.dereference(): 1039 sid = sa.Sid.dereference_as('_SID') 1040 for i in sid.IdentifierAuthority.Value: 1041 id_auth = i 1042 yield "S-" + "-".join(str(i) for i in (sid.Revision, id_auth) + 1043 tuple(sid.SubAuthority))
1044
1045 1046 -class _ETHREAD(obj.Struct):
1047 """ A class for threads """ 1048
1049 - def owning_process(self):
1050 """Return the EPROCESS that owns this thread""" 1051 return self.Tcb.ApcState.Process.dereference_as("_EPROCESS")
1052
1053 - def attached_process(self):
1054 """Return the EPROCESS that this thread is currently 1055 attached to.""" 1056 return self.Tcb.ApcState.Process.dereference_as("_EPROCESS")
1057
1058 1059 -class _HANDLE_TABLE(obj.Struct):
1060 """ A class for _HANDLE_TABLE. 1061 1062 This used to be a member of _EPROCESS but it was isolated per issue 1063 91 so that it could be subclassed and used to service other handle 1064 tables, such as the _KDDEBUGGER_DATA64.PspCidTable. 1065 """ 1066
1067 - def get_item(self, entry):
1068 """Returns the OBJECT_HEADER of the associated handle. The parent 1069 is the _HANDLE_TABLE_ENTRY so that an object can be linked to its 1070 GrantedAccess. 1071 """ 1072 return entry.Object.dereference_as("_OBJECT_HEADER", parent=entry)
1073
1074 - def _make_handle_array(self, table_offset, level):
1075 """ Returns an array of _HANDLE_TABLE_ENTRY rooted at offset, 1076 and iterates over them. 1077 """ 1078 # level == 0 means we are at the bottom level and this is a table of 1079 # _HANDLE_TABLE_ENTRY, otherwise, it means we are a table of pointers to 1080 # lower tables. 1081 if level == 0: 1082 table = self.obj_profile.Array( 1083 offset=table_offset, 1084 target="_HANDLE_TABLE_ENTRY", 1085 size=0x1000) 1086 1087 for entry in table: 1088 yield self.get_item(entry) 1089 1090 else: 1091 table = self.obj_profile.PointerArray( 1092 offset=table_offset, size=0x1000) 1093 1094 for entry in table: 1095 if entry: 1096 for item in self._make_handle_array(entry, level-1): 1097 yield item
1098
1099 - def handles(self):
1100 """ A generator which yields this process's handles 1101 1102 _HANDLE_TABLE tables are multi-level tables at the first level 1103 they are pointers to second level table, which might be 1104 pointers to third level tables etc, until the final table 1105 contains the real _OBJECT_HEADER table. 1106 1107 This generator iterates over all the handles recursively 1108 yielding all handles. We take care of recursing into the 1109 nested tables automatically. 1110 1111 Reference: 1112 http://forum.sysinternals.com/hiding-a-process-pspcidtable_topic15362.html 1113 """ 1114 # This should work equally for 32 and 64 bit systems 1115 LEVEL_MASK = 7 1116 1117 table = self.TableCode & ~LEVEL_MASK 1118 level = self.TableCode & LEVEL_MASK 1119 1120 for i, handle in enumerate(self._make_handle_array(table, level)): 1121 # New object header uses TypeIndex. 1122 if handle.m("TypeIndex") > 0x0 or handle.m("Type").Name: 1123 handle.HandleValue = i * 4 1124 1125 yield handle
1126
1127 1128 -class _PSP_CID_TABLE(_HANDLE_TABLE):
1129 """Subclass the Windows handle table object for parsing PspCidTable""" 1130
1131 - def get_item(self, entry):
1132 p = self.obj_profile.Object("address", entry.Object.v(), self.obj_vm) 1133 1134 handle = self.obj_profile.Object( 1135 "_OBJECT_HEADER", 1136 offset=(p & ~7) - self.obj_profile.get_obj_offset( 1137 '_OBJECT_HEADER', 'Body'), 1138 vm=self.obj_vm) 1139 1140 return handle
1141
1142 1143 -class ObjectMixin(object):
1144 """A mixin to be applied on Object Manager Objects.""" 1145 1146 @utils.safe_property
1147 - def ObjectHeader(self):
1148 return self.obj_profile._OBJECT_HEADER( 1149 self.obj_offset - self.obj_profile.get_obj_size( 1150 "_OBJECT_HEADER"))
1151
1152 1153 -class _OBJECT_HEADER(obj.Struct):
1154 """A Rekall Memory Forensics object to handle Windows object headers. 1155 1156 This object applies only to versions below windows 7. (old version 1157 objects). See: 1158 http://codemachine.com/article_objectheader.html 1159 """ 1160 1161 # A mapping between the object type name and the struct name for it. 1162 type_lookup = dict( 1163 Device="_DEVICE_OBJECT", 1164 Directory="_OBJECT_DIRECTORY", 1165 Driver="_DRIVER_OBJECT", 1166 File="_FILE_OBJECT", 1167 Key="_CM_KEY_BODY", 1168 Mutant="_KMUTANT", 1169 Process="_EPROCESS", 1170 Section="_SECTION_OBJECT", 1171 SymbolicLink="_OBJECT_SYMBOLIC_LINK", 1172 Thread="_ETHREAD", 1173 Token="_TOKEN", 1174 ) 1175 1176 optional_headers = [ 1177 ('NameInfo', '_OBJECT_HEADER_NAME_INFO', 'NameInfoOffset'), 1178 ('HandleInfo', '_OBJECT_HEADER_HANDLE_INFO', 'HandleInfoOffset'), 1179 ('QuotaInfo', '_OBJECT_HEADER_QUOTA_INFO', 'QuotaInfoOffset')] 1180
1181 - def __init__(self, handle_value=0, **kwargs):
1182 self.HandleValue = handle_value 1183 self._preamble_size = 0 1184 super(_OBJECT_HEADER, self).__init__(**kwargs)
1185
1186 - def _GetOptionalHeader(self, struct_name, member):
1187 header_offset = self.m(member).v() 1188 if header_offset == 0: 1189 return obj.NoneObject("Header not set") 1190 1191 return self.obj_profile.Object( 1192 struct_name, offset=self.obj_offset - header_offset, 1193 vm=self.obj_vm, parent=self)
1194 1195 @utils.safe_property
1196 - def obj_size(self):
1197 """The size of the object header is actually the position of the Body 1198 element.""" 1199 return self.obj_profile.get_obj_offset("_OBJECT_HEADER", "Body")
1200
1201 - def dereference_as(self, type_name, vm=None):
1202 """Instantiate an object from the _OBJECT_HEADER.Body""" 1203 return self.obj_profile.Object( 1204 type_name=type_name, offset=self.Body.obj_offset, 1205 vm=vm or self.obj_vm, parent=self)
1206
1207 - def get_object_type(self, vm=None):
1208 """Return the object's type as a string""" 1209 type_obj = self.obj_profile._OBJECT_TYPE( 1210 vm=vm or self.obj_session.kernel_address_space, 1211 offset=self.Type) 1212 1213 return type_obj.Name.v()
1214 1215 @utils.safe_property
1216 - def Object(self):
1217 """Return the object following this header.""" 1218 required_type = self.type_lookup.get(self.get_object_type()) 1219 if required_type: 1220 return self.Body.cast(required_type) 1221 1222 return obj.NoneObject("Unknown object type")
1223 1224 1225 # Build properties for the optional headers. 1226 for _name, _y, _z in _OBJECT_HEADER.optional_headers: 1227 setattr(_OBJECT_HEADER, _name, property( 1228 lambda x, y=_y, z=_z: x._GetOptionalHeader(y, z)))
1229 1230 1231 -class _DEVICE_OBJECT(ObjectMixin, obj.Struct):
1232 """A Device Object."""
1233
1234 1235 -class _FILE_OBJECT(ObjectMixin, obj.Struct):
1236 """Class for file objects""" 1237 1238 @utils.safe_property
1239 - def AccessString(self):
1240 """Make a nicely formatted ACL string.""" 1241 return (((self.ReadAccess > 0 and "R") or '-') + 1242 ((self.WriteAccess > 0 and "W") or '-') + 1243 ((self.DeleteAccess > 0 and "D") or '-') + 1244 ((self.SharedRead > 0 and "r") or '-') + 1245 ((self.SharedWrite > 0 and "w") or '-') + 1246 ((self.SharedDelete > 0 and "d") or '-'))
1247
1248 - def file_name_with_device(self):
1249 """Return the name of the file, prefixed with the name 1250 of the device object to which the file belongs""" 1251 name = u"" 1252 if self.DeviceObject: 1253 device_name = self.DeviceObject.ObjectHeader.NameInfo.Name 1254 if device_name: 1255 name = u"\\Device\\{0}".format(device_name) 1256 1257 if self.FileName: 1258 name += unicode(self.FileName) 1259 1260 return name
1261
1262 - def file_name_with_drive(self, vm=None):
1263 """Returns the name of the file prepended with the drive letter. 1264 1265 We resolve the drive letter by matching it with the currently assigned 1266 letter to the mounted device. The result of this function should be 1267 usable by file system APIs to open the file on a live system. 1268 """ 1269 name = u"" 1270 drive_letter_device_map = self.obj_session.GetParameter( 1271 "drive_letter_device_map") 1272 1273 device_obj = self.DeviceObject.deref(vm=vm) 1274 if device_obj: 1275 device_name = device_obj.ObjectHeader.NameInfo.Name 1276 if device_name: 1277 try: 1278 name = u"\\Device\\{0}".format(device_name) 1279 except UnicodeError: 1280 return obj.NoneObject("Invalid filename") 1281 1282 if name in drive_letter_device_map: 1283 name = drive_letter_device_map.get(name) 1284 1285 filename = self.FileName.v(vm=vm) 1286 if filename: 1287 name += unicode(filename) 1288 1289 return name
1290
1291 1292 1293 -class _OBJECT_DIRECTORY(ObjectMixin, obj.Struct):
1294 """Object directories hold other objects. 1295 1296 http://msdn.microsoft.com/en-us/library/windows/hardware/ff557755(v=vs.85).aspx 1297 """ 1298
1299 - def list(self):
1300 for bucket in self.HashBuckets: 1301 for entry in bucket.walk_list("ChainLink"): 1302 target_obj_header = self.obj_profile._OBJECT_HEADER( 1303 entry.Object.v() - self.obj_profile.get_obj_size( 1304 "_OBJECT_HEADER")) 1305 1306 yield target_obj_header
1307
1308 - def __iter__(self):
1309 return self.list()
1310
1311 - def __getitem__(self, name):
1312 for item in self: 1313 if item.NameInfo.Name == name: 1314 return item 1315 1316 raise KeyError
1317
1318 1319 -class _EX_FAST_REF(obj.Struct):
1320 """This type allows instantiating an object from its .Object member.""" 1321
1322 - def __init__(self, target=None, **kwargs):
1323 self.target = target 1324 super(_EX_FAST_REF, self).__init__(**kwargs) 1325 end_bit = self.RefCnt.end_bit 1326 self.mask = ~ (2 ** end_bit - 1) 1327 self._object = None
1328
1329 - def is_valid(self):
1330 if self.Object.v() == 0: 1331 return False 1332 1333 return True
1334
1335 - def v(self):
1336 return self.m("Object").obj_offset & self.mask
1337 1338 @utils.safe_property
1339 - def Object(self):
1340 if self._object is None: 1341 result = self.m("Object") 1342 self._object = result.cast(value=result.v() & self.mask) 1343 1344 return self._object
1345
1346 - def dereference(self, vm=None):
1347 if self.target is None: 1348 raise AttributeError( 1349 "No target specified for dereferencing an _EX_FAST_REF.") 1350 1351 if not self.is_valid(): 1352 return obj.NoneObject("_EX_FAST_REF not valid") 1353 1354 return self.Object.dereference_as(self.target)
1355
1356 - def dereference_as(self, type_name, parent=None, **kwargs):
1357 """Use the _EX_FAST_REF.Object pointer to resolve an object of the 1358 specified type. 1359 """ 1360 if not self.is_valid(): 1361 return obj.NoneObject("_EX_FAST_REF not valid") 1362 1363 parent = parent or self.obj_parent or self 1364 return self.Object.dereference_as(type_name, parent=parent, **kwargs)
1365
1366 - def __getattr__(self, attr):
1367 return getattr(self.dereference(), attr)
1368
1369 1370 -class _CM_KEY_BODY(obj.Struct):
1371 """Registry key""" 1372
1373 - def full_key_name(self):
1374 output = [] 1375 kcb = self.KeyControlBlock 1376 while kcb.ParentKcb: 1377 if kcb.NameBlock.Name == None: 1378 break 1379 output.append(str(kcb.NameBlock.Name)) 1380 kcb = kcb.ParentKcb 1381 return "\\".join(reversed(output))
1382
1383 1384 -class VadTraverser(obj.Struct):
1385 """The windows Vad tree is basically the same in all versions of windows, 1386 but the exact name of the structs vary with version. This is the base class 1387 for all Vad traversor. 1388 """ 1389 ## The actual type depends on this tag value. 1390 tag_map = {'Vadl': '_MMVAD_LONG', 1391 'VadS': '_MMVAD_SHORT', 1392 'Vad ': '_MMVAD', 1393 'VadF': '_MMVAD_SHORT', 1394 'Vadm': '_MMVAD_LONG', 1395 } 1396 1397 left = "LeftChild" 1398 right = "RightChild" 1399
1400 - def traverse_as_type(self, type=None, member=None):
1401 """Traverse an AVL tree - similar to _LIST_ENTRY.list_as_type().""" 1402 relative_offset = self.obj_profile.get_obj_offset(type, member) 1403 1404 for node in self.traverse(type="_RTL_BALANCED_NODE"): 1405 yield self.obj_profile.Object( 1406 type, node.obj_offset - relative_offset)
1407
1408 - def traverse(self, visited=None, depth=0, type=None):
1409 """Traverse the VAD tree. 1410 1411 Generate all the left items, then the right items. 1412 1413 We try to be tolerant of cycles by storing all offsets visited. 1414 1415 If type is specified we always return that type instead of check the 1416 pool tag from the tag_map. 1417 1418 """ 1419 if visited == None: 1420 visited = set() 1421 1422 if depth > 100: 1423 self.obj_session.logging.error( 1424 "Vad tree too deep - something went wrong!") 1425 visited.add(self.obj_offset) 1426 return 1427 1428 ## We try to prevent loops here 1429 if self.obj_offset in visited: 1430 return 1431 1432 self.obj_context['depth'] = depth 1433 1434 # Find out which Vad type we need to be: 1435 if type is not None: 1436 yield self.cast(type) 1437 1438 elif self.Tag in self.tag_map: 1439 yield self.cast(self.tag_map[self.Tag]) 1440 1441 # This tag is valid for the Root. 1442 elif depth and self.Tag.v() != "\x00": 1443 return 1444 1445 for c in self.m(self.left).traverse(visited=visited, depth=depth+1, 1446 type=type): 1447 visited.add(self.obj_offset) 1448 yield c 1449 1450 for c in self.m(self.right).traverse(visited=visited, depth=depth+1, 1451 type=type): 1452 visited.add(self.obj_offset) 1453 yield c
1454 1467
1468 1469 -class _KTIMER(obj.Struct):
1470 @utils.safe_property
1471 - def Dpc(self):
1472 # On Windows 7 Patch guard obfuscates the DPC address. 1473 self.KiWaitNever = self.obj_profile.get_constant_object( 1474 "KiWaitNever", "unsigned long long") 1475 if not self.KiWaitNever: 1476 return self.m("Dpc") 1477 1478 self.KiWaitAlways = self.obj_profile.get_constant_object( 1479 "KiWaitAlways", "unsigned long long") 1480 1481 return self._DeobfuscateDpc()
1482
1483 - def _byteswap(self, value):
1484 return struct.unpack(">Q", struct.pack("<Q", value))[0]
1485
1486 - def _Rol64(self, value, bits):
1487 return ((value << bits % 64) & (2**64-1) | 1488 ((value & (2**64-1)) >> (64-(bits % 64))))
1489
1490 - def _DeobfuscateDpc(self):
1491 # Reference: 1492 # http://uninformed.org/index.cgi?v=8&a=5&p=10 1493 1494 # ------ nt!KiSetTimerEx ------ 1495 # MOV RAX, [RIP+0x229bf0] 0x6D7CFFA404933FBB nt!KiWaitNever 1496 # MOV RBX, [RIP+0x229cc1] 0x933DD660CFFF8004 nt!KiWaitAlways 1497 # MOV R14, [RSP+0xb0] <----- DPC 1498 # XOR RBX, R14 1499 # ... 1500 # BSWAP RBX 1501 # ... 1502 # XOR RBX, RCX <---- Timer object. 1503 # MOV ECX, EAX 1504 # ROR RBX, CL 1505 # XOR RBX, RAX <--- Obfuscated DPC 1506 Obfuscated = self.m("Dpc").cast("unsigned long long") 1507 1508 Deobfuscated = Obfuscated ^ self.KiWaitNever 1509 Deobfuscated = self._Rol64(Deobfuscated, 0xFF & self.KiWaitNever) 1510 Deobfuscated = Deobfuscated ^ (self.obj_offset | 0xffff000000000000) 1511 Deobfuscated = self._byteswap(Deobfuscated) 1512 Deobfuscated = Deobfuscated ^ int(self.KiWaitAlways) 1513 1514 return self.obj_profile._KDPC(Deobfuscated, parent=self, 1515 vm=self.obj_vm)
1516
1517 1518 -class _SHARED_CACHE_MAP(obj.Struct):
1519 @utils.safe_property
1520 - def FileObject(self):
1521 result = self.m("FileObject") 1522 if result == None: 1523 result = self.m('FileObjectFastRef').dereference_as( 1524 "_FILE_OBJECT") 1525 1526 return result
1527
1528 1529 -class _RTL_BITMAP(obj.Struct):
1530
1531 - def __getitem__(self, index):
1532 char = ord(self.Buffer[index / 8]) 1533 return bool(char & 2 ** (index % 8))
1534
1535 - def __len__(self):
1536 return int(self.SizeOfBitMap)
1537
1538 - def __iter__(self):
1539 for i in xrange(len(self)): 1540 yield self[i]
1541
1542 1543 -def InitializeWindowsProfile(profile):
1544 """Install the basic windows overlays.""" 1545 profile.add_classes({ 1546 '_RTL_BITMAP': _RTL_BITMAP, 1547 '_RTL_BITMAP_EX': _RTL_BITMAP, 1548 '_UNICODE_STRING': _UNICODE_STRING, 1549 '_UNICODE_STRING32': _UNICODE_STRING, 1550 '_EPROCESS': _EPROCESS, 1551 '_ETHREAD': _ETHREAD, 1552 '_HANDLE_TABLE': _HANDLE_TABLE, 1553 '_POOL_HEADER': _POOL_HEADER, 1554 '_OBJECT_HEADER': _OBJECT_HEADER, 1555 '_PSP_CID_TABLE': _PSP_CID_TABLE, 1556 '_FILE_OBJECT': _FILE_OBJECT, 1557 '_DEVICE_OBJECT': _DEVICE_OBJECT, 1558 '_OBJECT_DIRECTORY': _OBJECT_DIRECTORY, 1559 '_EX_FAST_REF': _EX_FAST_REF, 1560 '_CM_KEY_BODY': _CM_KEY_BODY, 1561 '_LDR_DATA_TABLE_ENTRY': _LDR_DATA_TABLE_ENTRY, 1562 '_LDR_DATA_TABLE_ENTRY32': _LDR_DATA_TABLE_ENTRY, 1563 "_MM_SESSION_SPACE": _MM_SESSION_SPACE, 1564 "_RTL_BALANCED_LINKS": _RTL_BALANCED_LINKS, 1565 "_LUID": _LUID, 1566 "_SID": _SID, 1567 "_KTIMER": _KTIMER, 1568 "_SHARED_CACHE_MAP": _SHARED_CACHE_MAP, 1569 "RVAPointer": pe_vtypes.RVAPointer, 1570 "SentinelArray": pe_vtypes.SentinelArray, 1571 "SentinelListArray": pe_vtypes.SentinelListArray, 1572 }) 1573 1574 profile.add_overlay(windows_overlay) 1575 profile.add_constant_type( 1576 "MmPfnDatabase", "Pointer", dict( 1577 target="Array", 1578 target_args=dict( 1579 target="_MMPFN" 1580 ) 1581 ) 1582 ) 1583 1584 # Pooltags for common objects (These are different in Win8). 1585 profile.add_constants(dict( 1586 DRIVER_POOLTAG="Dri\xf6", 1587 EPROCESS_POOLTAG="Pro\xe3", 1588 FILE_POOLTAG="Fil\xe5", 1589 SYMLINK_POOLTAG="Sym\xe2", 1590 MODULE_POOLTAG="MmLd", 1591 MUTANT_POOLTAG="Mut\xe1", 1592 THREAD_POOLTAG='\x54\x68\x72\xe5', 1593 )) 1594 1595 # These constants are always the same in all versions of Windows. 1596 if profile.metadata("arch") == "AMD64": 1597 # Ref: 1598 # reactos/include/xdk/amd64/ke.h:17 1599 ki_shared_data_address = 0xFFFFF78000000000 1600 else: 1601 # reactos/include/xdk/x86/ke.h:19 1602 ki_shared_data_address = 0xffdf0000 1603 1604 ki_shared_data_address = profile.integer_to_address(ki_shared_data_address) 1605 1606 def func(profile=profile): 1607 return (profile.get_constant("KI_USER_SHARED_DATA_RAW") - 1608 profile.GetImageBase())
1609 1610 profile.add_constants( 1611 dict(KI_USER_SHARED_DATA_RAW=ki_shared_data_address, 1612 KI_USER_SHARED_DATA=func 1613 ) 1614 ) 1615