Package winappdbg :: Module system
[hide private]
[frames] | no frames]

Source Code for Module winappdbg.system

   1  # Copyright (c) 2009, Mario Vilas 
   2  # All rights reserved. 
   3  # 
   4  # Redistribution and use in source and binary forms, with or without 
   5  # modification, are permitted provided that the following conditions are met: 
   6  # 
   7  #     * Redistributions of source code must retain the above copyright notice, 
   8  #       this list of conditions and the following disclaimer. 
   9  #     * Redistributions in binary form must reproduce the above copyright 
  10  #       notice,this list of conditions and the following disclaimer in the 
  11  #       documentation and/or other materials provided with the distribution. 
  12  #     * Neither the name of the copyright holder nor the names of its 
  13  #       contributors may be used to endorse or promote products derived from 
  14  #       this software without specific prior written permission. 
  15  # 
  16  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  17  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  18  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  19  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  20  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  21  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  22  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  23  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  24  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  25  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  26  # POSSIBILITY OF SUCH DAMAGE. 
  27   
  28  """ 
  29  Instrumentation module. 
  30   
  31  @see: U{http://apps.sourceforge.net/trac/winappdbg/wiki/Instrumentation} 
  32   
  33  @group Instrumentation: 
  34      System, Process, Thread, Module 
  35  @group Capabilities (private): 
  36      ModuleContainer, ThreadContainer, ProcessContainer, SymbolContainer, 
  37      ThreadDebugOperations, ProcessDebugOperations, 
  38      MemoryOperations, MemoryAddresses, SymbolOperations, PathOperations, 
  39      SymbolEnumerator 
  40  """ 
  41   
  42  # FIXME 
  43  # I've been told the host process for the latest versions of VMWare 
  44  # can't be instrumented, because they try to stop code injection into the VMs. 
  45  # The solution appears to be to run the debugger from a user account that 
  46  # belongs to the VMware group. I haven't yet confirmed this. 
  47   
  48  __revision__ = "$Id: system.py 550 2009-12-13 23:52:46Z qvasimodo $" 
  49   
  50  __all__ =   [ 
  51                  # Instrumentation classes. 
  52                  'System', 
  53                  'Process', 
  54                  'Thread', 
  55                  'Module', 
  56   
  57                  # Static functions 
  58                  'MemoryAddresses', 
  59                  'PathOperations', 
  60              ] 
  61   
  62  import win32 
  63  import win32.version 
  64  from textio import HexInput, HexDump 
  65   
  66  import re 
  67  import os 
  68  import sys 
  69  import ctypes 
  70  import struct 
  71   
  72  try: 
  73      from distorm import Decode, Decode16Bits, Decode32Bits, Decode64Bits 
  74  except ImportError: 
  75      Decode16Bits = None 
  76      Decode32Bits = None 
  77      Decode64Bits = None 
