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

Source Code for Module winappdbg.system

   1  #!~/.wine/drive_c/Python25/python.exe 
   2  # -*- coding: utf-8 -*- 
   3   
   4  # Copyright (c) 2009-2014, Mario Vilas 
   5  # All rights reserved. 
   6  # 
   7  # Redistribution and use in source and binary forms, with or without 
   8  # modification, are permitted provided that the following conditions are met: 
   9  # 
  10  #     * Redistributions of source code must retain the above copyright notice, 
  11  #       this list of conditions and the following disclaimer. 
  12  #     * Redistributions in binary form must reproduce the above copyright 
  13  #       notice,this list of conditions and the following disclaimer in the 
  14  #       documentation and/or other materials provided with the distribution. 
  15  #     * Neither the name of the copyright holder nor the names of its 
  16  #       contributors may be used to endorse or promote products derived from 
  17  #       this software without specific prior written permission. 
  18  # 
  19  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  20  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  21  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  22  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  23  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  24  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  25  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  26  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  27  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  28  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  29  # POSSIBILITY OF SUCH DAMAGE. 
  30   
  31  """ 
  32  System settings. 
  33   
  34  @group Instrumentation: 
  35      System 
  36  """ 
  37   
  38  from __future__ import with_statement 
  39   
  40  __revision__ = "$Id: system.py 1299 2013-12-20 09:30:55Z qvasimodo $" 
  41   
  42  __all__ = ['System'] 
  43   
  44  import win32 
  45  import win32.version 
  46  from registry import Registry 
  47  from textio import HexInput, HexDump 
  48  from util import Regenerator, PathOperations, MemoryAddresses, DebugRegister, \ 
  49                   classproperty 
  50  from process import _ProcessContainer 
  51  from window import Window 
  52   
  53  import os 
  54  import ctypes 
  55  import warnings 
  56   
  57  from os import path, getenv 
