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""" 32Process instrumentation. 33 34@group Instrumentation: 35 Process 36""" 37 38from __future__ import with_statement 39 40# FIXME 41# I've been told the host process for the latest versions of VMWare 42# can't be instrumented, because they try to stop code injection into the VMs. 43# The solution appears to be to run the debugger from a user account that 44# belongs to the VMware group. I haven't confirmed this yet. 45 46__revision__ = "$Id$" 47 48__all__ = ['Process'] 49 50import sys 51from winappdbg import win32 52from winappdbg import compat 53from winappdbg.textio import HexDump, HexInput 54from winappdbg.util import Regenerator, PathOperations, MemoryAddresses 55from winappdbg.module import Module, _ModuleContainer 56from winappdbg.thread import Thread, _ThreadContainer 57from winappdbg.window import Window 58from winappdbg.search import Search, \ 59 Pattern, BytePattern, TextPattern, RegExpPattern, HexPattern 60from winappdbg.disasm import Disassembler 61 62import re 63import os 64import os.path 65import ctypes 66import struct 67import warnings 68import traceback 69 70# delayed import 71System = None 72 73#============================================================================== 74 75# TODO 76# * Remote GetLastError() 77# * The memory operation methods do not take into account that code breakpoints 78# change the memory. This object should talk to BreakpointContainer to 79# retrieve the original memory contents where code breakpoints are enabled. 80# * A memory cache could be implemented here. 81 82class Process (_ThreadContainer, _ModuleContainer): 83 """ 84 Interface to a process. Contains threads and modules snapshots. 85 86 @group Properties: 87 get_pid, is_alive, is_debugged, is_wow64, get_arch, get_bits, 88 get_filename, get_exit_code, 89 get_start_time, get_exit_time, get_running_time, 90 get_services, get_dep_policy, get_peb, get_peb_address, 91 get_entry_point, get_main_module, get_image_base, get_image_name, 92 get_command_line, get_environment, 93 get_command_line_block, 94 get_environment_block, get_environment_variables, 95 get_handle, open_handle, close_handle 96 97 @group Instrumentation: 98 kill, wait, suspend, resume, inject_code, inject_dll, clean_exit 99 100 @group Disassembly: 101 disassemble, disassemble_around, disassemble_around_pc, 102 disassemble_string, disassemble_instruction, disassemble_current 103 104 @group Debugging: 105 flush_instruction_cache, debug_break, peek_pointers_in_data 106 107 @group Memory mapping: 108 take_memory_snapshot, generate_memory_snapshot, iter_memory_snapshot, 109 restore_memory_snapshot, get_memory_map, get_mapped_filenames, 110 generate_memory_map, iter_memory_map, 111 is_pointer, is_address_valid, is_address_free, is_address_reserved, 112 is_address_commited, is_address_guard, is_address_readable, 113 is_address_writeable, is_address_copy_on_write, is_address_executable, 114 is_address_executable_and_writeable, 115 is_buffer, 116 is_buffer_readable, is_buffer_writeable, is_buffer_executable, 117 is_buffer_executable_and_writeable, is_buffer_copy_on_write 118 119 @group Memory allocation: 120 malloc, free, mprotect, mquery 121 122 @group Memory read: 123 read, read_char, read_int, read_uint, read_float, read_double, 124 read_dword, read_qword, read_pointer, read_string, read_structure, 125 peek, peek_char, peek_int, peek_uint, peek_float, peek_double, 126 peek_dword, peek_qword, peek_pointer, peek_string 127 128 @group Memory write: 129 write, write_char, write_int, write_uint, write_float, write_double, 130 write_dword, write_qword, write_pointer, 131 poke, poke_char, poke_int, poke_uint, poke_float, poke_double, 132 poke_dword, poke_qword, poke_pointer 133 134 @group Memory search: 135 search, search_bytes, search_hexa, search_text, search_regexp, strings 136 137 @group Processes snapshot: 138 scan, clear, __contains__, __iter__, __len__ 139 140 @group Deprecated: 141 get_environment_data, parse_environment_data 142 143 @type dwProcessId: int 144 @ivar dwProcessId: Global process ID. Use L{get_pid} instead. 145 146 @type hProcess: L{ProcessHandle} 147 @ivar hProcess: Handle to the process. Use L{get_handle} instead. 148 149 @type fileName: str 150 @ivar fileName: Filename of the main module. Use L{get_filename} instead. 151 """ 152 153 def __init__(self, dwProcessId, hProcess = None, fileName = None): 154 """ 155 @type dwProcessId: int 156 @param dwProcessId: Global process ID. 157 158 @type hProcess: L{ProcessHandle} 159 @param hProcess: Handle to the process. 160 161 @type fileName: str 162 @param fileName: (Optional) Filename of the main module. 163 """ 164 _ThreadContainer.__init__(self) 165 _ModuleContainer.__init__(self) 166 167 self.dwProcessId = dwProcessId 168 self.hProcess = hProcess 169 self.fileName = fileName 170 171 def get_pid(self): 172 """ 173 @rtype: int 174 @return: Process global ID. 175 """ 176 return self.dwProcessId 177 178 def get_filename(self): 179 """ 180 @rtype: str 181 @return: Filename of the main module of the process. 182 """ 183 if not self.fileName: 184 self.fileName = self.get_image_name() 185 return self.fileName 186 187 def open_handle(self, dwDesiredAccess = win32.PROCESS_ALL_ACCESS): 188 """ 189 Opens a new handle to the process. 190 191 The new handle is stored in the L{hProcess} property. 192 193 @warn: Normally you should call L{get_handle} instead, since it's much 194 "smarter" and tries to reuse handles and merge access rights. 195 196 @type dwDesiredAccess: int 197 @param dwDesiredAccess: Desired access rights. 198 Defaults to L{win32.PROCESS_ALL_ACCESS}. 199 See: U{http://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx} 200 201 @raise WindowsError: It's not possible to open a handle to the process 202 with the requested access rights. This tipically happens because 203 the target process is a system process and the debugger is not 204 runnning with administrative rights. 205 """ 206 hProcess = win32.OpenProcess(dwDesiredAccess, win32.FALSE, self.dwProcessId) 207 208 try: 209 self.close_handle() 210 except Exception: 211 warnings.warn( 212 "Failed to close process handle: %s" % traceback.format_exc()) 213 214 self.hProcess = hProcess 215 216 def close_handle(self): 217 """ 218 Closes the handle to the process. 219 220 @note: Normally you don't need to call this method. All handles 221 created by I{WinAppDbg} are automatically closed when the garbage 222 collector claims them. So unless you've been tinkering with it, 223 setting L{hProcess} to C{None} should be enough. 224 """ 225 try: 226 if hasattr(self.hProcess, 'close'): 227 self.hProcess.close() 228 elif self.hProcess not in (None, win32.INVALID_HANDLE_VALUE): 229 win32.CloseHandle(self.hProcess) 230 finally: 231 self.hProcess = None 232 233 def get_handle(self, dwDesiredAccess = win32.PROCESS_ALL_ACCESS): 234 """ 235 Returns a handle to the process with I{at least} the access rights 236 requested. 237 238 @note: 239 If a handle was previously opened and has the required access 240 rights, it's reused. If not, a new handle is opened with the 241 combination of the old and new access rights. 242 243 @type dwDesiredAccess: int 244 @param dwDesiredAccess: Desired access rights. 245 Defaults to L{win32.PROCESS_ALL_ACCESS}. 246 See: U{http://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx} 247 248 @rtype: L{ProcessHandle} 249 @return: Handle to the process. 250 251 @raise WindowsError: It's not possible to open a handle to the process 252 with the requested access rights. This tipically happens because 253 the target process is a system process and the debugger is not 254 runnning with administrative rights. 255 """ 256 if self.hProcess in (None, win32.INVALID_HANDLE_VALUE): 257 self.open_handle(dwDesiredAccess) 258 else: 259 dwAccess = self.hProcess.dwAccess 260 if (dwAccess | dwDesiredAccess) != dwAccess: 261 self.open_handle(dwAccess | dwDesiredAccess) 262 return self.hProcess 263 264#------------------------------------------------------------------------------ 265 266 # Not really sure if it's a good idea... 267## def __eq__(self, aProcess): 268## """ 269## Compare two Process objects. The comparison is made using the IDs. 270## 271## @warning: 272## If you have two Process instances with different handles the 273## equality operator still returns C{True}, so be careful! 274## 275## @type aProcess: L{Process} 276## @param aProcess: Another Process object. 277## 278## @rtype: bool 279## @return: C{True} if the two process IDs are equal, 280## C{False} otherwise. 281## """ 282## return isinstance(aProcess, Process) and \ 283## self.get_pid() == aProcess.get_pid() 284 285 def __contains__(self, anObject): 286 """ 287 The same as: C{self.has_thread(anObject) or self.has_module(anObject)} 288 289 @type anObject: L{Thread}, L{Module} or int 290 @param anObject: Object to look for. 291 Can be a Thread, Module, thread global ID or module base address. 292 293 @rtype: bool 294 @return: C{True} if the requested object was found in the snapshot. 295 """ 296 return _ThreadContainer.__contains__(self, anObject) or \ 297 _ModuleContainer.__contains__(self, anObject) 298 299 def __len__(self): 300 """ 301 @see: L{get_thread_count}, L{get_module_count} 302 @rtype: int 303 @return: Count of L{Thread} and L{Module} objects in this snapshot. 304 """ 305 return _ThreadContainer.__len__(self) + \ 306 _ModuleContainer.__len__(self) 307 308 class __ThreadsAndModulesIterator (object): 309 """ 310 Iterator object for L{Process} objects. 311 Iterates through L{Thread} objects first, L{Module} objects next. 312 """ 313 314 def __init__(self, container): 315 """ 316 @type container: L{Process} 317 @param container: L{Thread} and L{Module} container. 318 """ 319 self.__container = container 320 self.__iterator = None 321 self.__state = 0 322 323 def __iter__(self): 324 'x.__iter__() <==> iter(x)' 325 return self 326 327 def next(self): 328 'x.next() -> the next value, or raise StopIteration' 329 if self.__state == 0: 330 self.__iterator = self.__container.iter_threads() 331 self.__state = 1 332 if self.__state == 1: 333 try: 334 return self.__iterator.next() 335 except StopIteration: 336 self.__iterator = self.__container.iter_modules() 337 self.__state = 2 338 if self.__state == 2: 339 try: 340 return self.__iterator.next() 341 except StopIteration: 342 self.__iterator = None 343 self.__state = 3 344 raise StopIteration 345 346 def __iter__(self): 347 """ 348 @see: L{iter_threads}, L{iter_modules} 349 @rtype: iterator 350 @return: Iterator of L{Thread} and L{Module} objects in this snapshot. 351 All threads are iterated first, then all modules. 352 """ 353 return self.__ThreadsAndModulesIterator(self) 354 355#------------------------------------------------------------------------------ 356 357 def wait(self, dwTimeout = None): 358 """ 359 Waits for the process to finish executing. 360 361 @raise WindowsError: On error an exception is raised. 362 """ 363 self.get_handle(win32.SYNCHRONIZE).wait(dwTimeout) 364 365 def kill(self, dwExitCode = 0): 366 """ 367 Terminates the execution of the process. 368 369 @raise WindowsError: On error an exception is raised. 370 """ 371 hProcess = self.get_handle(win32.PROCESS_TERMINATE) 372 win32.TerminateProcess(hProcess, dwExitCode) 373 374 def suspend(self): 375 """ 376 Suspends execution on all threads of the process. 377 378 @raise WindowsError: On error an exception is raised. 379 """ 380 self.scan_threads() # force refresh the snapshot 381 suspended = list() 382 try: 383 for aThread in self.iter_threads(): 384 aThread.suspend() 385 suspended.append(aThread) 386 except Exception: 387 for aThread in suspended: 388 try: 389 aThread.resume() 390 except Exception: 391 pass 392 raise 393 394 def resume(self): 395 """ 396 Resumes execution on all threads of the process. 397 398 @raise WindowsError: On error an exception is raised. 399 """ 400 if self.get_thread_count() == 0: 401 self.scan_threads() # only refresh the snapshot if empty 402 resumed = list() 403 try: 404 for aThread in self.iter_threads(): 405 aThread.resume() 406 resumed.append(aThread) 407 except Exception: 408 for aThread in resumed: 409 try: 410 aThread.suspend() 411 except Exception: 412 pass 413 raise 414 415 def is_debugged(self): 416 """ 417 Tries to determine if the process is being debugged by another process. 418 It may detect other debuggers besides WinAppDbg. 419 420 @rtype: bool 421 @return: C{True} if the process has a debugger attached. 422 423 @warning: 424 May return inaccurate results when some anti-debug techniques are 425 used by the target process. 426 427 @note: To know if a process currently being debugged by a L{Debug} 428 object, call L{Debug.is_debugee} instead. 429 """ 430 # FIXME the MSDN docs don't say what access rights are needed here! 431 hProcess = self.get_handle(win32.PROCESS_QUERY_INFORMATION) 432 return win32.CheckRemoteDebuggerPresent(hProcess) 433 434 def is_alive(self): 435 """ 436 @rtype: bool 437 @return: C{True} if the process is currently running. 438 """ 439 try: 440 self.wait(0) 441 except WindowsError: 442 e = sys.exc_info()[1] 443 return e.winerror == win32.WAIT_TIMEOUT 444 return False 445 446 def get_exit_code(self): 447 """ 448 @rtype: int 449 @return: Process exit code, or C{STILL_ACTIVE} if it's still alive. 450 451 @warning: If a process returns C{STILL_ACTIVE} as it's exit code, 452 you may not be able to determine if it's active or not with this 453 method. Use L{is_alive} to check if the process is still active. 454 Alternatively you can call L{get_handle} to get the handle object 455 and then L{ProcessHandle.wait} on it to wait until the process 456 finishes running. 457 """ 458 if win32.PROCESS_ALL_ACCESS == win32.PROCESS_ALL_ACCESS_VISTA: 459 dwAccess = win32.PROCESS_QUERY_LIMITED_INFORMATION 460 else: 461 dwAccess = win32.PROCESS_QUERY_INFORMATION 462 return win32.GetExitCodeProcess( self.get_handle(dwAccess) ) 463 464#------------------------------------------------------------------------------ 465 466 def scan(self): 467 """ 468 Populates the snapshot of threads and modules. 469 """ 470 self.scan_threads() 471 self.scan_modules() 472 473 def clear(self): 474 """ 475 Clears the snapshot of threads and modules. 476 """ 477 try: 478 try: 479 self.clear_threads() 480 finally: 481 self.clear_modules() 482 finally: 483 self.close_handle() 484 485#------------------------------------------------------------------------------ 486 487 # Regular expression to find hexadecimal values of any size. 488 __hexa_parameter = re.compile('0x[0-9A-Fa-f]+') 489 490 def __fixup_labels(self, disasm): 491 """ 492 Private method used when disassembling from process memory. 493 494 It has no return value because the list is modified in place. On return 495 all raw memory addresses are replaced by labels when possible. 496 497 @type disasm: list of tuple(int, int, str, str) 498 @param disasm: Output of one of the dissassembly functions. 499 """ 500 for index in compat.xrange(len(disasm)): 501 (address, size, text, dump) = disasm[index] 502 m = self.__hexa_parameter.search(text) 503 while m: 504 s, e = m.span() 505 value = text[s:e] 506 try: 507 label = self.get_label_at_address( int(value, 0x10) ) 508 except Exception: 509 label = None 510 if label: 511 text = text[:s] + label + text[e:] 512 e = s + len(value) 513 m = self.__hexa_parameter.search(text, e) 514 disasm[index] = (address, size, text, dump) 515 516 def disassemble_string(self, lpAddress, code): 517 """ 518 Disassemble instructions from a block of binary code. 519 520 @type lpAddress: int 521 @param lpAddress: Memory address where the code was read from. 522 523 @type code: str 524 @param code: Binary code to disassemble. 525 526 @rtype: list of tuple( long, int, str, str ) 527 @return: List of tuples. Each tuple represents an assembly instruction 528 and contains: 529 - Memory address of instruction. 530 - Size of instruction in bytes. 531 - Disassembly line of instruction. 532 - Hexadecimal dump of instruction. 533 534 @raise NotImplementedError: 535 No compatible disassembler was found for the current platform. 536 """ 537 try: 538 disasm = self.__disasm 539 except AttributeError: 540 disasm = self.__disasm = Disassembler( self.get_arch() ) 541 return disasm.decode(lpAddress, code) 542 543 def disassemble(self, lpAddress, dwSize): 544 """ 545 Disassemble instructions from the address space of the process. 546 547 @type lpAddress: int 548 @param lpAddress: Memory address where to read the code from. 549 550 @type dwSize: int 551 @param dwSize: Size of binary code to disassemble. 552 553 @rtype: list of tuple( long, int, str, str ) 554 @return: List of tuples. Each tuple represents an assembly instruction 555 and contains: 556 - Memory address of instruction. 557 - Size of instruction in bytes. 558 - Disassembly line of instruction. 559 - Hexadecimal dump of instruction. 560 """ 561 data = self.read(lpAddress, dwSize) 562 disasm = self.disassemble_string(lpAddress, data) 563 self.__fixup_labels(disasm) 564 return disasm 565 566 # FIXME 567 # This algorithm really bad, I've got to write a better one :P 568 def disassemble_around(self, lpAddress, dwSize = 64): 569 """ 570 Disassemble around the given address. 571 572 @type lpAddress: int 573 @param lpAddress: Memory address where to read the code from. 574 575 @type dwSize: int 576 @param dwSize: Delta offset. 577 Code will be read from lpAddress - dwSize to lpAddress + dwSize. 578 579 @rtype: list of tuple( long, int, str, str ) 580 @return: List of tuples. Each tuple represents an assembly instruction 581 and contains: 582 - Memory address of instruction. 583 - Size of instruction in bytes. 584 - Disassembly line of instruction. 585 - Hexadecimal dump of instruction. 586 """ 587 dwDelta = int(float(dwSize) / 2.0) 588 addr_1 = lpAddress - dwDelta 589 addr_2 = lpAddress 590 size_1 = dwDelta 591 size_2 = dwSize - dwDelta 592 data = self.read(addr_1, dwSize) 593 data_1 = data[:size_1] 594 data_2 = data[size_1:] 595 disasm_1 = self.disassemble_string(addr_1, data_1) 596 disasm_2 = self.disassemble_string(addr_2, data_2) 597 disasm = disasm_1 + disasm_2 598 self.__fixup_labels(disasm) 599 return disasm 600 601 def disassemble_around_pc(self, dwThreadId, dwSize = 64): 602 """ 603 Disassemble around the program counter of the given thread. 604 605 @type dwThreadId: int 606 @param dwThreadId: Global thread ID. 607 The program counter for this thread will be used as the disassembly 608 address. 609 610 @type dwSize: int 611 @param dwSize: Delta offset. 612 Code will be read from pc - dwSize to pc + dwSize. 613 614 @rtype: list of tuple( long, int, str, str ) 615 @return: List of tuples. Each tuple represents an assembly instruction 616 and contains: 617 - Memory address of instruction. 618 - Size of instruction in bytes. 619 - Disassembly line of instruction. 620 - Hexadecimal dump of instruction. 621 """ 622 aThread = self.get_thread(dwThreadId) 623 return self.disassemble_around(aThread.get_pc(), dwSize) 624 625 def disassemble_instruction(self, lpAddress): 626 """ 627 Disassemble the instruction at the given memory address. 628 629 @type lpAddress: int 630 @param lpAddress: Memory address where to read the code from. 631 632 @rtype: tuple( long, int, str, str ) 633 @return: The tuple represents an assembly instruction 634 and contains: 635 - Memory address of instruction. 636 - Size of instruction in bytes. 637 - Disassembly line of instruction. 638 - Hexadecimal dump of instruction. 639 """ 640 return self.disassemble(lpAddress, 15)[0] 641 642 def disassemble_current(self, dwThreadId): 643 """ 644 Disassemble the instruction at the program counter of the given thread. 645 646 @type dwThreadId: int 647 @param dwThreadId: Global thread ID. 648 The program counter for this thread will be used as the disassembly 649 address. 650 651 @rtype: tuple( long, int, str, str ) 652 @return: The tuple represents an assembly instruction 653 and contains: 654 - Memory address of instruction. 655 - Size of instruction in bytes. 656 - Disassembly line of instruction. 657 - Hexadecimal dump of instruction. 658 """ 659 aThread = self.get_thread(dwThreadId) 660 return self.disassemble_instruction(aThread.get_pc()) 661 662#------------------------------------------------------------------------------ 663 664 def flush_instruction_cache(self): 665 """ 666 Flush the instruction cache. This is required if the process memory is 667 modified and one or more threads are executing nearby the modified 668 memory region. 669 670 @see: U{http://blogs.msdn.com/oldnewthing/archive/2003/12/08/55954.aspx#55958} 671 672 @raise WindowsError: Raises exception on error. 673 """ 674 # FIXME 675 # No idea what access rights are required here! 676 # Maybe PROCESS_VM_OPERATION ??? 677 # In any case we're only calling this from the debugger, 678 # so it should be fine (we already have PROCESS_ALL_ACCESS). 679 win32.FlushInstructionCache( self.get_handle() ) 680 681 def debug_break(self): 682 """ 683 Triggers the system breakpoint in the process. 684 685 @raise WindowsError: On error an exception is raised. 686 """ 687 # The exception is raised by a new thread. 688 # When continuing the exception, the thread dies by itself. 689 # This thread is hidden from the debugger. 690 win32.DebugBreakProcess( self.get_handle() ) 691 692 def is_wow64(self): 693 """ 694 Determines if the process is running under WOW64. 695 696 @rtype: bool 697 @return: 698 C{True} if the process is running under WOW64. That is, a 32-bit 699 application running in a 64-bit Windows. 700 701 C{False} if the process is either a 32-bit application running in 702 a 32-bit Windows, or a 64-bit application running in a 64-bit 703 Windows. 704 705 @raise WindowsError: On error an exception is raised. 706 707 @see: U{http://msdn.microsoft.com/en-us/library/aa384249(VS.85).aspx} 708 """ 709 try: 710 wow64 = self.__wow64 711 except AttributeError: 712 if (win32.bits == 32 and not win32.wow64): 713 wow64 = False 714 else: 715 if win32.PROCESS_ALL_ACCESS == win32.PROCESS_ALL_ACCESS_VISTA: 716 dwAccess = win32.PROCESS_QUERY_LIMITED_INFORMATION 717 else: 718 dwAccess = win32.PROCESS_QUERY_INFORMATION 719 hProcess = self.get_handle(dwAccess) 720 try: 721 wow64 = win32.IsWow64Process(hProcess) 722 except AttributeError: 723 wow64 = False 724 self.__wow64 = wow64 725 return wow64 726 727 def get_arch(self): 728 """ 729 @rtype: str 730 @return: The architecture in which this process believes to be running. 731 For example, if running a 32 bit binary in a 64 bit machine, the 732 architecture returned by this method will be L{win32.ARCH_I386}, 733 but the value of L{System.arch} will be L{win32.ARCH_AMD64}. 734 """ 735 736 # Are we in a 32 bit machine? 737 if win32.bits == 32 and not win32.wow64: 738 return win32.arch 739 740 # Is the process outside of WOW64? 741 if not self.is_wow64(): 742 return win32.arch 743 744 # In WOW64, "amd64" becomes "i386". 745 if win32.arch == win32.ARCH_AMD64: 746 return win32.ARCH_I386 747 748 # We don't know the translation for other architectures. 749 raise NotImplementedError() 750 751 def get_bits(self): 752 """ 753 @rtype: str 754 @return: The number of bits in which this process believes to be 755 running. For example, if running a 32 bit binary in a 64 bit 756 machine, the number of bits returned by this method will be C{32}, 757 but the value of L{System.arch} will be C{64}. 758 """ 759 760 # Are we in a 32 bit machine? 761 if win32.bits == 32 and not win32.wow64: 762 763 # All processes are 32 bits. 764 return 32 765 766 # Is the process inside WOW64? 767 if self.is_wow64(): 768 769 # The process is 32 bits. 770 return 32 771 772 # The process is 64 bits. 773 return 64 774 775 # TODO: get_os, to test compatibility run 776 # See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683224(v=vs.85).aspx 777 778#------------------------------------------------------------------------------ 779 780 def get_start_time(self): 781 """ 782 Determines when has this process started running. 783 784 @rtype: win32.SYSTEMTIME 785 @return: Process start time. 786 """ 787 if win32.PROCESS_ALL_ACCESS == win32.PROCESS_ALL_ACCESS_VISTA: 788 dwAccess = win32.PROCESS_QUERY_LIMITED_INFORMATION 789 else: 790 dwAccess = win32.PROCESS_QUERY_INFORMATION 791 hProcess = self.get_handle(dwAccess) 792 CreationTime = win32.GetProcessTimes(hProcess)[0] 793 return win32.FileTimeToSystemTime(CreationTime) 794 795 def get_exit_time(self): 796 """ 797 Determines when has this process finished running. 798 If the process is still alive, the current time is returned instead. 799 800 @rtype: win32.SYSTEMTIME 801 @return: Process exit time. 802 """ 803 if self.is_alive(): 804 ExitTime = win32.GetSystemTimeAsFileTime() 805 else: 806 if win32.PROCESS_ALL_ACCESS == win32.PROCESS_ALL_ACCESS_VISTA: 807 dwAccess = win32.PROCESS_QUERY_LIMITED_INFORMATION 808 else: 809 dwAccess = win32.PROCESS_QUERY_INFORMATION 810 hProcess = self.get_handle(dwAccess) 811 ExitTime = win32.GetProcessTimes(hProcess)[1] 812 return win32.FileTimeToSystemTime(ExitTime) 813 814 def get_running_time(self): 815 """ 816 Determines how long has this process been running. 817 818 @rtype: long 819 @return: Process running time in milliseconds. 820 """ 821 if win32.PROCESS_ALL_ACCESS == win32.PROCESS_ALL_ACCESS_VISTA: 822 dwAccess = win32.PROCESS_QUERY_LIMITED_INFORMATION 823 else: 824 dwAccess = win32.PROCESS_QUERY_INFORMATION 825 hProcess = self.get_handle(dwAccess) 826 (CreationTime, ExitTime, _, _) = win32.GetProcessTimes(hProcess) 827 if self.is_alive(): 828 ExitTime = win32.GetSystemTimeAsFileTime() 829 CreationTime = CreationTime.dwLowDateTime + (CreationTime.dwHighDateTime << 32) 830 ExitTime = ExitTime.dwLowDateTime + ( ExitTime.dwHighDateTime << 32) 831 RunningTime = ExitTime - CreationTime 832 return RunningTime / 10000 # 100 nanoseconds steps => milliseconds 833 834#------------------------------------------------------------------------------ 835 836 def __load_System_class(self): 837 global System # delayed import 838 if System is None: 839 from system import System 840 841 def get_services(self): 842 """ 843 Retrieves the list of system services that are currently running in 844 this process. 845 846 @see: L{System.get_services} 847 848 @rtype: list( L{win32.ServiceStatusProcessEntry} ) 849 @return: List of service status descriptors. 850 """ 851 self.__load_System_class() 852 pid = self.get_pid() 853 return [d for d in System.get_active_services() if d.ProcessId == pid] 854 855#------------------------------------------------------------------------------ 856 857 def get_dep_policy(self): 858 """ 859 Retrieves the DEP (Data Execution Prevention) policy for this process. 860 861 @note: This method is only available in Windows XP SP3 and above, and 862 only for 32 bit processes. It will fail in any other circumstance. 863 864 @see: U{http://msdn.microsoft.com/en-us/library/bb736297(v=vs.85).aspx} 865 866 @rtype: tuple(int, int) 867 @return: 868 The first member of the tuple is the DEP flags. It can be a 869 combination of the following values: 870 - 0: DEP is disabled for this process. 871 - 1: DEP is enabled for this process. (C{PROCESS_DEP_ENABLE}) 872 - 2: DEP-ATL thunk emulation is disabled for this process. 873 (C{PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION}) 874 875 The second member of the tuple is the permanent flag. If C{TRUE} 876 the DEP settings cannot be changed in runtime for this process. 877 878 @raise WindowsError: On error an exception is raised. 879 """ 880 hProcess = self.get_handle(win32.PROCESS_QUERY_INFORMATION) 881 try: 882 return win32.kernel32.GetProcessDEPPolicy(hProcess) 883 except AttributeError: 884 msg = "This method is only available in Windows XP SP3 and above." 885 raise NotImplementedError(msg) 886 887#------------------------------------------------------------------------------ 888 889 def get_peb(self): 890 """ 891 Returns a copy of the PEB. 892 To dereference pointers in it call L{Process.read_structure}. 893 894 @rtype: L{win32.PEB} 895 @return: PEB structure. 896 @raise WindowsError: An exception is raised on error. 897 """ 898 self.get_handle( win32.PROCESS_VM_READ | 899 win32.PROCESS_QUERY_INFORMATION ) 900 return self.read_structure(self.get_peb_address(), win32.PEB) 901 902 def get_peb_address(self): 903 """ 904 Returns a remote pointer to the PEB. 905 906 @rtype: int 907 @return: Remote pointer to the L{win32.PEB} structure. 908 Returns C{None} on error. 909 """ 910 try: 911 return self._peb_ptr 912 except AttributeError: 913 hProcess = self.get_handle(win32.PROCESS_QUERY_INFORMATION) 914 pbi = win32.NtQueryInformationProcess(hProcess, 915 win32.ProcessBasicInformation) 916 address = pbi.PebBaseAddress 917 self._peb_ptr = address 918 return address 919 920 def get_entry_point(self): 921 """ 922 Alias to C{process.get_main_module().get_entry_point()}. 923 924 @rtype: int 925 @return: Address of the entry point of the main module. 926 """ 927 return self.get_main_module().get_entry_point() 928 929 def get_main_module(self): 930 """ 931 @rtype: L{Module} 932 @return: Module object for the process main module. 933 """ 934 return self.get_module(self.get_image_base()) 935 936 def get_image_base(self): 937 """ 938 @rtype: int 939 @return: Image base address for the process main module. 940 """ 941 return self.get_peb().ImageBaseAddress 942 943 def get_image_name(self): 944 """ 945 @rtype: int 946 @return: Filename of the process main module. 947 948 This method does it's best to retrieve the filename. 949 However sometimes this is not possible, so C{None} may 950 be returned instead. 951 """ 952 953 # Method 1: Module.fileName 954 # It's cached if the filename was already found by the other methods, 955 # if it came with the corresponding debug event, or it was found by the 956 # toolhelp API. 957 mainModule = None 958 try: 959 mainModule = self.get_main_module() 960 name = mainModule.fileName 961 if not name: 962 name = None 963 except (KeyError, AttributeError, WindowsError): 964## traceback.print_exc() # XXX DEBUG 965 name = None 966 967 # Method 2: QueryFullProcessImageName() 968 # Not implemented until Windows Vista. 969 if not name: 970 try: 971 hProcess = self.get_handle( 972 win32.PROCESS_QUERY_LIMITED_INFORMATION) 973 name = win32.QueryFullProcessImageName(hProcess) 974 except (AttributeError, WindowsError): 975## traceback.print_exc() # XXX DEBUG 976 name = None 977 978 # Method 3: GetProcessImageFileName() 979 # 980 # Not implemented until Windows XP. 981 # For more info see: 982 # https://voidnish.wordpress.com/2005/06/20/getprocessimagefilenamequerydosdevice-trivia/ 983 if not name: 984 try: 985 hProcess = self.get_handle(win32.PROCESS_QUERY_INFORMATION) 986 name = win32.GetProcessImageFileName(hProcess) 987 if name: 988 name = PathOperations.native_to_win32_pathname(name) 989 else: 990 name = None 991 except (AttributeError, WindowsError): 992## traceback.print_exc() # XXX DEBUG 993 if not name: 994 name = None 995 996 # Method 4: GetModuleFileNameEx() 997 # Not implemented until Windows 2000. 998 # 999 # May be spoofed by malware, since this information resides 1000 # in usermode space (see http://www.ragestorm.net/blogs/?p=163). 1001 if not name: 1002 try: 1003 hProcess = self.get_handle( win32.PROCESS_VM_READ | 1004 win32.PROCESS_QUERY_INFORMATION ) 1005 try: 1006 name = win32.GetModuleFileNameEx(hProcess) 1007 except WindowsError: 1008## traceback.print_exc() # XXX DEBUG 1009 name = win32.GetModuleFileNameEx( 1010 hProcess, self.get_image_base()) 1011 if name: 1012 name = PathOperations.native_to_win32_pathname(name) 1013 else: 1014 name = None 1015 except (AttributeError, WindowsError): 1016## traceback.print_exc() # XXX DEBUG 1017 if not name: 1018 name = None 1019 1020 # Method 5: PEB.ProcessParameters->ImagePathName 1021 # 1022 # May fail since it's using an undocumented internal structure. 1023 # 1024 # May be spoofed by malware, since this information resides 1025 # in usermode space (see http://www.ragestorm.net/blogs/?p=163). 1026 if not name: 1027 try: 1028 peb = self.get_peb() 1029 pp = self.read_structure(peb.ProcessParameters, 1030 win32.RTL_USER_PROCESS_PARAMETERS) 1031 s = pp.ImagePathName 1032 name = self.peek_string(s.Buffer, 1033 dwMaxSize=s.MaximumLength, fUnicode=True) 1034 if name: 1035 name = PathOperations.native_to_win32_pathname(name) 1036 else: 1037 name = None 1038 except (AttributeError, WindowsError): 1039## traceback.print_exc() # XXX DEBUG 1040 name = None 1041 1042 # Method 6: Module.get_filename() 1043 # It tries to get the filename from the file handle. 1044 # 1045 # There are currently some problems due to the strange way the API 1046 # works - it returns the pathname without the drive letter, and I 1047 # couldn't figure out a way to fix it. 1048 if not name and mainModule is not None: 1049 try: 1050 name = mainModule.get_filename() 1051 if not name: 1052 name = None 1053 except (AttributeError, WindowsError): 1054## traceback.print_exc() # XXX DEBUG 1055 name = None 1056 1057 # Remember the filename. 1058 if name and mainModule is not None: 1059 mainModule.fileName = name 1060 1061 # Return the image filename, or None on error. 1062 return name 1063 1064 def get_command_line_block(self): 1065 """ 1066 Retrieves the command line block memory address and size. 1067 1068 @rtype: tuple(int, int) 1069 @return: Tuple with the memory address of the command line block 1070 and it's maximum size in Unicode characters. 1071 1072 @raise WindowsError: On error an exception is raised. 1073 """ 1074 peb = self.get_peb() 1075 pp = self.read_structure(peb.ProcessParameters, 1076 win32.RTL_USER_PROCESS_PARAMETERS) 1077 s = pp.CommandLine 1078 return (s.Buffer, s.MaximumLength) 1079 1080 def get_environment_block(self): 1081 """ 1082 Retrieves the environment block memory address for the process. 1083 1084 @note: The size is always enough to contain the environment data, but 1085 it may not be an exact size. It's best to read the memory and 1086 scan for two null wide chars to find the actual size. 1087 1088 @rtype: tuple(int, int) 1089 @return: Tuple with the memory address of the environment block 1090 and it's size. 1091 1092 @raise WindowsError: On error an exception is raised. 1093 """ 1094 peb = self.get_peb() 1095 pp = self.read_structure(peb.ProcessParameters, 1096 win32.RTL_USER_PROCESS_PARAMETERS) 1097 Environment = pp.Environment 1098 try: 1099 EnvironmentSize = pp.EnvironmentSize 1100 except AttributeError: 1101 mbi = self.mquery(Environment) 1102 EnvironmentSize = mbi.RegionSize + mbi.BaseAddress - Environment 1103 return (Environment, EnvironmentSize) 1104 1105 def get_command_line(self): 1106 """ 1107 Retrieves the command line with wich the program was started. 1108 1109 @rtype: str 1110 @return: Command line string. 1111 1112 @raise WindowsError: On error an exception is raised. 1113 """ 1114 (Buffer, MaximumLength) = self.get_command_line_block() 1115 CommandLine = self.peek_string(Buffer, dwMaxSize=MaximumLength, 1116 fUnicode=True) 1117 gst = win32.GuessStringType 1118 if gst.t_default == gst.t_ansi: 1119 CommandLine = CommandLine.encode('cp1252') 1120 return CommandLine 1121 1122 def get_environment_variables(self): 1123 """ 1124 Retrieves the environment variables with wich the program is running. 1125 1126 @rtype: list of tuple(compat.unicode, compat.unicode) 1127 @return: Environment keys and values as found in the process memory. 1128 1129 @raise WindowsError: On error an exception is raised. 1130 """ 1131 1132 # Note: the first bytes are garbage and must be skipped. Then the first 1133 # two environment entries are the current drive and directory as key 1134 # and value pairs, followed by the ExitCode variable (it's what batch 1135 # files know as "errorlevel"). After that, the real environment vars 1136 # are there in alphabetical order. In theory that's where it stops, 1137 # but I've always seen one more "variable" tucked at the end which 1138 # may be another environment block but in ANSI. I haven't examined it 1139 # yet, I'm just skipping it because if it's parsed as Unicode it just 1140 # renders garbage. 1141 1142 # Read the environment block contents. 1143 data = self.peek( *self.get_environment_block() ) 1144 1145 # Put them into a Unicode buffer. 1146 tmp = ctypes.create_string_buffer(data) 1147 buffer = ctypes.create_unicode_buffer(len(data)) 1148 ctypes.memmove(buffer, tmp, len(data)) 1149 del tmp 1150 1151 # Skip until the first Unicode null char is found. 1152 pos = 0 1153 while buffer[pos] != u'\0': 1154 pos += 1 1155 pos += 1 1156 1157 # Loop for each environment variable... 1158 environment = [] 1159 while buffer[pos] != u'\0': 1160 1161 # Until we find a null char... 1162 env_name_pos = pos 1163 env_name = u'' 1164 found_name = False 1165 while buffer[pos] != u'\0': 1166 1167 # Get the current char. 1168 char = buffer[pos] 1169 1170 # Is it an equal sign? 1171 if char == u'=': 1172 1173 # Skip leading equal signs. 1174 if env_name_pos == pos: 1175 env_name_pos += 1 1176 pos += 1 1177 continue 1178 1179 # Otherwise we found the separator equal sign. 1180 pos += 1 1181 found_name = True 1182 break 1183 1184 # Add the char to the variable name. 1185 env_name += char 1186 1187 # Next char. 1188 pos += 1 1189 1190 # If the name was not parsed properly, stop. 1191 if not found_name: 1192 break 1193 1194 # Read the variable value until we find a null char. 1195 env_value = u'' 1196 while buffer[pos] != u'\0': 1197 env_value += buffer[pos] 1198 pos += 1 1199 1200 # Skip the null char. 1201 pos += 1 1202 1203 # Add to the list of environment variables found. 1204 environment.append( (env_name, env_value) ) 1205 1206 # Remove the last entry, it's garbage. 1207 if environment: 1208 environment.pop() 1209 1210 # Return the environment variables. 1211 return environment 1212 1213 def get_environment_data(self, fUnicode = None): 1214 """ 1215 Retrieves the environment block data with wich the program is running. 1216 1217 @warn: Deprecated since WinAppDbg 1.5. 1218 1219 @see: L{win32.GuessStringType} 1220 1221 @type fUnicode: bool or None 1222 @param fUnicode: C{True} to return a list of Unicode strings, C{False} 1223 to return a list of ANSI strings, or C{None} to return whatever 1224 the default is for string types. 1225 1226 @rtype: list of str 1227 @return: Environment keys and values separated by a (C{=}) character, 1228 as found in the process memory. 1229 1230 @raise WindowsError: On error an exception is raised. 1231 """ 1232 1233 # Issue a deprecation warning. 1234 warnings.warn( 1235 "Process.get_environment_data() is deprecated" \ 1236 " since WinAppDbg 1.5.", 1237 DeprecationWarning) 1238 1239 # Get the environment variables. 1240 block = [ key + u'=' + value for (key, value) \ 1241 in self.get_environment_variables() ] 1242 1243 # Convert the data to ANSI if requested. 1244 if fUnicode is None: 1245 gst = win32.GuessStringType 1246 fUnicode = gst.t_default == gst.t_unicode 1247 if not fUnicode: 1248 block = [x.encode('cp1252') for x in block] 1249 1250 # Return the environment data. 1251 return block 1252 1253 @staticmethod 1254 def parse_environment_data(block): 1255 """ 1256 Parse the environment block into a Python dictionary. 1257 1258 @warn: Deprecated since WinAppDbg 1.5. 1259 1260 @note: Values of duplicated keys are joined using null characters. 1261 1262 @type block: list of str 1263 @param block: List of strings as returned by L{get_environment_data}. 1264 1265 @rtype: dict(str S{->} str) 1266 @return: Dictionary of environment keys and values. 1267 """ 1268 1269 # Issue a deprecation warning. 1270 warnings.warn( 1271 "Process.parse_environment_data() is deprecated" \ 1272 " since WinAppDbg 1.5.", 1273 DeprecationWarning) 1274 1275 # Create an empty environment dictionary. 1276 environment = dict() 1277 1278 # End here if the environment block is empty. 1279 if not block: 1280 return environment 1281 1282 # Prepare the tokens (ANSI or Unicode). 1283 gst = win32.GuessStringType 1284 if type(block[0]) == gst.t_ansi: 1285 equals = '=' 1286 terminator = '\0' 1287 else: 1288 equals = u'=' 1289 terminator = u'\0' 1290 1291 # Split the blocks into key/value pairs. 1292 for chunk in block: 1293 sep = chunk.find(equals, 1) 1294 if sep < 0: 1295## raise Exception() 1296 continue # corrupted environment block? 1297 key, value = chunk[:sep], chunk[sep+1:] 1298 1299 # For duplicated keys, append the value. 1300 # Values are separated using null terminators. 1301 if key not in environment: 1302 environment[key] = value 1303 else: 1304 environment[key] += terminator + value 1305 1306 # Return the environment dictionary. 1307 return environment 1308 1309 def get_environment(self, fUnicode = None): 1310 """ 1311 Retrieves the environment with wich the program is running. 1312 1313 @note: Duplicated keys are joined using null characters. 1314 To avoid this behavior, call L{get_environment_variables} instead 1315 and convert the results to a dictionary directly, like this: 1316 C{dict(process.get_environment_variables())} 1317 1318 @see: L{win32.GuessStringType} 1319 1320 @type fUnicode: bool or None 1321 @param fUnicode: C{True} to return a list of Unicode strings, C{False} 1322 to return a list of ANSI strings, or C{None} to return whatever 1323 the default is for string types. 1324 1325 @rtype: dict(str S{->} str) 1326 @return: Dictionary of environment keys and values. 1327 1328 @raise WindowsError: On error an exception is raised. 1329 """ 1330 1331 # Get the environment variables. 1332 variables = self.get_environment_variables() 1333 1334 # Convert the strings to ANSI if requested. 1335 if fUnicode is None: 1336 gst = win32.GuessStringType 1337 fUnicode = gst.t_default == gst.t_unicode 1338 if not fUnicode: 1339 variables = [ ( key.encode('cp1252'), value.encode('cp1252') ) \ 1340 for (key, value) in variables ] 1341 1342 # Add the variables to a dictionary, concatenating duplicates. 1343 environment = dict() 1344 for key, value in variables: 1345 if key in environment: 1346 environment[key] = environment[key] + u'\0' + value 1347 else: 1348 environment[key] = value 1349 1350 # Return the dictionary. 1351 return environment 1352 1353#------------------------------------------------------------------------------ 1354 1355 def search(self, pattern, minAddr = None, maxAddr = None): 1356 """ 1357 Search for the given pattern within the process memory. 1358 1359 @type pattern: str, compat.unicode or L{Pattern} 1360 @param pattern: Pattern to search for. 1361 It may be a byte string, a Unicode string, or an instance of 1362 L{Pattern}. 1363 1364 The following L{Pattern} subclasses are provided by WinAppDbg: 1365 - L{BytePattern} 1366 - L{TextPattern} 1367 - L{RegExpPattern} 1368 - L{HexPattern} 1369 1370 You can also write your own subclass of L{Pattern} for customized 1371 searches. 1372 1373 @type minAddr: int 1374 @param minAddr: (Optional) Start the search at this memory address. 1375 1376 @type maxAddr: int 1377 @param maxAddr: (Optional) Stop the search at this memory address. 1378 1379 @rtype: iterator of tuple( int, int, str ) 1380 @return: An iterator of tuples. Each tuple contains the following: 1381 - The memory address where the pattern was found. 1382 - The size of the data that matches the pattern. 1383 - The data that matches the pattern. 1384 1385 @raise WindowsError: An error occurred when querying or reading the 1386 process memory. 1387 """ 1388 if isinstance(pattern, str): 1389 return self.search_bytes(pattern, minAddr, maxAddr) 1390 if isinstance(pattern, compat.unicode): 1391 return self.search_bytes(pattern.encode("utf-16le"), 1392 minAddr, maxAddr) 1393 if isinstance(pattern, Pattern): 1394 return Search.search_process(self, pattern, minAddr, maxAddr) 1395 raise TypeError("Unknown pattern type: %r" % type(pattern)) 1396 1397 def search_bytes(self, bytes, minAddr = None, maxAddr = None): 1398 """ 1399 Search for the given byte pattern within the process memory. 1400 1401 @type bytes: str 1402 @param bytes: Bytes to search for. 1403 1404 @type minAddr: int 1405 @param minAddr: (Optional) Start the search at this memory address. 1406 1407 @type maxAddr: int 1408 @param maxAddr: (Optional) Stop the search at this memory address. 1409 1410 @rtype: iterator of int 1411 @return: An iterator of memory addresses where the pattern was found. 1412 1413 @raise WindowsError: An error occurred when querying or reading the 1414 process memory. 1415 """ 1416 pattern = BytePattern(bytes) 1417 matches = Search.search_process(self, pattern, minAddr, maxAddr) 1418 for addr, size, data in matches: 1419 yield addr 1420 1421 def search_text(self, text, encoding = "utf-16le", 1422 caseSensitive = False, 1423 minAddr = None, 1424 maxAddr = None): 1425 """ 1426 Search for the given text within the process memory. 1427 1428 @type text: str or compat.unicode 1429 @param text: Text to search for. 1430 1431 @type encoding: str 1432 @param encoding: (Optional) Encoding for the text parameter. 1433 Only used when the text to search for is a Unicode string. 1434 Don't change unless you know what you're doing! 1435 1436 @type caseSensitive: bool 1437 @param caseSensitive: C{True} of the search is case sensitive, 1438 C{False} otherwise. 1439 1440 @type minAddr: int 1441 @param minAddr: (Optional) Start the search at this memory address. 1442 1443 @type maxAddr: int 1444 @param maxAddr: (Optional) Stop the search at this memory address. 1445 1446 @rtype: iterator of tuple( int, str ) 1447 @return: An iterator of tuples. Each tuple contains the following: 1448 - The memory address where the pattern was found. 1449 - The text that matches the pattern. 1450 1451 @raise WindowsError: An error occurred when querying or reading the 1452 process memory. 1453 """ 1454 pattern = TextPattern(text, encoding, caseSensitive) 1455 matches = Search.search_process(self, pattern, minAddr, maxAddr) 1456 for addr, size, data in matches: 1457 yield addr, data 1458 1459 def search_regexp(self, regexp, flags = 0, 1460 minAddr = None, 1461 maxAddr = None, 1462 bufferPages = -1): 1463 """ 1464 Search for the given regular expression within the process memory. 1465 1466 @type regexp: str 1467 @param regexp: Regular expression string. 1468 1469 @type flags: int 1470 @param flags: Regular expression flags. 1471 1472 @type minAddr: int 1473 @param minAddr: (Optional) Start the search at this memory address. 1474 1475 @type maxAddr: int 1476 @param maxAddr: (Optional) Stop the search at this memory address. 1477 1478 @type bufferPages: int 1479 @param bufferPages: (Optional) Number of memory pages to buffer when 1480 performing the search. Valid values are: 1481 - C{0} or C{None}: 1482 Automatically determine the required buffer size. May not give 1483 complete results for regular expressions that match variable 1484 sized strings. 1485 - C{> 0}: Set the buffer size, in memory pages. 1486 - C{< 0}: Disable buffering entirely. This may give you a little 1487 speed gain at the cost of an increased memory usage. If the 1488 target process has very large contiguous memory regions it may 1489 actually be slower or even fail. It's also the only way to 1490 guarantee complete results for regular expressions that match 1491 variable sized strings. 1492 1493 @rtype: iterator of tuple( int, int, str ) 1494 @return: An iterator of tuples. Each tuple contains the following: 1495 - The memory address where the pattern was found. 1496 - The size of the data that matches the pattern. 1497 - The data that matches the pattern. 1498 1499 @raise WindowsError: An error occurred when querying or reading the 1500 process memory. 1501 """ 1502 pattern = RegExpPattern(regexp, flags) 1503 return Search.search_process(self, pattern, 1504 minAddr, maxAddr, 1505 bufferPages) 1506 1507 def search_hexa(self, hexa, minAddr = None, maxAddr = None): 1508 """ 1509 Search for the given hexadecimal pattern within the process memory. 1510 1511 Hex patterns must be in this form:: 1512 "68 65 6c 6c 6f 20 77 6f 72 6c 64" # "hello world" 1513 1514 Spaces are optional. Capitalization of hex digits doesn't matter. 1515 This is exactly equivalent to the previous example:: 1516 "68656C6C6F20776F726C64" # "hello world" 1517 1518 Wildcards are allowed, in the form of a C{?} sign in any hex digit:: 1519 "5? 5? c3" # pop register / pop register / ret 1520 "b8 ?? ?? ?? ??" # mov eax, immediate value 1521 1522 @type hexa: str 1523 @param hexa: Pattern to search for. 1524 1525 @type minAddr: int 1526 @param minAddr: (Optional) Start the search at this memory address. 1527 1528 @type maxAddr: int 1529 @param maxAddr: (Optional) Stop the search at this memory address. 1530 1531 @rtype: iterator of tuple( int, str ) 1532 @return: An iterator of tuples. Each tuple contains the following: 1533 - The memory address where the pattern was found. 1534 - The bytes that match the pattern. 1535 1536 @raise WindowsError: An error occurred when querying or reading the 1537 process memory. 1538 """ 1539 pattern = HexPattern(hexa) 1540 matches = Search.search_process(self, pattern, minAddr, maxAddr) 1541 for addr, size, data in matches: 1542 yield addr, data 1543 1544 def strings(self, minSize = 4, maxSize = 1024): 1545 """ 1546 Extract ASCII strings from the process memory. 1547 1548 @type minSize: int 1549 @param minSize: (Optional) Minimum size of the strings to search for. 1550 1551 @type maxSize: int 1552 @param maxSize: (Optional) Maximum size of the strings to search for. 1553 1554 @rtype: iterator of tuple(int, int, str) 1555 @return: Iterator of strings extracted from the process memory. 1556 Each tuple contains the following: 1557 - The memory address where the string was found. 1558 - The size of the string. 1559 - The string. 1560 """ 1561 return Search.extract_ascii_strings(self, minSize = minSize, 1562 maxSize = maxSize) 1563 1564#------------------------------------------------------------------------------ 1565 1566 def __read_c_type(self, address, format, c_type): 1567 size = ctypes.sizeof(c_type) 1568 packed = self.read(address, size) 1569 if len(packed) != size: 1570 raise ctypes.WinError() 1571 return struct.unpack(format, packed)[0] 1572 1573 def __write_c_type(self, address, format, unpacked): 1574 packed = struct.pack('@L', unpacked) 1575 self.write(address, packed) 1576 1577 # XXX TODO 1578 # + Maybe change page permissions before trying to read? 1579 def read(self, lpBaseAddress, nSize): 1580 """ 1581 Reads from the memory of the process. 1582 1583 @see: L{peek} 1584 1585 @type lpBaseAddress: int 1586 @param lpBaseAddress: Memory address to begin reading. 1587 1588 @type nSize: int 1589 @param nSize: Number of bytes to read. 1590 1591 @rtype: str 1592 @return: Bytes read from the process memory. 1593 1594 @raise WindowsError: On error an exception is raised. 1595 """ 1596 hProcess = self.get_handle( win32.PROCESS_VM_READ | 1597 win32.PROCESS_QUERY_INFORMATION ) 1598 if not self.is_buffer(lpBaseAddress, nSize): 1599 raise ctypes.WinError(win32.ERROR_INVALID_ADDRESS) 1600 data = win32.ReadProcessMemory(hProcess, lpBaseAddress, nSize) 1601 if len(data) != nSize: 1602 raise ctypes.WinError() 1603 return data 1604 1605 def write(self, lpBaseAddress, lpBuffer): 1606 """ 1607 Writes to the memory of the process. 1608 1609 @note: Page permissions may be changed temporarily while writing. 1610 1611 @see: L{poke} 1612 1613 @type lpBaseAddress: int 1614 @param lpBaseAddress: Memory address to begin writing. 1615 1616 @type lpBuffer: str 1617 @param lpBuffer: Bytes to write. 1618 1619 @raise WindowsError: On error an exception is raised. 1620 """ 1621 r = self.poke(lpBaseAddress, lpBuffer) 1622 if r != len(lpBuffer): 1623 raise ctypes.WinError() 1624 1625 def read_char(self, lpBaseAddress): 1626 """ 1627 Reads a single character to the memory of the process. 1628 1629 @see: L{peek_char} 1630 1631 @type lpBaseAddress: int 1632 @param lpBaseAddress: Memory address to begin writing. 1633 1634 @rtype: int 1635 @return: Character value read from the process memory. 1636 1637 @raise WindowsError: On error an exception is raised. 1638 """ 1639 return ord( self.read(lpBaseAddress, 1) ) 1640 1641 def write_char(self, lpBaseAddress, char): 1642 """ 1643 Writes a single character to the memory of the process. 1644 1645 @note: Page permissions may be changed temporarily while writing. 1646 1647 @see: L{poke_char} 1648 1649 @type lpBaseAddress: int 1650 @param lpBaseAddress: Memory address to begin writing. 1651 1652 @type char: int 1653 @param char: Character to write. 1654 1655 @raise WindowsError: On error an exception is raised. 1656 """ 1657 self.write(lpBaseAddress, chr(char)) 1658 1659 def read_int(self, lpBaseAddress): 1660 """ 1661 Reads a signed integer from the memory of the process. 1662 1663 @see: L{peek_int} 1664 1665 @type lpBaseAddress: int 1666 @param lpBaseAddress: Memory address to begin reading. 1667 1668 @rtype: int 1669 @return: Integer value read from the process memory. 1670 1671 @raise WindowsError: On error an exception is raised. 1672 """ 1673 return self.__read_c_type(lpBaseAddress, compat.b('@l'), ctypes.c_int) 1674 1675 def write_int(self, lpBaseAddress, unpackedValue): 1676 """ 1677 Writes a signed integer to the memory of the process. 1678 1679 @note: Page permissions may be changed temporarily while writing. 1680 1681 @see: L{poke_int} 1682 1683 @type lpBaseAddress: int 1684 @param lpBaseAddress: Memory address to begin writing. 1685 1686 @type unpackedValue: int, long 1687 @param unpackedValue: Value to write. 1688 1689 @raise WindowsError: On error an exception is raised. 1690 """ 1691 self.__write_c_type(lpBaseAddress, '@l', unpackedValue) 1692 1693 def read_uint(self, lpBaseAddress): 1694 """ 1695 Reads an unsigned integer from the memory of the process. 1696 1697 @see: L{peek_uint} 1698 1699 @type lpBaseAddress: int 1700 @param lpBaseAddress: Memory address to begin reading. 1701 1702 @rtype: int 1703 @return: Integer value read from the process memory. 1704 1705 @raise WindowsError: On error an exception is raised. 1706 """ 1707 return self.__read_c_type(lpBaseAddress, '@L', ctypes.c_uint) 1708 1709 def write_uint(self, lpBaseAddress, unpackedValue): 1710 """ 1711 Writes an unsigned integer to the memory of the process. 1712 1713 @note: Page permissions may be changed temporarily while writing. 1714 1715 @see: L{poke_uint} 1716 1717 @type lpBaseAddress: int 1718 @param lpBaseAddress: Memory address to begin writing. 1719 1720 @type unpackedValue: int, long 1721 @param unpackedValue: Value to write. 1722 1723 @raise WindowsError: On error an exception is raised. 1724 """ 1725 self.__write_c_type(lpBaseAddress, '@L', unpackedValue) 1726 1727 def read_float(self, lpBaseAddress): 1728 """ 1729 Reads a float from the memory of the process. 1730 1731 @see: L{peek_float} 1732 1733 @type lpBaseAddress: int 1734 @param lpBaseAddress: Memory address to begin reading. 1735 1736 @rtype: int 1737 @return: Floating point value read from the process memory. 1738 1739 @raise WindowsError: On error an exception is raised. 1740 """ 1741 return self.__read_c_type(lpBaseAddress, '@f', ctypes.c_float) 1742 1743 def write_float(self, lpBaseAddress, unpackedValue): 1744 """ 1745 Writes a float to the memory of the process. 1746 1747 @note: Page permissions may be changed temporarily while writing. 1748 1749 @see: L{poke_float} 1750 1751 @type lpBaseAddress: int 1752 @param lpBaseAddress: Memory address to begin writing. 1753 1754 @type unpackedValue: int, long 1755 @param unpackedValue: Floating point value to write. 1756 1757 @raise WindowsError: On error an exception is raised. 1758 """ 1759 self.__write_c_type(lpBaseAddress, '@f', unpackedValue) 1760 1761 def read_double(self, lpBaseAddress): 1762 """ 1763 Reads a double from the memory of the process. 1764 1765 @see: L{peek_double} 1766 1767 @type lpBaseAddress: int 1768 @param lpBaseAddress: Memory address to begin reading. 1769 1770 @rtype: int 1771 @return: Floating point value read from the process memory. 1772 1773 @raise WindowsError: On error an exception is raised. 1774 """ 1775 return self.__read_c_type(lpBaseAddress, '@d', ctypes.c_double) 1776 1777 def write_double(self, lpBaseAddress, unpackedValue): 1778 """ 1779 Writes a double to the memory of the process. 1780 1781 @note: Page permissions may be changed temporarily while writing. 1782 1783 @see: L{poke_double} 1784 1785 @type lpBaseAddress: int 1786 @param lpBaseAddress: Memory address to begin writing. 1787 1788 @type unpackedValue: int, long 1789 @param unpackedValue: Floating point value to write. 1790 1791 @raise WindowsError: On error an exception is raised. 1792 """ 1793 self.__write_c_type(lpBaseAddress, '@d', unpackedValue) 1794 1795 def read_pointer(self, lpBaseAddress): 1796 """ 1797 Reads a pointer value from the memory of the process. 1798 1799 @see: L{peek_pointer} 1800 1801 @type lpBaseAddress: int 1802 @param lpBaseAddress: Memory address to begin reading. 1803 1804 @rtype: int 1805 @return: Pointer value read from the process memory. 1806 1807 @raise WindowsError: On error an exception is raised. 1808 """ 1809 return self.__read_c_type(lpBaseAddress, '@P', ctypes.c_void_p) 1810 1811 def write_pointer(self, lpBaseAddress, unpackedValue): 1812 """ 1813 Writes a pointer value to the memory of the process. 1814 1815 @note: Page permissions may be changed temporarily while writing. 1816 1817 @see: L{poke_pointer} 1818 1819 @type lpBaseAddress: int 1820 @param lpBaseAddress: Memory address to begin writing. 1821 1822 @type unpackedValue: int, long 1823 @param unpackedValue: Value to write. 1824 1825 @raise WindowsError: On error an exception is raised. 1826 """ 1827 self.__write_c_type(lpBaseAddress, '@P', unpackedValue) 1828 1829 def read_dword(self, lpBaseAddress): 1830 """ 1831 Reads a DWORD from the memory of the process. 1832 1833 @see: L{peek_dword} 1834 1835 @type lpBaseAddress: int 1836 @param lpBaseAddress: Memory address to begin reading. 1837 1838 @rtype: int 1839 @return: Integer value read from the process memory. 1840 1841 @raise WindowsError: On error an exception is raised. 1842 """ 1843 return self.__read_c_type(lpBaseAddress, '=L', win32.DWORD) 1844 1845 def write_dword(self, lpBaseAddress, unpackedValue): 1846 """ 1847 Writes a DWORD to the memory of the process. 1848 1849 @note: Page permissions may be changed temporarily while writing. 1850 1851 @see: L{poke_dword} 1852 1853 @type lpBaseAddress: int 1854 @param lpBaseAddress: Memory address to begin writing. 1855 1856 @type unpackedValue: int, long 1857 @param unpackedValue: Value to write. 1858 1859 @raise WindowsError: On error an exception is raised. 1860 """ 1861 self.__write_c_type(lpBaseAddress, '=L', unpackedValue) 1862 1863 def read_qword(self, lpBaseAddress): 1864 """ 1865 Reads a QWORD from the memory of the process. 1866 1867 @see: L{peek_qword} 1868 1869 @type lpBaseAddress: int 1870 @param lpBaseAddress: Memory address to begin reading. 1871 1872 @rtype: int 1873 @return: Integer value read from the process memory. 1874 1875 @raise WindowsError: On error an exception is raised. 1876 """ 1877 return self.__read_c_type(lpBaseAddress, '=Q', win32.QWORD) 1878 1879 def write_qword(self, lpBaseAddress, unpackedValue): 1880 """ 1881 Writes a QWORD to the memory of the process. 1882 1883 @note: Page permissions may be changed temporarily while writing. 1884 1885 @see: L{poke_qword} 1886 1887 @type lpBaseAddress: int 1888 @param lpBaseAddress: Memory address to begin writing. 1889 1890 @type unpackedValue: int, long 1891 @param unpackedValue: Value to write. 1892 1893 @raise WindowsError: On error an exception is raised. 1894 """ 1895 self.__write_c_type(lpBaseAddress, '=Q', unpackedValue) 1896 1897 def read_structure(self, lpBaseAddress, stype): 1898 """ 1899 Reads a ctypes structure from the memory of the process. 1900 1901 @see: L{read} 1902 1903 @type lpBaseAddress: int 1904 @param lpBaseAddress: Memory address to begin reading. 1905 1906 @type stype: class ctypes.Structure or a subclass. 1907 @param stype: Structure definition. 1908 1909 @rtype: int 1910 @return: Structure instance filled in with data 1911 read from the process memory. 1912 1913 @raise WindowsError: On error an exception is raised. 1914 """ 1915 if type(lpBaseAddress) not in (type(0), type(long(0))): 1916 lpBaseAddress = ctypes.cast(lpBaseAddress, ctypes.c_void_p) 1917 data = self.read(lpBaseAddress, ctypes.sizeof(stype)) 1918 buff = ctypes.create_string_buffer(data) 1919 ptr = ctypes.cast(ctypes.pointer(buff), ctypes.POINTER(stype)) 1920 return ptr.contents 1921 1922# XXX TODO 1923## def write_structure(self, lpBaseAddress, sStructure): 1924## """ 1925## Writes a ctypes structure into the memory of the process. 1926## 1927## @note: Page permissions may be changed temporarily while writing. 1928## 1929## @see: L{write} 1930## 1931## @type lpBaseAddress: int 1932## @param lpBaseAddress: Memory address to begin writing. 1933## 1934## @type sStructure: ctypes.Structure or a subclass' instance. 1935## @param sStructure: Structure definition. 1936## 1937## @rtype: int 1938## @return: Structure instance filled in with data 1939## read from the process memory. 1940## 1941## @raise WindowsError: On error an exception is raised. 1942## """ 1943## size = ctypes.sizeof(sStructure) 1944## data = ctypes.create_string_buffer("", size = size) 1945## win32.CopyMemory(ctypes.byref(data), ctypes.byref(sStructure), size) 1946## self.write(lpBaseAddress, data.raw) 1947 1948 def read_string(self, lpBaseAddress, nChars, fUnicode = False): 1949 """ 1950 Reads an ASCII or Unicode string 1951 from the address space of the process. 1952 1953 @see: L{peek_string} 1954 1955 @type lpBaseAddress: int 1956 @param lpBaseAddress: Memory address to begin reading. 1957 1958 @type nChars: int 1959 @param nChars: String length to read, in characters. 1960 Remember that Unicode strings have two byte characters. 1961 1962 @type fUnicode: bool 1963 @param fUnicode: C{True} is the string is expected to be Unicode, 1964 C{False} if it's expected to be ANSI. 1965 1966 @rtype: str, compat.unicode 1967 @return: String read from the process memory space. 1968 1969 @raise WindowsError: On error an exception is raised. 1970 """ 1971 if fUnicode: 1972 nChars = nChars * 2 1973 szString = self.read(lpBaseAddress, nChars) 1974 if fUnicode: 1975 szString = compat.unicode(szString, 'U16', 'ignore') 1976 return szString 1977 1978#------------------------------------------------------------------------------ 1979 1980 # FIXME this won't work properly with a different endianness! 1981 def __peek_c_type(self, address, format, c_type): 1982 size = ctypes.sizeof(c_type) 1983 packed = self.peek(address, size) 1984 if len(packed) < size: 1985 packed = '\0' * (size - len(packed)) + packed 1986 elif len(packed) > size: 1987 packed = packed[:size] 1988 return struct.unpack(format, packed)[0] 1989 1990 def __poke_c_type(self, address, format, unpacked): 1991 packed = struct.pack('@L', unpacked) 1992 return self.poke(address, packed) 1993 1994 def peek(self, lpBaseAddress, nSize): 1995 """ 1996 Reads the memory of the process. 1997 1998 @see: L{read} 1999 2000 @type lpBaseAddress: int 2001 @param lpBaseAddress: Memory address to begin reading. 2002 2003 @type nSize: int 2004 @param nSize: Number of bytes to read. 2005 2006 @rtype: str 2007 @return: Bytes read from the process memory. 2008 Returns an empty string on error. 2009 """ 2010 # XXX TODO 2011 # + Maybe change page permissions before trying to read? 2012 # + Maybe use mquery instead of get_memory_map? 2013 # (less syscalls if we break out of the loop earlier) 2014 data = '' 2015 if nSize > 0: 2016 try: 2017 hProcess = self.get_handle( win32.PROCESS_VM_READ | 2018 win32.PROCESS_QUERY_INFORMATION ) 2019 for mbi in self.get_memory_map(lpBaseAddress, 2020 lpBaseAddress + nSize): 2021 if not mbi.is_readable(): 2022 nSize = mbi.BaseAddress - lpBaseAddress 2023 break 2024 if nSize > 0: 2025 data = win32.ReadProcessMemory( 2026 hProcess, lpBaseAddress, nSize) 2027 except WindowsError: 2028 e = sys.exc_info()[1] 2029 msg = "Error reading process %d address %s: %s" 2030 msg %= (self.get_pid(), 2031 HexDump.address(lpBaseAddress), 2032 e.strerror) 2033 warnings.warn(msg) 2034 return data 2035 2036 def poke(self, lpBaseAddress, lpBuffer): 2037 """ 2038 Writes to the memory of the process. 2039 2040 @note: Page permissions may be changed temporarily while writing. 2041 2042 @see: L{write} 2043 2044 @type lpBaseAddress: int 2045 @param lpBaseAddress: Memory address to begin writing. 2046 2047 @type lpBuffer: str 2048 @param lpBuffer: Bytes to write. 2049 2050 @rtype: int 2051 @return: Number of bytes written. 2052 May be less than the number of bytes to write. 2053 """ 2054 assert isinstance(lpBuffer, compat.bytes) 2055 hProcess = self.get_handle( win32.PROCESS_VM_WRITE | 2056 win32.PROCESS_VM_OPERATION | 2057 win32.PROCESS_QUERY_INFORMATION ) 2058 mbi = self.mquery(lpBaseAddress) 2059 if not mbi.has_content(): 2060 raise ctypes.WinError(win32.ERROR_INVALID_ADDRESS) 2061 if mbi.is_image() or mbi.is_mapped(): 2062 prot = win32.PAGE_WRITECOPY 2063 elif mbi.is_writeable(): 2064 prot = None 2065 elif mbi.is_executable(): 2066 prot = win32.PAGE_EXECUTE_READWRITE 2067 else: 2068 prot = win32.PAGE_READWRITE 2069 if prot is not None: 2070 try: 2071 self.mprotect(lpBaseAddress, len(lpBuffer), prot) 2072 except Exception: 2073 prot = None 2074 msg = ("Failed to adjust page permissions" 2075 " for process %s at address %s: %s") 2076 msg = msg % (self.get_pid(), 2077 HexDump.address(lpBaseAddress, self.get_bits()), 2078 traceback.format_exc()) 2079 warnings.warn(msg, RuntimeWarning) 2080 try: 2081 r = win32.WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer) 2082 finally: 2083 if prot is not None: 2084 self.mprotect(lpBaseAddress, len(lpBuffer), mbi.Protect) 2085 return r 2086 2087 def peek_char(self, lpBaseAddress): 2088 """ 2089 Reads a single character from the memory of the process. 2090 2091 @see: L{read_char} 2092 2093 @type lpBaseAddress: int 2094 @param lpBaseAddress: Memory address to begin reading. 2095 2096 @rtype: int 2097 @return: Character read from the process memory. 2098 Returns zero on error. 2099 """ 2100 char = self.peek(lpBaseAddress, 1) 2101 if char: 2102 return ord(char) 2103 return 0 2104 2105 def poke_char(self, lpBaseAddress, char): 2106 """ 2107 Writes a single character to the memory of the process. 2108 2109 @note: Page permissions may be changed temporarily while writing. 2110 2111 @see: L{write_char} 2112 2113 @type lpBaseAddress: int 2114 @param lpBaseAddress: Memory address to begin writing. 2115 2116 @type char: str 2117 @param char: Character to write. 2118 2119 @rtype: int 2120 @return: Number of bytes written. 2121 May be less than the number of bytes to write. 2122 """ 2123 return self.poke(lpBaseAddress, chr(char)) 2124 2125 def peek_int(self, lpBaseAddress): 2126 """ 2127 Reads a signed integer from the memory of the process. 2128 2129 @see: L{read_int} 2130 2131 @type lpBaseAddress: int 2132 @param lpBaseAddress: Memory address to begin reading. 2133 2134 @rtype: int 2135 @return: Integer value read from the process memory. 2136 Returns zero on error. 2137 """ 2138 return self.__peek_c_type(lpBaseAddress, '@l', ctypes.c_int) 2139 2140 def poke_int(self, lpBaseAddress, unpackedValue): 2141 """ 2142 Writes a signed integer to the memory of the process. 2143 2144 @note: Page permissions may be changed temporarily while writing. 2145 2146 @see: L{write_int} 2147 2148 @type lpBaseAddress: int 2149 @param lpBaseAddress: Memory address to begin writing. 2150 2151 @type unpackedValue: int, long 2152 @param unpackedValue: Value to write. 2153 2154 @rtype: int 2155 @return: Number of bytes written. 2156 May be less than the number of bytes to write. 2157 """ 2158 return self.__poke_c_type(lpBaseAddress, '@l', unpackedValue) 2159 2160 def peek_uint(self, lpBaseAddress): 2161 """ 2162 Reads an unsigned integer from the memory of the process. 2163 2164 @see: L{read_uint} 2165 2166 @type lpBaseAddress: int 2167 @param lpBaseAddress: Memory address to begin reading. 2168 2169 @rtype: int 2170 @return: Integer value read from the process memory. 2171 Returns zero on error. 2172 """ 2173 return self.__peek_c_type(lpBaseAddress, '@L', ctypes.c_uint) 2174 2175 def poke_uint(self, lpBaseAddress, unpackedValue): 2176 """ 2177 Writes an unsigned integer to the memory of the process. 2178 2179 @note: Page permissions may be changed temporarily while writing. 2180 2181 @see: L{write_uint} 2182 2183 @type lpBaseAddress: int 2184 @param lpBaseAddress: Memory address to begin writing. 2185 2186 @type unpackedValue: int, long 2187 @param unpackedValue: Value to write. 2188 2189 @rtype: int 2190 @return: Number of bytes written. 2191 May be less than the number of bytes to write. 2192 """ 2193 return self.__poke_c_type(lpBaseAddress, '@L', unpackedValue) 2194 2195 def peek_float(self, lpBaseAddress): 2196 """ 2197 Reads a float from the memory of the process. 2198 2199 @see: L{read_float} 2200 2201 @type lpBaseAddress: int 2202 @param lpBaseAddress: Memory address to begin reading. 2203 2204 @rtype: int 2205 @return: Integer value read from the process memory. 2206 Returns zero on error. 2207 """ 2208 return self.__peek_c_type(lpBaseAddress, '@f', ctypes.c_float) 2209 2210 def poke_float(self, lpBaseAddress, unpackedValue): 2211 """ 2212 Writes a float to the memory of the process. 2213 2214 @note: Page permissions may be changed temporarily while writing. 2215 2216 @see: L{write_float} 2217 2218 @type lpBaseAddress: int 2219 @param lpBaseAddress: Memory address to begin writing. 2220 2221 @type unpackedValue: int, long 2222 @param unpackedValue: Value to write. 2223 2224 @rtype: int 2225 @return: Number of bytes written. 2226 May be less than the number of bytes to write. 2227 """ 2228 return self.__poke_c_type(lpBaseAddress, '@f', unpackedValue) 2229 2230 def peek_double(self, lpBaseAddress): 2231 """ 2232 Reads a double from the memory of the process. 2233 2234 @see: L{read_double} 2235 2236 @type lpBaseAddress: int 2237 @param lpBaseAddress: Memory address to begin reading. 2238 2239 @rtype: int 2240 @return: Integer value read from the process memory. 2241 Returns zero on error. 2242 """ 2243 return self.__peek_c_type(lpBaseAddress, '@d', ctypes.c_double) 2244 2245 def poke_double(self, lpBaseAddress, unpackedValue): 2246 """ 2247 Writes a double to the memory of the process. 2248 2249 @note: Page permissions may be changed temporarily while writing. 2250 2251 @see: L{write_double} 2252 2253 @type lpBaseAddress: int 2254 @param lpBaseAddress: Memory address to begin writing. 2255 2256 @type unpackedValue: int, long 2257 @param unpackedValue: Value to write. 2258 2259 @rtype: int 2260 @return: Number of bytes written. 2261 May be less than the number of bytes to write. 2262 """ 2263 return self.__poke_c_type(lpBaseAddress, '@d', unpackedValue) 2264 2265 def peek_dword(self, lpBaseAddress): 2266 """ 2267 Reads a DWORD from the memory of the process. 2268 2269 @see: L{read_dword} 2270 2271 @type lpBaseAddress: int 2272 @param lpBaseAddress: Memory address to begin reading. 2273 2274 @rtype: int 2275 @return: Integer value read from the process memory. 2276 Returns zero on error. 2277 """ 2278 return self.__peek_c_type(lpBaseAddress, '=L', win32.DWORD) 2279 2280 def poke_dword(self, lpBaseAddress, unpackedValue): 2281 """ 2282 Writes a DWORD to the memory of the process. 2283 2284 @note: Page permissions may be changed temporarily while writing. 2285 2286 @see: L{write_dword} 2287 2288 @type lpBaseAddress: int 2289 @param lpBaseAddress: Memory address to begin writing. 2290 2291 @type unpackedValue: int, long 2292 @param unpackedValue: Value to write. 2293 2294 @rtype: int 2295 @return: Number of bytes written. 2296 May be less than the number of bytes to write. 2297 """ 2298 return self.__poke_c_type(lpBaseAddress, '=L', unpackedValue) 2299 2300 def peek_qword(self, lpBaseAddress): 2301 """ 2302 Reads a QWORD from the memory of the process. 2303 2304 @see: L{read_qword} 2305 2306 @type lpBaseAddress: int 2307 @param lpBaseAddress: Memory address to begin reading. 2308 2309 @rtype: int 2310 @return: Integer value read from the process memory. 2311 Returns zero on error. 2312 """ 2313 return self.__peek_c_type(lpBaseAddress, '=Q', win32.QWORD) 2314 2315 def poke_qword(self, lpBaseAddress, unpackedValue): 2316 """ 2317 Writes a QWORD to the memory of the process. 2318 2319 @note: Page permissions may be changed temporarily while writing. 2320 2321 @see: L{write_qword} 2322 2323 @type lpBaseAddress: int 2324 @param lpBaseAddress: Memory address to begin writing. 2325 2326 @type unpackedValue: int, long 2327 @param unpackedValue: Value to write. 2328 2329 @rtype: int 2330 @return: Number of bytes written. 2331 May be less than the number of bytes to write. 2332 """ 2333 return self.__poke_c_type(lpBaseAddress, '=Q', unpackedValue) 2334 2335 def peek_pointer(self, lpBaseAddress): 2336 """ 2337 Reads a pointer value from the memory of the process. 2338 2339 @see: L{read_pointer} 2340 2341 @type lpBaseAddress: int 2342 @param lpBaseAddress: Memory address to begin reading. 2343 2344 @rtype: int 2345 @return: Pointer value read from the process memory. 2346 Returns zero on error. 2347 """ 2348 return self.__peek_c_type(lpBaseAddress, '@P', ctypes.c_void_p) 2349 2350 def poke_pointer(self, lpBaseAddress, unpackedValue): 2351 """ 2352 Writes a pointer value to the memory of the process. 2353 2354 @note: Page permissions may be changed temporarily while writing. 2355 2356 @see: L{write_pointer} 2357 2358 @type lpBaseAddress: int 2359 @param lpBaseAddress: Memory address to begin writing. 2360 2361 @type unpackedValue: int, long 2362 @param unpackedValue: Value to write. 2363 2364 @rtype: int 2365 @return: Number of bytes written. 2366 May be less than the number of bytes to write. 2367 """ 2368 return self.__poke_c_type(lpBaseAddress, '@P', unpackedValue) 2369 2370 def peek_string(self, lpBaseAddress, fUnicode = False, dwMaxSize = 0x1000): 2371 """ 2372 Tries to read an ASCII or Unicode string 2373 from the address space of the process. 2374 2375 @see: L{read_string} 2376 2377 @type lpBaseAddress: int 2378 @param lpBaseAddress: Memory address to begin reading. 2379 2380 @type fUnicode: bool 2381 @param fUnicode: C{True} is the string is expected to be Unicode, 2382 C{False} if it's expected to be ANSI. 2383 2384 @type dwMaxSize: int 2385 @param dwMaxSize: Maximum allowed string length to read, in bytes. 2386 2387 @rtype: str, compat.unicode 2388 @return: String read from the process memory space. 2389 It B{doesn't} include the terminating null character. 2390 Returns an empty string on failure. 2391 """ 2392 2393 # Validate the parameters. 2394 if not lpBaseAddress or dwMaxSize == 0: 2395 if fUnicode: 2396 return u'' 2397 return '' 2398 if not dwMaxSize: 2399 dwMaxSize = 0x1000 2400 2401 # Read the string. 2402 szString = self.peek(lpBaseAddress, dwMaxSize) 2403 2404 # If the string is Unicode... 2405 if fUnicode: 2406 2407 # Decode the string. 2408 szString = compat.unicode(szString, 'U16', 'replace') 2409## try: 2410## szString = compat.unicode(szString, 'U16') 2411## except UnicodeDecodeError: 2412## szString = struct.unpack('H' * (len(szString) / 2), szString) 2413## szString = [ unichr(c) for c in szString ] 2414## szString = u''.join(szString) 2415 2416 # Truncate the string when the first null char is found. 2417 szString = szString[ : szString.find(u'\0') ] 2418 2419 # If the string is ANSI... 2420 else: 2421 2422 # Truncate the string when the first null char is found. 2423 szString = szString[ : szString.find('\0') ] 2424 2425 # Return the decoded string. 2426 return szString 2427 2428 # TODO 2429 # try to avoid reading the same page twice by caching it 2430 def peek_pointers_in_data(self, data, peekSize = 16, peekStep = 1): 2431 """ 2432 Tries to guess which values in the given data are valid pointers, 2433 and reads some data from them. 2434 2435 @see: L{peek} 2436 2437 @type data: str 2438 @param data: Binary data to find pointers in. 2439 2440 @type peekSize: int 2441 @param peekSize: Number of bytes to read from each pointer found. 2442 2443 @type peekStep: int 2444 @param peekStep: Expected data alignment. 2445 Tipically you specify 1 when data alignment is unknown, 2446 or 4 when you expect data to be DWORD aligned. 2447 Any other value may be specified. 2448 2449 @rtype: dict( str S{->} str ) 2450 @return: Dictionary mapping stack offsets to the data they point to. 2451 """ 2452 result = dict() 2453 ptrSize = win32.sizeof(win32.LPVOID) 2454 if ptrSize == 4: 2455 ptrFmt = '<L' 2456 else: 2457 ptrFmt = '<Q' 2458 if len(data) > 0: 2459 for i in compat.xrange(0, len(data), peekStep): 2460 packed = data[i:i+ptrSize] 2461 if len(packed) == ptrSize: 2462 address = struct.unpack(ptrFmt, packed)[0] 2463## if not address & (~0xFFFF): continue 2464 peek_data = self.peek(address, peekSize) 2465 if peek_data: 2466 result[i] = peek_data 2467 return result 2468 2469#------------------------------------------------------------------------------ 2470 2471 def malloc(self, dwSize, lpAddress = None): 2472 """ 2473 Allocates memory into the address space of the process. 2474 2475 @see: L{free} 2476 2477 @type dwSize: int 2478 @param dwSize: Number of bytes to allocate. 2479 2480 @type lpAddress: int 2481 @param lpAddress: (Optional) 2482 Desired address for the newly allocated memory. 2483 This is only a hint, the memory could still be allocated somewhere 2484 else. 2485 2486 @rtype: int 2487 @return: Address of the newly allocated memory. 2488 2489 @raise WindowsError: On error an exception is raised. 2490 """ 2491 hProcess = self.get_handle(win32.PROCESS_VM_OPERATION) 2492 return win32.VirtualAllocEx(hProcess, lpAddress, dwSize) 2493 2494 def mprotect(self, lpAddress, dwSize, flNewProtect): 2495 """ 2496 Set memory protection in the address space of the process. 2497 2498 @see: U{http://msdn.microsoft.com/en-us/library/aa366899.aspx} 2499 2500 @type lpAddress: int 2501 @param lpAddress: Address of memory to protect. 2502 2503 @type dwSize: int 2504 @param dwSize: Number of bytes to protect. 2505 2506 @type flNewProtect: int 2507 @param flNewProtect: New protect flags. 2508 2509 @rtype: int 2510 @return: Old protect flags. 2511 2512 @raise WindowsError: On error an exception is raised. 2513 """ 2514 hProcess = self.get_handle(win32.PROCESS_VM_OPERATION) 2515 return win32.VirtualProtectEx(hProcess, lpAddress, dwSize, flNewProtect) 2516 2517 def mquery(self, lpAddress): 2518 """ 2519 Query memory information from the address space of the process. 2520 Returns a L{win32.MemoryBasicInformation} object. 2521 2522 @see: U{http://msdn.microsoft.com/en-us/library/aa366907(VS.85).aspx} 2523 2524 @type lpAddress: int 2525 @param lpAddress: Address of memory to query. 2526 2527 @rtype: L{win32.MemoryBasicInformation} 2528 @return: Memory region information. 2529 2530 @raise WindowsError: On error an exception is raised. 2531 """ 2532 hProcess = self.get_handle(win32.PROCESS_QUERY_INFORMATION) 2533 return win32.VirtualQueryEx(hProcess, lpAddress) 2534 2535 def free(self, lpAddress): 2536 """ 2537 Frees memory from the address space of the process. 2538 2539 @see: U{http://msdn.microsoft.com/en-us/library/aa366894(v=vs.85).aspx} 2540 2541 @type lpAddress: int 2542 @param lpAddress: Address of memory to free. 2543 Must be the base address returned by L{malloc}. 2544 2545 @raise WindowsError: On error an exception is raised. 2546 """ 2547 hProcess = self.get_handle(win32.PROCESS_VM_OPERATION) 2548 win32.VirtualFreeEx(hProcess, lpAddress) 2549 2550#------------------------------------------------------------------------------ 2551 2552 def is_pointer(self, address): 2553 """ 2554 Determines if an address is a valid code or data pointer. 2555 2556 That is, the address must be valid and must point to code or data in 2557 the target process. 2558 2559 @type address: int 2560 @param address: Memory address to query. 2561 2562 @rtype: bool 2563 @return: C{True} if the address is a valid code or data pointer. 2564 2565 @raise WindowsError: An exception is raised on error. 2566 """ 2567 try: 2568 mbi = self.mquery(address) 2569 except WindowsError: 2570 e = sys.exc_info()[1] 2571 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2572 return False 2573 raise 2574 return mbi.has_content() 2575 2576 def is_address_valid(self, address): 2577 """ 2578 Determines if an address is a valid user mode address. 2579 2580 @type address: int 2581 @param address: Memory address to query. 2582 2583 @rtype: bool 2584 @return: C{True} if the address is a valid user mode address. 2585 2586 @raise WindowsError: An exception is raised on error. 2587 """ 2588 try: 2589 mbi = self.mquery(address) 2590 except WindowsError: 2591 e = sys.exc_info()[1] 2592 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2593 return False 2594 raise 2595 return True 2596 2597 def is_address_free(self, address): 2598 """ 2599 Determines if an address belongs to a free page. 2600 2601 @note: Returns always C{False} for kernel mode addresses. 2602 2603 @type address: int 2604 @param address: Memory address to query. 2605 2606 @rtype: bool 2607 @return: C{True} if the address belongs to a free page. 2608 2609 @raise WindowsError: An exception is raised on error. 2610 """ 2611 try: 2612 mbi = self.mquery(address) 2613 except WindowsError: 2614 e = sys.exc_info()[1] 2615 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2616 return False 2617 raise 2618 return mbi.is_free() 2619 2620 def is_address_reserved(self, address): 2621 """ 2622 Determines if an address belongs to a reserved page. 2623 2624 @note: Returns always C{False} for kernel mode addresses. 2625 2626 @type address: int 2627 @param address: Memory address to query. 2628 2629 @rtype: bool 2630 @return: C{True} if the address belongs to a reserved page. 2631 2632 @raise WindowsError: An exception is raised on error. 2633 """ 2634 try: 2635 mbi = self.mquery(address) 2636 except WindowsError: 2637 e = sys.exc_info()[1] 2638 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2639 return False 2640 raise 2641 return mbi.is_reserved() 2642 2643 def is_address_commited(self, address): 2644 """ 2645 Determines if an address belongs to a commited page. 2646 2647 @note: Returns always C{False} for kernel mode addresses. 2648 2649 @type address: int 2650 @param address: Memory address to query. 2651 2652 @rtype: bool 2653 @return: C{True} if the address belongs to a commited page. 2654 2655 @raise WindowsError: An exception is raised on error. 2656 """ 2657 try: 2658 mbi = self.mquery(address) 2659 except WindowsError: 2660 e = sys.exc_info()[1] 2661 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2662 return False 2663 raise 2664 return mbi.is_commited() 2665 2666 def is_address_guard(self, address): 2667 """ 2668 Determines if an address belongs to a guard page. 2669 2670 @note: Returns always C{False} for kernel mode addresses. 2671 2672 @type address: int 2673 @param address: Memory address to query. 2674 2675 @rtype: bool 2676 @return: C{True} if the address belongs to a guard page. 2677 2678 @raise WindowsError: An exception is raised on error. 2679 """ 2680 try: 2681 mbi = self.mquery(address) 2682 except WindowsError: 2683 e = sys.exc_info()[1] 2684 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2685 return False 2686 raise 2687 return mbi.is_guard() 2688 2689 def is_address_readable(self, address): 2690 """ 2691 Determines if an address belongs to a commited and readable page. 2692 The page may or may not have additional permissions. 2693 2694 @note: Returns always C{False} for kernel mode addresses. 2695 2696 @type address: int 2697 @param address: Memory address to query. 2698 2699 @rtype: bool 2700 @return: 2701 C{True} if the address belongs to a commited and readable page. 2702 2703 @raise WindowsError: An exception is raised on error. 2704 """ 2705 try: 2706 mbi = self.mquery(address) 2707 except WindowsError: 2708 e = sys.exc_info()[1] 2709 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2710 return False 2711 raise 2712 return mbi.is_readable() 2713 2714 def is_address_writeable(self, address): 2715 """ 2716 Determines if an address belongs to a commited and writeable page. 2717 The page may or may not have additional permissions. 2718 2719 @note: Returns always C{False} for kernel mode addresses. 2720 2721 @type address: int 2722 @param address: Memory address to query. 2723 2724 @rtype: bool 2725 @return: 2726 C{True} if the address belongs to a commited and writeable page. 2727 2728 @raise WindowsError: An exception is raised on error. 2729 """ 2730 try: 2731 mbi = self.mquery(address) 2732 except WindowsError: 2733 e = sys.exc_info()[1] 2734 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2735 return False 2736 raise 2737 return mbi.is_writeable() 2738 2739 def is_address_copy_on_write(self, address): 2740 """ 2741 Determines if an address belongs to a commited, copy-on-write page. 2742 The page may or may not have additional permissions. 2743 2744 @note: Returns always C{False} for kernel mode addresses. 2745 2746 @type address: int 2747 @param address: Memory address to query. 2748 2749 @rtype: bool 2750 @return: 2751 C{True} if the address belongs to a commited, copy-on-write page. 2752 2753 @raise WindowsError: An exception is raised on error. 2754 """ 2755 try: 2756 mbi = self.mquery(address) 2757 except WindowsError: 2758 e = sys.exc_info()[1] 2759 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2760 return False 2761 raise 2762 return mbi.is_copy_on_write() 2763 2764 def is_address_executable(self, address): 2765 """ 2766 Determines if an address belongs to a commited and executable page. 2767 The page may or may not have additional permissions. 2768 2769 @note: Returns always C{False} for kernel mode addresses. 2770 2771 @type address: int 2772 @param address: Memory address to query. 2773 2774 @rtype: bool 2775 @return: 2776 C{True} if the address belongs to a commited and executable page. 2777 2778 @raise WindowsError: An exception is raised on error. 2779 """ 2780 try: 2781 mbi = self.mquery(address) 2782 except WindowsError: 2783 e = sys.exc_info()[1] 2784 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2785 return False 2786 raise 2787 return mbi.is_executable() 2788 2789 def is_address_executable_and_writeable(self, address): 2790 """ 2791 Determines if an address belongs to a commited, writeable and 2792 executable page. The page may or may not have additional permissions. 2793 2794 Looking for writeable and executable pages is important when 2795 exploiting a software vulnerability. 2796 2797 @note: Returns always C{False} for kernel mode addresses. 2798 2799 @type address: int 2800 @param address: Memory address to query. 2801 2802 @rtype: bool 2803 @return: 2804 C{True} if the address belongs to a commited, writeable and 2805 executable page. 2806 2807 @raise WindowsError: An exception is raised on error. 2808 """ 2809 try: 2810 mbi = self.mquery(address) 2811 except WindowsError: 2812 e = sys.exc_info()[1] 2813 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2814 return False 2815 raise 2816 return mbi.is_executable_and_writeable() 2817 2818 def is_buffer(self, address, size): 2819 """ 2820 Determines if the given memory area is a valid code or data buffer. 2821 2822 @note: Returns always C{False} for kernel mode addresses. 2823 2824 @see: L{mquery} 2825 2826 @type address: int 2827 @param address: Memory address. 2828 2829 @type size: int 2830 @param size: Number of bytes. Must be greater than zero. 2831 2832 @rtype: bool 2833 @return: C{True} if the memory area is a valid code or data buffer, 2834 C{False} otherwise. 2835 2836 @raise ValueError: The size argument must be greater than zero. 2837 @raise WindowsError: On error an exception is raised. 2838 """ 2839 if size <= 0: 2840 raise ValueError("The size argument must be greater than zero") 2841 while size > 0: 2842 try: 2843 mbi = self.mquery(address) 2844 except WindowsError: 2845 e = sys.exc_info()[1] 2846 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2847 return False 2848 raise 2849 if not mbi.has_content(): 2850 return False 2851 size = size - mbi.RegionSize 2852 return True 2853 2854 def is_buffer_readable(self, address, size): 2855 """ 2856 Determines if the given memory area is readable. 2857 2858 @note: Returns always C{False} for kernel mode addresses. 2859 2860 @see: L{mquery} 2861 2862 @type address: int 2863 @param address: Memory address. 2864 2865 @type size: int 2866 @param size: Number of bytes. Must be greater than zero. 2867 2868 @rtype: bool 2869 @return: C{True} if the memory area is readable, C{False} otherwise. 2870 2871 @raise ValueError: The size argument must be greater than zero. 2872 @raise WindowsError: On error an exception is raised. 2873 """ 2874 if size <= 0: 2875 raise ValueError("The size argument must be greater than zero") 2876 while size > 0: 2877 try: 2878 mbi = self.mquery(address) 2879 except WindowsError: 2880 e = sys.exc_info()[1] 2881 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2882 return False 2883 raise 2884 if not mbi.is_readable(): 2885 return False 2886 size = size - mbi.RegionSize 2887 return True 2888 2889 def is_buffer_writeable(self, address, size): 2890 """ 2891 Determines if the given memory area is writeable. 2892 2893 @note: Returns always C{False} for kernel mode addresses. 2894 2895 @see: L{mquery} 2896 2897 @type address: int 2898 @param address: Memory address. 2899 2900 @type size: int 2901 @param size: Number of bytes. Must be greater than zero. 2902 2903 @rtype: bool 2904 @return: C{True} if the memory area is writeable, C{False} otherwise. 2905 2906 @raise ValueError: The size argument must be greater than zero. 2907 @raise WindowsError: On error an exception is raised. 2908 """ 2909 if size <= 0: 2910 raise ValueError("The size argument must be greater than zero") 2911 while size > 0: 2912 try: 2913 mbi = self.mquery(address) 2914 except WindowsError: 2915 e = sys.exc_info()[1] 2916 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2917 return False 2918 raise 2919 if not mbi.is_writeable(): 2920 return False 2921 size = size - mbi.RegionSize 2922 return True 2923 2924 def is_buffer_copy_on_write(self, address, size): 2925 """ 2926 Determines if the given memory area is marked as copy-on-write. 2927 2928 @note: Returns always C{False} for kernel mode addresses. 2929 2930 @see: L{mquery} 2931 2932 @type address: int 2933 @param address: Memory address. 2934 2935 @type size: int 2936 @param size: Number of bytes. Must be greater than zero. 2937 2938 @rtype: bool 2939 @return: C{True} if the memory area is marked as copy-on-write, 2940 C{False} otherwise. 2941 2942 @raise ValueError: The size argument must be greater than zero. 2943 @raise WindowsError: On error an exception is raised. 2944 """ 2945 if size <= 0: 2946 raise ValueError("The size argument must be greater than zero") 2947 while size > 0: 2948 try: 2949 mbi = self.mquery(address) 2950 except WindowsError: 2951 e = sys.exc_info()[1] 2952 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2953 return False 2954 raise 2955 if not mbi.is_copy_on_write(): 2956 return False 2957 size = size - mbi.RegionSize 2958 return True 2959 2960 def is_buffer_executable(self, address, size): 2961 """ 2962 Determines if the given memory area is executable. 2963 2964 @note: Returns always C{False} for kernel mode addresses. 2965 2966 @see: L{mquery} 2967 2968 @type address: int 2969 @param address: Memory address. 2970 2971 @type size: int 2972 @param size: Number of bytes. Must be greater than zero. 2973 2974 @rtype: bool 2975 @return: C{True} if the memory area is executable, C{False} otherwise. 2976 2977 @raise ValueError: The size argument must be greater than zero. 2978 @raise WindowsError: On error an exception is raised. 2979 """ 2980 if size <= 0: 2981 raise ValueError("The size argument must be greater than zero") 2982 while size > 0: 2983 try: 2984 mbi = self.mquery(address) 2985 except WindowsError: 2986 e = sys.exc_info()[1] 2987 if e.winerror == win32.ERROR_INVALID_PARAMETER: 2988 return False 2989 raise 2990 if not mbi.is_executable(): 2991 return False 2992 size = size - mbi.RegionSize 2993 return True 2994 2995 def is_buffer_executable_and_writeable(self, address, size): 2996 """ 2997 Determines if the given memory area is writeable and executable. 2998 2999 Looking for writeable and executable pages is important when 3000 exploiting a software vulnerability. 3001 3002 @note: Returns always C{False} for kernel mode addresses. 3003 3004 @see: L{mquery} 3005 3006 @type address: int 3007 @param address: Memory address. 3008 3009 @type size: int 3010 @param size: Number of bytes. Must be greater than zero. 3011 3012 @rtype: bool 3013 @return: C{True} if the memory area is writeable and executable, 3014 C{False} otherwise. 3015 3016 @raise ValueError: The size argument must be greater than zero. 3017 @raise WindowsError: On error an exception is raised. 3018 """ 3019 if size <= 0: 3020 raise ValueError("The size argument must be greater than zero") 3021 while size > 0: 3022 try: 3023 mbi = self.mquery(address) 3024 except WindowsError: 3025 e = sys.exc_info()[1] 3026 if e.winerror == win32.ERROR_INVALID_PARAMETER: 3027 return False 3028 raise 3029 if not mbi.is_executable(): 3030 return False 3031 size = size - mbi.RegionSize 3032 return True 3033 3034 def get_memory_map(self, minAddr = None, maxAddr = None): 3035 """ 3036 Produces a memory map to the process address space. 3037 3038 Optionally restrict the map to the given address range. 3039 3040 @see: L{mquery} 3041 3042 @type minAddr: int 3043 @param minAddr: (Optional) Starting address in address range to query. 3044 3045 @type maxAddr: int 3046 @param maxAddr: (Optional) Ending address in address range to query. 3047 3048 @rtype: list( L{win32.MemoryBasicInformation} ) 3049 @return: List of memory region information objects. 3050 """ 3051 return list(self.iter_memory_map(minAddr, maxAddr)) 3052 3053 def generate_memory_map(self, minAddr = None, maxAddr = None): 3054 """ 3055 Returns a L{Regenerator} that can iterate indefinitely over the memory 3056 map to the process address space. 3057 3058 Optionally restrict the map to the given address range. 3059 3060 @see: L{mquery} 3061 3062 @type minAddr: int 3063 @param minAddr: (Optional) Starting address in address range to query. 3064 3065 @type maxAddr: int 3066 @param maxAddr: (Optional) Ending address in address range to query. 3067 3068 @rtype: L{Regenerator} of L{win32.MemoryBasicInformation} 3069 @return: List of memory region information objects. 3070 """ 3071 return Regenerator(self.iter_memory_map, minAddr, maxAddr) 3072 3073 def iter_memory_map(self, minAddr = None, maxAddr = None): 3074 """ 3075 Produces an iterator over the memory map to the process address space. 3076 3077 Optionally restrict the map to the given address range. 3078 3079 @see: L{mquery} 3080 3081 @type minAddr: int 3082 @param minAddr: (Optional) Starting address in address range to query. 3083 3084 @type maxAddr: int 3085 @param maxAddr: (Optional) Ending address in address range to query. 3086 3087 @rtype: iterator of L{win32.MemoryBasicInformation} 3088 @return: List of memory region information objects. 3089 """ 3090 minAddr, maxAddr = MemoryAddresses.align_address_range(minAddr,maxAddr) 3091 prevAddr = minAddr - 1 3092 currentAddr = minAddr 3093 while prevAddr < currentAddr < maxAddr: 3094 try: 3095 mbi = self.mquery(currentAddr) 3096 except WindowsError: 3097 e = sys.exc_info()[1] 3098 if e.winerror == win32.ERROR_INVALID_PARAMETER: 3099 break 3100 raise 3101 yield mbi 3102 prevAddr = currentAddr 3103 currentAddr = mbi.BaseAddress + mbi.RegionSize 3104 3105 def get_mapped_filenames(self, memoryMap = None): 3106 """ 3107 Retrieves the filenames for memory mapped files in the debugee. 3108 3109 @type memoryMap: list( L{win32.MemoryBasicInformation} ) 3110 @param memoryMap: (Optional) Memory map returned by L{get_memory_map}. 3111 If not given, the current memory map is used. 3112 3113 @rtype: dict( int S{->} str ) 3114 @return: Dictionary mapping memory addresses to file names. 3115 Native filenames are converted to Win32 filenames when possible. 3116 """ 3117 hProcess = self.get_handle( win32.PROCESS_VM_READ | 3118 win32.PROCESS_QUERY_INFORMATION ) 3119 if not memoryMap: 3120 memoryMap = self.get_memory_map() 3121 mappedFilenames = dict() 3122 for mbi in memoryMap: 3123 if mbi.Type not in (win32.MEM_IMAGE, win32.MEM_MAPPED): 3124 continue 3125 baseAddress = mbi.BaseAddress 3126 fileName = "" 3127 try: 3128 fileName = win32.GetMappedFileName(hProcess, baseAddress) 3129 fileName = PathOperations.native_to_win32_pathname(fileName) 3130 except WindowsError: 3131 #e = sys.exc_info()[1] 3132 #try: 3133 # msg = "Can't get mapped file name at address %s in process " \ 3134 # "%d, reason: %s" % (HexDump.address(baseAddress), 3135 # self.get_pid(), 3136 # e.strerror) 3137 # warnings.warn(msg, Warning) 3138 #except Exception: 3139 pass 3140 mappedFilenames[baseAddress] = fileName 3141 return mappedFilenames 3142 3143 def generate_memory_snapshot(self, minAddr = None, maxAddr = None): 3144 """ 3145 Returns a L{Regenerator} that allows you to iterate through the memory 3146 contents of a process indefinitely. 3147 3148 It's basically the same as the L{take_memory_snapshot} method, but it 3149 takes the snapshot of each memory region as it goes, as opposed to 3150 taking the whole snapshot at once. This allows you to work with very 3151 large snapshots without a significant performance penalty. 3152 3153 Example:: 3154 # Print the memory contents of a process. 3155 process.suspend() 3156 try: 3157 snapshot = process.generate_memory_snapshot() 3158 for mbi in snapshot: 3159 print HexDump.hexblock(mbi.content, mbi.BaseAddress) 3160 finally: 3161 process.resume() 3162 3163 The downside of this is the process must remain suspended while 3164 iterating the snapshot, otherwise strange things may happen. 3165 3166 The snapshot can be iterated more than once. Each time it's iterated 3167 the memory contents of the process will be fetched again. 3168 3169 You can also iterate the memory of a dead process, just as long as the 3170 last open handle to it hasn't been closed. 3171 3172 @see: L{take_memory_snapshot} 3173 3174 @type minAddr: int 3175 @param minAddr: (Optional) Starting address in address range to query. 3176 3177 @type maxAddr: int 3178 @param maxAddr: (Optional) Ending address in address range to query. 3179 3180 @rtype: L{Regenerator} of L{win32.MemoryBasicInformation} 3181 @return: Generator that when iterated returns memory region information 3182 objects. Two extra properties are added to these objects: 3183 - C{filename}: Mapped filename, or C{None}. 3184 - C{content}: Memory contents, or C{None}. 3185 """ 3186 return Regenerator(self.iter_memory_snapshot, minAddr, maxAddr) 3187 3188 def iter_memory_snapshot(self, minAddr = None, maxAddr = None): 3189 """ 3190 Returns an iterator that allows you to go through the memory contents 3191 of a process. 3192 3193 It's basically the same as the L{take_memory_snapshot} method, but it 3194 takes the snapshot of each memory region as it goes, as opposed to 3195 taking the whole snapshot at once. This allows you to work with very 3196 large snapshots without a significant performance penalty. 3197 3198 Example:: 3199 # Print the memory contents of a process. 3200 process.suspend() 3201 try: 3202 snapshot = process.generate_memory_snapshot() 3203 for mbi in snapshot: 3204 print HexDump.hexblock(mbi.content, mbi.BaseAddress) 3205 finally: 3206 process.resume() 3207 3208 The downside of this is the process must remain suspended while 3209 iterating the snapshot, otherwise strange things may happen. 3210 3211 The snapshot can only iterated once. To be able to iterate indefinitely 3212 call the L{generate_memory_snapshot} method instead. 3213 3214 You can also iterate the memory of a dead process, just as long as the 3215 last open handle to it hasn't been closed. 3216 3217 @see: L{take_memory_snapshot} 3218 3219 @type minAddr: int 3220 @param minAddr: (Optional) Starting address in address range to query. 3221 3222 @type maxAddr: int 3223 @param maxAddr: (Optional) Ending address in address range to query. 3224 3225 @rtype: iterator of L{win32.MemoryBasicInformation} 3226 @return: Iterator of memory region information objects. 3227 Two extra properties are added to these objects: 3228 - C{filename}: Mapped filename, or C{None}. 3229 - C{content}: Memory contents, or C{None}. 3230 """ 3231 3232 # One may feel tempted to include calls to self.suspend() and 3233 # self.resume() here, but that wouldn't work on a dead process. 3234 # It also wouldn't be needed when debugging since the process is 3235 # already suspended when the debug event arrives. So it's up to 3236 # the user to suspend the process if needed. 3237 3238 # Get the memory map. 3239 memory = self.get_memory_map(minAddr, maxAddr) 3240 3241 # Abort if the map couldn't be retrieved. 3242 if not memory: 3243 return 3244 3245 # Get the mapped filenames. 3246 # Don't fail on access denied errors. 3247 try: 3248 filenames = self.get_mapped_filenames(memory) 3249 except WindowsError: 3250 e = sys.exc_info()[1] 3251 if e.winerror != win32.ERROR_ACCESS_DENIED: 3252 raise 3253 filenames = dict() 3254 3255 # Trim the first memory information block if needed. 3256 if minAddr is not None: 3257 minAddr = MemoryAddresses.align_address_to_page_start(minAddr) 3258 mbi = memory[0] 3259 if mbi.BaseAddress < minAddr: 3260 mbi.RegionSize = mbi.BaseAddress + mbi.RegionSize - minAddr 3261 mbi.BaseAddress = minAddr 3262 3263 # Trim the last memory information block if needed. 3264 if maxAddr is not None: 3265 if maxAddr != MemoryAddresses.align_address_to_page_start(maxAddr): 3266 maxAddr = MemoryAddresses.align_address_to_page_end(maxAddr) 3267 mbi = memory[-1] 3268 if mbi.BaseAddress + mbi.RegionSize > maxAddr: 3269 mbi.RegionSize = maxAddr - mbi.BaseAddress 3270 3271 # Read the contents of each block and yield it. 3272 while memory: 3273 mbi = memory.pop(0) # so the garbage collector can take it 3274 mbi.filename = filenames.get(mbi.BaseAddress, None) 3275 if mbi.has_content(): 3276 mbi.content = self.read(mbi.BaseAddress, mbi.RegionSize) 3277 else: 3278 mbi.content = None 3279 yield mbi 3280 3281 def take_memory_snapshot(self, minAddr = None, maxAddr = None): 3282 """ 3283 Takes a snapshot of the memory contents of the process. 3284 3285 It's best if the process is suspended (if alive) when taking the 3286 snapshot. Execution can be resumed afterwards. 3287 3288 Example:: 3289 # Print the memory contents of a process. 3290 process.suspend() 3291 try: 3292 snapshot = process.take_memory_snapshot() 3293 for mbi in snapshot: 3294 print HexDump.hexblock(mbi.content, mbi.BaseAddress) 3295 finally: 3296 process.resume() 3297 3298 You can also iterate the memory of a dead process, just as long as the 3299 last open handle to it hasn't been closed. 3300 3301 @warning: If the target process has a very big memory footprint, the 3302 resulting snapshot will be equally big. This may result in a severe 3303 performance penalty. 3304 3305 @see: L{generate_memory_snapshot} 3306 3307 @type minAddr: int 3308 @param minAddr: (Optional) Starting address in address range to query. 3309 3310 @type maxAddr: int 3311 @param maxAddr: (Optional) Ending address in address range to query. 3312 3313 @rtype: list( L{win32.MemoryBasicInformation} ) 3314 @return: List of memory region information objects. 3315 Two extra properties are added to these objects: 3316 - C{filename}: Mapped filename, or C{None}. 3317 - C{content}: Memory contents, or C{None}. 3318 """ 3319 return list( self.iter_memory_snapshot(minAddr, maxAddr) ) 3320 3321 def restore_memory_snapshot(self, snapshot, 3322 bSkipMappedFiles = True, 3323 bSkipOnError = False): 3324 """ 3325 Attempts to restore the memory state as it was when the given snapshot 3326 was taken. 3327 3328 @warning: Currently only the memory contents, state and protect bits 3329 are restored. Under some circumstances this method may fail (for 3330 example if memory was freed and then reused by a mapped file). 3331 3332 @type snapshot: list( L{win32.MemoryBasicInformation} ) 3333 @param snapshot: Memory snapshot returned by L{take_memory_snapshot}. 3334 Snapshots returned by L{generate_memory_snapshot} don't work here. 3335 3336 @type bSkipMappedFiles: bool 3337 @param bSkipMappedFiles: C{True} to avoid restoring the contents of 3338 memory mapped files, C{False} otherwise. Use with care! Setting 3339 this to C{False} can cause undesired side effects - changes to 3340 memory mapped files may be written to disk by the OS. Also note 3341 that most mapped files are typically executables and don't change, 3342 so trying to restore their contents is usually a waste of time. 3343 3344 @type bSkipOnError: bool 3345 @param bSkipOnError: C{True} to issue a warning when an error occurs 3346 during the restoration of the snapshot, C{False} to stop and raise 3347 an exception instead. Use with care! Setting this to C{True} will 3348 cause the debugger to falsely believe the memory snapshot has been 3349 correctly restored. 3350 3351 @raise WindowsError: An error occured while restoring the snapshot. 3352 @raise RuntimeError: An error occured while restoring the snapshot. 3353 @raise TypeError: A snapshot of the wrong type was passed. 3354 """ 3355 if not snapshot or not isinstance(snapshot, list) \ 3356 or not isinstance(snapshot[0], win32.MemoryBasicInformation): 3357 raise TypeError( "Only snapshots returned by " \ 3358 "take_memory_snapshot() can be used here." ) 3359 3360 # Get the process handle. 3361 hProcess = self.get_handle( win32.PROCESS_VM_WRITE | 3362 win32.PROCESS_VM_OPERATION | 3363 win32.PROCESS_SUSPEND_RESUME | 3364 win32.PROCESS_QUERY_INFORMATION ) 3365 3366 # Freeze the process. 3367 self.suspend() 3368 try: 3369 3370 # For each memory region in the snapshot... 3371 for old_mbi in snapshot: 3372 3373 # If the region matches, restore it directly. 3374 new_mbi = self.mquery(old_mbi.BaseAddress) 3375 if new_mbi.BaseAddress == old_mbi.BaseAddress and \ 3376 new_mbi.RegionSize == old_mbi.RegionSize: 3377 self.__restore_mbi(hProcess, new_mbi, old_mbi, 3378 bSkipMappedFiles) 3379 3380 # If the region doesn't match, restore it page by page. 3381 else: 3382 3383 # We need a copy so we don't corrupt the snapshot. 3384 old_mbi = win32.MemoryBasicInformation(old_mbi) 3385 3386 # Get the overlapping range of pages. 3387 old_start = old_mbi.BaseAddress 3388 old_end = old_start + old_mbi.RegionSize 3389 new_start = new_mbi.BaseAddress 3390 new_end = new_start + new_mbi.RegionSize 3391 if old_start > new_start: 3392 start = old_start 3393 else: 3394 start = new_start 3395 if old_end < new_end: 3396 end = old_end 3397 else: 3398 end = new_end 3399 3400 # Restore each page in the overlapping range. 3401 step = MemoryAddresses.pageSize 3402 old_mbi.RegionSize = step 3403 new_mbi.RegionSize = step 3404 address = start 3405 while address < end: 3406 old_mbi.BaseAddress = address 3407 new_mbi.BaseAddress = address 3408 self.__restore_mbi(hProcess, new_mbi, old_mbi, 3409 bSkipMappedFiles, bSkipOnError) 3410 address = address + step 3411 3412 # Resume execution. 3413 finally: 3414 self.resume() 3415 3416 def __restore_mbi(self, hProcess, new_mbi, old_mbi, bSkipMappedFiles, 3417 bSkipOnError): 3418 """ 3419 Used internally by L{restore_memory_snapshot}. 3420 """ 3421 3422## print "Restoring %s-%s" % ( 3423## HexDump.address(old_mbi.BaseAddress, self.get_bits()), 3424## HexDump.address(old_mbi.BaseAddress + old_mbi.RegionSize, 3425## self.get_bits())) 3426 3427 try: 3428 3429 # Restore the region state. 3430 if new_mbi.State != old_mbi.State: 3431 if new_mbi.is_free(): 3432 if old_mbi.is_reserved(): 3433 3434 # Free -> Reserved 3435 address = win32.VirtualAllocEx(hProcess, 3436 old_mbi.BaseAddress, 3437 old_mbi.RegionSize, 3438 win32.MEM_RESERVE, 3439 old_mbi.Protect) 3440 if address != old_mbi.BaseAddress: 3441 self.free(address) 3442 msg = "Error restoring region at address %s" 3443 msg = msg % HexDump(old_mbi.BaseAddress, 3444 self.get_bits()) 3445 raise RuntimeError(msg) 3446 # permissions already restored 3447 new_mbi.Protect = old_mbi.Protect 3448 3449 else: # elif old_mbi.is_commited(): 3450 3451 # Free -> Commited 3452 address = win32.VirtualAllocEx(hProcess, 3453 old_mbi.BaseAddress, 3454 old_mbi.RegionSize, 3455 win32.MEM_RESERVE | \ 3456 win32.MEM_COMMIT, 3457 old_mbi.Protect) 3458 if address != old_mbi.BaseAddress: 3459 self.free(address) 3460 msg = "Error restoring region at address %s" 3461 msg = msg % HexDump(old_mbi.BaseAddress, 3462 self.get_bits()) 3463 raise RuntimeError(msg) 3464 # permissions already restored 3465 new_mbi.Protect = old_mbi.Protect 3466 3467 elif new_mbi.is_reserved(): 3468 if old_mbi.is_commited(): 3469 3470 # Reserved -> Commited 3471 address = win32.VirtualAllocEx(hProcess, 3472 old_mbi.BaseAddress, 3473 old_mbi.RegionSize, 3474 win32.MEM_COMMIT, 3475 old_mbi.Protect) 3476 if address != old_mbi.BaseAddress: 3477 self.free(address) 3478 msg = "Error restoring region at address %s" 3479 msg = msg % HexDump(old_mbi.BaseAddress, 3480 self.get_bits()) 3481 raise RuntimeError(msg) 3482 # permissions already restored 3483 new_mbi.Protect = old_mbi.Protect 3484 3485 else: # elif old_mbi.is_free(): 3486 3487 # Reserved -> Free 3488 win32.VirtualFreeEx(hProcess, 3489 old_mbi.BaseAddress, 3490 old_mbi.RegionSize, 3491 win32.MEM_RELEASE) 3492 3493 else: # elif new_mbi.is_commited(): 3494 if old_mbi.is_reserved(): 3495 3496 # Commited -> Reserved 3497 win32.VirtualFreeEx(hProcess, 3498 old_mbi.BaseAddress, 3499 old_mbi.RegionSize, 3500 win32.MEM_DECOMMIT) 3501 3502 else: # elif old_mbi.is_free(): 3503 3504 # Commited -> Free 3505 win32.VirtualFreeEx(hProcess, 3506 old_mbi.BaseAddress, 3507 old_mbi.RegionSize, 3508 win32.MEM_DECOMMIT | win32.MEM_RELEASE) 3509 3510 new_mbi.State = old_mbi.State 3511 3512 # Restore the region permissions. 3513 if old_mbi.is_commited() and old_mbi.Protect != new_mbi.Protect: 3514 win32.VirtualProtectEx(hProcess, old_mbi.BaseAddress, 3515 old_mbi.RegionSize, old_mbi.Protect) 3516 new_mbi.Protect = old_mbi.Protect 3517 3518 # Restore the region data. 3519 # Ignore write errors when the region belongs to a mapped file. 3520 if old_mbi.has_content(): 3521 if old_mbi.Type != 0: 3522 if not bSkipMappedFiles: 3523 self.poke(old_mbi.BaseAddress, old_mbi.content) 3524 else: 3525 self.write(old_mbi.BaseAddress, old_mbi.content) 3526 new_mbi.content = old_mbi.content 3527 3528 # On error, skip this region or raise an exception. 3529 except Exception: 3530 if not bSkipOnError: 3531 raise 3532 msg = "Error restoring region at address %s: %s" 3533 msg = msg % ( 3534 HexDump(old_mbi.BaseAddress, self.get_bits()), 3535 traceback.format_exc()) 3536 warnings.warn(msg, RuntimeWarning) 3537 3538#------------------------------------------------------------------------------ 3539 3540 def inject_code(self, payload, lpParameter = 0): 3541 """ 3542 Injects relocatable code into the process memory and executes it. 3543 3544 @warning: Don't forget to free the memory when you're done with it! 3545 Otherwise you'll be leaking memory in the target process. 3546 3547 @see: L{inject_dll} 3548 3549 @type payload: str 3550 @param payload: Relocatable code to run in a new thread. 3551 3552 @type lpParameter: int 3553 @param lpParameter: (Optional) Parameter to be pushed in the stack. 3554 3555 @rtype: tuple( L{Thread}, int ) 3556 @return: The injected Thread object 3557 and the memory address where the code was written. 3558 3559 @raise WindowsError: An exception is raised on error. 3560 """ 3561 3562 # Uncomment for debugging... 3563## payload = '\xCC' + payload 3564 3565 # Allocate the memory for the shellcode. 3566 lpStartAddress = self.malloc(len(payload)) 3567 3568 # Catch exceptions so we can free the memory on error. 3569 try: 3570 3571 # Write the shellcode to our memory location. 3572 self.write(lpStartAddress, payload) 3573 3574 # Start a new thread for the shellcode to run. 3575 aThread = self.start_thread(lpStartAddress, lpParameter, 3576 bSuspended = False) 3577 3578 # Remember the shellcode address. 3579 # It will be freed ONLY by the Thread.kill() method 3580 # and the EventHandler class, otherwise you'll have to 3581 # free it in your code, or have your shellcode clean up 3582 # after itself (recommended). 3583 aThread.pInjectedMemory = lpStartAddress 3584 3585 # Free the memory on error. 3586 except Exception: 3587 self.free(lpStartAddress) 3588 raise 3589 3590 # Return the Thread object and the shellcode address. 3591 return aThread, lpStartAddress 3592 3593 # TODO 3594 # The shellcode should check for errors, otherwise it just crashes 3595 # when the DLL can't be loaded or the procedure can't be found. 3596 # On error the shellcode should execute an int3 instruction. 3597 def inject_dll(self, dllname, procname = None, lpParameter = 0, 3598 bWait = True, dwTimeout = None): 3599 """ 3600 Injects a DLL into the process memory. 3601 3602 @warning: Setting C{bWait} to C{True} when the process is frozen by a 3603 debug event will cause a deadlock in your debugger. 3604 3605 @warning: This involves allocating memory in the target process. 3606 This is how the freeing of this memory is handled: 3607 3608 - If the C{bWait} flag is set to C{True} the memory will be freed 3609 automatically before returning from this method. 3610 - If the C{bWait} flag is set to C{False}, the memory address is 3611 set as the L{Thread.pInjectedMemory} property of the returned 3612 thread object. 3613 - L{Debug} objects free L{Thread.pInjectedMemory} automatically 3614 both when it detaches from a process and when the injected 3615 thread finishes its execution. 3616 - The {Thread.kill} method also frees L{Thread.pInjectedMemory} 3617 automatically, even if you're not attached to the process. 3618 3619 You could still be leaking memory if not careful. For example, if 3620 you inject a dll into a process you're not attached to, you don't 3621 wait for the thread's completion and you don't kill it either, the 3622 memory would be leaked. 3623 3624 @see: L{inject_code} 3625 3626 @type dllname: str 3627 @param dllname: Name of the DLL module to load. 3628 3629 @type procname: str 3630 @param procname: (Optional) Procedure to call when the DLL is loaded. 3631 3632 @type lpParameter: int 3633 @param lpParameter: (Optional) Parameter to the C{procname} procedure. 3634 3635 @type bWait: bool 3636 @param bWait: C{True} to wait for the process to finish. 3637 C{False} to return immediately. 3638 3639 @type dwTimeout: int 3640 @param dwTimeout: (Optional) Timeout value in milliseconds. 3641 Ignored if C{bWait} is C{False}. 3642 3643 @rtype: L{Thread} 3644 @return: Newly created thread object. If C{bWait} is set to C{True} the 3645 thread will be dead, otherwise it will be alive. 3646 3647 @raise NotImplementedError: The target platform is not supported. 3648 Currently calling a procedure in the library is only supported in 3649 the I{i386} architecture. 3650 3651 @raise WindowsError: An exception is raised on error. 3652 """ 3653 3654 # Resolve kernel32.dll 3655 aModule = self.get_module_by_name(compat.b('kernel32.dll')) 3656 if aModule is None: 3657 self.scan_modules() 3658 aModule = self.get_module_by_name(compat.b('kernel32.dll')) 3659 if aModule is None: 3660 raise RuntimeError( 3661 "Cannot resolve kernel32.dll in the remote process") 3662 3663 # Old method, using shellcode. 3664 if procname: 3665 if self.get_arch() != win32.ARCH_I386: 3666 raise NotImplementedError() 3667 dllname = compat.b(dllname) 3668 3669 # Resolve kernel32.dll!LoadLibraryA 3670 pllib = aModule.resolve(compat.b('LoadLibraryA')) 3671 if not pllib: 3672 raise RuntimeError( 3673 "Cannot resolve kernel32.dll!LoadLibraryA" 3674 " in the remote process") 3675 3676 # Resolve kernel32.dll!GetProcAddress 3677 pgpad = aModule.resolve(compat.b('GetProcAddress')) 3678 if not pgpad: 3679 raise RuntimeError( 3680 "Cannot resolve kernel32.dll!GetProcAddress" 3681 " in the remote process") 3682 3683 # Resolve kernel32.dll!VirtualFree 3684 pvf = aModule.resolve(compat.b('VirtualFree')) 3685 if not pvf: 3686 raise RuntimeError( 3687 "Cannot resolve kernel32.dll!VirtualFree" 3688 " in the remote process") 3689 3690 # Shellcode follows... 3691 code = compat.b('') 3692 3693 # push dllname 3694 code += compat.b('\xe8') + struct.pack('<L', len(dllname) + 1) + dllname + compat.b('\0') 3695 3696 # mov eax, LoadLibraryA 3697 code += compat.b('\xb8') + struct.pack('<L', pllib) 3698 3699 # call eax 3700 code += compat.b('\xff\xd0') 3701 3702 if procname: 3703 3704 # push procname 3705 code += compat.b('\xe8') + struct.pack('<L', len(procname) + 1) 3706 code += procname + compat.b('\0') 3707 3708 # push eax 3709 code += compat.b('\x50') 3710 3711 # mov eax, GetProcAddress 3712 code += compat.b('\xb8') + struct.pack('<L', pgpad) 3713 3714 # call eax 3715 code += compat.b('\xff\xd0') 3716 3717 # mov ebp, esp ; preserve stack pointer 3718 code += compat.b('\x8b\xec') 3719 3720 # push lpParameter 3721 code += compat.b('\x68') + struct.pack('<L', lpParameter) 3722 3723 # call eax 3724 code += compat.b('\xff\xd0') 3725 3726 # mov esp, ebp ; restore stack pointer 3727 code += compat.b('\x8b\xe5') 3728 3729 # pop edx ; our own return address 3730 code += compat.b('\x5a') 3731 3732 # push MEM_RELEASE ; dwFreeType 3733 code += compat.b('\x68') + struct.pack('<L', win32.MEM_RELEASE) 3734 3735 # push 0x1000 ; dwSize, shellcode max size 4096 bytes 3736 code += compat.b('\x68') + struct.pack('<L', 0x1000) 3737 3738 # call $+5 3739 code += compat.b('\xe8\x00\x00\x00\x00') 3740 3741 # and dword ptr [esp], 0xFFFFF000 ; align to page boundary 3742 code += compat.b('\x81\x24\x24\x00\xf0\xff\xff') 3743 3744 # mov eax, VirtualFree 3745 code += compat.b('\xb8') + struct.pack('<L', pvf) 3746 3747 # push edx ; our own return address 3748 code += compat.b('\x52') 3749 3750 # jmp eax ; VirtualFree will return to our own return address 3751 code += compat.b('\xff\xe0') 3752 3753 # Inject the shellcode. 3754 # There's no need to free the memory, 3755 # because the shellcode will free it itself. 3756 aThread, lpStartAddress = self.inject_code(code, lpParameter) 3757 3758 # New method, not using shellcode. 3759 else: 3760 3761 # Resolve kernel32.dll!LoadLibrary (A/W) 3762 if type(dllname) == type(u''): 3763 pllibname = compat.b('LoadLibraryW') 3764 bufferlen = (len(dllname) + 1) * 2 3765 dllname = win32.ctypes.create_unicode_buffer(dllname).raw[:bufferlen + 1] 3766 else: 3767 pllibname = compat.b('LoadLibraryA') 3768 dllname = compat.b(dllname) + compat.b('\x00') 3769 bufferlen = len(dllname) 3770 pllib = aModule.resolve(pllibname) 3771 if not pllib: 3772 msg = "Cannot resolve kernel32.dll!%s in the remote process" 3773 raise RuntimeError(msg % pllibname) 3774 3775 # Copy the library name into the process memory space. 3776 pbuffer = self.malloc(bufferlen) 3777 try: 3778 self.write(pbuffer, dllname) 3779 3780 # Create a new thread to load the library. 3781 try: 3782 aThread = self.start_thread(pllib, pbuffer) 3783 except WindowsError: 3784 e = sys.exc_info()[1] 3785 if e.winerror != win32.ERROR_NOT_ENOUGH_MEMORY: 3786 raise 3787 3788 # This specific error is caused by trying to spawn a new 3789 # thread in a process belonging to a different Terminal 3790 # Services session (for example a service). 3791 raise NotImplementedError( 3792 "Target process belongs to a different" 3793 " Terminal Services session, cannot inject!" 3794 ) 3795 3796 # Remember the buffer address. 3797 # It will be freed ONLY by the Thread.kill() method 3798 # and the EventHandler class, otherwise you'll have to 3799 # free it in your code. 3800 aThread.pInjectedMemory = pbuffer 3801 3802 # Free the memory on error. 3803 except Exception: 3804 self.free(pbuffer) 3805 raise 3806 3807 # Wait for the thread to finish. 3808 if bWait: 3809 aThread.wait(dwTimeout) 3810 self.free(aThread.pInjectedMemory) 3811 del aThread.pInjectedMemory 3812 3813 # Return the thread object. 3814 return aThread 3815 3816 def clean_exit(self, dwExitCode = 0, bWait = False, dwTimeout = None): 3817 """ 3818 Injects a new thread to call ExitProcess(). 3819 Optionally waits for the injected thread to finish. 3820 3821 @warning: Setting C{bWait} to C{True} when the process is frozen by a 3822 debug event will cause a deadlock in your debugger. 3823 3824 @type dwExitCode: int 3825 @param dwExitCode: Process exit code. 3826 3827 @type bWait: bool 3828 @param bWait: C{True} to wait for the process to finish. 3829 C{False} to return immediately. 3830 3831 @type dwTimeout: int 3832 @param dwTimeout: (Optional) Timeout value in milliseconds. 3833 Ignored if C{bWait} is C{False}. 3834 3835 @raise WindowsError: An exception is raised on error. 3836 """ 3837 if not dwExitCode: 3838 dwExitCode = 0 3839 pExitProcess = self.resolve_label('kernel32!ExitProcess') 3840 aThread = self.start_thread(pExitProcess, dwExitCode) 3841 if bWait: 3842 aThread.wait(dwTimeout) 3843 3844#------------------------------------------------------------------------------ 3845 3846 def _notify_create_process(self, event): 3847 """ 3848 Notify the creation of a new process. 3849 3850 This is done automatically by the L{Debug} class, you shouldn't need 3851 to call it yourself. 3852 3853 @type event: L{CreateProcessEvent} 3854 @param event: Create process event. 3855 3856 @rtype: bool 3857 @return: C{True} to call the user-defined handle, C{False} otherwise. 3858 """ 3859 # Do not use super() here. 3860 bCallHandler = _ThreadContainer._notify_create_process(self, event) 3861 bCallHandler = bCallHandler and \ 3862 _ModuleContainer._notify_create_process(self, event) 3863 return bCallHandler 3864 3865#============================================================================== 3866 3867class _ProcessContainer (object): 3868 """ 3869 Encapsulates the capability to contain Process objects. 3870 3871 @group Instrumentation: 3872 start_process, argv_to_cmdline, cmdline_to_argv, get_explorer_pid 3873 3874 @group Processes snapshot: 3875 scan, scan_processes, scan_processes_fast, 3876 get_process, get_process_count, get_process_ids, 3877 has_process, iter_processes, iter_process_ids, 3878 find_processes_by_filename, get_pid_from_tid, 3879 get_windows, 3880 scan_process_filenames, 3881 clear, clear_processes, clear_dead_processes, 3882 clear_unattached_processes, 3883 close_process_handles, 3884 close_process_and_thread_handles 3885 3886 @group Threads snapshots: 3887 scan_processes_and_threads, 3888 get_thread, get_thread_count, get_thread_ids, 3889 has_thread 3890 3891 @group Modules snapshots: 3892 scan_modules, find_modules_by_address, 3893 find_modules_by_base, find_modules_by_name, 3894 get_module_count 3895 """ 3896 3897 def __init__(self): 3898 self.__processDict = dict() 3899 3900 def __initialize_snapshot(self): 3901 """ 3902 Private method to automatically initialize the snapshot 3903 when you try to use it without calling any of the scan_* 3904 methods first. You don't need to call this yourself. 3905 """ 3906 if not self.__processDict: 3907 try: 3908 self.scan_processes() # remote desktop api (relative fn) 3909 except Exception: 3910 self.scan_processes_fast() # psapi (no filenames) 3911 self.scan_process_filenames() # get the pathnames when possible 3912 3913 def __contains__(self, anObject): 3914 """ 3915 @type anObject: L{Process}, L{Thread}, int 3916 @param anObject: 3917 - C{int}: Global ID of the process to look for. 3918 - C{int}: Global ID of the thread to look for. 3919 - C{Process}: Process object to look for. 3920 - C{Thread}: Thread object to look for. 3921 3922 @rtype: bool 3923 @return: C{True} if the snapshot contains 3924 a L{Process} or L{Thread} object with the same ID. 3925 """ 3926 if isinstance(anObject, Process): 3927 anObject = anObject.dwProcessId 3928 if self.has_process(anObject): 3929 return True 3930 for aProcess in self.iter_processes(): 3931 if anObject in aProcess: 3932 return True 3933 return False 3934 3935 def __iter__(self): 3936 """ 3937 @see: L{iter_processes} 3938 @rtype: dictionary-valueiterator 3939 @return: Iterator of L{Process} objects in this snapshot. 3940 """ 3941 return self.iter_processes() 3942 3943 def __len__(self): 3944 """ 3945 @see: L{get_process_count} 3946 @rtype: int 3947 @return: Count of L{Process} objects in this snapshot. 3948 """ 3949 return self.get_process_count() 3950 3951 def has_process(self, dwProcessId): 3952 """ 3953 @type dwProcessId: int 3954 @param dwProcessId: Global ID of the process to look for. 3955 3956 @rtype: bool 3957 @return: C{True} if the snapshot contains a 3958 L{Process} object with the given global ID. 3959 """ 3960 self.__initialize_snapshot() 3961 return dwProcessId in self.__processDict 3962 3963 def get_process(self, dwProcessId): 3964 """ 3965 @type dwProcessId: int 3966 @param dwProcessId: Global ID of the process to look for. 3967 3968 @rtype: L{Process} 3969 @return: Process object with the given global ID. 3970 """ 3971 self.__initialize_snapshot() 3972 if dwProcessId not in self.__processDict: 3973 msg = "Unknown process ID %d" % dwProcessId 3974 raise KeyError(msg) 3975 return self.__processDict[dwProcessId] 3976 3977 def iter_process_ids(self): 3978 """ 3979 @see: L{iter_processes} 3980 @rtype: dictionary-keyiterator 3981 @return: Iterator of global process IDs in this snapshot. 3982 """ 3983 self.__initialize_snapshot() 3984 return compat.iterkeys(self.__processDict) 3985 3986 def iter_processes(self): 3987 """ 3988 @see: L{iter_process_ids} 3989 @rtype: dictionary-valueiterator 3990 @return: Iterator of L{Process} objects in this snapshot. 3991 """ 3992 self.__initialize_snapshot() 3993 return compat.itervalues(self.__processDict) 3994 3995 def get_process_ids(self): 3996 """ 3997 @see: L{iter_process_ids} 3998 @rtype: list( int ) 3999 @return: List of global process IDs in this snapshot. 4000 """ 4001 self.__initialize_snapshot() 4002 return compat.keys(self.__processDict) 4003 4004 def get_process_count(self): 4005 """ 4006 @rtype: int 4007 @return: Count of L{Process} objects in this snapshot. 4008 """ 4009 self.__initialize_snapshot() 4010 return len(self.__processDict) 4011 4012#------------------------------------------------------------------------------ 4013 4014 # XXX TODO 4015 # Support for string searches on the window captions. 4016 4017 def get_windows(self): 4018 """ 4019 @rtype: list of L{Window} 4020 @return: Returns a list of windows 4021 handled by all processes in this snapshot. 4022 """ 4023 window_list = list() 4024 for process in self.iter_processes(): 4025 window_list.extend( process.get_windows() ) 4026 return window_list 4027 4028 def get_pid_from_tid(self, dwThreadId): 4029 """ 4030 Retrieves the global ID of the process that owns the thread. 4031 4032 @type dwThreadId: int 4033 @param dwThreadId: Thread global ID. 4034 4035 @rtype: int 4036 @return: Process global ID. 4037 4038 @raise KeyError: The thread does not exist. 4039 """ 4040 try: 4041 4042 # No good, because in XP and below it tries to get the PID 4043 # through the toolhelp API, and that's slow. We don't want 4044 # to scan for threads over and over for each call. 4045## dwProcessId = Thread(dwThreadId).get_pid() 4046 4047 # This API only exists in Windows 2003, Vista and above. 4048 try: 4049 hThread = win32.OpenThread( 4050 win32.THREAD_QUERY_LIMITED_INFORMATION, False, dwThreadId) 4051 except WindowsError: 4052 e = sys.exc_info()[1] 4053 if e.winerror != win32.ERROR_ACCESS_DENIED: 4054 raise 4055 hThread = win32.OpenThread( 4056 win32.THREAD_QUERY_INFORMATION, False, dwThreadId) 4057 try: 4058 return win32.GetProcessIdOfThread(hThread) 4059 finally: 4060 hThread.close() 4061 4062 # If all else fails, go through all processes in the snapshot 4063 # looking for the one that owns the thread we're looking for. 4064 # If the snapshot was empty the iteration should trigger an 4065 # automatic scan. Otherwise, it'll look for the thread in what 4066 # could possibly be an outdated snapshot. 4067 except Exception: 4068 for aProcess in self.iter_processes(): 4069 if aProcess.has_thread(dwThreadId): 4070 return aProcess.get_pid() 4071 4072 # The thread wasn't found, so let's refresh the snapshot and retry. 4073 # Normally this shouldn't happen since this function is only useful 4074 # for the debugger, so the thread should already exist in the snapshot. 4075 self.scan_processes_and_threads() 4076 for aProcess in self.iter_processes(): 4077 if aProcess.has_thread(dwThreadId): 4078 return aProcess.get_pid() 4079 4080 # No luck! It appears to be the thread doesn't exist after all. 4081 msg = "Unknown thread ID %d" % dwThreadId 4082 raise KeyError(msg) 4083 4084#------------------------------------------------------------------------------ 4085 4086 @staticmethod 4087 def argv_to_cmdline(argv): 4088 """ 4089 Convert a list of arguments to a single command line string. 4090 4091 @type argv: list( str ) 4092 @param argv: List of argument strings. 4093 The first element is the program to execute. 4094 4095 @rtype: str 4096 @return: Command line string. 4097 """ 4098 cmdline = list() 4099 for token in argv: 4100 if not token: 4101 token = '""' 4102 else: 4103 if '"' in token: 4104 token = token.replace('"', '\\"') 4105 if ' ' in token or \ 4106 '\t' in token or \ 4107 '\n' in token or \ 4108 '\r' in token: 4109 token = '"%s"' % token 4110 cmdline.append(token) 4111 return ' '.join(cmdline) 4112 4113 @staticmethod 4114 def cmdline_to_argv(lpCmdLine): 4115 """ 4116 Convert a single command line string to a list of arguments. 4117 4118 @type lpCmdLine: str 4119 @param lpCmdLine: Command line string. 4120 The first token is the program to execute. 4121 4122 @rtype: list( str ) 4123 @return: List of argument strings. 4124 """ 4125 if not lpCmdLine: 4126 return [] 4127 return win32.CommandLineToArgv(lpCmdLine) 4128 4129 def start_process(self, lpCmdLine, **kwargs): 4130 """ 4131 Starts a new process for instrumenting (or debugging). 4132 4133 @type lpCmdLine: str 4134 @param lpCmdLine: Command line to execute. Can't be an empty string. 4135 4136 @type bConsole: bool 4137 @keyword bConsole: True to inherit the console of the debugger. 4138 Defaults to C{False}. 4139 4140 @type bDebug: bool 4141 @keyword bDebug: C{True} to attach to the new process. 4142 To debug a process it's best to use the L{Debug} class instead. 4143 Defaults to C{False}. 4144 4145 @type bFollow: bool 4146 @keyword bFollow: C{True} to automatically attach to the child 4147 processes of the newly created process. Ignored unless C{bDebug} is 4148 C{True}. Defaults to C{False}. 4149 4150 @type bInheritHandles: bool 4151 @keyword bInheritHandles: C{True} if the new process should inherit 4152 it's parent process' handles. Defaults to C{False}. 4153 4154 @type bSuspended: bool 4155 @keyword bSuspended: C{True} to suspend the main thread before any code 4156 is executed in the debugee. Defaults to C{False}. 4157 4158 @type dwParentProcessId: int or None 4159 @keyword dwParentProcessId: C{None} if the debugger process should be 4160 the parent process (default), or a process ID to forcefully set as 4161 the debugee's parent (only available for Windows Vista and above). 4162 4163 @type iTrustLevel: int 4164 @keyword iTrustLevel: Trust level. 4165 Must be one of the following values: 4166 - 0: B{No trust}. May not access certain resources, such as 4167 cryptographic keys and credentials. Only available since 4168 Windows XP and 2003, desktop editions. 4169 - 1: B{Normal trust}. Run with the same privileges as a normal 4170 user, that is, one that doesn't have the I{Administrator} or 4171 I{Power User} user rights. Only available since Windows XP 4172 and 2003, desktop editions. 4173 - 2: B{Full trust}. Run with the exact same privileges as the 4174 current user. This is the default value. 4175 4176 @type bAllowElevation: bool 4177 @keyword bAllowElevation: C{True} to allow the child process to keep 4178 UAC elevation, if the debugger itself is running elevated. C{False} 4179 to ensure the child process doesn't run with elevation. Defaults to 4180 C{True}. 4181 4182 This flag is only meaningful on Windows Vista and above, and if the 4183 debugger itself is running with elevation. It can be used to make 4184 sure the child processes don't run elevated as well. 4185 4186 This flag DOES NOT force an elevation prompt when the debugger is 4187 not running with elevation. 4188 4189 Note that running the debugger with elevation (or the Python 4190 interpreter at all for that matter) is not normally required. 4191 You should only need to if the target program requires elevation 4192 to work properly (for example if you try to debug an installer). 4193 4194 @rtype: L{Process} 4195 @return: Process object. 4196 """ 4197 4198 # Get the flags. 4199 bConsole = kwargs.pop('bConsole', False) 4200 bDebug = kwargs.pop('bDebug', False) 4201 bFollow = kwargs.pop('bFollow', False) 4202 bSuspended = kwargs.pop('bSuspended', False) 4203 bInheritHandles = kwargs.pop('bInheritHandles', False) 4204 dwParentProcessId = kwargs.pop('dwParentProcessId', None) 4205 iTrustLevel = kwargs.pop('iTrustLevel', 2) 4206 bAllowElevation = kwargs.pop('bAllowElevation', True) 4207 if kwargs: 4208 raise TypeError("Unknown keyword arguments: %s" % compat.keys(kwargs)) 4209 if not lpCmdLine: 4210 raise ValueError("Missing command line to execute!") 4211 4212 # Sanitize the trust level flag. 4213 if iTrustLevel is None: 4214 iTrustLevel = 2 4215 4216 # The UAC elevation flag is only meaningful if we're running elevated. 4217 try: 4218 bAllowElevation = bAllowElevation or not self.is_admin() 4219 except AttributeError: 4220 bAllowElevation = True 4221 warnings.warn( 4222 "UAC elevation is only available in Windows Vista and above", 4223 RuntimeWarning) 4224 4225 # Calculate the process creation flags. 4226 dwCreationFlags = 0 4227 dwCreationFlags |= win32.CREATE_DEFAULT_ERROR_MODE 4228 dwCreationFlags |= win32.CREATE_BREAKAWAY_FROM_JOB 4229 ##dwCreationFlags |= win32.CREATE_UNICODE_ENVIRONMENT 4230 if not bConsole: 4231 dwCreationFlags |= win32.DETACHED_PROCESS 4232 #dwCreationFlags |= win32.CREATE_NO_WINDOW # weird stuff happens 4233 if bSuspended: 4234 dwCreationFlags |= win32.CREATE_SUSPENDED 4235 if bDebug: 4236 dwCreationFlags |= win32.DEBUG_PROCESS 4237 if not bFollow: 4238 dwCreationFlags |= win32.DEBUG_ONLY_THIS_PROCESS 4239 4240 # Change the parent process if requested. 4241 # May fail on old versions of Windows. 4242 lpStartupInfo = None 4243 if dwParentProcessId is not None: 4244 myPID = win32.GetCurrentProcessId() 4245 if dwParentProcessId != myPID: 4246 if self.has_process(dwParentProcessId): 4247 ParentProcess = self.get_process(dwParentProcessId) 4248 else: 4249 ParentProcess = Process(dwParentProcessId) 4250 ParentProcessHandle = ParentProcess.get_handle( 4251 win32.PROCESS_CREATE_PROCESS) 4252 AttributeListData = ( 4253 ( 4254 win32.PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, 4255 ParentProcessHandle._as_parameter_ 4256 ), 4257 ) 4258 AttributeList = win32.ProcThreadAttributeList(AttributeListData) 4259 StartupInfoEx = win32.STARTUPINFOEX() 4260 StartupInfo = StartupInfoEx.StartupInfo 4261 StartupInfo.cb = win32.sizeof(win32.STARTUPINFOEX) 4262 StartupInfo.lpReserved = 0 4263 StartupInfo.lpDesktop = 0 4264 StartupInfo.lpTitle = 0 4265 StartupInfo.dwFlags = 0 4266 StartupInfo.cbReserved2 = 0 4267 StartupInfo.lpReserved2 = 0 4268 StartupInfoEx.lpAttributeList = AttributeList.value 4269 lpStartupInfo = StartupInfoEx 4270 dwCreationFlags |= win32.EXTENDED_STARTUPINFO_PRESENT 4271 4272 pi = None 4273 try: 4274 4275 # Create the process the easy way. 4276 if iTrustLevel >= 2 and bAllowElevation: 4277 pi = win32.CreateProcess(None, lpCmdLine, 4278 bInheritHandles = bInheritHandles, 4279 dwCreationFlags = dwCreationFlags, 4280 lpStartupInfo = lpStartupInfo) 4281 4282 # Create the process the hard way... 4283 else: 4284 4285 # If we allow elevation, use the current process token. 4286 # If not, get the token from the current shell process. 4287 hToken = None 4288 try: 4289 if not bAllowElevation: 4290 if bFollow: 4291 msg = ( 4292 "Child processes can't be autofollowed" 4293 " when dropping UAC elevation.") 4294 raise NotImplementedError(msg) 4295 if bConsole: 4296 msg = ( 4297 "Child processes can't inherit the debugger's" 4298 " console when dropping UAC elevation.") 4299 raise NotImplementedError(msg) 4300 if bInheritHandles: 4301 msg = ( 4302 "Child processes can't inherit the debugger's" 4303 " handles when dropping UAC elevation.") 4304 raise NotImplementedError(msg) 4305 try: 4306 hWnd = self.get_shell_window() 4307 except WindowsError: 4308 hWnd = self.get_desktop_window() 4309 shell = hWnd.get_process() 4310 try: 4311 hShell = shell.get_handle( 4312 win32.PROCESS_QUERY_INFORMATION) 4313 with win32.OpenProcessToken(hShell) as hShellToken: 4314 hToken = win32.DuplicateTokenEx(hShellToken) 4315 finally: 4316 shell.close_handle() 4317 4318 # Lower trust level if requested. 4319 if iTrustLevel < 2: 4320 if iTrustLevel > 0: 4321 dwLevelId = win32.SAFER_LEVELID_NORMALUSER 4322 else: 4323 dwLevelId = win32.SAFER_LEVELID_UNTRUSTED 4324 with win32.SaferCreateLevel(dwLevelId = dwLevelId) as hSafer: 4325 hSaferToken = win32.SaferComputeTokenFromLevel( 4326 hSafer, hToken)[0] 4327 try: 4328 if hToken is not None: 4329 hToken.close() 4330 except: 4331 hSaferToken.close() 4332 raise 4333 hToken = hSaferToken 4334 4335 # If we have a computed token, call CreateProcessAsUser(). 4336 if bAllowElevation: 4337 pi = win32.CreateProcessAsUser( 4338 hToken = hToken, 4339 lpCommandLine = lpCmdLine, 4340 bInheritHandles = bInheritHandles, 4341 dwCreationFlags = dwCreationFlags, 4342 lpStartupInfo = lpStartupInfo) 4343 4344 # If we have a primary token call CreateProcessWithToken(). 4345 # The problem is, there are many flags CreateProcess() and 4346 # CreateProcessAsUser() accept but CreateProcessWithToken() 4347 # and CreateProcessWithLogonW() don't, so we need to work 4348 # around them. 4349 else: 4350 4351 # Remove the debug flags. 4352 dwCreationFlags &= ~win32.DEBUG_PROCESS 4353 dwCreationFlags &= ~win32.DEBUG_ONLY_THIS_PROCESS 4354 4355 # Remove the console flags. 4356 dwCreationFlags &= ~win32.DETACHED_PROCESS 4357 4358 # The process will be created suspended. 4359 dwCreationFlags |= win32.CREATE_SUSPENDED 4360 4361 # Create the process using the new primary token. 4362 pi = win32.CreateProcessWithToken( 4363 hToken = hToken, 4364 dwLogonFlags = win32.LOGON_WITH_PROFILE, 4365 lpCommandLine = lpCmdLine, 4366 dwCreationFlags = dwCreationFlags, 4367 lpStartupInfo = lpStartupInfo) 4368 4369 # Attach as a debugger, if requested. 4370 if bDebug: 4371 win32.DebugActiveProcess(pi.dwProcessId) 4372 4373 # Resume execution, if requested. 4374 if not bSuspended: 4375 win32.ResumeThread(pi.hThread) 4376 4377 # Close the token when we're done with it. 4378 finally: 4379 if hToken is not None: 4380 hToken.close() 4381 4382 # Wrap the new process and thread in Process and Thread objects, 4383 # and add them to the corresponding snapshots. 4384 aProcess = Process(pi.dwProcessId, pi.hProcess) 4385 aThread = Thread (pi.dwThreadId, pi.hThread) 4386 aProcess._add_thread(aThread) 4387 self._add_process(aProcess) 4388 4389 # Clean up on error. 4390 except: 4391 if pi is not None: 4392 try: 4393 win32.TerminateProcess(pi.hProcess) 4394 except WindowsError: 4395 pass 4396 pi.hThread.close() 4397 pi.hProcess.close() 4398 raise 4399 4400 # Return the new Process object. 4401 return aProcess 4402 4403 def get_explorer_pid(self): 4404 """ 4405 Tries to find the process ID for "explorer.exe". 4406 4407 @rtype: int or None 4408 @return: Returns the process ID, or C{None} on error. 4409 """ 4410 try: 4411 exp = win32.SHGetFolderPath(win32.CSIDL_WINDOWS) 4412 except Exception: 4413 exp = None 4414 if not exp: 4415 exp = os.getenv('SystemRoot') 4416 if exp: 4417 exp = os.path.join(exp, 'explorer.exe') 4418 exp_list = self.find_processes_by_filename(exp) 4419 if exp_list: 4420 return exp_list[0][0].get_pid() 4421 return None 4422 4423#------------------------------------------------------------------------------ 4424 4425 # XXX this methods musn't end up calling __initialize_snapshot by accident! 4426 4427 def scan(self): 4428 """ 4429 Populates the snapshot with running processes and threads, 4430 and loaded modules. 4431 4432 Tipically this is the first method called after instantiating a 4433 L{System} object, as it makes a best effort approach to gathering 4434 information on running processes. 4435 4436 @rtype: bool 4437 @return: C{True} if the snapshot is complete, C{False} if the debugger 4438 doesn't have permission to scan some processes. In either case, the 4439 snapshot is complete for all processes the debugger has access to. 4440 """ 4441 has_threads = True 4442 try: 4443 try: 4444 4445 # Try using the Toolhelp API 4446 # to scan for processes and threads. 4447 self.scan_processes_and_threads() 4448 4449 except Exception: 4450 4451 # On error, try using the PSAPI to scan for process IDs only. 4452 self.scan_processes_fast() 4453 4454 # Now try using the Toolhelp again to get the threads. 4455 for aProcess in self.__processDict.values(): 4456 if aProcess._get_thread_ids(): 4457 try: 4458 aProcess.scan_threads() 4459 except WindowsError: 4460 has_threads = False 4461 4462 finally: 4463 4464 # Try using the Remote Desktop API to scan for processes only. 4465 # This will update the filenames when it's not possible 4466 # to obtain them from the Toolhelp API. 4467 self.scan_processes() 4468 4469 # When finished scanning for processes, try modules too. 4470 has_modules = self.scan_modules() 4471 4472 # Try updating the process filenames when possible. 4473 has_full_names = self.scan_process_filenames() 4474 4475 # Return the completion status. 4476 return has_threads and has_modules and has_full_names 4477 4478 def scan_processes_and_threads(self): 4479 """ 4480 Populates the snapshot with running processes and threads. 4481 4482 Tipically you don't need to call this method directly, if unsure use 4483 L{scan} instead. 4484 4485 @note: This method uses the Toolhelp API. 4486 4487 @see: L{scan_modules} 4488 4489 @raise WindowsError: An error occured while updating the snapshot. 4490 The snapshot was not modified. 4491 """ 4492 4493 # The main module filename may be spoofed by malware, 4494 # since this information resides in usermode space. 4495 # See: http://www.ragestorm.net/blogs/?p=163 4496 4497 our_pid = win32.GetCurrentProcessId() 4498 dead_pids = set( compat.iterkeys(self.__processDict) ) 4499 found_tids = set() 4500 4501 # Ignore our own process if it's in the snapshot for some reason 4502 if our_pid in dead_pids: 4503 dead_pids.remove(our_pid) 4504 4505 # Take a snapshot of all processes and threads 4506 dwFlags = win32.TH32CS_SNAPPROCESS | win32.TH32CS_SNAPTHREAD 4507 with win32.CreateToolhelp32Snapshot(dwFlags) as hSnapshot: 4508 4509 # Add all the processes (excluding our own) 4510 pe = win32.Process32First(hSnapshot) 4511 while pe is not None: 4512 dwProcessId = pe.th32ProcessID 4513 if dwProcessId != our_pid: 4514 if dwProcessId in dead_pids: 4515 dead_pids.remove(dwProcessId) 4516 if dwProcessId not in self.__processDict: 4517 aProcess = Process(dwProcessId, fileName=pe.szExeFile) 4518 self._add_process(aProcess) 4519 elif pe.szExeFile: 4520 aProcess = self.get_process(dwProcessId) 4521 if not aProcess.fileName: 4522 aProcess.fileName = pe.szExeFile 4523 pe = win32.Process32Next(hSnapshot) 4524 4525 # Add all the threads 4526 te = win32.Thread32First(hSnapshot) 4527 while te is not None: 4528 dwProcessId = te.th32OwnerProcessID 4529 if dwProcessId != our_pid: 4530 if dwProcessId in dead_pids: 4531 dead_pids.remove(dwProcessId) 4532 if dwProcessId in self.__processDict: 4533 aProcess = self.get_process(dwProcessId) 4534 else: 4535 aProcess = Process(dwProcessId) 4536 self._add_process(aProcess) 4537 dwThreadId = te.th32ThreadID 4538 found_tids.add(dwThreadId) 4539 if not aProcess._has_thread_id(dwThreadId): 4540 aThread = Thread(dwThreadId, process = aProcess) 4541 aProcess._add_thread(aThread) 4542 te = win32.Thread32Next(hSnapshot) 4543 4544 # Remove dead processes 4545 for pid in dead_pids: 4546 self._del_process(pid) 4547 4548 # Remove dead threads 4549 for aProcess in compat.itervalues(self.__processDict): 4550 dead_tids = set( aProcess._get_thread_ids() ) 4551 dead_tids.difference_update(found_tids) 4552 for tid in dead_tids: 4553 aProcess._del_thread(tid) 4554 4555 def scan_modules(self): 4556 """ 4557 Populates the snapshot with loaded modules. 4558 4559 Tipically you don't need to call this method directly, if unsure use 4560 L{scan} instead. 4561 4562 @note: This method uses the Toolhelp API. 4563 4564 @see: L{scan_processes_and_threads} 4565 4566 @rtype: bool 4567 @return: C{True} if the snapshot is complete, C{False} if the debugger 4568 doesn't have permission to scan some processes. In either case, the 4569 snapshot is complete for all processes the debugger has access to. 4570 """ 4571 complete = True 4572 for aProcess in compat.itervalues(self.__processDict): 4573 try: 4574 aProcess.scan_modules() 4575 except WindowsError: 4576 complete = False 4577 return complete 4578 4579 def scan_processes(self): 4580 """ 4581 Populates the snapshot with running processes. 4582 4583 Tipically you don't need to call this method directly, if unsure use 4584 L{scan} instead. 4585 4586 @note: This method uses the Remote Desktop API instead of the Toolhelp 4587 API. It might give slightly different results, especially if the 4588 current process does not have full privileges. 4589 4590 @note: This method will only retrieve process filenames. To get the 4591 process pathnames instead, B{after} this method call 4592 L{scan_process_filenames}. 4593 4594 @raise WindowsError: An error occured while updating the snapshot. 4595 The snapshot was not modified. 4596 """ 4597 4598 # Get the previous list of PIDs. 4599 # We'll be removing live PIDs from it as we find them. 4600 our_pid = win32.GetCurrentProcessId() 4601 dead_pids = set( compat.iterkeys(self.__processDict) ) 4602 4603 # Ignore our own PID. 4604 if our_pid in dead_pids: 4605 dead_pids.remove(our_pid) 4606 4607 # Get the list of processes from the Remote Desktop API. 4608 pProcessInfo = None 4609 try: 4610 pProcessInfo, dwCount = win32.WTSEnumerateProcesses( 4611 win32.WTS_CURRENT_SERVER_HANDLE) 4612 4613 # For each process found... 4614 for index in compat.xrange(dwCount): 4615 sProcessInfo = pProcessInfo[index] 4616 4617## # Ignore processes belonging to other sessions. 4618## if sProcessInfo.SessionId != win32.WTS_CURRENT_SESSION: 4619## continue 4620 4621 # Ignore our own PID. 4622 pid = sProcessInfo.ProcessId 4623 if pid == our_pid: 4624 continue 4625 4626 # Remove the PID from the dead PIDs list. 4627 if pid in dead_pids: 4628 dead_pids.remove(pid) 4629 4630 # Get the "process name". 4631 # Empirically, this seems to be the filename without the path. 4632 # (The MSDN docs aren't very clear about this API call). 4633 fileName = sProcessInfo.pProcessName 4634 4635 # If the process is new, add a new Process object. 4636 if pid not in self.__processDict: 4637 aProcess = Process(pid, fileName = fileName) 4638 self._add_process(aProcess) 4639 4640 # If the process was already in the snapshot, and the 4641 # filename is missing, update the Process object. 4642 elif fileName: 4643 aProcess = self.__processDict.get(pid) 4644 if not aProcess.fileName: 4645 aProcess.fileName = fileName 4646 4647 # Free the memory allocated by the Remote Desktop API. 4648 finally: 4649 if pProcessInfo is not None: 4650 try: 4651 win32.WTSFreeMemory(pProcessInfo) 4652 except WindowsError: 4653 pass 4654 4655 # At this point the only remaining PIDs from the old list are dead. 4656 # Remove them from the snapshot. 4657 for pid in dead_pids: 4658 self._del_process(pid) 4659 4660 def scan_processes_fast(self): 4661 """ 4662 Populates the snapshot with running processes. 4663 Only the PID is retrieved for each process. 4664 4665 Dead processes are removed. 4666 Threads and modules of living processes are ignored. 4667 4668 Tipically you don't need to call this method directly, if unsure use 4669 L{scan} instead. 4670 4671 @note: This method uses the PSAPI. It may be faster for scanning, 4672 but some information may be missing, outdated or slower to obtain. 4673 This could be a good tradeoff under some circumstances. 4674 """ 4675 4676 # Get the new and old list of pids 4677 new_pids = set( win32.EnumProcesses() ) 4678 old_pids = set( compat.iterkeys(self.__processDict) ) 4679 4680 # Ignore our own pid 4681 our_pid = win32.GetCurrentProcessId() 4682 if our_pid in new_pids: 4683 new_pids.remove(our_pid) 4684 if our_pid in old_pids: 4685 old_pids.remove(our_pid) 4686 4687 # Add newly found pids 4688 for pid in new_pids.difference(old_pids): 4689 self._add_process( Process(pid) ) 4690 4691 # Remove missing pids 4692 for pid in old_pids.difference(new_pids): 4693 self._del_process(pid) 4694 4695 def scan_process_filenames(self): 4696 """ 4697 Update the filename for each process in the snapshot when possible. 4698 4699 @note: Tipically you don't need to call this method. It's called 4700 automatically by L{scan} to get the full pathname for each process 4701 when possible, since some scan methods only get filenames without 4702 the path component. 4703 4704 If unsure, use L{scan} instead. 4705 4706 @see: L{scan}, L{Process.get_filename} 4707 4708 @rtype: bool 4709 @return: C{True} if all the pathnames were retrieved, C{False} if the 4710 debugger doesn't have permission to scan some processes. In either 4711 case, all processes the debugger has access to have a full pathname 4712 instead of just a filename. 4713 """ 4714 complete = True 4715 for aProcess in self.__processDict.values(): 4716 try: 4717 new_name = None 4718 old_name = aProcess.fileName 4719 try: 4720 aProcess.fileName = None 4721 new_name = aProcess.get_filename() 4722 finally: 4723 if not new_name: 4724 aProcess.fileName = old_name 4725 complete = False 4726 except Exception: 4727 complete = False 4728 return complete 4729 4730#------------------------------------------------------------------------------ 4731 4732 def clear_dead_processes(self): 4733 """ 4734 Removes Process objects from the snapshot 4735 referring to processes no longer running. 4736 """ 4737 for pid in self.get_process_ids(): 4738 aProcess = self.get_process(pid) 4739 if not aProcess.is_alive(): 4740 self._del_process(aProcess) 4741 4742 def clear_unattached_processes(self): 4743 """ 4744 Removes Process objects from the snapshot 4745 referring to processes not being debugged. 4746 """ 4747 for pid in self.get_process_ids(): 4748 aProcess = self.get_process(pid) 4749 if not aProcess.is_being_debugged(): 4750 self._del_process(aProcess) 4751 4752 def close_process_handles(self): 4753 """ 4754 Closes all open handles to processes in this snapshot. 4755 """ 4756 for pid in self.get_process_ids(): 4757 aProcess = self.get_process(pid) 4758 try: 4759 aProcess.close_handle() 4760 except Exception: 4761 e = sys.exc_info()[1] 4762 try: 4763 msg = "Cannot close process handle %s, reason: %s" 4764 msg %= (aProcess.hProcess.value, str(e)) 4765 warnings.warn(msg) 4766 except Exception: 4767 pass 4768 4769 def close_process_and_thread_handles(self): 4770 """ 4771 Closes all open handles to processes and threads in this snapshot. 4772 """ 4773 for aProcess in self.iter_processes(): 4774 aProcess.close_thread_handles() 4775 try: 4776 aProcess.close_handle() 4777 except Exception: 4778 e = sys.exc_info()[1] 4779 try: 4780 msg = "Cannot close process handle %s, reason: %s" 4781 msg %= (aProcess.hProcess.value, str(e)) 4782 warnings.warn(msg) 4783 except Exception: 4784 pass 4785 4786 def clear_processes(self): 4787 """ 4788 Removes all L{Process}, L{Thread} and L{Module} objects in this snapshot. 4789 """ 4790 #self.close_process_and_thread_handles() 4791 for aProcess in self.iter_processes(): 4792 aProcess.clear() 4793 self.__processDict = dict() 4794 4795 def clear(self): 4796 """ 4797 Clears this snapshot. 4798 4799 @see: L{clear_processes} 4800 """ 4801 self.clear_processes() 4802 4803#------------------------------------------------------------------------------ 4804 4805 # Docs for these methods are taken from the _ThreadContainer class. 4806 4807 def has_thread(self, dwThreadId): 4808 dwProcessId = self.get_pid_from_tid(dwThreadId) 4809 if dwProcessId is None: 4810 return False 4811 return self.has_process(dwProcessId) 4812 4813 def get_thread(self, dwThreadId): 4814 dwProcessId = self.get_pid_from_tid(dwThreadId) 4815 if dwProcessId is None: 4816 msg = "Unknown thread ID %d" % dwThreadId 4817 raise KeyError(msg) 4818 return self.get_process(dwProcessId).get_thread(dwThreadId) 4819 4820 def get_thread_ids(self): 4821 ids = list() 4822 for aProcess in self.iter_processes(): 4823 ids += aProcess.get_thread_ids() 4824 return ids 4825 4826 def get_thread_count(self): 4827 count = 0 4828 for aProcess in self.iter_processes(): 4829 count += aProcess.get_thread_count() 4830 return count 4831 4832 has_thread.__doc__ = _ThreadContainer.has_thread.__doc__ 4833 get_thread.__doc__ = _ThreadContainer.get_thread.__doc__ 4834 get_thread_ids.__doc__ = _ThreadContainer.get_thread_ids.__doc__ 4835 get_thread_count.__doc__ = _ThreadContainer.get_thread_count.__doc__ 4836 4837#------------------------------------------------------------------------------ 4838 4839 # Docs for these methods are taken from the _ModuleContainer class. 4840 4841 def get_module_count(self): 4842 count = 0 4843 for aProcess in self.iter_processes(): 4844 count += aProcess.get_module_count() 4845 return count 4846 4847 get_module_count.__doc__ = _ModuleContainer.get_module_count.__doc__ 4848 4849#------------------------------------------------------------------------------ 4850 4851 def find_modules_by_base(self, lpBaseOfDll): 4852 """ 4853 @rtype: list( L{Module}... ) 4854 @return: List of Module objects with the given base address. 4855 """ 4856 found = list() 4857 for aProcess in self.iter_processes(): 4858 if aProcess.has_module(lpBaseOfDll): 4859 aModule = aProcess.get_module(lpBaseOfDll) 4860 found.append( (aProcess, aModule) ) 4861 return found 4862 4863 def find_modules_by_name(self, fileName): 4864 """ 4865 @rtype: list( L{Module}... ) 4866 @return: List of Module objects found. 4867 """ 4868 found = list() 4869 for aProcess in self.iter_processes(): 4870 aModule = aProcess.get_module_by_name(fileName) 4871 if aModule is not None: 4872 found.append( (aProcess, aModule) ) 4873 return found 4874 4875 def find_modules_by_address(self, address): 4876 """ 4877 @rtype: list( L{Module}... ) 4878 @return: List of Module objects that best match the given address. 4879 """ 4880 found = list() 4881 for aProcess in self.iter_processes(): 4882 aModule = aProcess.get_module_at_address(address) 4883 if aModule is not None: 4884 found.append( (aProcess, aModule) ) 4885 return found 4886 4887 def __find_processes_by_filename(self, filename): 4888 """ 4889 Internally used by L{find_processes_by_filename}. 4890 """ 4891 found = list() 4892 filename = filename.lower() 4893 if PathOperations.path_is_absolute(filename): 4894 for aProcess in self.iter_processes(): 4895 imagename = aProcess.get_filename() 4896 if imagename and imagename.lower() == filename: 4897 found.append( (aProcess, imagename) ) 4898 else: 4899 for aProcess in self.iter_processes(): 4900 imagename = aProcess.get_filename() 4901 if imagename: 4902 imagename = PathOperations.pathname_to_filename(imagename) 4903 if imagename.lower() == filename: 4904 found.append( (aProcess, imagename) ) 4905 return found 4906 4907 def find_processes_by_filename(self, fileName): 4908 """ 4909 @type fileName: str 4910 @param fileName: Filename to search for. 4911 If it's a full pathname, the match must be exact. 4912 If it's a base filename only, the file part is matched, 4913 regardless of the directory where it's located. 4914 4915 @note: If the process is not found and the file extension is not 4916 given, this method will search again assuming a default 4917 extension (.exe). 4918 4919 @rtype: list of tuple( L{Process}, str ) 4920 @return: List of processes matching the given main module filename. 4921 Each tuple contains a Process object and it's filename. 4922 """ 4923 found = self.__find_processes_by_filename(fileName) 4924 if not found: 4925 fn, ext = PathOperations.split_extension(fileName) 4926 if not ext: 4927 fileName = '%s.exe' % fn 4928 found = self.__find_processes_by_filename(fileName) 4929 return found 4930 4931#------------------------------------------------------------------------------ 4932 4933 # XXX _notify_* methods should not trigger a scan 4934 4935 def _add_process(self, aProcess): 4936 """ 4937 Private method to add a process object to the snapshot. 4938 4939 @type aProcess: L{Process} 4940 @param aProcess: Process object. 4941 """ 4942## if not isinstance(aProcess, Process): 4943## if hasattr(aProcess, '__class__'): 4944## typename = aProcess.__class__.__name__ 4945## else: 4946## typename = str(type(aProcess)) 4947## msg = "Expected Process, got %s instead" % typename 4948## raise TypeError(msg) 4949 dwProcessId = aProcess.dwProcessId 4950## if dwProcessId in self.__processDict: 4951## msg = "Process already exists: %d" % dwProcessId 4952## raise KeyError(msg) 4953 self.__processDict[dwProcessId] = aProcess 4954 4955 def _del_process(self, dwProcessId): 4956 """ 4957 Private method to remove a process object from the snapshot. 4958 4959 @type dwProcessId: int 4960 @param dwProcessId: Global process ID. 4961 """ 4962 try: 4963 aProcess = self.__processDict[dwProcessId] 4964 del self.__processDict[dwProcessId] 4965 except KeyError: 4966 aProcess = None 4967 msg = "Unknown process ID %d" % dwProcessId 4968 warnings.warn(msg, RuntimeWarning) 4969 if aProcess: 4970 aProcess.clear() # remove circular references 4971 4972 # Notify the creation of a new process. 4973 def _notify_create_process(self, event): 4974 """ 4975 Notify the creation of a new process. 4976 4977 This is done automatically by the L{Debug} class, you shouldn't need 4978 to call it yourself. 4979 4980 @type event: L{CreateProcessEvent} 4981 @param event: Create process event. 4982 4983 @rtype: bool 4984 @return: C{True} to call the user-defined handle, C{False} otherwise. 4985 """ 4986 dwProcessId = event.get_pid() 4987 dwThreadId = event.get_tid() 4988 hProcess = event.get_process_handle() 4989## if not self.has_process(dwProcessId): # XXX this would trigger a scan 4990 if dwProcessId not in self.__processDict: 4991 aProcess = Process(dwProcessId, hProcess) 4992 self._add_process(aProcess) 4993 aProcess.fileName = event.get_filename() 4994 else: 4995 aProcess = self.get_process(dwProcessId) 4996 #if hProcess != win32.INVALID_HANDLE_VALUE: 4997 # aProcess.hProcess = hProcess # may have more privileges 4998 if not aProcess.fileName: 4999 fileName = event.get_filename() 5000 if fileName: 5001 aProcess.fileName = fileName 5002 return aProcess._notify_create_process(event) # pass it to the process 5003 5004 def _notify_exit_process(self, event): 5005 """ 5006 Notify the termination of a process. 5007 5008 This is done automatically by the L{Debug} class, you shouldn't need 5009 to call it yourself. 5010 5011 @type event: L{ExitProcessEvent} 5012 @param event: Exit process event. 5013 5014 @rtype: bool 5015 @return: C{True} to call the user-defined handle, C{False} otherwise. 5016 """ 5017 dwProcessId = event.get_pid() 5018## if self.has_process(dwProcessId): # XXX this would trigger a scan 5019 if dwProcessId in self.__processDict: 5020 self._del_process(dwProcessId) 5021 return True 5022