Package rekall :: Package plugins :: Package windows :: Package malware :: Module cmdhistory
[frames] | no frames]

Source Code for Module rekall.plugins.windows.malware.cmdhistory

   1  # Rekall Memory Forensics 
   2  # 
   3  # Copyright 2013 Google Inc. All Rights Reserved. 
   4  # 
   5  # Authors: 
   6  # Michael Hale Ligh <michael.ligh@mnin.org> 
   7  # 
   8  # Contributors/References: 
   9  #   Richard Stevens and Eoghan Casey 
  10  #   Extracting Windows Cmd Line Details from Physical Memory. 
  11  #   http://ww.dfrws.org/2010/proceedings/stevens.pdf 
  12  #   Michael Cohen <scudette@gmail.com> 
  13  # 
  14  # This program is free software; you can redistribute it and/or modify 
  15  # it under the terms of the GNU General Public License as published by 
  16  # the Free Software Foundation; either version 2 of the License, or (at 
  17  # your option) any later version. 
  18  # 
  19  # This program is distributed in the hope that it will be useful, but 
  20  # WITHOUT ANY WARRANTY; without even the implied warranty of 
  21  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
  22  # General Public License for more details. 
  23  # 
  24  # You should have received a copy of the GNU General Public License 
  25  # along with this program; if not, write to the Free Software 
  26  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
  27  # 
  28   
  29  # pylint: disable=protected-access 
  30  from rekall import obj 
  31  from rekall.plugins.overlays import basic 
  32  from rekall.plugins.windows import common 
  33  from rekall.plugins.windows import vadinfo 
  34  from rekall.plugins.overlays.windows import pe_vtypes 
  35  from rekall_lib import utils 
  36   
  37   
  38  MAX_HISTORY_DEFAULT = 50 
  39  HISTORY_BUFFERS_DEFAULTS = 4 
  40   
  41  # The following all use these standard types. 
  42  common_types = { 
  43      '_LIST_ENTRY' : [0x8, { 
  44          'Flink' : [0x0, ['pointer', ['_LIST_ENTRY']]], 
  45          'Blink' : [0x4, ['pointer', ['_LIST_ENTRY']]], 
  46          }]} 
  47   
  48  common_types_64 = { 
  49      '_LIST_ENTRY' : [0x10, { 
  50          'Flink' : [0x0, ['pointer', ['_LIST_ENTRY']]], 
  51          'Blink' : [0x8, ['pointer', ['_LIST_ENTRY']]], 
  52          }]} 
  53   
  54  # Windows 7 Types from conhost.exe 
  55  conhost_types_x86 = { 
  56      '_COMMAND': [None, { 
  57          'CmdLength': [0x00, ['unsigned short']], 
  58          'Cmd' : [0x02, ['UnicodeString', dict( 
  59              encoding='utf16', 
  60              length=lambda x: x.CmdLength 
  61              )]], 
  62          }], 
  63      '_COMMAND_HISTORY': [None, { 
  64          'ListEntry': [0x00, ['_LIST_ENTRY']], 
  65          'Flags' : [0x08, ['Flags', dict( 
  66              bitmap={ 
  67                  'Allocated': 0, 
  68                  'Reset': 1 
  69                  } 
  70              )]], 
  71          'Application': [0x0C, ['Pointer', dict( 
  72              target='UnicodeString', 
  73              target_args=dict( 
  74                  encoding='utf16', 
  75                  length=256 
  76                  ) 
  77              )]], 
  78          'CommandCount': [0x10, ['short']], 
  79          'LastAdded': [0x12, ['short']], 
  80          'LastDisplayed': [0x14, ['short']], 
  81          'FirstCommand': [0x16, ['short']], 
  82          'CommandCountMax': [0x18, ['short']], 
  83          'ProcessHandle': [0x1C, ['unsigned int']], 
  84          'PopupList': [0x20, ['_LIST_ENTRY']], 
  85          'CommandBucket': [0x28, ['Array', dict( 
  86              count=lambda x: x.CommandCount, 
  87              target='Pointer', 
  88              target_args=dict( 
  89                  target='_COMMAND' 
  90                  ) 
  91              )]], 
  92          }], 
  93   
  94      '_ALIAS': [None, { 
  95          'ListEntry': [0x00, ['_LIST_ENTRY']], 
  96          'SourceLength': [0x08, ['unsigned short']], 
  97          'TargetLength': [0x0A, ['unsigned short']], 
  98          'Source': [0x0C, ['Pointer', dict( 
  99              target='UnicodeString', 
 100              target_args=dict( 
 101                  encoding='utf16', 
 102                  length=lambda x: x.SourceLength * 2 
 103                  ) 
 104              )]], 
 105   
 106          'Target': [0x10, ['Pointer', dict( 
 107              target='UnicodeString', 
 108              target_args=dict( 
 109                  encoding='utf16', 
 110                  length=lambda x: x.TargetLength * 2 
 111                  ) 
 112              )]], 
 113          }], 
 114      '_EXE_ALIAS_LIST' : [None, { 
 115          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 116          'ExeLength': [0x08, ['unsigned short']], 
 117          'ExeName': [0x0C, ['Pointer', dict( 
 118              target='UnicodeString', 
 119              target_args=dict( 
 120                  encoding='utf16', 
 121                  length=lambda x: x.ExeLength * 2 
 122                  ) 
 123              )]], 
 124          'AliasList': [0x10, ['_LIST_ENTRY']], 
 125          }], 
 126   
 127      '_POPUP_LIST' : [None, { 
 128          'ListEntry' : [0x00, ['_LIST_ENTRY']], 
 129          }], 
 130   
 131      '_CONSOLE_INFORMATION': [None, { 
 132          'CurrentScreenBuffer': [0x98, ['pointer', ['_SCREEN_INFORMATION']]], 
 133          'ScreenBuffer': [0x9C, ['pointer', ['_SCREEN_INFORMATION']]], 
 134          'HistoryList': [0xD4, ['_LIST_ENTRY']], 
 135          'ProcessList': [0x18, ['_LIST_ENTRY']], # SrvGetConsoleProcessList() 
 136          'ExeAliasList': [0xDC, ['_LIST_ENTRY']], # GetConsoleAliasExes() 
 137   
 138          # GetConsoleHistoryInfo() 
 139          'HistoryBufferCount': [0xE4, ['unsigned short']], 
 140   
 141          # GetConsoleHistoryInfo() 
 142          'HistoryBufferMax': [0xE6, ['unsigned short']], 
 143   
 144          'CommandHistorySize': [0xE8, ['unsigned short']], 
 145          'OriginalTitle': [0xEC, ['Pointer', dict( 
 146              target='UnicodeString', 
 147              target_args=dict( 
 148                  encoding='utf16', 
 149                  length=256 
 150                  ) 
 151              )]], # GetConsoleOriginalTitle() 
 152   
 153          'Title': [0xF0, ['Pointer', dict( 
 154              target='UnicodeString', 
 155              target_args=dict( 
 156                  encoding='utf16', 
 157                  length=256 
 158                  ) 
 159              )]], # GetConsoleTitle() 
 160          }], 
 161   
 162      '_CONSOLE_PROCESS': [None, { 
 163          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 164          'ProcessHandle': [0x8, ['unsigned int']], 
 165          }], 
 166      '_SCREEN_INFORMATION': [None, { 
 167          'ScreenX': [0x08, ['short']], 
 168          'ScreenY': [0x0A, ['short']], 
 169          'Rows': [0x3C, ['Pointer', dict( 
 170              target='Array', 
 171              target_args=dict( 
 172                  count=lambda x: x.ScreenY, 
 173                  target='_ROW' 
 174                  ) 
 175              )]], 
 176          'Next': [0xDC, ['Pointer', dict(target='_SCREEN_INFORMATION')]], 
 177          }], 
 178      '_ROW': [0x1C, { 
 179          'Chars': [0x08, ['Pointer', dict( 
 180              target='UnicodeString', 
 181              target_args=dict( 
 182                  encoding='utf16', 
 183                  length=lambda x: x.obj_parent.ScreenX * 2, 
 184                  ) 
 185              )]], 
 186          }], 
 187      } 
 188   
 189  # Windows 7 Types from conhost.exe 
 190  conhost_types_x64 = { 
 191      '_COMMAND': [None, { 
 192          'CmdLength': [0x00, ['unsigned short']], 
 193          'Cmd' : [0x02, ['UnicodeString', dict( 
 194              encoding='utf16', 
 195              length=lambda x: x.CmdLength)]], 
 196          }], 
 197      '_COMMAND_HISTORY': [None, { 
 198          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 199   
 200          # AllocateCommandHistory() 
 201          'Flags' : [0x10, ['Flags', {'bitmap': {'Allocated': 0, 'Reset': 1}}]], 
 202   
 203          # AllocateCommandHistory() 
 204          'Application': [0x18, ['Pointer', dict( 
 205              target='UnicodeString', 
 206              target_args=dict( 
 207                  encoding='utf16', 
 208                  length=256 
 209                  ) 
 210              )]], 
 211          'CommandCount': [0x20, ['short']], 
 212          'LastAdded': [0x22, ['short']], 
 213          'LastDisplayed': [0x24, ['short']], 
 214          'FirstCommand': [0x26, ['short']], 
 215          'CommandCountMax': [0x28, ['short']], # AllocateCommandHistory() 
 216          'ProcessHandle': [0x30, ['address']], # AllocateCommandHistory() 
 217          'PopupList': [0x38, ['_LIST_ENTRY']], # AllocateCommandHistory() 
 218          'CommandBucket': [0x48, ['Array', dict( 
 219              count=lambda x: x.CommandCount, 
 220              target='Pointer', 
 221              target_args=dict( 
 222                  target='_COMMAND') 
 223              )]], 
 224          }], 
 225      '_ALIAS': [None, { 
 226          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 227          'SourceLength': [0x10, ['unsigned short']], # AddAlias() 
 228          'TargetLength': [0x12, ['unsigned short']], # AddAlias() 
 229   
 230          # reversed from AddAlias() 
 231          'Source': [0x18, ['pointer', ['UnicodeString', dict( 
 232              encoding='utf16', 
 233              length=lambda x: x.SourceLength * 2)]]], 
 234   
 235          'Target': [0x20, ['pointer', ['UnicodeString', dict( 
 236              encoding='utf16', 
 237              length=lambda x: x.TargetLength * 2 
 238              )]]], # AddAlias() 
 239          }], 
 240      '_EXE_ALIAS_LIST' : [None, { 
 241          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 242          'ExeLength': [0x10, ['unsigned short']], # AddExeAliasList() 
 243   
 244          # AddExeAliasList() 
 245          'ExeName': [0x18, ['pointer', ['UnicodeString', dict( 
 246              encoding='utf16', 
 247              length=lambda x: x.ExeLength * 2)]]], 
 248   
 249          'AliasList': [0x20, ['_LIST_ENTRY']], # AddExeAliasList() 
 250          }], 
 251      '_POPUP_LIST' : [None, { 
 252          'ListEntry' : [0x00, ['_LIST_ENTRY']], 
 253          }], 
 254      '_CONSOLE_INFORMATION': [None, { 
 255          # MOV RCX, [RIP+0x25bb5]   conhost!gConsoleInformation+0x28 
 256          'ProcessList': [0x28, ['_LIST_ENTRY']], 
 257          'CurrentScreenBuffer': [0xE0, ['Pointer', dict( 
 258              target='_SCREEN_INFORMATION' 
 259              )]], # AllocateConsole() 
 260   
 261          'ScreenBuffer': [0xE8, ['Pointer', dict( 
 262              target='_SCREEN_INFORMATION' 
 263              )]], # AllocateConsole() 
 264   
 265          'HistoryList': [0x148, ['_LIST_ENTRY']], # AllocateCommandHistory() 
 266          'ExeAliasList': [0x148, ['_LIST_ENTRY']], # SrvGetConsoleAliasExes() 
 267          'HistoryBufferCount': [0x168, ['unsigned short']], # AllocateConsole() 
 268          'HistoryBufferMax': [0x16A, ['unsigned short']], # AllocateConsole() 
 269          'CommandHistorySize': [0x16C, ['unsigned short']], # AllocateConsole() 
 270   
 271          'OriginalTitle': [0x170, ['Pointer', dict( 
 272              target='UnicodeString', 
 273              target_args=dict( 
 274                  encoding='utf16', 
 275                  length=256 
 276                  ) 
 277              )]], # SrvGetConsoleTitle() 
 278   
 279          'Title': [0x178, ['Pointer', dict( 
 280              target='UnicodeString', 
 281              target_args=dict( 
 282                  encoding='utf16', 
 283                  length=256 
 284                  ) 
 285              )]], # SrvGetConsoleTitle() 
 286          }], 
 287      '_CONSOLE_PROCESS': [None, { 
 288          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 289          'ProcessHandle': [0x10, ['unsigned int']], # FindProcessInList() 
 290          }], 
 291   
 292      '_SCREEN_INFORMATION': [None, { 
 293          'ScreenX': [8, ['short']], 
 294          'ScreenY': [10, ['short']], 
 295          'Rows': [0x48, ['Pointer', dict( 
 296              target="Array", 
 297              target_args=dict( 
 298                  count=lambda x: x.ScreenY, 
 299                  target='_ROW' 
 300                  ) 
 301              )]], 
 302   
 303          'Next': [0x128, ['pointer', ['_SCREEN_INFORMATION']]], 
 304          }], 
 305      '_ROW': [0x28, { 
 306          'Chars': [0x08, ['pointer', ['UnicodeString', dict( 
 307              encoding='utf16', 
 308              length=lambda x: x.obj_parent.obj_parent.ScreenX * 2, 
 309          )]]], 
 310          }], 
 311      } 
 312   
 313  # Windows XP, 2003, 2008, Vista from winsrv.dll 
 314  winsrv_types_x86 = { 
 315      '_COMMAND': [None, { 
 316          'CmdLength': [0x00, ['unsigned short']], 
 317          'Cmd' : [0x02, ['UnicodeString', dict( 
 318              encoding='utf16', 
 319              length=lambda x: x.CmdLength 
 320              )]], 
 321          }], 
 322      '_COMMAND_HISTORY': [None, { 
 323          'Flags' : [0x00, ['Flags', { 
 324              'bitmap': { 
 325                  'Allocated': 0, 
 326                  'Reset': 1 
 327                  } 
 328              }]], 
 329          'ListEntry': [0x04, ['_LIST_ENTRY']], 
 330          'Application': [0x0C, ['pointer', ['UnicodeString', dict( 
 331              encoding='utf16', length=256)]]], 
 332          'CommandCount': [0x10, ['short']], 
 333          'LastAdded': [0x12, ['short']], 
 334          'LastDisplayed': [0x14, ['short']], 
 335          'FirstCommand': [0x16, ['short']], 
 336          'CommandCountMax': [0x18, ['short']], 
 337          'ProcessHandle': [0x1C, ['unsigned int']], 
 338          'PopupList': [0x20, ['_LIST_ENTRY']], 
 339          'CommandBucket': [0x28, ['Array', dict( 
 340              count=lambda x: x.CommandCount, 
 341              target='Pointer', 
 342              target_args=dict( 
 343                  target='_COMMAND' 
 344                  ) 
 345              )]], 
 346          }], 
 347   
 348      '_ALIAS': [None, { 
 349          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 350          'SourceLength': [0x08, ['unsigned short']], 
 351          'TargetLength': [0x0A, ['unsigned short']], 
 352          'Source': [0x0C, ['pointer', ['UnicodeString', dict( 
 353              encoding='utf16', 
 354              length=lambda x: x.SourceLength * 2 
 355              )]]], 
 356          'Target': [0x10, ['pointer', ['UnicodeString', dict( 
 357              encoding='utf16', 
 358              length=lambda x: x.TargetLength * 2)]]], 
 359          }], 
 360      '_EXE_ALIAS_LIST' : [None, { 
 361          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 362          'ExeLength': [0x08, ['unsigned short']], 
 363          'ExeName': [0x0C, ['pointer', [ 
 364              'UnicodeString', dict( 
 365                  encoding='utf16', 
 366                  length=lambda x: x.ExeLength * 2)]]], 
 367          'AliasList': [0x10, ['_LIST_ENTRY']], 
 368          }], 
 369      '_POPUP_LIST' : [None, { 
 370          'ListEntry' : [0x00, ['_LIST_ENTRY']], 
 371          }], 
 372      '_CONSOLE_INFORMATION': [None, { 
 373          'CurrentScreenBuffer': [0xB0, ['pointer', ['_SCREEN_INFORMATION']]], 
 374          'ScreenBuffer': [0xB4, ['pointer', ['_SCREEN_INFORMATION']]], 
 375          'HistoryList': [0x108, ['_LIST_ENTRY']], 
 376          'ProcessList': [0x100, ['_LIST_ENTRY']], 
 377          'ExeAliasList': [0x110, ['_LIST_ENTRY']], 
 378          'HistoryBufferCount': [0x118, ['unsigned short']], 
 379          'HistoryBufferMax': [0x11A, ['unsigned short']], 
 380          'CommandHistorySize': [0x11C, ['unsigned short']], 
 381          'OriginalTitle': [0x124, ['pointer', [ 
 382              'UnicodeString', dict( 
 383                  encoding='utf16', 
 384                  length=256)]]], 
 385          'Title': [0x128, ['pointer', [ 
 386              'UnicodeString', dict( 
 387                  encoding='utf16', 
 388                  length=256 
 389                  )]]], 
 390          }], 
 391      '_CONSOLE_PROCESS': [None, { 
 392          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 393          'ProcessHandle': [0x08, ['unsigned int']], 
 394          'Process': [0x0C, ['pointer', ['_CSR_PROCESS']]], 
 395          }], 
 396      '_SCREEN_INFORMATION': [None, { 
 397          'Console': [0x00, ['pointer', ['_CONSOLE_INFORMATION']]], 
 398          'ScreenX': [0x24, ['short']], 
 399          'ScreenY': [0x26, ['short']], 
 400          'Rows': [0x58, ['pointer', [ 
 401              'array', lambda x: x.ScreenY, ['_ROW']]]], 
 402          'Next': [0xF8, ['pointer', ['_SCREEN_INFORMATION']]], 
 403          }], 
 404      '_ROW': [0x1C, { 
 405          'Chars': [0x08, ['pointer', [ 
 406              'UnicodeString', dict( 
 407                  encoding='utf16', length=256 
 408                  )]]], 
 409          }], 
 410   
 411      # this is a public PDB 
 412      '_CSR_PROCESS' : [0x60, { 
 413          'ClientId' : [0x0, ['_CLIENT_ID']], 
 414          'ListLink' : [0x8, ['_LIST_ENTRY']], 
 415          'ThreadList' : [0x10, ['_LIST_ENTRY']], 
 416          'NtSession' : [0x18, ['pointer', ['_CSR_NT_SESSION']]], 
 417          'ClientPort' : [0x1c, ['pointer', ['void']]], 
 418          'ClientViewBase' : [0x20, ['pointer', ['unsigned char']]], 
 419          'ClientViewBounds' : [0x24, ['pointer', ['unsigned char']]], 
 420          'ProcessHandle' : [0x28, ['pointer', ['void']]], 
 421          'SequenceNumber' : [0x2c, ['unsigned long']], 
 422          'Flags' : [0x30, ['unsigned long']], 
 423          'DebugFlags' : [0x34, ['unsigned long']], 
 424          'ReferenceCount' : [0x38, ['unsigned long']], 
 425          'ProcessGroupId' : [0x3c, ['unsigned long']], 
 426          'ProcessGroupSequence' : [0x40, ['unsigned long']], 
 427          'LastMessageSequence' : [0x44, ['unsigned long']], 
 428          'NumOutstandingMessages' : [0x48, ['unsigned long']], 
 429          'ShutdownLevel' : [0x4c, ['unsigned long']], 
 430          'ShutdownFlags' : [0x50, ['unsigned long']], 
 431          'Luid' : [0x54, ['_LUID']], 
 432          'ServerDllPerProcessData' : [0x5c, [ 
 433              'array', 1, ['pointer', ['void']]]], 
 434          }], 
 435      } 
 436   
 437  winsrv_types_x64 = { 
 438      '_COMMAND': [None, { 
 439          'CmdLength': [0x00, ['unsigned short']], 
 440          'Cmd' : [0x02, ['UnicodeString', dict( 
 441              encoding='utf16', 
 442              length=lambda x: x.CmdLength)]], 
 443          }], 
 444      '_COMMAND_HISTORY': [None, { 
 445          'Flags' : [0x00, ['Flags', { 
 446              'bitmap': {'Allocated': 0, 'Reset': 1}}]], 
 447          'ListEntry': [0x08, ['_LIST_ENTRY']], 
 448          'Application': [0x18, ['pointer', [ 
 449              'UnicodeString', dict( 
 450                  encoding='utf16', 
 451                  length=256)]]], 
 452          'CommandCount': [0x20, ['short']], 
 453          'LastAdded': [0x22, ['short']], 
 454          'LastDisplayed': [0x24, ['short']], 
 455          'FirstCommand': [0x26, ['short']], 
 456          'CommandCountMax': [0x28, ['short']], 
 457          'ProcessHandle': [0x30, ['unsigned int']], 
 458          'PopupList': [0x38, ['_LIST_ENTRY']], 
 459          'CommandBucket': [0x48, [ 
 460              'array', lambda x: x.CommandCount, [ 
 461                  'pointer', ['_COMMAND']]]], 
 462          }], 
 463      '_ALIAS': [None, { 
 464          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 465          'SourceLength': [0x10, ['unsigned short']], 
 466          'TargetLength': [0x12, ['unsigned short']], 
 467          'Source': [0x14, ['pointer', [ 
 468              'UnicodeString', dict( 
 469                  encoding='utf16', 
 470                  length=lambda x: x.SourceLength * 2)]]], 
 471          'Target': [0x1C, ['pointer', ['UnicodeString', dict( 
 472              encoding='utf16', 
 473              length=lambda x: x.TargetLength * 2)]]], 
 474          }], 
 475      '_EXE_ALIAS_LIST' : [None, { 
 476          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 477          'ExeLength': [0x10, ['unsigned short']], 
 478          'ExeName': [0x12, ['pointer', [ 
 479              'UnicodeString', dict( 
 480                  encoding='utf16', 
 481                  length=lambda x: x.ExeLength * 2)]]], 
 482          'AliasList': [0x1A, ['_LIST_ENTRY']], 
 483          }], 
 484      '_POPUP_LIST' : [None, { 
 485          'ListEntry' : [0x00, ['_LIST_ENTRY']], 
 486          }], 
 487      '_CONSOLE_INFORMATION': [None, { 
 488          'CurrentScreenBuffer': [0xE8, ['pointer', ['_SCREEN_INFORMATION']]], 
 489          'ScreenBuffer': [0xF0, ['pointer', ['_SCREEN_INFORMATION']]], 
 490          'HistoryList': [0x188, ['_LIST_ENTRY']], 
 491          'ProcessList': [0x178, ['_LIST_ENTRY']], 
 492          'ExeAliasList': [0x198, ['_LIST_ENTRY']], 
 493          'HistoryBufferCount': [0x1A8, ['unsigned short']], 
 494          'HistoryBufferMax': [0x1AA, ['unsigned short']], 
 495          'CommandHistorySize': [0x1AC, ['unsigned short']], 
 496          'OriginalTitle': [0x1B0, ['pointer', [ 
 497              'UnicodeString', dict( 
 498                  encoding='utf16', length=256)]]], 
 499          'Title': [0x1B8, ['pointer', [ 
 500              'UnicodeString', dict( 
 501                  encoding='utf16', length=256)]]], 
 502          }], 
 503      '_CONSOLE_PROCESS': [None, { 
 504          'ListEntry': [0x00, ['_LIST_ENTRY']], 
 505          'ProcessHandle': [0x10, ['unsigned int']], 
 506          'Process': [0x18, ['pointer', ['_CSR_PROCESS']]], 
 507          }], 
 508      '_SCREEN_INFORMATION': [None, { 
 509          'Console': [0x00, ['pointer', ['_CONSOLE_INFORMATION']]], 
 510          'ScreenX': [0x28, ['short']], 
 511          'ScreenY': [0x2A, ['short']], 
 512          'Rows': [0x68, ['pointer', [ 
 513              'array', lambda x: x.ScreenY, ['_ROW']]]], 
 514          'Next': [0x128, ['pointer', ['_SCREEN_INFORMATION']]], 
 515          }], 
 516      '_ROW': [0x28, { 
 517          'Chars': [0x08, ['pointer', [ 
 518              'UnicodeString', dict( 
 519                  encoding='utf16', 
 520                  length=256)]]], 
 521          }], 
 522   
 523      # this is a public PDB 
 524      '_CSR_PROCESS' : [0x60, { 
 525          'ClientId' : [0x0, ['_CLIENT_ID']], 
 526          'ListLink' : [0x8, ['_LIST_ENTRY']], 
 527          'ThreadList' : [0x10, ['_LIST_ENTRY']], 
 528          'NtSession' : [0x18, ['pointer', ['_CSR_NT_SESSION']]], 
 529          'ClientPort' : [0x1c, ['pointer', ['void']]], 
 530          'ClientViewBase' : [0x20, ['pointer', ['unsigned char']]], 
 531          'ClientViewBounds' : [0x24, ['pointer', ['unsigned char']]], 
 532          'ProcessHandle' : [0x28, ['pointer', ['void']]], 
 533          'SequenceNumber' : [0x2c, ['unsigned long']], 
 534          'Flags' : [0x30, ['unsigned long']], 
 535          'DebugFlags' : [0x34, ['unsigned long']], 
 536          'ReferenceCount' : [0x38, ['unsigned long']], 
 537          'ProcessGroupId' : [0x3c, ['unsigned long']], 
 538          'ProcessGroupSequence' : [0x40, ['unsigned long']], 
 539          'LastMessageSequence' : [0x44, ['unsigned long']], 
 540          'NumOutstandingMessages' : [0x48, ['unsigned long']], 
 541          'ShutdownLevel' : [0x4c, ['unsigned long']], 
 542          'ShutdownFlags' : [0x50, ['unsigned long']], 
 543          'Luid' : [0x54, ['_LUID']], 
 544          'ServerDllPerProcessData' : [0x5c, [ 
 545              'array', 1, ['pointer', ['void']]]], 
 546          }], 
 547      } 