58 59 #============================================================================== 60 61 -class System (_ProcessContainer):
62 """ 63 Interface to a batch of processes, plus some system wide settings. 64 Contains a snapshot of processes. 65 66 @group Platform settings: 67 arch, bits, os, wow64, pageSize 68 69 @group Instrumentation: 70 find_window, get_window_at, get_foreground_window, 71 get_desktop_window, get_shell_window 72 73 @group Debugging: 74 load_dbghelp, fix_symbol_store_path, 75 request_debug_privileges, drop_debug_privileges 76 77 @group Postmortem debugging: 78 get_postmortem_debugger, set_postmortem_debugger, 79 get_postmortem_exclusion_list, add_to_postmortem_exclusion_list, 80 remove_from_postmortem_exclusion_list 81 82 @group System services: 83 get_services, get_active_services, 84 start_service, stop_service, 85 pause_service, resume_service, 86 get_service_display_name, get_service_from_display_name 87 88 @group Permissions and privileges: 89 request_privileges, drop_privileges, adjust_privileges, is_admin 90 91 @group Miscellaneous global settings: 92 set_kill_on_exit_mode, read_msr, write_msr, enable_step_on_branch_mode, 93 get_last_branch_location 94 95 @type arch: str 96 @cvar arch: Name of the processor architecture we're running on. 97 For more details see L{win32.version._get_arch}. 98 99 @type bits: int 100 @cvar bits: Size of the machine word in bits for the current architecture. 101 For more details see L{win32.version._get_bits}. 102 103 @type os: str 104 @cvar os: Name of the Windows version we're runing on. 105 For more details see L{win32.version._get_os}. 106 107 @type wow64: bool 108 @cvar wow64: C{True} if the debugger is a 32 bits process running in a 64 109 bits version of Windows, C{False} otherwise. 110 111 @type pageSize: int 112 @cvar pageSize: Page size in bytes. Defaults to 0x1000 but it's 113 automatically updated on runtime when importing the module. 114 115 @type registry: L{Registry} 116 @cvar registry: Windows Registry for this machine. 117 """ 118 119 arch = win32.arch 120 bits = win32.bits 121 os = win32.os 122 wow64 = win32.wow64 123 124 @classproperty
125 - def pageSize(cls):
129 130 registry = Registry() 131 132 #------------------------------------------------------------------------------ 133 134 @staticmethod
135 - def find_window(className = None, windowName = None):
136 """ 137 Find the first top-level window in the current desktop to match the 138 given class name and/or window name. If neither are provided any 139 top-level window will match. 140 141 @see: L{get_window_at} 142 143 @type className: str 144 @param className: (Optional) Class name of the window to find. 145 If C{None} or not used any class name will match the search. 146 147 @type windowName: str 148 @param windowName: (Optional) Caption text of the window to find. 149 If C{None} or not used any caption text will match the search. 150 151 @rtype: L{Window} or None 152 @return: A window that matches the request. There may be more matching 153 windows, but this method only returns one. If no matching window 154 is found, the return value is C{None}. 155 156 @raise WindowsError: An error occured while processing this request. 157 """ 158 # I'd love to reverse the order of the parameters 159 # but that might create some confusion. :( 160 hWnd = win32.FindWindow(className, windowName) 161 if hWnd: 162 return Window(hWnd)
163 164 @staticmethod
165 - def get_window_at(x, y):
166 """ 167 Get the window located at the given coordinates in the desktop. 168 If no such window exists an exception is raised. 169 170 @see: L{find_window} 171 172 @type x: int 173 @param x: Horizontal coordinate. 174 @type y: int 175 @param y: Vertical coordinate. 176 177 @rtype: L{Window} 178 @return: Window at the requested position. If no such window 179 exists a C{WindowsError} exception is raised. 180 181 @raise WindowsError: An error occured while processing this request. 182 """ 183 return Window( win32.WindowFromPoint( (x, y) ) )
184 185 @staticmethod
187 """ 188 @rtype: L{Window} 189 @return: Returns the foreground window. 190 @raise WindowsError: An error occured while processing this request. 191 """ 192 return Window( win32.GetForegroundWindow() )
193 194 @staticmethod
195 - def get_desktop_window():
196 """ 197 @rtype: L{Window} 198 @return: Returns the desktop window. 199 @raise WindowsError: An error occured while processing this request. 200 """ 201 return Window( win32.GetDesktopWindow() )
202 203 @staticmethod
204 - def get_shell_window():
205 """ 206 @rtype: L{Window} 207 @return: Returns the shell window. 208 @raise WindowsError: An error occured while processing this request. 209 """ 210 return Window( win32.GetShellWindow() )
211 212 #------------------------------------------------------------------------------ 213 214 @classmethod
215 - def request_debug_privileges(cls, bIgnoreExceptions = False):
216 """ 217 Requests debug privileges. 218 219 This may be needed to debug processes running as SYSTEM 220 (such as services) since Windows XP. 221 222 @type bIgnoreExceptions: bool 223 @param bIgnoreExceptions: C{True} to ignore any exceptions that may be 224 raised when requesting debug privileges. 225 226 @rtype: bool 227 @return: C{True} on success, C{False} on failure. 228 229 @raise WindowsError: Raises an exception on error, unless 230 C{bIgnoreExceptions} is C{True}. 231 """ 232 try: 233 cls.request_privileges(win32.SE_DEBUG_NAME) 234 return True 235 except Exception, e: 236 if not bIgnoreExceptions: 237 raise 238 return False
239 240 @classmethod
241 - def drop_debug_privileges(cls, bIgnoreExceptions = False):
242 """ 243 Drops debug privileges. 244 245 This may be needed to avoid being detected 246 by certain anti-debug tricks. 247 248 @type bIgnoreExceptions: bool 249 @param bIgnoreExceptions: C{True} to ignore any exceptions that may be 250 raised when dropping debug privileges. 251 252 @rtype: bool 253 @return: C{True} on success, C{False} on failure. 254 255 @raise WindowsError: Raises an exception on error, unless 256 C{bIgnoreExceptions} is C{True}. 257 """ 258 try: 259 cls.drop_privileges(win32.SE_DEBUG_NAME) 260 return True 261 except Exception, e: 262 if not bIgnoreExceptions: 263 raise 264 return False
265 266 @classmethod
267 - def request_privileges(cls, *privileges):
268 """ 269 Requests privileges. 270 271 @type privileges: int... 272 @param privileges: Privileges to request. 273 274 @raise WindowsError: Raises an exception on error. 275 """ 276 cls.adjust_privileges(True, privileges)
277 278 @classmethod
279 - def drop_privileges(cls, *privileges):
280 """ 281 Drops privileges. 282 283 @type privileges: int... 284 @param privileges: Privileges to drop. 285 286 @raise WindowsError: Raises an exception on error. 287 """ 288 cls.adjust_privileges(False, privileges)
289 290 @staticmethod
291 - def adjust_privileges(state, privileges):
292 """ 293 Requests or drops privileges. 294 295 @type state: bool 296 @param state: C{True} to request, C{False} to drop. 297 298 @type privileges: list(int) 299 @param privileges: Privileges to request or drop. 300 301 @raise WindowsError: Raises an exception on error. 302 """ 303 with win32.OpenProcessToken(win32.GetCurrentProcess(), 304 win32.TOKEN_ADJUST_PRIVILEGES) as hToken: 305 NewState = ( (priv, state) for priv in privileges ) 306 win32.AdjustTokenPrivileges(hToken, NewState)
307 308 @staticmethod
309 - def is_admin():
310 """ 311 @rtype: bool 312 @return: C{True} if the current user as Administrator privileges, 313 C{False} otherwise. Since Windows Vista and above this means if 314 the current process is running with UAC elevation or not. 315 """ 316 return win32.IsUserAnAdmin()
317 318 #------------------------------------------------------------------------------ 319 320 __binary_types = { 321 win32.VFT_APP: "application", 322 win32.VFT_DLL: "dynamic link library", 323 win32.VFT_STATIC_LIB: "static link library", 324 win32.VFT_FONT: "font", 325 win32.VFT_DRV: "driver", 326 win32.VFT_VXD: "legacy driver", 327 } 328 329 __driver_types = { 330 win32.VFT2_DRV_COMM: "communications driver", 331 win32.VFT2_DRV_DISPLAY: "display driver", 332 win32.VFT2_DRV_INSTALLABLE: "installable driver", 333 win32.VFT2_DRV_KEYBOARD: "keyboard driver", 334 win32.VFT2_DRV_LANGUAGE: "language driver", 335 win32.VFT2_DRV_MOUSE: "mouse driver", 336 win32.VFT2_DRV_NETWORK: "network driver", 337 win32.VFT2_DRV_PRINTER: "printer driver", 338 win32.VFT2_DRV_SOUND: "sound driver", 339 win32.VFT2_DRV_SYSTEM: "system driver", 340 win32.VFT2_DRV_VERSIONED_PRINTER: "versioned printer driver", 341 } 342 343 __font_types = { 344 win32.VFT2_FONT_RASTER: "raster font", 345 win32.VFT2_FONT_TRUETYPE: "TrueType font", 346 win32.VFT2_FONT_VECTOR: "vector font", 347 } 348 349 __months = ( 350 "January", 351 "February", 352 "March", 353 "April", 354 "May", 355 "June", 356 "July", 357 "August", 358 "September", 359 "October", 360 "November", 361 "December", 362 ) 363 364 __days_of_the_week = ( 365 "Sunday", 366 "Monday", 367 "Tuesday", 368 "Wednesday", 369 "Thursday", 370 "Friday", 371 "Saturday", 372 ) 373 374 @classmethod
375 - def get_file_version_info(cls, filename):
376 """ 377 Get the program version from an executable file, if available. 378 379 @type filename: str 380 @param filename: Pathname to the executable file to query. 381 382 @rtype: tuple(str, str, bool, bool, str, str) 383 @return: Tuple with version information extracted from the executable 384 file metadata, containing the following: 385 - File version number (C{"major.minor"}). 386 - Product version number (C{"major.minor"}). 387 - C{True} for debug builds, C{False} for production builds. 388 - C{True} for legacy OS builds (DOS, OS/2, Win16), 389 C{False} for modern OS builds. 390 - Binary file type. 391 May be one of the following values: 392 - "application" 393 - "dynamic link library" 394 - "static link library" 395 - "font" 396 - "raster font" 397 - "TrueType font" 398 - "vector font" 399 - "driver" 400 - "communications driver" 401 - "display driver" 402 - "installable driver" 403 - "keyboard driver" 404 - "language driver" 405 - "legacy driver" 406 - "mouse driver" 407 - "network driver" 408 - "printer driver" 409 - "sound driver" 410 - "system driver" 411 - "versioned printer driver" 412 - Binary creation timestamp. 413 Any of the fields may be C{None} if not available. 414 415 @raise WindowsError: Raises an exception on error. 416 """ 417 418 # Get the file version info structure. 419 pBlock = win32.GetFileVersionInfo(filename) 420 pBuffer, dwLen = win32.VerQueryValue(pBlock, "\\") 421 if dwLen != ctypes.sizeof(win32.VS_FIXEDFILEINFO): 422 raise ctypes.WinError(win32.ERROR_BAD_LENGTH) 423 pVersionInfo = ctypes.cast(pBuffer, 424 ctypes.POINTER(win32.VS_FIXEDFILEINFO)) 425 VersionInfo = pVersionInfo.contents 426 if VersionInfo.dwSignature != 0xFEEF04BD: 427 raise ctypes.WinError(win32.ERROR_BAD_ARGUMENTS) 428 429 # File and product versions. 430 FileVersion = "%d.%d" % (VersionInfo.dwFileVersionMS, 431 VersionInfo.dwFileVersionLS) 432 ProductVersion = "%d.%d" % (VersionInfo.dwProductVersionMS, 433 VersionInfo.dwProductVersionLS) 434 435 # Debug build? 436 if VersionInfo.dwFileFlagsMask & win32.VS_FF_DEBUG: 437 DebugBuild = (VersionInfo.dwFileFlags & win32.VS_FF_DEBUG) != 0 438 else: 439 DebugBuild = None 440 441 # Legacy OS build? 442 LegacyBuild = (VersionInfo.dwFileOS != win32.VOS_NT_WINDOWS32) 443 444 # File type. 445 FileType = cls.__binary_types.get(VersionInfo.dwFileType) 446 if VersionInfo.dwFileType == win32.VFT_DRV: 447 FileType = cls.__driver_types.get(VersionInfo.dwFileSubtype) 448 elif VersionInfo.dwFileType == win32.VFT_FONT: 449 FileType = cls.__font_types.get(VersionInfo.dwFileSubtype) 450 451 # Timestamp, ex: "Monday, July 7, 2013 (12:20:50.126)". 452 # FIXME: how do we know the time zone? 453 FileDate = (VersionInfo.dwFileDateMS << 32) + VersionInfo.dwFileDateLS 454 if FileDate: 455 CreationTime = win32.FileTimeToSystemTime(FileDate) 456 CreationTimestamp = "%s, %s %d, %d (%d:%d:%d.%d)" % ( 457 cls.__days_of_the_week[CreationTime.wDayOfWeek], 458 cls.__months[CreationTime.wMonth], 459 CreationTime.wDay, 460 CreationTime.wYear, 461 CreationTime.wHour, 462 CreationTime.wMinute, 463 CreationTime.wSecond, 464 CreationTime.wMilliseconds, 465 ) 466 else: 467 CreationTimestamp = None 468 469 # Return the file version info. 470 return ( 471 FileVersion, 472 ProductVersion, 473 DebugBuild, 474 LegacyBuild, 475 FileType, 476 CreationTimestamp, 477 )
478 479 #------------------------------------------------------------------------------ 480 481 # Locations for dbghelp.dll. 482 # Unfortunately, Microsoft started bundling WinDbg with the 483 # platform SDK, so the install directories may vary across 484 # versions and platforms. 485 __dbghelp_locations = { 486 487 # Intel 64 bits. 488 win32.ARCH_AMD64: set([ 489 490 # WinDbg bundled with the SDK, version 8.0. 491 path.join( 492 getenv("ProgramFiles", "C:\\Program Files"), 493 "Windows Kits", 494 "8.0", 495 "Debuggers", 496 "x64", 497 "dbghelp.dll"), 498 path.join( 499 getenv("ProgramW6432", getenv("ProgramFiles", 500 "C:\\Program Files")), 501 "Windows Kits", 502 "8.0", 503 "Debuggers", 504 "x64", 505 "dbghelp.dll"), 506 507 # Old standalone versions of WinDbg. 508 path.join( 509 getenv("ProgramFiles", "C:\\Program Files"), 510 "Debugging Tools for Windows (x64)", 511 "dbghelp.dll"), 512 ]), 513 514 # Intel 32 bits. 515 win32.ARCH_I386 : set([ 516 517 # WinDbg bundled with the SDK, version 8.0. 518 path.join( 519 getenv("ProgramFiles", "C:\\Program Files"), 520 "Windows Kits", 521 "8.0", 522 "Debuggers", 523 "x86", 524 "dbghelp.dll"), 525 path.join( 526 getenv("ProgramW6432", getenv("ProgramFiles", 527 "C:\\Program Files")), 528 "Windows Kits", 529 "8.0", 530 "Debuggers", 531 "x86", 532 "dbghelp.dll"), 533 534 # Old standalone versions of WinDbg. 535 path.join( 536 getenv("ProgramFiles", "C:\\Program Files"), 537 "Debugging Tools for Windows (x86)", 538 "dbghelp.dll"), 539 540 # Version shipped with Windows. 541 path.join( 542 getenv("ProgramFiles", "C:\\Program Files"), 543 "Debugging Tools for Windows (x86)", 544 "dbghelp.dll"), 545 ]), 546 } 547 548 @classmethod
549 - def load_dbghelp(cls, pathname = None):
550 """ 551 Load the specified version of the C{dbghelp.dll} library. 552 553 This library is shipped with the Debugging Tools for Windows, and it's 554 required to load debug symbols. 555 556 Normally you don't need to call this method, as WinAppDbg already tries 557 to load the latest version automatically - but it may come in handy if 558 the Debugging Tools are installed in a non standard folder. 559 560 Example:: 561 from winappdbg import Debug 562 563 def simple_debugger( argv ): 564 565 # Instance a Debug object, passing it the event handler callback 566 debug = Debug( my_event_handler ) 567 try: 568 569 # Load a specific dbghelp.dll file 570 debug.system.load_dbghelp("C:\Some folder\dbghelp.dll") 571 572 # Start a new process for debugging 573 debug.execv( argv ) 574 575 # Wait for the debugee to finish 576 debug.loop() 577 578 # Stop the debugger 579 finally: 580 debug.stop() 581 582 @see: U{http://msdn.microsoft.com/en-us/library/ms679294(VS.85).aspx} 583 584 @type pathname: str 585 @param pathname: 586 (Optional) Full pathname to the C{dbghelp.dll} library. 587 If not provided this method will try to autodetect it. 588 589 @rtype: ctypes.WinDLL 590 @return: Loaded instance of C{dbghelp.dll}. 591 592 @raise NotImplementedError: This feature was not implemented for the 593 current architecture. 594 595 @raise WindowsError: An error occured while processing this request. 596 """ 597 598 # If an explicit pathname was not given, search for the library. 599 if not pathname: 600 601 # Under WOW64 we'll treat AMD64 as I386. 602 arch = win32.arch 603 if arch == win32.ARCH_AMD64 and win32.bits == 32: 604 arch = win32.ARCH_I386 605 606 # Check if the architecture is supported. 607 if not arch in cls.__dbghelp_locations: 608 msg = "Architecture %s is not currently supported." 609 raise NotImplementedError(msg % arch) 610 611 # Grab all versions of the library we can find. 612 found = [] 613 for pathname in cls.__dbghelp_locations[arch]: 614 if path.isfile(pathname): 615 try: 616 f_ver, p_ver = cls.get_file_version_info(pathname)[:2] 617 except WindowsError: 618 msg = "Failed to parse file version metadata for: %s" 619 warnings.warn(msg % pathname) 620 if not f_ver: 621 f_ver = p_ver 622 elif p_ver and p_ver > f_ver: 623 f_ver = p_ver 624 found.append( (f_ver, pathname) ) 625 626 # If we found any, use the newest version. 627 if found: 628 found.sort() 629 pathname = found.pop()[1] 630 631 # If we didn't find any, trust the default DLL search algorithm. 632 else: 633 pathname = "dbghelp.dll" 634 635 # Load the library. 636 dbghelp = ctypes.windll.LoadLibrary(pathname) 637 638 # Set it globally as the library to be used. 639 ctypes.windll.dbghelp = dbghelp 640 641 # Return the library. 642 return dbghelp
643 644 @staticmethod
645 - def fix_symbol_store_path(symbol_store_path = None, 646 remote = True, 647 force = False):
648 """ 649 Fix the symbol store path. Equivalent to the C{.symfix} command in 650 Microsoft WinDbg. 651 652 If the symbol store path environment variable hasn't been set, this 653 method will provide a default one. 654 655 @type symbol_store_path: str or None 656 @param symbol_store_path: (Optional) Symbol store path to set. 657 658 @type remote: bool 659 @param remote: (Optional) Defines the symbol store path to set when the 660 C{symbol_store_path} is C{None}. 661 662 If C{True} the default symbol store path is set to the Microsoft 663 symbol server. Debug symbols will be downloaded through HTTP. 664 This gives the best results but is also quite slow. 665 666 If C{False} the default symbol store path is set to the local 667 cache only. This prevents debug symbols from being downloaded and 668 is faster, but unless you've installed the debug symbols on this 669 machine or downloaded them in a previous debugging session, some 670 symbols may be missing. 671 672 If the C{symbol_store_path} argument is not C{None}, this argument 673 is ignored entirely. 674 675 @type force: bool 676 @param force: (Optional) If C{True} the new symbol store path is set 677 always. If C{False} the new symbol store path is only set if 678 missing. 679 680 This allows you to call this method preventively to ensure the 681 symbol server is always set up correctly when running your script, 682 but without messing up whatever configuration the user has. 683 684 Example:: 685 from winappdbg import Debug, System 686 687 def simple_debugger( argv ): 688 689 # Instance a Debug object 690 debug = Debug( MyEventHandler() ) 691 try: 692 693 # Make sure the remote symbol store is set 694 System.fix_symbol_store_path(remote = True, 695 force = False) 696 697 # Start a new process for debugging 698 debug.execv( argv ) 699 700 # Wait for the debugee to finish 701 debug.loop() 702 703 # Stop the debugger 704 finally: 705 debug.stop() 706 707 @rtype: str or None 708 @return: The previously set symbol store path if any, 709 otherwise returns C{None}. 710 """ 711 try: 712 if symbol_store_path is None: 713 local_path = "C:\\SYMBOLS" 714 if not path.isdir(local_path): 715 local_path = "C:\\Windows\\Symbols" 716 if not path.isdir(local_path): 717 local_path = path.abspath(".") 718 if remote: 719 symbol_store_path = ( 720 "cache*;SRV*" 721 + local_path + 722 "*" 723 "http://msdl.microsoft.com/download/symbols" 724 ) 725 else: 726 symbol_store_path = "cache*;SRV*" + local_path 727 previous = os.environ.get("_NT_SYMBOL_PATH", None) 728 if not previous or force: 729 os.environ["_NT_SYMBOL_PATH"] = symbol_store_path 730 return previous 731 except Exception, e: 732 warnings.warn("Cannot fix symbol path, reason: %s" % str(e), 733 RuntimeWarning)
734 735 #------------------------------------------------------------------------------ 736 737 @staticmethod
738 - def set_kill_on_exit_mode(bKillOnExit = False):
739 """ 740 Defines the behavior of the debugged processes when the debugging 741 thread dies. This method only affects the calling thread. 742 743 Works on the following platforms: 744 745 - Microsoft Windows XP and above. 746 - Wine (Windows Emulator). 747 748 Fails on the following platforms: 749 750 - Microsoft Windows 2000 and below. 751 - ReactOS. 752 753 @type bKillOnExit: bool 754 @param bKillOnExit: C{True} to automatically kill processes when the 755 debugger thread dies. C{False} to automatically detach from 756 processes when the debugger thread dies. 757 758 @rtype: bool 759 @return: C{True} on success, C{False} on error. 760 761 @note: 762 This call will fail if a debug port was not created. That is, if 763 the debugger isn't attached to at least one process. For more info 764 see: U{http://msdn.microsoft.com/en-us/library/ms679307.aspx} 765 """ 766 try: 767 # won't work before calling CreateProcess or DebugActiveProcess 768 win32.DebugSetProcessKillOnExit(bKillOnExit) 769 except (AttributeError, WindowsError): 770 return False 771 return True
772 773 @staticmethod
774 - def read_msr(address):
775 """ 776 Read the contents of the specified MSR (Machine Specific Register). 777 778 @type address: int 779 @param address: MSR to read. 780 781 @rtype: int 782 @return: Value of the specified MSR. 783 784 @raise WindowsError: 785 Raises an exception on error. 786 787 @raise NotImplementedError: 788 Current architecture is not C{i386} or C{amd64}. 789 790 @warning: 791 It could potentially brick your machine. 792 It works on my machine, but your mileage may vary. 793 """ 794 if win32.arch not in (win32.ARCH_I386, win32.ARCH_AMD64): 795 raise NotImplementedError( 796 "MSR reading is only supported on i386 or amd64 processors.") 797 msr = win32.SYSDBG_MSR() 798 msr.Address = address 799 msr.Data = 0 800 win32.NtSystemDebugControl(win32.SysDbgReadMsr, 801 InputBuffer = msr, 802 OutputBuffer = msr) 803 return msr.Data
804 805 @staticmethod
806 - def write_msr(address, value):
807 """ 808 Set the contents of the specified MSR (Machine Specific Register). 809 810 @type address: int 811 @param address: MSR to write. 812 813 @type value: int 814 @param value: Contents to write on the MSR. 815 816 @raise WindowsError: 817 Raises an exception on error. 818 819 @raise NotImplementedError: 820 Current architecture is not C{i386} or C{amd64}. 821 822 @warning: 823 It could potentially brick your machine. 824 It works on my machine, but your mileage may vary. 825 """ 826 if win32.arch not in (win32.ARCH_I386, win32.ARCH_AMD64): 827 raise NotImplementedError( 828 "MSR writing is only supported on i386 or amd64 processors.") 829 msr = win32.SYSDBG_MSR() 830 msr.Address = address 831 msr.Data = value 832 win32.NtSystemDebugControl(win32.SysDbgWriteMsr, InputBuffer = msr)
833 834 @classmethod
836 """ 837 When tracing, call this on every single step event 838 for step on branch mode. 839 840 @raise WindowsError: 841 Raises C{ERROR_DEBUGGER_INACTIVE} if the debugger is not attached 842 to least one process. 843 844 @raise NotImplementedError: 845 Current architecture is not C{i386} or C{amd64}. 846 847 @warning: 848 This method uses the processor's machine specific registers (MSR). 849 It could potentially brick your machine. 850 It works on my machine, but your mileage may vary. 851 852 @note: 853 It doesn't seem to work in VMWare or VirtualBox machines. 854 Maybe it fails in other virtualization/emulation environments, 855 no extensive testing was made so far. 856 """ 857 cls.write_msr(DebugRegister.DebugCtlMSR, 858 DebugRegister.BranchTrapFlag | DebugRegister.LastBranchRecord)
859 860 @classmethod
861 - def get_last_branch_location(cls):
862 """ 863 Returns the source and destination addresses of the last taken branch. 864 865 @rtype: tuple( int, int ) 866 @return: Source and destination addresses of the last taken branch. 867 868 @raise WindowsError: 869 Raises an exception on error. 870 871 @raise NotImplementedError: 872 Current architecture is not C{i386} or C{amd64}. 873 874 @warning: 875 This method uses the processor's machine specific registers (MSR). 876 It could potentially brick your machine. 877 It works on my machine, but your mileage may vary. 878 879 @note: 880 It doesn't seem to work in VMWare or VirtualBox machines. 881 Maybe it fails in other virtualization/emulation environments, 882 no extensive testing was made so far. 883 """ 884 LastBranchFromIP = cls.read_msr(DebugRegister.LastBranchFromIP) 885 LastBranchToIP = cls.read_msr(DebugRegister.LastBranchToIP) 886 return ( LastBranchFromIP, LastBranchToIP )
887 888 #------------------------------------------------------------------------------ 889 890 @classmethod
891 - def get_postmortem_debugger(cls, bits = None):
892 """ 893 Returns the postmortem debugging settings from the Registry. 894 895 @see: L{set_postmortem_debugger} 896 897 @type bits: int 898 @param bits: Set to C{32} for the 32 bits debugger, or C{64} for the 899 64 bits debugger. Set to {None} for the default (L{System.bits}. 900 901 @rtype: tuple( str, bool, int ) 902 @return: A tuple containing the command line string to the postmortem 903 debugger, a boolean specifying if user interaction is allowed 904 before attaching, and an integer specifying a user defined hotkey. 905 Any member of the tuple may be C{None}. 906 See L{set_postmortem_debugger} for more details. 907 908 @raise WindowsError: 909 Raises an exception on error. 910 """ 911 if bits is None: 912 bits = cls.bits 913 elif bits not in (32, 64): 914 raise NotImplementedError("Unknown architecture (%r bits)" % bits) 915 916 if bits == 32 and cls.bits == 64: 917 keyname = 'HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug' 918 else: 919 keyname = 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug' 920 921 key = cls.registry[keyname] 922 923 debugger = key.get('Debugger') 924 auto = key.get('Auto') 925 hotkey = key.get('UserDebuggerHotkey') 926 927 if auto is not None: 928 auto = bool(auto) 929 930 return (debugger, auto, hotkey)
931 932 @classmethod
933 - def get_postmortem_exclusion_list(cls, bits = None):
934 """ 935 Returns the exclusion list for the postmortem debugger. 936 937 @see: L{get_postmortem_debugger} 938 939 @type bits: int 940 @param bits: Set to C{32} for the 32 bits debugger, or C{64} for the 941 64 bits debugger. Set to {None} for the default (L{System.bits}). 942 943 @rtype: list( str ) 944 @return: List of excluded application filenames. 945 946 @raise WindowsError: 947 Raises an exception on error. 948 """ 949 if bits is None: 950 bits = cls.bits 951 elif bits not in (32, 64): 952 raise NotImplementedError("Unknown architecture (%r bits)" % bits) 953 954 if bits == 32 and cls.bits == 64: 955 keyname = 'HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList' 956 else: 957 keyname = 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList' 958 959 try: 960 key = cls.registry[keyname] 961 except KeyError: 962 return [] 963 964 return [name for (name, enabled) in key.items() if enabled]
965 966 @classmethod
967 - def set_postmortem_debugger(cls, cmdline, 968 auto = None, hotkey = None, bits = None):
969 """ 970 Sets the postmortem debugging settings in the Registry. 971 972 @warning: This method requires administrative rights. 973 974 @see: L{get_postmortem_debugger} 975 976 @type cmdline: str 977 @param cmdline: Command line to the new postmortem debugger. 978 When the debugger is invoked, the first "%ld" is replaced with the 979 process ID and the second "%ld" is replaced with the event handle. 980 Don't forget to enclose the program filename in double quotes if 981 the path contains spaces. 982 983 @type auto: bool 984 @param auto: Set to C{True} if no user interaction is allowed, C{False} 985 to prompt a confirmation dialog before attaching. 986 Use C{None} to leave this value unchanged. 987 988 @type hotkey: int 989 @param hotkey: Virtual key scan code for the user defined hotkey. 990 Use C{0} to disable the hotkey. 991 Use C{None} to leave this value unchanged. 992 993 @type bits: int 994 @param bits: Set to C{32} for the 32 bits debugger, or C{64} for the 995 64 bits debugger. Set to {None} for the default (L{System.bits}). 996 997 @rtype: tuple( str, bool, int ) 998 @return: Previously defined command line and auto flag. 999 1000 @raise WindowsError: 1001 Raises an exception on error. 1002 """ 1003 if bits is None: 1004 bits = cls.bits 1005 elif bits not in (32, 64): 1006 raise NotImplementedError("Unknown architecture (%r bits)" % bits) 1007 1008 if bits == 32 and cls.bits == 64: 1009 keyname = 'HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug' 1010 else: 1011 keyname = 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug' 1012 1013 key = cls.registry[keyname] 1014 1015 if cmdline is not None: 1016 key['Debugger'] = cmdline 1017 if auto is not None: 1018 key['Auto'] = int(bool(auto)) 1019 if hotkey is not None: 1020 key['UserDebuggerHotkey'] = int(hotkey)
1021 1022 @classmethod
1023 - def add_to_postmortem_exclusion_list(cls, pathname, bits = None):
1024 """ 1025 Adds the given filename to the exclusion list for postmortem debugging. 1026 1027 @warning: This method requires administrative rights. 1028 1029 @see: L{get_postmortem_exclusion_list} 1030 1031 @type pathname: str 1032 @param pathname: 1033 Application pathname to exclude from postmortem debugging. 1034 1035 @type bits: int 1036 @param bits: Set to C{32} for the 32 bits debugger, or C{64} for the 1037 64 bits debugger. Set to {None} for the default (L{System.bits}). 1038 1039 @raise WindowsError: 1040 Raises an exception on error. 1041 """ 1042 if bits is None: 1043 bits = cls.bits 1044 elif bits not in (32, 64): 1045 raise NotImplementedError("Unknown architecture (%r bits)" % bits) 1046 1047 if bits == 32 and cls.bits == 64: 1048 keyname = 'HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList' 1049 else: 1050 keyname = 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList' 1051 1052 try: 1053 key = cls.registry[keyname] 1054 except KeyError: 1055 key = cls.registry.create(keyname) 1056 1057 key[pathname] = 1
1058 1059 @classmethod
1060 - def remove_from_postmortem_exclusion_list(cls, pathname, bits = None):
1061 """ 1062 Removes the given filename to the exclusion list for postmortem 1063 debugging from the Registry. 1064 1065 @warning: This method requires administrative rights. 1066 1067 @warning: Don't ever delete entries you haven't created yourself! 1068 Some entries are set by default for your version of Windows. 1069 Deleting them might deadlock your system under some circumstances. 1070 1071 For more details see: 1072 U{http://msdn.microsoft.com/en-us/library/bb204634(v=vs.85).aspx} 1073 1074 @see: L{get_postmortem_exclusion_list} 1075 1076 @type pathname: str 1077 @param pathname: Application pathname to remove from the postmortem 1078 debugging exclusion list. 1079 1080 @type bits: int 1081 @param bits: Set to C{32} for the 32 bits debugger, or C{64} for the 1082 64 bits debugger. Set to {None} for the default (L{System.bits}). 1083 1084 @raise WindowsError: 1085 Raises an exception on error. 1086 """ 1087 if bits is None: 1088 bits = cls.bits 1089 elif bits not in (32, 64): 1090 raise NotImplementedError("Unknown architecture (%r bits)" % bits) 1091 1092 if bits == 32 and cls.bits == 64: 1093 keyname = 'HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList' 1094 else: 1095 keyname = 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList' 1096 1097 try: 1098 key = cls.registry[keyname] 1099 except KeyError: 1100 return 1101 1102 try: 1103 del key[pathname] 1104 except KeyError: 1105 return
1106 1107 #------------------------------------------------------------------------------ 1108 1109 @staticmethod
1110 - def get_services():
1111 """ 1112 Retrieve a list of all system services. 1113 1114 @see: L{get_active_services}, 1115 L{start_service}, L{stop_service}, 1116 L{pause_service}, L{resume_service} 1117 1118 @rtype: list( L{win32.ServiceStatusProcessEntry} ) 1119 @return: List of service status descriptors. 1120 """ 1121 with win32.OpenSCManager( 1122 dwDesiredAccess = win32.SC_MANAGER_ENUMERATE_SERVICE 1123 ) as hSCManager: 1124 try: 1125 return win32.EnumServicesStatusEx(hSCManager) 1126 except AttributeError: 1127 return win32.EnumServicesStatus(hSCManager)
1128 1129 @staticmethod
1130 - def get_active_services():
1131 """ 1132 Retrieve a list of all active system services. 1133 1134 @see: L{get_services}, 1135 L{start_service}, L{stop_service}, 1136 L{pause_service}, L{resume_service} 1137 1138 @rtype: list( L{win32.ServiceStatusProcessEntry} ) 1139 @return: List of service status descriptors. 1140 """ 1141 with win32.OpenSCManager( 1142 dwDesiredAccess = win32.SC_MANAGER_ENUMERATE_SERVICE 1143 ) as hSCManager: 1144 return [ entry for entry in win32.EnumServicesStatusEx(hSCManager, 1145 dwServiceType = win32.SERVICE_WIN32, 1146 dwServiceState = win32.SERVICE_ACTIVE) \ 1147 if entry.ProcessId ]
1148 1149 @staticmethod
1150 - def get_service(name):
1151 """ 1152 Get the service descriptor for the given service name. 1153 1154 @see: L{start_service}, L{stop_service}, 1155 L{pause_service}, L{resume_service} 1156 1157 @type name: str 1158 @param name: Service unique name. You can get this value from the 1159 C{ServiceName} member of the service descriptors returned by 1160 L{get_services} or L{get_active_services}. 1161 1162 @rtype: L{win32.ServiceStatusProcess} 1163 @return: Service status descriptor. 1164 """ 1165 with win32.OpenSCManager( 1166 dwDesiredAccess = win32.SC_MANAGER_ENUMERATE_SERVICE 1167 ) as hSCManager: 1168 with win32.OpenService(hSCManager, name, 1169 dwDesiredAccess = win32.SERVICE_QUERY_STATUS 1170 ) as hService: 1171 try: 1172 return win32.QueryServiceStatusEx(hService) 1173 except AttributeError: 1174 return win32.QueryServiceStatus(hService)
1175 1176 @staticmethod
1177 - def get_service_display_name(name):
1178 """ 1179 Get the service display name for the given service name. 1180 1181 @see: L{get_service} 1182 1183 @type name: str 1184 @param name: Service unique name. You can get this value from the 1185 C{ServiceName} member of the service descriptors returned by 1186 L{get_services} or L{get_active_services}. 1187 1188 @rtype: str 1189 @return: Service display name. 1190 """ 1191 with win32.OpenSCManager( 1192 dwDesiredAccess = win32.SC_MANAGER_ENUMERATE_SERVICE 1193 ) as hSCManager: 1194 return win32.GetServiceDisplayName(hSCManager, name)
1195 1196 @staticmethod
1197 - def get_service_from_display_name(displayName):
1198 """ 1199 Get the service unique name given its display name. 1200 1201 @see: L{get_service} 1202 1203 @type displayName: str 1204 @param displayName: Service display name. You can get this value from 1205 the C{DisplayName} member of the service descriptors returned by 1206 L{get_services} or L{get_active_services}. 1207 1208 @rtype: str 1209 @return: Service unique name. 1210 """ 1211 with win32.OpenSCManager( 1212 dwDesiredAccess = win32.SC_MANAGER_ENUMERATE_SERVICE 1213 ) as hSCManager: 1214 return win32.GetServiceKeyName(hSCManager, displayName)
1215 1216 @staticmethod
1217 - def start_service(name, argv = None):
1218 """ 1219 Start the service given by name. 1220 1221 @warn: This method requires UAC elevation in Windows Vista and above. 1222 1223 @see: L{stop_service}, L{pause_service}, L{resume_service} 1224 1225 @type name: str 1226 @param name: Service unique name. You can get this value from the 1227 C{ServiceName} member of the service descriptors returned by 1228 L{get_services} or L{get_active_services}. 1229 """ 1230 with win32.OpenSCManager( 1231 dwDesiredAccess = win32.SC_MANAGER_CONNECT 1232 ) as hSCManager: 1233 with win32.OpenService(hSCManager, name, 1234 dwDesiredAccess = win32.SERVICE_START 1235 ) as hService: 1236 win32.StartService(hService)
1237 1238 @staticmethod
1239 - def stop_service(name):
1240 """ 1241 Stop the service given by name. 1242 1243 @warn: This method requires UAC elevation in Windows Vista and above. 1244 1245 @see: L{get_services}, L{get_active_services}, 1246 L{start_service}, L{pause_service}, L{resume_service} 1247 """ 1248 with win32.OpenSCManager( 1249 dwDesiredAccess = win32.SC_MANAGER_CONNECT 1250 ) as hSCManager: 1251 with win32.OpenService(hSCManager, name, 1252 dwDesiredAccess = win32.SERVICE_STOP 1253 ) as hService: 1254 win32.ControlService(hService, win32.SERVICE_CONTROL_STOP)
1255 1256 @staticmethod
1257 - def pause_service(name):
1258 """ 1259 Pause the service given by name. 1260 1261 @warn: This method requires UAC elevation in Windows Vista and above. 1262 1263 @note: Not all services support this. 1264 1265 @see: L{get_services}, L{get_active_services}, 1266 L{start_service}, L{stop_service}, L{resume_service} 1267 """ 1268 with win32.OpenSCManager( 1269 dwDesiredAccess = win32.SC_MANAGER_CONNECT 1270 ) as hSCManager: 1271 with win32.OpenService(hSCManager, name, 1272 dwDesiredAccess = win32.SERVICE_PAUSE_CONTINUE 1273 ) as hService: 1274 win32.ControlService(hService, win32.SERVICE_CONTROL_PAUSE)
1275 1276 @staticmethod
1277 - def resume_service(name):
1278 """ 1279 Resume the service given by name. 1280 1281 @warn: This method requires UAC elevation in Windows Vista and above. 1282 1283 @note: Not all services support this. 1284 1285 @see: L{get_services}, L{get_active_services}, 1286 L{start_service}, L{stop_service}, L{pause_service} 1287 """ 1288 with win32.OpenSCManager( 1289 dwDesiredAccess = win32.SC_MANAGER_CONNECT 1290 ) as hSCManager: 1291 with win32.OpenService(hSCManager, name, 1292 dwDesiredAccess = win32.SERVICE_PAUSE_CONTINUE 1293 ) as hService: 1294 win32.ControlService(hService, win32.SERVICE_CONTROL_CONTINUE)
1295 1296 # TODO: create_service, delete_service 1297