78 - def Decode(*argv, **argd):
79 "PLEASE INSTALL DISTORM BEFORE GENERATING THE DOCUMENTATION" 80 msg = ("diStorm is not installed or can't be found. " 81 "Download it from: http://www.ragestorm.net/distorm/") 82 raise NotImplementedError, msg
83
84 #============================================================================== 85 86 -class PathOperations (object):
87 """ 88 Static methods for filename and pathname manipulation. 89 """ 90 91 @staticmethod
92 - def pathname_to_filename(pathname):
93 """ 94 @type pathname: str 95 @param pathname: Absolute path. 96 97 @rtype: str 98 @return: Relative path. 99 """ 100 return win32.PathFindFileName(pathname)
101 102 @staticmethod
103 - def filename_to_pathname(filename):
104 """ 105 @type filename: str 106 @param filename: Relative path. 107 108 @rtype: str 109 @return: Absolute path. 110 """ 111 return win32.GetFullPathName(filename)
112 113 @staticmethod
114 - def path_is_relative(path):
115 """ 116 @see: L{path_is_absolute} 117 118 @type path: str 119 @param path: Absolute or relative path. 120 121 @rtype: bool 122 @return: C{True} if the path is relative, C{False} if it's absolute. 123 """ 124 return win32.PathIsRelative(path)
125 126 @staticmethod
127 - def path_is_absolute(path):
128 """ 129 @see: L{path_is_relative} 130 131 @type path: str 132 @param path: Absolute or relative path. 133 134 @rtype: bool 135 @return: C{True} if the path is absolute, C{False} if it's relative. 136 """ 137 return not win32.PathIsRelative(path)
138 139 @staticmethod
140 - def split_extension(pathname):
141 """ 142 @type pathname: str 143 @param pathname: Absolute path. 144 145 @rtype: tuple( str, str ) 146 @return: 147 Tuple containing the file and extension components of the filename. 148 """ 149 filepart = win32.PathRemoveExtension(pathname) 150 extpart = win32.PathFindExtension(pathname) 151 return (filepart, extpart)
152 153 @staticmethod
154 - def split_filename(pathname):
155 """ 156 @type pathname: str 157 @param pathname: Absolute path. 158 159 @rtype: tuple( str, str ) 160 @return: Tuple containing the path to the file and the base filename. 161 """ 162 filepart = win32.PathFindFileName(pathname) 163 pathpart = win32.PathRemoveFileSpec(pathname) 164 return (pathpart, filepart)
165 166 @staticmethod
167 - def split_path(path):
168 """ 169 @see: L{join_path} 170 171 @type path: str 172 @param path: Absolute or relative path. 173 174 @rtype: list( str... ) 175 @return: List of path components. 176 """ 177 components = list() 178 while path: 179 next = win32.PathFindNextComponent(path) 180 if next: 181 prev = path[ : -len(next) ] 182 components.append(prev) 183 path = next 184 return components
185 186 @staticmethod
187 - def join_path(*components):
188 """ 189 @see: L{split_path} 190 191 @type components: tuple( str... ) 192 @param components: Path components. 193 194 @rtype: str 195 @return: Absolute or relative path. 196 """ 197 if components: 198 path = components[0] 199 for next in components[1:]: 200 path = win32.PathAppend(path, next) 201 else: 202 path = "" 203 return path
204 205 @staticmethod
206 - def native_to_win32_pathname(name):
207 """ 208 @type name: str 209 @param name: Native (NT) absolute pathname. 210 211 @rtype: str 212 @return: Win32 absolute pathname. 213 """ 214 # XXX TODO 215 # There are probably some native paths that 216 # won't be converted by this naive approach. 217 if name.startswith("\\"): 218 if name.startswith("\\??\\"): 219 name = name[4:] 220 elif name.startswith("\\SystemRoot\\"): 221 system_root_path = os.environ['SYSTEMROOT'] 222 if system_root_path.endswith('\\'): 223 system_root_path = system_root_path[:-1] 224 name = system_root_path + name[11:] 225 else: 226 for drive_number in xrange(ord('A'), ord('Z') + 1): 227 drive_letter = '%c:' % drive_number 228 try: 229 device_native_path = win32.QueryDosDevice(drive_letter) 230 except WindowsError, e: 231 if e.winerror in (win32.ERROR_FILE_NOT_FOUND, \ 232 win32.ERROR_PATH_NOT_FOUND): 233 continue 234 raise 235 if not device_native_path.endswith('\\'): 236 device_native_path += '\\' 237 if name.startswith(device_native_path): 238 name = drive_letter + '\\' + \ 239 name[ len(device_native_path) : ] 240 break 241 return name
242
243 #============================================================================== 244 245 -class ModuleContainer (object):
246 """ 247 Encapsulates the capability to contain Module objects. 248 249 @group Modules snapshot: 250 scan_modules, 251 get_module, get_module_bases, get_module_count, 252 get_module_at_address, get_module_by_name, 253 has_module, iter_modules, iter_module_addresses, 254 clear_modules 255 256 @group Event notifications (private): 257 notify_load_dll, 258 notify_unload_dll 259 """ 260
261 - def __init__(self):
262 super(ModuleContainer, self).__init__() 263 self.__moduleDict = dict()
264
265 - def __initialize_snapshot(self):
266 """ 267 Private method to automatically initialize the snapshot 268 when you try to use it without calling any of the scan_* 269 methods first. You don't need to call this yourself. 270 """ 271 if not self.__moduleDict: 272 self.scan_modules()
273
274 - def __contains__(self, anObject):
275 """ 276 @type anObject: L{Module}, int 277 @param anObject: 278 - C{Module}: Module object to look for. 279 - C{int}: Base address of the DLL to look for. 280 281 @rtype: bool 282 @return: C{True} if the snapshot contains 283 a L{Module} object with the same base address. 284 """ 285 if isinstance(anObject, Module): 286 anObject = anObject.lpBaseOfDll 287 return self.has_module(anObject)
288
289 - def __iter__(self):
290 """ 291 @see: L{iter_modules} 292 @rtype: dictionary-valueiterator 293 @return: Iterator of L{Module} objects in this snapshot. 294 """ 295 return self.iter_modules()
296
297 - def __len__(self):
298 """ 299 @see: L{get_module_count} 300 @rtype: int 301 @return: Count of L{Module} objects in this snapshot. 302 """ 303 return self.get_module_count()
304
305 - def has_module(self, lpBaseOfDll):
306 """ 307 @type lpBaseOfDll: int 308 @param lpBaseOfDll: Base address of the DLL to look for. 309 310 @rtype: bool 311 @return: C{True} if the snapshot contains a 312 L{Module} object with the given base address. 313 """ 314 self.__initialize_snapshot() 315 return lpBaseOfDll in self.__moduleDict
316
317 - def get_module(self, lpBaseOfDll):
318 """ 319 @type lpBaseOfDll: int 320 @param lpBaseOfDll: Base address of the DLL to look for. 321 322 @rtype: L{Module} 323 @return: Module object with the given base address. 324 """ 325 self.__initialize_snapshot() 326 if lpBaseOfDll not in self.__moduleDict: 327 msg = "Unknown DLL base address %s" 328 msg = msg % HexDump.address(lpBaseOfDll) 329 raise KeyError, msg 330 return self.__moduleDict[lpBaseOfDll]
331
332 - def iter_module_addresses(self):
333 """ 334 @see: L{iter_modules} 335 @rtype: dictionary-keyiterator 336 @return: Iterator of DLL base addresses in this snapshot. 337 """ 338 self.__initialize_snapshot() 339 return self.__moduleDict.iterkeys()
340
341 - def iter_modules(self):
342 """ 343 @see: L{iter_module_addresses} 344 @rtype: dictionary-valueiterator 345 @return: Iterator of L{Module} objects in this snapshot. 346 """ 347 self.__initialize_snapshot() 348 return self.__moduleDict.itervalues()
349
350 - def get_module_bases(self):
351 """ 352 @see: L{iter_module_addresses} 353 @rtype: list( int... ) 354 @return: List of DLL base addresses in this snapshot. 355 """ 356 self.__initialize_snapshot() 357 return self.__moduleDict.keys()
358
359 - def get_module_count(self):
360 """ 361 @rtype: int 362 @return: Count of L{Module} objects in this snapshot. 363 """ 364 self.__initialize_snapshot() 365 return len(self.__moduleDict)
366 367 #------------------------------------------------------------------------------ 368
369 - def get_module_by_name(self, modName):
370 """ 371 @type modName: int 372 @param modName: 373 Name of the module to look for, as returned by L{Module.get_name}. 374 If two or more modules with the same name are loaded, only one 375 of the matching modules is returned. 376 377 You can also pass a full pathname to the DLL file. 378 This works correctly even if two modules with the same name 379 are loaded from different paths. 380 381 @rtype: L{Module} 382 @return: C{Module} object that best matches the given name. 383 Returns C{None} if no C{Module} can be found. 384 """ 385 386 # Convert modName to lowercase. 387 # This helps make case insensitive string comparisons. 388 modName = modName.lower() 389 390 # modName is an absolute pathname. 391 if PathOperations.path_is_absolute(modName): 392 for lib in self.iter_modules(): 393 if modName == lib.get_filename().lower(): 394 return lib 395 return None # Stop trying to match the name. 396 397 # Get all the module names. 398 # This prevents having to iterate through the module list 399 # more than once. 400 modDict = [ ( lib.get_name(), lib ) for lib in self.iter_modules() ] 401 modDict = dict(modDict) 402 403 # modName is a base filename. 404 if modName in modDict: 405 return modDict[modName] 406 407 # modName is a base filename without extension. 408 filepart, extpart = PathOperations.split_extension(modName) 409 if filepart and extpart: 410 if filepart in modDict: 411 return modDict[filepart] 412 413 # modName is a base address. 414 try: 415 baseAddress = HexInput.integer(modName) 416 except ValueError: 417 return None 418 if self.has_module(baseAddress): 419 return self.get_module(baseAddress) 420 421 # Module not found. 422 return None
423
424 - def get_module_at_address(self, address):
425 """ 426 @type address: int 427 @param address: Memory address to query. 428 429 @rtype: L{Module} 430 @return: C{Module} object that best matches the given address. 431 Returns C{None} if no C{Module} can be found. 432 """ 433 bases = self.get_module_bases() 434 bases.sort() 435 ## bases.append(0x100000000) # invalid, > 4 gb. address space 436 bases.append(0x1000000000000000) # invalid, > 64 bit address 437 if address >= bases[0]: 438 for i in xrange(len(bases)-1): # -1 because last base is fake 439 begin, end = bases[i:i+2] 440 if begin <= address <= end: 441 module = self.get_module(begin) 442 here = module.is_address_here(address) 443 if here is False: 444 break 445 else: # True or None 446 return module 447 return None
448 449 # XXX this method musn't end up calling __initialize_snapshot by accident!
450 - def scan_modules(self):
451 """ 452 Populates the snapshot with loaded modules. 453 """ 454 455 # Ignore process IDs 0 and 4. 456 # PID 0: System Idle Process. Also has a special meaning to the 457 # toolhelp APIs (current process). 458 # PID 4: System Integrity Group. See this forum post for more info: 459 # http://tinyurl.com/ycza8jo 460 # (points to social.technet.microsoft.com) 461 dwProcessId = self.get_pid() 462 if dwProcessId in (0, 4): 463 return 464 465 # It would seem easier to clear the snapshot first. 466 # But then all open handles would be closed. 467 found_bases = set() 468 hSnapshot = win32.CreateToolhelp32Snapshot(win32.TH32CS_SNAPMODULE, \ 469 dwProcessId) 470 try: 471 me = win32.Module32First(hSnapshot) 472 while me is not None: 473 lpBaseAddress = me.modBaseAddr 474 fileName = me.szExePath 475 if not fileName: 476 fileName = me.szModule 477 if not fileName: 478 fileName = None 479 found_bases.add(lpBaseAddress) 480 ## if not self.has_module(lpBaseAddress): # XXX triggers a scan 481 if not self.__moduleDict.has_key(lpBaseAddress): 482 aModule = Module(lpBaseAddress, fileName = fileName, 483 SizeOfImage = me.modBaseSize, 484 process = self) 485 self.__add_module(aModule) 486 else: 487 aModule = self.get_module(lpBaseAddress) 488 if not aModule.fileName: 489 aModule.fileName = fileName 490 if not aModule.SizeOfImage: 491 aModule.SizeOfImage = me.modBaseSize 492 if not aModule.process: 493 aModule.process = self 494 me = win32.Module32Next(hSnapshot) 495 finally: 496 win32.CloseHandle(hSnapshot) 497 ## for base in self.get_module_bases(): # XXX triggers a scan 498 for base in self.__moduleDict.keys(): 499 if base not in found_bases: 500 self.__del_module(base)
501
502 - def clear_modules(self):
503 """ 504 Clears the modules snapshot. 505 """ 506 self.__moduleDict = dict()
507 508 #------------------------------------------------------------------------------ 509 510 # XXX notify_* methods should not trigger a scan 511
512 - def __add_module(self, aModule):
513 ## if not isinstance(aModule, Module): 514 ## if hasattr(aModule, '__class__'): 515 ## typename = aModule.__class__.__name__ 516 ## else: 517 ## typename = str(type(aModule)) 518 ## msg = "Expected Module, got %s instead" % typename 519 ## raise TypeError, msg 520 lpBaseOfDll = aModule.get_base() 521 ## if lpBaseOfDll in self.__moduleDict: 522 ## msg = "Module already exists: %d" % lpBaseOfDll 523 ## raise KeyError, msg 524 self.__moduleDict[lpBaseOfDll] = aModule
525
526 - def __del_module(self, lpBaseOfDll):
527 ## if lpBaseOfDll not in self.__moduleDict: 528 ## msg = "Unknown base address %d" % lpBaseOfDll 529 ## raise KeyError, msg 530 del self.__moduleDict[lpBaseOfDll]
531
532 - def __add_loaded_module(self, event):
533 lpBaseOfDll = event.get_module_base() 534 hFile = event.get_file_handle() 535 ## if not self.has_module(lpBaseOfDll): # XXX this would trigger a scan 536 if not self.__moduleDict.has_key(lpBaseOfDll): 537 fileName = event.get_filename() 538 if not fileName: 539 fileName = None 540 if hasattr(event, 'get_start_address'): 541 EntryPoint = event.get_start_address() 542 else: 543 EntryPoint = None 544 aModule = Module(lpBaseOfDll, hFile, fileName = fileName, 545 EntryPoint = EntryPoint, 546 process = self) 547 self.__add_module(aModule) 548 else: 549 aModule = self.get_module(lpBaseOfDll) 550 if hFile != win32.INVALID_HANDLE_VALUE: 551 aModule.hFile = hFile 552 if not aModule.process: 553 aModule.process = self 554 if aModule.EntryPoint is None and \ 555 hasattr(event, 'get_start_address'): 556 aModule.EntryPoint = event.get_start_address() 557 if not aModule.fileName: 558 fileName = event.get_filename() 559 if fileName: 560 aModule.fileName = fileName
561
562 - def notify_create_process(self, event):
563 """ 564 Notify the load of the main module. 565 566 This is done automatically by the L{Debug} class, you shouldn't need 567 to call it yourself. 568 569 @type event: L{CreateProcessEvent} 570 @param event: Create process event. 571 """ 572 self.__add_loaded_module(event) 573 return True
574
575 - def notify_load_dll(self, event):
576 """ 577 Notify the load of a new module. 578 579 This is done automatically by the L{Debug} class, you shouldn't need 580 to call it yourself. 581 582 @type event: L{LoadDLLEvent} 583 @param event: Load DLL event. 584 """ 585 self.__add_loaded_module(event) 586 return True
587
588 - def notify_unload_dll(self, event):
589 """ 590 Notify the release of a loaded module. 591 592 This is done automatically by the L{Debug} class, you shouldn't need 593 to call it yourself. 594 595 @type event: L{UnloadDLLEvent} 596 @param event: Unload DLL event. 597 """ 598 lpBaseOfDll = event.get_module_base() 599 ## if self.has_module(lpBaseOfDll): # XXX this would trigger a scan 600 if self.__moduleDict.has_key(lpBaseOfDll): 601 self.__del_module(lpBaseOfDll) 602 return True
603
604 #============================================================================== 605 606 -class ThreadContainer (object):
607 """ 608 Encapsulates the capability to contain Thread objects. 609 610 @group Instrumentation: 611 start_thread 612 613 @group Threads snapshot: 614 scan_threads, 615 get_thread, get_thread_count, get_thread_ids, 616 has_thread, iter_threads, iter_thread_ids, 617 find_threads_by_name, 618 clear_threads, clear_dead_threads, close_thread_handles 619 620 @group Event notifications (private): 621 notify_create_process, 622 notify_create_thread, 623 notify_exit_thread 624 """ 625
626 - def __init__(self):
627 super(ThreadContainer, self).__init__() 628 self.__threadDict = dict()
629
630 - def __initialize_snapshot(self):
631 """ 632 Private method to automatically initialize the snapshot 633 when you try to use it without calling any of the scan_* 634 methods first. You don't need to call this yourself. 635 """ 636 if not self.__threadDict: 637 self.scan_threads()
638
639 - def __contains__(self, anObject):
640 """ 641 @type anObject: L{Thread}, int 642 @param anObject: 643 - C{int}: Global ID of the thread to look for. 644 - C{Thread}: Thread object to look for. 645 646 @rtype: bool 647 @return: C{True} if the snapshot contains 648 a L{Thread} object with the same ID. 649 """ 650 if isinstance(anObject, Thread): 651 anObject = anObject.dwThreadId 652 return self.has_thread(anObject)
653
654 - def __iter__(self):
655 """ 656 @see: L{iter_threads} 657 @rtype: dictionary-valueiterator 658 @return: Iterator of L{Thread} objects in this snapshot. 659 """ 660 return self.iter_threads()
661
662 - def __len__(self):
663 """ 664 @see: L{get_thread_count} 665 @rtype: int 666 @return: Count of L{Thread} objects in this snapshot. 667 """ 668 return self.get_thread_count()
669
670 - def has_thread(self, dwThreadId):
671 """ 672 @type dwThreadId: int 673 @param dwThreadId: Global ID of the thread to look for. 674 675 @rtype: bool 676 @return: C{True} if the snapshot contains a 677 L{Thread} object with the given global ID. 678 """ 679 self.__initialize_snapshot() 680 return dwThreadId in self.__threadDict
681
682 - def get_thread(self, dwThreadId):
683 """ 684 @type dwThreadId: int 685 @param dwThreadId: Global ID of the thread to look for. 686 687 @rtype: L{Thread} 688 @return: Thread object with the given global ID. 689 """ 690 self.__initialize_snapshot() 691 if dwThreadId not in self.__threadDict: 692 msg = "Unknown thread ID: %d" % dwThreadId 693 raise KeyError, msg 694 return self.__threadDict[dwThreadId]
695
696 - def iter_thread_ids(self):
697 """ 698 @see: L{iter_threads} 699 @rtype: dictionary-keyiterator 700 @return: Iterator of global thread IDs in this snapshot. 701 """ 702 self.__initialize_snapshot() 703 return self.__threadDict.iterkeys()
704
705 - def iter_threads(self):
706 """ 707 @see: L{iter_thread_ids} 708 @rtype: dictionary-valueiterator 709 @return: Iterator of L{Thread} objects in this snapshot. 710 """ 711 self.__initialize_snapshot() 712 return self.__threadDict.itervalues()
713
714 - def get_thread_ids(self):
715 """ 716 @rtype: list( int ) 717 @return: List of global thread IDs in this snapshot. 718 """ 719 self.__initialize_snapshot() 720 return self.__threadDict.keys()
721
722 - def get_thread_count(self):
723 """ 724 @rtype: int 725 @return: Count of L{Thread} objects in this snapshot. 726 """ 727 self.__initialize_snapshot() 728 return len(self.__threadDict)
729 730 #------------------------------------------------------------------------------ 731
732 - def find_threads_by_name(self, name, bExactMatch = True):
733 """ 734 Find threads by name, using different search methods. 735 736 @type name: str, None 737 @param name: Name to look for. Use C{None} to find nameless threads. 738 739 @type bExactMatch: bool 740 @param bExactMatch: C{True} if the name must be 741 B{exactly} as given, C{False} if the name can be 742 loosely matched. 743 744 This parameter is ignored when C{name} is C{None}. 745 746 @rtype: list( L{Thread} ) 747 @return: All threads matching the given name. 748 """ 749 found_threads = list() 750 751 # Find threads with no name. 752 if name is None: 753 for aThread in self.iter_threads(): 754 if aThread.get_name() is None: 755 found_threads.append(aThread) 756 757 # Find threads matching the given name exactly. 758 elif bExactMatch: 759 for aThread in self.iter_threads(): 760 if aThread.get_name() == name: 761 found_threads.append(aThread) 762 763 # Find threads whose names match the given substring. 764 else: 765 for aThread in self.iter_threads(): 766 t_name = aThread.get_name() 767 if t_name is not None and name in t_name: 768 found_threads.append(aThread) 769 770 return found_threads
771 772 #------------------------------------------------------------------------------ 773
774 - def start_thread(self, lpStartAddress, lpParameter=0, bSuspended = False):
775 """ 776 Remotely creates a new thread in the process. 777 778 @type lpStartAddress: int 779 @param lpStartAddress: Start address for the new thread. 780 781 @type lpParameter: int 782 @param lpParameter: Optional argument for the new thread. 783 784 @type bSuspended: bool 785 @param bSuspended: C{True} if the new thread should be suspended. 786 In that case use L{Thread.resume} to start execution. 787 """ 788 if bSuspended: 789 dwCreationFlags = win32.CREATE_SUSPENDED 790 else: 791 dwCreationFlags = 0 792 hThread, dwThreadId = win32.CreateRemoteThread(self.get_handle(), 0, 0, 793 lpStartAddress, lpParameter, dwCreationFlags) 794 aThread = Thread(dwThreadId, hThread, self) 795 self.__add_thread(aThread) 796 return aThread
797 798 #------------------------------------------------------------------------------ 799 800 # TODO 801 # maybe put all the toolhelp code into their own set of classes? 802 # 803 # XXX this method musn't end up calling __initialize_snapshot by accident!
804 - def scan_threads(self):
805 """ 806 Populates the snapshot with running threads. 807 """ 808 809 # Ignore process IDs 0 and 4. 810 # PID 0: System Idle Process. Also has a special meaning to the 811 # toolhelp APIs (current process). 812 # PID 4: System Integrity Group. See this forum post for more info: 813 # http://tinyurl.com/ycza8jo 814 # (points to social.technet.microsoft.com) 815 dwProcessId = self.get_pid() 816 if dwProcessId in (0, 4): 817 return 818 819 ## dead_tids = set( self.get_thread_ids() ) # XXX triggers a scan 820 dead_tids = self.__threadDict.keys() 821 dwProcessId = self.get_pid() 822 hSnapshot = win32.CreateToolhelp32Snapshot(win32.TH32CS_SNAPTHREAD, 823 dwProcessId) 824 try: 825 te = win32.Thread32First(hSnapshot) 826 while te is not None: 827 if te.th32OwnerProcessID == dwProcessId: 828 dwThreadId = te.th32ThreadID 829 if dwThreadId in dead_tids: 830 dead_tids.remove(dwThreadId) 831 ## if not self.has_thread(dwThreadId): # XXX triggers a scan 832 if not self.__threadDict.has_key(dwThreadId): 833 aThread = Thread(dwThreadId, process = self) 834 self.__add_thread(aThread) 835 te = win32.Thread32Next(hSnapshot) 836 finally: 837 win32.CloseHandle(hSnapshot) 838 for tid in dead_tids: 839 self.__del_thread(tid)
840
841 - def clear_dead_threads(self):
842 """ 843 Remove Thread objects from the snapshot 844 referring to threads no longer running. 845 """ 846 for tid in self.get_thread_ids(): 847 aThread = self.get_thread(tid) 848 if not aThread.is_alive(): 849 self.__del_thread(aThread)
850
851 - def clear_threads(self):
852 """ 853 Clears the threads snapshot. 854 """ 855 self.__threadDict = dict()
856
857 - def close_thread_handles(self):
858 """ 859 Closes all open handles to threads in the snapshot. 860 """ 861 for aThread in self.iter_threads(): 862 try: 863 aThread.close_handle() 864 except Exception, e: 865 pass
866 867 #------------------------------------------------------------------------------ 868 869 # XXX notify_* methods should not trigger a scan 870
871 - def __add_thread(self, aThread):
872 ## if not isinstance(aThread, Thread): 873 ## if hasattr(aThread, '__class__'): 874 ## typename = aThread.__class__.__name__ 875 ## else: 876 ## typename = str(type(aThread)) 877 ## msg = "Expected Thread, got %s instead" % typename 878 ## raise TypeError, msg 879 dwThreadId = aThread.dwThreadId 880 ## if dwThreadId in self.__threadDict: 881 ## msg = "Already have a Thread object with ID %d" % dwThreadId 882 ## raise KeyError, msg 883 aThread.dwProcessId = self.get_pid() 884 self.__threadDict[dwThreadId] = aThread
885
886 - def __del_thread(self, dwThreadId):
887 ## if dwThreadId not in self.__threadDict: 888 ## msg = "Unknown thread ID: %d" % dwThreadId 889 ## raise KeyError, msg 890 del self.__threadDict[dwThreadId]
891
892 - def __add_created_thread(self, event):
893 dwThreadId = event.get_tid() 894 hThread = event.get_thread_handle() 895 ## if not self.has_thread(dwThreadId): # XXX this would trigger a scan 896 if not self.__threadDict.has_key(dwThreadId): 897 aThread = Thread(dwThreadId, hThread, self) 898 self.__add_thread(aThread) 899 else: 900 aThread = self.get_thread(dwThreadId) 901 if hThread != win32.INVALID_HANDLE_VALUE: 902 aThread.hThread = hThread # may have more privileges
903
904 - def notify_create_process(self, event):
905 """ 906 Notify the creation of the main thread of this process. 907 908 This is done automatically by the L{Debug} class, you shouldn't need 909 to call it yourself. 910 911 @type event: L{CreateProcessEvent} 912 @param event: Create process event. 913 """ 914 self.__add_created_thread(event) 915 return True
916
917 - def notify_create_thread(self, event):
918 """ 919 Notify the creation of a new thread in this process. 920 921 This is done automatically by the L{Debug} class, you shouldn't need 922 to call it yourself. 923 924 @type event: L{CreateThreadEvent} 925 @param event: Create thread event. 926 """ 927 self.__add_created_thread(event) 928 return True
929
930 - def notify_exit_thread(self, event):
931 """ 932 Notify the termination of a thread. 933 934 This is done automatically by the L{Debug} class, you shouldn't need 935 to call it yourself. 936 937 @type event: L{ExitThreadEvent} 938 @param event: Exit thread event. 939 """ 940 dwThreadId = event.get_tid() 941 ## if self.has_thread(dwThreadId): # XXX this would trigger a scan 942 if self.__threadDict.has_key(dwThreadId): 943 self.__del_thread(dwThreadId) 944 return True
945
946 #============================================================================== 947 948 -class ProcessContainer (object):
949 """ 950 Encapsulates the capability to contain Process objects. 951 952 @group Instrumentation: 953 start_process, argv_to_cmdline, cmdline_to_argv 954 955 @group Processes snapshot: 956 scan, scan_processes, scan_processes_fast, 957 get_process, get_process_count, get_process_ids, 958 has_process, iter_processes, iter_process_ids, 959 find_processes_by_filename, get_pid_from_tid, 960 clear, clear_processes, clear_dead_processes, 961 clear_unattached_processes, 962 close_process_handles, 963 close_process_and_thread_handles 964 965 @group Threads snapshots: 966 scan_processes_and_threads, 967 get_thread, get_thread_count, get_thread_ids, 968 has_thread 969 970 @group Modules snapshots: 971 scan_modules, find_modules_by_address, 972 find_modules_by_base, find_modules_by_name, 973 get_module_count 974 975 @group Event notifications (private): 976 notify_create_process, 977 notify_exit_process 978 """ 979
980 - def __init__(self):
981 super(ProcessContainer, self).__init__() 982 self.__processDict = dict()
983
984 - def __initialize_snapshot(self):
985 """ 986 Private method to automatically initialize the snapshot 987 when you try to use it without calling any of the scan_* 988 methods first. You don't need to call this yourself. 989 """ 990 if not self.__processDict: 991 ## self.scan() # recursive scan 992 try: 993 self.scan_processes() # normal scan 994 except Exception: 995 self.scan_processes_fast() # fast scan (no filenames)
996
997 - def __contains__(self, anObject):
998 """ 999 @type anObject: L{Process}, L{Thread}, int 1000 @param anObject: 1001 - C{int}: Global ID of the process to look for. 1002 - C{int}: Global ID of the thread to look for. 1003 - C{Process}: Process object to look for. 1004 - C{Thread}: Thread object to look for. 1005 1006 @rtype: bool 1007 @return: C{True} if the snapshot contains 1008 a L{Process} or L{Thread} object with the same ID. 1009 """ 1010 if isinstance(anObject, Process): 1011 anObject = anObject.dwProcessId 1012 if self.has_process(anObject): 1013 return True 1014 for aProcess in self.iter_processes(): 1015 if anObject in aProcess: 1016 return True 1017 return False
1018
1019 - def __iter__(self):
1020 """ 1021 @see: L{iter_processes} 1022 @rtype: dictionary-valueiterator 1023 @return: Iterator of L{Process} objects in this snapshot. 1024 """ 1025 return self.iter_processes()
1026
1027 - def __len__(self):
1028 """ 1029 @see: L{get_process_count} 1030 @rtype: int 1031 @return: Count of L{Process} objects in this snapshot. 1032 """ 1033 return self.get_process_count()
1034
1035 - def has_process(self, dwProcessId):
1036 """ 1037 @type dwProcessId: int 1038 @param dwProcessId: Global ID of the process to look for. 1039 1040 @rtype: bool 1041 @return: C{True} if the snapshot contains a 1042 L{Process} object with the given global ID. 1043 """ 1044 self.__initialize_snapshot() 1045 return dwProcessId in self.__processDict
1046
1047 - def get_process(self, dwProcessId):
1048 """ 1049 @type dwProcessId: int 1050 @param dwProcessId: Global ID of the process to look for. 1051 1052 @rtype: L{Process} 1053 @return: Process object with the given global ID. 1054 """ 1055 self.__initialize_snapshot() 1056 if dwProcessId not in self.__processDict: 1057 msg = "Unknown process ID %d" % dwProcessId 1058 raise KeyError, msg 1059 return self.__processDict[dwProcessId]
1060
1061 - def iter_process_ids(self):
1062 """ 1063 @see: L{iter_processes} 1064 @rtype: dictionary-keyiterator 1065 @return: Iterator of global process IDs in this snapshot. 1066 """ 1067 self.__initialize_snapshot() 1068 return self.__processDict.iterkeys()
1069
1070 - def iter_processes(self):
1071 """ 1072 @see: L{iter_process_ids} 1073 @rtype: dictionary-valueiterator 1074 @return: Iterator of L{Process} objects in this snapshot. 1075 """ 1076 self.__initialize_snapshot() 1077 return self.__processDict.itervalues()
1078
1079 - def get_process_ids(self):
1080 """ 1081 @see: L{iter_process_ids} 1082 @rtype: list( int ) 1083 @return: List of global process IDs in this snapshot. 1084 """ 1085 self.__initialize_snapshot() 1086 return self.__processDict.keys()
1087
1088 - def get_process_count(self):
1089 """ 1090 @rtype: int 1091 @return: Count of L{Process} objects in this snapshot. 1092 """ 1093 self.__initialize_snapshot() 1094 return len(self.__processDict)
1095 1096 #------------------------------------------------------------------------------ 1097
1098 - def get_windows(self):
1099 window_list = list() 1100 for process in self.iter_processes(): 1101 window_list.extend( process.get_windows() ) 1102 return window_list
1103
1104 - def get_pid_from_tid(self, dwThreadId):
1105 """ 1106 Tries to retrieve the global ID of the process that owns the thread. 1107 If it's not possible, returns C{None}. 1108 1109 @type dwThreadId: int 1110 @param dwThreadId: Thread global ID. 1111 1112 @rtype: int or None 1113 @return: Process global ID, or C{None}. 1114 """ 1115 try: 1116 dwProcessId = Thread(dwThreadId).get_pid() 1117 except Exception: 1118 dwProcessId = None 1119 if dwProcessId is None: 1120 for aProcess in self.iter_processes(): 1121 if aProcess.has_thread(dwThreadId): 1122 dwProcessId = aProcess.get_pid() 1123 break 1124 return dwProcessId
1125 1126 #------------------------------------------------------------------------------ 1127 1128 @staticmethod
1129 - def argv_to_cmdline(argv):
1130 """ 1131 Convert a list of arguments to a single command line string. 1132 1133 @type argv: list( str ) 1134 @param argv: List of argument strings. 1135 The first element is the program to execute. 1136 1137 @rtype: str 1138 @return: Command line string. 1139 """ 1140 cmdline = list() 1141 for token in argv: 1142 if not token: 1143 token = '""' 1144 else: 1145 if '"' in token: 1146 token = token.replace('"', '\\"') 1147 if ' ' in token or \ 1148 '\t' in token or \ 1149 '\n' in token or \ 1150 '\r' in token: 1151 token = '"%s"' % token 1152 cmdline.append(token) 1153 return ' '.join(cmdline)
1154 1155 @staticmethod
1156 - def cmdline_to_argv(lpCmdLine):
1157 """ 1158 Convert a single command line string to a list of arguments. 1159 1160 @type lpCmdLine: str 1161 @param lpCmdLine: Command line string. 1162 The first token is the program to execute. 1163 1164 @rtype: list( str ) 1165 @return: List of argument strings. 1166 """ 1167 if not lpCmdLine: 1168 return [] 1169 return win32.CommandLineToArgv(lpCmdLine)
1170
1171 - def start_process(self, lpCmdLine, 1172 bConsole = False, 1173 bDebug = False, 1174 bFollow = False, 1175 bSuspended = False, 1176 bInheritHandles = False, 1177 dwParentProcessId = None 1178 ):
1179 """ 1180 Starts a new process for instrumenting (or debugging). 1181 1182 @type lpCmdLine: str 1183 @param lpCmdLine: Command line to execute. Can't be an empty string. 1184 1185 @type bConsole: bool 1186 @param bConsole: C{True} if the new process should inherit the console. 1187 Defaults to C{False}. 1188 1189 @type bDebug: bool 1190 @param bDebug: C{True} to attach to the new process. 1191 To debug a process it's best to use the L{Debug} class instead. 1192 Defaults to C{False}. 1193 1194 @type bFollow: bool 1195 @param bFollow: C{True} to automatically attach to the child processes 1196 of the newly created process. Ignored unless C{bDebug} is C{True}. 1197 Defaults to C{False}. 1198 1199 @type bSuspended: bool 1200 @param bSuspended: C{True} if the new process should be suspended. 1201 Defaults to C{False}. 1202 1203 @type bInheritHandles: bool 1204 @param bInheritHandles: C{True} if the new process should inherit it's 1205 parent process' handles. Defaults to C{False}. 1206 1207 @type dwParentProcessId: int or None 1208 @param dwParentProcessId: C{None} if the debugger process should be the 1209 parent process (default), or a process ID to forcefully set as the 1210 debuguee's parent (only available for Windows Vista and above). 1211 1212 @rtype: L{Process} 1213 @return: Process object. 1214 """ 1215 if not lpCmdLine: 1216 raise ValueError, "Missing command line to execute!" 1217 dwCreationFlags = 0 1218 dwCreationFlags |= win32.CREATE_DEFAULT_ERROR_MODE 1219 dwCreationFlags |= win32.CREATE_BREAKAWAY_FROM_JOB 1220 if not bConsole: 1221 dwCreationFlags |= win32.DETACHED_PROCESS 1222 if bSuspended: 1223 dwCreationFlags |= win32.CREATE_SUSPENDED 1224 if bDebug: 1225 dwCreationFlags |= win32.DEBUG_PROCESS 1226 if bDebug and not bFollow: 1227 dwCreationFlags |= win32.DEBUG_ONLY_THIS_PROCESS 1228 lpStartupInfo = None 1229 if dwParentProcessId is not None: 1230 myPID = win32.GetProcessId( win32.GetCurrentProcess() ) 1231 if dwParentProcessId != myPID: 1232 if self.has_process(dwParentProcessId): 1233 ParentProcess = self.get_process(dwParentProcessId) 1234 else: 1235 ParentProcess = Process(dwParentProcessId) 1236 ParentProcessHandle = ParentProcess.get_handle()._as_parameter_ 1237 AttributeList = ( 1238 ( 1239 win32.PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, 1240 ParentProcessHandle 1241 ), 1242 ) 1243 AttributeList = win32.ProcThreadAttributeList(AttributeList) 1244 StartupInfoEx = win32.STARTUPINFOEX() 1245 StartupInfo = StartupInfoEx.StartupInfo 1246 StartupInfo.cb = win32.sizeof(win32.STARTUPINFOEX) 1247 StartupInfo.lpReserved = 0 1248 StartupInfo.lpDesktop = 0 1249 StartupInfo.lpTitle = 0 1250 StartupInfo.dwFlags = 0 1251 StartupInfo.cbReserved2 = 0 1252 StartupInfo.lpReserved2 = 0 1253 StartupInfoEx.lpAttributeList = AttributeList.value 1254 lpStartupInfo = StartupInfoEx 1255 dwCreationFlags |= win32.EXTENDED_STARTUPINFO_PRESENT 1256 pi = win32.CreateProcess(win32.NULL, lpCmdLine, 1257 bInheritHandles = bInheritHandles, 1258 dwCreationFlags = dwCreationFlags, 1259 lpStartupInfo = lpStartupInfo) 1260 aProcess = Process(pi.dwProcessId, pi.hProcess) 1261 aThread = Thread (pi.dwThreadId, pi.hThread) 1262 aProcess._ThreadContainer__add_thread(aThread) 1263 self.__add_process(aProcess) 1264 return aProcess
1265 1266 #------------------------------------------------------------------------------ 1267 1268 # XXX this methods musn't end up calling __initialize_snapshot by accident! 1269
1270 - def scan(self):
1271 """ 1272 Populates the snapshot with running processes and threads, 1273 and loaded modules. 1274 """ 1275 try: 1276 self.scan_processes_and_threads() 1277 except Exception: 1278 self.scan_processes_fast() 1279 raise 1280 self.scan_modules()
1281
1282 - def scan_processes_and_threads(self):
1283 """ 1284 Populates the snapshot with running processes and threads. 1285 """ 1286 our_pid = win32.GetProcessId( win32.GetCurrentProcess() ) 1287 ## dead_pids = set( self.get_process_ids() ) # XXX triggers a scan 1288 dead_pids = set( self.__processDict.keys() ) 1289 found_tids = set() 1290 1291 # Ignore our own process if it's in the snapshot for some reason 1292 if our_pid in dead_pids: 1293 dead_pids.remove(our_pid) 1294 1295 # Take a snapshot of all processes and threads 1296 # (excluding our own) 1297 dwFlags = win32.TH32CS_SNAPPROCESS | win32.TH32CS_SNAPTHREAD 1298 hSnapshot = win32.CreateToolhelp32Snapshot(dwFlags) 1299 try: 1300 1301 # Add all the processes 1302 pe = win32.Process32First(hSnapshot) 1303 while pe is not None: 1304 dwProcessId = pe.th32ProcessID 1305 if dwProcessId != our_pid: 1306 if dwProcessId in dead_pids: 1307 dead_pids.remove(dwProcessId) 1308 ## if not self.has_process(dwProcessId): # XXX triggers a scan 1309 if not self.__processDict.has_key(dwProcessId): 1310 aProcess = Process(dwProcessId) 1311 self.__add_process(aProcess) 1312 elif pe.szExeFile: 1313 aProcess = self.get_process(dwProcessId) 1314 if not aProcess.fileName: 1315 aProcess.fileName = pe.szExeFile 1316 pe = win32.Process32Next(hSnapshot) 1317 1318 # Add all the threads 1319 te = win32.Thread32First(hSnapshot) 1320 while te is not None: 1321 dwProcessId = te.th32OwnerProcessID 1322 if dwProcessId != our_pid: 1323 if dwProcessId in dead_pids: 1324 dead_pids.remove(dwProcessId) 1325 ## if self.has_process(dwProcessId): # XXX triggers a scan 1326 if self.__processDict.has_key(dwProcessId): 1327 aProcess = self.get_process(dwProcessId) 1328 else: 1329 aProcess = Process(dwProcessId) 1330 self.__add_process(aProcess) 1331 dwThreadId = te.th32ThreadID 1332 found_tids.add(dwThreadId) 1333 ## if not aProcess.has_thread(dwThreadId): # XXX triggers a scan 1334 if not aProcess._ThreadContainer__threadDict.has_key(dwThreadId): 1335 aThread = Thread(dwThreadId, process = aProcess) 1336 aProcess._ThreadContainer__add_thread(aThread) 1337 te = win32.Thread32Next(hSnapshot) 1338 1339 # Always close the snapshot handle before returning 1340 finally: 1341 win32.CloseHandle(hSnapshot) 1342 1343 # Remove dead processes 1344 for pid in dead_pids: 1345 self.__del_process(pid) 1346 1347 # Remove dead threads 1348 ## for aProcess in self.iter_processes(): # XXX triggers a scan 1349 for aProcess in self.__processDict.itervalues(): 1350 ## dead_tids = set( aProcess.get_thread_ids() ) # XXX triggers a scan 1351 dead_tids = set( aProcess._ThreadContainer__threadDict.keys() ) 1352 dead_tids.difference_update(found_tids) 1353 for tid in dead_tids: 1354 aProcess._ThreadContainer__del_thread(tid)
1355
1356 - def scan_modules(self):
1357 """ 1358 Populates the snapshot with loaded modules. 1359 """ 1360 ## for aProcess in self.iter_processes(): # XXX triggers a scan 1361 for aProcess in self.__processDict.itervalues(): 1362 try: 1363 aProcess.scan_modules() 1364 except WindowsError, e: 1365 # For some reason, scanning the modules of PID 4 always fails. 1366 dwProcessId = aProcess.get_pid() 1367 if dwProcessId == 4 and e.winerror == 8: 1368 continue
1369
1370 - def scan_processes(self):
1371 """ 1372 Populates the snapshot with running processes. 1373 """ 1374 our_pid = win32.GetProcessId( win32.GetCurrentProcess() ) 1375 ## dead_pids = set( self.get_process_ids() ) # XXX triggers a scan 1376 dead_pids = set( self.__processDict.keys() ) 1377 if our_pid in dead_pids: 1378 dead_pids.remove(our_pid) 1379 hSnapshot = win32.CreateToolhelp32Snapshot(win32.TH32CS_SNAPPROCESS) 1380 try: 1381 pe = win32.Process32First(hSnapshot) 1382 while pe is not None: 1383 dwProcessId = pe.th32ProcessID 1384 if dwProcessId != our_pid: 1385 if dwProcessId in dead_pids: 1386 dead_pids.remove(dwProcessId) 1387 ## if not self.has_process(dwProcessId): # XXX triggers a scan 1388 if not self.__processDict.has_key(dwProcessId): 1389 aProcess = Process(dwProcessId) 1390 self.__add_process(aProcess) 1391 elif pe.szExeFile: 1392 aProcess = self.get_process(dwProcessId) 1393 if not aProcess.fileName: 1394 aProcess.fileName = pe.szExeFile 1395 pe = win32.Process32Next(hSnapshot) 1396 finally: 1397 win32.CloseHandle(hSnapshot) 1398 for pid in dead_pids: 1399 self.__del_process(pid)
1400
1401 - def scan_processes_fast(self):
1402 """ 1403 Populates the snapshot with running processes. 1404 Only the PID is retrieved for each process. 1405 1406 Dead processes are removed. 1407 Threads and modules of living processes are ignored. 1408 1409 @note: This method may be faster for scanning, but some information 1410 may be missing, outdated or slower to obtain. This could be a good 1411 tradeoff under some circumstances. 1412 """ 1413 1414 # Get the new and old list of pids 1415 new_pids = set( win32.EnumProcesses() ) 1416 ## old_pids = set( self.get_process_ids() ) # XXX triggers a scan 1417 old_pids = set( self.__processDict.keys() ) 1418 1419 # Ignore our own pid 1420 our_pid = win32.GetProcessId( win32.GetCurrentProcess() ) 1421 if our_pid in new_pids: 1422 new_pids.remove(our_pid) 1423 if our_pid in old_pids: 1424 old_pids.remove(our_pid) 1425 1426 # Add newly found pids 1427 for pid in new_pids.difference(old_pids): 1428 self.__add_process( Process(pid) ) 1429 1430 # Remove missing pids 1431 for pid in old_pids.difference(new_pids): 1432 self.__del_process(pid)
1433
1434 - def clear_dead_processes(self):
1435 """ 1436 Removes Process objects from the snapshot 1437 referring to processes no longer running. 1438 """ 1439 for pid in self.get_process_ids(): 1440 aProcess = self.get_process(pid) 1441 if not aProcess.is_alive(): 1442 self.__del_process(aProcess)
1443
1444 - def clear_unattached_processes(self):
1445 """ 1446 Removes Process objects from the snapshot 1447 referring to processes not being debugged. 1448 """ 1449 for pid in self.get_process_ids(): 1450 aProcess = self.get_process(pid) 1451 if not aProcess.is_being_debugged(): 1452 self.__del_process(aProcess)
1453
1454 - def close_process_handles(self):
1455 """ 1456 Closes all open handles to processes in this snapshot. 1457 """ 1458 for pid in self.get_process_ids(): 1459 aProcess = self.get_process(pid) 1460 try: 1461 aProcess.close_handle() 1462 except Exception, e: 1463 pass
1464
1466 """ 1467 Closes all open handles to processes and threads in this snapshot. 1468 """ 1469 for pid in self.get_process_ids(): 1470 aProcess = self.get_process(pid) 1471 aProcess.close_thread_handles() 1472 try: 1473 aProcess.close_handle() 1474 except Exception, e: 1475 pass
1476
1477 - def clear_processes(self):
1478 """ 1479 Removes all L{Process}, L{Thread} and L{Module} objects in this snapshot. 1480 """ 1481 self.__processDict = dict()
1482
1483 - def clear(self):
1484 """ 1485 Clears this snapshot. 1486 1487 @see: L{clear_processes} 1488 """ 1489 self.clear_processes()
1490 1491 #------------------------------------------------------------------------------ 1492 1493 # Docs for these methods are taken from the ThreadContainer class. 1494
1495 - def has_thread(self, dwThreadId):
1496 dwProcessId = self.get_pid_from_tid(dwThreadId) 1497 if dwProcessId is None: 1498 return False 1499 return self.has_process(dwProcessId)
1500
1501 - def get_thread(self, dwThreadId):
1502 dwProcessId = self.get_pid_from_tid(dwThreadId) 1503 if dwProcessId is None: 1504 msg = "Unknown thread ID %d" % dwThreadId 1505 raise KeyError, msg 1506 return self.get_process(dwProcessId).get_thread(dwThreadId)
1507
1508 - def get_thread_ids(self):
1509 ids = list() 1510 for aProcess in self.iter_processes(): 1511 ids += aProcess.get_thread_ids() 1512 return ids
1513
1514 - def get_thread_count(self):
1515 count = 0 1516 for aProcess in self.iter_processes(): 1517 count += aProcess.get_thread_count() 1518 return count
1519 1520 has_thread.__doc__ = ThreadContainer.has_thread.__doc__ 1521 get_thread.__doc__ = ThreadContainer.get_thread.__doc__ 1522 get_thread_ids.__doc__ = ThreadContainer.get_thread_ids.__doc__ 1523 get_thread_count.__doc__ = ThreadContainer.get_thread_count.__doc__ 1524 1525 #------------------------------------------------------------------------------ 1526 1527 # Docs for these methods are taken from the ModuleContainer class. 1528
1529 - def get_module_count(self):
1530 count = 0 1531 for aProcess in self.iter_processes(): 1532 count += aProcess.get_module_count() 1533 return count
1534 1535 get_module_count.__doc__ = ModuleContainer.get_module_count.__doc__ 1536 1537 #------------------------------------------------------------------------------ 1538
1539 - def find_modules_by_base(self, lpBaseOfDll):
1540 """ 1541 @rtype: list( L{Module}... ) 1542 @return: List of Module objects with the given base address. 1543 """ 1544 found = list() 1545 for aProcess in self.iter_processes(): 1546 if aProcess.has_module(lpBaseOfDll): 1547 aModule = aProcess.get_module(lpBaseOfDll) 1548 found.append( (aProcess, aModule) ) 1549 return found
1550
1551 - def find_modules_by_name(self, fileName):
1552 """ 1553 @rtype: list( L{Module}... ) 1554 @return: List of Module objects found. 1555 """ 1556 found = list() 1557 for aProcess in self.iter_processes(): 1558 aModule = aProcess.get_module_by_name(fileName) 1559 if aModule is not None: 1560 found.append( (aProcess, aModule) ) 1561 return found
1562
1563 - def find_modules_by_address(self, address):
1564 """ 1565 @rtype: list( L{Module}... ) 1566 @return: List of Module objects that best match the given address. 1567 """ 1568 found = list() 1569 for aProcess in self.iter_processes(): 1570 aModule = aProcess.get_module_at_address(address) 1571 if aModule is not None: 1572 found.append( (aProcess, aModule) ) 1573 return found
1574
1575 - def __find_processes_by_filename(self, filename):
1576 """ 1577 Internally used by L{find_processes_by_filename}. 1578 """ 1579 found = list() 1580 filename = filename.lower() 1581 if PathOperations.path_is_absolute(filename): 1582 for aProcess in self.iter_processes(): 1583 imagename = aProcess.get_filename() 1584 if imagename and imagename.lower() == filename: 1585 found.append( (aProcess, imagename) ) 1586 else: 1587 for aProcess in self.iter_processes(): 1588 imagename = aProcess.get_filename() 1589 if imagename: 1590 imagename = PathOperations.pathname_to_filename(imagename) 1591 if imagename.lower() == filename: 1592 found.append( (aProcess, imagename) ) 1593 return found
1594
1595 - def find_processes_by_filename(self, fileName):
1596 """ 1597 @type fileName: str 1598 @param fileName: Filename to search for. 1599 If it's a full pathname, the match must be exact. 1600 If it's a base filename only, the file part is matched, 1601 regardless of the directory where it's located. 1602 1603 @note: If the process is not found and the file extension is not 1604 given, this method will search again assuming a default 1605 extension (.exe). 1606 1607 @rtype: list of tuple( L{Process}, str ) 1608 @return: List of processes matching the given main module filename. 1609 Each tuple contains a Process object and it's filename. 1610 """ 1611 found = self.__find_processes_by_filename(fileName) 1612 if not found: 1613 fn, ext = PathOperations.split_extension(fileName) 1614 if not ext: 1615 fileName = '%s.exe' % fn 1616 found = self.__find_processes_by_filename(fileName) 1617 return found
1618 1619 #------------------------------------------------------------------------------ 1620 1621 # XXX notify_* methods should not trigger a scan 1622
1623 - def __add_process(self, aProcess):
1624 ## if not isinstance(aProcess, Process): 1625 ## if hasattr(aProcess, '__class__'): 1626 ## typename = aProcess.__class__.__name__ 1627 ## else: 1628 ## typename = str(type(aProcess)) 1629 ## msg = "Expected Process, got %s instead" % typename 1630 ## raise TypeError, msg 1631 dwProcessId = aProcess.dwProcessId 1632 ## if dwProcessId in self.__processDict: 1633 ## msg = "Process already exists: %d" % dwProcessId 1634 ## raise KeyError, msg 1635 self.__processDict[dwProcessId] = aProcess
1636
1637 - def __del_process(self, dwProcessId):
1638 ## if dwProcessId not in self.__processDict: 1639 ## msg = "Unknown process ID %d" % dwProcessId 1640 ## raise KeyError, msg 1641 del self.__processDict[dwProcessId]
1642 1643 # Notify the creation of a new process.
1644 - def notify_create_process(self, event):
1645 """ 1646 Notify the creation of a new process. 1647 1648 This is done automatically by the L{Debug} class, you shouldn't need 1649 to call it yourself. 1650 1651 @type event: L{CreateProcessEvent} 1652 @param event: Create process event. 1653 """ 1654 dwProcessId = event.get_pid() 1655 dwThreadId = event.get_tid() 1656 hProcess = event.get_process_handle() 1657 ## if not self.has_process(dwProcessId): # XXX this would trigger a scan 1658 if not self.__processDict.has_key(dwProcessId): 1659 aProcess = Process(dwProcessId, hProcess) 1660 self.__add_process(aProcess) 1661 aProcess.fileName = event.get_filename() 1662 else: 1663 aProcess = self.get_process(dwProcessId) 1664 if hProcess != win32.INVALID_HANDLE_VALUE: 1665 aProcess.hProcess = hProcess # may have more privileges 1666 if not aProcess.fileName: 1667 fileName = event.get_filename() 1668 if fileName: 1669 aProcess.fileName = fileName 1670 return aProcess.notify_create_process(event) # pass it to the process
1671
1672 - def notify_exit_process(self, event):
1673 """ 1674 Notify the termination of a process. 1675 1676 This is done automatically by the L{Debug} class, you shouldn't need 1677 to call it yourself. 1678 1679 @type event: L{ExitProcessEvent} 1680 @param event: Exit process event. 1681 """ 1682 dwProcessId = event.get_pid() 1683 ## if self.has_process(dwProcessId): # XXX this would trigger a scan 1684 if self.__processDict.has_key(dwProcessId): 1685 self.__del_process(dwProcessId) 1686 return True
1687
1688 #============================================================================== 1689 1690 -class MemoryAddresses (object):
1691 """ 1692 Class to manipulate memory addresses. 1693 """ 1694 1695 @staticmethod
1696 - def align_address_to_page_start(address):
1697 """ 1698 Align the given address to the start of the page it occupies. 1699 1700 @type address: int 1701 @param address: Memory address. 1702 1703 @rtype: int 1704 @return: Aligned memory address. 1705 """ 1706 return address - ( address % System.pageSize )
1707 1708 @staticmethod
1709 - def align_address_to_page_end(address):
1710 """ 1711 Align the given address to the end of the page it occupies. 1712 1713 @type address: int 1714 @param address: Memory address. 1715 1716 @rtype: int 1717 @return: Aligned memory address. 1718 """ 1719 return address + System.pageSize - ( address % System.pageSize )
1720 1721 @classmethod
1722 - def align_address_range(cls, begin, end):
1723 """ 1724 Align the given address range to the start and end of the page(s) it occupies. 1725 1726 @type begin: int 1727 @param begin: Memory address of the beginning of the buffer. 1728 1729 @type end: int 1730 @param end: Memory address of the end of the buffer. 1731 1732 @rtype: tuple( int, int ) 1733 @return: Aligned memory addresses. 1734 """ 1735 if end > begin: 1736 begin, end = end, begin 1737 return ( 1738 cls.align_address_to_page_start(begin), 1739 cls.align_address_to_page_end(end) 1740 )
1741 1742 @classmethod
1743 - def get_buffer_size_in_pages(cls, address, size):
1744 """ 1745 Get the number of pages in use by the given buffer. 1746 1747 @type address: int 1748 @param address: Aligned memory address. 1749 1750 @type size: int 1751 @param size: Buffer size. 1752 1753 @rtype: int 1754 @return: Buffer size in number of pages. 1755 """ 1756 if size < 0: 1757 size = -size 1758 address = address - size 1759 begin, end = cls.align_address_range(address, address + size) 1760 return int(float(end - begin) / float(System.pageSize))
1761 1762 @staticmethod
1763 - def do_ranges_intersect(begin, end, old_begin, old_end):
1764 return (old_begin <= begin < old_end) or \ 1765 (old_begin < end <= old_end) or \ 1766 (begin <= old_begin < end) or \ 1767 (begin < old_end <= end)
1768
1769 #============================================================================== 1770 1771 # TODO 1772 # * This methods do not take into account that code breakpoints change the 1773 # memory. This object should talk to BreakpointContainer to retrieve the 1774 # original memory contents where code breakpoints are enabled. 1775 # * A memory cache could be implemented here. 1776 -class MemoryOperations (object):
1777 """ 1778 Encapsulates the capabilities to manipulate the memory of a process. 1779 1780 @group Memory mapping: 1781 get_memory_map, malloc, free, mprotect, mquery, is_pointer, 1782 is_address_valid, is_address_free, is_address_reserved, 1783 is_address_commited, is_address_guard, is_address_readable, 1784 is_address_writeable, is_address_copy_on_write, is_address_executable, 1785 is_address_executable_and_writeable 1786 1787 @group Memory read: 1788 read, read_char, read_uint, read_pointer, read_structure, 1789 peek, peek_char, peek_uint, peek_pointer, peek_string 1790 1791 @group Memory write: 1792 write, write_char, write_uint, write_pointer, 1793 poke, poke_char, poke_uint, poke_pointer 1794 """ 1795 1796 # FIXME 1797 # * under Wine reading from an unmapped address returns nulls 1798 # this is wrong, the call to ReadProcessMemory should fail instead 1799 # * under ReactOS it doesn't seem to work at all (more testing needed)
1800 - def read(self, lpBaseAddress, nSize):
1801 """ 1802 Reads from the memory of the process. 1803 1804 @see: L{peek} 1805 1806 @type lpBaseAddress: int 1807 @param lpBaseAddress: Memory address to begin reading. 1808 1809 @type nSize: int 1810 @param nSize: Number of bytes to read. 1811 1812 @rtype: str 1813 @return: Bytes read from the process memory. 1814 1815 @raise WindowsError: On error an exception is raised. 1816 """ 1817 if not self.mquery(lpBaseAddress).has_content(): 1818 raise ctypes.WinError(win32.ERROR_INVALID_ADDRESS) 1819 data = win32.ReadProcessMemory(self.get_handle(), lpBaseAddress, nSize) 1820 if len(data) != nSize: 1821 raise ctypes.WinError() 1822 return data
1823 1824 # FIXME 1825 # * under ReactOS it doesn't seem to work at all (more testing needed)
1826 - def write(self, lpBaseAddress, lpBuffer):
1827 """ 1828 Writes to the memory of the process. 1829 1830 @see: L{poke} 1831 1832 @type lpBaseAddress: int 1833 @param lpBaseAddress: Memory address to begin writing. 1834 1835 @type lpBuffer: int 1836 @param lpBuffer: Bytes to write. 1837 1838 @raise WindowsError: On error an exception is raised. 1839 """ 1840 if not self.mquery(lpBaseAddress).has_content(): 1841 raise ctypes.WinError(win32.ERROR_INVALID_ADDRESS) 1842 r = win32.WriteProcessMemory(self.get_handle(), lpBaseAddress, lpBuffer) 1843 if r != len(lpBuffer): 1844 raise ctypes.WinError()
1845
1846 - def read_uint(self, lpBaseAddress):
1847 """ 1848 Reads a single unsigned integer from the memory of the process. 1849 1850 @see: L{peek} 1851 1852 @type lpBaseAddress: int 1853 @param lpBaseAddress: Memory address to begin reading. 1854 1855 @rtype: int 1856 @return: Integer value read from the process memory. 1857 1858 @raise WindowsError: On error an exception is raised. 1859 """ 1860 packedDword = self.read(lpBaseAddress, 4) 1861 if len(packedDword) != 4: 1862 raise ctypes.WinError() 1863 unpackedDword = struct.unpack('<L', packedDword)[0] 1864 return unpackedDword
1865
1866 - def write_uint(self, lpBaseAddress, unpackedDword):
1867 """ 1868 Writes a single unsigned integer to the memory of the process. 1869 1870 @see: L{poke_uint} 1871 1872 @type lpBaseAddress: int 1873 @param lpBaseAddress: Memory address to begin writing. 1874 1875 @type unpackedDword: int, long 1876 @param unpackedDword: Value to write. 1877 1878 @raise WindowsError: On error an exception is raised. 1879 """ 1880 packedDword = struct.pack('<L', unpackedDword) 1881 self.write(lpBaseAddress, packedDword)
1882
1883 - def read_pointer(self, lpBaseAddress):
1884 """ 1885 Reads a single pointer value from the memory of the process. 1886 1887 @see: L{peek_pointer} 1888 1889 @type lpBaseAddress: int 1890 @param lpBaseAddress: Memory address to begin reading. 1891 1892 @rtype: int 1893 @return: Pointer value read from the process memory. 1894 1895 @raise WindowsError: On error an exception is raised. 1896 """ 1897 lpvoidLength = win32.sizeof(win32.LPVOID) 1898 packedValue = self.read(lpBaseAddress, lpvoidLength) 1899 if lpvoidLength == 4: 1900 lpvoidFmt = '<L' 1901 else: 1902 lpvoidFmt = '<Q' 1903 unpackedValue = struct.unpack(lpvoidFmt, packedValue)[0] 1904 return unpackedValue
1905
1906 - def write_pointer(self, lpBaseAddress, unpackedValue):
1907 """ 1908 Writes a single pointer value to the memory of the process. 1909 1910 @see: L{poke_pointer} 1911 1912 @type lpBaseAddress: int 1913 @param lpBaseAddress: Memory address to begin writing. 1914 1915 @type unpackedValue: int, long 1916 @param unpackedValue: Value to write. 1917 1918 @raise WindowsError: On error an exception is raised. 1919 """ 1920 lpvoidLength = win32.sizeof(win32.LPVOID) 1921 if lpvoidLength == 4: 1922 lpvoidFmt = '<L' 1923 else: 1924 lpvoidFmt = '<Q' 1925 packedValue = struct.pack(lpvoidFmt, unpackedValue) 1926 self.write(lpBaseAddress, packedValue)
1927
1928 - def read_char(self, lpBaseAddress):
1929 """ 1930 Reads a single character to the memory of the process. 1931 1932 @see: L{write_char} 1933 1934 @type lpBaseAddress: int 1935 @param lpBaseAddress: Memory address to begin writing. 1936 1937 @rtype: int 1938 @return: Character value read from the process memory. 1939 1940 @raise WindowsError: On error an exception is raised. 1941 """ 1942 return ord( self.read(lpBaseAddress, 1) )
1943
1944 - def write_char(self, lpBaseAddress, char):
1945 """ 1946 Writes a single character to the memory of the process. 1947 1948 @see: L{write_char} 1949 1950 @type lpBaseAddress: int 1951 @param lpBaseAddress: Memory address to begin writing. 1952 1953 @type char: int 1954 @param char: Character to write. 1955 1956 @raise WindowsError: On error an exception is raised. 1957 """ 1958 self.write(lpBaseAddress, chr(char))
1959
1960 - def read_structure(self, lpBaseAddress, stype):
1961 """ 1962 Reads a ctypes structure from the memory of the process. 1963 1964 @see: L{read} 1965 1966 @type lpBaseAddress: int 1967 @param lpBaseAddress: Memory address to begin reading. 1968 1969 @type stype: class ctypes.Structure or a subclass. 1970 @param stype: Structure definition. 1971 1972 @rtype: int 1973 @return: Structure instance filled in with data 1974 read from the process memory. 1975 1976 @raise WindowsError: On error an exception is raised. 1977 """ 1978 if type(lpBaseAddress) not in (type(0), type(0L)): 1979 lpBaseAddress = ctypes.cast(lpBaseAddress, ctypes.c_void_p) 1980 data = self.read(lpBaseAddress, ctypes.sizeof(stype)) 1981 buff = ctypes.create_string_buffer(data) 1982 ptr = ctypes.cast(ctypes.pointer(buff), ctypes.POINTER(stype)) 1983 return ptr.contents
1984 1985 # TODO 1986 ## def write_structure(self, lpBaseAddress, sStructure): 1987 ## """ 1988 ## Writes a ctypes structure into the memory of the process. 1989 ## 1990 ## @see: L{write} 1991 ## 1992 ## @type lpBaseAddress: int 1993 ## @param lpBaseAddress: Memory address to begin writing. 1994 ## 1995 ## @type sStructure: ctypes.Structure or a subclass' instance. 1996 ## @param sStructure: Structure definition. 1997 ## 1998 ## @rtype: int 1999 ## @return: Structure instance filled in with data 2000 ## read from the process memory. 2001 ## 2002 ## @raise WindowsError: On error an exception is raised. 2003 ## """ 2004 ## size = ctypes.sizeof(sStructure) 2005 ## data = ctypes.create_string_buffer("", size = size) 2006 ## win32.CopyMemory(ctypes.byref(data), ctypes.byref(sStructure), size) 2007 ## self.write(lpBaseAddress, data.raw) 2008
2009 - def read_string(self, lpBaseAddress, nChars, fUnicode = False):
2010 """ 2011 Reads an ASCII or Unicode string 2012 from the address space of the process. 2013 2014 @see: L{read} 2015 2016 @type lpBaseAddress: int 2017 @param lpBaseAddress: Memory address to begin reading. 2018 2019 @type nChars: int 2020 @param nChars: String length to read, in characters. 2021 Remember that Unicode strings have two byte characters. 2022 2023 @type fUnicode: bool 2024 @param fUnicode: C{True} is the string is expected to be Unicode, 2025 C{False} if it's expected to be ANSI. 2026 2027 @rtype: str, unicode 2028 @return: String read from the process memory space. 2029 2030 @raise WindowsError: On error an exception is raised. 2031 """ 2032 if fUnicode: 2033 nChars = nChars * 2 2034 szString = self.read(lpBaseAddress, nChars) 2035 if fUnicode: 2036 szString = unicode(szString, 'U16', 'ignore') 2037 return szString
2038 2039 #------------------------------------------------------------------------------ 2040
2041 - def peek(self, lpBaseAddress, nSize):
2042 """ 2043 Reads the memory of the process. 2044 2045 @see: L{read} 2046 2047 @type lpBaseAddress: int 2048 @param lpBaseAddress: Memory address to begin reading. 2049 2050 @type nSize: int 2051 @param nSize: Number of bytes to read. 2052 2053 @rtype: str 2054 @return: Bytes read from the process memory. 2055 Returns an empty string on error. 2056 """ 2057 data = '' 2058 if nSize > 0: 2059 try: 2060 data = win32.ReadProcessMemory(self.get_handle(), 2061 lpBaseAddress, nSize) 2062 except WindowsError: 2063 pass 2064 return data
2065
2066 - def poke(self, lpBaseAddress, lpBuffer):
2067 """ 2068 Writes to the memory of the process. 2069 2070 @see: L{write} 2071 2072 @type lpBaseAddress: int 2073 @param lpBaseAddress: Memory address to begin writing. 2074 2075 @type lpBuffer: str 2076 @param lpBuffer: Bytes to write. 2077 2078 @rtype: int 2079 @return: Number of bytes written. 2080 May be less than the number of bytes to write. 2081 """ 2082 try: 2083 bytesWritten = win32.WriteProcessMemory(self.get_handle(), 2084 lpBaseAddress, lpBuffer) 2085 except WindowsError: 2086 bytesWritten = 0 2087 return bytesWritten
2088
2089 - def peek_uint(self, lpBaseAddress):
2090 """ 2091 Reads a single unsigned integer from the memory of the process. 2092 2093 @see: L{read_uint} 2094 2095 @type lpBaseAddress: int 2096 @param lpBaseAddress: Memory address to begin reading. 2097 2098 @rtype: int 2099 @return: Integer value read from the process memory. 2100 Returns zero on error. 2101 """ 2102 dwordLength = win32.sizeof(win32.UINT) 2103 packedDword = self.peek(lpBaseAddress, dwordLength) 2104 if len(packedDword) < dwordLength: 2105 packedDword += '\x00' * (dwordLength - len(packedDword)) 2106 unpackedDword = struct.unpack('<L', packedDword)[0] 2107 return unpackedDword
2108
2109 - def poke_uint(self, lpBaseAddress, unpackedDword):
2110 """ 2111 Writes a single unsigned integer to the memory of the process. 2112 2113 @see: L{write_uint} 2114 2115 @type lpBaseAddress: int 2116 @param lpBaseAddress: Memory address to begin writing. 2117 2118 @type unpackedDword: int, long 2119 @param unpackedDword: Value to write. 2120 2121 @rtype: int 2122 @return: Number of bytes written. 2123 May be less than the number of bytes to write. 2124 """ 2125 packedDword = struct.pack('<L', unpackedDword) 2126 dwBytesWritten = self.poke(lpBaseAddress, packedDword) 2127 return dwBytesWritten
2128
2129 - def peek_pointer(self, lpBaseAddress):
2130 """ 2131 Reads a single pointer value from the memory of the process. 2132 2133 @see: L{read_pointer} 2134 2135 @type lpBaseAddress: int 2136 @param lpBaseAddress: Memory address to begin reading. 2137 2138 @rtype: int 2139 @return: Pointer value read from the process memory. 2140 Returns zero on error. 2141 """ 2142 lpvoidLength = win32.sizeof(win32.LPVOID) 2143 packedValue = self.read(lpBaseAddress, lpvoidLength) 2144 if len(packedValue) < lpvoidLength: 2145 packedValue += '\x00' * (lpvoidLength - len(packedValue)) 2146 if lpvoidLength == 4: 2147 lpvoidFmt = '<L' 2148 else: 2149 lpvoidFmt = '<Q' 2150 unpackedValue = struct.unpack(lpvoidFmt, packedValue)[0] 2151 return unpackedValue
2152
2153 - def poke_pointer(self, lpBaseAddress, unpackedValue):
2154 """ 2155 Writes a single pointer value to the memory of the process. 2156 2157 @see: L{write_pointer} 2158 2159 @type lpBaseAddress: int 2160 @param lpBaseAddress: Memory address to begin writing. 2161 2162 @type unpackedValue: int, long 2163 @param unpackedValue: Value to write. 2164 2165 @rtype: int 2166 @return: Number of bytes written. 2167 May be less than the number of bytes to write. 2168 """ 2169 lpvoidLength = win32.sizeof(win32.LPVOID) 2170 if lpvoidLength == 4: 2171 lpvoidFmt = '<L' 2172 else: 2173 lpvoidFmt = '<Q' 2174 packedValue = struct.pack(lpvoidFmt, unpackedValue) 2175 dwBytesWritten = self.poke(lpBaseAddress, packedValue) 2176 return dwBytesWritten
2177
2178 - def peek_char(self, lpBaseAddress):
2179 """ 2180 Reads a single character from the memory of the process. 2181 2182 @see: L{read_char} 2183 2184 @type lpBaseAddress: int 2185 @param lpBaseAddress: Memory address to begin reading. 2186 2187 @rtype: int 2188 @return: Character read from the process memory. 2189 Returns zero on error. 2190 """ 2191 char = self.peek(lpBaseAddress, 1) 2192 if char: 2193 return ord(char) 2194 return 0
2195
2196 - def poke_char(self, lpBaseAddress, char):
2197 """ 2198 Writes a single character to the memory of the process. 2199 2200 @see: L{write_char} 2201 2202 @type lpBaseAddress: int 2203 @param lpBaseAddress: Memory address to begin writing. 2204 2205 @type char: str 2206 @param char: Character to write. 2207 2208 @rtype: int 2209 @return: Number of bytes written. 2210 May be less than the number of bytes to write. 2211 """ 2212 return self.poke(lpBaseAddress, chr(char))
2213
2214 - def peek_string(self, lpBaseAddress, fUnicode = False, dwMaxSize = 0x1000):
2215 """ 2216 Tries to read an ASCII or Unicode string 2217 from the address space of the process. 2218 2219 @see: L{peek} 2220 2221 @type lpBaseAddress: int 2222 @param lpBaseAddress: Memory address to begin reading. 2223 2224 @type fUnicode: bool 2225 @param fUnicode: C{True} is the string is expected to be Unicode, 2226 C{False} if it's expected to be ANSI. 2227 2228 @type dwMaxSize: int 2229 @param dwMaxSize: Maximum allowed string length to read, in bytes. 2230 2231 @rtype: str, unicode 2232 @return: String read from the process memory space. 2233 It doesn't include the terminating null character. 2234 Returns an empty string on failure. 2235 """ 2236 # It's copied to a ctypes buffer and back to Python string 2237 # to make sure the string is parsed just like a C string should. 2238 # This avoids having troublesome null characters around. 2239 szString = self.peek(lpBaseAddress, dwMaxSize) 2240 if fUnicode: 2241 szString = unicode(szString, 'U16', 'ignore') 2242 szString = ctypes.create_unicode_buffer(szString).value 2243 else: 2244 szString = ctypes.create_string_buffer(szString).value 2245 return szString
2246 2247 #------------------------------------------------------------------------------ 2248
2249 - def malloc(self, dwSize, lpAddress = win32.NULL):
2250 """ 2251 Allocates memory into the address space of the process. 2252 2253 @see: L{free} 2254 2255 @type dwSize: int 2256 @param dwSize: Number of bytes to allocate. 2257 2258 @type lpAddress: int 2259 @param lpAddress: (Optional) 2260 Desired address for the newly allocated memory. 2261 This is only a hint, the memory could still be allocated somewhere 2262 else. 2263 2264 @rtype: int 2265 @return: Address of the newly allocated memory. 2266 2267 @raise WindowsError: On error an exception is raised. 2268 """ 2269 return win32.VirtualAllocEx(self.get_handle(), lpAddress, dwSize)
2270
2271 - def mprotect(self, lpAddress, dwSize, flNewProtect):
2272 """ 2273 Set memory protection in the address space of the process. 2274 2275 @see: U{http://msdn.microsoft.com/en-us/library/aa366899.aspx} 2276 2277 @type lpAddress: int 2278 @param lpAddress: Address of memory to protect. 2279 2280 @type dwSize: int 2281 @param dwSize: Number of bytes to protect. 2282 2283 @type flNewProtect: int 2284 @param flNewProtect: New protect flags. 2285 2286 @rtype: int 2287 @return: Old protect flags. 2288 2289 @raise WindowsError: On error an exception is raised. 2290 """ 2291 return win32.VirtualProtectEx(self.get_handle(), lpAddress, dwSize, 2292 flNewProtect)
2293
2294 - def mquery(self, lpAddress):
2295 """ 2296 Query memory information from the address space of the process. 2297 Returns a L{win32.MemoryBasicInformation} object. 2298 2299 @see: U{http://msdn.microsoft.com/en-us/library/aa366907(VS.85).aspx} 2300 2301 @type lpAddress: int 2302 @param lpAddress: Address of memory to query. 2303 2304 @rtype: L{win32.MemoryBasicInformation} 2305 @return: Memory region information. 2306 2307 @raise WindowsError: On error an exception is raised. 2308 """ 2309 return win32.VirtualQueryEx(self.get_handle(), lpAddress)
2310
2311 - def free(self, lpAddress, dwSize = 0):
2312 """ 2313 Frees memory from the address space of the process. 2314 2315 @see: L{malloc} 2316 2317 @type lpAddress: int 2318 @param lpAddress: Address of memory to free. 2319 2320 @type dwSize: int 2321 @param dwSize: (Optional) Number of bytes to free. 2322 2323 @rtype: bool 2324 @return: C{True} on success, C{False} on error. 2325 """ 2326 success = win32.VirtualFreeEx(self.get_handle(), lpAddress, dwSize) 2327 return bool(success)
2328 2329 #------------------------------------------------------------------------------ 2330
2331 - def is_pointer(self, address):
2332 """ 2333 Determines if an address is a valid code or data pointer. 2334 2335 That is, the address must be valid and must point to code or data in 2336 the target process. 2337 2338 @type address: int 2339 @param address: Memory address to query. 2340 2341 @rtype: bool 2342 @return: C{True} if the address is a valid code or data pointer. 2343 2344 @raise WindowsError: An exception is raised on error. 2345 """ 2346 try: 2347 mbi = self.mquery(address) 2348 except WindowsError, e: 2349 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2350 return False 2351 raise 2352 return mbi.has_content()
2353
2354 - def is_address_valid(self, address):
2355 """ 2356 Determines if an address is a valid user mode address. 2357 2358 @type address: int 2359 @param address: Memory address to query. 2360 2361 @rtype: bool 2362 @return: C{True} if the address is a valid user mode address. 2363 2364 @raise WindowsError: An exception is raised on error. 2365 """ 2366 try: 2367 mbi = self.mquery(address) 2368 except WindowsError, e: 2369 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2370 return False 2371 raise 2372 return True
2373
2374 - def is_address_free(self, address):
2375 """ 2376 Determines if an address belongs to a free page. 2377 2378 @note: Returns always C{False} for kernel mode addresses. 2379 2380 @type address: int 2381 @param address: Memory address to query. 2382 2383 @rtype: bool 2384 @return: C{True} if the address belongs to a free page. 2385 2386 @raise WindowsError: An exception is raised on error. 2387 """ 2388 try: 2389 mbi = self.mquery(address) 2390 except WindowsError, e: 2391 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2392 return False 2393 raise 2394 return mbi.is_free()
2395
2396 - def is_address_reserved(self, address):
2397 """ 2398 Determines if an address belongs to a reserved page. 2399 2400 @note: Returns always C{False} for kernel mode addresses. 2401 2402 @type address: int 2403 @param address: Memory address to query. 2404 2405 @rtype: bool 2406 @return: C{True} if the address belongs to a reserved page. 2407 2408 @raise WindowsError: An exception is raised on error. 2409 """ 2410 try: 2411 mbi = self.mquery(address) 2412 except WindowsError, e: 2413 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2414 return False 2415 raise 2416 return mbi.is_reserved()
2417
2418 - def is_address_commited(self, address):
2419 """ 2420 Determines if an address belongs to a commited page. 2421 2422 @note: Returns always C{False} for kernel mode addresses. 2423 2424 @type address: int 2425 @param address: Memory address to query. 2426 2427 @rtype: bool 2428 @return: C{True} if the address belongs to a commited page. 2429 2430 @raise WindowsError: An exception is raised on error. 2431 """ 2432 try: 2433 mbi = self.mquery(address) 2434 except WindowsError, e: 2435 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2436 return False 2437 raise 2438 return mbi.is_commited()
2439
2440 - def is_address_guard(self, address):
2441 """ 2442 Determines if an address belongs to a guard page. 2443 2444 @note: Returns always C{False} for kernel mode addresses. 2445 2446 @type address: int 2447 @param address: Memory address to query. 2448 2449 @rtype: bool 2450 @return: C{True} if the address belongs to a guard page. 2451 2452 @raise WindowsError: An exception is raised on error. 2453 """ 2454 try: 2455 mbi = self.mquery(address) 2456 except WindowsError, e: 2457 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2458 return False 2459 raise 2460 return mbi.is_guard()
2461
2462 - def is_address_readable(self, address):
2463 """ 2464 Determines if an address belongs to a commited and readable page. 2465 The page may or may not have additional permissions. 2466 2467 @note: Returns always C{False} for kernel mode addresses. 2468 2469 @type address: int 2470 @param address: Memory address to query. 2471 2472 @rtype: bool 2473 @return: 2474 C{True} if the address belongs to a commited and readable page. 2475 2476 @raise WindowsError: An exception is raised on error. 2477 """ 2478 try: 2479 mbi = self.mquery(address) 2480 except WindowsError, e: 2481 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2482 return False 2483 raise 2484 return mbi.is_readable()
2485
2486 - def is_address_writeable(self, address):
2487 """ 2488 Determines if an address belongs to a commited and writeable page. 2489 The page may or may not have additional permissions. 2490 2491 @note: Returns always C{False} for kernel mode addresses. 2492 2493 @type address: int 2494 @param address: Memory address to query. 2495 2496 @rtype: bool 2497 @return: 2498 C{True} if the address belongs to a commited and writeable page. 2499 2500 @raise WindowsError: An exception is raised on error. 2501 """ 2502 try: 2503 mbi = self.mquery(address) 2504 except WindowsError, e: 2505 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2506 return False 2507 raise 2508 return mbi.is_writeable()
2509
2510 - def is_address_copy_on_write(self, address):
2511 """ 2512 Determines if an address belongs to a commited, copy-on-write page. 2513 The page may or may not have additional permissions. 2514 2515 @note: Returns always C{False} for kernel mode addresses. 2516 2517 @type address: int 2518 @param address: Memory address to query. 2519 2520 @rtype: bool 2521 @return: 2522 C{True} if the address belongs to a commited, copy-on-write page. 2523 2524 @raise WindowsError: An exception is raised on error. 2525 """ 2526 try: 2527 mbi = self.mquery(address) 2528 except WindowsError, e: 2529 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2530 return False 2531 raise 2532 return mbi.is_copy_on_write()
2533
2534 - def is_address_executable(self, address):
2535 """ 2536 Determines if an address belongs to a commited and executable page. 2537 The page may or may not have additional permissions. 2538 2539 @note: Returns always C{False} for kernel mode addresses. 2540 2541 @type address: int 2542 @param address: Memory address to query. 2543 2544 @rtype: bool 2545 @return: 2546 C{True} if the address belongs to a commited and executable page. 2547 2548 @raise WindowsError: An exception is raised on error. 2549 """ 2550 try: 2551 mbi = self.mquery(address) 2552 except WindowsError, e: 2553 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2554 return False 2555 raise 2556 return mbi.is_executable()
2557
2558 - def is_address_executable_and_writeable(self, address):
2559 """ 2560 Determines if an address belongs to a commited, writeable and 2561 executable page. The page may or may not have additional permissions. 2562 2563 Looking for writeable and executable pages is important when 2564 exploiting a software vulnerability. 2565 2566 @note: Returns always C{False} for kernel mode addresses. 2567 2568 @type address: int 2569 @param address: Memory address to query. 2570 2571 @rtype: bool 2572 @return: 2573 C{True} if the address belongs to a commited, writeable and 2574 executable page. 2575 2576 @raise WindowsError: An exception is raised on error. 2577 """ 2578 try: 2579 mbi = self.mquery(address) 2580 except WindowsError, e: 2581 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2582 return False 2583 raise 2584 return mbi.is_executable_and_writeable()
2585
2586 - def get_memory_map(self, minAddr = None, maxAddr = None):
2587 """ 2588 Produces a memory map to the process address space. 2589 Optionally restrict the map to the given address range. 2590 2591 @see: L{mquery} 2592 2593 @type minAddr: int 2594 @param minAddr: (Optional) Starting address in address range to query. 2595 2596 @type maxAddr: int 2597 @param maxAddr: (Optional) Ending address in address range to query. 2598 2599 @rtype: list( L{win32.MemoryBasicInformation} ) 2600 @return: List of memory region information objects. 2601 """ 2602 if minAddr is None: 2603 minAddr = 0 2604 if maxAddr is None: 2605 maxAddr = win32.LPVOID(-1).value # XXX HACK 2606 if minAddr > maxAddr: 2607 minAddr, maxAddr = maxAddr, minAddr 2608 minAddr = MemoryAddresses.align_address_to_page_start(minAddr) 2609 maxAddr = MemoryAddresses.align_address_to_page_end(maxAddr) 2610 prevAddr = minAddr 2611 currentAddr = minAddr 2612 memoryMap = list() 2613 while currentAddr <= maxAddr and currentAddr >= prevAddr: 2614 try: 2615 mbi = self.mquery(currentAddr) 2616 except WindowsError, e: 2617 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2618 break 2619 raise 2620 memoryMap.append(mbi) 2621 prevAddr = currentAddr 2622 currentAddr = mbi.BaseAddress + mbi.RegionSize 2623 return memoryMap
2624
2625 - def get_mapped_filenames(self, memoryMap = None):
2626 """ 2627 Retrieves the filenames for memory mapped files in the debugee. 2628 2629 @type memoryMap: list( L{win32.MemoryBasicInformation} ) 2630 @param memoryMap: (Optional) Memory map returned by L{get_memory_map}. 2631 If not given, the current memory map is used. 2632 2633 @rtype: dict( int S{->} str ) 2634 @return: Dictionary mapping memory addresses to file names. 2635 Native filenames are converted to Win32 filenames when possible. 2636 """ 2637 hProcess = self.get_handle() 2638 if not memoryMap: 2639 memoryMap = self.get_memory_map() 2640 mappedFilenames = dict() 2641 for mbi in memoryMap: 2642 2643 # this check is redundant, but it saves an API call 2644 # just comment it out if it gives problems 2645 if mbi.Type not in (win32.MEM_IMAGE, win32.MEM_MAPPED): 2646 continue 2647 2648 baseAddress = mbi.BaseAddress 2649 fileName = "" 2650 try: 2651 fileName = win32.GetMappedFileName(hProcess, baseAddress) 2652 fileName = PathOperations.native_to_win32_pathname(fileName) 2653 except WindowsError, e: 2654 ## print str(e) # XXX DEBUG 2655 pass 2656 mappedFilenames[baseAddress] = fileName 2657 return mappedFilenames
2658
2659 - def take_memory_snapshot(self, minAddr = None, maxAddr = None):
2660 """ 2661 Takes a snapshot of the memory contents of the process. 2662 2663 @type minAddr: int 2664 @param minAddr: (Optional) Starting address in address range to query. 2665 2666 @type maxAddr: int 2667 @param maxAddr: (Optional) Ending address in address range to query. 2668 2669 @rtype: list( L{win32.MemoryBasicInformation} ) 2670 @return: List of memory region information objects. 2671 Two extra properties are added to these objects: 2672 - C{filename}: Mapped filename, or C{None}. 2673 - C{content}: Memory contents, or C{None}. 2674 """ 2675 snapshot = self.get_memory_map(minAddr, maxAddr) 2676 filenames = self.get_mapped_filenames(snapshot) 2677 for mbi in snapshot: 2678 mbi.filename = filenames.get(mbi.BaseAddress, None) 2679 if mbi.has_content(): 2680 mbi.content = self.read(mbi.BaseAddress, mbi.RegionSize) 2681 else: 2682 mbi.content = None 2683 return snapshot
2684
2685 - def restore_memory_snapshot(self, snapshot):
2686 """ 2687 Attempts to restore the memory state as it was when the given snapshot 2688 was taken. 2689 2690 @warning: Currently only the memory contents, state and protect bits 2691 are restored. Under some circumstances this method may fail (for 2692 example if memory was freed and then reused by a mapped file). 2693 2694 @type snapshot: list( L{win32.MemoryBasicInformation} ) 2695 @param snapshot: Memory snapshot returned by L{take_memory_snapshot}. 2696 2697 @raise WindowsError: An error occured while restoring the snapshot. 2698 @raise RuntimeError: An error occured while restoring the snapshot. 2699 """ 2700 2701 # Get the process handle. 2702 hProcess = self.get_handle() 2703 2704 # Freeze the process. 2705 self.suspend() 2706 try: 2707 2708 # For each memory region in the snapshot... 2709 for old_mbi in snapshot: 2710 2711 # If the region matches, restore it directly. 2712 new_mbi = self.mquery(old_mbi.BaseAddress) 2713 if new_mbi.BaseAddress == old_mbi.BaseAddress and new_mbi.RegionSize == old_mbi.RegionSize: 2714 self.__restore_mbi(hProcess, new_mbi, old_mbi) 2715 2716 # If the region doesn't match, restore it page by page. 2717 else: 2718 start = old_mbi.BaseAddress 2719 end = start + old_mbi.RegionSize 2720 for address in xrange(start, end, System.pageSize): 2721 new_mbi = self.mquery(address) 2722 self.__restore_mbi(hProcess, new_mbi, old_mbi) 2723 2724 # Resume execution. 2725 finally: 2726 self.resume()
2727
2728 - def __restore_mbi(self, hProcess, new_mbi, old_mbi):
2729 """ 2730 Used internally by L{restore_memory_snapshot}. 2731 """ 2732 2733 ## print "Restoring %s-%s" % (HexDump.address(old_mbi.BaseAddress), HexDump.address(old_mbi.BaseAddress + old_mbi.RegionSize)) 2734 2735 # Restore the region state. 2736 if new_mbi.State != old_mbi.State: 2737 if new_mbi.is_free(): 2738 if old_mbi.is_reserved(): 2739 address = win32.VirtualAllocEx(hProcess, old_mbi.BaseAddress, old_mbi.RegionSize, win32.MEM_RESERVE, old_mbi.Protect) 2740 if address != old_mbi.BaseAddress: 2741 self.free(address) 2742 msg = "Error restoring region at address %s" 2743 msg = msg % HexDump(old_mbi.BaseAddress) 2744 raise RuntimeError, msg 2745 new_mbi.Protect = old_mbi.Protect # permissions already restored 2746 else: # is_commited 2747 address = win32.VirtualAllocEx(hProcess, old_mbi.BaseAddress, old_mbi.RegionSize, win32.MEM_RESERVE | win32.MEM_COMMIT, old_mbi.Protect) 2748 if address != old_mbi.BaseAddress: 2749 self.free(address) 2750 msg = "Error restoring region at address %s" 2751 msg = msg % HexDump(old_mbi.BaseAddress) 2752 raise RuntimeError, msg 2753 new_mbi.Protect = old_mbi.Protect # permissions already restored 2754 elif new_mbi.is_reserved(): 2755 if old_mbi.is_commited(): 2756 address = win32.VirtualAllocEx(hProcess, old_mbi.BaseAddress, old_mbi.RegionSize, win32.MEM_COMMIT, old_mbi.Protect) 2757 if address != old_mbi.BaseAddress: 2758 self.free(address) 2759 msg = "Error restoring region at address %s" 2760 msg = msg % HexDump(old_mbi.BaseAddress) 2761 raise RuntimeError, msg 2762 new_mbi.Protect = old_mbi.Protect # permissions already restored 2763 else: # is_free 2764 win32.VirtualFreeEx(hProcess, old_mbi.BaseAddress, old_mbi.RegionSize, win32.MEM_RELEASE) 2765 else: # is_commited 2766 if old_mbi.is_reserved(): 2767 win32.VirtualFreeEx(hProcess, old_mbi.BaseAddress, old_mbi.RegionSize, win32.MEM_DECOMMIT) 2768 else: # is_free 2769 win32.VirtualFreeEx(hProcess, old_mbi.BaseAddress, old_mbi.RegionSize, win32.MEM_DECOMMIT | win32.MEM_RELEASE) 2770 2771 # Restore the region permissions. 2772 if old_mbi.Protect != new_mbi.Protect: 2773 win32.VirtualProtectEx(hProcess, old_mbi.BaseAddress, old_mbi.RegionSize, old_mbi.Protect) 2774 2775 # Restore the region data. 2776 # Ignore write errors when the region belongs to a mapped file. 2777 if old_mbi.has_content(): 2778 if old_mbi.Type != 0: 2779 self.poke(old_mbi.BaseAddress, old_mbi.content) 2780 else: 2781 self.write(old_mbi.BaseAddress, old_mbi.content)
2782
2783 #============================================================================== 2784 2785 -class SymbolEnumerator (object):
2786 """ 2787 Internally used by L{SymbolContainer} to enumerate symbols in a module. 2788 """ 2789
2790 - def __init__(self):
2791 self.symbols = list()
2792
2793 - def __call__(self, SymbolName, SymbolAddress, SymbolSize, UserContext):
2794 """ 2795 Callback that receives symbols and stores them in a Python list. 2796 """ 2797 ## try: 2798 ## SymbolName = win32.UnDecorateSymbolName(SymbolName) 2799 ## except Exception, e: 2800 ## pass 2801 self.symbols.append( (SymbolName, SymbolAddress, SymbolSize) ) 2802 return win32.TRUE
2803
2804 -class SymbolContainer (object):
2805 """ 2806 Capability to contain symbols. Used by L{Module}. 2807 2808 @group Symbols: 2809 load_symbols, unload_symbols, get_symbols, iter_symbols, 2810 resolve_symbol, get_symbol_at_address 2811 """ 2812
2813 - def __init__(self):
2814 self.__symbols = list()
2815 2816 # XXX FIXME 2817 # I've been told sometimes the debugging symbols APIs don't correctly 2818 # handle redirected exports (for example ws2_32!recv). 2819 # I haven't been able to reproduce the bug yet.
2820 - def load_symbols(self):
2821 """ 2822 Loads the debugging symbols for a module. 2823 Automatically called by L{get_symbols}. 2824 """ 2825 hProcess = self.get_process().get_handle() 2826 hFile = self.hFile 2827 BaseOfDll = self.get_base() 2828 SizeOfDll = self.get_size() 2829 Enumerator = SymbolEnumerator() 2830 try: 2831 win32.SymInitialize(hProcess) 2832 SymOptions = win32.SymGetOptions() 2833 win32.SymSetOptions(SymOptions | \ 2834 win32.SYMOPT_ALLOW_ZERO_ADDRESS | \ 2835 win32.SYMOPT_CASE_INSENSITIVE | \ 2836 win32.SYMOPT_FAVOR_COMPRESSED | \ 2837 win32.SYMOPT_INCLUDE_32BIT_MODULES | \ 2838 win32.SYMOPT_UNDNAME) 2839 try: 2840 win32.SymSetOptions(SymOptions | win32.SYMOPT_ALLOW_ABSOLUTE_SYMBOLS) 2841 except WindowsError: 2842 pass 2843 try: 2844 try: 2845 win32.SymLoadModule64(hProcess, hFile, None, None, BaseOfDll, SizeOfDll) 2846 except WindowsError: 2847 ImageName = self.get_filename() 2848 win32.SymLoadModule64(hProcess, None, ImageName, None, BaseOfDll, SizeOfDll) 2849 try: 2850 win32.SymEnumerateSymbols64(hProcess, BaseOfDll, Enumerator) 2851 finally: 2852 win32.SymUnloadModule64(hProcess, BaseOfDll) 2853 finally: 2854 win32.SymCleanup(hProcess) 2855 except WindowsError, e: 2856 ## import traceback # XXX DEBUG 2857 ## traceback.print_exc() 2858 pass 2859 self.__symbols = Enumerator.symbols
2860
2861 - def unload_symbols(self):
2862 """ 2863 Unloads the debugging symbols for a module. 2864 """ 2865 self.__symbols = list()
2866
2867 - def get_symbols(self):
2868 """ 2869 Returns the debugging symbols for a module. 2870 The symbols are automatically loaded when needed. 2871 2872 @rtype: list of tuple( str, int, int ) 2873 @return: List of symbols. 2874 Each symbol is represented by a tuple that contains: 2875 - Symbol name 2876 - Symbol memory address 2877 - Symbol size in bytes 2878 """ 2879 if not self.__symbols: 2880 self.load_symbols() 2881 return list(self.__symbols)
2882
2883 - def iter_symbols(self):
2884 """ 2885 Returns an iterator for the debugging symbols in a module, 2886 in no particular order. 2887 The symbols are automatically loaded when needed. 2888 2889 @rtype: iterator of tuple( str, int, int ) 2890 @return: Iterator of symbols. 2891 Each symbol is represented by a tuple that contains: 2892 - Symbol name 2893 - Symbol memory address 2894 - Symbol size in bytes 2895 """ 2896 if not self.__symbols: 2897 self.load_symbols() 2898 return self.__symbols.__iter__()
2899
2900 - def resolve_symbol(self, symbol, bCaseSensitive = False):
2901 """ 2902 Resolves a debugging symbol's address. 2903 2904 @type symbol: str 2905 @param symbol: Name of the symbol to resolve. 2906 2907 @type bCaseSensitive: bool 2908 @param bCaseSensitive: C{True} for case sensitive matches, 2909 C{False} for case insensitive. 2910 2911 @rtype: int or None 2912 @return: Memory address of symbol. C{None} if not found. 2913 """ 2914 if bCaseSensitive: 2915 for (SymbolName, SymbolAddress, SymbolSize) in self.iter_symbols(): 2916 if symbol == SymbolName: 2917 return SymbolAddress 2918 else: 2919 symbol = symbol.lower() 2920 for (SymbolName, SymbolAddress, SymbolSize) in self.iter_symbols(): 2921 if symbol == SymbolName.lower(): 2922 return SymbolAddress
2923
2924 - def get_symbol_at_address(self, address):
2925 found = None 2926 for (SymbolName, SymbolAddress, SymbolSize) in self.iter_symbols(): 2927 if SymbolAddress > address: 2928 continue 2929 if SymbolAddress + SymbolSize > address: 2930 if not found or found[1] < SymbolAddress: 2931 found = (SymbolName, SymbolAddress, SymbolSize) 2932 return found
2933
2934 #============================================================================== 2935 2936 -class SymbolOperations (object):
2937 """ 2938 Encapsulates symbol operations capabilities. 2939 2940 Requires a L{ModuleContainer}. 2941 2942 @note: Labels are an approximated way of referencing memory locations 2943 across different executions of the same process, or different processes 2944 with common modules. They are not meant to be perfectly unique, and 2945 some errors may occur when multiple modules with the same name are 2946 loaded, or when module filenames can't be retrieved. 2947 2948 Read more on labels here: 2949 U{http://apps.sourceforge.net/trac/winappdbg/wiki/HowLabelsWork} 2950 2951 @group Labels: 2952 parse_label, 2953 split_label, 2954 sanitize_label, 2955 resolve_label, 2956 get_label_at_address, 2957 split_label_strict, 2958 split_label_fuzzy 2959 2960 @group Symbols: 2961 load_symbols, unload_symbols, get_symbols, iter_symbols, 2962 resolve_symbol, get_symbol_at_address 2963 2964 @group Debugging: 2965 get_system_breakpoint, get_user_breakpoint, get_breakin_breakpoint, 2966 is_system_defined_breakpoint 2967 """ 2968
2969 - def __init__(self):
2970 super(SymbolOperations, self).__init__() 2971 2972 # Replace split_label with the fuzzy version on object instances. 2973 self.split_label = self.__use_fuzzy_mode
2974 2975 @staticmethod
2976 - def parse_label(module = None, function = None, offset = None):
2977 """ 2978 Creates a label from a module and a function name, plus an offset. 2979 2980 @warning: This method only parses the label, it doesn't make sure the 2981 label actually points to a valid memory location. 2982 2983 @type module: None or str 2984 @param module: (Optional) Module name. 2985 2986 @type function: None, str or int 2987 @param function: (Optional) Function name or ordinal. 2988 2989 @type offset: None or int 2990 @param offset: (Optional) Offset value. 2991 2992 If C{function} is specified, offset from the function. 2993 2994 If C{function} is C{None}, offset from the module. 2995 2996 @rtype: str 2997 @return: 2998 Label representing the given function in the given module. 2999 3000 @raise ValueError: 3001 The module or function name contain invalid characters. 3002 """ 3003 3004 # TODO 3005 # Invalid characters should be escaped or filtered. 3006 3007 # Convert ordinals to strings. 3008 try: 3009 function = "#0x%x" % function 3010 except TypeError: 3011 pass 3012 3013 # Validate the parameters. 3014 if module is not None and ('!' in module or '+' in module): 3015 raise ValueError, "Invalid module name: %s" % module 3016 if function is not None and ('!' in function or '+' in function): 3017 raise ValueError, "Invalid function name: %s" % function 3018 3019 # Parse the label. 3020 if module: 3021 if function: 3022 if offset: 3023 label = "%s!%s+0x%x" % (module, function, offset) 3024 else: 3025 label = "%s!%s" % (module, function) 3026 else: 3027 if offset: 3028 ## label = "%s+0x%x!" % (module, offset) 3029 label = "%s!0x%x" % (module, offset) 3030 else: 3031 label = "%s!" % module 3032 else: 3033 if function: 3034 if offset: 3035 label = "!%s+0x%x" % (function, offset) 3036 else: 3037 label = "!%s" % function 3038 else: 3039 if offset: 3040 label = "0x%x" % offset 3041 else: 3042 label = "0x0" 3043 3044 return label
3045 3046 @staticmethod
3047 - def split_label_strict(label):
3048 """ 3049 Splits a label created with L{parse_label}. 3050 3051 To parse labels with a less strict syntax, use the L{split_label_fuzzy} 3052 method instead. 3053 3054 @warning: This method only parses the label, it doesn't make sure the 3055 label actually points to a valid memory location. 3056 3057 @type label: str 3058 @param label: Label to split. 3059 3060 @rtype: tuple( str or None, str or int or None, int or None ) 3061 @return: Tuple containing the C{module} name, 3062 the C{function} name or ordinal, and the C{offset} value. 3063 3064 If the label doesn't specify a module, 3065 then C{module} is C{None}. 3066 3067 If the label doesn't specify a function, 3068 then C{function} is C{None}. 3069 3070 If the label doesn't specify an offset, 3071 then C{offset} is C{0}. 3072 3073 @raise ValueError: The label is malformed. 3074 """ 3075 module = function = None 3076 offset = 0 3077 3078 # Special case: None 3079 if not label: 3080 label = "0x0" 3081 else: 3082 3083 # Remove all blanks. 3084 label = label.replace(' ', '') 3085 label = label.replace('\t', '') 3086 label = label.replace('\r', '') 3087 label = label.replace('\n', '') 3088 3089 # Special case: empty label. 3090 if not label: 3091 label = "0x0" 3092 3093 # * ! * 3094 if '!' in label: 3095 try: 3096 module, function = label.split('!') 3097 except ValueError: 3098 raise ValueError, "Malformed label: %s" % label 3099 3100 # module ! function 3101 if function: 3102 if '+' in module: 3103 raise ValueError, "Malformed label: %s" % label 3104 3105 # module ! function + offset 3106 if '+' in function: 3107 try: 3108 function, offset = function.split('+') 3109 except ValueError: 3110 raise ValueError, "Malformed label: %s" % label 3111 try: 3112 offset = HexInput.integer(offset) 3113 except ValueError: 3114 raise ValueError, "Malformed label: %s" % label 3115 else: 3116 3117 # module ! offset 3118 try: 3119 offset = HexInput.integer(function) 3120 function = None 3121 except ValueError: 3122 pass 3123 else: 3124 3125 # module + offset ! 3126 if '+' in module: 3127 try: 3128 module, offset = module.split('+') 3129 except ValueError: 3130 raise ValueError, "Malformed label: %s" % label 3131 try: 3132 offset = HexInput.integer(offset) 3133 except ValueError: 3134 raise ValueError, "Malformed label: %s" % label 3135 3136 else: 3137 3138 # module ! 3139 try: 3140 offset = HexInput.integer(module) 3141 module = None 3142 3143 # offset ! 3144 except ValueError: 3145 pass 3146 3147 if not module: 3148 module = None 3149 if not function: 3150 function = None 3151 3152 # * 3153 else: 3154 3155 # offset 3156 try: 3157 offset = HexInput.integer(label) 3158 3159 # # ordinal 3160 except ValueError: 3161 if label.startswith('#'): 3162 function = label 3163 try: 3164 HexInput.integer(function[1:]) 3165 3166 # module? 3167 # function? 3168 except ValueError: 3169 raise ValueError, "Ambiguous label: %s" % label 3170 3171 # module? 3172 # function? 3173 else: 3174 raise ValueError, "Ambiguous label: %s" % label 3175 3176 # Convert function ordinal strings into integers. 3177 if function and function.startswith('#'): 3178 try: 3179 function = HexInput.integer(function[1:]) 3180 except ValueError: 3181 pass 3182 3183 # Convert null offsets to None. 3184 if not offset: 3185 offset = None 3186 3187 return (module, function, offset)
3188
3189 - def split_label_fuzzy(self, label):
3190 """ 3191 Splits a label entered as user input. 3192 3193 It's more flexible in it's syntax parsing than the L{split_label_strict} 3194 method, as it allows the exclamation mark (B{C{!}}) to be omitted. The 3195 ambiguity is resolved by searching the modules in the snapshot to guess 3196 if a label refers to a module or a function. It also tries to rebuild 3197 labels when they contain hardcoded addresses. 3198 3199 @warning: This method only parses the label, it doesn't make sure the 3200 label actually points to a valid memory location. 3201 3202 @type label: str 3203 @param label: Label to split. 3204 3205 @rtype: tuple( str or None, str or int or None, int or None ) 3206 @return: Tuple containing the C{module} name, 3207 the C{function} name or ordinal, and the C{offset} value. 3208 3209 If the label doesn't specify a module, 3210 then C{module} is C{None}. 3211 3212 If the label doesn't specify a function, 3213 then C{function} is C{None}. 3214 3215 If the label doesn't specify an offset, 3216 then C{offset} is C{0}. 3217 3218 @raise ValueError: The label is malformed. 3219 """ 3220 module = function = None 3221 offset = 0 3222 3223 # Special case: None 3224 if not label: 3225 label = "0x0" 3226 else: 3227 3228 # Remove all blanks. 3229 label = label.replace(' ', '') 3230 label = label.replace('\t', '') 3231 label = label.replace('\r', '') 3232 label = label.replace('\n', '') 3233 3234 # Special case: empty label. 3235 if not label: 3236 label = "0x0" 3237 3238 # If an exclamation sign is present, we know we can parse it strictly. 3239 if '!' in label: 3240 return self.split_label_strict(label) 3241 3242 ## # Try to parse it strictly, on error do it the fuzzy way. 3243 ## try: 3244 ## return self.split_label(label) 3245 ## except ValueError: 3246 ## pass 3247 3248 # * + offset 3249 if '+' in label: 3250 try: 3251 prefix, offset = label.split('+') 3252 except ValueError: 3253 raise ValueError, "Malformed label: %s" % label 3254 try: 3255 offset = HexInput.integer(offset) 3256 except ValueError: 3257 raise ValueError, "Malformed label: %s" % label 3258 label = prefix 3259 3260 # This parses both filenames and base addresses. 3261 modobj = self.get_module_by_name(label) 3262 if modobj: 3263 3264 # module 3265 # module + offset 3266 module = modobj.get_name() 3267 3268 else: 3269 3270 # TODO 3271 # If 0xAAAAAAAA + 0xBBBBBBBB is given, 3272 # A is interpreted as a module base address, 3273 # and B as an offset. 3274 # If that fails, it'd be good to add A+B and try to 3275 # use the nearest loaded module. 3276 3277 # offset 3278 # base address + offset (when no module has that base address) 3279 try: 3280 address = HexInput.integer(label) 3281 3282 if offset: 3283 # If 0xAAAAAAAA + 0xBBBBBBBB is given, 3284 # A is interpreted as a module base address, 3285 # and B as an offset. 3286 # If that fails, we get here, meaning no module was found 3287 # at A. Then add up A+B and work with that as a hardcoded 3288 # address. 3289 offset = address + offset 3290 else: 3291 # If the label is a hardcoded address, we get here. 3292 offset = address 3293 3294 # If only a hardcoded address is given, 3295 # rebuild the label using get_label_at_address. 3296 # Then parse it again, but this time strictly, 3297 # both because there is no need for fuzzy syntax and 3298 # to prevent an infinite recursion if there's a bug here. 3299 try: 3300 new_label = self.get_label_at_address(offset) 3301 module, function, offset = \ 3302 self.split_label_strict(new_label) 3303 except ValueError: 3304 pass 3305 3306 # function 3307 # function + offset 3308 except ValueError: 3309 function = label 3310 3311 # Convert function ordinal strings into integers. 3312 if function and function.startswith('#'): 3313 try: 3314 function = HexInput.integer(function[1:]) 3315 except ValueError: 3316 pass 3317 3318 # Convert null offsets to None. 3319 if not offset: 3320 offset = None 3321 3322 return (module, function, offset)
3323 3324 @classmethod
3325 - def split_label(cls, label):
3326 """ 3327 Splits a label into it's C{module}, C{function} and C{offset} 3328 components, as used in L{parse_label}. 3329 3330 When called as a static method, the strict syntax mode is used:: 3331 3332 winappdbg.Process.split_label( "kernel32!CreateFileA" ) 3333 3334 When called as an instance method, the fuzzy syntax mode is used:: 3335 3336 aProcessInstance.split_label( "CreateFileA" ) 3337 3338 @see: L{split_label_strict}, L{split_label_fuzzy} 3339 3340 @type label: str 3341 @param label: Label to split. 3342 3343 @rtype: tuple( str or None, str or int or None, int or None ) 3344 @return: 3345 Tuple containing the C{module} name, 3346 the C{function} name or ordinal, and the C{offset} value. 3347 3348 If the label doesn't specify a module, 3349 then C{module} is C{None}. 3350 3351 If the label doesn't specify a function, 3352 then C{function} is C{None}. 3353 3354 If the label doesn't specify an offset, 3355 then C{offset} is C{0}. 3356 3357 @raise ValueError: The label is malformed. 3358 """ 3359 3360 # XXX 3361 # Docstring indentation was removed so epydoc doesn't complain 3362 # when parsing the docs for __use_fuzzy_mode(). 3363 3364 # This function is overwritten by __init__ 3365 # so here is the static implementation only. 3366 return cls.split_label_strict(label)
3367 3368 # The split_label method is replaced with this function by __init__.
3369 - def __use_fuzzy_mode(self, label):
3370 "@see: L{split_label}" 3371 return self.split_label_fuzzy(label)
3372 ## __use_fuzzy_mode.__doc__ = split_label.__doc__ 3373
3374 - def sanitize_label(self, label):
3375 """ 3376 Converts a label taken from user input into a well-formed label. 3377 3378 @type label: str 3379 @param label: Label taken from user input. 3380 3381 @rtype: str 3382 @return: Sanitized label. 3383 """ 3384 (module, function, offset) = self.split_label_fuzzy(label) 3385 label = self.parse_label(module, function, offset) 3386 return label
3387
3388 - def resolve_label(self, label):
3389 """ 3390 Resolve the memory address of the given label. 3391 3392 @note: 3393 If multiple modules with the same name are loaded, 3394 the label may be resolved at any of them. For a more precise 3395 way to resolve functions use the base address to get the L{Module} 3396 object (see L{Process.get_module}) and then call L{Module.resolve}. 3397 3398 If no module name is specified in the label, the function may be 3399 resolved in any loaded module. If you want to resolve all functions 3400 with that name in all processes, call L{Process.iter_modules} to 3401 iterate through all loaded modules, and then try to resolve the 3402 function in each one of them using L{Module.resolve}. 3403 3404 @type label: str 3405 @param label: Label to resolve. 3406 3407 @rtype: int 3408 @return: Memory address pointed to by the label. 3409 3410 @raise ValueError: The label is malformed or impossible to resolve. 3411 @raise RuntimeError: Cannot resolve the module or function. 3412 """ 3413 # Default address if no module or function are given. 3414 # An offset may be added later. 3415 address = 0 3416 3417 # Split the label into module, function and offset components. 3418 module, function, offset = self.split_label_fuzzy(label) 3419 3420 # Resolve the module. 3421 if module: 3422 modobj = self.get_module_by_name(module) 3423 if not modobj: 3424 msg = "Module %r not found" % module 3425 raise RuntimeError, msg 3426 3427 # Resolve the exported function or debugging symbol. 3428 # If all else fails, check for the special symbol "start". 3429 if function: 3430 address = modobj.resolve(function) 3431 if address is None: 3432 address = modobj.resolve_symbol(function) 3433 if address is None: 3434 if function == "start": 3435 address = modobj.get_entry_point() 3436 if address is None: 3437 msg = "Symbol %r not found in module %s" 3438 msg = msg % (function, module) 3439 raise RuntimeError, msg 3440 3441 # No function, use the base address. 3442 else: 3443 address = modobj.get_base() 3444 3445 # Resolve the function in any module. 3446 elif function: 3447 for modobj in self.iter_modules(): 3448 address = modobj.resolve(function) 3449 if address is not None: 3450 break 3451 if address is None: 3452 msg = "Function %r not found in any module" % function 3453 raise RuntimeError, msg 3454 3455 # Return the address plus the offset. 3456 if offset: 3457 address = address + offset 3458 return address
3459
3460 - def get_label_at_address(self, address, offset = None):
3461 """ 3462 Creates a label from the given memory address. 3463 3464 @warning: This method uses the name of the nearest currently loaded 3465 module. If that module is unloaded later, the label becomes 3466 impossible to resolve. 3467 3468 @type address: int 3469 @param address: Memory address. 3470 3471 @type offset: None or int 3472 @param offset: (Optional) Offset value. 3473 3474 @rtype: str 3475 @return: Label pointing to the given address. 3476 """ 3477 if offset: 3478 address = address + offset 3479 modobj = self.get_module_at_address(address) 3480 if modobj: 3481 label = modobj.get_label_at_address(address) 3482 else: 3483 label = self.parse_label(None, None, address) 3484 return label
3485 3486 # XXX TODO 3487 # DbgBreakPointWithStatus: http://msdn.microsoft.com/en-us/library/ms792807.aspx 3488
3489 - def is_system_defined_breakpoint(self, address):
3490 """ 3491 @type address: int 3492 @param address: Memory address. 3493 3494 @rtype: bool 3495 @return: C{True} if the given address points to a system defined 3496 breakpoint. System defined breakpoints are hardcoded into 3497 system libraries. 3498 """ 3499 return address is not None and ( 3500 address == self.get_system_breakpoint() or \ 3501 address == self.get_wow64_system_breakpoint() or \ 3502 address == self.get_user_breakpoint() or \ 3503 address == self.get_breakin_breakpoint() 3504 )
3505 3506 # FIXME 3507 # In Wine, the system breakpoint seems to be somewhere in kernel32. 3508 # In Windows 2000 I've been told it's in ntdll!NtDebugBreak (not sure yet).
3509 - def get_system_breakpoint(self):
3510 """ 3511 @rtype: int or None 3512 @return: Memory address of the system breakpoint 3513 within the process address space. 3514 Returns C{None} on error. 3515 """ 3516 try: 3517 return self.resolve_label("ntdll!DbgBreakPoint") 3518 except Exception: 3519 return None
3520 3521 # Equivalent of ntdll!DbgBreakPoint in Wow64.
3523 """ 3524 @rtype: int or None 3525 @return: Memory address of the Wow64 system breakpoint 3526 within the process address space. 3527 Returns C{None} on error. 3528 """ 3529 try: 3530 return self.resolve_label("ntdll32!DbgBreakPoint") 3531 except Exception: 3532 return None
3533 3534 # I don't know when this breakpoint is actually used...
3535 - def get_user_breakpoint(self):
3536 """ 3537 @rtype: int or None 3538 @return: Memory address of the user breakpoint 3539 within the process address space. 3540 Returns C{None} on error. 3541 """ 3542 try: 3543 return self.resolve_label("ntdll!DbgUserBreakPoint") 3544 except Exception: 3545 return None
3546 3547 # Equivalent of ntdll!DbgBreakPoint in Wow64.
3548 - def get_wow64_user_breakpoint(self):
3549 """ 3550 @rtype: int or None 3551 @return: Memory address of the Wow64 user breakpoint 3552 within the process address space. 3553 Returns C{None} on error. 3554 """ 3555 try: 3556 return self.resolve_label("ntdll32!DbgUserBreakPoint") 3557 except Exception: 3558 return None
3559 3560 # This breakpoint can only be resolved when the 3561 # debugging symbols for ntdll.dll are loaded.
3562 - def get_breakin_breakpoint(self):
3563 """ 3564 @rtype: int or None 3565 @return: Memory address of the remote breakin breakpoint 3566 within the process address space. 3567 Returns C{None} on error. 3568 """ 3569 try: 3570 return self.resolve_label("ntdll!DbgUiRemoteBreakin") 3571 except Exception: 3572 return None
3573 3574 # Equivalent of ntdll!DbgBreakPoint in Wow64.
3576 """ 3577 @rtype: int or None 3578 @return: Memory address of the Wow64 remote breakin breakpoint 3579 within the process address space. 3580 Returns C{None} on error. 3581 """ 3582 try: 3583 return self.resolve_label("ntdll32!DbgUiRemoteBreakin") 3584 except Exception: 3585 return None
3586
3587 - def load_symbols(self):
3588 for aModule in self.iter_modules(): 3589 aModule.load_symbols()
3590
3591 - def unload_symbols(self):
3592 for aModule in self.iter_modules(): 3593 aModule.unload_symbols()
3594
3595 - def get_symbols(self):
3596 symbols = list() 3597 for aModule in self.iter_modules(): 3598 for symbol in aModule.iter_symbols(): 3599 symbols.append(symbol) 3600 return symbols
3601
3602 - def iter_symbols(self):
3603 for aModule in self.iter_modules(): 3604 for symbol in aModule.iter_symbols(): 3605 yield symbol
3606
3607 - def resolve_symbol(self, symbol):
3608 symbol = symbol.lower() 3609 for (SymbolName, SymbolAddress, SymbolSize) in self.iter_symbols(): 3610 if symbol == SymbolName.lower(): 3611 return SymbolAddress
3612
3613 - def get_symbol_at_address(self, address):
3614 found = None 3615 for (SymbolName, SymbolAddress, SymbolSize) in self.iter_symbols(): 3616 if SymbolAddress <= address: 3617 if SymbolAddress + SymbolSize > address: 3618 if not found or found[1] < SymbolAddress: 3619 found = (SymbolName, SymbolAddress, SymbolSize) 3620 return found
3621
3622 #============================================================================== 3623 3624 # TODO 3625 # + fetch special registers (MMX, XMM, 3DNow!, etc) 3626 3627 -class ThreadDebugOperations (object):
3628 """ 3629 Encapsulates several useful debugging routines for threads. 3630 3631 @group Properties: 3632 get_teb, get_teb_address, is_wow64 3633 3634 @group Disassembly: 3635 disassemble, disassemble_around, disassemble_around_pc, 3636 disassemble_string, disassemble_instruction, disassemble_current 3637 3638 @group Stack: 3639 get_stack_frame, get_stack_frame_range, get_stack_range, 3640 get_stack_trace, get_stack_trace_with_labels, 3641 read_stack_data, read_stack_dwords, 3642 peek_stack_data, peek_stack_dwords 3643 3644 @group Miscellaneous: 3645 read_code_bytes, peek_code_bytes, 3646 peek_pointers_in_data, peek_pointers_in_registers, 3647 get_linear_address, get_label_at_pc, 3648 get_seh_chain, get_wait_chain 3649 """ 3650
3651 - def is_wow64(self):
3652 """ 3653 Determines if the thread is running under WOW64. 3654 3655 @rtype: bool 3656 @return: 3657 C{True} if the thread is running under WOW64. That is, it belongs 3658 to a 32-bit application running in a 64-bit Windows. 3659 3660 C{False} if the thread belongs to either a 32-bit application 3661 running in a 32-bit Windows, or a 64-bit application running in a 3662 64-bit Windows. 3663 3664 @raise WindowsError: On error an exception is raised. 3665 3666 @see: U{http://msdn.microsoft.com/en-us/library/aa384249(VS.85).aspx} 3667 """ 3668 return self.get_process().is_wow64()
3669 3670 # TODO 3671 # Maybe it'd be a good idea to cache the TEB, or at least it's pointer. 3672 # The pointers may be obtained when debugging at create_thread_event. 3673
3674 - def get_teb(self):
3675 """ 3676 Returns a copy of the TEB. 3677 To dereference pointers in it call L{Process.read_structure}. 3678 3679 @rtype: L{TEB} 3680 @return: TEB structure. 3681 @raise WindowsError: An exception is raised on error. 3682 """ 3683 return self.get_process().read_structure( self.get_teb_address(), 3684 win32.TEB )
3685
3686 - def get_teb_address(self):
3687 """ 3688 Returns a remote pointer to the TEB. 3689 3690 @rtype: int 3691 @return: Remote pointer to the L{TEB} structure. 3692 @raise WindowsError: An exception is raised on error. 3693 """ 3694 try: 3695 tbi = win32.NtQueryInformationThread( self.get_handle(), 3696 win32.ThreadBasicInformation) 3697 address = tbi.TebBaseAddress 3698 except WindowsError: 3699 address = self.get_linear_address('SegFs', 0) # fs:[0] 3700 if not address: 3701 raise 3702 return address
3703
3704 - def get_linear_address(self, segment, address):
3705 """ 3706 Translates segment-relative addresses to linear addresses. 3707 3708 Linear addresses can be used to access a process memory, 3709 calling L{Process.read} and L{Process.write}. 3710 3711 @type segment: str 3712 @param segment: Segment register name. 3713 3714 @type address: int 3715 @param address: Segment relative memory address. 3716 3717 @rtype: int 3718 @return: Linear memory address. 3719 3720 @raise ValueError: Address is too large for selector. 3721 3722 @raise WindowsError: 3723 The current architecture does not support selectors. 3724 Selectors only exist in x86-based systems. 3725 """ 3726 selector = self.get_register(segment) 3727 ldt = win32.GetThreadSelectorEntry(self.get_handle(), selector) 3728 BaseLow = ldt.BaseLow 3729 BaseMid = ldt.HighWord.Bytes.BaseMid << 16 3730 BaseHi = ldt.HighWord.Bytes.BaseHi << 24 3731 Base = BaseLow | BaseMid | BaseHi 3732 LimitLow = ldt.LimitLow 3733 LimitHi = ldt.HighWord.Bits.LimitHi << 16 3734 Limit = LimitLow | LimitHi 3735 if address > Limit: 3736 msg = "Address %s too large for segment %s (selector %d)" 3737 msg = msg % (HexDump.address(address), segment, selector) 3738 raise ValueError, msg 3739 return Base + address
3740
3741 - def get_label_at_pc(self):
3742 """ 3743 @rtype: str 3744 @return: Label that points to the instruction currently being executed. 3745 """ 3746 return self.get_process().get_label_at_address( self.get_pc() )
3747
3748 - def get_seh_chain(self):
3749 """ 3750 @rtype: list of tuple( int, int ) 3751 @return: List of structured exception handlers. 3752 Each SEH is represented as a tuple of two addresses: 3753 - Address of the SEH block 3754 - Address of the SEH callback function 3755 3756 @raise NotImplementedError: 3757 This method is only supported in 32 bits versions of Windows. 3758 """ 3759 if System.arch != 'i386': 3760 raise NotImplementedError, \ 3761 "SEH chain parsing is only supported in 32-bit Windows." 3762 process = self.get_process() 3763 seh_chain = list() 3764 try: 3765 seh = process.read_uint( self.get_linear_address('SegFs', 0) ) 3766 while seh != 0xFFFFFFFF: 3767 seh_func = process.read_uint( seh + 4 ) 3768 seh_chain.append( (seh, seh_func) ) 3769 seh = process.read_uint( seh ) 3770 except WindowsError, e: 3771 pass 3772 return seh_chain
3773
3774 - def get_wait_chain(self):
3775 """ 3776 @rtype: 3777 tuple of ( 3778 list of L{win32.WAITCHAIN_NODE_INFO} structures, 3779 bool) 3780 @return: 3781 Wait chain for the thread. 3782 The boolean indicates if there's a cycle in the chain. 3783 @raise AttributeError: 3784 This method is only suppported in Windows Vista and above. 3785 @see: 3786 U{http://msdn.microsoft.com/en-us/library/ms681622%28VS.85%29.aspx} 3787 """ 3788 hWct = win32.OpenThreadWaitChainSession() 3789 try: 3790 return win32.GetThreadWaitChain(hWct, None, 0, self.get_tid()) 3791 finally: 3792 win32.CloseThreadWaitChainSession(hWct)
3793
3794 - def get_stack_range(self):
3795 """ 3796 @rtype: tuple( int, int ) 3797 @return: Stack beginning and end pointers, in memory addresses order. 3798 That is, the first pointer is the stack top, and the second pointer 3799 is the stack bottom, since the stack grows towards lower memory 3800 addresses. 3801 @raise WindowsError: Raises an exception on error. 3802 """ 3803 teb = self.get_teb() 3804 tib = teb.NtTib 3805 return ( tib.StackLimit, tib.StackBase ) # top, bottom
3806
3807 - def __get_stack_trace(self, depth = 16, bUseLabels = True, 3808 bMakePretty = True):
3809 """ 3810 Tries to get a stack trace for the current function. 3811 Only works for functions with standard prologue and epilogue. 3812 3813 @type depth: int 3814 @param depth: Maximum depth of stack trace. 3815 3816 @type bUseLabels: bool 3817 @param bUseLabels: C{True} to use labels, C{False} to use addresses. 3818 3819 @rtype: tuple of tuple( int, int, str ) 3820 @return: Stack trace of the thread as a tuple of 3821 ( return address, frame pointer address, module filename ) 3822 when C{bUseLabels} is C{True}, or a tuple of 3823 ( return address, frame pointer label ) 3824 when C{bUseLabels} is C{False}. 3825 3826 @raise WindowsError: Raises an exception on error. 3827 """ 3828 aProcess = self.get_process() 3829 st, sb = self.get_stack_range() # top, bottom 3830 fp = self.get_fp() 3831 trace = list() 3832 if aProcess.get_module_count() == 0: 3833 aProcess.scan_modules() 3834 while depth > 0: 3835 if fp == 0: 3836 break 3837 if not st <= fp < sb: 3838 break 3839 ra = aProcess.peek_pointer(fp + 4) 3840 if ra == 0: 3841 break 3842 lib = aProcess.get_module_at_address(ra) 3843 if lib is None: 3844 lib = "" 3845 else: 3846 if lib.fileName: 3847 lib = lib.fileName 3848 else: 3849 lib = "%s" % HexDump.address(lib.lpBaseOfDll) 3850 if bUseLabels: 3851 label = aProcess.get_label_at_address(ra) 3852 if bMakePretty: 3853 label = '%s (%s)' % (HexDump.address(ra), label) 3854 trace.append( (fp, label) ) 3855 else: 3856 trace.append( (fp, ra, lib) ) 3857 fp = aProcess.peek_pointer(fp) 3858 return tuple(trace)
3859
3860 - def get_stack_trace(self, depth = 16):
3861 """ 3862 Tries to get a stack trace for the current function. 3863 Only works for functions with standard prologue and epilogue. 3864 3865 @type depth: int 3866 @param depth: Maximum depth of stack trace. 3867 3868 @rtype: tuple of tuple( int, int, str ) 3869 @return: Stack trace of the thread as a tuple of 3870 ( return address, frame pointer address, module filename ). 3871 3872 @raise WindowsError: Raises an exception on error. 3873 """ 3874 return self.__get_stack_trace(depth, False)
3875
3876 - def get_stack_trace_with_labels(self, depth = 16, bMakePretty = True):
3877 """ 3878 Tries to get a stack trace for the current function. 3879 Only works for functions with standard prologue and epilogue. 3880 3881 @type depth: int 3882 @param depth: Maximum depth of stack trace. 3883 3884 @type bMakePretty: bool 3885 @param bMakePretty: 3886 C{True} for user readable labels, 3887 C{False} for labels that can be passed to L{Process.resolve_label}. 3888 3889 "Pretty" labels look better when producing output for the user to 3890 read, while pure labels are more useful programatically. 3891 3892 @rtype: tuple of tuple( int, int, str ) 3893 @return: Stack trace of the thread as a tuple of 3894 ( return address, frame pointer label ). 3895 3896 @raise WindowsError: Raises an exception on error. 3897 """ 3898 return self.__get_stack_trace(depth, True)
3899
3900 - def get_stack_frame_range(self):
3901 """ 3902 Returns the starting and ending addresses of the stack frame. 3903 Only works for functions with standard prologue and epilogue. 3904 3905 @rtype: tuple( int, int ) 3906 @return: Stack frame range. 3907 May not be accurate, depending on the compiler used. 3908 3909 @raise RuntimeError: The stack frame is invalid, 3910 or the function doesn't have a standard prologue 3911 and epilogue. 3912 3913 @raise WindowsError: An error occured when getting the thread context. 3914 """ 3915 st, sb = self.get_stack_range() # top, bottom 3916 sp = self.get_sp() 3917 fp = self.get_fp() 3918 size = fp - sp 3919 if not st <= sp < sb: 3920 raise RuntimeError, 'Stack pointer lies outside the stack' 3921 if not st <= fp < sb: 3922 raise RuntimeError, 'Frame pointer lies outside the stack' 3923 if sp > fp: 3924 raise RuntimeError, 'No valid stack frame found' 3925 return (sp, fp)
3926
3927 - def get_stack_frame(self, max_size = None):
3928 """ 3929 Reads the contents of the current stack frame. 3930 Only works for functions with standard prologue and epilogue. 3931 3932 @type max_size: int 3933 @param max_size: (Optional) Maximum amount of bytes to read. 3934 3935 @rtype: str 3936 @return: Stack frame data. 3937 May not be accurate, depending on the compiler used. 3938 May return an empty string. 3939 3940 @raise RuntimeError: The stack frame is invalid, 3941 or the function doesn't have a standard prologue 3942 and epilogue. 3943 3944 @raise WindowsError: An error occured when getting the thread context 3945 or reading data from the process memory. 3946 """ 3947 sp, fp = self.get_stack_frame_range() 3948 size = fp - sp 3949 if max_size and size > max_size: 3950 size = max_size 3951 return self.get_process().peek(sp, size)
3952
3953 - def read_stack_data(self, size = 128, offset = 0):
3954 """ 3955 Reads the contents of the top of the stack. 3956 3957 @type size: int 3958 @param size: Number of bytes to read. 3959 3960 @type offset: int 3961 @param offset: Offset from the stack pointer to begin reading. 3962 3963 @rtype: str 3964 @return: Stack data. 3965 3966 @raise WindowsError: Could not read the requested data. 3967 """ 3968 aProcess = self.get_process() 3969 return aProcess.read(self.get_sp() + offset, size)
3970
3971 - def peek_stack_data(self, size = 128, offset = 0):
3972 """ 3973 Tries to read the contents of the top of the stack. 3974 3975 @type size: int 3976 @param size: Number of bytes to read. 3977 3978 @type offset: int 3979 @param offset: Offset from the stack pointer to begin reading. 3980 3981 @rtype: str 3982 @return: Stack data. 3983 Returned data may be less than the requested size. 3984 """ 3985 aProcess = self.get_process() 3986 return aProcess.peek(self.get_sp() + offset, size)
3987
3988 - def read_stack_dwords(self, count, offset = 0):
3989 """ 3990 Reads DWORDs from the top of the stack. 3991 3992 @type count: int 3993 @param count: Number of DWORDs to read. 3994 3995 @type offset: int 3996 @param offset: Offset from the stack pointer to begin reading. 3997 3998 @rtype: tuple( int... ) 3999 @return: Tuple of integers read from the stack. 4000 4001 @raise WindowsError: Could not read the requested data. 4002 """ 4003 stackData = self.read_stack_data(count * 4, offset) 4004 return struct.unpack('<'+('L'*count), stackData)
4005
4006 - def peek_stack_dwords(self, count, offset = 0):
4007 """ 4008 Tries to read DWORDs from the top of the stack. 4009 4010 @type count: int 4011 @param count: Number of DWORDs to read. 4012 4013 @type offset: int 4014 @param offset: Offset from the stack pointer to begin reading. 4015 4016 @rtype: tuple( int... ) 4017 @return: Tuple of integers read from the stack. 4018 May be less than the requested number of DWORDs. 4019 """ 4020 stackData = self.peek_stack_data(count * 4, offset) 4021 if len(stackData) & 3: 4022 stackData = stackData[:-len(stackData) & 3] 4023 if not stackData: 4024 return () 4025 return struct.unpack('<'+('L'*count), stackData)
4026
4027 - def read_stack_qwords(self, count, offset = 0):
4028 """ 4029 Reads QWORDs from the top of the stack. 4030 4031 @type count: int 4032 @param count: Number of QWORDs to read. 4033 4034 @type offset: int 4035 @param offset: Offset from the stack pointer to begin reading. 4036 4037 @rtype: tuple( int... ) 4038 @return: Tuple of integers read from the stack. 4039 4040 @raise WindowsError: Could not read the requested data. 4041 """ 4042 stackData = self.read_stack_data(count * 8, offset) 4043 return struct.unpack('<'+('Q'*count), stackData)
4044
4045 - def peek_stack_qwords(self, count, offset = 0):
4046 """ 4047 Tries to read QWORDs from the top of the stack. 4048 4049 @type count: int 4050 @param count: Number of QWORDs to read. 4051 4052 @type offset: int 4053 @param offset: Offset from the stack pointer to begin reading. 4054 4055 @rtype: tuple( int... ) 4056 @return: Tuple of integers read from the stack. 4057 May be less than the requested number of QWORDs. 4058 """ 4059 stackData = self.peek_stack_data(count * 8, offset) 4060 if len(stackData) & 7: 4061 stackData = stackData[:-len(stackData) & 7] 4062 if not stackData: 4063 return () 4064 return struct.unpack('<'+('Q'*count), stackData)
4065
4066 - def read_code_bytes(self, size = 128, offset = 0):
4067 """ 4068 Tries to read some bytes of the code currently being executed. 4069 4070 @type size: int 4071 @param size: Number of bytes to read. 4072 4073 @type offset: int 4074 @param offset: Offset from the program counter to begin reading. 4075 4076 @rtype: str 4077 @return: Bytes read from the process memory. 4078 4079 @raise WindowsError: Could not read the requested data. 4080 """ 4081 return self.get_process().read(self.get_pc() + offset, size)
4082
4083 - def peek_code_bytes(self, size = 128, offset = 0):
4084 """ 4085 Tries to read some bytes of the code currently being executed. 4086 4087 @type size: int 4088 @param size: Number of bytes to read. 4089 4090 @type offset: int 4091 @param offset: Offset from the program counter to begin reading. 4092 4093 @rtype: str 4094 @return: Bytes read from the process memory. 4095 May be less than the requested number of bytes. 4096 """ 4097 return self.get_process().peek(self.get_pc() + offset, size)
4098
4099 - def peek_pointers_in_registers(self, peekSize = 16, context = None):
4100 """ 4101 Tries to guess which values in the registers are valid pointers, 4102 and reads some data from them. 4103 4104 @type peekSize: int 4105 @param peekSize: Number of bytes to read from each pointer found. 4106 4107 @type context: dict( str S{->} int ) 4108 @param context: (Optional) 4109 Dictionary mapping register names to their values. 4110 If not given, the current thread context will be used. 4111 4112 @rtype: dict( str S{->} str ) 4113 @return: Dictionary mapping register names to the data they point to. 4114 """ 4115 peekable_registers = ( 4116 'Eax', 'Ebx', 'Ecx', 'Edx', 'Esi', 'Edi', 'Ebp' 4117 ) 4118 if not context: 4119 context = self.get_context(win32.CONTEXT_CONTROL | \ 4120 win32.CONTEXT_INTEGER) 4121 aProcess = self.get_process() 4122 data = dict() 4123 for (reg_name, reg_value) in context.iteritems(): 4124 if reg_name not in peekable_registers: 4125 continue 4126 ## if reg_name == 'Ebp': 4127 ## stack_begin, stack_end = self.get_stack_range() 4128 ## print hex(stack_end), hex(reg_value), hex(stack_begin) 4129 ## if stack_begin and stack_end and stack_end < stack_begin and \ 4130 ## stack_begin <= reg_value <= stack_end: 4131 ## continue 4132 reg_data = aProcess.peek(reg_value, peekSize) 4133 if reg_data: 4134 data[reg_name] = reg_data 4135 return data
4136 4137 # TODO 4138 # try to avoid reading the same page twice by caching it
4139 - def peek_pointers_in_data(self, data, peekSize = 16, peekStep = 1):
4140 """ 4141 Tries to guess which values in the given data are valid pointers, 4142 and reads some data from them. 4143 4144 @type data: str 4145 @param data: Binary data to find pointers in. 4146 4147 @type peekSize: int 4148 @param peekSize: Number of bytes to read from each pointer found. 4149 4150 @type peekStep: int 4151 @param peekStep: Expected data alignment. 4152 Tipically you specify 1 when data alignment is unknown, 4153 or 4 when you expect data to be DWORD aligned. 4154 Any other value may be specified. 4155 4156 @rtype: dict( str S{->} str ) 4157 @return: Dictionary mapping stack offsets to the data they point to. 4158 """ 4159 aProcess = self.get_process() 4160 return aProcess.peek_pointers_in_data(data, peekSize, peekStep)
4161 4162 #------------------------------------------------------------------------------ 4163 4164 # TODO 4165 # The disassemble_around and disassemble_around_pc methods 4166 # should take as parameter instruction counts rather than sizes 4167
4168 - def disassemble_string(self, lpAddress, code):
4169 """ 4170 Disassemble instructions from a block of binary code. 4171 4172 @type lpAddress: int 4173 @param lpAddress: Memory address where the code was read from. 4174 4175 @type code: str 4176 @param code: Binary code to disassemble. 4177 4178 @rtype: list of tuple( long, int, str, str ) 4179 @return: List of tuples. Each tuple represents an assembly instruction 4180 and contains: 4181 - Memory address of instruction. 4182 - Size of instruction in bytes. 4183 - Disassembly line of instruction. 4184 - Hexadecimal dump of instruction. 4185 """ 4186 aProcess = self.get_process() 4187 return aProcess.disassemble_string(lpAddress, code)
4188
4189 - def disassemble(self, lpAddress, dwSize):
4190 """ 4191 Disassemble instructions from the address space of the process. 4192 4193 @type lpAddress: int 4194 @param lpAddress: Memory address where to read the code from. 4195 4196 @type dwSize: int 4197 @param dwSize: Size of binary code to disassemble. 4198 4199 @rtype: list of tuple( long, int, str, str ) 4200 @return: List of tuples. Each tuple represents an assembly instruction 4201 and contains: 4202 - Memory address of instruction. 4203 - Size of instruction in bytes. 4204 - Disassembly line of instruction. 4205 - Hexadecimal dump of instruction. 4206 """ 4207 aProcess = self.get_process() 4208 return aProcess.disassemble(lpAddress, dwSize)
4209
4210 - def disassemble_around(self, lpAddress, dwSize = 64):
4211 """ 4212 Disassemble around the given address. 4213 4214 @type lpAddress: int 4215 @param lpAddress: Memory address where to read the code from. 4216 4217 @type dwSize: int 4218 @param dwSize: Delta offset. 4219 Code will be read from lpAddress - dwSize to lpAddress + dwSize. 4220 4221 @rtype: list of tuple( long, int, str, str ) 4222 @return: List of tuples. Each tuple represents an assembly instruction 4223 and contains: 4224 - Memory address of instruction. 4225 - Size of instruction in bytes. 4226 - Disassembly line of instruction. 4227 - Hexadecimal dump of instruction. 4228 """ 4229 aProcess = self.get_process() 4230 return aProcess.disassemble_around(lpAddress, dwSize)
4231
4232 - def disassemble_around_pc(self, dwSize = 64):
4233 """ 4234 Disassemble around the program counter of the given thread. 4235 4236 @type dwSize: int 4237 @param dwSize: Delta offset. 4238 Code will be read from pc - dwSize to pc + dwSize. 4239 4240 @rtype: list of tuple( long, int, str, str ) 4241 @return: List of tuples. Each tuple represents an assembly instruction 4242 and contains: 4243 - Memory address of instruction. 4244 - Size of instruction in bytes. 4245 - Disassembly line of instruction. 4246 - Hexadecimal dump of instruction. 4247 """ 4248 aProcess = self.get_process() 4249 return aProcess.disassemble_around(self.get_pc(), dwSize)
4250
4251 - def disassemble_instruction(self, lpAddress):
4252 """ 4253 Disassemble the instruction at the given memory address. 4254 4255 @type lpAddress: int 4256 @param lpAddress: Memory address where to read the code from. 4257 4258 @rtype: tuple( long, int, str, str ) 4259 @return: The tuple represents an assembly instruction 4260 and contains: 4261 - Memory address of instruction. 4262 - Size of instruction in bytes. 4263 - Disassembly line of instruction. 4264 - Hexadecimal dump of instruction. 4265 """ 4266 aProcess = self.get_process() 4267 return aProcess.disassemble(lpAddress, 15)[0]
4268
4269 - def disassemble_current(self):
4270 """ 4271 Disassemble the instruction at the program counter of the given thread. 4272 4273 @rtype: tuple( long, int, str, str ) 4274 @return: The tuple represents an assembly instruction 4275 and contains: 4276 - Memory address of instruction. 4277 - Size of instruction in bytes. 4278 - Disassembly line of instruction. 4279 - Hexadecimal dump of instruction. 4280 """ 4281 return self.disassemble_instruction(self.get_pc())
4282
4283 #============================================================================== 4284 4285 # TODO 4286 # + remote GetLastError 4287 4288 -class ProcessDebugOperations (object):
4289 """ 4290 Encapsulates several useful debugging routines for processes. 4291 4292 @group Properties: 4293 get_peb, get_peb_address, 4294 get_main_module, get_image_base, get_image_name, 4295 is_wow64 4296 4297 @group Disassembly: 4298 disassemble, disassemble_around, disassemble_around_pc, 4299 disassemble_string, disassemble_instruction, disassemble_current 4300 4301 @group Debugging: 4302 flush_instruction_cache, debug_break, peek_pointers_in_data 4303 """ 4304 4305 __hexa_parameter = re.compile('0x[0-9A-Za-z]+') 4306
4307 - def __fixup_labels(self, disasm):
4308 for index in xrange(len(disasm)): 4309 (address, size, text, dump) = disasm[index] 4310 m = self.__hexa_parameter.search(text) 4311 while m: 4312 s, e = m.span() 4313 value = text[s:e] 4314 try: 4315 label = self.get_label_at_address( int(value, 0x10) ) 4316 except Exception, e: 4317 label = None 4318 if label: 4319 text = text[:s] + label + text[e:] 4320 e = s + len(value) 4321 m = self.__hexa_parameter.search(text, e) 4322 disasm[index] = (address, size, text, dump)
4323
4324 - def disassemble_string(self, lpAddress, code):
4325 """ 4326 Disassemble instructions from a block of binary code. 4327 4328 @type lpAddress: int 4329 @param lpAddress: Memory address where the code was read from. 4330 4331 @type code: str 4332 @param code: Binary code to disassemble. 4333 4334 @rtype: list of tuple( long, int, str, str ) 4335 @return: List of tuples. Each tuple represents an assembly instruction 4336 and contains: 4337 - Memory address of instruction. 4338 - Size of instruction in bytes. 4339 - Disassembly line of instruction. 4340 - Hexadecimal dump of instruction. 4341 """ 4342 if System.arch not in ('i386', 'amd64'): 4343 raise NotImplementedError 4344 if (not System.wow64 and System.bits == 32) or self.is_wow64(): 4345 return Decode(lpAddress, code, Decode32Bits) 4346 return Decode(lpAddress, code, Decode64Bits)
4347
4348 - def disassemble(self, lpAddress, dwSize):
4349 """ 4350 Disassemble instructions from the address space of the process. 4351 4352 @type lpAddress: int 4353 @param lpAddress: Memory address where to read the code from. 4354 4355 @type dwSize: int 4356 @param dwSize: Size of binary code to disassemble. 4357 4358 @rtype: list of tuple( long, int, str, str ) 4359 @return: List of tuples. Each tuple represents an assembly instruction 4360 and contains: 4361 - Memory address of instruction. 4362 - Size of instruction in bytes. 4363 - Disassembly line of instruction. 4364 - Hexadecimal dump of instruction. 4365 """ 4366 data = self.read(lpAddress, dwSize) 4367 disasm = self.disassemble_string(lpAddress, data) 4368 self.__fixup_labels(disasm) 4369 return disasm
4370 4371 # FIXME 4372 # This algorithm really sucks, I've got to write a better one :P
4373 - def disassemble_around(self, lpAddress, dwSize = 64):
4374 """ 4375 Disassemble around the given address. 4376 4377 @type lpAddress: int 4378 @param lpAddress: Memory address where to read the code from. 4379 4380 @type dwSize: int 4381 @param dwSize: Delta offset. 4382 Code will be read from lpAddress - dwSize to lpAddress + dwSize. 4383 4384 @rtype: list of tuple( long, int, str, str ) 4385 @return: List of tuples. Each tuple represents an assembly instruction 4386 and contains: 4387 - Memory address of instruction. 4388 - Size of instruction in bytes. 4389 - Disassembly line of instruction. 4390 - Hexadecimal dump of instruction. 4391 """ 4392 dwDelta = int(float(dwSize) / 2.0) 4393 addr_1 = lpAddress - dwDelta 4394 addr_2 = lpAddress 4395 size_1 = dwDelta 4396 size_2 = dwSize - dwDelta 4397 data = self.read(addr_1, dwSize) 4398 data_1 = data[:size_1] 4399 data_2 = data[size_1:] 4400 disasm_1 = self.disassemble_string(addr_1, data_1) 4401 disasm_2 = self.disassemble_string(addr_2, data_2) 4402 disasm = disasm_1 + disasm_2 4403 self.__fixup_labels(disasm) 4404 return disasm
4405
4406 - def disassemble_around_pc(self, dwThreadId, dwSize = 64):
4407 """ 4408 Disassemble around the program counter of the given thread. 4409 4410 @type dwThreadId: int 4411 @param dwThreadId: Global thread ID. 4412 The program counter for this thread will be used as the disassembly 4413 address. 4414 4415 @type dwSize: int 4416 @param dwSize: Delta offset. 4417 Code will be read from pc - dwSize to pc + dwSize. 4418 4419 @rtype: list of tuple( long, int, str, str ) 4420 @return: List of tuples. Each tuple represents an assembly instruction 4421 and contains: 4422 - Memory address of instruction. 4423 - Size of instruction in bytes. 4424 - Disassembly line of instruction. 4425 - Hexadecimal dump of instruction. 4426 """ 4427 aThread = self.get_thread(dwThreadId) 4428 return self.disassemble_around(aThread.get_pc(), dwSize)
4429
4430 - def disassemble_instruction(self, lpAddress):
4431 """ 4432 Disassemble the instruction at the given memory address. 4433 4434 @type lpAddress: int 4435 @param lpAddress: Memory address where to read the code from. 4436 4437 @rtype: tuple( long, int, str, str ) 4438 @return: The tuple represents an assembly instruction 4439 and contains: 4440 - Memory address of instruction. 4441 - Size of instruction in bytes. 4442 - Disassembly line of instruction. 4443 - Hexadecimal dump of instruction. 4444 """ 4445 return self.disassemble(lpAddress, 15)[0]
4446
4447 - def disassemble_current(self, dwThreadId):
4448 """ 4449 Disassemble the instruction at the program counter of the given thread. 4450 4451 @type dwThreadId: int 4452 @param dwThreadId: Global thread ID. 4453 The program counter for this thread will be used as the disassembly 4454 address. 4455 4456 @rtype: tuple( long, int, str, str ) 4457 @return: The tuple represents an assembly instruction 4458 and contains: 4459 - Memory address of instruction. 4460 - Size of instruction in bytes. 4461 - Disassembly line of instruction. 4462 - Hexadecimal dump of instruction. 4463 """ 4464 aThread = self.get_thread(dwThreadId) 4465 return self.disassemble_instruction(aThread.get_pc())
4466 4467 #------------------------------------------------------------------------------ 4468
4469 - def flush_instruction_cache(self):
4470 """ 4471 Flush the instruction cache. This is required if the process memory is 4472 modified and one or more threads are executing nearby the modified 4473 memory region. 4474 4475 @see: U{http://blogs.msdn.com/oldnewthing/archive/2003/12/08/55954.aspx#55958} 4476 4477 @raise WindowsError: Raises exception on error. 4478 """ 4479 win32.FlushInstructionCache( self.get_handle() )
4480
4481 - def debug_break(self):
4482 """ 4483 Triggers the system breakpoint in the process. 4484 4485 @raise WindowsError: On error an exception is raised. 4486 """ 4487 # The exception is raised by a new thread. 4488 # When continuing the exception, the thread dies by itself. 4489 # This thread is hidden from the debugger. 4490 win32.DebugBreakProcess( self.get_handle() )
4491
4492 - def is_wow64(self):
4493 """ 4494 Determines if the process is running under WOW64. 4495 4496 @rtype: bool 4497 @return: 4498 C{True} if the process is running under WOW64. That is, a 32-bit 4499 application running in a 64-bit Windows. 4500 4501 C{False} if the process is either a 32-bit application running in 4502 a 32-bit Windows, or a 64-bit application running in a 64-bit 4503 Windows. 4504 4505 @raise WindowsError: On error an exception is raised. 4506 4507 @see: U{http://msdn.microsoft.com/en-us/library/aa384249(VS.85).aspx} 4508 """ 4509 hProcess = self.get_handle() 4510 try: 4511 return win32.IsWow64Process(hProcess) 4512 except AttributeError: 4513 return False
4514 4515 #------------------------------------------------------------------------------ 4516
4517 - def get_peb(self):
4518 """ 4519 Returns a copy of the PEB. 4520 To dereference pointers in it call L{Process.read_structure}. 4521 4522 @rtype: L{win32.PEB} 4523 @return: PEB structure. 4524 @raise WindowsError: An exception is raised on error. 4525 """ 4526 return self.read_structure(self.get_peb_address(), win32.PEB)
4527
4528 - def get_peb_address(self):
4529 """ 4530 Returns a remote pointer to the PEB. 4531 4532 @rtype: int 4533 @return: Remote pointer to the L{win32.PEB} structure. 4534 Returns C{None} on error. 4535 """ 4536 pbi = win32.NtQueryInformationProcess(self.get_handle(), 4537 win32.ProcessBasicInformation) 4538 return pbi.PebBaseAddress
4539
4540 - def get_main_module(self):
4541 """ 4542 @rtype: L{Module} 4543 @return: Module object for the process main module. 4544 """ 4545 return self.get_module(self.get_image_base())
4546
4547 - def get_image_base(self):
4548 """ 4549 @rtype: int 4550 @return: Image base address for the process main module. 4551 """ 4552 return self.get_peb().ImageBaseAddress
4553 4554 # TODO 4555 # Still not working sometimes, I need more implementations. 4556 # Example: PIFSvc.exe from Symantec, under Windows XP. 4557 # Note that using the toolhelp api won't help, it also fails. 4558 # My guess is tasklist.exe uses undocumented apis (at ntdll?).
4559 - def get_image_name(self):
4560 """ 4561 @rtype: int 4562 @return: Filename of the process main module. 4563 4564 This method does it's best to retrieve the filename. 4565 However sometimes this is not possible, so C{None} may 4566 be returned instead. 4567 """ 4568 4569 name = None 4570 4571 # Method 1: Module.fileName 4572 # It's cached if the filename was already found by the other methods, 4573 # or it came with the corresponding debug event. 4574 if not name: 4575 try: 4576 name = self.get_main_module().fileName 4577 if not name: 4578 name = None 4579 except (KeyError, AttributeError, WindowsError): 4580 name = None 4581 4582 # Method 2: QueryFullProcessImageName() 4583 # Not implemented until Windows Vista. 4584 if not name: 4585 try: 4586 name = win32.QueryFullProcessImageName(self.get_handle()) 4587 except (AttributeError, WindowsError): 4588 name = None 4589 4590 # Method 3: GetProcessImageFileName() 4591 # Not implemented until Windows XP. 4592 # For more info see http://blog.voidnish.com/?p=72 4593 if not name: 4594 try: 4595 name = win32.GetProcessImageFileName(self.get_handle()) 4596 if name: 4597 name = PathOperations.native_to_win32_pathname(name) 4598 else: 4599 name = None 4600 except (AttributeError, WindowsError): 4601 if not name: 4602 name = None 4603 4604 # Method 4: GetModuleFileNameEx() 4605 # Not implemented until Windows 2000. 4606 if not name: 4607 try: 4608 name = win32.GetModuleFileNameEx(self.get_handle(), win32.NULL) 4609 if name: 4610 name = PathOperations.native_to_win32_pathname(name) 4611 else: 4612 name = None 4613 except (AttributeError, WindowsError): 4614 if not name: 4615 name = None 4616 4617 # Method 5: PEB.ProcessParameters->ImagePathName 4618 # May fail since it's using an undocumented internal structure. 4619 if not name: 4620 try: 4621 peb = self.get_peb() 4622 pp = self.read_structure(peb.ProcessParameters, 4623 win32.RTL_USER_PROCESS_PARAMETERS) 4624 s = pp.ImagePathName 4625 name = self.peek_string(s.Buffer, 4626 dwMaxSize=s.MaximumLength, fUnicode=True) 4627 if name: 4628 name = PathOperations.native_to_win32_pathname(name) 4629 else: 4630 name = None 4631 except (AttributeError, WindowsError): 4632 name = None 4633 4634 # Method 6: Module.get_filename() 4635 # It tries to get the filename from the file handle. 4636 # There are currently some problems due to the strange way the API 4637 # works - it returns the pathname without the drive letter, and I 4638 # couldn't figure out a way to fix it. 4639 if not name: 4640 try: 4641 name = self.get_main_module().get_filename() 4642 except (KeyError, AttributeError, WindowsError): 4643 name = None 4644 4645 # Return the image filename, or None on error. 4646 return name
4647
4648 - def get_command_line(self):
4649 """ 4650 Retrieves the command line with wich the program was started. 4651 4652 @rtype: str 4653 @return: Command line string. 4654 4655 @raise WindowsError: On error an exception is raised. 4656 """ 4657 peb = self.get_peb() 4658 pp = self.read_structure(peb.ProcessParameters, 4659 win32.RTL_USER_PROCESS_PARAMETERS) 4660 s = pp.CommandLine 4661 return self.peek_string(s.Buffer, dwMaxSize=s.MaximumLength, 4662 fUnicode=True)
4663 4664 #------------------------------------------------------------------------------ 4665 4666 # TODO 4667 # try to avoid reading the same page twice by caching it
4668 - def peek_pointers_in_data(self, data, peekSize = 16, peekStep = 1):
4669 """ 4670 Tries to guess which values in the given data are valid pointers, 4671 and reads some data from them. 4672 4673 @type data: str 4674 @param data: Binary data to find pointers in. 4675 4676 @type peekSize: int 4677 @param peekSize: Number of bytes to read from each pointer found. 4678 4679 @type peekStep: int 4680 @param peekStep: Expected data alignment. 4681 Tipically you specify 1 when data alignment is unknown, 4682 or 4 when you expect data to be DWORD aligned. 4683 Any other value may be specified. 4684 4685 @rtype: dict( str S{->} str ) 4686 @return: Dictionary mapping stack offsets to the data they point to. 4687 """ 4688 result = dict() 4689 ptrSize = win32.sizeof(win32.LPVOID) 4690 if ptrSize == 4: 4691 ptrFmt = '<L' 4692 else: 4693 ptrFmt = '<Q' 4694 if len(data) > 0: 4695 for i in xrange(0, len(data), peekStep): 4696 packed = data[i:i+ptrSize] 4697 if len(packed) == ptrSize: 4698 address = struct.unpack(ptrFmt, packed)[0] 4699 ## if not address & (~0xFFFF): continue 4700 peek_data = self.peek(address, peekSize) 4701 if peek_data: 4702 result[i] = peek_data 4703 return result
4704
4705 #============================================================================== 4706 4707 -class Window (object):
4708
4709 - def __init__(self, hWnd = None, process = None, thread = None):
4710 self.hWnd = hWnd 4711 self.process = process 4712 self.thread = thread 4713 self.dwProcessId = None 4714 self.dwThreadId = None
4715
4716 - def get_handle(self):
4717 if self.hWnd is None: 4718 raise ValueError, "No window handle set!" 4719 return self.hWnd
4720
4721 - def get_pid(self):
4722 if self.process: 4723 return process.get_pid() 4724 if not self.dwProcessId: 4725 self.__get_pid_and_tid() 4726 return self.dwProcessId
4727
4728 - def get_tid(self):
4729 if self.thread: 4730 return thread.get_tid() 4731 if not self.dwThreadId: 4732 self.__get_pid_and_tid() 4733 return self.dwThreadId
4734
4735 - def __get_pid_and_tid(self):
4736 self.dwThreadId, self.dwProcessId = \ 4737 win32.GetWindowThreadProcessId(self.hWnd)
4738
4739 - def get_process(self):
4740 if not self.process: 4741 self.process = self.get_thread().get_process() 4742 return self.process
4743
4744 - def get_thread(self):
4745 if not self.thread: 4746 self.thread = Thread( self.get_tid() ) 4747 return self.thread
4748
4749 - def get_classname(self):
4750 return win32.GetClassName( self.get_handle() )
4751
4752 - def get_text(self):
4753 buffer = ctypes.create_string_buffer("", 0x10000) 4754 win32.SendMessageA(self.get_handle(), win32.WM_GETTEXT, ctypes.byref(buffer), 0x10000) 4755 return buffer.value
4756
4757 - def set_text(self, text):
4758 win32.SendMessage(self.get_handle(), win32.WM_SETTEXT, text, len(text))
4759
4760 - def get_parent(self):
4761 return Window( win32.GetParent( self.get_handle() ), \ 4762 self.process, self.thread )
4763
4764 - def get_children(self):
4765 return [ 4766 Window( hWnd, self.process, self.thread ) \ 4767 for hWnd in win32.EnumChildWindows( self.get_handle() ) 4768 ]
4769
4770 - def get_tree(self):
4771 subtree = dict() 4772 for aWindow in self.get_children(): 4773 subtree[ aWindow.get_handle() ] = aWindow.get_tree() 4774 return subtree
4775
4776 - def get_root(self):
4777 hWnd = self.get_handle() 4778 hPrevWnd = hWnd 4779 while hWnd: 4780 hPrevWnd = hWnd 4781 hWnd = win32.GetParent(hWnd) 4782 return Window(hPrevWnd)
4783
4784 - def enable(self):
4785 win32.EnableWindow( self.get_handle(), True )
4786
4787 - def disable(self):
4788 win32.EnableWindow( self.get_handle(), False )
4789
4790 - def show(self, bAsync = True):
4791 if bAsync: 4792 win32.ShowWindowAsync( self.get_handle(), win32.SW_SHOW ) 4793 else: 4794 win32.ShowWindow( self.get_handle(), win32.SW_SHOW )
4795
4796 - def hide(self, bAsync = True):
4797 if bAsync: 4798 win32.ShowWindowAsync( self.get_handle(), win32.SW_HIDE ) 4799 else: 4800 win32.ShowWindow( self.get_handle(), win32.SW_HIDE )
4801
4802 - def maximize(self, bAsync = True):
4803 if bAsync: 4804 win32.ShowWindowAsync( self.get_handle(), win32.SW_MAXIMIZE ) 4805 else: 4806 win32.ShowWindow( self.get_handle(), win32.SW_MAXIMIZE )
4807
4808 - def minimize(self, bAsync = True):
4809 if bAsync: 4810 win32.ShowWindowAsync( self.get_handle(), win32.SW_MINIMIZE ) 4811 else: 4812 win32.ShowWindow( self.get_handle(), win32.SW_MINIMIZE )
4813
4814 - def restore(self, bAsync = True):
4815 if bAsync: 4816 win32.ShowWindowAsync( self.get_handle(), win32.SW_RESTORE ) 4817 else: 4818 win32.ShowWindow( self.get_handle(), win32.SW_RESTORE )
4819
4820 #============================================================================== 4821 4822 -class Module (SymbolContainer):
4823 """ 4824 Interface to a DLL library loaded in the context of another process. 4825 4826 @group Properties: 4827 get_base, get_filename, get_name, get_size, get_entry_point, 4828 get_process, get_pid 4829 4830 @group Labels: 4831 get_label, get_label_at_address, is_address_here, 4832 resolve, resolve_label, match_name 4833 4834 @group Handle: 4835 get_handle, open_handle, close_handle 4836 4837 @type unknown: str 4838 @cvar unknown: Suggested tag for unknown modules. 4839 4840 @type lpBaseOfDll: int 4841 @ivar lpBaseOfDll: Base of DLL module. 4842 Use L{get_base} instead. 4843 4844 @type hFile: L{FileHandle} 4845 @ivar hFile: Handle to the module file. 4846 Use L{get_handle} instead. 4847 4848 @type fileName: str 4849 @ivar fileName: Module filename. 4850 Use L{get_filename} instead. 4851 4852 @type SizeOfImage: int 4853 @ivar SizeOfImage: Size of the module. 4854 Use L{get_size} instead. 4855 4856 @type EntryPoint: int 4857 @ivar EntryPoint: Entry point of the module. 4858 Use L{get_entry_point} instead. 4859 4860 @type process: L{Process} 4861 @ivar process: Process where the module is loaded. 4862 Use L{get_process} instead. 4863 """ 4864 4865 unknown = '<unknown>' 4866
4867 - def __init__(self, lpBaseOfDll, hFile = None, fileName = None, 4868 SizeOfImage = None, 4869 EntryPoint = None, 4870 process = None):
4871 """ 4872 @type lpBaseOfDll: str 4873 @param lpBaseOfDll: Base address of the module. 4874 4875 @type hFile: L{FileHandle} 4876 @param hFile: (Optional) Handle to the module file. 4877 4878 @type fileName: str 4879 @param fileName: (Optional) Module filename. 4880 4881 @type SizeOfImage: int 4882 @param SizeOfImage: (Optional) Size of the module. 4883 4884 @type EntryPoint: int 4885 @param EntryPoint: (Optional) Entry point of the module. 4886 4887 @type process: L{Process} 4888 @param process: (Optional) Process where the module is loaded. 4889 """ 4890 super(Module, self).__init__() 4891 self.lpBaseOfDll = lpBaseOfDll 4892 self.hFile = hFile 4893 self.fileName = fileName 4894 self.SizeOfImage = SizeOfImage 4895 self.EntryPoint = EntryPoint 4896 self.process = process
4897
4898 - def get_base(self):
4899 """ 4900 @rtype: int or None 4901 @return: Base address of the module. 4902 Returns C{None} if unknown. 4903 """ 4904 return self.lpBaseOfDll
4905
4906 - def get_size(self):
4907 """ 4908 @rtype: int or None 4909 @return: Base size of the module. 4910 Returns C{None} if unknown. 4911 """ 4912 if not self.SizeOfImage: 4913 self.__get_size_and_entry_point() 4914 return self.SizeOfImage
4915
4916 - def get_entry_point(self):
4917 """ 4918 @rtype: int or None 4919 @return: Entry point of the module. 4920 Returns C{None} if unknown. 4921 """ 4922 if not self.EntryPoint: 4923 self.__get_size_and_entry_point() 4924 return self.EntryPoint
4925
4926 - def __get_size_and_entry_point(self):
4927 "Get the size and entry point of the module using the Win32 API." 4928 process = self.get_process() 4929 if process: 4930 try: 4931 handle = process.get_handle() 4932 base = self.get_base() 4933 mi = win32.GetModuleInformation(handle, base) 4934 self.SizeOfImage = mi.SizeOfImage 4935 self.EntryPoint = mi.EntryPoint 4936 except WindowsError: 4937 ## raise # XXX DEBUG 4938 pass
4939
4940 - def get_filename(self):
4941 """ 4942 @rtype: str or None 4943 @return: Module filename. 4944 Returns C{None} if unknown. 4945 """ 4946 if self.fileName is None: 4947 if self.hFile not in (None, win32.INVALID_HANDLE_VALUE): 4948 self.fileName = self.hFile.get_filename() 4949 return self.fileName
4950
4951 - def __filename_to_modname(self, pathname):
4952 """ 4953 @type pathname: str 4954 @param pathname: Pathname to a module. 4955 4956 @rtype: str 4957 @return: Module name. 4958 """ 4959 filename = PathOperations.pathname_to_filename(pathname) 4960 if filename: 4961 filename = filename.lower() 4962 filepart, extpart = PathOperations.split_extension(filename) 4963 if filepart and extpart: 4964 modName = filepart 4965 else: 4966 modName = filename 4967 else: 4968 modName = pathname 4969 return modName
4970
4971 - def get_name(self):
4972 """ 4973 @rtype: str 4974 @return: Module name, as used in labels. 4975 4976 @warning: Names are B{NOT} guaranteed to be unique. 4977 4978 If you need unique identification for a loaded module, 4979 use the base address instead. 4980 4981 @see: L{get_label} 4982 """ 4983 pathname = self.get_filename() 4984 if pathname: 4985 modName = self.__filename_to_modname(pathname) 4986 else: 4987 modName = "0x%x" % self.get_base() 4988 return modName
4989
4990 - def match_name(self, name):
4991 """ 4992 @rtype: bool 4993 @return: 4994 C{True} if the given name could refer to this module. 4995 It may not be exactly the same returned by L{get_name}. 4996 """ 4997 4998 # If the given name is exactly our name, return True. 4999 # Comparison is case insensitive. 5000 my_name = self.get_name().lower() 5001 if name.lower() == my_name: 5002 return True 5003 5004 # If the given name is a base address, compare it with ours. 5005 try: 5006 base = HexInput.integer(name) 5007 except ValueError: 5008 base = None 5009 if base is not None and base == self.get_base(): 5010 return True 5011 5012 # If the given name is a filename, convert it to a module name. 5013 # Then compare it with ours, case insensitive. 5014 modName = self.__filename_to_modname(name) 5015 if modName.lower() == my_name: 5016 return True 5017 5018 # No match. 5019 return False
5020
5021 - def get_process(self):
5022 """ 5023 @rtype: L{Process} or None 5024 @return: Parent Process object. 5025 Returns C{None} on error. 5026 """ 5027 return self.process
5028
5029 - def get_pid(self):
5030 """ 5031 @rtype: int or None 5032 @return: Parent process global ID. 5033 Returns C{None} on error. 5034 """ 5035 if self.process is None: 5036 return None 5037 return self.process.get_pid()
5038 5039 #------------------------------------------------------------------------------ 5040
5041 - def open_handle(self):
5042 """ 5043 Opens a new handle to the module. 5044 """ 5045 5046 if not self.get_filename(): 5047 msg = "Cannot retrieve filename for module at %s" 5048 msg = msg % HexDump.address( self.get_base() ) 5049 raise Exception, msg 5050 5051 hFile = win32.CreateFile(self.get_filename(), 5052 dwShareMode = win32.FILE_SHARE_READ, 5053 dwCreationDisposition = win32.OPEN_EXISTING) 5054 try: 5055 self.close_handle() 5056 finally: 5057 self.hFile = hFile
5058
5059 - def close_handle(self):
5060 """ 5061 Closes the handle to the module. 5062 """ 5063 try: 5064 if hasattr(self.hFile, 'close'): 5065 self.hFile.close() 5066 elif self.hFile not in (None, win32.INVALID_HANDLE_VALUE): 5067 win32.CloseHandle(self.hFile) 5068 finally: 5069 self.hFile = None
5070
5071 - def get_handle(self):
5072 """ 5073 @rtype: L{FileHandle} 5074 @return: Handle to the module file. 5075 """ 5076 if self.hFile in (None, win32.INVALID_HANDLE_VALUE): 5077 self.open_handle() 5078 return self.hFile
5079 5080 #------------------------------------------------------------------------------ 5081
5082 - def get_label(self, function = None, offset = None):
5083 """ 5084 Retrieves the label for the given function of this module or the module 5085 base address if no function name is given. 5086 5087 @type function: str 5088 @param function: (Optional) Exported function name. 5089 5090 @type offset: int 5091 @param offset: (Optional) Offset from the module base address. 5092 5093 @rtype: str 5094 @return: Label for the module base address, plus the offset if given. 5095 """ 5096 return SymbolOperations.parse_label(self.get_name(), function, offset)
5097
5098 - def get_label_at_address(self, address, offset = None):
5099 """ 5100 Creates a label from the given memory address. 5101 5102 If the address belongs to the module, the label is made relative to 5103 it's base address. 5104 5105 @type address: int 5106 @param address: Memory address. 5107 5108 @type offset: None or int 5109 @param offset: (Optional) Offset value. 5110 5111 @rtype: str 5112 @return: Label pointing to the given address. 5113 """ 5114 5115 # Add the offset to the address. 5116 if offset: 5117 address = address + offset 5118 5119 # Make the label relative to the base address if no match is found. 5120 module = self.get_name() 5121 function = None 5122 offset = address - self.get_base() 5123 5124 # Make the label relative to the entrypoint if no other match is found. 5125 # Skip if the entry point is unknown. 5126 start = self.get_entry_point() 5127 if start and start <= address: 5128 function = "start" 5129 offset = address - start 5130 5131 # Enumerate exported functions and debug symbols, 5132 # then find the closest match, if possible. 5133 try: 5134 symbol = self.get_symbol_at_address(address) 5135 if symbol: 5136 (SymbolName, SymbolAddress, SymbolSize) = symbol 5137 new_offset = address - SymbolAddress 5138 if new_offset <= offset: 5139 function = SymbolName 5140 offset = new_offset 5141 except WindowsError, e: 5142 pass 5143 5144 # Parse the label and return it. 5145 return SymbolOperations.parse_label(module, function, offset)
5146
5147 - def is_address_here(self, address):
5148 """ 5149 Tries to determine if the given address belongs to this module. 5150 5151 @type address: int 5152 @param address: Memory address. 5153 5154 @rtype: bool or None 5155 @return: C{True} if the address belongs to the module, 5156 C{False} if it doesn't, 5157 and C{None} if it can't be determined. 5158 """ 5159 base = self.get_base() 5160 size = self.get_size() 5161 if base and size: 5162 return base <= address < (base + size) 5163 return None
5164
5165 - def resolve(self, function):
5166 """ 5167 Resolves a function exported by this module. 5168 5169 @type function: str or int 5170 @param function: 5171 str: Name of the function. 5172 int: Ordinal of the function. 5173 5174 @rtype: int 5175 @return: Memory address of the exported function in the process. 5176 Returns None on error. 5177 """ 5178 5179 # Unknown DLL filename, there's nothing we can do. 5180 filename = self.get_filename() 5181 if not filename: 5182 return None 5183 5184 # If the DLL is already mapped locally, resolve the function. 5185 try: 5186 hlib = win32.GetModuleHandle(filename) 5187 address = win32.GetProcAddress(hlib, function) 5188 except WindowsError, e: 5189 5190 # Load the DLL locally, resolve the function and unload it. 5191 try: 5192 hlib = win32.LoadLibraryEx(filename, 5193 win32.DONT_RESOLVE_DLL_REFERENCES) 5194 try: 5195 address = win32.GetProcAddress(hlib, function) 5196 finally: 5197 win32.FreeLibrary(hlib) 5198 except WindowsError, e: 5199 return None 5200 5201 # A NULL pointer means the function was not found. 5202 if address == win32.NULL: 5203 return None 5204 5205 # Compensate for DLL base relocations locally and remotely. 5206 return address - hlib + self.lpBaseOfDll
5207
5208 - def resolve_label(self, label):
5209 """ 5210 Resolves a label for this module only. If the label refers to another 5211 module, an exception is raised. 5212 5213 @type label: str 5214 @param label: Label to resolve. 5215 5216 @rtype: int 5217 @return: Memory address pointed to by the label. 5218 5219 @raise ValueError: The label is malformed or impossible to resolve. 5220 @raise RuntimeError: Cannot resolve the module or function. 5221 """ 5222 5223 # Split the label into it's components. 5224 # Use the fuzzy mode whenever possible. 5225 aProcess = self.get_process() 5226 if aProcess is not None: 5227 (module, procedure, offset) = aProcess.split_label(label) 5228 else: 5229 (module, procedure, offset) = Process.split_label(label) 5230 5231 # If a module name is given that doesn't match ours, 5232 # raise an exception. 5233 if module and not self.match_name(module): 5234 raise RuntimeError, "Label does not belong to this module" 5235 5236 # Resolve the procedure if given. 5237 if procedure: 5238 address = self.resolve(procedure) 5239 if address is None: 5240 5241 # If it's a symbol, use the symbol. 5242 address = self.resolve_symbol(procedure) 5243 5244 # If it's the keyword "start" use the entry point. 5245 if address is None and procedure == "start": 5246 address = self.get_entry_point() 5247 5248 # The procedure was not found. 5249 if address is None: 5250 if not module: 5251 module = self.get_name() 5252 msg = "Can't find procedure %s in module %s" 5253 msg = msg % (procedure, module) 5254 raise RuntimeError, msg 5255 5256 # If no procedure is given use the base address of the module. 5257 else: 5258 address = self.get_base() 5259 5260 # Add the offset if given and return the resolved address. 5261 if offset: 5262 address = address + offset 5263 return address
5264
5265 #============================================================================== 5266 5267 -class Thread (ThreadDebugOperations):
5268 """ 5269 Interface to a thread in another process. 5270 5271 @group Properties: 5272 get_tid, get_pid, get_process, get_exit_code, is_alive, 5273 get_name, set_name 5274 @group Instrumentation: 5275 suspend, resume, kill, wait 5276 @group Registers: 5277 get_context, 5278 get_register, 5279 get_flags, get_flag_value, 5280 get_pc, get_sp, get_fp, 5281 get_cf, get_df, get_sf, get_tf, get_zf, 5282 set_context, 5283 set_register, 5284 set_flags, set_flag_value, 5285 set_pc, set_sp, set_fp, 5286 set_cf, set_df, set_sf, set_tf, set_zf, 5287 clear_cf, clear_df, clear_sf, clear_tf, clear_zf, 5288 Flags 5289 @group Handle: 5290 get_handle, open_handle, close_handle 5291 5292 @type dwThreadId: int 5293 @ivar dwThreadId: Global thread ID. Use L{get_tid} instead. 5294 5295 @type hThread: L{ThreadHandle} 5296 @ivar hThread: Handle to the thread. Use L{get_handle} instead. 5297 5298 @type process: L{Process} 5299 @ivar process: Parent process object. Use L{get_process} instead. 5300 5301 @type pInjectedMemory: int 5302 @ivar pInjectedMemory: If the thread was created by L{Process.inject_code}, 5303 this member contains a pointer to the memory buffer for the injected 5304 code. Otherwise it's C{None}. 5305 5306 The L{kill} method uses this member to free the buffer 5307 when the injected thread is killed. 5308 """ 5309
5310 - def __init__(self, dwThreadId, hThread = None, process = None):
5311 """ 5312 @type dwThreadId: int 5313 @param dwThreadId: Global thread ID. 5314 5315 @type hThread: L{ThreadHandle} 5316 @param hThread: (Optional) Handle to the thread. 5317 5318 @type process: L{Process} 5319 @param process: (Optional) Parent Process object. 5320 """ 5321 super(Thread, self).__init__() 5322 self.dwProcessId = None 5323 self.dwThreadId = dwThreadId 5324 self.hThread = hThread 5325 self.pInjectedMemory = None 5326 self.process = process 5327 self.set_name() 5328 if process is not None and not isinstance(process, Process): 5329 msg = "Parent process for Thread must be a Process instance, " 5330 msg += "got %s instead" % type(process) 5331 raise TypeError, msg
5332
5333 - def get_process(self):
5334 """ 5335 @rtype: L{Process} 5336 @return: Parent Process object. 5337 """ 5338 if self.process is None: 5339 self.process = Process(self.get_pid()) 5340 return self.process
5341
5342 - def get_pid(self):
5343 """ 5344 @rtype: int 5345 @return: Parent process global ID. 5346 5347 @raise WindowsError: An error occured when calling a Win32 API function. 5348 @raise RuntimeError: The parent process ID can't be found. 5349 """ 5350 if self.dwProcessId is None: 5351 if self.process is None: 5352 hThread = self.get_handle() 5353 try: 5354 # I wish this had been implemented before Vista... 5355 self.dwProcessId = win32.GetProcessIdOfThread(hThread) 5356 except AttributeError: 5357 # This method really sucks :P 5358 self.dwProcessId = self.__get_pid_by_scanning() 5359 else: 5360 self.dwProcessId = self.process.get_pid() 5361 return self.dwProcessId
5362
5363 - def __get_pid_by_scanning(self):
5364 'Internally used by get_pid().' 5365 dwProcessId = None 5366 dwThreadId = self.get_tid() 5367 hSnapshot = win32.CreateToolhelp32Snapshot(win32.TH32CS_SNAPTHREAD) 5368 try: 5369 te = win32.Thread32First(hSnapshot) 5370 while te is not None: 5371 if te.th32ThreadID == dwThreadId: 5372 dwProcessId = te.th32OwnerProcessID 5373 break 5374 te = win32.Thread32Next(hSnapshot) 5375 finally: 5376 win32.CloseHandle(hSnapshot) 5377 if dwProcessId is None: 5378 msg = "Cannot find thread ID %d in any process" % dwThreadId 5379 raise RuntimeError, msg 5380 return dwProcessId
5381
5382 - def get_tid(self):
5383 """ 5384 @rtype: int 5385 @return: Thread global ID. 5386 """ 5387 return self.dwThreadId
5388
5389 - def get_name(self):
5390 """ 5391 @rtype: str 5392 @return: Thread name, or C{None} if the thread is nameless. 5393 """ 5394 return self.name
5395
5396 - def set_name(self, name = None):
5397 """ 5398 Sets the thread's name. 5399 5400 @type name: str 5401 @param name: Thread name, or C{None} if the thread is nameless. 5402 """ 5403 self.name = name
5404 5405 #------------------------------------------------------------------------------ 5406
5407 - def open_handle(self, dwDesiredAccess = win32.PROCESS_ALL_ACCESS):
5408 """ 5409 Opens a new handle to the thread. 5410 """ 5411 hThread = win32.OpenThread(dwDesiredAccess, win32.FALSE, self.dwThreadId) 5412 try: 5413 self.close_handle() 5414 finally: 5415 self.hThread = hThread
5416
5417 - def close_handle(self):
5418 """ 5419 Closes the handle to the thread. 5420 """ 5421 try: 5422 if hasattr(self.hThread, 'close'): 5423 self.hThread.close() 5424 elif self.hThread not in (None, win32.INVALID_HANDLE_VALUE): 5425 win32.CloseHandle(self.hThread) 5426 finally: 5427 self.hThread = None
5428
5429 - def get_handle(self):
5430 """ 5431 @rtype: ThreadHandle 5432 @return: Handle to the thread. 5433 """ 5434 if self.hThread in (None, win32.INVALID_HANDLE_VALUE): 5435 self.open_handle() 5436 return self.hThread
5437 5438 #------------------------------------------------------------------------------ 5439
5440 - def wait(self, dwTimeout = None):
5441 """ 5442 Waits for the thread to finish executing. 5443 5444 @type dwTimeout: int 5445 @param dwTimeout: (Optional) Timeout value in milliseconds. 5446 Use C{INFINITE} or C{None} for no timeout. 5447 """ 5448 self.get_handle().wait(dwTimeout)
5449
5450 - def kill(self, dwExitCode = 0):
5451 """ 5452 Terminates the thread execution. 5453 5454 @note: If the C{lpInjectedMemory} member contains a valid pointer, 5455 the memory is freed. 5456 5457 @type dwExitCode: int 5458 @param dwExitCode: (Optional) Thread exit code. 5459 """ 5460 win32.TerminateThread(self.get_handle(), dwExitCode) 5461 if self.pInjectedMemory is not None: 5462 try: 5463 self.get_process().free(self.pInjectedMemory) 5464 self.pInjectedMemory = None 5465 except Exception: 5466 pass
5467 ## raise # XXX DEBUG 5468
5469 - def suspend(self):
5470 """ 5471 Suspends the thread execution. 5472 5473 @rtype: int 5474 @return: Suspend count. If zero, the thread is running. 5475 """ 5476 return win32.SuspendThread(self.get_handle())
5477
5478 - def resume(self):
5479 """ 5480 Resumes the thread execution. 5481 5482 @rtype: int 5483 @return: Suspend count. If zero, the thread is running. 5484 """ 5485 return win32.ResumeThread(self.get_handle())
5486
5487 - def is_alive(self):
5488 """ 5489 @rtype: bool 5490 @return: C{True} if the thread if currently running. 5491 """ 5492 try: 5493 hProcess = self.get_handle() 5494 except WindowsError: 5495 return False 5496 try: 5497 hProcess.wait(0) 5498 except WindowsError: 5499 return False 5500 return True
5501
5502 - def get_exit_code(self):
5503 """ 5504 @rtype: int 5505 @return: Thread exit code, or C{STILL_ACTIVE} if it's still alive. 5506 """ 5507 return win32.GetExitCodeThread(self.get_handle())
5508 5509 #------------------------------------------------------------------------------ 5510
5511 - def get_windows(self):
5512 """ 5513 @rtype: list of L{Window} 5514 @return: Returns a list of windows handled by this thread. 5515 """ 5516 try: 5517 process = self.get_process() 5518 except Exception: 5519 process = None 5520 return [ 5521 Window( hWnd, process, self ) \ 5522 for hWnd in win32.EnumThreadWindows( self.get_tid() ) 5523 ]
5524 5525 #------------------------------------------------------------------------------ 5526 5527 # TODO 5528 # A registers cache could be implemented here.
5529 - def get_context(self, ContextFlags = None):
5530 """ 5531 @type ContextFlags: int 5532 @param ContextFlags: Optional, specify which registers to retrieve. 5533 Defaults to C{win32.CONTEXT_ALL} which retrieves all registes 5534 for the current platform. 5535 5536 @rtype: dict( str S{->} int ) 5537 @return: Dictionary mapping register names to their values. 5538 5539 @see: L{set_context} 5540 """ 5541 5542 # Get the thread handle. 5543 hThread = self.get_handle() 5544 5545 # Threads can't be suspended when the exit process event arrives. 5546 # Funny thing is, you can still get the context. (?) 5547 try: 5548 self.suspend() 5549 bSuspended = True 5550 except WindowsError: 5551 bSuspended = False 5552 5553 # If an exception is raised, make sure the thread execution is resumed. 5554 try: 5555 5556 # If we're not in WOW64, things are simple :) 5557 if not System.wow64: 5558 ## if self.is_wow64(): 5559 ## if ContextFlags is not None: 5560 ## ContextFlags = ContextFlags & (~win32.ContextArchMask) 5561 ## ContextFlags = ContextFlags | win32.WOW64_CONTEXT_i386 5562 ## ctx = win32.Wow64GetThreadContext(hThread, 5563 ## ContextFlags = ContextFlags) 5564 ## else: 5565 ctx = win32.GetThreadContext(hThread, 5566 ContextFlags = ContextFlags) 5567 5568 # If we're in WOW64, things are tricky! 5569 else: 5570 if self.is_wow64(): 5571 ctx = win32.GetThreadContext(hThread, 5572 ContextFlags = ContextFlags) 5573 else: 5574 # XXX only i386/AMD64 is supported in this particular case 5575 if System.arch != 'i386': 5576 raise NotImplementedError 5577 if ContextFlags is not None: 5578 ContextFlags = ContextFlags & (~win32.ContextArchMask) 5579 ContextFlags = ContextFlags | win32.context_amd64.CONTEXT_AMD64 5580 ctx = win32.context_amd64.GetThreadContext(hThread, 5581 ContextFlags = ContextFlags) 5582 finally: 5583 if bSuspended: 5584 self.resume() 5585 return ctx
5586
5587 - def set_context(self, context):
5588 """ 5589 Sets the values of the registers. 5590 5591 @see: L{get_context} 5592 5593 @type context: dict( str S{->} int ) 5594 @param context: Dictionary mapping register names to their values. 5595 """ 5596 # No fix for the exit process event bug. 5597 # Setting the context of a dead thread is pointless anyway. 5598 self.suspend() 5599 try: 5600 if System.bits == 64 and self.is_wow64(): 5601 win32.Wow64SetThreadContext(self.get_handle(), context) 5602 else: 5603 win32.SetThreadContext(self.get_handle(), context) 5604 finally: 5605 self.resume()
5606
5607 - def get_register(self, register):
5608 """ 5609 @type register: str 5610 @param register: Register name. 5611 5612 @rtype: int 5613 @return: Value of the requested register. 5614 """ 5615 'Returns the value of a specific register.' 5616 context = self.get_context() 5617 return context[register]
5618
5619 - def set_register(self, register, value):
5620 """ 5621 Sets the value of a specific register. 5622 5623 @type register: str 5624 @param register: Register name. 5625 5626 @rtype: int 5627 @return: Register value. 5628 """ 5629 context = self.get_context() 5630 context[register] = value 5631 self.set_context(context)
5632 5633 #------------------------------------------------------------------------------ 5634 5635 if win32.CONTEXT.arch in ('i386', 'amd64'): 5636
5637 - def get_pc(self):
5638 """ 5639 @rtype: int 5640 @return: Value of the program counter register. 5641 """ 5642 context = self.get_context(win32.CONTEXT_CONTROL) 5643 return context.pc
5644
5645 - def set_pc(self, pc):
5646 """ 5647 Sets the value of the program counter register. 5648 5649 @type pc: int 5650 @param pc: Value of the program counter register. 5651 """ 5652 context = self.get_context(win32.CONTEXT_CONTROL) 5653 context.pc = pc 5654 self.set_context(context)
5655
5656 - def get_sp(self):
5657 """ 5658 @rtype: int 5659 @return: Value of the stack pointer register. 5660 """ 5661 context = self.get_context(win32.CONTEXT_CONTROL) 5662 return context.sp
5663
5664 - def set_sp(self, sp):
5665 """ 5666 Sets the value of the stack pointer register. 5667 5668 @type sp: int 5669 @param sp: Value of the stack pointer register. 5670 """ 5671 context = self.get_context(win32.CONTEXT_CONTROL) 5672 context.sp = sp 5673 self.set_context(context)
5674
5675 - def get_fp(self):
5676 """ 5677 @rtype: int 5678 @return: Value of the frame pointer register. 5679 """ 5680 context = self.get_context(win32.CONTEXT_CONTROL) 5681 return context.fp
5682
5683 - def set_fp(self, fp):
5684 """ 5685 Sets the value of the frame pointer register. 5686 5687 @type fp: int 5688 @param fp: Value of the frame pointer register. 5689 """ 5690 context = self.get_context(win32.CONTEXT_CONTROL) 5691 context.fp = fp 5692 self.set_context(context)
5693 5694 elif win32.CONTEXT.arch == 'ia64': 5695
5696 - def get_gp(self):
5697 """ 5698 @rtype: int 5699 @return: Value of the GP register. 5700 """ 5701 context = self.get_context(win32.CONTEXT_CONTROL) 5702 return context.gp
5703
5704 - def set_gp(self, gp):
5705 """ 5706 Sets the value of the frame pointer register. 5707 5708 @type gp: int 5709 @param gp: Value of the GP register. 5710 """ 5711 context = self.get_context(win32.CONTEXT_CONTROL) 5712 context.gp = gp 5713 self.set_context(context)
5714
5715 - def get_sp(self):
5716 """ 5717 @rtype: int 5718 @return: Value of the SP register. 5719 """ 5720 context = self.get_context(win32.CONTEXT_CONTROL) 5721 return context.sp
5722
5723 - def set_sp(self, sp):
5724 """ 5725 Sets the value of the SP register. 5726 5727 @type sp: int 5728 @param sp: Value of the SP register. 5729 """ 5730 context = self.get_context(win32.CONTEXT_CONTROL) 5731 context.sp = sp 5732 self.set_context(context)
5733
5734 - def get_rp(self):
5735 """ 5736 @rtype: int 5737 @return: Value of the RP register. 5738 """ 5739 context = self.get_context(win32.CONTEXT_CONTROL) 5740 return context.rp
5741
5742 - def set_rp(self, rp):
5743 """ 5744 Sets the value of the RP register. 5745 5746 @type rp: int 5747 @param rp: Value of the RP register. 5748 """ 5749 context = self.get_context(win32.CONTEXT_CONTROL) 5750 context.rp = rp 5751 self.set_context(context)
5752 5753 #------------------------------------------------------------------------------ 5754 5755 if win32.CONTEXT.arch in ('i386', 'amd64'): 5756
5757 - class Flags (object):
5758 'Commonly used processor flags' 5759 Overflow = 0x800 5760 Direction = 0x400 5761 Interrupts = 0x200 5762 Trap = 0x100 5763 Sign = 0x80 5764 Zero = 0x40 5765 # 0x20 ??? 5766 Auxiliary = 0x10 5767 # 0x8 ??? 5768 Parity = 0x4 5769 # 0x2 ??? 5770 Carry = 0x1
5771
5772 - def get_flags(self, FlagMask = 0xFFFFFFFF):
5773 """ 5774 @type FlagMask: int 5775 @param FlagMask: (Optional) Bitwise-AND mask. 5776 5777 @rtype: int 5778 @return: Flags register contents, optionally masking out some bits. 5779 """ 5780 context = self.get_context(win32.CONTEXT_CONTROL) 5781 return context['EFlags'] & FlagMask
5782
5783 - def set_flags(self, eflags, FlagMask = 0xFFFFFFFF):
5784 """ 5785 Sets the flags register, optionally masking some bits. 5786 5787 @type eflags: int 5788 @param eflags: Flags register contents. 5789 5790 @type FlagMask: int 5791 @param FlagMask: (Optional) Bitwise-AND mask. 5792 """ 5793 context = self.get_context(win32.CONTEXT_CONTROL) 5794 context['EFlags'] = (context['EFlags'] & FlagMask) | eflags 5795 self.set_context(context)
5796
5797 - def get_flag_value(self, FlagBit):
5798 """ 5799 @type FlagBit: int 5800 @param FlagBit: One of the L{Flags}. 5801 5802 @rtype: bool 5803 @return: Boolean value of the requested flag. 5804 """ 5805 return bool( self.get_flags(FlagBit) )
5806
5807 - def set_flag_value(self, FlagBit, FlagValue):
5808 """ 5809 Sets a single flag, leaving the others intact. 5810 5811 @type FlagBit: int 5812 @param FlagBit: One of the L{Flags}. 5813 5814 @type FlagValue: bool 5815 @param FlagValue: Boolean value of the flag. 5816 """ 5817 if FlagValue: 5818 eflags = FlagBit 5819 else: 5820 eflags = 0 5821 FlagMask = 0xFFFFFFFF ^ FlagBit 5822 self.set_flags(eflags, FlagMask)
5823
5824 - def get_zf(self):
5825 """ 5826 @rtype: bool 5827 @return: Boolean value of the Zero flag. 5828 """ 5829 return self.get_flag_value(self.Flags.Zero)
5830
5831 - def get_cf(self):
5832 """ 5833 @rtype: bool 5834 @return: Boolean value of the Carry flag. 5835 """ 5836 return self.get_flag_value(self.Flags.Carry)
5837
5838 - def get_sf(self):
5839 """ 5840 @rtype: bool 5841 @return: Boolean value of the Sign flag. 5842 """ 5843 return self.get_flag_value(self.Flags.Sign)
5844
5845 - def get_df(self):
5846 """ 5847 @rtype: bool 5848 @return: Boolean value of the Direction flag. 5849 """ 5850 return self.get_flag_value(self.Flags.Direction)
5851
5852 - def get_tf(self):
5853 """ 5854 @rtype: bool 5855 @return: Boolean value of the Trap flag. 5856 """ 5857 return self.get_flag_value(self.Flags.Trap)
5858
5859 - def clear_zf(self):
5860 'Clears the Zero flag.' 5861 self.set_flag_value(self.Flags.Zero, False)
5862
5863 - def clear_cf(self):
5864 'Clears the Carry flag.' 5865 self.set_flag_value(self.Flags.Carry, False)
5866
5867 - def clear_sf(self):
5868 'Clears the Sign flag.' 5869 self.set_flag_value(self.Flags.Sign, False)
5870
5871 - def clear_df(self):
5872 'Clears the Direction flag.' 5873 self.set_flag_value(self.Flags.Direction, False)
5874
5875 - def clear_tf(self):
5876 'Clears the Trap flag.' 5877 self.set_flag_value(self.Flags.Trap, False)
5878
5879 - def set_zf(self):
5880 'Sets the Zero flag.' 5881 self.set_flag_value(self.Flags.Zero, True)
5882
5883 - def set_cf(self):
5884 'Sets the Carry flag.' 5885 self.set_flag_value(self.Flags.Carry, True)
5886
5887 - def set_sf(self):
5888 'Sets the Sign flag.' 5889 self.set_flag_value(self.Flags.Sign, True)
5890
5891 - def set_df(self):
5892 'Sets the Direction flag.' 5893 self.set_flag_value(self.Flags.Direction, True)
5894
5895 - def set_tf(self):
5896 'Sets the Trap flag.' 5897 self.set_flag_value(self.Flags.Trap, True)
5898
5899 #============================================================================== 5900 5901 -class Process (MemoryOperations, ProcessDebugOperations, SymbolOperations, \ 5902 ThreadContainer, ModuleContainer):
5903 """ 5904 Interface to a process. Contains threads and modules snapshots. 5905 5906 @group Properties: 5907 get_pid, get_filename, get_exit_code, 5908 is_alive, is_debugged 5909 5910 @group Instrumentation: 5911 kill, wait, suspend, resume, inject_code, inject_dll 5912 5913 @group Processes snapshot: 5914 scan, clear, __contains__, __iter__, __len__ 5915 5916 @group Handle: 5917 get_handle, open_handle, close_handle 5918 5919 @type dwProcessId: int 5920 @ivar dwProcessId: Global process ID. Use L{get_pid} instead. 5921 5922 @type hProcess: L{ProcessHandle} 5923 @ivar hProcess: Handle to the process. Use L{get_handle} instead. 5924 5925 @type fileName: str 5926 @ivar fileName: Filename of the main module. Use L{get_filename} instead. 5927 """ 5928
5929 - def __init__(self, dwProcessId, hProcess = None, fileName = None):
5930 """ 5931 @type dwProcessId: int 5932 @param dwProcessId: Global process ID. 5933 5934 @type hProcess: L{ProcessHandle} 5935 @param hProcess: Handle to the process. 5936 5937 @type fileName: str 5938 @param fileName: (Optional) Filename of the main module. 5939 """ 5940 MemoryOperations.__init__(self) 5941 ProcessDebugOperations.__init__(self) 5942 SymbolOperations.__init__(self) 5943 ThreadContainer.__init__(self) 5944 ModuleContainer.__init__(self) 5945 5946 self.dwProcessId = dwProcessId 5947 self.hProcess = hProcess 5948 self.fileName = fileName
5949
5950 - def get_pid(self):
5951 """ 5952 @rtype: int 5953 @return: Process global ID. 5954 """ 5955 return self.dwProcessId
5956
5957 - def get_filename(self):
5958 """ 5959 @rtype: str 5960 @return: Filename of the main module of the process. 5961 """ 5962 if not self.fileName: 5963 self.fileName = self.get_image_name() 5964 return self.fileName
5965
5966 - def open_handle(self):
5967 """ 5968 Opens a new handle to the process. 5969 """ 5970 hProcess = win32.OpenProcess(win32.PROCESS_ALL_ACCESS, win32.FALSE, 5971 self.dwProcessId) 5972 try: 5973 self.close_handle() 5974 finally: 5975 self.hProcess = hProcess
5976
5977 - def close_handle(self):
5978 """ 5979 Closes the handle to the process. 5980 """ 5981 try: 5982 if hasattr(self.hProcess, 'close'): 5983 self.hProcess.close() 5984 elif self.hProcess not in (None, win32.INVALID_HANDLE_VALUE): 5985 win32.CloseHandle(self.hProcess) 5986 finally: 5987 self.hProcess = None
5988
5989 - def get_handle(self):
5990 """ 5991 @rtype: L{ProcessHandle} 5992 @return: Handle to the process. 5993 """ 5994 if self.hProcess in (None, win32.INVALID_HANDLE_VALUE): 5995 self.open_handle() 5996 return self.hProcess
5997 5998 #------------------------------------------------------------------------------ 5999
6000 - def __contains__(self, anObject):
6001 """ 6002 The same as: C{self.has_thread(anObject) or self.has_module(anObject)} 6003 6004 @type anObject: L{Thread}, L{Module} or int 6005 @param anObject: Object to look for. 6006 Can be a Thread, Module, thread global ID or module base address. 6007 6008 @rtype: bool 6009 @return: C{True} if the requested object was found in the snapshot. 6010 """ 6011 return ThreadContainer.__contains__(self, anObject) or \ 6012 ModuleContainer.__contains__(self, anObject)
6013
6014 - def __len__(self):
6015 """ 6016 @see: L{get_thread_count}, L{get_module_count} 6017 @rtype: int 6018 @return: Count of L{Thread} and L{Module} objects in this snapshot. 6019 """ 6020 return ThreadContainer.__len__(self) + \ 6021 ModuleContainer.__len__(self)
6022
6023 - class __ThreadsAndModulesIterator (object):
6024 """ 6025 Iterator object for L{Process} objects. 6026 Iterates through L{Thread} objects first, L{Module} objects next. 6027 """ 6028
6029 - def __init__(self, container):
6030 """ 6031 @type container: L{Process} 6032 @param container: L{Thread} and L{Module} container. 6033 """ 6034 self.__container = container 6035 self.__iterator = None 6036 self.__state = 0
6037
6038 - def next(self):
6039 'x.next() -> the next value, or raise StopIteration' 6040 if self.__state == 0: 6041 self.__iterator = self.__container.iter_threads() 6042 self.__state = 1 6043 if self.__state == 1: 6044 try: 6045 return self.__iterator.next() 6046 except StopIteration: 6047 self.__iterator = self.__container.iter_modules() 6048 self.__state = 2 6049 if self.__state == 2: 6050 try: 6051 return self.__iterator.next() 6052 except StopIteration: 6053 self.__iterator = None 6054 self.__state = 3 6055 raise StopIteration
6056
6057 - def __iter__(self):
6058 """ 6059 @see: L{iter_threads}, L{iter_modules} 6060 @rtype: iterator 6061 @return: Iterator of L{Thread} and L{Module} objects in this snapshot. 6062 All threads are iterated first, then all modules. 6063 """ 6064 return self.__ThreadsAndModulesIterator(self)
6065 6066 #------------------------------------------------------------------------------ 6067
6068 - def wait(self, dwTimeout = None):
6069 """ 6070 Waits for the process to finish executing. 6071 6072 @raise WindowsError: On error an exception is raised. 6073 """ 6074 self.get_handle().wait(dwTimeout)
6075
6076 - def kill(self, dwExitCode = 0):
6077 """ 6078 Terminates the execution of the process. 6079 6080 @raise WindowsError: On error an exception is raised. 6081 """ 6082 win32.TerminateProcess(self.get_handle(), dwExitCode)
6083
6084 - def suspend(self):
6085 """ 6086 Suspends execution on all threads of the process. 6087 6088 @raise WindowsError: On error an exception is raised. 6089 """ 6090 if self.get_thread_count() == 0: 6091 self.scan_threads() 6092 suspended = list() 6093 try: 6094 for aThread in self.iter_threads(): 6095 aThread.suspend() 6096 suspended.append(aThread) 6097 except Exception: 6098 for aThread in suspended: 6099 try: 6100 aThread.resume() 6101 except Exception: 6102 pass 6103 raise
6104
6105 - def resume(self):
6106 """ 6107 Resumes execution on all threads of the process. 6108 6109 @raise WindowsError: On error an exception is raised. 6110 """ 6111 if self.get_thread_count() == 0: 6112 self.scan_threads() 6113 resumed = list() 6114 try: 6115 for aThread in self.iter_threads(): 6116 aThread.resume() 6117 resumed.append(aThread) 6118 except Exception: 6119 for aThread in resumed: 6120 try: 6121 aThread.suspend() 6122 except Exception: 6123 pass 6124 raise
6125
6126 - def is_debugged(self):
6127 """ 6128 Tries to determine if the process is being debugged by another process. 6129 It may detect other debuggers besides WinAppDbg. 6130 6131 @rtype: bool 6132 @return: C{True} if the process has a debugger attached. 6133 6134 @warning: 6135 May return inaccurate results when some anti-debug techniques are 6136 used by the target process. 6137 6138 @note: To know if a process currently being debugged by a L{Debug} 6139 object, call L{Debug.is_debugee} instead. 6140 """ 6141 return win32.CheckRemoteDebuggerPresent(self.get_handle())
6142
6143 - def is_alive(self):
6144 """ 6145 @rtype: bool 6146 @return: C{True} if the process is currently running. 6147 """ 6148 try: 6149 self.wait(0) 6150 except WindowsError, e: 6151 return e.winerror == win32.WAIT_TIMEOUT 6152 return False
6153
6154 - def get_exit_code(self):
6155 """ 6156 @rtype: int 6157 @return: Process exit code, or C{STILL_ACTIVE} if it's still alive. 6158 6159 @warning: If a process returns C{STILL_ACTIVE} as it's exit code, 6160 you may not be able to determine if it's active or not with this 6161 method. Use L{is_alive} to check if the process is still active. 6162 Alternatively you can call L{get_handle} to get the handle object 6163 and then L{ProcessHandle.wait} on it to wait until the process 6164 finishes running. 6165 """ 6166 return win32.GetExitCodeProcess(self.get_handle())
6167 6168 #------------------------------------------------------------------------------ 6169
6170 - def scan(self):
6171 """ 6172 Populates the snapshot of threads and modules. 6173 """ 6174 self.scan_threads() 6175 self.scan_modules()
6176
6177 - def clear(self):
6178 """ 6179 Clears the snapshot of threads and modules. 6180 """ 6181 self.clear_threads() 6182 self.clear_modules()
6183 6184 #------------------------------------------------------------------------------ 6185
6186 - def get_windows(self):
6187 """ 6188 @rtype: list of L{Window} 6189 @return: Returns a list of windows handled by this process. 6190 """ 6191 window_list = list() 6192 for thread in self.iter_threads(): 6193 window_list.extend( thread.get_windows() ) 6194 return window_list
6195 6196 #------------------------------------------------------------------------------ 6197
6198 - def inject_code(self, payload, lpParameter = 0):
6199 """ 6200 Injects relocatable code into the process memory and executes it. 6201 6202 @see: L{inject_dll} 6203 6204 @type payload: str 6205 @param payload: Relocatable code to run in a new thread. 6206 6207 @type lpParameter: int 6208 @param lpParameter: (Optional) Parameter to be pushed in the stack. 6209 6210 @rtype: tuple( L{Thread}, int ) 6211 @return: The injected Thread object 6212 and the memory address where the code was written. 6213 6214 @raise WindowsError: An exception is raised on error. 6215 """ 6216 6217 # Uncomment for debugging... 6218 ## payload = '\xCC' + payload 6219 6220 # Allocate the memory for the shellcode. 6221 lpStartAddress = self.malloc(len(payload)) 6222 6223 # Catch exceptions so we can free the memory on error. 6224 try: 6225 6226 # Write the shellcode to our memory location. 6227 self.write(lpStartAddress, payload) 6228 6229 # Start a new thread for the shellcode to run. 6230 aThread = self.start_thread(lpStartAddress, lpParameter, 6231 bSuspended = False) 6232 6233 # Remember the shellcode address. 6234 # It will be freed ONLY by the Thread.kill() method 6235 # and the EventHandler class, otherwise you'll have to 6236 # free it in your code, or have your shellcode clean up 6237 # after itself (recommended). 6238 aThread.pInjectedMemory = lpStartAddress 6239 6240 # Free the memory on error. 6241 except Exception, e: 6242 self.free(lpStartAddress) 6243 raise 6244 6245 # Return the Thread object and the shellcode address. 6246 return aThread, lpStartAddress
6247 6248 # TODO 6249 # The shellcode should check for errors, otherwise it just crashes 6250 # when the DLL can't be loaded or the procedure can't be found. 6251 # On error the shellcode should execute an int3 instruction.
6252 - def inject_dll(self, dllname, procname = None, lpParameter = 0, 6253 bWait = True, dwTimeout = None):
6254 """ 6255 Injects a DLL into the process memory. 6256 6257 @warning: Setting C{bWait} to C{True} when the process is frozen by a 6258 debug event will cause a deadlock in your debugger. 6259 6260 @see: L{inject_code} 6261 6262 @type dllname: str 6263 @param dllname: Name of the DLL module to load. 6264 6265 @type procname: str 6266 @param procname: (Optional) Procedure to call when the DLL is loaded. 6267 6268 @type lpParameter: int 6269 @param lpParameter: (Optional) Parameter to the C{procname} procedure. 6270 6271 @type bWait: bool 6272 @param bWait: C{True} to wait for the process to finish. 6273 C{False} to return immediately. 6274 6275 @type dwTimeout: int 6276 @param dwTimeout: (Optional) Timeout value in milliseconds. 6277 Ignored if C{bWait} is C{False}. 6278 6279 @raise NotImplementedError: The target platform is not supported. 6280 Currently calling a procedure in the library is only supported in 6281 the I{i386} architecture. 6282 6283 @raise WindowsError: An exception is raised on error. 6284 """ 6285 6286 # Resolve kernel32.dll 6287 aModule = self.get_module_by_name('kernel32.dll') 6288 if aModule is None: 6289 self.scan_modules() 6290 aModule = self.get_module_by_name('kernel32.dll') 6291 if aModule is None: 6292 raise RuntimeError, \ 6293 "Cannot resolve kernel32.dll in the remote process" 6294 6295 # Old method, using shellcode. 6296 if procname: 6297 if System.arch != 'i386': 6298 raise NotImplementedError 6299 dllname = str(dllname) 6300 6301 # Resolve kernel32.dll!LoadLibraryA 6302 pllib = aModule.resolve('LoadLibraryA') 6303 if not pllib: 6304 raise RuntimeError, \ 6305 "Cannot resolve kernel32.dll!LoadLibraryA in the remote process" 6306 6307 # Resolve kernel32.dll!GetProcAddress 6308 pgpad = aModule.resolve('GetProcAddress') 6309 if not pgpad: 6310 raise RuntimeError, \ 6311 "Cannot resolve kernel32.dll!GetProcAddress in the remote process" 6312 6313 # Resolve kernel32.dll!VirtualFree 6314 pvf = aModule.resolve('VirtualFree') 6315 if not pvf: 6316 raise RuntimeError, \ 6317 "Cannot resolve kernel32.dll!VirtualFree in the remote process" 6318 6319 # Shellcode follows... 6320 code = ''.encode('utf8') 6321 6322 # push dllname 6323 code += '\xe8' + struct.pack('<L', len(dllname) + 1) + dllname + '\0' 6324 6325 # mov eax, LoadLibraryA 6326 code += '\xb8' + struct.pack('<L', pllib) 6327 6328 # call eax 6329 code += '\xff\xd0' 6330 6331 if procname: 6332 6333 # push procname 6334 code += '\xe8' + struct.pack('<L', len(procname) + 1) 6335 code += procname + '\0' 6336 6337 # push eax 6338 code += '\x50' 6339 6340 # mov eax, GetProcAddress 6341 code += '\xb8' + struct.pack('<L', pgpad) 6342 6343 # call eax 6344 code += '\xff\xd0' 6345 6346 # mov ebp, esp ; preserve stack pointer 6347 code += '\x8b\xec' 6348 6349 # push lpParameter 6350 code += '\x68' + struct.pack('<L', lpParameter) 6351 6352 # call eax 6353 code += '\xff\xd0' 6354 6355 # mov esp, ebp ; restore stack pointer 6356 code += '\x8b\xe5' 6357 6358 # pop edx ; our own return address 6359 code += '\x5a' 6360 6361 # push MEM_RELEASE ; dwFreeType 6362 code += '\x68' + struct.pack('<L', win32.MEM_RELEASE) 6363 6364 # push 0x1000 ; dwSize, shellcode max size 4096 bytes 6365 code += '\x68' + struct.pack('<L', 0x1000) 6366 6367 # call $+5 6368 code += '\xe8\x00\x00\x00\x00' 6369 6370 # and dword ptr [esp], 0xFFFFF000 ; align to page boundary 6371 code += '\x81\x24\x24\x00\xf0\xff\xff' 6372 6373 # mov eax, VirtualFree 6374 code += '\xb8' + struct.pack('<L', pvf) 6375 6376 # push edx ; our own return address 6377 code += '\x52' 6378 6379 # jmp eax ; VirtualFree will return to our own return address 6380 code += '\xff\xe0' 6381 6382 # Inject the shellcode. 6383 aThread, lpStartAddress = self.inject_code(code, lpParameter) 6384 6385 # There's no need to free the memory, 6386 # because the shellcode will free it itself. 6387 aThread.pInjectedMemory = None 6388 6389 # New method, not using shellcode. 6390 else: 6391 6392 # Resolve kernel32.dll!LoadLibrary (A/W) 6393 if type(dllname) == type(u''): 6394 pllibname = 'LoadLibraryW' 6395 bufferlen = (len(dllname) + 1) * 2 6396 dllname = win32.ctypes.create_unicode_buffer(dllname).raw[:bufferlen + 1] 6397 else: 6398 pllibname = 'LoadLibraryA' 6399 dllname = str(dllname) + '\x00' 6400 bufferlen = len(dllname) 6401 pllib = aModule.resolve(pllibname) 6402 if not pllib: 6403 msg = "Cannot resolve kernel32.dll!%s in the remote process" 6404 raise RuntimeError, msg % pllibname 6405 6406 # Copy the library name into the process memory space. 6407 pbuffer = self.malloc(bufferlen) 6408 try: 6409 self.write(pbuffer, dllname) 6410 6411 # Create a new thread to load the library. 6412 aThread = self.start_thread(pllib, pbuffer) 6413 6414 # Remember the buffer address. 6415 # It will be freed ONLY by the Thread.kill() method 6416 # and the EventHandler class, otherwise you'll have to 6417 # free it in your code. 6418 aThread.pInjectedMemory = pbuffer 6419 6420 # Free the memory on error. 6421 except Exception: 6422 self.free(pbuffer, bufferlen) 6423 raise 6424 6425 # Wait for the thread to finish. 6426 if bWait: 6427 aThread.wait(dwTimeout)
6428
6429 - def clean_exit(self, dwExitCode = 0, bWait = False, dwTimeout = None):
6430 """ 6431 Injects a new thread to call ExitProcess(). 6432 Optionally waits for the injected thread to finish. 6433 6434 @warning: Setting C{bWait} to C{True} when the process is frozen by a 6435 debug event will cause a deadlock in your debugger. 6436 6437 @type dwExitCode: int 6438 @param dwExitCode: Process exit code. 6439 6440 @type bWait: bool 6441 @param bWait: C{True} to wait for the process to finish. 6442 C{False} to return immediately. 6443 6444 @type dwTimeout: int 6445 @param dwTimeout: (Optional) Timeout value in milliseconds. 6446 Ignored if C{bWait} is C{False}. 6447 6448 @raise WindowsError: An exception is raised on error. 6449 """ 6450 if not dwExitCode: 6451 dwExitCode = 0 6452 pExitProcess = self.resolve_label('kernel32!ExitProcess') 6453 aThread = self.start_thread(pExitProcess, dwExitCode) 6454 if bWait: 6455 aThread.wait(dwTimeout)
6456 6457 #------------------------------------------------------------------------------ 6458
6459 - def notify_create_process(self, event):
6460 """ 6461 Notify the creation of a new process. 6462 6463 This is done automatically by the L{Debug} class, you shouldn't need 6464 to call it yourself. 6465 6466 @type event: L{CreateProcessEvent} 6467 @param event: Create process event. 6468 """ 6469 # Do not use super() here. 6470 bCallHandler = ThreadContainer.notify_create_process(self, event) 6471 bCallHandler = bCallHandler and \ 6472 ModuleContainer.notify_create_process(self, event) 6473 return bCallHandler
6474
6475 #============================================================================== 6476 6477 -class System (ProcessContainer):
6478 """ 6479 Interface to a batch of processes, plus some system wide settings. 6480 Contains a snapshot of processes. 6481 6482 @group Global settings: 6483 arch, pageSize, 6484 set_kill_on_exit_mode, request_debug_privileges, 6485 enable_step_on_branch_mode 6486 6487 @type arch: str 6488 @cvar arch: Name of the processor architecture we're running on. 6489 For more details see L{win32.version.get_arch}. 6490 6491 @type bits: int 6492 @cvar bits: Size of the machine word in bits for the current architecture. 6493 For more details see L{win32.version.get_bits}. 6494 6495 @type os: str 6496 @cvar os: Name of the Windows version we're runing on. 6497 For more details see L{win32.version.get_os}. 6498 6499 @type wow64: bool 6500 @cvar wow64: C{True} if the debugger is a 32 bits process running in a 64 6501 bits version of Windows, C{False} otherwise. 6502 6503 @type pageSize: int 6504 @cvar pageSize: Page size in bytes. Defaults to 0x1000 but it's 6505 automatically updated on runtime when importing the module. 6506 """ 6507 6508 arch = win32.version.arch 6509 bits = win32.version.bits 6510 os = win32.version.os 6511 6512 # Try to determine if the debugger itself is running on WOW64. 6513 # On error assume False. 6514 try: 6515 wow64 = win32.IsWow64Process( win32.GetCurrentProcess() ) 6516 except Exception: 6517 wow64 = False 6518 6519 # Try to get the pageSize value on runtime, 6520 # ignoring exceptions on failure. 6521 try: 6522 try: 6523 pageSize = win32.GetSystemInfo().dwPageSize 6524 except WindowsError: 6525 pageSize = 0x1000 6526 except NameError: 6527 pageSize = 0x1000 6528 6529 #------------------------------------------------------------------------------ 6530 6531 @staticmethod
6532 - def request_debug_privileges(bIgnoreExceptions = False):
6533 """ 6534 Requests debug privileges. 6535 6536 This may be needed to debug processes running as SYSTEM 6537 (such as services) since Windows XP. 6538 """ 6539 try: 6540 privs = ( 6541 (win32.SE_DEBUG_NAME, True), 6542 ) 6543 hToken = win32.OpenProcessToken(win32.GetCurrentProcess(), 6544 win32.TOKEN_ADJUST_PRIVILEGES) 6545 try: 6546 win32.AdjustTokenPrivileges(hToken, privs) 6547 finally: 6548 win32.CloseHandle(hToken) 6549 return True 6550 except Exception, e: 6551 if not bIgnoreExceptions: 6552 raise 6553 return False
6554 6555 @staticmethod
6556 - def set_kill_on_exit_mode(bKillOnExit = False):
6557 """ 6558 Automatically detach from processes when the current thread dies. 6559 6560 Works on the following platforms: 6561 6562 - Microsoft Windows XP and above. 6563 - Wine (Windows Emulator). 6564 6565 Fails on the following platforms: 6566 6567 - Microsoft Windows 2000 and below. 6568 - ReactOS. 6569 6570 @type bKillOnExit: bool 6571 @param bKillOnExit: C{True} to automatically kill processes when the 6572 debugger thread dies. C{False} to automatically detach from 6573 processes when the debugger thread dies. 6574 6575 @rtype: bool 6576 @return: C{True} on success, C{False} on error. 6577 """ 6578 try: 6579 # won't work before calling CreateProcess or DebugActiveProcess 6580 # http://msdn.microsoft.com/en-us/library/ms679307.aspx 6581 win32.DebugSetProcessKillOnExit(bKillOnExit) 6582 return True 6583 except (AttributeError, WindowsError): 6584 pass 6585 return False
6586 6587 @staticmethod
6589 """ 6590 When tracing, call this on every single step event 6591 for step on branch mode. 6592 6593 @raise WindowsError: 6594 Raises C{ERROR_DEBUGGER_INACTIVE} if the debugger is not attached 6595 to least one process. 6596 6597 @warning: 6598 This has a HARDCODED value for a machine specific register (MSR). 6599 It could potentially brick your machine. 6600 It works on my machine, but your mileage may vary. 6601 6602 @note: 6603 It doesn't seem to work in VirtualBox machines. 6604 Maybe it fails in other virtualization/emulation environments, 6605 no extensive testing was made so far. 6606 """ 6607 msr = win32.SYSDBG_MSR() 6608 msr.Address = 0x1D9 6609 msr.Data = 2 6610 return win32.NtSystemDebugControl(win32.SysDbgWriteMsr, msr)
6611