548 549 -class _CONSOLE_INFORMATION(obj.Struct):
550 """ object class for console information structs """ 551
552 - def get_screens(self):
553 """Generator for screens in the console. 554 555 A console can have multiple screen buffers at a time, 556 but only the current/active one is displayed. 557 558 Multiple screens are tracked using the singly-linked 559 list _SCREEN_INFORMATION.Next. 560 561 See CreateConsoleScreenBuffer 562 """ 563 screens = [self.CurrentScreenBuffer] 564 565 if self.ScreenBuffer not in screens: 566 screens.append(self.ScreenBuffer) 567 568 for screen in screens: 569 cur = screen 570 while cur and cur.v() != 0: 571 yield cur 572 cur = cur.Next.dereference()
573
574 -class _SCREEN_INFORMATION(obj.Struct):
575 """ object class for screen information """ 576
577 - def get_buffer(self, truncate=True):
578 """Get the screen buffer. 579 580 The screen buffer is comprised of the screen's Y 581 coordinate which tells us the number of rows and 582 the X coordinate which tells us the width of each 583 row in characters. These together provide all of 584 the input and output that users see when the 585 console is displayed. 586 587 @param truncate: True if the empty rows at the 588 end (i.e. bottom) of the screen buffer should be 589 supressed. 590 """ 591 rows = [] 592 593 for _, row in enumerate(self.Rows.dereference()): 594 if row.Chars.is_valid(): 595 rows.append(unicode(row.Chars.dereference())[0:self.ScreenX]) 596 597 # To truncate empty rows at the end, walk the list 598 # backwards and get the last non-empty row. Use that 599 # row index to splice. An "empty" row isn't just "" 600 # as one might assume. It is actually ScreenX number 601 # of space characters 602 603 if truncate: 604 non_empty_index = 0 605 for index, row in enumerate(reversed(rows)): 606 ## It seems that when the buffer width is greater than 128 607 ## characters, its truncated to 128 in memory. 608 if row.count(" ") != min(self.ScreenX, 128): 609 non_empty_index = index 610 break 611 if non_empty_index == 0: 612 rows = [] 613 else: 614 rows = rows[0:len(rows) - non_empty_index] 615 616 return rows
617
618 619 -class WinSrv86(basic.Profile32Bits, basic.BasicClasses):
620 """A domain specific profile for the xp, 2008.""" 621
622 - def __init__(self, **kwargs):
623 super(WinSrv86, self).__init__(**kwargs) 624 self.add_types(common_types) 625 self.add_types(winsrv_types_x86) 626 self.add_classes({ 627 '_CONSOLE_INFORMATION': _CONSOLE_INFORMATION, 628 '_SCREEN_INFORMATION': _SCREEN_INFORMATION, 629 })
630
631 632 -class WinSrv64(basic.ProfileLLP64, basic.BasicClasses):
633 """A domain specific profile for the xp, 2008.""" 634
635 - def __init__(self, **kwargs):
636 super(WinSrv64, self).__init__(**kwargs) 637 self.add_types(common_types_64) 638 self.add_types(winsrv_types_x64) 639 self.add_classes({ 640 '_CONSOLE_INFORMATION': _CONSOLE_INFORMATION, 641 '_SCREEN_INFORMATION': _SCREEN_INFORMATION, 642 })
643
644 645 -class ConHost86(basic.Profile32Bits, basic.BasicClasses):
646 """A domain specific profile for windows 7.""" 647
648 - def __init__(self, **kwargs):
649 super(ConHost86, self).__init__(**kwargs) 650 self.add_types(common_types) 651 self.add_types(conhost_types_x86) 652 self.add_classes({ 653 '_CONSOLE_INFORMATION': _CONSOLE_INFORMATION, 654 '_SCREEN_INFORMATION': _SCREEN_INFORMATION, 655 })
656
657 658 -class ConHost64(basic.ProfileLLP64, basic.BasicClasses):
659 """A domain specific profile for windows 7.""" 660
661 - def __init__(self, **kwargs):
662 super(ConHost64, self).__init__(**kwargs) 663 self.add_types(common_types_64) 664 self.add_types(conhost_types_x64) 665 self.add_classes({ 666 '_CONSOLE_INFORMATION': _CONSOLE_INFORMATION, 667 '_SCREEN_INFORMATION': _SCREEN_INFORMATION, 668 })
669
670 671 -class WinHistoryScanner(vadinfo.VadScanner):
672 """A vad scanner for command histories. 673 674 The default pattern we search for, as described by Stevens and Casey, is 675 "\x32\x00". That's because CommandCountMax is a little-endian unsigned short 676 whose default value is 50. However, that value can be changed by right 677 clicking cmd.exe and going to Properties->Options->Cmd History or by calling 678 the API function kernel32!SetConsoleHistoryInfo. Thus you can tweak the 679 search criteria by using the --MAX_HISTORY. 680 """
681 - def __init__(self, max_history=MAX_HISTORY_DEFAULT, **kwargs):
682 super(WinHistoryScanner, self).__init__(**kwargs) 683 self.max_history = max_history
684
685 - def scan(self, **kwargs):
686 for hit in super(WinHistoryScanner, self).scan(**kwargs): 687 # Check to see if the object is valid. 688 hist = self.profile.Object( 689 "_COMMAND_HISTORY", vm=self.address_space, 690 offset=hit - self.profile.get_obj_offset( 691 "_COMMAND_HISTORY", "CommandCountMax")) 692 693 if not hist.is_valid(): 694 continue 695 696 # The count must be between zero and max 697 if hist.CommandCount < 0 or hist.CommandCount > self.max_history: 698 continue 699 700 # Last added must be between -1 and max 701 if hist.LastAdded < -1 or hist.LastAdded > self.max_history: 702 continue 703 704 # Last displayed must be between -1 and max 705 if hist.LastDisplayed < -1 or hist.LastDisplayed > self.max_history: 706 continue 707 708 # First command must be between zero and max 709 if hist.FirstCommand < 0 or hist.FirstCommand > self.max_history: 710 continue 711 712 # Validate first command with last added 713 if (hist.FirstCommand != 0 and 714 hist.FirstCommand != hist.LastAdded + 1): 715 continue 716 717 # Process handle must be a valid pid 718 if hist.ProcessHandle <= 0 or hist.ProcessHandle > 0xFFFF: 719 continue 720 721 Popup = self.profile._POPUP_LIST( 722 offset=hist.PopupList.Flink, vm=self.address_space) 723 724 # Check that the popup list entry is in tact 725 if Popup.ListEntry.Blink != hist.PopupList.obj_offset: 726 continue 727 728 yield hist
729
730 731 -class CmdScan(common.WindowsCommandPlugin):
732 """Extract command history by scanning for _COMMAND_HISTORY""" 733 __name = "cmdscan" 734 735 __args = [ 736 dict(name="max_history", default=MAX_HISTORY_DEFAULT, 737 type="IntParser", help="Value of history buffer size. See " 738 "HKEY_CURRENT_USER\\Console\\HistoryBufferSize " 739 "for default.") 740 ] 741
742 - def generate_hits(self):
743 """Generates _COMMAND_HISTORY objects.""" 744 architecture = self.profile.metadata("arch") 745 # The process we select is conhost on Win7 or csrss for others 746 747 if self.profile.metadata("major") >= 6: 748 process_name = "conhost.exe" 749 if architecture == "AMD64": 750 process_profile = ConHost64(session=self.session) 751 else: 752 process_profile = ConHost86(session=self.session) 753 else: 754 process_name = "csrss.exe" 755 if architecture == "AMD64": 756 process_profile = WinSrv64(session=self.session) 757 else: 758 process_profile = WinSrv86(session=self.session) 759 760 # Only select those processes we care about: 761 for task in self.session.plugins.pslist( 762 proc_regex=process_name).filter_processes(): 763 scanner = WinHistoryScanner( 764 task=task, process_profile=process_profile, 765 max_history=self.plugin_args.max_history, session=self.session) 766 767 pattern = chr(self.plugin_args.max_history) + "\x00" 768 scanner.checks = [ 769 ("StringCheck", dict(needle=pattern)) 770 ] 771 scanner.build_constraints() 772 773 for hist in scanner.scan(): 774 yield task, hist
775
776 - def render(self, renderer):
777 for task, hist in self.generate_hits(): 778 renderer.section() 779 renderer.format(u"CommandProcess: {0} Pid: {1}\n", 780 task.ImageFileName, task.UniqueProcessId) 781 renderer.format( 782 u"CommandHistory: {0:#x} Application: {1} Flags: {2}\n", 783 hist.obj_offset, hist.Application.dereference(), hist.Flags) 784 785 renderer.format( 786 u"CommandCount: {0} LastAdded: {1} LastDisplayed: {2}\n", 787 hist.CommandCount, hist.LastAdded, hist.LastDisplayed) 788 789 renderer.format(u"FirstCommand: {0} CommandCountMax: {1}\n", 790 hist.FirstCommand, hist.CommandCountMax) 791 792 renderer.format(u"ProcessHandle: {0:#x}\n", hist.ProcessHandle) 793 794 795 renderer.table_header([("Cmd", "command", ">3"), 796 ("Address", "address", "[addrpad]"), 797 ("Text", "text", "")]) 798 799 # If the _COMMAND_HISTORY is in use, we would only take 800 # hist.CommandCount but since we're brute forcing, try the 801 # maximum and hope that some slots were not overwritten 802 # or zero-ed out. 803 pointers = hist.obj_profile.Array( 804 target="address", count=hist.CommandCountMax, 805 offset=hist.obj_offset + hist.obj_profile.get_obj_offset( 806 "_COMMAND_HISTORY", "CommandBucket"), 807 vm=hist.obj_vm) 808 809 for i, p in enumerate(pointers): 810 cmd = p.cast("Pointer", target="_COMMAND").deref() 811 if cmd.obj_offset and cmd.Cmd: 812 renderer.table_row( 813 i, cmd.obj_offset, 814 utils.SmartUnicode(cmd.Cmd).encode("unicode_escape"))
815
816 817 -class ConsoleScanner(vadinfo.VadScanner):
818 """A scanner for _CONSOLE_INFORMATION.""" 819
820 - def __init__(self, max_history=MAX_HISTORY_DEFAULT, 821 history_buffers=HISTORY_BUFFERS_DEFAULTS, **kwargs):
822 super(ConsoleScanner, self).__init__(**kwargs) 823 self.max_history = max_history 824 self.history_buffers = history_buffers
825
826 - def scan(self, **kwargs):
827 for hit in super(ConsoleScanner, self).scan(**kwargs): 828 # Check to see if the object is valid. 829 console = self.profile.Object( 830 "_CONSOLE_INFORMATION", offset=hit - 831 self.profile.get_obj_offset( 832 "_CONSOLE_INFORMATION", "CommandHistorySize"), 833 vm=self.address_space, parent=self.task) 834 835 if (console.HistoryBufferMax != self.history_buffers or 836 console.HistoryBufferCount > self.history_buffers): 837 continue 838 839 # Check the first command history as the final constraint 840 next_history = console.HistoryList.Flink.dereference( 841 ).dereference_as("_COMMAND_HISTORY", "ListEntry") 842 if next_history.CommandCountMax != self.max_history: 843 continue 844 845 yield console
846
847 848 -class ConsoleScan(CmdScan):
849 """Extract command history by scanning for _CONSOLE_INFORMATION""" 850 851 __name = "consolescan" 852 853 __args = [ 854 dict(name="history_buffers", default=HISTORY_BUFFERS_DEFAULTS, 855 type="IntParser", 856 help="Value of history buffer size. See " 857 "HKEY_CURRENT_USER\\Console\\HistoryBufferSize " 858 "for default.") 859 ] 860
861 - def generate_hits(self):
862 """Generates _CONSOLE_INFORMATION objects.""" 863 architecture = self.profile.metadata("arch") 864 # The process we select is conhost on Win7 or csrss for others 865 866 # Only select those processes we care about: 867 for task in self.session.plugins.pslist( 868 proc_regex="(conhost.exe|csrss.exe)").filter_processes(): 869 870 if str(task.ImageFileName).lower() == "conhost.exe": 871 if architecture == "AMD64": 872 process_profile = ConHost64(session=self.session) 873 else: 874 process_profile = ConHost86(session=self.session) 875 876 elif str(task.ImageFileName).lower() == "csrss.exe": 877 if architecture == "AMD64": 878 process_profile = WinSrv64(session=self.session) 879 else: 880 process_profile = WinSrv86(session=self.session) 881 882 else: continue 883 884 scanner = ConsoleScanner( 885 task=task, process_profile=process_profile, 886 session=self.session, 887 max_history=self.plugin_args.max_history, 888 history_buffers=self.plugin_args.history_buffers) 889 890 pattern = chr(self.plugin_args.max_history) + "\x00" 891 scanner.checks = [ 892 ("StringCheck", dict(needle=pattern)) 893 ] 894 scanner.build_constraints() 895 896 for console in scanner.scan(): 897 yield task, console
898
899 - def render(self, renderer):
900 for task, console in self.generate_hits(): 901 renderer.section() 902 903 renderer.format(u"ConsoleProcess: {0} Pid: {1}\n", 904 task.ImageFileName, task.UniqueProcessId) 905 906 renderer.format(u"Console: {0:#x} CommandHistorySize: {1}\n", 907 console, console.CommandHistorySize) 908 909 renderer.format( 910 u"HistoryBufferCount: {0} HistoryBufferMax: {1}\n", 911 console.HistoryBufferCount, console.HistoryBufferMax) 912 913 renderer.format(u"OriginalTitle: {0}\n", 914 console.OriginalTitle.dereference()) 915 916 renderer.format(u"Title: {0}\n", console.Title.dereference()) 917 918 for console_proc in console.ProcessList.list_of_type( 919 "_CONSOLE_PROCESS", "ListEntry"): 920 process = task.ObReferenceObjectByHandle( 921 console_proc.ProcessHandle, type="_EPROCESS") 922 923 if process: 924 renderer.format( 925 u"AttachedProcess: {0} Pid: {1} Handle: {2:#x}\n", 926 process.ImageFileName, process.UniqueProcessId, 927 console_proc.ProcessHandle) 928 929 for hist in console.HistoryList.list_of_type( 930 "_COMMAND_HISTORY", "ListEntry"): 931 renderer.format(u"----\n") 932 933 renderer.format( 934 u"CommandHistory: {0:#x} Application: {1} Flags: {2}\n", 935 hist, hist.Application.dereference(), 936 hist.Flags) 937 renderer.format( 938 u"CommandCount: {0} LastAdded: {1} LastDisplayed: {2}\n", 939 hist.CommandCount, hist.LastAdded, hist.LastDisplayed) 940 941 renderer.format(u"FirstCommand: {0} CommandCountMax: {1}\n", 942 hist.FirstCommand, hist.CommandCountMax) 943 944 renderer.format(u"ProcessHandle: {0:#x}\n", hist.ProcessHandle) 945 for i, cmd in enumerate(hist.CommandBucket): 946 if cmd.Cmd.is_valid(): 947 renderer.format(u"Cmd #{0} at {1:#x}: {2}\n", 948 i, cmd, unicode(cmd.Cmd)) 949 950 for exe_alias in console.ExeAliasList.list_of_type( 951 "_EXE_ALIAS_LIST", "ListEntry"): 952 953 for alias in exe_alias.AliasList.list_of_type( 954 "_ALIAS", "ListEntry"): 955 renderer.format(u"----\n") 956 renderer.format( 957 u"Alias: {0} Source: {1} Target: {2}\n", 958 exe_alias.ExeName.dereference(), 959 alias.Source.dereference(), 960 alias.Target.dereference()) 961 962 for screen in console.get_screens(): 963 renderer.format(u"----\n") 964 renderer.format(u"Screen {0:#x} X:{1} Y:{2}\n", 965 screen.dereference(), screen.ScreenX, 966 screen.ScreenY) 967 968 renderer.format(u"Dump:\n{0}\n", '\n'.join(screen.get_buffer()))
969
970 971 -class Conhost(pe_vtypes.BasicPEProfile):
972 """A profile for Conhost.exe.""" 973 974 @classmethod
975 - def Initialize(cls, profile):
984
985 986 -class Consoles(common.WindowsCommandPlugin):
987 """Enumerate command consoles.""" 988 989 name = "consoles" 990
991 - def _render_conhost_process(self, task, renderer):
992 self.cc.SwitchProcessContext(task) 993 console = self.session.address_resolver.get_constant_object( 994 "conhost!gConsoleInformation", "_CONSOLE_INFORMATION") 995 996 if console == None: 997 self.session.logging.warning( 998 "Unable to load profile for conhost.exe.") 999 return 1000 1001 renderer.format(u"ConsoleProcess: {0}\n", task) 1002 renderer.format(u"Title: {0}\n", console.Title.deref()) 1003 renderer.format(u"OriginalTitle: {0}\n", 1004 console.OriginalTitle.dereference()) 1005 1006 for console_proc in console.ProcessList.list_of_type( 1007 "_CONSOLE_PROCESS", "ListEntry"): 1008 process = task.ObReferenceObjectByHandle( 1009 console_proc.ProcessHandle, type="_EPROCESS") 1010 1011 if process: 1012 renderer.format( 1013 u"AttachedProcess: {0} Handle: {1:style=address}\n", 1014 process, console_proc.ProcessHandle) 1015 1016 for hist in console.HistoryList.list_of_type( 1017 "_COMMAND_HISTORY", "ListEntry"): 1018 renderer.format(u"----\n") 1019 1020 renderer.format( 1021 u"CommandHistory: {0:#x} Application: {1} Flags: {2}\n", 1022 hist, hist.Application.dereference(), 1023 hist.Flags) 1024 1025 renderer.format( 1026 u"CommandCount: {0} LastAdded: {1} LastDisplayed: {2}\n", 1027 hist.CommandCount, hist.LastAdded, hist.LastDisplayed) 1028 1029 renderer.format(u"FirstCommand: {0} CommandCountMax: {1}\n", 1030 hist.FirstCommand, hist.CommandCountMax) 1031 1032 renderer.format(u"ProcessHandle: {0:#x}\n", hist.ProcessHandle) 1033 for i, cmd in enumerate(hist.CommandBucket): 1034 if cmd.Cmd.is_valid(): 1035 renderer.format(u"Cmd #{0} at {1:#x}: {2}\n", 1036 i, cmd, unicode(cmd.Cmd)) 1037 1038 for exe_alias in console.ExeAliasList.list_of_type( 1039 "_EXE_ALIAS_LIST", "ListEntry"): 1040 1041 for alias in exe_alias.AliasList.list_of_type( 1042 "_ALIAS", "ListEntry"): 1043 if alias == None: 1044 continue 1045 1046 renderer.format(u"----\n") 1047 renderer.format( 1048 u"Alias: {0} Source: {1} Target: {2}\n", 1049 exe_alias.ExeName.dereference(), 1050 alias.Source.dereference(), 1051 alias.Target.dereference()) 1052 1053 for screen in console.ScreenBuffer.walk_list("Next"): 1054 renderer.format(u"----\n") 1055 renderer.format(u"Screen {0:#x} X:{1} Y:{2}\n", 1056 screen, screen.ScreenX, screen.ScreenY) 1057 1058 screen_data = [] 1059 for row in screen.Rows: 1060 row_data = row.Chars.deref() 1061 1062 # Since a row is always screen.ScreenX wide a 0 width row means 1063 # the page is not available or incorrect. 1064 if len(row_data) == 0: 1065 continue 1066 1067 screen_data.append((row_data, unicode(row_data).rstrip())) 1068 1069 # Trim empty rows from the end of the screen. 1070 while screen_data and not screen_data[-1][1]: 1071 screen_data.pop(-1) 1072 1073 for row, row_string in screen_data: 1074 renderer.format( 1075 "{0:style=address}: {1}\n", row, row_string)
1076
1077 - def render(self, renderer):
1078 self.cc = self.session.plugins.cc() 1079 with self.cc: 1080 for task in self.session.plugins.pslist( 1081 proc_regex="conhost.exe").filter_processes(): 1082 renderer.section() 1083 self._render_conhost_process(task, renderer)
1084