AndrewHaxalot

PyDbg.py

Dec 9th, 2013
282
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 147.51 KB | None | 0 0
  1. #!c:\python\python.exe
  2.  
  3. #
  4. # PyDBG
  5. # Copyright (C) 2006 Pedram Amini <pedram.amini@gmail.com>
  6. #
  7. # $Id: pydbg.py 253 2011-01-24 19:13:57Z my.name.is.sober $
  8. #
  9. # This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
  10. # License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
  11. # version.
  12. #
  13. # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  14. # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
  17. # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. #
  19.  
  20. '''
  21. @author:       Pedram Amini
  22. @license:      GNU General Public License 2.0 or later
  23. @contact:      pedram.amini@gmail.com
  24. @organization: www.openrce.org
  25. '''
  26.  
  27. import os.path
  28. import sys
  29. import copy
  30. import signal
  31. import struct
  32. import pydasm
  33. import socket
  34.  
  35. from my_ctypes  import *
  36. from defines    import *
  37. from windows_h  import *
  38.  
  39. # macos compatability.
  40. try:
  41.     kernel32 = windll.kernel32
  42.     advapi32 = windll.advapi32
  43.     ntdll    = windll.ntdll
  44.     iphlpapi = windll.iphlpapi
  45. except:
  46.     kernel32 = CDLL(os.path.join(os.path.dirname(__file__), "libmacdll.dylib"))
  47.     advapi32 = kernel32
  48.  
  49. from breakpoint              import *
  50. from hardware_breakpoint     import *
  51. from memory_breakpoint       import *
  52. from memory_snapshot_block   import *
  53. from memory_snapshot_context import *
  54. from pdx                     import *
  55. from system_dll              import *
  56.  
  57. class pydbg:
  58.     '''
  59.    This class implements standard low leven functionality including:
  60.        - The load() / attach() routines.
  61.        - The main debug event loop.
  62.        - Convenience wrappers for commonly used Windows API.
  63.        - Single step toggling routine.
  64.        - Win32 error handler wrapped around PDX.
  65.        - Base exception / event handler routines which are meant to be overridden.
  66.  
  67.    Higher level functionality is also implemented including:
  68.        - Register manipulation.
  69.        - Soft (INT 3) breakpoints.
  70.        - Memory breakpoints (page permissions).
  71.        - Hardware breakpoints.
  72.        - Exception / event handling call backs.
  73.        - Pydasm (libdasm) disassembly wrapper.
  74.        - Process memory snapshotting and restoring.
  75.        - Endian manipulation routines.
  76.        - Debugger hiding.
  77.        - Function resolution.
  78.        - "Intelligent" memory derefencing.
  79.        - Stack/SEH unwinding.
  80.        - Etc...
  81.    '''
  82.  
  83.     STRING_EXPLORATON_BUF_SIZE    = 256
  84.     STRING_EXPLORATION_MIN_LENGTH = 2
  85.  
  86.     ####################################################################################################################
  87.     def __init__ (self, ff=True, cs=False):
  88.         '''
  89.        Set the default attributes. See the source if you want to modify the default creation values.
  90.  
  91.        @type  ff: Boolean
  92.        @param ff: (Optional, Def=True) Flag controlling whether or not pydbg attaches to forked processes
  93.        @type  cs: Boolean
  94.        @param cs: (Optional, Def=False) Flag controlling whether or not pydbg is in client/server (socket) mode
  95.        '''
  96.  
  97.         # private variables, internal use only:
  98.         self._restore_breakpoint      = None      # breakpoint to restore
  99.         self._guarded_pages           = set()     # specific pages we set PAGE_GUARD on
  100.         self._guards_active           = True      # flag specifying whether or not guard pages are active
  101.  
  102.         self.page_size                = 0         # memory page size (dynamically resolved at run-time)
  103.         self.pid                      = 0         # debuggee's process id
  104.         self.h_process                = None      # debuggee's process handle
  105.         self.h_thread                 = None      # handle to current debuggee thread
  106.         self.debugger_active          = True      # flag controlling the main debugger event handling loop
  107.         self.follow_forks             = ff        # flag controlling whether or not pydbg attaches to forked processes
  108.         self.client_server            = cs        # flag controlling whether or not pydbg is in client/server mode
  109.         self.callbacks                = {}        # exception callback handler dictionary
  110.         self.system_dlls              = []        # list of loaded system dlls
  111.         self.dirty                    = False     # flag specifying that the memory space of the debuggee was modified
  112.         self.system_break             = None      # the address at which initial and forced breakpoints occur at
  113.         self.peb                      = None      # process environment block address
  114.         self.tebs                     = {}        # dictionary of thread IDs to thread environment block addresses
  115.  
  116.         # internal variables specific to the last triggered exception.
  117.         self.context                  = None      # thread context of offending thread
  118.         self.dbg                      = None      # DEBUG_EVENT
  119.         self.exception_address        = None      # from dbg.u.Exception.ExceptionRecord.ExceptionAddress
  120.         self.write_violation          = None      # from dbg.u.Exception.ExceptionRecord.ExceptionInformation[0]
  121.         self.violation_address        = None      # from dbg.u.Exception.ExceptionRecord.ExceptionInformation[1]
  122.         self.exception_code           = None      # from dbg.u.Exception.ExceptionRecord.ExceptionCode
  123.  
  124.         self.breakpoints              = {}        # internal breakpoint dictionary, keyed by address
  125.         self.memory_breakpoints       = {}        # internal memory breakpoint dictionary, keyed by base address
  126.         self.hardware_breakpoints     = {}        # internal hardware breakpoint array, indexed by slot (0-3 inclusive)
  127.         self.memory_snapshot_blocks   = []        # list of memory blocks at time of memory snapshot
  128.         self.memory_snapshot_contexts = []        # list of threads contexts at time of memory snapshot
  129.  
  130.         self.first_breakpoint         = True      # this flag gets disabled once the windows initial break is handled
  131.         self.memory_breakpoint_hit    = 0         # address of hit memory breakpoint or zero on miss
  132.                                                   # designates whether or not the violation was in reaction to a memory
  133.                                                   # breakpoint hit or other unrelated event.
  134.         self.hardware_breakpoint_hit  = None      # hardware breakpoint on hit or None on miss
  135.                                                   # designates whether or not the single step event was in reaction to
  136.                                                   # a hardware breakpoint hit or other unrelated event.
  137.  
  138.         self.instruction              = None      # pydasm instruction object, propagated by self.disasm()
  139.         self.mnemonic                 = None      # pydasm decoded instruction mnemonic, propagated by self.disasm()
  140.         self.op1                      = None      # pydasm decoded 1st operand, propagated by self.disasm()
  141.         self.op2                      = None      # pydasm decoded 2nd operand, propagated by self.disasm()
  142.         self.op3                      = None      # pydasm decoded 3rd operand, propagated by self.disasm()
  143.  
  144.         # control debug/error logging.
  145.         self._log = lambda msg: None #sys.stderr.write("PDBG_LOG> " + msg + "\n")
  146.         self._err = lambda msg: sys.stderr.write("PDBG_ERR> " + msg + "\n")
  147.  
  148.         # determine the system page size.
  149.         system_info = SYSTEM_INFO()
  150.         kernel32.GetSystemInfo(byref(system_info))
  151.         self.page_size = system_info.dwPageSize
  152.  
  153.         # determine the system DbgBreakPoint address. this is the address at which initial and forced breaks happen.
  154.         # XXX - need to look into fixing this for pydbg client/server.
  155.         self.system_break = self.func_resolve("ntdll.dll", "DbgBreakPoint")
  156.  
  157.         self._log("system page size is %d" % self.page_size)
  158.  
  159.  
  160.     ####################################################################################################################
  161.     def addr_to_dll (self, address):
  162.         '''
  163.        Return the system DLL that contains the address specified.
  164.  
  165.        @type  address: DWORD
  166.        @param address: Address to search system DLL ranges for
  167.  
  168.        @rtype:  system_dll
  169.        @return: System DLL that contains the address specified or None if not found.
  170.        '''
  171.  
  172.         for dll in self.system_dlls:
  173.             if dll.base < address < dll.base + dll.size:
  174.                 return dll
  175.  
  176.         return None
  177.  
  178.  
  179.     ####################################################################################################################
  180.     def addr_to_module (self, address):
  181.         '''
  182.        Return the MODULEENTRY32 structure for the module that contains the address specified.
  183.  
  184.        @type  address: DWORD
  185.        @param address: Address to search loaded module ranges for
  186.  
  187.        @rtype:  MODULEENTRY32
  188.        @return: MODULEENTRY32 strucutre that contains the address specified or None if not found.
  189.        '''
  190.  
  191.         found = None
  192.  
  193.         for module in self.iterate_modules():
  194.             if module.modBaseAddr < address < module.modBaseAddr + module.modBaseSize:
  195.                 # we have to make a copy of the 'module' since it is an iterator and will be blown away.
  196.                 # the reason we can't "break" out of the loop is because there will be a handle leak.
  197.                 # and we can't use enumerate_modules() because we need the entire module structure.
  198.                 # so there...
  199.                 found = copy.copy(module)
  200.  
  201.         return found
  202.  
  203.  
  204.     ####################################################################################################################
  205.     def attach (self, pid):
  206.         '''
  207.        Attach to the specified process by PID. Saves a process handle in self.h_process and prevents debuggee from
  208.        exiting on debugger quit.
  209.  
  210.        @type  pid: Integer
  211.        @param pid: Process ID to attach to
  212.  
  213.        @raise pdx: An exception is raised on failure.
  214.        @rtype:     pydbg
  215.        @return:    Self
  216.        '''
  217.  
  218.         self._log("attaching to pid %d" % pid)
  219.  
  220.         # obtain necessary debug privileges.
  221.         self.get_debug_privileges()
  222.  
  223.         self.pid = pid
  224.         self.open_process(pid)
  225.  
  226.         self.debug_active_process(pid)
  227.  
  228.         # allow detaching on systems that support it.
  229.         try:
  230.             self.debug_set_process_kill_on_exit(False)
  231.         except:
  232.             pass
  233.  
  234.         # enumerate the TEBs and add them to the internal dictionary.
  235.         for thread_id in self.enumerate_threads():
  236.             thread_handle  = self.open_thread(thread_id)
  237.             thread_context = self.get_thread_context(thread_handle)
  238.             selector_entry = LDT_ENTRY()
  239.  
  240.             if not kernel32.GetThreadSelectorEntry(thread_handle, thread_context.SegFs, byref(selector_entry)):
  241.                 self.win32_error("GetThreadSelectorEntry()")
  242.  
  243.             self.close_handle(thread_handle)
  244.  
  245.             teb  = selector_entry.BaseLow
  246.             teb += (selector_entry.HighWord.Bits.BaseMid << 16) + (selector_entry.HighWord.Bits.BaseHi << 24)
  247.  
  248.             # add this TEB to the internal dictionary.
  249.             self.tebs[thread_id] = teb
  250.  
  251.             # if the PEB has not been set yet, do so now.
  252.             if not self.peb:
  253.                 self.peb = self.read_process_memory(teb + 0x30, 4)
  254.                 self.peb = struct.unpack("<L", self.peb)[0]
  255.  
  256.         return self.ret_self()
  257.  
  258.  
  259.     ####################################################################################################################
  260.     def bp_del (self, address):
  261.         '''
  262.        Removes the breakpoint from target address.
  263.  
  264.        @see: bp_set(), bp_del_all(), bp_is_ours()
  265.  
  266.        @type  address: DWORD or List
  267.        @param address: Address or list of addresses to remove breakpoint from
  268.  
  269.        @raise pdx: An exception is raised on failure.
  270.        @rtype:     pydbg
  271.        @return:    Self
  272.        '''
  273.  
  274.         # if a list of addresses to remove breakpoints from was supplied.
  275.         if type(address) is list:
  276.             # pass each lone address to ourself.
  277.             for addr in address:
  278.                 self.bp_del(addr)
  279.  
  280.             return self.ret_self()
  281.  
  282.         self._log("bp_del(0x%08x)" % address)
  283.  
  284.         # ensure a breakpoint exists at the target address.
  285.         if self.breakpoints.has_key(address):
  286.             # restore the original byte.
  287.             self.write_process_memory(address, self.breakpoints[address].original_byte)
  288.             self.set_attr("dirty", True)
  289.  
  290.             # remove the breakpoint from the internal list.
  291.             del self.breakpoints[address]
  292.  
  293.         return self.ret_self()
  294.  
  295.  
  296.     ####################################################################################################################
  297.     def bp_del_all (self):
  298.         '''
  299.        Removes all breakpoints from the debuggee.
  300.  
  301.        @see: bp_set(), bp_del(), bp_is_ours()
  302.  
  303.        @raise pdx: An exception is raised on failure.
  304.        @rtype:     pydbg
  305.        @return:    Self
  306.        '''
  307.  
  308.         self._log("bp_del_all()")
  309.  
  310.         for bp in self.breakpoints.keys():
  311.             self.bp_del(bp)
  312.  
  313.         return self.ret_self()
  314.  
  315.  
  316.     ####################################################################################################################
  317.     def bp_del_hw (self, address=None, slot=None):
  318.         '''
  319.        Removes the hardware breakpoint from the specified address or slot. Either an address or a slot must be
  320.        specified, but not both.
  321.  
  322.        @see:  bp_set_hw(), bp_del_hw_all()
  323.  
  324.        @type  address:   DWORD
  325.        @param address:   (Optional) Address to remove hardware breakpoint from.
  326.        @type  slot:      Integer (0 through 3)
  327.        @param slot:      (Optional)
  328.  
  329.        @raise pdx: An exception is raised on failure.
  330.        @rtype:     pydbg
  331.        @return:    Self
  332.        '''
  333.  
  334.         if address == slot == None:
  335.             raise pdx("hw bp address or slot # must be specified.")
  336.  
  337.         if not address and slot not in xrange(4):
  338.             raise pdx("invalid hw bp slot: %d. valid range is 0 through 3" % slot)
  339.  
  340.         # de-activate the hardware breakpoint for all active threads.
  341.         for thread_id in self.enumerate_threads():
  342.             context = self.get_thread_context(thread_id=thread_id)
  343.  
  344.             if address:
  345.                 if   context.Dr0 == address: slot = 0
  346.                 elif context.Dr1 == address: slot = 1
  347.                 elif context.Dr2 == address: slot = 2
  348.                 elif context.Dr3 == address: slot = 3
  349.  
  350.             # mark slot as inactive.
  351.             # bits 0, 2, 4, 6 for local  (L0 - L3)
  352.             # bits 1, 3, 5, 7 for global (L0 - L3)
  353.  
  354.             context.Dr7 &= ~(1 << (slot * 2))
  355.  
  356.             # remove address from the specified slot.
  357.             if   slot == 0: context.Dr0 = 0x00000000
  358.             elif slot == 1: context.Dr1 = 0x00000000
  359.             elif slot == 2: context.Dr2 = 0x00000000
  360.             elif slot == 3: context.Dr3 = 0x00000000
  361.  
  362.             # remove the condition (RW0 - RW3) field from the appropriate slot (bits 16/17, 20/21, 24,25, 28/29)
  363.             context.Dr7 &= ~(3 << ((slot * 4) + 16))
  364.  
  365.             # remove the length (LEN0-LEN3) field from the appropriate slot (bits 18/19, 22/23, 26/27, 30/31)
  366.             context.Dr7 &= ~(3 << ((slot * 4) + 18))
  367.  
  368.             # set the thread context.
  369.             self.set_thread_context(context, thread_id=thread_id)
  370.  
  371.         # remove the breakpoint from the internal list.
  372.         del self.hardware_breakpoints[slot]
  373.  
  374.         return self.ret_self()
  375.  
  376.  
  377.     ####################################################################################################################
  378.     def bp_del_hw_all (self):
  379.         '''
  380.        Removes all hardware breakpoints from the debuggee.
  381.  
  382.        @see: bp_set_hw(), bp_del_hw()
  383.  
  384.        @raise pdx: An exception is raised on failure.
  385.        @rtype:     pydbg
  386.        @return:    Self
  387.        '''
  388.  
  389.         if self.hardware_breakpoints.has_key(0): self.bp_del_hw(slot=0)
  390.         if self.hardware_breakpoints.has_key(1): self.bp_del_hw(slot=1)
  391.         if self.hardware_breakpoints.has_key(2): self.bp_del_hw(slot=2)
  392.         if self.hardware_breakpoints.has_key(3): self.bp_del_hw(slot=3)
  393.  
  394.         return self.ret_self()
  395.  
  396.  
  397.     ####################################################################################################################
  398.     def bp_del_mem (self, address):
  399.         '''
  400.        Removes the memory breakpoint from target address.
  401.  
  402.        @see: bp_del_mem_all(), bp_set_mem(), bp_is_ours_mem()
  403.  
  404.        @type  address: DWORD
  405.        @param address: Address or list of addresses to remove memory breakpoint from
  406.  
  407.        @raise pdx: An exception is raised on failure.
  408.        @rtype:     pydbg
  409.        @return:    Self
  410.        '''
  411.  
  412.         self._log("bp_del_mem(0x%08x)" % address)
  413.  
  414.         # ensure a memory breakpoint exists at the target address.
  415.         if self.memory_breakpoints.has_key(address):
  416.             size = self.memory_breakpoints[address].size
  417.             mbi  = self.memory_breakpoints[address].mbi
  418.  
  419.             # remove the memory breakpoint from our internal list.
  420.             del self.memory_breakpoints[address]
  421.  
  422.             # page-aligned target memory range.
  423.             start = mbi.BaseAddress
  424.             end   = address + size                                  # non page-aligned range end
  425.             end   = end + self.page_size - (end % self.page_size)   # page-aligned range end
  426.  
  427.             # for each page in the target range, restore the original page permissions if no other breakpoint exists.
  428.             for page in range(start, end, self.page_size):
  429.                 other_bp_found = False
  430.  
  431.                 for mem_bp in self.memory_breakpoints.values():
  432.                     if page <= mem_bp.address < page + self.page_size:
  433.                         other_bp_found = True
  434.                         break
  435.                     if page <= mem_bp.address + size < page + self.page_size:
  436.                         other_bp_found = True
  437.                         break
  438.  
  439.                 if not other_bp_found:
  440.                     try:
  441.                         self.virtual_protect(page, 1, mbi.Protect & ~PAGE_GUARD)
  442.  
  443.                         # remove the page from the set of tracked GUARD pages.
  444.                         self._guarded_pages.remove(mbi.BaseAddress)
  445.                     except:
  446.                         pass
  447.  
  448.         return self.ret_self()
  449.  
  450.  
  451.     ####################################################################################################################
  452.     def bp_del_mem_all (self):
  453.         '''
  454.        Removes all memory breakpoints from the debuggee.
  455.  
  456.        @see: bp_del_mem(), bp_set_mem(), bp_is_ours_mem()
  457.  
  458.        @raise pdx: An exception is raised on failure.
  459.        @rtype:     pydbg
  460.        @return:    Self
  461.        '''
  462.  
  463.         self._log("bp_del_mem_all()")
  464.  
  465.         for address in self.memory_breakpoints.keys():
  466.             self.bp_del_mem(address)
  467.  
  468.         return self.ret_self()
  469.  
  470.  
  471.     ####################################################################################################################
  472.     def bp_is_ours (self, address_to_check):
  473.         '''
  474.        Determine if a breakpoint address belongs to us.
  475.  
  476.        @see: bp_set(), bp_del(), bp_del_all()
  477.  
  478.        @type  address_to_check: DWORD
  479.        @param address_to_check: Address to check if we have set a breakpoint at
  480.  
  481.        @rtype:  Bool
  482.        @return: True if breakpoint in question is ours, False otherwise
  483.        '''
  484.  
  485.         if self.breakpoints.has_key(address_to_check):
  486.             return True
  487.  
  488.         return False
  489.  
  490.  
  491.     ####################################################################################################################
  492.     def bp_is_ours_mem (self, address_to_check):
  493.         '''
  494.        Determines if the specified address falls within the range of one of our memory breakpoints. When handling
  495.        potential memory breakpoint exceptions it is mandatory to check the offending address with this routine as
  496.        memory breakpoints are implemented by changing page permissions and the referenced address may very well exist
  497.        within the same page as a memory breakpoint but not within the actual range of the buffer we wish to break on.
  498.  
  499.        @see: bp_set_mem(), bp_del_mem(), bp_del_mem_all()
  500.  
  501.        @type  address_to_check: DWORD
  502.        @param address_to_check: Address to check if we have set a breakpoint on
  503.  
  504.        @rtype:  Mixed
  505.        @return: The starting address of the buffer our breakpoint triggered on or False if address falls outside range.
  506.        '''
  507.  
  508.         for address in self.memory_breakpoints:
  509.             size = self.memory_breakpoints[address].size
  510.  
  511.             if address_to_check >= address and address_to_check <= address + size:
  512.                 return address
  513.  
  514.         return False
  515.  
  516.  
  517.     ####################################################################################################################
  518.     def bp_set (self, address, description="", restore=True, handler=None):
  519.         '''
  520.        Sets a breakpoint at the designated address. Register an EXCEPTION_BREAKPOINT callback handler to catch
  521.        breakpoint events. If a list of addresses is submitted to this routine then the entire list of new breakpoints
  522.        get the same description and restore. The optional "handler" parameter can be used to identify a function to
  523.        specifically handle the specified bp, as opposed to the generic bp callback handler. The prototype of the
  524.        callback routines is::
  525.  
  526.            func (pydbg)
  527.                return DBG_CONTINUE     # or other continue status
  528.  
  529.        @see: bp_is_ours(), bp_del(), bp_del_all()
  530.  
  531.        @type  address:     DWORD or List
  532.        @param address:     Address or list of addresses to set breakpoint at
  533.        @type  description: String
  534.        @param description: (Optional) Description to associate with this breakpoint
  535.        @type  restore:     Bool
  536.        @param restore:     (Optional, def=True) Flag controlling whether or not to restore the breakpoint
  537.        @type  handler:     Function Pointer
  538.        @param handler:     (Optional, def=None) Optional handler to call for this bp instead of the default handler
  539.  
  540.        @raise pdx: An exception is raised on failure.
  541.        @rtype:     pydbg
  542.        @return:    Self
  543.        '''
  544.  
  545.         # if a list of addresses to set breakpoints on from was supplied
  546.         if type(address) is list:
  547.             # pass each lone address to ourself (each one gets the same description / restore flag).
  548.             for addr in address:
  549.                 self.bp_set(addr, description, restore, handler)
  550.  
  551.             return self.ret_self()
  552.  
  553.         self._log("bp_set(0x%08x)" % address)
  554.  
  555.         # ensure a breakpoint doesn't already exist at the target address.
  556.         if not self.breakpoints.has_key(address):
  557.             try:
  558.                 # save the original byte at the requested breakpoint address.
  559.                 original_byte = self.read_process_memory(address, 1)
  560.  
  561.                 # write an int3 into the target process space.
  562.                 self.write_process_memory(address, "\xCC")
  563.                 self.set_attr("dirty", True)
  564.  
  565.                 # add the breakpoint to the internal list.
  566.                 self.breakpoints[address] = breakpoint(address, original_byte, description, restore, handler)
  567.             except:
  568.                 raise pdx("Failed setting breakpoint at %08x" % address)
  569.  
  570.         return self.ret_self()
  571.  
  572.  
  573.     ####################################################################################################################
  574.     def bp_set_hw (self, address, length, condition, description="", restore=True, handler=None):
  575.         '''
  576.        Sets a hardware breakpoint at the designated address. Register an EXCEPTION_SINGLE_STEP callback handler to
  577.        catch hardware breakpoint events. Setting hardware breakpoints requires the internal h_thread handle be set.
  578.        This means that you can not set one outside the context of an debug event handler. If you want to set a hardware
  579.        breakpoint as soon as you attach to or load a process, do so in the first chance breakpoint handler.
  580.  
  581.        For more information regarding the Intel x86 debug registers and hardware breakpoints see::
  582.  
  583.            http://pdos.csail.mit.edu/6.828/2005/readings/ia32/IA32-3.pdf
  584.            Section 15.2
  585.  
  586.        Alternatively, you can register a custom handler to handle hits on the specific hw breakpoint slot.
  587.  
  588.        *Warning: Setting hardware breakpoints during the first system breakpoint will be removed upon process
  589.        continue.  A better approach is to set a software breakpoint that when hit will set your hardware breakpoints.
  590.  
  591.        @note: Hardware breakpoints are handled globally throughout the entire process and not a single specific thread.
  592.        @see:  bp_del_hw(), bp_del_hw_all()
  593.  
  594.        @type  address:     DWORD
  595.        @param address:     Address to set hardware breakpoint at
  596.        @type  length:      Integer (1, 2 or 4)
  597.        @param length:      Size of hardware breakpoint in bytes (byte, word or dword)
  598.        @type  condition:   Integer (HW_ACCESS, HW_WRITE, HW_EXECUTE)
  599.        @param condition:   Condition to set the hardware breakpoint to activate on
  600.        @type  description: String
  601.        @param description: (Optional) Description of breakpoint
  602.        @type  restore:     Boolean
  603.        @param restore:     (Optional, def=True) Flag controlling whether or not to restore the breakpoint
  604.        @type  handler:     Function Pointer
  605.        @param handler:     (Optional, def=None) Optional handler to call for this bp instead of the default handler
  606.  
  607.        @raise pdx: An exception is raised on failure.
  608.        @rtype:     pydbg
  609.        @return:    Self
  610.        '''
  611.  
  612.         self._log("bp_set_hw(%08x, %d, %s)" % (address, length, condition))
  613.  
  614.         # instantiate a new hardware breakpoint object for the new bp to create.
  615.         hw_bp = hardware_breakpoint(address, length, condition, description, restore, handler=handler)
  616.  
  617.         if length not in (1, 2, 4):
  618.             raise pdx("invalid hw breakpoint length: %d." % length)
  619.  
  620.         # length -= 1 because the following codes are used for determining length:
  621.         #       00 - 1 byte length
  622.         #       01 - 2 byte length
  623.         #       10 - undefined
  624.         #       11 - 4 byte length
  625.         length -= 1
  626.  
  627.         # condition table:
  628.         #       00 - break on instruction execution only
  629.         #       01 - break on data writes only
  630.         #       10 - undefined
  631.         #       11 - break on data reads or writes but not instruction fetches
  632.         if condition not in (HW_ACCESS, HW_EXECUTE, HW_WRITE):
  633.             raise pdx("invalid hw breakpoint condition: %d" % condition)
  634.  
  635.         # check for any available hardware breakpoint slots. there doesn't appear to be any difference between local
  636.         # and global as far as we are concerned on windows.
  637.         #
  638.         #     bits 0, 2, 4, 6 for local  (L0 - L3)
  639.         #     bits 1, 3, 5, 7 for global (G0 - G3)
  640.         #
  641.         # we could programatically search for an open slot in a given thread context with the following code:
  642.         #
  643.         #    available = None
  644.         #    for slot in xrange(4):
  645.         #        if context.Dr7 & (1 << (slot * 2)) == 0:
  646.         #            available = slot
  647.         #            break
  648.         #
  649.         # but since we are doing global hardware breakpoints, we rely on ourself for tracking open slots.
  650.  
  651.         if not self.hardware_breakpoints.has_key(0):
  652.             available = 0
  653.         elif not self.hardware_breakpoints.has_key(1):
  654.             available = 1
  655.         elif not self.hardware_breakpoints.has_key(2):
  656.             available = 2
  657.         elif not self.hardware_breakpoints.has_key(3):
  658.             available = 3
  659.         else:
  660.             raise pdx("no hw breakpoint slots available.")
  661.  
  662.         # activate the hardware breakpoint for all active threads.
  663.         for thread_id in self.enumerate_threads():
  664.             context = self.get_thread_context(thread_id=thread_id)
  665.  
  666.             # mark available debug register as active (L0 - L3).
  667.             context.Dr7 |= 1 << (available * 2)
  668.  
  669.             # save our breakpoint address to the available hw bp slot.
  670.             if   available == 0: context.Dr0 = address
  671.             elif available == 1: context.Dr1 = address
  672.             elif available == 2: context.Dr2 = address
  673.             elif available == 3: context.Dr3 = address
  674.  
  675.             # set the condition (RW0 - RW3) field for the appropriate slot (bits 16/17, 20/21, 24,25, 28/29)
  676.             context.Dr7 |= condition << ((available * 4) + 16)
  677.  
  678.             # set the length (LEN0-LEN3) field for the appropriate slot (bits 18/19, 22/23, 26/27, 30/31)
  679.             context.Dr7 |= length << ((available * 4) + 18)
  680.  
  681.             # set the thread context.
  682.             self.set_thread_context(context, thread_id=thread_id)
  683.  
  684.         # update the internal hardware breakpoint array at the used slot index.
  685.         hw_bp.slot = available
  686.         self.hardware_breakpoints[available] = hw_bp
  687.  
  688.         return self.ret_self()
  689.  
  690.  
  691.     ####################################################################################################################
  692.     def bp_set_mem (self, address, size, description="", handler=None):
  693.         '''
  694.        Sets a memory breakpoint at the target address. This is implemented by changing the permissions of the page
  695.        containing the address to PAGE_GUARD. To catch memory breakpoints you have to register the EXCEPTION_GUARD_PAGE
  696.        callback. Within the callback handler check the internal pydbg variable self.memory_breakpoint_hit to
  697.        determine if the violation was a result of a direct memory breakpoint hit or some unrelated event.
  698.        Alternatively, you can register a custom handler to handle the memory breakpoint. Memory breakpoints are
  699.        automatically restored via the internal single step handler. To remove a memory breakpoint, you must explicitly
  700.        call bp_del_mem().
  701.  
  702.        @see: bp_is_ours_mem(), bp_del_mem(), bp_del_mem_all()
  703.  
  704.        @type  address:     DWORD
  705.        @param address:     Starting address of the buffer to break on
  706.        @type  size:        Integer
  707.        @param size:        Size of the buffer to break on
  708.        @type  description: String
  709.        @param description: (Optional) Description to associate with this breakpoint
  710.        @type  handler:     Function Pointer
  711.        @param handler:     (Optional, def=None) Optional handler to call for this bp instead of the default handler
  712.  
  713.        @raise pdx: An exception is raised on failure.
  714.        @rtype:     pydbg
  715.        @return:    Self
  716.        '''
  717.  
  718.         self._log("bp_set_mem() buffer range is %08x - %08x" % (address, address + size))
  719.  
  720.         # ensure the target address doesn't already sit in a memory breakpoint range:
  721.         if self.bp_is_ours_mem(address):
  722.             self._log("a memory breakpoint spanning %08x already exists" % address)
  723.             return self.ret_self()
  724.  
  725.         # determine the base address of the page containing the starting point of our buffer.
  726.         try:
  727.             mbi = self.virtual_query(address)
  728.         except:
  729.             raise pdx("bp_set_mem(): failed querying address: %08x" % address)
  730.  
  731.         self._log("buffer starting at %08x sits on page starting at %08x" % (address, mbi.BaseAddress))
  732.  
  733.         # individually change the page permissions for each page our buffer spans.
  734.         # why do we individually set the page permissions of each page as opposed to a range of pages? because empirical
  735.         # testing shows that when you set a PAGE_GUARD on a range of pages, if any of those pages are accessed, then
  736.         # the PAGE_GUARD attribute is dropped for the entire range of pages that was originally modified. this is
  737.         # undesirable for our purposes when it comes to the ease of restoring hit memory breakpoints.
  738.         current_page = mbi.BaseAddress
  739.  
  740.         while current_page <= address + size:
  741.             self._log("changing page permissions on %08x" % current_page)
  742.  
  743.             # keep track of explicitly guarded pages, to differentiate from pages guarded by the debuggee / OS.
  744.             self._guarded_pages.add(current_page)
  745.             self.virtual_protect(current_page, 1, mbi.Protect | PAGE_GUARD)
  746.  
  747.             current_page += self.page_size
  748.  
  749.         # add the breakpoint to the internal list.
  750.         self.memory_breakpoints[address] = memory_breakpoint(address, size, mbi, description, handler)
  751.  
  752.         return self.ret_self()
  753.  
  754.  
  755.     ####################################################################################################################
  756.     def close_handle (self, handle):
  757.         '''
  758.        Convenience wraper around kernel32.CloseHandle()
  759.  
  760.        @type  handle: Handle
  761.        @param handle: Handle to close
  762.  
  763.        @rtype:  Bool
  764.        @return: Return value from CloseHandle().
  765.        '''
  766.  
  767.         return kernel32.CloseHandle(handle)
  768.  
  769.  
  770.     ####################################################################################################################
  771.     def dbg_print_all_debug_registers (self):
  772.         '''
  773.        *** DEBUG ROUTINE ***
  774.  
  775.        This is a debugging routine that was used when debugging hardware breakpoints. It was too useful to be removed
  776.        from the release code.
  777.        '''
  778.  
  779.         # ensure we have an up to date context for the current thread.
  780.         context = self.get_thread_context(self.h_thread)
  781.  
  782.         print "eip = %08x" % context.Eip
  783.         print "Dr0 = %08x" % context.Dr0
  784.         print "Dr1 = %08x" % context.Dr1
  785.         print "Dr2 = %08x" % context.Dr2
  786.         print "Dr3 = %08x" % context.Dr3
  787.         print "Dr7 = %s"   % self.to_binary(context.Dr7)
  788.         print "      10987654321098765432109876543210"
  789.         print "      332222222222111111111"
  790.  
  791.  
  792.     ####################################################################################################################
  793.     def dbg_print_all_guarded_pages (self):
  794.         '''
  795.        *** DEBUG ROUTINE ***
  796.  
  797.        This is a debugging routine that was used when debugging memory breakpoints. It was too useful to be removed
  798.        from the release code.
  799.        '''
  800.  
  801.         cursor = 0
  802.  
  803.         # scan through the entire memory range.
  804.         while cursor < 0xFFFFFFFF:
  805.             try:
  806.                 mbi = self.virtual_query(cursor)
  807.             except:
  808.                 break
  809.  
  810.             if mbi.Protect & PAGE_GUARD:
  811.                 address = mbi.BaseAddress
  812.                 print "PAGE GUARD on %08x" % mbi.BaseAddress
  813.  
  814.                 while 1:
  815.                     address += self.page_size
  816.                     tmp_mbi  = self.virtual_query(address)
  817.  
  818.                     if not tmp_mbi.Protect & PAGE_GUARD:
  819.                         break
  820.  
  821.                     print "PAGE GUARD on %08x" % address
  822.  
  823.             cursor += mbi.RegionSize
  824.  
  825.  
  826.     ####################################################################################################################
  827.     def debug_active_process (self, pid):
  828.         '''
  829.        Convenience wrapper around GetLastError() and FormatMessage(). Returns the error code and formatted message
  830.        associated with the last error. You probably do not want to call this directly, rather look at attach().
  831.  
  832.        @type  pid: Integer
  833.        @param pid: Process ID to attach to
  834.  
  835.        @raise pdx: An exception is raised on failure.
  836.        '''
  837.  
  838.         if not kernel32.DebugActiveProcess(pid):
  839.             raise pdx("DebugActiveProcess(%d)" % pid, True)
  840.  
  841.  
  842.     ####################################################################################################################
  843.     def debug_event_iteration (self):
  844.         '''
  845.        Check for and process a debug event.
  846.        '''
  847.  
  848.         continue_status = DBG_CONTINUE
  849.         dbg             = DEBUG_EVENT()
  850.  
  851.         # wait for a debug event.
  852.         if kernel32.WaitForDebugEvent(byref(dbg), 100):
  853.             # grab various information with regards to the current exception.
  854.             self.h_thread          = self.open_thread(dbg.dwThreadId)
  855.             self.context           = self.get_thread_context(self.h_thread)
  856.             self.dbg               = dbg
  857.             self.exception_address = dbg.u.Exception.ExceptionRecord.ExceptionAddress
  858.             self.write_violation   = dbg.u.Exception.ExceptionRecord.ExceptionInformation[0]
  859.             self.violation_address = dbg.u.Exception.ExceptionRecord.ExceptionInformation[1]
  860.             self.exception_code    = dbg.u.Exception.ExceptionRecord.ExceptionCode
  861.  
  862.             if dbg.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT:
  863.                 continue_status = self.event_handler_create_process()
  864.  
  865.             elif dbg.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT:
  866.                 continue_status = self.event_handler_create_thread()
  867.  
  868.             elif dbg.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT:
  869.                 continue_status = self.event_handler_exit_process()
  870.  
  871.             elif dbg.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT:
  872.                 continue_status = self.event_handler_exit_thread()
  873.  
  874.             elif dbg.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT:
  875.                 continue_status = self.event_handler_load_dll()
  876.  
  877.             elif dbg.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT:
  878.                 continue_status = self.event_handler_unload_dll()
  879.  
  880.             # an exception was caught.
  881.             elif dbg.dwDebugEventCode == EXCEPTION_DEBUG_EVENT:
  882.                 ec = dbg.u.Exception.ExceptionRecord.ExceptionCode
  883.  
  884.                 self._log("debug_event_loop() exception: %08x" % ec)
  885.  
  886.                 # call the internal handler for the exception event that just occured.
  887.                 if ec == EXCEPTION_ACCESS_VIOLATION:
  888.                     continue_status = self.exception_handler_access_violation()
  889.                 elif ec == EXCEPTION_BREAKPOINT:
  890.                     continue_status = self.exception_handler_breakpoint()
  891.                 elif ec == EXCEPTION_GUARD_PAGE:
  892.                     continue_status = self.exception_handler_guard_page()
  893.                 elif ec == EXCEPTION_SINGLE_STEP:
  894.                     continue_status = self.exception_handler_single_step()
  895.                 # generic callback support.
  896.                 elif self.callbacks.has_key(ec):
  897.                     continue_status = self.callbacks[ec](self)
  898.                 # unhandled exception.
  899.                 else:
  900.                     self._log("TID:%04x caused an unhandled exception (%08x) at %08x" % (self.dbg.dwThreadId, ec, self.exception_address))
  901.                     continue_status = DBG_EXCEPTION_NOT_HANDLED
  902.  
  903.             # if the memory space of the debuggee was tainted, flush the instruction cache.
  904.             # from MSDN: Applications should call FlushInstructionCache if they generate or modify code in memory.
  905.             #            The CPU cannot detect the change, and may execute the old code it cached.
  906.             if self.dirty:
  907.                 kernel32.FlushInstructionCache(self.h_process, 0, 0)
  908.  
  909.             # close the opened thread handle and resume executing the thread that triggered the debug event.
  910.             self.close_handle(self.h_thread)
  911.             kernel32.ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, continue_status)
  912.  
  913.  
  914.     ####################################################################################################################
  915.     def debug_event_loop (self):
  916.         '''
  917.        Enter the infinite debug event handling loop. This is the main loop of the debugger and is responsible for
  918.        catching debug events and exceptions and dispatching them appropriately. This routine will check for and call
  919.        the USER_CALLBACK_DEBUG_EVENT callback on each loop iteration. run() is an alias for this routine.
  920.  
  921.        @see: run()
  922.  
  923.        @raise pdx: An exception is raised on any exceptional conditions, such as debugger being interrupted or
  924.        debuggee quiting.
  925.        '''
  926.  
  927.         while self.debugger_active:
  928.             # don't let the user interrupt us in the midst of handling a debug event.
  929.             try:
  930.                 def_sigint_handler = None
  931.                 def_sigint_handler = signal.signal(signal.SIGINT, self.sigint_handler)
  932.             except:
  933.                 pass
  934.  
  935.             # if a user callback was specified, call it.
  936.             if self.callbacks.has_key(USER_CALLBACK_DEBUG_EVENT):
  937.                 # user callbacks do not / should not access debugger or contextual information.
  938.                 self.dbg = self.context = None
  939.                 self.callbacks[USER_CALLBACK_DEBUG_EVENT](self)
  940.  
  941.             # iterate through a debug event.
  942.             self.debug_event_iteration()
  943.  
  944.             # resume keyboard interruptability.
  945.             if def_sigint_handler:
  946.                 signal.signal(signal.SIGINT, def_sigint_handler)
  947.  
  948.         # close the global process handle.
  949.         self.close_handle(self.h_process)
  950.  
  951.  
  952.     ####################################################################################################################
  953.     def debug_set_process_kill_on_exit (self, kill_on_exit):
  954.         '''
  955.        Convenience wrapper around DebugSetProcessKillOnExit().
  956.  
  957.        @type  kill_on_exit: Bool
  958.        @param kill_on_exit: True to kill the process on debugger exit, False to let debuggee continue running.
  959.  
  960.        @raise pdx: An exception is raised on failure.
  961.        '''
  962.  
  963.         if not kernel32.DebugSetProcessKillOnExit(kill_on_exit):
  964.             raise pdx("DebugActiveProcess(%s)" % kill_on_exit, True)
  965.  
  966.  
  967.     ####################################################################################################################
  968.     def detach (self):
  969.         '''
  970.        Detach from debuggee.
  971.  
  972.        @raise pdx: An exception is raised on failure.
  973.        @rtype:     pydbg
  974.        @return:    Self
  975.        '''
  976.  
  977.         self._log("detaching from debuggee")
  978.  
  979.         # remove all software, memory and hardware breakpoints.
  980.         self.bp_del_all()
  981.         self.bp_del_mem_all()
  982.         self.bp_del_hw_all()
  983.  
  984.         # try to detach from the target process if the API is available on the current platform.
  985.         kernel32.DebugActiveProcessStop(self.pid)
  986.  
  987.         self.set_debugger_active(False)
  988.         return self.ret_self()
  989.  
  990.  
  991.     ####################################################################################################################
  992.     def disasm (self, address):
  993.         '''
  994.        Pydasm disassemble utility function wrapper. Stores the pydasm decoded instruction in self.instruction.
  995.  
  996.        @type  address: DWORD
  997.        @param address: Address to disassemble at
  998.  
  999.        @rtype:  String
  1000.        @return: Disassembled string.
  1001.        '''
  1002.  
  1003.         try:
  1004.             data  = self.read_process_memory(address, 32)
  1005.         except:
  1006.             return "Unable to disassemble at %08x" % address
  1007.  
  1008.         # update our internal member variables.
  1009.         self.instruction = pydasm.get_instruction(data, pydasm.MODE_32)
  1010.  
  1011.         if not self.instruction:
  1012.             self.mnemonic = "[UNKNOWN]"
  1013.             self.op1      = ""
  1014.             self.op2      = ""
  1015.             self.op3      = ""
  1016.  
  1017.             return "[UNKNOWN]"
  1018.         else:
  1019.             self.mnemonic = pydasm.get_mnemonic_string(self.instruction, pydasm.FORMAT_INTEL)
  1020.             self.op1      = pydasm.get_operand_string(self.instruction, 0, pydasm.FORMAT_INTEL, address)
  1021.             self.op2      = pydasm.get_operand_string(self.instruction, 1, pydasm.FORMAT_INTEL, address)
  1022.             self.op3      = pydasm.get_operand_string(self.instruction, 2, pydasm.FORMAT_INTEL, address)
  1023.  
  1024.             # the rstrip() is for removing extraneous trailing whitespace that libdasm sometimes leaves.
  1025.             return pydasm.get_instruction_string(self.instruction, pydasm.FORMAT_INTEL, address).rstrip(" ")
  1026.  
  1027.  
  1028.     ####################################################################################################################
  1029.     def disasm_around (self, address, num_inst=5):
  1030.         '''
  1031.        Given a specified address this routine will return the list of 5 instructions before and after the instruction
  1032.        at address (including the instruction at address, so 11 instructions in total). This is accomplished by grabbing
  1033.        a larger chunk of data around the address than what is predicted as necessary and then disassembling forward.
  1034.        If during the forward disassembly the requested address lines up with the start of an instruction, then the
  1035.        assumption is made that the forward disassembly self corrected itself and the instruction set is returned. If
  1036.        we are unable to align with the original address, then we modify our data slice and try again until we do.
  1037.  
  1038.        @type  address:  DWORD
  1039.        @param address:  Address to disassemble around
  1040.        @type  num_inst: Integer
  1041.        @param num_inst: (Optional, Def=5) Number of instructions to disassemble up/down from address
  1042.  
  1043.        @rtype:  List
  1044.        @return: List of tuples (address, disassembly) of instructions around the specified address.
  1045.        '''
  1046.        
  1047.         if num_inst == 0:
  1048.             return [(address, self.disasm(address))]
  1049.        
  1050.         if num_inst < 0 or not int == type(num_inst):
  1051.             self._err("disasm_around called with an invalid window size. reurning error value")
  1052.             return [(address, "invalid window size supplied")]
  1053.        
  1054.         # grab a safe window size of bytes.
  1055.         window_size = (num_inst * 64) / 5
  1056.  
  1057.         # grab a window of bytes before and after the requested address.
  1058.         try:
  1059.             data = self.read_process_memory(address - window_size, window_size * 2)
  1060.         except:
  1061.             return [(address, "Unable to disassemble")]
  1062.  
  1063.         # the rstrip() is for removing extraneous trailing whitespace that libdasm sometimes leaves.
  1064.         i           = pydasm.get_instruction(data[window_size:], pydasm.MODE_32)
  1065.         disassembly = pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, address).rstrip(" ")
  1066.         complete    = False
  1067.         start_byte  = 0
  1068.  
  1069.         # loop until we retrieve a set of instructions that align to the requested address.
  1070.         while not complete:
  1071.             instructions = []
  1072.             slice        = data[start_byte:]
  1073.             offset       = 0
  1074.  
  1075.             # step through the bytes in the data slice.
  1076.             while offset < len(slice):
  1077.                 i = pydasm.get_instruction(slice[offset:], pydasm.MODE_32)
  1078.  
  1079.                 if not i:
  1080.                     break
  1081.  
  1082.                 # calculate the actual address of the instruction at the current offset and grab the disassembly
  1083.                 addr = address - window_size + start_byte + offset
  1084.                 inst = pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, addr).rstrip(" ")
  1085.  
  1086.                 # add the address / instruction pair to our list of tuples.
  1087.                 instructions.append((addr, inst))
  1088.  
  1089.                 # increment the offset into the data slice by the length of the current instruction.
  1090.                 offset += i.length
  1091.  
  1092.             # we're done processing a data slice.
  1093.             # step through each addres / instruction tuple in our instruction list looking for an instruction alignment
  1094.             # match. we do the match on address and the original disassembled instruction.
  1095.             index_of_address = 0
  1096.             for (addr, inst) in instructions:
  1097.                 if addr == address and inst == disassembly:
  1098.                     complete = True
  1099.                     break
  1100.  
  1101.                 index_of_address += 1
  1102.  
  1103.             start_byte += 1
  1104.  
  1105.         return instructions[index_of_address-num_inst:index_of_address+num_inst+1]
  1106.  
  1107.  
  1108.     ####################################################################################################################
  1109.     def dump_context (self, context=None, stack_depth=5, print_dots=True):
  1110.         '''
  1111.        Return an informational block of text describing the CPU context of the current thread. Information includes:
  1112.            - Disassembly at current EIP
  1113.            - Register values in hex, decimal and "smart" dereferenced
  1114.            - ESP, ESP+4, ESP+8 ... values in hex, decimal and "smart" dereferenced
  1115.  
  1116.        @see: dump_context_list()
  1117.  
  1118.        @type  context:     Context
  1119.        @param context:     (Optional) Current thread context to examine
  1120.        @type  stack_depth: Integer
  1121.        @param stack_depth: (Optional, def:5) Number of dwords to dereference off of the stack (not including ESP)
  1122.        @type  print_dots:  Bool
  1123.        @param print_dots:  (Optional, def:True) Controls suppression of dot in place of non-printable
  1124.  
  1125.        @rtype:  String
  1126.        @return: Information about current thread context.
  1127.        '''
  1128.  
  1129.         # if the optional current thread context was not supplied, grab it for the current thread.
  1130.         if not context:
  1131.             context = self.context
  1132.  
  1133.         context_list = self.dump_context_list(context, stack_depth, print_dots)
  1134.  
  1135.         context_dump  = "CONTEXT DUMP\n"
  1136.         context_dump += "  EIP: %08x %s\n" % (context.Eip, context_list["eip"])
  1137.         context_dump += "  EAX: %08x (%10d) -> %s\n" % (context.Eax, context.Eax, context_list["eax"])
  1138.         context_dump += "  EBX: %08x (%10d) -> %s\n" % (context.Ebx, context.Ebx, context_list["ebx"])
  1139.         context_dump += "  ECX: %08x (%10d) -> %s\n" % (context.Ecx, context.Ecx, context_list["ecx"])
  1140.         context_dump += "  EDX: %08x (%10d) -> %s\n" % (context.Edx, context.Edx, context_list["edx"])
  1141.         context_dump += "  EDI: %08x (%10d) -> %s\n" % (context.Edi, context.Edi, context_list["edi"])
  1142.         context_dump += "  ESI: %08x (%10d) -> %s\n" % (context.Esi, context.Esi, context_list["esi"])
  1143.         context_dump += "  EBP: %08x (%10d) -> %s\n" % (context.Ebp, context.Ebp, context_list["ebp"])
  1144.         context_dump += "  ESP: %08x (%10d) -> %s\n" % (context.Esp, context.Esp, context_list["esp"])
  1145.  
  1146.         for offset in xrange(0, stack_depth + 1):
  1147.             context_dump += "  +%02x: %08x (%10d) -> %s\n" %    \
  1148.             (                                                   \
  1149.                 offset * 4,                                     \
  1150.                 context_list["esp+%02x"%(offset*4)]["value"],   \
  1151.                 context_list["esp+%02x"%(offset*4)]["value"],   \
  1152.                 context_list["esp+%02x"%(offset*4)]["desc"]     \
  1153.             )
  1154.  
  1155.         return context_dump
  1156.  
  1157.  
  1158.     ####################################################################################################################
  1159.     def dump_context_list (self, context=None, stack_depth=5, print_dots=True, hex_dump=False):
  1160.         '''
  1161.        Return an informational list of items describing the CPU context of the current thread. Information includes:
  1162.            - Disassembly at current EIP
  1163.            - Register values in hex, decimal and "smart" dereferenced
  1164.            - ESP, ESP+4, ESP+8 ... values in hex, decimal and "smart" dereferenced
  1165.  
  1166.        @see: dump_context()
  1167.  
  1168.        @type  context:     Context
  1169.        @param context:     (Optional) Current thread context to examine
  1170.        @type  stack_depth: Integer
  1171.        @param stack_depth: (Optional, def:5) Number of dwords to dereference off of the stack (not including ESP)
  1172.        @type  print_dots:  Bool
  1173.        @param print_dots:  (Optional, def:True) Controls suppression of dot in place of non-printable
  1174.        @type  hex_dump:   Bool
  1175.        @param hex_dump:   (Optional, def=False) Return a hex dump in the absense of string detection
  1176.  
  1177.        @rtype:  Dictionary
  1178.        @return: Dictionary of information about current thread context.
  1179.        '''
  1180.  
  1181.         # if the optional current thread context was not supplied, grab it for the current thread.
  1182.         if not context:
  1183.             context = self.context
  1184.  
  1185.         context_list = {}
  1186.  
  1187.         context_list["eip"] = self.disasm(context.Eip)
  1188.         context_list["eax"] = self.smart_dereference(context.Eax, print_dots, hex_dump)
  1189.         context_list["ebx"] = self.smart_dereference(context.Ebx, print_dots, hex_dump)
  1190.         context_list["ecx"] = self.smart_dereference(context.Ecx, print_dots, hex_dump)
  1191.         context_list["edx"] = self.smart_dereference(context.Edx, print_dots, hex_dump)
  1192.         context_list["edi"] = self.smart_dereference(context.Edi, print_dots, hex_dump)
  1193.         context_list["esi"] = self.smart_dereference(context.Esi, print_dots, hex_dump)
  1194.         context_list["ebp"] = self.smart_dereference(context.Ebp, print_dots, hex_dump)
  1195.         context_list["esp"] = self.smart_dereference(context.Esp, print_dots, hex_dump)
  1196.  
  1197.         for offset in xrange(0, stack_depth + 1):
  1198.             try:
  1199.                 esp = self.flip_endian_dword(self.read_process_memory(context.Esp + offset * 4, 4))
  1200.  
  1201.                 context_list["esp+%02x"%(offset*4)]          = {}
  1202.                 context_list["esp+%02x"%(offset*4)]["value"] = esp
  1203.                 context_list["esp+%02x"%(offset*4)]["desc"]  = self.smart_dereference(esp, print_dots, hex_dump)
  1204.             except:
  1205.                 context_list["esp+%02x"%(offset*4)]          = {}
  1206.                 context_list["esp+%02x"%(offset*4)]["value"] = 0
  1207.                 context_list["esp+%02x"%(offset*4)]["desc"]  = "[INVALID]"
  1208.  
  1209.         return context_list
  1210.  
  1211.  
  1212.     #####################################################################################################################
  1213.     def enumerate_modules (self):
  1214.         '''
  1215.        Using the CreateToolhelp32Snapshot() API enumerate and return the list of module name / base address tuples that
  1216.        belong to the debuggee
  1217.  
  1218.        @see: iterate_modules()
  1219.  
  1220.        @rtype:  List
  1221.        @return: List of module name / base address tuples.
  1222.        '''
  1223.  
  1224.         self._log("enumerate_modules()")
  1225.  
  1226.         module      = MODULEENTRY32()
  1227.         module_list = []
  1228.         snapshot    = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, self.pid)
  1229.  
  1230.         if snapshot == INVALID_HANDLE_VALUE:
  1231.             raise pdx("CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, %d" % self.pid, True)
  1232.  
  1233.         # we *must* set the size of the structure prior to using it, otherwise Module32First() will fail.
  1234.         module.dwSize = sizeof(module)
  1235.  
  1236.         found_mod = kernel32.Module32First(snapshot, byref(module))
  1237.  
  1238.         while found_mod:
  1239.             module_list.append((module.szModule, module.modBaseAddr))
  1240.             found_mod = kernel32.Module32Next(snapshot, byref(module))
  1241.  
  1242.         self.close_handle(snapshot)
  1243.         return module_list
  1244.  
  1245.  
  1246.     ####################################################################################################################
  1247.     def enumerate_processes (self):
  1248.         '''
  1249.        Using the CreateToolhelp32Snapshot() API enumerate all system processes returning a list of pid / process name
  1250.        tuples.
  1251.  
  1252.        @see: iterate_processes()
  1253.  
  1254.        @rtype:  List
  1255.        @return: List of pid / process name tuples.
  1256.  
  1257.        Example::
  1258.  
  1259.            for (pid, name) in pydbg.enumerate_processes():
  1260.                if name == "test.exe":
  1261.                    break
  1262.  
  1263.            pydbg.attach(pid)
  1264.        '''
  1265.  
  1266.         self._log("enumerate_processes()")
  1267.  
  1268.         pe           = PROCESSENTRY32()
  1269.         process_list = []
  1270.         snapshot     = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
  1271.  
  1272.         if snapshot == INVALID_HANDLE_VALUE:
  1273.             raise pdx("CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0", True)
  1274.  
  1275.         # we *must* set the size of the structure prior to using it, otherwise Process32First() will fail.
  1276.         pe.dwSize = sizeof(PROCESSENTRY32)
  1277.  
  1278.         found_proc = kernel32.Process32First(snapshot, byref(pe))
  1279.  
  1280.         while found_proc:
  1281.             process_list.append((pe.th32ProcessID, pe.szExeFile))
  1282.             found_proc = kernel32.Process32Next(snapshot, byref(pe))
  1283.  
  1284.         self.close_handle(snapshot)
  1285.         return process_list
  1286.  
  1287.  
  1288.     ####################################################################################################################
  1289.     def enumerate_threads (self):
  1290.         '''
  1291.        Using the CreateToolhelp32Snapshot() API enumerate all system threads returning a list of thread IDs that
  1292.        belong to the debuggee.
  1293.  
  1294.        @see: iterate_threads()
  1295.  
  1296.        @rtype:  List
  1297.        @return: List of thread IDs belonging to the debuggee.
  1298.  
  1299.        Example::
  1300.            for thread_id in self.enumerate_threads():
  1301.                context = self.get_thread_context(None, thread_id)
  1302.        '''
  1303.  
  1304.         self._log("enumerate_threads()")
  1305.  
  1306.         thread_entry     = THREADENTRY32()
  1307.         debuggee_threads = []
  1308.         snapshot         = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, self.pid)
  1309.  
  1310.         if snapshot == INVALID_HANDLE_VALUE:
  1311.             raise pdx("CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, %d" % self.pid, True)
  1312.  
  1313.         # we *must* set the size of the structure prior to using it, otherwise Thread32First() will fail.
  1314.         thread_entry.dwSize = sizeof(thread_entry)
  1315.  
  1316.         success = kernel32.Thread32First(snapshot, byref(thread_entry))
  1317.  
  1318.         while success:
  1319.             if thread_entry.th32OwnerProcessID == self.pid:
  1320.                 debuggee_threads.append(thread_entry.th32ThreadID)
  1321.  
  1322.             success = kernel32.Thread32Next(snapshot, byref(thread_entry))
  1323.  
  1324.         self.close_handle(snapshot)
  1325.         return debuggee_threads
  1326.  
  1327.  
  1328.     ####################################################################################################################
  1329.     def event_handler_create_process (self):
  1330.         '''
  1331.        This is the default CREATE_PROCESS_DEBUG_EVENT handler.
  1332.  
  1333.        @rtype:  DWORD
  1334.        @return: Debug event continue status.
  1335.        '''
  1336.  
  1337.         self._log("event_handler_create_process()")
  1338.  
  1339.         # don't need this.
  1340.         self.close_handle(self.dbg.u.CreateProcessInfo.hFile)
  1341.  
  1342.         if not self.follow_forks:
  1343.             return DBG_CONTINUE
  1344.  
  1345.         if self.callbacks.has_key(CREATE_PROCESS_DEBUG_EVENT):
  1346.             return self.callbacks[CREATE_PROCESS_DEBUG_EVENT](self)
  1347.         else:
  1348.             return DBG_CONTINUE
  1349.  
  1350.  
  1351.     ####################################################################################################################
  1352.     def event_handler_create_thread (self):
  1353.         '''
  1354.        This is the default CREATE_THREAD_DEBUG_EVENT handler.
  1355.  
  1356.        @rtype:  DWORD
  1357.        @return: Debug event continue status.
  1358.        '''
  1359.  
  1360.         self._log("event_handler_create_thread(%d)" % self.dbg.dwThreadId)
  1361.  
  1362.         # resolve the newly created threads TEB and add it to the internal dictionary.
  1363.         thread_id      = self.dbg.dwThreadId
  1364.         thread_handle  = self.dbg.u.CreateThread.hThread
  1365.         thread_context = self.get_thread_context(thread_handle)
  1366.         selector_entry = LDT_ENTRY()
  1367.  
  1368.         if not kernel32.GetThreadSelectorEntry(thread_handle, thread_context.SegFs, byref(selector_entry)):
  1369.             self.win32_error("GetThreadSelectorEntry()")
  1370.  
  1371.         teb  = selector_entry.BaseLow
  1372.         teb += (selector_entry.HighWord.Bits.BaseMid << 16) + (selector_entry.HighWord.Bits.BaseHi << 24)
  1373.  
  1374.         # add this TEB to the internal dictionary.
  1375.         self.tebs[thread_id] = teb
  1376.  
  1377.         #  apply any existing hardware breakpoints to this new thread.
  1378.         for slot, hw_bp in self.hardware_breakpoints.items():
  1379.             # mark available debug register as active (L0 - L3).
  1380.             thread_context.Dr7 |= 1 << (slot * 2)
  1381.  
  1382.             # save our breakpoint address to the available hw bp slot.
  1383.             if   slot == 0: thread_context.Dr0 = hw_bp.address
  1384.             elif slot == 1: thread_context.Dr1 = hw_bp.address
  1385.             elif slot == 2: thread_context.Dr2 = hw_bp.address
  1386.             elif slot == 3: thread_context.Dr3 = hw_bp.address
  1387.  
  1388.             # set the condition (RW0 - RW3) field for the appropriate slot (bits 16/17, 20/21, 24,25, 28/29)
  1389.             thread_context.Dr7 |= hw_bp.condition << ((slot * 4) + 16)
  1390.  
  1391.             # set the length (LEN0-LEN3) field for the appropriate slot (bits 18/19, 22/23, 26/27, 30/31)
  1392.             thread_context.Dr7 |= hw_bp.length << ((slot * 4) + 18)
  1393.  
  1394.             # set the thread context.
  1395.             self.set_thread_context(thread_context, thread_id=thread_id)
  1396.  
  1397.         # pass control to user defined callback.
  1398.         if self.callbacks.has_key(CREATE_THREAD_DEBUG_EVENT):
  1399.             return self.callbacks[CREATE_THREAD_DEBUG_EVENT](self)
  1400.         else:
  1401.             return DBG_CONTINUE
  1402.  
  1403.  
  1404.     ####################################################################################################################
  1405.     def event_handler_exit_process (self):
  1406.         '''
  1407.        This is the default EXIT_PROCESS_DEBUG_EVENT handler.
  1408.  
  1409.        @raise pdx: An exception is raised to denote process exit.
  1410.        '''
  1411.  
  1412.         self.set_debugger_active(False)
  1413.  
  1414.         if self.callbacks.has_key(EXIT_PROCESS_DEBUG_EVENT):
  1415.             return self.callbacks[EXIT_PROCESS_DEBUG_EVENT](self)
  1416.         else:
  1417.             return DBG_CONTINUE
  1418.  
  1419.  
  1420.     ####################################################################################################################
  1421.     def event_handler_exit_thread (self):
  1422.         '''
  1423.        This is the default EXIT_THREAD_DEBUG_EVENT handler.
  1424.  
  1425.        @rtype:  DWORD
  1426.        @return: Debug event continue status.
  1427.        '''
  1428.  
  1429.         # before we remove the TEB entry from our internal list, let's give the user a chance to do something with it.
  1430.         if self.callbacks.has_key(EXIT_THREAD_DEBUG_EVENT):
  1431.             continue_status = self.callbacks[EXIT_THREAD_DEBUG_EVENT](self)
  1432.         else:
  1433.             continue_status = DBG_CONTINUE
  1434.  
  1435.         # remove the TEB entry for the exiting thread id.
  1436.         if self.tebs.has_key(self.dbg.dwThreadId):
  1437.             del(self.tebs[self.dbg.dwThreadId])
  1438.  
  1439.         return continue_status
  1440.  
  1441.  
  1442.     ####################################################################################################################
  1443.     def event_handler_load_dll (self):
  1444.         '''
  1445.        This is the default LOAD_DLL_DEBUG_EVENT handler. You can access the last loaded dll in your callback handler
  1446.        with the following example code::
  1447.  
  1448.            last_dll = pydbg.get_system_dll(-1)
  1449.            print "loading:%s from %s into:%08x size:%d" % (last_dll.name, last_dll.path, last_dll.base, last_dll.size)
  1450.  
  1451.        The get_system_dll() routine is preferred over directly accessing the internal data structure for proper and
  1452.        transparent client/server support.
  1453.  
  1454.        @rtype:  DWORD
  1455.        @return: Debug event continue status.
  1456.        '''
  1457.  
  1458.         dll = system_dll(self.dbg.u.LoadDll.hFile, self.dbg.u.LoadDll.lpBaseOfDll)
  1459.         self.system_dlls.append(dll)
  1460.  
  1461.         if self.callbacks.has_key(LOAD_DLL_DEBUG_EVENT):
  1462.             return self.callbacks[LOAD_DLL_DEBUG_EVENT](self)
  1463.         else:
  1464.             return DBG_CONTINUE
  1465.  
  1466.  
  1467.     ####################################################################################################################
  1468.     def event_handler_unload_dll (self):
  1469.         '''
  1470.        This is the default UNLOAD_DLL_DEBUG_EVENT handler.
  1471.  
  1472.        @rtype:  DWORD
  1473.        @return: Debug event continue status.
  1474.        '''
  1475.  
  1476.         base     = self.dbg.u.UnloadDll.lpBaseOfDll
  1477.         unloading = None
  1478.  
  1479.         for system_dll in self.system_dlls:
  1480.             if system_dll.base == base:
  1481.                 unloading = system_dll
  1482.                 break
  1483.  
  1484.         # before we remove the system dll from our internal list, let's give the user a chance to do something with it.
  1485.         if self.callbacks.has_key(UNLOAD_DLL_DEBUG_EVENT):
  1486.             continue_status = self.callbacks[UNLOAD_DLL_DEBUG_EVENT](self)
  1487.         else:
  1488.             continue_status = DBG_CONTINUE
  1489.  
  1490.         if not unloading:
  1491.             #raise pdx("Unable to locate DLL that is being unloaded from %08x" % base, False)
  1492.             pass
  1493.         else:
  1494.             # close the open file handle to the system dll being unloaded.
  1495.             self.close_handle(unloading.handle)
  1496.  
  1497.             # remove the system dll from the internal list.
  1498.             self.system_dlls.remove(unloading)
  1499.             del(unloading)
  1500.  
  1501.         return continue_status
  1502.  
  1503.  
  1504.     ####################################################################################################################
  1505.     def exception_handler_access_violation (self):
  1506.         '''
  1507.        This is the default EXCEPTION_ACCESS_VIOLATION handler. Responsible for handling the access violation and
  1508.        passing control to the registered user callback handler.
  1509.  
  1510.        @attention: If you catch an access violaton and wish to terminate the process, you *must* still return
  1511.                    DBG_CONTINUE to avoid a deadlock.
  1512.  
  1513.        @rtype:  DWORD
  1514.        @return: Debug event continue status.
  1515.        '''
  1516.  
  1517.         if self.callbacks.has_key(EXCEPTION_ACCESS_VIOLATION):
  1518.             return self.callbacks[EXCEPTION_ACCESS_VIOLATION](self)
  1519.         else:
  1520.             return DBG_EXCEPTION_NOT_HANDLED
  1521.  
  1522.  
  1523.     ####################################################################################################################
  1524.     def exception_handler_breakpoint (self):
  1525.         '''
  1526.        This is the default EXCEPTION_BREAKPOINT handler, responsible for transparently restoring soft breakpoints
  1527.        and passing control to the registered user callback handler.
  1528.  
  1529.        @rtype:  DWORD
  1530.        @return: Debug event continue status.
  1531.        '''
  1532.  
  1533.         self._log("pydbg.exception_handler_breakpoint() at %08x from thread id %d" % (self.exception_address, self.dbg.dwThreadId))
  1534.  
  1535.         # breakpoints we did not set.
  1536.         if not self.bp_is_ours(self.exception_address):
  1537.             # system breakpoints.
  1538.             if self.exception_address == self.system_break:
  1539.                 # pass control to user registered call back.
  1540.                 if self.callbacks.has_key(EXCEPTION_BREAKPOINT):
  1541.                     continue_status = self.callbacks[EXCEPTION_BREAKPOINT](self)
  1542.                 else:
  1543.                     continue_status = DBG_CONTINUE
  1544.  
  1545.                 if self.first_breakpoint:
  1546.                     self._log("first windows driven system breakpoint at %08x" % self.exception_address)
  1547.                     self.first_breakpoint = False
  1548.  
  1549.             # ignore all other breakpoints we didn't explicitly set.
  1550.             else:
  1551.                 self._log("breakpoint not ours %08x" % self.exception_address)
  1552.                 continue_status = DBG_EXCEPTION_NOT_HANDLED
  1553.  
  1554.         # breakpoints we did set.
  1555.         else:
  1556.             # restore the original byte at the breakpoint address.
  1557.             self._log("restoring original byte at %08x" % self.exception_address)
  1558.             self.write_process_memory(self.exception_address, self.breakpoints[self.exception_address].original_byte)
  1559.             self.set_attr("dirty", True)
  1560.  
  1561.             # before we can continue, we have to correct the value of EIP. the reason for this is that the 1-byte INT 3
  1562.             # we inserted causes EIP to "slide" + 1 into the original instruction and must be reset.
  1563.             self.set_register("EIP", self.exception_address)
  1564.             self.context.Eip -= 1
  1565.  
  1566.             # if there is a specific handler registered for this bp, pass control to it.
  1567.             if self.breakpoints[self.exception_address].handler:
  1568.                 self._log("calling user handler")
  1569.                 continue_status = self.breakpoints[self.exception_address].handler(self)
  1570.  
  1571.             # pass control to default user registered call back handler, if it is specified.
  1572.             elif self.callbacks.has_key(EXCEPTION_BREAKPOINT):
  1573.                 continue_status = self.callbacks[EXCEPTION_BREAKPOINT](self)
  1574.  
  1575.             else:
  1576.                 continue_status = DBG_CONTINUE
  1577.  
  1578.             # if the breakpoint still exists, ie: the user didn't erase it during the callback, and the breakpoint is
  1579.             # flagged for restore, then tell the single step handler about it. furthermore, check if the debugger is
  1580.             # still active, that way we don't try and single step if the user requested a detach.
  1581.             if self.get_attr("debugger_active") and self.breakpoints.has_key(self.exception_address):
  1582.                 if self.breakpoints[self.exception_address].restore:
  1583.                     self._restore_breakpoint = self.breakpoints[self.exception_address]
  1584.                     self.single_step(True)
  1585.  
  1586.                 self.bp_del(self.exception_address)
  1587.  
  1588.         return continue_status
  1589.  
  1590.  
  1591.     ####################################################################################################################
  1592.     def exception_handler_guard_page (self):
  1593.         '''
  1594.        This is the default EXCEPTION_GUARD_PAGE handler, responsible for transparently restoring memory breakpoints
  1595.        passing control to the registered user callback handler.
  1596.  
  1597.        @rtype:  DWORD
  1598.        @return: Debug event continue status.
  1599.        '''
  1600.  
  1601.         self._log("pydbg.exception_handler_guard_page()")
  1602.  
  1603.         # determine the base address of the page where the offending reference resides.
  1604.         mbi = self.virtual_query(self.violation_address)
  1605.  
  1606.         # if the hit is on a page we did not explicitly GUARD, then pass the violation to the debuggee.
  1607.         if mbi.BaseAddress not in self._guarded_pages:
  1608.             return DBG_EXCEPTION_NOT_HANDLED
  1609.  
  1610.         # determine if the hit was within a monitored buffer, or simply on the same page.
  1611.         self.memory_breakpoint_hit = self.bp_is_ours_mem(self.violation_address)
  1612.  
  1613.         # grab the actual memory breakpoint object, for the hit breakpoint.
  1614.         if self.memory_breakpoint_hit:
  1615.             self._log("direct hit on memory breakpoint at %08x" % self.memory_breakpoint_hit)
  1616.  
  1617.         if self.write_violation:
  1618.             self._log("write violation from %08x on %08x of mem bp" % (self.exception_address, self.violation_address))
  1619.         else:
  1620.             self._log("read violation from %08x on %08x of mem bp" % (self.exception_address, self.violation_address))
  1621.  
  1622.         # if there is a specific handler registered for this bp, pass control to it.
  1623.         if self.memory_breakpoint_hit and self.memory_breakpoints[self.memory_breakpoint_hit].handler:
  1624.             continue_status = self.memory_breakpoints[self.memory_breakpoint_hit].handler(self)
  1625.  
  1626.         # pass control to default user registered call back handler, if it is specified.
  1627.         elif self.callbacks.has_key(EXCEPTION_GUARD_PAGE):
  1628.             continue_status = self.callbacks[EXCEPTION_GUARD_PAGE](self)
  1629.  
  1630.         else:
  1631.             continue_status = DBG_CONTINUE
  1632.  
  1633.         # if the hit page is still in our list of explicitly guarded pages, ie: the user didn't erase it during the
  1634.         # callback, then tell the single step handler about it. furthermore, check if the debugger is still active,
  1635.         # that way we don't try and single step if the user requested a detach.
  1636.         if self.get_attr("debugger_active") and mbi.BaseAddress in self._guarded_pages:
  1637.             self._restore_breakpoint = memory_breakpoint(None, None, mbi, None)
  1638.             self.single_step(True)
  1639.  
  1640.         return continue_status
  1641.  
  1642.  
  1643.     ####################################################################################################################
  1644.     def exception_handler_single_step (self):
  1645.         '''
  1646.        This is the default EXCEPTION_SINGLE_STEP handler, responsible for transparently restoring breakpoints and
  1647.        passing control to the registered user callback handler.
  1648.  
  1649.        @rtype:  DWORD
  1650.        @return: Debug event continue status.
  1651.        '''
  1652.  
  1653.         self._log("pydbg.exception_handler_single_step()")
  1654.  
  1655.         # if there is a breakpoint to restore.
  1656.         if self._restore_breakpoint:
  1657.             bp = self._restore_breakpoint
  1658.  
  1659.             # restore a soft breakpoint.
  1660.             if isinstance(bp, breakpoint):
  1661.                 self._log("restoring breakpoint at 0x%08x" % bp.address)
  1662.                 self.bp_set(bp.address, bp.description, bp.restore, bp.handler)
  1663.  
  1664.             # restore PAGE_GUARD for a memory breakpoint (make sure guards are not temporarily suspended).
  1665.             elif isinstance(bp, memory_breakpoint) and self._guards_active:
  1666.                 self._log("restoring %08x +PAGE_GUARD on page based @ %08x" % (bp.mbi.Protect, bp.mbi.BaseAddress))
  1667.                 self.virtual_protect(bp.mbi.BaseAddress, 1, bp.mbi.Protect | PAGE_GUARD)
  1668.  
  1669.             # restore a hardware breakpoint.
  1670.             elif isinstance(bp, hardware_breakpoint):
  1671.                 self._log("restoring hardware breakpoint on %08x" % bp.address)
  1672.                 self.bp_set_hw(bp.address, bp.length, bp.condition, bp.description, bp.restore, bp.handler)
  1673.  
  1674.         # determine if this single step event occured in reaction to a hardware breakpoint and grab the hit breakpoint.
  1675.         # according to the Intel docs, we should be able to check for the BS flag in Dr6. but it appears that windows
  1676.         # isn't properly propogating that flag down to us.
  1677.         if self.context.Dr6 & 0x1 and self.hardware_breakpoints.has_key(0):
  1678.             self.hardware_breakpoint_hit = self.hardware_breakpoints[0]
  1679.  
  1680.         elif self.context.Dr6 & 0x2 and self.hardware_breakpoints.has_key(1):
  1681.             self.hardware_breakpoint_hit = self.hardware_breakpoints[1]
  1682.  
  1683.         elif self.context.Dr6 & 0x4 and self.hardware_breakpoints.has_key(2):
  1684.             self.hardware_breakpoint_hit = self.hardware_breakpoints[2]
  1685.  
  1686.         elif self.context.Dr6 & 0x8 and self.hardware_breakpoints.has_key(3):
  1687.             self.hardware_breakpoint_hit = self.hardware_breakpoints[3]
  1688.  
  1689.         # if we are dealing with a hardware breakpoint and there is a specific handler registered, pass control to it.
  1690.         if self.hardware_breakpoint_hit and self.hardware_breakpoint_hit.handler:
  1691.             continue_status = self.hardware_breakpoint_hit.handler(self)
  1692.  
  1693.         # pass control to default user registered call back handler, if it is specified.
  1694.         elif self.callbacks.has_key(EXCEPTION_SINGLE_STEP):
  1695.             continue_status = self.callbacks[EXCEPTION_SINGLE_STEP](self)
  1696.  
  1697.         # if we single stepped to handle a breakpoint restore.
  1698.         elif self._restore_breakpoint:
  1699.             continue_status = DBG_CONTINUE
  1700.  
  1701.             # macos compatability.
  1702.             # need to clear TRAP flag for MacOS. this doesn't hurt Windows aside from a negligible speed hit.
  1703.             context         = self.get_thread_context(self.h_thread)
  1704.             context.EFlags &= ~EFLAGS_TRAP
  1705.             self.set_thread_context(context)
  1706.  
  1707.         else:
  1708.             continue_status = DBG_EXCEPTION_NOT_HANDLED
  1709.  
  1710.         # if we are handling a hardware breakpoint hit and it still exists, ie: the user didn't erase it during the
  1711.         # callback, and the breakpoint is flagged for restore, then tell the single step handler about it. furthermore,
  1712.         # check if the debugger is still active, that way we don't try and single step if the user requested a detach.
  1713.         if self.hardware_breakpoint_hit != None and self.get_attr("debugger_active"):
  1714.             slot = self.hardware_breakpoint_hit.slot
  1715.  
  1716.             if self.hardware_breakpoints.has_key(slot):
  1717.                 curr = self.hardware_breakpoints[slot]
  1718.                 prev = self.hardware_breakpoint_hit
  1719.  
  1720.                 if curr.address == prev.address:
  1721.                     if prev.restore:
  1722.                         self._restore_breakpoint = prev
  1723.                         self.single_step(True)
  1724.  
  1725.                     self.bp_del_hw(slot=prev.slot)
  1726.  
  1727.         # reset the hardware breakpoint hit flag and restore breakpoint variable.
  1728.         self.hardware_breakpoint_hit = None
  1729.         self._restore_breakpoint     = None
  1730.  
  1731.         return continue_status
  1732.  
  1733.  
  1734.     ####################################################################################################################
  1735.     def func_resolve (self, dll, function):
  1736.         '''
  1737.        Utility function that resolves the address of a given module / function name pair under the context of the
  1738.        debugger.
  1739.  
  1740.        @see: func_resolve_debuggee()
  1741.  
  1742.        @type  dll:      String
  1743.        @param dll:      Name of the DLL (case-insensitive)
  1744.        @type  function: String
  1745.        @param function: Name of the function to resolve (case-sensitive)
  1746.  
  1747.        @rtype:  DWORD
  1748.        @return: Address
  1749.        '''
  1750.  
  1751.         handle  = kernel32.LoadLibraryA(dll)
  1752.         address = kernel32.GetProcAddress(handle, function)
  1753.  
  1754.         kernel32.FreeLibrary(handle)
  1755.  
  1756.         return address
  1757.  
  1758.  
  1759.     ####################################################################################################################
  1760.     def func_resolve_debuggee (self, dll_name, func_name):
  1761.         '''
  1762.        Utility function that resolves the address of a given module / function name pair under the context of the
  1763.        debuggee. Note: Be weary of calling this function from within a LOAD_DLL handler as the module is not yet
  1764.        fully loaded and therefore the snapshot will not include it.
  1765.  
  1766.        @author: Otto Ebeling
  1767.        @see:    func_resolve()
  1768.        @todo:   Add support for followed imports.
  1769.  
  1770.        @type  dll_name:  String
  1771.        @param dll_name:  Name of the DLL (case-insensitive, ex:ws2_32.dll)
  1772.        @type  func_name: String
  1773.        @param func_name: Name of the function to resolve (case-sensitive)
  1774.  
  1775.        @rtype:  DWORD
  1776.        @return: Address of the symbol in the target process address space if it can be resolved, None otherwise
  1777.        '''
  1778.  
  1779.         dll_name = dll_name.lower()
  1780.  
  1781.         # we can't make the assumption that all DLL names end in .dll, for example Quicktime libs end in .qtx / .qts
  1782.         # so instead of this old line:
  1783.         #     if not dll_name.endswith(".dll"):
  1784.         # we'll check for the presence of a dot and will add .dll as a conveneince.
  1785.         if not dll_name.count("."):
  1786.             dll_name += ".dll"
  1787.  
  1788.         for module in self.iterate_modules():
  1789.             if module.szModule.lower() == dll_name:
  1790.                 base_address = module.modBaseAddr
  1791.                 dos_header   = self.read_process_memory(base_address, 0x40)
  1792.  
  1793.                 # check validity of DOS header.
  1794.                 if len(dos_header) != 0x40 or dos_header[:2] != "MZ":
  1795.                     continue
  1796.  
  1797.                 e_lfanew   = struct.unpack("<I", dos_header[0x3c:0x40])[0]
  1798.                 pe_headers = self.read_process_memory(base_address + e_lfanew, 0xF8)
  1799.  
  1800.                 # check validity of PE headers.
  1801.                 if len(pe_headers) != 0xF8 or pe_headers[:2] != "PE":
  1802.                     continue
  1803.  
  1804.                 export_directory_rva = struct.unpack("<I", pe_headers[0x78:0x7C])[0]
  1805.                 export_directory_len = struct.unpack("<I", pe_headers[0x7C:0x80])[0]
  1806.                 export_directory     = self.read_process_memory(base_address + export_directory_rva, export_directory_len)
  1807.                 num_of_functions     = struct.unpack("<I", export_directory[0x14:0x18])[0]
  1808.                 num_of_names         = struct.unpack("<I", export_directory[0x18:0x1C])[0]
  1809.                 address_of_functions = struct.unpack("<I", export_directory[0x1C:0x20])[0]
  1810.                 address_of_names     = struct.unpack("<I", export_directory[0x20:0x24])[0]
  1811.                 address_of_ordinals  = struct.unpack("<I", export_directory[0x24:0x28])[0]
  1812.                 name_table           = self.read_process_memory(base_address + address_of_names, num_of_names * 4)
  1813.  
  1814.                 # perform a binary search across the function names.
  1815.                 low  = 0
  1816.                 high = num_of_names
  1817.  
  1818.                 while low <= high:
  1819.                     # python does not suffer from integer overflows:
  1820.                     #     http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
  1821.                     middle          = (low + high) / 2
  1822.                     current_address = base_address + struct.unpack("<I", name_table[middle*4:(middle+1)*4])[0]
  1823.  
  1824.                     # we use a crude approach here. read 256 bytes and cut on NULL char. not very beautiful, but reading
  1825.                     # 1 byte at a time is very slow.
  1826.                     name_buffer = self.read_process_memory(current_address, 256)
  1827.                     name_buffer = name_buffer[:name_buffer.find("\0")]
  1828.  
  1829.                     if name_buffer < func_name:
  1830.                         low = middle + 1
  1831.                     elif name_buffer > func_name:
  1832.                         high = middle - 1
  1833.                     else:
  1834.                         # MSFT documentation is misleading - see http://www.bitsum.com/pedocerrors.htm
  1835.                         bin_ordinal      = self.read_process_memory(base_address + address_of_ordinals + middle * 2, 2)
  1836.                         ordinal          = struct.unpack("<H", bin_ordinal)[0]   # ordinalBase has already been subtracted
  1837.                         bin_func_address = self.read_process_memory(base_address + address_of_functions + ordinal * 4, 4)
  1838.                         function_address = struct.unpack("<I", bin_func_address)[0]
  1839.  
  1840.                         return base_address + function_address
  1841.  
  1842.                 # function was not found.
  1843.                 return None
  1844.  
  1845.         # module was not found.
  1846.         return None
  1847.  
  1848.  
  1849.     ####################################################################################################################
  1850.     def get_ascii_string (self, data):
  1851.         '''
  1852.        Retrieve the ASCII string, if any, from data. Ensure that the string is valid by checking against the minimum
  1853.        length requirement defined in self.STRING_EXPLORATION_MIN_LENGTH.
  1854.  
  1855.        @type  data: Raw
  1856.        @param data: Data to explore for printable ascii string
  1857.  
  1858.        @rtype:  String
  1859.        @return: False on failure, ascii string on discovered string.
  1860.        '''
  1861.  
  1862.         discovered = ""
  1863.  
  1864.         for char in data:
  1865.             # if we've hit a non printable char, break
  1866.             if ord(char) < 32 or ord(char) > 126:
  1867.                 break
  1868.  
  1869.             discovered += char
  1870.  
  1871.         if len(discovered) < self.STRING_EXPLORATION_MIN_LENGTH:
  1872.             return False
  1873.  
  1874.         return discovered
  1875.  
  1876.  
  1877.  
  1878.     ####################################################################################################################
  1879.     def get_arg (self, index, context=None):
  1880.         '''
  1881.        Given a thread context, this convenience routine will retrieve the function argument at the specified index.
  1882.        The return address of the function can be retrieved by specifying an index of 0. This routine should be called
  1883.        from breakpoint handlers at the top of a function.
  1884.  
  1885.        @type  index:   Integer
  1886.        @param index:   Data to explore for printable ascii string
  1887.        @type  context: Context
  1888.        @param context: (Optional) Current thread context to examine
  1889.  
  1890.        @rtype:  DWORD
  1891.        @return: Value of specified argument.
  1892.        '''
  1893.  
  1894.         # if the optional current thread context was not supplied, grab it for the current thread.
  1895.         if not context:
  1896.             context = self.context
  1897.  
  1898.         arg_val = self.read_process_memory(context.Esp + index * 4, 4)
  1899.         arg_val = self.flip_endian_dword(arg_val)
  1900.  
  1901.         return arg_val
  1902.  
  1903.  
  1904.     ####################################################################################################################
  1905.     def get_attr (self, attribute):
  1906.         '''
  1907.        Return the value for the specified class attribute. This routine should be used over directly accessing class
  1908.        member variables for transparent support across local vs. client/server debugger clients.
  1909.  
  1910.        @see: set_attr()
  1911.  
  1912.        @type  attribute: String
  1913.        @param attribute: Name of attribute to return.
  1914.  
  1915.        @rtype:  Mixed
  1916.        @return: Requested attribute or None if not found.
  1917.        '''
  1918.  
  1919.         if not hasattr(self, attribute):
  1920.             return None
  1921.  
  1922.         return getattr(self, attribute)
  1923.  
  1924.  
  1925.     ####################################################################################################################
  1926.     def get_debug_privileges (self):
  1927.         '''
  1928.        Obtain necessary privileges for debugging.
  1929.  
  1930.        @raise pdx: An exception is raised on failure.
  1931.        '''
  1932.  
  1933.         h_token     = HANDLE()
  1934.         luid        = LUID()
  1935.         token_state = TOKEN_PRIVILEGES()
  1936.  
  1937.         self._log("get_debug_privileges()")
  1938.  
  1939.         if not advapi32.OpenProcessToken(kernel32.GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, byref(h_token)):
  1940.             raise pdx("OpenProcessToken()", True)
  1941.  
  1942.         if not advapi32.LookupPrivilegeValueA(0, "seDebugPrivilege", byref(luid)):
  1943.             raise pdx("LookupPrivilegeValue()", True)
  1944.  
  1945.         token_state.PrivilegeCount = 1
  1946.         token_state.Privileges[0].Luid = luid
  1947.         token_state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED
  1948.  
  1949.         if not advapi32.AdjustTokenPrivileges(h_token, 0, byref(token_state), 0, 0, 0):
  1950.             raise pdx("AdjustTokenPrivileges()", True)
  1951.  
  1952.  
  1953.     ####################################################################################################################
  1954.     def get_instruction (self, address):
  1955.         '''
  1956.        Pydasm disassemble utility function wrapper. Returns the pydasm decoded instruction in self.instruction.
  1957.  
  1958.        @type  address: DWORD
  1959.        @param address: Address to disassemble at
  1960.  
  1961.        @rtype:  pydasm instruction
  1962.        @return: pydasm instruction
  1963.        '''
  1964.  
  1965.         try:
  1966.             data  = self.read_process_memory(address, 32)
  1967.         except:
  1968.             return "Unable to disassemble at %08x" % address
  1969.  
  1970.         return pydasm.get_instruction(data, pydasm.MODE_32)
  1971.  
  1972.  
  1973.     ####################################################################################################################
  1974.     def get_printable_string (self, data, print_dots=True):
  1975.         '''
  1976.        description
  1977.  
  1978.        @type  data:       Raw
  1979.        @param data:       Data to explore for printable ascii string
  1980.        @type  print_dots: Bool
  1981.        @param print_dots: (Optional, def:True) Controls suppression of dot in place of non-printable
  1982.  
  1983.        @rtype:  String
  1984.        @return: False on failure, discovered printable chars in string otherwise.
  1985.        '''
  1986.  
  1987.         discovered = ""
  1988.  
  1989.         for char in data:
  1990.             if ord(char) >= 32 and ord(char) <= 126:
  1991.                 discovered += char
  1992.             elif print_dots:
  1993.                 discovered += "."
  1994.  
  1995.         return discovered
  1996.  
  1997.  
  1998.     ####################################################################################################################
  1999.     def get_register (self, register):
  2000.         '''
  2001.        Get the value of a register in the debuggee within the context of the self.h_thread.
  2002.  
  2003.        @type  register: Register
  2004.        @param register: One of EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP, EIP
  2005.  
  2006.        @raise pdx: An exception is raised on failure.
  2007.        @rtype:     DWORD
  2008.        @return:    Value of specified register.
  2009.        '''
  2010.  
  2011.         self._log("getting %s in thread id %d" % (register, self.dbg.dwThreadId))
  2012.  
  2013.         register = register.upper()
  2014.         if register not in ("EAX", "EBX", "ECX", "EDX", "ESI", "EDI", "ESP", "EBP", "EIP"):
  2015.             raise pdx("invalid register specified")
  2016.  
  2017.         # ensure we have an up to date thread context.
  2018.         context = self.get_thread_context(self.h_thread)
  2019.  
  2020.         if   register == "EAX": return context.Eax
  2021.         elif register == "EBX": return context.Ebx
  2022.         elif register == "ECX": return context.Ecx
  2023.         elif register == "EDX": return context.Edx
  2024.         elif register == "ESI": return context.Esi
  2025.         elif register == "EDI": return context.Edi
  2026.         elif register == "ESP": return context.Esp
  2027.         elif register == "EBP": return context.Ebp
  2028.         elif register == "EIP": return context.Eip
  2029.  
  2030.         # this shouldn't ever really be reached.
  2031.         return 0
  2032.  
  2033.  
  2034.     ####################################################################################################################
  2035.     def get_system_dll (self, idx):
  2036.         '''
  2037.        Return the system DLL at the specified index. If the debugger is in client / server mode, remove the PE
  2038.        structure (we do not want to send that mammoth over the wire).
  2039.  
  2040.        @type  idx: Integer
  2041.        @param idx: Index into self.system_dlls[] to retrieve DLL from.
  2042.  
  2043.        @rtype:  Mixed
  2044.        @return: Requested attribute or None if not found.
  2045.        '''
  2046.  
  2047.         self._log("get_system_dll()")
  2048.  
  2049.         try:
  2050.             dll = self.system_dlls[idx]
  2051.         except:
  2052.             # index out of range.
  2053.             return None
  2054.  
  2055.         dll.pe = None
  2056.         return dll
  2057.  
  2058.  
  2059.     ####################################################################################################################
  2060.     def get_thread_context (self, thread_handle=None, thread_id=0):
  2061.         '''
  2062.        Convenience wrapper around GetThreadContext(). Can obtain a thread context via a handle or thread id.
  2063.  
  2064.        @type  thread_handle: HANDLE
  2065.        @param thread_handle: (Optional) Handle of thread to get context of
  2066.        @type  thread_id:     Integer
  2067.        @param thread_id:     (Optional) ID of thread to get context of
  2068.  
  2069.        @raise pdx: An exception is raised on failure.
  2070.        @rtype:     CONTEXT
  2071.        @return:    Thread CONTEXT on success.
  2072.        '''
  2073.  
  2074.         context = CONTEXT()
  2075.         context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS
  2076.  
  2077.         # if a thread handle was not specified, get one from the thread id.
  2078.         if not thread_handle:
  2079.             h_thread = self.open_thread(thread_id)
  2080.         else:
  2081.             h_thread = thread_handle
  2082.  
  2083.         if not kernel32.GetThreadContext(h_thread, byref(context)):
  2084.             raise pdx("GetThreadContext()", True)
  2085.  
  2086.         # if we had to resolve the thread handle, close it.
  2087.         if not thread_handle:
  2088.             self.close_handle(h_thread)
  2089.  
  2090.         return context
  2091.  
  2092.  
  2093.     ####################################################################################################################
  2094.     def get_unicode_string (self, data):
  2095.         '''
  2096.        description
  2097.  
  2098.        @type  data: Raw
  2099.        @param data: Data to explore for printable unicode string
  2100.  
  2101.        @rtype:  String
  2102.        @return: False on failure, ascii-converted unicode string on discovered string.
  2103.        '''
  2104.  
  2105.         discovered  = ""
  2106.         every_other = True
  2107.  
  2108.         for char in data:
  2109.             if every_other:
  2110.                 # if we've hit a non printable char, break
  2111.                 if ord(char) < 32 or ord(char) > 126:
  2112.                     break
  2113.  
  2114.                 discovered += char
  2115.  
  2116.             every_other = not every_other
  2117.  
  2118.         if len(discovered) < self.STRING_EXPLORATION_MIN_LENGTH:
  2119.             return False
  2120.  
  2121.         return discovered
  2122.  
  2123.  
  2124.     ####################################################################################################################
  2125.     def hex_dump (self, data, addr=0, prefix=""):
  2126.         '''
  2127.        Utility function that converts data into hex dump format.
  2128.  
  2129.        @type  data:   Raw Bytes
  2130.        @param data:   Raw bytes to view in hex dump
  2131.        @type  addr:   DWORD
  2132.        @param addr:   (Optional, def=0) Address to start hex offset display from
  2133.        @type  prefix: String (Optional, def="")
  2134.        @param prefix: String to prefix each line of hex dump with.
  2135.  
  2136.        @rtype:  String
  2137.        @return: Hex dump of data.
  2138.        '''
  2139.  
  2140.         dump  = prefix
  2141.         slice = ""
  2142.  
  2143.         for byte in data:
  2144.             if addr % 16 == 0:
  2145.                 dump += " "
  2146.  
  2147.                 for char in slice:
  2148.                     if ord(char) >= 32 and ord(char) <= 126:
  2149.                         dump += char
  2150.                     else:
  2151.                         dump += "."
  2152.  
  2153.                 dump += "\n%s%04x: " % (prefix, addr)
  2154.                 slice = ""
  2155.  
  2156.             dump  += "%02x " % ord(byte)
  2157.             slice += byte
  2158.             addr  += 1
  2159.  
  2160.         remainder = addr % 16
  2161.  
  2162.         if remainder != 0:
  2163.             dump += "   " * (16 - remainder) + " "
  2164.  
  2165.         for char in slice:
  2166.             if ord(char) >= 32 and ord(char) <= 126:
  2167.                 dump += char
  2168.             else:
  2169.                 dump += "."
  2170.  
  2171.         return dump + "\n"
  2172.  
  2173.  
  2174.     ####################################################################################################################
  2175.     def hide_debugger (self):
  2176.         '''
  2177.        Hide the presence of the debugger. This routine requires an active context and therefore can not be called
  2178.        immediately after a load() for example. Call it from the first chance breakpoint handler. This routine hides
  2179.        the debugger in the following ways:
  2180.  
  2181.            - Modifies the PEB flag that IsDebuggerPresent() checks for.
  2182.  
  2183.        @raise pdx: An exception is raised if we are unable to hide the debugger for various reasons.
  2184.        '''
  2185.  
  2186.         selector_entry = LDT_ENTRY()
  2187.  
  2188.         # a current thread context is required.
  2189.         if not self.context:
  2190.             raise pdx("hide_debugger(): a thread context is required. Call me from a breakpoint handler.")
  2191.  
  2192.         if not kernel32.GetThreadSelectorEntry(self.h_thread, self.context.SegFs, byref(selector_entry)):
  2193.             self.win32_error("GetThreadSelectorEntry()")
  2194.  
  2195.         fs_base  = selector_entry.BaseLow
  2196.         fs_base += (selector_entry.HighWord.Bits.BaseMid << 16) + (selector_entry.HighWord.Bits.BaseHi << 24)
  2197.  
  2198.         # http://openrce.org/reference_library/files/reference/Windows Memory Layout, User-Kernel Address Spaces.pdf
  2199.         # find the peb.
  2200.         peb = self.read_process_memory(fs_base + 0x30, 4)
  2201.         peb = self.flip_endian_dword(peb)
  2202.  
  2203.         # zero out the flag. (3rd byte)
  2204.         self.write_process_memory(peb+2, "\x00", 1)
  2205.  
  2206.         return self.ret_self()
  2207.  
  2208.  
  2209.     ####################################################################################################################
  2210.     def is_address_on_stack (self, address, context=None):
  2211.         '''
  2212.        Utility function to determine if the specified address exists on the current thread stack or not.
  2213.  
  2214.        @type  address: DWORD
  2215.        @param address: Address to check
  2216.        @type  context: Context
  2217.        @param context: (Optional) Current thread context to examine
  2218.  
  2219.        @rtype:  Bool
  2220.        @return: True if address lies in current threads stack range, False otherwise.
  2221.        '''
  2222.  
  2223.         # if the optional current thread context was not supplied, grab it for the current thread.
  2224.         if not context:
  2225.             context = self.context
  2226.  
  2227.         (stack_top, stack_bottom) = self.stack_range(context)
  2228.  
  2229.         if address >= stack_bottom and address <= stack_top:
  2230.             return True
  2231.  
  2232.         return False
  2233.  
  2234.  
  2235.     #####################################################################################################################
  2236.     def iterate_modules (self):
  2237.         '''
  2238.        A simple iterator function that can be used to iterate through all modules the target process has mapped in its
  2239.        address space. Yielded objects are of type MODULEENTRY32.
  2240.  
  2241.        @author:  Otto Ebeling
  2242.        @see:     enumerate_modules()
  2243.        @warning: break-ing out of loops over this routine will cause a handle leak.
  2244.  
  2245.        @rtype:  MODULEENTRY32
  2246.        @return: Iterated module entries.
  2247.        '''
  2248.  
  2249.         self._log("iterate_modules()")
  2250.  
  2251.         current_entry = MODULEENTRY32()
  2252.         snapshot      = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, self.pid)
  2253.  
  2254.         if snapshot == INVALID_HANDLE_VALUE:
  2255.             raise pdx("CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, %d" % self.pid, True)
  2256.  
  2257.         # we *must* set the size of the structure prior to using it, otherwise Module32First() will fail.
  2258.         current_entry.dwSize = sizeof(current_entry)
  2259.  
  2260.         if not kernel32.Module32First(snapshot, byref(current_entry)):
  2261.             return
  2262.  
  2263.         while 1:
  2264.             yield current_entry
  2265.  
  2266.             if not kernel32.Module32Next(snapshot, byref(current_entry)):
  2267.                 break
  2268.  
  2269.         # if the above loop is "broken" out of, then this handle leaks.
  2270.         self.close_handle(snapshot)
  2271.  
  2272.  
  2273.     #####################################################################################################################
  2274.     def iterate_processes (self):
  2275.         '''
  2276.        A simple iterator function that can be used to iterate through all running processes. Yielded objects are of
  2277.        type PROCESSENTRY32.
  2278.  
  2279.        @see:     enumerate_processes()
  2280.        @warning: break-ing out of loops over this routine will cause a handle leak.
  2281.  
  2282.        @rtype:  PROCESSENTRY32
  2283.        @return: Iterated process entries.
  2284.        '''
  2285.  
  2286.         self._log("iterate_processes()")
  2287.  
  2288.         pe       = PROCESSENTRY32()
  2289.         snapshot = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
  2290.  
  2291.         if snapshot == INVALID_HANDLE_VALUE:
  2292.             raise pdx("CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0", True)
  2293.  
  2294.         # we *must* set the size of the structure prior to using it, otherwise Process32First() will fail.
  2295.         pe.dwSize = sizeof(PROCESSENTRY32)
  2296.  
  2297.         if not kernel32.Process32First(snapshot, byref(pe)):
  2298.             return
  2299.  
  2300.         while 1:
  2301.             yield pe
  2302.  
  2303.             if not kernel32.Process32Next(snapshot, byref(pe)):
  2304.                 break
  2305.  
  2306.         # if the above loop is "broken" out of, then this handle leaks.
  2307.         self.close_handle(snapshot)
  2308.  
  2309.  
  2310.     #####################################################################################################################
  2311.     def iterate_threads (self):
  2312.         '''
  2313.        A simple iterator function that can be used to iterate through all running processes. Yielded objects are of
  2314.        type THREADENTRY32.
  2315.  
  2316.        @see:     enumerate_threads()
  2317.        @warning: break-ing out of loops over this routine will cause a handle leak.
  2318.  
  2319.        @rtype:  THREADENTRY32
  2320.        @return: Iterated process entries.
  2321.        '''
  2322.  
  2323.         self._log("iterate_threads()")
  2324.  
  2325.         thread_entry = THREADENTRY32()
  2326.         snapshot     = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, self.pid)
  2327.  
  2328.         if snapshot == INVALID_HANDLE_VALUE:
  2329.             raise pdx("CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, %d" % self.pid, True)
  2330.  
  2331.         # we *must* set the size of the structure prior to using it, otherwise Thread32First() will fail.
  2332.         thread_entry.dwSize = sizeof(thread_entry)
  2333.  
  2334.         if not kernel32.Thread32First(snapshot, byref(thread_entry)):
  2335.             return
  2336.  
  2337.         while 1:
  2338.             if thread_entry.th32OwnerProcessID == self.pid:
  2339.                 yield thread_entry
  2340.  
  2341.             if not kernel32.Thread32Next(snapshot, byref(thread_entry)):
  2342.                 break
  2343.  
  2344.         # if the above loop is "broken" out of, then this handle leaks.
  2345.         self.close_handle(snapshot)
  2346.  
  2347.  
  2348.     ####################################################################################################################
  2349.     def flip_endian (self, dword):
  2350.         '''
  2351.        Utility function to flip the endianess a given DWORD into raw bytes.
  2352.  
  2353.        @type  dword: DWORD
  2354.        @param dowrd: DWORD whose endianess to flip
  2355.  
  2356.        @rtype:  Raw Bytes
  2357.        @return: Converted DWORD in raw bytes.
  2358.        '''
  2359.  
  2360.         byte1 = chr(dword % 256)
  2361.         dword = dword >> 8
  2362.         byte2 = chr(dword % 256)
  2363.         dword = dword >> 8
  2364.         byte3 = chr(dword % 256)
  2365.         dword = dword >> 8
  2366.         byte4 = chr(dword % 256)
  2367.  
  2368.         return "%c%c%c%c" % (byte1, byte2, byte3, byte4)
  2369.  
  2370.  
  2371.     ####################################################################################################################
  2372.     def flip_endian_dword (self, bytes):
  2373.         '''
  2374.        Utility function to flip the endianess of a given set of raw bytes into a DWORD.
  2375.  
  2376.        @type  bytes: Raw Bytes
  2377.        @param bytes: Raw bytes whose endianess to flip
  2378.  
  2379.        @rtype:  DWORD
  2380.        @return: Converted DWORD.
  2381.        '''
  2382.  
  2383.         return struct.unpack("<L", bytes)[0]
  2384.  
  2385.  
  2386.     ####################################################################################################################
  2387.     def load (self, path_to_file, command_line=None, create_new_console=False, show_window=True):
  2388.         '''
  2389.        Load the specified executable and optional command line arguments into the debugger.
  2390.  
  2391.        @todo: This routines needs to be further tested ... I nomally just attach.
  2392.  
  2393.        @type  path_to_file:       String
  2394.        @param path_to_file:       Full path to executable to load in debugger
  2395.        @type  command_line:       String
  2396.        @param command_line:       (Optional, def=None) Command line arguments to pass to debuggee
  2397.        @type  create_new_console: Boolean
  2398.        @param create_new_console: (Optional, def=False) Create a new console for the debuggee.
  2399.        @type  show_window:        Boolean
  2400.        @param show_window:        (Optional, def=True) Show / hide the debuggee window.
  2401.  
  2402.        @raise pdx: An exception is raised if we are unable to load the specified executable in the debugger.
  2403.        '''
  2404.  
  2405.         pi = PROCESS_INFORMATION()
  2406.         si = STARTUPINFO()
  2407.  
  2408.         si.cb = sizeof(si)
  2409.  
  2410.         # these flags control the main window display of the debuggee.
  2411.         if not show_window:
  2412.             si.dwFlags     = 0x1
  2413.             si.wShowWindow = 0x0
  2414.  
  2415.         # CreateProcess() seems to work better with command line arguments when the path_to_file is passed as NULL.
  2416.         if command_line:
  2417.             command_line = path_to_file + " " + command_line
  2418.             path_to_file = 0
  2419.  
  2420.         if self.follow_forks:
  2421.             creation_flags = DEBUG_PROCESS
  2422.         else:
  2423.             creation_flags = DEBUG_ONLY_THIS_PROCESS
  2424.  
  2425.         if create_new_console:
  2426.             creation_flags |= CREATE_NEW_CONSOLE
  2427.  
  2428.         success = kernel32.CreateProcessA(c_char_p(path_to_file),
  2429.                                           c_char_p(command_line),
  2430.                                           0,
  2431.                                           0,
  2432.                                           0,
  2433.                                           creation_flags,
  2434.                                           0,
  2435.                                           0,
  2436.                                           byref(si),
  2437.                                           byref(pi))
  2438.  
  2439.         if not success:
  2440.             raise pdx("CreateProcess()", True)
  2441.  
  2442.         # allow detaching on systems that support it.
  2443.         try:
  2444.             self.debug_set_process_kill_on_exit(False)
  2445.         except:
  2446.             pass
  2447.  
  2448.         # store the handles we need.
  2449.         self.pid       = pi.dwProcessId
  2450.         self.h_process = pi.hProcess
  2451.  
  2452.         # resolve the PEB address.
  2453.         selector_entry = LDT_ENTRY()
  2454.         thread_context = self.get_thread_context(pi.hThread)
  2455.  
  2456.         if not kernel32.GetThreadSelectorEntry(pi.hThread, thread_context.SegFs, byref(selector_entry)):
  2457.             self.win32_error("GetThreadSelectorEntry()")
  2458.  
  2459.         teb  = selector_entry.BaseLow
  2460.         teb += (selector_entry.HighWord.Bits.BaseMid << 16) + (selector_entry.HighWord.Bits.BaseHi << 24)
  2461.  
  2462.         # add this TEB to the internal dictionary.
  2463.         self.tebs[pi.dwThreadId] = teb
  2464.  
  2465.         self.peb = self.read_process_memory(teb + 0x30, 4)
  2466.         self.peb = struct.unpack("<L", self.peb)[0]
  2467.  
  2468.         # if the function (CreateProcess) succeeds, be sure to call the CloseHandle function to close the hProcess and
  2469.         # hThread handles when you are finished with them. -bill gates
  2470.         #
  2471.         # we keep the process handle open but don't need the thread handle.
  2472.         self.close_handle(pi.hThread)
  2473.  
  2474.  
  2475.     ####################################################################################################################
  2476.     def open_process (self, pid):
  2477.         '''
  2478.        Convenience wrapper around OpenProcess().
  2479.  
  2480.        @type  pid: Integer
  2481.        @param pid: Process ID to attach to
  2482.  
  2483.        @raise pdx: An exception is raised on failure.
  2484.        '''
  2485.  
  2486.         self.h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
  2487.  
  2488.         if not self.h_process:
  2489.             raise pdx("OpenProcess(%d)" % pid, True)
  2490.  
  2491.         return self.h_process
  2492.  
  2493.  
  2494.     ####################################################################################################################
  2495.     def open_thread (self, thread_id):
  2496.         '''
  2497.        Convenience wrapper around OpenThread().
  2498.  
  2499.        @type  thread_id: Integer
  2500.        @param thread_id: ID of thread to obtain handle to
  2501.  
  2502.        @raise pdx: An exception is raised on failure.
  2503.        '''
  2504.  
  2505.         h_thread = kernel32.OpenThread(THREAD_ALL_ACCESS, None, thread_id)
  2506.  
  2507.         if not h_thread:
  2508.             raise pdx("OpenThread(%d)" % thread_id, True)
  2509.  
  2510.         return h_thread
  2511.  
  2512.  
  2513.     ####################################################################################################################
  2514.     def page_guard_clear (self):
  2515.         '''
  2516.        Clear all debugger-set PAGE_GUARDs from memory. This is useful for suspending memory breakpoints to single step
  2517.        past a REP instruction.
  2518.  
  2519.        @see: page_guard_restore()
  2520.  
  2521.        @rtype:     pydbg
  2522.        @return:    Self
  2523.        '''
  2524.  
  2525.         self._guards_active = False
  2526.  
  2527.         for page in self._guarded_pages:
  2528.             # make a best effort, let's not crash on failure though.
  2529.             try:
  2530.                 mbi = self.virtual_query(page)
  2531.                 self.virtual_protect(mbi.BaseAddress, 1, mbi.Protect & ~PAGE_GUARD)
  2532.             except:
  2533.                 pass
  2534.  
  2535.         return self.ret_self()
  2536.  
  2537.  
  2538.     ####################################################################################################################
  2539.     def page_guard_restore (self):
  2540.         '''
  2541.        Restore all previously cleared debugger-set PAGE_GUARDs from memory. This is useful for suspending memory
  2542.        breakpoints to single step past a REP instruction.
  2543.  
  2544.        @see: page_guard_clear()
  2545.  
  2546.        @rtype:  pydbg
  2547.        @return: Self
  2548.        '''
  2549.  
  2550.         self._guards_active = True
  2551.  
  2552.         for page in self._guarded_pages:
  2553.             # make a best effort, let's not crash on failure though.
  2554.             try:
  2555.                 mbi = self.virtual_query(page)
  2556.                 self.virtual_protect(mbi.BaseAddress, 1, mbi.Protect | PAGE_GUARD)
  2557.             except:
  2558.                 pass
  2559.  
  2560.         return self.ret_self()
  2561.  
  2562.  
  2563.     ####################################################################################################################
  2564.     def pid_to_port (self, pid):
  2565.         '''
  2566.        A helper function that enumerates the IPv4 endpoints for a given process ID.
  2567.  
  2568.        @author:    Justin Seitz
  2569.        @type  pid: Integer
  2570.        @param pid: Process ID to find port information on.
  2571.  
  2572.        @raise pdx: An exception is raised on failure
  2573.        @rtype:     A list of tuples
  2574.        @return:    A list of the protocol, bound address and listening port
  2575.        '''
  2576.  
  2577.         # local variables to hold all our necessary sweetness.
  2578.         listening_port = None
  2579.         bound_address  = None
  2580.         protocol       = None
  2581.         port_list      = []
  2582.         tcp_table      = MIB_TCPTABLE_OWNER_PID()
  2583.         udp_table      = MIB_UDPTABLE_OWNER_PID()
  2584.         init_size      = c_int()
  2585.  
  2586.         #### TCP ENDPOINTS
  2587.  
  2588.         # the first run is to determine the sizing of the struct.
  2589.         size_result = iphlpapi.GetExtendedTcpTable(byref(tcp_table),        \
  2590.                                                    byref(init_size),        \
  2591.                                                    False,                   \
  2592.                                                    AF_INET,                 \
  2593.                                                    TCP_TABLE_OWNER_PID_ALL, \
  2594.                                                    0)
  2595.  
  2596.         if not size_result:
  2597.             raise pdx("Couldn't retrieve extended TCP information for PID: %d" % pid, True)
  2598.  
  2599.         # retrieve the table of TCP_ROW structs, with the correct size this time.
  2600.         reslt       = iphlpapi.GetExtendedTcpTable(byref(tcp_table),        \
  2601.                                                    byref(init_size),        \
  2602.                                                    False,                   \
  2603.                                                    AF_INET,                 \
  2604.                                                    TCP_TABLE_OWNER_PID_ALL, \
  2605.                                                    0)
  2606.  
  2607.         # step through the entries. we only want ports that have the listening flag set. snag the port, address and
  2608.         # protocol tuple and add it to port_list.
  2609.         for i in xrange(tcp_table.dwNumEntries):
  2610.             if tcp_table.table[i].dwOwningPid == pid:
  2611.                 if tcp_table.table[i].dwState == MIB_TCP_STATE_LISTEN:
  2612.                     listening_port = "%d" % socket.ntohs(tcp_table.table[i].dwLocalPort)
  2613.                     bound_address  = socket.inet_ntoa(struct.pack("L", tcp_table.table[i].dwLocalAddr))
  2614.                     protocol       = "TCP"
  2615.  
  2616.                     port_list.append((protocol, bound_address, listening_port))
  2617.  
  2618.         #### UDP ENDPOINTS
  2619.  
  2620.         # NOTE: An application can bind a UDP port explicitly to send datagrams, this may not be 100% accurate
  2621.         # so we only take into account those UDP sockets which are bound in a manner that allows datagrams on any
  2622.         # interface.
  2623.         init_size   = c_int(0)
  2624.         size_resuld = iphlpapi.GetExtendedUdpTable(byref(udp_table),    \
  2625.                                                    byref(init_size),    \
  2626.                                                    False,               \
  2627.                                                    AF_INET,             \
  2628.                                                    UDP_TABLE_OWNER_PID, \
  2629.                                                    0)
  2630.  
  2631.         # retrieve the table of UDP_ROW structs.
  2632.         if not size_result:
  2633.             raise pdx("Couldn't retrieve extended UDP information for PID: %d" % pid, True)
  2634.  
  2635.         result     = iphlpapi.GetExtendedUdpTable(byref(udp_table),    \
  2636.                                                   byref(init_size),    \
  2637.                                                   False,               \
  2638.                                                   AF_INET,             \
  2639.                                                   UDP_TABLE_OWNER_PID, \
  2640.                                                   0)
  2641.  
  2642.         for i in range(udp_table.dwNumEntries):
  2643.             if udp_table.table[i].dwOwningPid == pid:
  2644.                 # if the local addr is 0 then it is a listening socket accepting datagrams.
  2645.                 if udp_table.table[i].dwLocalAddr == 0:
  2646.                     listening_port = "%d" % socket.ntohs(udp_table.table[i].dwLocalPort)
  2647.                     bound_address  = socket.inet_ntoa(struct.pack("L", udp_table.table[i].dwLocalAddr))
  2648.                     protocol       = "UDP"
  2649.  
  2650.                     port_list.append((protocol, bound_address, listening_port))
  2651.  
  2652.         return port_list
  2653.  
  2654.  
  2655.     ####################################################################################################################
  2656.     def process_restore (self):
  2657.         '''
  2658.        Restore memory / context snapshot of the debuggee. All threads must be suspended before calling this routine.
  2659.  
  2660.        @raise pdx: An exception is raised on failure.
  2661.        @rtype:     pydbg
  2662.        @return:    Self
  2663.        '''
  2664.  
  2665.         # fetch the current list of threads.
  2666.         current_thread_list = self.enumerate_threads()
  2667.  
  2668.         # restore the thread context for threads still active.
  2669.         for thread_context in self.memory_snapshot_contexts:
  2670.             if thread_context.thread_id in current_thread_list:
  2671.                 self.set_thread_context(thread_context.context, thread_id=thread_context.thread_id)
  2672.  
  2673.         # restore all saved memory blocks.
  2674.         for memory_block in self.memory_snapshot_blocks:
  2675.             try:
  2676.                 self.write_process_memory(memory_block.mbi.BaseAddress, memory_block.data, memory_block.mbi.RegionSize)
  2677.             except pdx, x:
  2678.                 self._err("-- IGNORING ERROR --")
  2679.                 self._err("process_restore: " + x.__str__().rstrip("\r\n"))
  2680.                 pass
  2681.  
  2682.         return self.ret_self()
  2683.  
  2684.  
  2685.     ####################################################################################################################
  2686.     def process_snapshot (self, mem_only=False):
  2687.         '''
  2688.        Take memory / context snapshot of the debuggee. All threads must be suspended before calling this routine.
  2689.  
  2690.        @raise pdx: An exception is raised on failure.
  2691.        @rtype:     pydbg
  2692.        @return:    Self
  2693.        '''
  2694.  
  2695.         self._log("taking debuggee snapshot")
  2696.  
  2697.         do_not_snapshot = [PAGE_READONLY, PAGE_EXECUTE_READ, PAGE_GUARD, PAGE_NOACCESS]
  2698.         cursor          = 0
  2699.  
  2700.         # reset the internal snapshot data structure lists.
  2701.         self.memory_snapshot_blocks   = []
  2702.         self.memory_snapshot_contexts = []
  2703.  
  2704.         if not mem_only:
  2705.             # enumerate the running threads and save a copy of their contexts.
  2706.             for thread_id in self.enumerate_threads():
  2707.                 context = self.get_thread_context(None, thread_id)
  2708.    
  2709.                 self.memory_snapshot_contexts.append(memory_snapshot_context(thread_id, context))
  2710.    
  2711.                 self._log("saving thread context of thread id: %08x" % thread_id)
  2712.  
  2713.         # scan through the entire memory range and save a copy of suitable memory blocks.
  2714.         while cursor < 0xFFFFFFFF:
  2715.             save_block = True
  2716.  
  2717.             try:
  2718.                 mbi = self.virtual_query(cursor)
  2719.             except:
  2720.                 break
  2721.  
  2722.             # do not snapshot blocks of memory that match the following characteristics.
  2723.             # XXX - might want to drop the MEM_IMAGE check to accomodate for self modifying code.
  2724.             if mbi.State != MEM_COMMIT or mbi.Type == MEM_IMAGE:
  2725.                 save_block = False
  2726.  
  2727.             for has_protection in do_not_snapshot:
  2728.                 if mbi.Protect & has_protection:
  2729.                     save_block = False
  2730.                     break
  2731.  
  2732.             if save_block:
  2733.                 self._log("Adding %08x +%d to memory snapsnot." % (mbi.BaseAddress, mbi.RegionSize))
  2734.  
  2735.                 # read the raw bytes from the memory block.
  2736.                 data = self.read_process_memory(mbi.BaseAddress, mbi.RegionSize)
  2737.  
  2738.                 self.memory_snapshot_blocks.append(memory_snapshot_block(mbi, data))
  2739.  
  2740.             cursor += mbi.RegionSize
  2741.  
  2742.         return self.ret_self()
  2743.  
  2744.  
  2745.     ####################################################################################################################
  2746.     def read (self, address, length):
  2747.         '''
  2748.        Alias to read_process_memory().
  2749.  
  2750.        @see: read_process_memory
  2751.        '''
  2752.  
  2753.         return self.read_process_memory(address, length)
  2754.  
  2755.  
  2756.     ####################################################################################################################
  2757.     def read_msr (self, address):
  2758.         '''
  2759.        Read data from the specified MSR address.
  2760.  
  2761.        @see: write_msr
  2762.  
  2763.        @type  address: DWORD
  2764.        @param address: MSR address to read from.
  2765.  
  2766.        @rtype:  tuple
  2767.        @return: (read status, msr structure)
  2768.        '''
  2769.  
  2770.         msr         = SYSDBG_MSR()
  2771.         msr.Address = 0x1D9
  2772.         msr.Data    = 0xFF  # must initialize this value.
  2773.  
  2774.         status = ntdll.NtSystemDebugControl(SysDbgReadMsr,
  2775.                                             byref(msr),
  2776.                                             sizeof(SYSDBG_MSR),
  2777.                                             byref(msr),
  2778.                                             sizeof(SYSDBG_MSR),
  2779.                                             0)
  2780.  
  2781.         return (status, msr)
  2782.  
  2783.  
  2784.     ####################################################################################################################
  2785.     def read_process_memory (self, address, length):
  2786.         '''
  2787.        Read from the debuggee process space.
  2788.  
  2789.        @type  address: DWORD
  2790.        @param address: Address to read from.
  2791.        @type  length:  Integer
  2792.        @param length:  Length, in bytes, of data to read.
  2793.  
  2794.        @raise pdx: An exception is raised on failure.
  2795.        @rtype:     Raw
  2796.        @return:    Read data.
  2797.        '''
  2798.  
  2799.         data         = ""
  2800.         read_buf     = create_string_buffer(length)
  2801.         count        = c_ulong(0)
  2802.         orig_length  = length
  2803.         orig_address = address
  2804.  
  2805.         # ensure we can read from the requested memory space.
  2806.         _address = address
  2807.         _length  = length
  2808.  
  2809.         try:
  2810.             old_protect = self.virtual_protect(_address, _length, PAGE_EXECUTE_READWRITE)
  2811.         except:
  2812.             pass
  2813.  
  2814.         while length:
  2815.             if not kernel32.ReadProcessMemory(self.h_process, address, read_buf, length, byref(count)):
  2816.                 if not len(data):
  2817.                     raise pdx("ReadProcessMemory(%08x, %d, read=%d)" % (address, length, count.value), True)
  2818.                 else:
  2819.                     return data
  2820.  
  2821.             data    += read_buf.raw
  2822.             length  -= count.value
  2823.             address += count.value
  2824.  
  2825.         # restore the original page permissions on the target memory region.
  2826.         try:
  2827.             self.virtual_protect(_address, _length, old_protect)
  2828.         except:
  2829.             pass
  2830.  
  2831.         return data
  2832.  
  2833.  
  2834.     ####################################################################################################################
  2835.     def resume_all_threads (self):
  2836.         '''
  2837.        Resume all process threads.
  2838.  
  2839.        @see: suspend_all_threads()
  2840.  
  2841.        @raise pdx: An exception is raised on failure.
  2842.        @rtype:     pydbg
  2843.        @return:    Self
  2844.        '''
  2845.  
  2846.         for thread_id in self.enumerate_threads():
  2847.             self.resume_thread(thread_id)
  2848.  
  2849.         return self.ret_self()
  2850.  
  2851.  
  2852.     ####################################################################################################################
  2853.     def resume_thread (self, thread_id):
  2854.         '''
  2855.        Resume the specified thread.
  2856.  
  2857.        @type  thread_id: DWORD
  2858.        @param thread_id: ID of thread to resume.
  2859.  
  2860.        @raise pdx: An exception is raised on failure.
  2861.        @rtype:     pydbg
  2862.        @return:    Self
  2863.        '''
  2864.  
  2865.         self._log("resuming thread: %08x" % thread_id)
  2866.  
  2867.         thread_handle = self.open_thread(thread_id)
  2868.  
  2869.         if kernel32.ResumeThread(thread_handle) == -1:
  2870.             raise pdx("ResumeThread()", True)
  2871.  
  2872.         self.close_handle(thread_handle)
  2873.  
  2874.         return self.ret_self()
  2875.  
  2876.  
  2877.     ####################################################################################################################
  2878.     def ret_self (self):
  2879.         '''
  2880.        This convenience routine exists for internal functions to call and transparently return the correct version of
  2881.        self. Specifically, an object in normal mode and a moniker when in client/server mode.
  2882.  
  2883.        @return: Client / server safe version of self
  2884.        '''
  2885.  
  2886.         if self.client_server:
  2887.             return "**SELF**"
  2888.         else:
  2889.             return self
  2890.  
  2891.  
  2892.     ####################################################################################################################
  2893.     def run (self):
  2894.         '''
  2895.        Alias for debug_event_loop().
  2896.  
  2897.        @see: debug_event_loop()
  2898.        '''
  2899.  
  2900.         self.debug_event_loop()
  2901.  
  2902.  
  2903.     ####################################################################################################################
  2904.     def seh_unwind (self, context=None):
  2905.         '''
  2906.        Unwind the the Structured Exception Handler (SEH) chain of the current or specified thread to the best of our
  2907.        abilities. The SEH chain is a simple singly linked list, the head of which is pointed to by fs:0. In cases where
  2908.        the SEH chain is corrupted and the handler address points to invalid memory, it will be returned as 0xFFFFFFFF.
  2909.  
  2910.        @type  context: Context
  2911.        @param context: (Optional) Current thread context to examine
  2912.  
  2913.        @rtype:  List of Tuples
  2914.        @return: Naturally ordered list of SEH addresses and handlers.
  2915.        '''
  2916.  
  2917.         self._log("seh_unwind()")
  2918.  
  2919.         selector_entry = LDT_ENTRY()
  2920.         seh_chain      = []
  2921.  
  2922.         # if the optional current thread context was not supplied, grab it for the current thread.
  2923.         if not context:
  2924.             context = self.context
  2925.  
  2926.         if not kernel32.GetThreadSelectorEntry(self.h_thread, context.SegFs, byref(selector_entry)):
  2927.             self.win32_error("GetThreadSelectorEntry()")
  2928.  
  2929.         fs_base  = selector_entry.BaseLow
  2930.         fs_base += (selector_entry.HighWord.Bits.BaseMid << 16) + (selector_entry.HighWord.Bits.BaseHi << 24)
  2931.  
  2932.         # determine the head of the current threads SEH chain.
  2933.         seh_head = self.read_process_memory(fs_base, 4)
  2934.         seh_head = self.flip_endian_dword(seh_head)
  2935.  
  2936.         while seh_head != 0xFFFFFFFF:
  2937.             try:
  2938.                 handler = self.read_process_memory(seh_head + 4, 4)
  2939.                 handler = self.flip_endian_dword(handler)
  2940.             except:
  2941.                 handler = 0xFFFFFFFF
  2942.  
  2943.             try:
  2944.                 seh_head = self.read_process_memory(seh_head, 4)
  2945.                 seh_head = self.flip_endian_dword(seh_head)
  2946.             except:
  2947.                 seh_head = 0xFFFFFFFF
  2948.  
  2949.             seh_chain.append((seh_head, handler))
  2950.  
  2951.         return seh_chain
  2952.  
  2953.  
  2954.     ####################################################################################################################
  2955.     def set_attr (self, attribute, value):
  2956.         '''
  2957.        Return the value for the specified class attribute. This routine should be used over directly accessing class
  2958.        member variables for transparent support across local vs. client/server debugger clients.
  2959.  
  2960.        @see: set_attr()
  2961.  
  2962.        @type  attribute: String
  2963.        @param attribute: Name of attribute to return.
  2964.        @type  value:     Mixed
  2965.        @param value:     Value to set attribute to.
  2966.        '''
  2967.  
  2968.         if hasattr(self, attribute):
  2969.             setattr(self, attribute, value)
  2970.  
  2971.  
  2972.     ####################################################################################################################
  2973.     def set_callback (self, exception_code, callback_func):
  2974.         '''
  2975.        Set a callback for the specified exception (or debug event) code. The prototype of the callback routines is::
  2976.  
  2977.            func (pydbg):
  2978.                return DBG_CONTINUE     # or other continue status
  2979.  
  2980.        You can register callbacks for any exception code or debug event. Look in the source for all event_handler_???
  2981.        and exception_handler_??? routines to see which ones have internal processing (internal handlers will still
  2982.        pass control to your callback). You can also register a user specified callback that is called on each loop
  2983.        iteration from within debug_event_loop(). The callback code is USER_CALLBACK_DEBUG_EVENT and the function
  2984.        prototype is::
  2985.  
  2986.            func (pydbg)
  2987.                return DBG_CONTINUE     # or other continue status
  2988.  
  2989.        User callbacks do not / should not access debugger or contextual information.
  2990.  
  2991.        @type  exception_code: Long
  2992.        @param exception_code: Exception code to establish a callback for
  2993.        @type  callback_func:  Function
  2994.        @param callback_func:  Function to call when specified exception code is caught.
  2995.        '''
  2996.  
  2997.         self.callbacks[exception_code] = callback_func
  2998.  
  2999.  
  3000.     ####################################################################################################################
  3001.     def set_debugger_active (self, enable):
  3002.         '''
  3003.        Enable or disable the control flag for the main debug event loop. This is a convenience shortcut over set_attr.
  3004.  
  3005.        @type  enable: Boolean
  3006.        @param enable: Flag controlling the main debug event loop.
  3007.        '''
  3008.  
  3009.         self._log("setting debug event loop flag to %s" % enable)
  3010.         self.debugger_active = enable
  3011.  
  3012.  
  3013.     ####################################################################################################################
  3014.     def set_register (self, register, value):
  3015.         '''
  3016.        Set the value of a register in the debuggee within the context of the self.h_thread.
  3017.  
  3018.        @type  register: Register
  3019.        @param register: One of EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP, EIP
  3020.        @type  value:    DWORD
  3021.        @param value:    Value to set register to
  3022.  
  3023.        @raise pdx: An exception is raised on failure.
  3024.        @rtype:     pydbg
  3025.        @return:    Self
  3026.        '''
  3027.  
  3028.         self._log("setting %s to %08x in thread id %d" % (register, value, self.dbg.dwThreadId))
  3029.  
  3030.         register = register.upper()
  3031.         if register not in ("EAX", "EBX", "ECX", "EDX", "ESI", "EDI", "ESP", "EBP", "EIP"):
  3032.             raise pdx("invalid register specified")
  3033.  
  3034.         # ensure we have an up to date thread context.
  3035.         context = self.get_thread_context(self.h_thread)
  3036.  
  3037.         if   register == "EAX": context.Eax = value
  3038.         elif register == "EBX": context.Ebx = value
  3039.         elif register == "ECX": context.Ecx = value
  3040.         elif register == "EDX": context.Edx = value
  3041.         elif register == "ESI": context.Esi = value
  3042.         elif register == "EDI": context.Edi = value
  3043.         elif register == "ESP": context.Esp = value
  3044.         elif register == "EBP": context.Ebp = value
  3045.         elif register == "EIP": context.Eip = value
  3046.  
  3047.         self.set_thread_context(context)
  3048.  
  3049.         return self.ret_self()
  3050.  
  3051.  
  3052.     ####################################################################################################################
  3053.     def set_thread_context (self, context, thread_handle=None, thread_id=0):
  3054.         '''
  3055.        Convenience wrapper around SetThreadContext(). Can set a thread context via a handle or thread id.
  3056.  
  3057.        @type  thread_handle: HANDLE
  3058.        @param thread_handle: (Optional) Handle of thread to get context of
  3059.        @type  context:       CONTEXT
  3060.        @param context:       Context to apply to specified thread
  3061.        @type  thread_id:     Integer
  3062.        @param thread_id:     (Optional, Def=0) ID of thread to get context of
  3063.  
  3064.        @raise pdx: An exception is raised on failure.
  3065.        @rtype:     pydbg
  3066.        @return:    Self
  3067.        '''
  3068.  
  3069.         # if neither a thread handle or thread id were specified, default to the internal one.
  3070.         if not thread_handle and not thread_id:
  3071.             h_thread = self.h_thread
  3072.  
  3073.         # if a thread handle was not specified, get one from the thread id.
  3074.         elif not thread_handle:
  3075.             h_thread = self.open_thread(thread_id)
  3076.  
  3077.         # use the specified thread handle.
  3078.         else:
  3079.             h_thread = thread_handle
  3080.  
  3081.         if not kernel32.SetThreadContext(h_thread, byref(context)):
  3082.             raise pdx("SetThreadContext()", True)
  3083.  
  3084.         # if we had to resolve the thread handle, close it.
  3085.         if not thread_handle and thread_id:
  3086.             self.close_handle(h_thread)
  3087.  
  3088.         return self.ret_self()
  3089.  
  3090.  
  3091.     ####################################################################################################################
  3092.     def sigint_handler (self, signal_number, stack_frame):
  3093.         '''
  3094.        Interrupt signal handler. We override the default handler to disable the run flag and exit the main
  3095.        debug event loop.
  3096.  
  3097.        @type  signal_number:
  3098.        @param signal_number:
  3099.        @type  stack_frame:
  3100.        @param stack_frame:
  3101.        '''
  3102.  
  3103.         self.set_debugger_active(False)
  3104.  
  3105.  
  3106.     ####################################################################################################################
  3107.     def single_step (self, enable, thread_handle=None):
  3108.         '''
  3109.        Enable or disable single stepping in the specified thread or self.h_thread if a thread handle is not specified.
  3110.  
  3111.        @type  enable:        Bool
  3112.        @param enable:        True to enable single stepping, False to disable
  3113.        @type  thread_handle: Handle
  3114.        @param thread_handle: (Optional, Def=None) Handle of thread to put into single step mode
  3115.  
  3116.        @raise pdx: An exception is raised on failure.
  3117.        @rtype:     pydbg
  3118.        @return:    Self
  3119.        '''
  3120.  
  3121.         self._log("single_step(%s)" % enable)
  3122.  
  3123.         if not thread_handle:
  3124.             thread_handle = self.h_thread
  3125.  
  3126.         context = self.get_thread_context(thread_handle)
  3127.  
  3128.         if enable:
  3129.             # single step already enabled.
  3130.             if context.EFlags & EFLAGS_TRAP:
  3131.                 return self.ret_self()
  3132.  
  3133.             context.EFlags |= EFLAGS_TRAP
  3134.         else:
  3135.             # single step already disabled:
  3136.             if not context.EFlags & EFLAGS_TRAP:
  3137.                 return self.ret_self()
  3138.  
  3139.             context.EFlags = context.EFlags & (0xFFFFFFFFFF ^ EFLAGS_TRAP)
  3140.  
  3141.         self.set_thread_context(context, thread_handle=thread_handle)
  3142.  
  3143.         return self.ret_self()
  3144.  
  3145.  
  3146.     ####################################################################################################################
  3147.     def smart_dereference (self, address, print_dots=True, hex_dump=False):
  3148.         '''
  3149.        "Intelligently" discover data behind an address. The address is dereferenced and explored in search of an ASCII
  3150.        or Unicode string. In the absense of a string the printable characters are returned with non-printables
  3151.        represented as dots (.). The location of the discovered data is returned as well as either "heap", "stack" or
  3152.        the name of the module it lies in (global data).
  3153.  
  3154.        @type  address:    DWORD
  3155.        @param address:    Address to smart dereference
  3156.        @type  print_dots: Bool
  3157.        @param print_dots: (Optional, def:True) Controls suppression of dot in place of non-printable
  3158.        @type  hex_dump:   Bool
  3159.        @param hex_dump:   (Optional, def=False) Return a hex dump in the absense of string detection
  3160.  
  3161.        @rtype:  String
  3162.        @return: String of data discovered behind dereference.
  3163.        '''
  3164.  
  3165.         try:
  3166.             mbi = self.virtual_query(address)
  3167.         except:
  3168.             return "N/A"
  3169.  
  3170.         # if the address doesn't point into writable memory (stack or heap), then bail.
  3171.         if not mbi.Protect & PAGE_READWRITE:
  3172.             return "N/A"
  3173.  
  3174.         # if the address does point to writeable memory, ensure it doesn't sit on the PEB or any of the TEBs.
  3175.         if mbi.BaseAddress == self.peb or mbi.BaseAddress in self.tebs.values():
  3176.             return "N/A"
  3177.  
  3178.         try:
  3179.             explored = self.read_process_memory(address, self.STRING_EXPLORATON_BUF_SIZE)
  3180.         except:
  3181.             return "N/A"
  3182.  
  3183.         # determine if the write-able address sits in the stack range.
  3184.         if self.is_address_on_stack(address):
  3185.             location = "stack"
  3186.  
  3187.         # otherwise it could be in a module's global section or on the heap.
  3188.         else:
  3189.             module = self.addr_to_module(address)
  3190.  
  3191.             if module:
  3192.                 location = "%s.data" % module.szModule
  3193.  
  3194.             # if the write-able address is not on the stack or in a module range, then we assume it's on the heap.
  3195.             # we *could* walk the heap structures to determine for sure, but it's a slow method and this process of
  3196.             # elimination works well enough.
  3197.             else:
  3198.                 location = "heap"
  3199.  
  3200.         explored_string = self.get_ascii_string(explored)
  3201.  
  3202.         if not explored_string:
  3203.             explored_string = self.get_unicode_string(explored)
  3204.  
  3205.         if not explored_string and hex_dump:
  3206.             explored_string = self.hex_dump(explored)
  3207.  
  3208.         if not explored_string:
  3209.             explored_string = self.get_printable_string(explored, print_dots)
  3210.  
  3211.         if hex_dump:
  3212.             return "%s --> %s" % (explored_string, location)
  3213.         else:
  3214.             return "%s (%s)" % (explored_string, location)
  3215.  
  3216.  
  3217.     ####################################################################################################################
  3218.     def stack_range (self, context=None):
  3219.         '''
  3220.        Determine the stack range (top and bottom) of the current or specified thread. The desired information is
  3221.        located at offsets 4 and 8 from the Thread Environment Block (TEB), which in turn is pointed to by fs:0.
  3222.  
  3223.        @type  context: Context
  3224.        @param context: (Optional) Current thread context to examine
  3225.  
  3226.        @rtype:  Mixed
  3227.        @return: List containing (stack_top, stack_bottom) on success, False otherwise.
  3228.        '''
  3229.  
  3230.         selector_entry = LDT_ENTRY()
  3231.  
  3232.         # if the optional current thread context was not supplied, grab it for the current thread.
  3233.         if not context:
  3234.             context = self.context
  3235.  
  3236.         if not kernel32.GetThreadSelectorEntry(self.h_thread, context.SegFs, byref(selector_entry)):
  3237.             self.win32_error("GetThreadSelectorEntry()")
  3238.  
  3239.         fs_base  = selector_entry.BaseLow
  3240.         fs_base += (selector_entry.HighWord.Bits.BaseMid << 16) + (selector_entry.HighWord.Bits.BaseHi << 24)
  3241.  
  3242.         # determine the top and bottom of the debuggee's stack.
  3243.         stack_top    = self.read_process_memory(fs_base + 4, 4)
  3244.         stack_bottom = self.read_process_memory(fs_base + 8, 4)
  3245.  
  3246.         stack_top    = self.flip_endian_dword(stack_top)
  3247.         stack_bottom = self.flip_endian_dword(stack_bottom)
  3248.  
  3249.         return (stack_top, stack_bottom)
  3250.  
  3251.  
  3252.     ####################################################################################################################
  3253.     def stack_unwind (self, context=None):
  3254.         '''
  3255.        Unwind the stack to the best of our ability. This function is really only useful if called when EBP is actually
  3256.        used as a frame pointer. If it is otherwise being used as a general purpose register then stack unwinding will
  3257.        fail immediately.
  3258.  
  3259.        @type  context: Context
  3260.        @param context: (Optional) Current thread context to examine
  3261.  
  3262.        @rtype:  List
  3263.        @return: The current call stack ordered from most recent call backwards.
  3264.        '''
  3265.  
  3266.         self._log("stack_unwind()")
  3267.  
  3268.         selector_entry = LDT_ENTRY()
  3269.         call_stack     = []
  3270.  
  3271.         # if the optional current thread context was not supplied, grab it for the current thread.
  3272.         if not context:
  3273.             context = self.context
  3274.  
  3275.         # determine the stack top / bottom.
  3276.         (stack_top, stack_bottom) = self.stack_range(context)
  3277.  
  3278.         this_frame = context.Ebp
  3279.  
  3280.         while this_frame > stack_bottom and this_frame < stack_top:
  3281.             # stack frame sanity check: must be DWORD boundary aligned.
  3282.             if this_frame & 3:
  3283.                 break
  3284.  
  3285.             try:
  3286.                 ret_addr = self.read_process_memory(this_frame + 4, 4)
  3287.                 ret_addr = self.flip_endian_dword(ret_addr)
  3288.             except:
  3289.                 break
  3290.  
  3291.             # return address sanity check: return address must live on an executable page.
  3292.             try:
  3293.                 mbi = self.virtual_query(ret_addr)
  3294.             except:
  3295.                 break
  3296.  
  3297.             if mbi.Protect not in (PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY):
  3298.                 break
  3299.  
  3300.             # add the return address to the call stack.
  3301.             call_stack.append(ret_addr)
  3302.  
  3303.             # follow the frame pointer to the next frame.
  3304.             try:
  3305.                 next_frame = self.read_process_memory(this_frame, 4)
  3306.                 next_frame = self.flip_endian_dword(next_frame)
  3307.             except:
  3308.                 break
  3309.  
  3310.             # stack frame sanity check: new frame must be at a higher address then the previous frame.
  3311.             if next_frame <= this_frame:
  3312.                 break
  3313.  
  3314.             this_frame = next_frame
  3315.  
  3316.         return call_stack
  3317.  
  3318.  
  3319.     ####################################################################################################################
  3320.     def suspend_all_threads (self):
  3321.         '''
  3322.        Suspend all process threads.
  3323.  
  3324.        @see: resume_all_threads()
  3325.  
  3326.        @raise pdx: An exception is raised on failure.
  3327.        @rtype:     pydbg
  3328.        @return:    Self
  3329.        '''
  3330.  
  3331.         for thread_id in self.enumerate_threads():
  3332.             self.suspend_thread(thread_id)
  3333.  
  3334.         return self.ret_self()
  3335.  
  3336.  
  3337.     ####################################################################################################################
  3338.     def suspend_thread (self, thread_id):
  3339.         '''
  3340.        Suspend the specified thread.
  3341.  
  3342.        @type  thread_id: DWORD
  3343.        @param thread_id: ID of thread to suspend
  3344.  
  3345.        @raise pdx: An exception is raised on failure.
  3346.        @rtype:     pydbg
  3347.        @return:    Self
  3348.        '''
  3349.  
  3350.         self._log("suspending thread: %08x" % thread_id)
  3351.  
  3352.         thread_handle = self.open_thread(thread_id)
  3353.  
  3354.         if kernel32.SuspendThread(thread_handle) == -1:
  3355.             raise pdx("SuspendThread()", True)
  3356.  
  3357.         self.close_handle(thread_handle)
  3358.  
  3359.         return self.ret_self()
  3360.  
  3361.  
  3362.     ####################################################################################################################
  3363.     def terminate_process (self, exit_code=0, method="terminateprocess"):
  3364.         '''
  3365.        Terminate the debuggee using the specified method.
  3366.  
  3367.        "terminateprocess": Terminate the debuggee by calling TerminateProcess(debuggee_handle).
  3368.        "exitprocess":      Terminate the debuggee by setting its current EIP to ExitProcess().
  3369.  
  3370.        @type  exit_code: Integer
  3371.        @param exit_code: (Optional, def=0) Exit code
  3372.        @type  method:    String
  3373.        @param method:    (Optonal, def="terminateprocess") Termination method. See __doc__ for more info.
  3374.  
  3375.        @raise pdx: An exception is raised on failure.
  3376.        '''
  3377.  
  3378.         if method.lower().startswith("exitprocess"):
  3379.             self.context.Eip = self.func_resolve_debuggee("kernel32", "ExitProcess")
  3380.             self.set_thread_context(self.context)
  3381.  
  3382.         # fall back to "terminateprocess".
  3383.         else:
  3384.             if not kernel32.TerminateProcess(self.h_process, exit_code):
  3385.                 raise pdx("TerminateProcess(%d)" % exit_code, True)
  3386.  
  3387.  
  3388.     ####################################################################################################################
  3389.     def to_binary (self, number, bit_count=32):
  3390.         '''
  3391.        Convert a number into a binary string. This is an ugly one liner that I ripped off of some site.
  3392.  
  3393.        @see: to_decimal()
  3394.  
  3395.        @type  number:    Integer
  3396.        @param number:    Number to convert to binary string.
  3397.        @type  bit_count: Integer
  3398.        @param bit_count: (Optional, Def=32) Number of bits to include in output string.
  3399.  
  3400.        @rtype:  String
  3401.        @return: Specified integer as a binary string
  3402.        '''
  3403.  
  3404.         return "".join(map(lambda x:str((number >> x) & 1), range(bit_count -1, -1, -1)))
  3405.  
  3406.  
  3407.     ####################################################################################################################
  3408.     def to_decimal (self, binary):
  3409.         '''
  3410.        Convert a binary string into a decimal number.
  3411.  
  3412.        @see: to_binary()
  3413.  
  3414.        @type  binary: String
  3415.        @param binary: Binary string to convert to decimal
  3416.  
  3417.        @rtype:  Integer
  3418.        @return: Specified binary string as an integer
  3419.        '''
  3420.  
  3421.         # this is an ugly one liner that I ripped off of some site.
  3422.         #return sum(map(lambda x: int(binary[x]) and 2**(len(binary) - x - 1), range(len(binary)-1, -1, -1)))
  3423.  
  3424.         # this is much cleaner (thanks cody)
  3425.         return int(binary, 2)
  3426.  
  3427.  
  3428.     ####################################################################################################################
  3429.     def virtual_alloc (self, address, size, alloc_type, protection):
  3430.         '''
  3431.        Convenience wrapper around VirtualAllocEx()
  3432.  
  3433.        @type  address:    DWORD
  3434.        @param address:    Desired starting address of region to allocate, can be None
  3435.        @type  size:       Integer
  3436.        @param size:       Size of memory region to allocate, in bytes
  3437.        @type  alloc_type: DWORD
  3438.        @param alloc_type: The type of memory allocation (most often MEM_COMMIT)
  3439.        @type  protection: DWORD
  3440.        @param protection: Memory protection to apply to the specified region
  3441.  
  3442.        @raise pdx: An exception is raised on failure.
  3443.        @rtype:     DWORD
  3444.        @return:    Base address of the allocated region of pages.
  3445.        '''
  3446.  
  3447.         if address:
  3448.             self._log("VirtualAllocEx(%08x, %d, %08x, %08x)" % (address, size, alloc_type, protection))
  3449.         else:
  3450.             self._log("VirtualAllocEx(NULL, %d, %08x, %08x)" % (size, alloc_type, protection))
  3451.  
  3452.         allocated_address = kernel32.VirtualAllocEx(self.h_process, address, size, alloc_type, protection)
  3453.  
  3454.         if not allocated_address:
  3455.             raise pdx("VirtualAllocEx(%08x, %d, %08x, %08x)" % (address, size, alloc_type, protection), True)
  3456.  
  3457.         return allocated_address
  3458.  
  3459.  
  3460.     ####################################################################################################################
  3461.     def virtual_free (self, address, size, free_type):
  3462.         '''
  3463.        Convenience wrapper around VirtualFreeEx()
  3464.  
  3465.        @type  address:    DWORD
  3466.        @param address:    Pointer to the starting address of the region of memory to be freed
  3467.        @type  size:       Integer
  3468.        @param size:       Size of memory region to free, in bytes
  3469.        @type  free_type:  DWORD
  3470.        @param free_type:  The type of free operation
  3471.  
  3472.        @raise pdx: An exception is raised on failure.
  3473.        '''
  3474.  
  3475.         self._log("VirtualFreeEx(%08x, %d, %08x)" % (address, size, free_type))
  3476.  
  3477.         if not kernel32.VirtualFreeEx(self.h_process, address, size, free_type):
  3478.             raise pdx("VirtualFreeEx(%08x, %d, %08x)" % (address, size, free_type), True)
  3479.  
  3480.  
  3481.     ####################################################################################################################
  3482.     def virtual_protect (self, base_address, size, protection):
  3483.         '''
  3484.        Convenience wrapper around VirtualProtectEx()
  3485.  
  3486.        @type  base_address: DWORD
  3487.        @param base_address: Base address of region of pages whose access protection attributes are to be changed
  3488.        @type  size:         Integer
  3489.        @param size:         Size of the region whose access protection attributes are to be changed
  3490.        @type  protection:   DWORD
  3491.        @param protection:   Memory protection to apply to the specified region
  3492.  
  3493.        @raise pdx: An exception is raised on failure.
  3494.        @rtype:     DWORD
  3495.        @return:    Previous access protection.
  3496.        '''
  3497.  
  3498.         #self._log("VirtualProtectEx( , 0x%08x, %d, %08x, ,)" % (base_address, size, protection))
  3499.  
  3500.         old_protect = c_ulong(0)
  3501.  
  3502.         if not kernel32.VirtualProtectEx(self.h_process, base_address, size, protection, byref(old_protect)):
  3503.             raise pdx("VirtualProtectEx(%08x, %d, %08x)" % (base_address, size, protection), True)
  3504.  
  3505.         return old_protect.value
  3506.  
  3507.  
  3508.     ####################################################################################################################
  3509.     def virtual_query (self, address):
  3510.         '''
  3511.        Convenience wrapper around VirtualQueryEx().
  3512.  
  3513.        @type  address: DWORD
  3514.        @param address: Address to query
  3515.  
  3516.        @raise pdx: An exception is raised on failure.
  3517.  
  3518.        @rtype:  MEMORY_BASIC_INFORMATION
  3519.        @return: MEMORY_BASIC_INFORMATION
  3520.        '''
  3521.  
  3522.         mbi = MEMORY_BASIC_INFORMATION()
  3523.  
  3524.         if kernel32.VirtualQueryEx(self.h_process, address, byref(mbi), sizeof(mbi)) < sizeof(mbi):
  3525.             raise pdx("VirtualQueryEx(%08x)" % address, True)
  3526.  
  3527.         return mbi
  3528.  
  3529.  
  3530.     ####################################################################################################################
  3531.     def win32_error (self, prefix=None):
  3532.         '''
  3533.        Convenience wrapper around GetLastError() and FormatMessage(). Raises an exception with the relevant error code
  3534.        and formatted message.
  3535.  
  3536.        @type  prefix: String
  3537.        @param prefix: (Optional) String to prefix error message with.
  3538.  
  3539.        @raise pdx: An exception is always raised by this routine.
  3540.        '''
  3541.  
  3542.         error      = c_char_p()
  3543.         error_code = kernel32.GetLastError()
  3544.  
  3545.         kernel32.FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  3546.                                 None,
  3547.                                 error_code,
  3548.                                 0x00000400,     # MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)
  3549.                                 byref(error),
  3550.                                 0,
  3551.                                 None)
  3552.         if prefix:
  3553.             error_message = "%s: %s" % (prefix, error.value)
  3554.         else:
  3555.             error_message = "GetLastError(): %s" % error.value
  3556.  
  3557.         raise pdx(error_message, error_code)
  3558.  
  3559.  
  3560.     ####################################################################################################################
  3561.     def write (self, address, data, length=0):
  3562.         '''
  3563.        Alias to write_process_memory().
  3564.  
  3565.        @see: write_process_memory
  3566.        '''
  3567.  
  3568.         return self.write_process_memory(address, data, length)
  3569.  
  3570.  
  3571.     ####################################################################################################################
  3572.     def write_msr (self, address, data):
  3573.         '''
  3574.        Write data to the specified MSR address.
  3575.  
  3576.        @see: read_msr
  3577.  
  3578.        @type  address: DWORD
  3579.        @param address: MSR address to write to.
  3580.        @type  data:    QWORD
  3581.        @param data:    Data to write to MSR address.
  3582.  
  3583.        @rtype:  tuple
  3584.        @return: (read status, msr structure)
  3585.        '''
  3586.  
  3587.         msr         = SYSDBG_MSR()
  3588.         msr.Address = address
  3589.         msr.Data    = data
  3590.  
  3591.         status = ntdll.NtSystemDebugControl(SysDbgWriteMsr,
  3592.                                             byref(msr),
  3593.                                             sizeof(SYSDBG_MSR),
  3594.                                             0,
  3595.                                             0,
  3596.                                             0)
  3597.  
  3598.         return status
  3599.  
  3600.  
  3601.     ####################################################################################################################
  3602.     def write_process_memory (self, address, data, length=0):
  3603.         '''
  3604.        Write to the debuggee process space. Convenience wrapper around WriteProcessMemory(). This routine will
  3605.        continuously attempt to write the data requested until it is complete.
  3606.  
  3607.        @type  address: DWORD
  3608.        @param address: Address to write to
  3609.        @type  data:    Raw Bytes
  3610.        @param data:    Data to write
  3611.        @type  length:  DWORD
  3612.        @param length:  (Optional, Def:len(data)) Length of data, in bytes, to write
  3613.  
  3614.        @raise pdx: An exception is raised on failure.
  3615.        '''
  3616.  
  3617.         count = c_ulong(0)
  3618.  
  3619.         # if the optional data length parameter was omitted, calculate the length ourselves.
  3620.         if not length:
  3621.             length = len(data)
  3622.  
  3623.         # ensure we can write to the requested memory space.
  3624.         _address = address
  3625.         _length  = length
  3626.         try:
  3627.             old_protect = self.virtual_protect(_address, _length, PAGE_EXECUTE_READWRITE)
  3628.         except:
  3629.             pass
  3630.  
  3631.         while length:
  3632.             c_data = c_char_p(data[count.value:])
  3633.  
  3634.             if not kernel32.WriteProcessMemory(self.h_process, address, c_data, length, byref(count)):
  3635.                 raise pdx("WriteProcessMemory(%08x, ..., %d)" % (address, length), True)
  3636.  
  3637.             length  -= count.value
  3638.             address += count.value
  3639.  
  3640.         # restore the original page permissions on the target memory region.
  3641.         try:
  3642.             self.virtual_protect(_address, _length, old_protect)
  3643.         except:
  3644.             pass
Add Comment
Please, Sign In to add comment