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

Source Code for Module winappdbg.process

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