Writing samples and doc !

This commit is contained in:
Clement Rouault
2016-02-10 17:30:54 +01:00
parent c40cb0c8b0
commit c5e021f10d
10 changed files with 350 additions and 96 deletions
+46
View File
@@ -0,0 +1,46 @@
:mod:`windows.debug` -- Debugging
=================================
.. module:: windows.debug
.. note::
See sample :ref:`sample_debugger`
:class:`Debugger`
"""""""""""""""""
The :class:`Debugger` is the base class to perform the debugging of a remote process.
The :class:`Debugger` have some functions called on given event that can be implemented by subclasses.
.. autoclass:: Debugger
:members:
.. automethod:: __init__
:class:`Breakpoint`
"""""""""""""""""""
Standard breakpoints types expect an address as argument.
An address can be:
* An :class:`int`
* A :class:`str` of form (breakpoint will be put when ``DLL`` is loaded):
* ``"DLL!ApiName"``
* ``"DLL!Offset"`` where offset is a int ("16", "0x10", ..)
When a breakpoint is hit, its ``trigger`` function is called with the debugger and a
``DEBUG_EXECEPTION_EVENT`` structure as argument.
.. autoclass:: Breakpoint
:members:
.. autoclass:: HXBreakpoint
:members:
:inherited-members:
+96
View File
@@ -0,0 +1,96 @@
Exception and Context related structures
========================================
.. module:: windows.exception
This module regroups all the Exception/Context related structures and functions.
Most of the structures are the Windows structure with a prefix ``E`` (For enhanced)
Those structure have the same fields that the normal windows ones but its types might vary for a simpler use.
This module also define the decorator :func:`VectoredException` which allows to play with ``Vectored Exception Handler`` in Python
See sample :ref:`sample_vectoredexception`
Exception Records
'''''''''''''''''
.. autoclass:: EEXCEPTION_RECORD
:members:
:inherited-members:
.. autoclass:: EEXCEPTION_RECORD32
:inherited-members:
.. autoclass:: EEXCEPTION_RECORD64
:members:
:inherited-members:
EXCEPTION DEBUG INFO
''''''''''''''''''''
.. autoclass:: EEXCEPTION_DEBUG_INFO32
:members:
:inherited-members:
.. data:: ExceptionRecord
:type: :class:`EEXCEPTION_RECORD32`
.. autoclass:: EEXCEPTION_DEBUG_INFO64
:members:
:inherited-members:
.. data:: ExceptionRecord
:type: :class:`EEXCEPTION_RECORD64`
Context
'''''''
.. autoclass:: ECONTEXT32
:members:
:inherited-members:
.. autoclass:: ECONTEXTWOW64
:members:
:inherited-members:
.. autoclass:: ECONTEXT64
:members:
:inherited-members:
.. autoclass:: EEflags
:members:
.. autoclass:: EDr7
:members:
EXCEPTION POINTERS
''''''''''''''''''
.. autoclass:: EEXCEPTION_POINTERS
:members:
.. data:: ExceptionRecord
:type: POINTER to :class:`EEXCEPTION_RECORD`
.. data:: ContextRecord
:type: POINTER to :class:`ECONTEXT32` or :class:`ECONTEXT64`
.. _vectoredexception:
Vectored Exception
''''''''''''''''''
.. note::
See sample :ref:`sample_vectoredexception`
.. autoclass:: VectoredException
:members:
+2 -1
View File
@@ -4,7 +4,7 @@
contain the root `toctree` directive.
Welcome to PythonForWindows's documentation!
=====================================
============================================
Contents:
@@ -17,6 +17,7 @@ Contents:
native_exec.rst
winproxy.rst
utils.rst
debug.rst
iat_hook.rst
wip.rst
internals.rst
+53
View File
@@ -181,3 +181,56 @@ Demo::
:mod:`windows.native_exec.nativeutils` -- Native utility functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.. module:: windows.native_exec.nativeutils
This module contains some native-code functions that can be used for various purposes.
Each function export a label that allow another :class:`MultipleInstr` to call the code of the function.
The current functions are:
* ``StrlenW64`` A 64bits wide-string STRLEN (``Label(":FUNC_STRLENW64")``)
* ``StrlenA64`` A 64bits ASCII STRLEN (``Label(":FUNC_STRLENA64")``)
* ``GetProcAddress64`` A 64bits export resolver (``Label(":FUNC_GETPROCADDRESS64")``)
* Arg1: The DLL (wstring)
* Arg2: The API (string)
* Return value:
* 0xfffffffffffffffe if the DLL is not found
* 0xffffffffffffffff if the API is not found
* The address of the function
* ``StrlenW32`` A 32bits wide-string STRLEN (``Label(":FUNC_STRLENW32")``)
* ``StrlenA32`` A 32bits ASCII STRLEN (``Label(":FUNC_STRLENA32")``)
* ``GetProcAddress32`` A 32bits export resolver (``Label(":FUNC_GETPROCADDRESS32")``)
* Arg1: The DLL (wstring)
* Arg2: The API (string)
* Return value:
* 0xfffffffe if the DLL is not found
* 0xffffffff if the API is not found
* The address of the function
To use those functions in a :class:`MultipleInstr` just call the label in your code and append the function at
the end of your :class:`MultipleInstr`
Example::
RemoteManualLoadLibray = x86.MultipleInstr()
RemoteManualLoadLibray += x86.Mov("ECX", x86.mem("[ESP + 4]"))
RemoteManualLoadLibray += x86.Push(x86.mem("[ECX + 4]"))
RemoteManualLoadLibray += x86.Push(x86.mem("[ECX]"))
RemoteManualLoadLibray += x86.Call(":FUNC_GETPROCADDRESS32")
RemoteManualLoadLibray += x86.Push(x86.mem("[ECX + 8]"))
RemoteManualLoadLibray += x86.Call("EAX") # LoadLibrary
RemoteManualLoadLibray += x86.Pop("ECX")
RemoteManualLoadLibray += x86.Pop("ECX")
RemoteManualLoadLibray += x86.Ret()
RemoteManualLoadLibray += GetProcAddress32
+7
View File
@@ -50,6 +50,13 @@ WinThread
:show-inheritance:
:inherited-members:
Token
'''''
.. autoclass:: Token
:members:
:inherited-members:
PEB Exploration
"""""""""""""""
+94
View File
@@ -188,3 +188,97 @@ Output::
...
KeyValue(name='PathName', value=u'C:\\Windows', type=1)]
registered owner = <KeyValue(name='RegisteredOwner', value=u'hakril', type=1)>
.. _sample_vectoredexception:
:func:`VectoredException`
"""""""""""""""""""""""""
In local process
''''''''''''''''
.. literalinclude:: ..\..\samples\veh_segv.py
Output::
(cmd λ) python.exe veh_segv.py
Protected page is at <0x1db0000>
Setting page protection to <PAGE_NOACCESS>
==Entry of VEH handler==
Instr at 0x1d1ab574 accessed to addr 0x1db0000
Resetting page protection to <PAGE_READWRITE>
==Entry of VEH handler==
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_NOACCESS>
Value 1 read
==Entry of VEH handler==
Instr at 0x1d1ab574 accessed to addr 0x1db0010
Resetting page protection to <PAGE_READWRITE>
==Entry of VEH handler==
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_NOACCESS>
Value 2 read
In remote process
'''''''''''''''''
.. literalinclude:: ..\..\samples\remote_veh_segv.py
Output::
(cmd λ) python .exe.\samples\remote_veh_segv.py
(In another console)
Tracing execution in module: <gdi32.dll>
Protected page is at 0x7ffa3c700000L
Instr at 0x7ffa3c70f0f0L accessed to addr 0x7ffa3c70f0f0L (gdi32.dll)
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_READWRITE>
Instr at 0x7ffa3c70f0f5L accessed to addr 0x7ffa3c70f0f5L (gdi32.dll)
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_READWRITE>
Instr at 0x7ffa3c70f0faL accessed to addr 0x7ffa3c70f0faL (gdi32.dll)
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_READWRITE>
Instr at 0x7ffa3c70f0ffL accessed to addr 0x7ffa3c70f0ffL (gdi32.dll)
Exception of type EXCEPTION_SINGLE_STEP(0x80000004L)
Resetting page protection to <PAGE_READWRITE>
Instr at 0x7ffa3c70f100L accessed to addr 0x7ffa3c70f100L (gdi32.dll)
No more tracing !
.. _sample_debugger:
Debugging
"""""""""
.. literalinclude:: ..\..\samples\debugger.py
Ouput::
(cmd λ) python.exe .\samples\debugger.py
Loading <KERNEL32.DLL>
Got exception EXCEPTION_BREAKPOINT(0x80000003L) at 0x77a73bad
Loading <C:\Windows\system32\IMM32.DLL>
Loading <C:\Windows\system32\uxtheme.dll>
Loading <C:\Windows\system32\uxtheme.dll>
Loading <C:\Windows\system32\uxtheme.dll>
Loading <C:\Windows\system32\uxtheme.dll>
Loading <kernel32.dll>
Loading <C:\Windows\WinSxS\x86_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.9600.17415_none_dad8722c5bcc2d8f\gdiplus.dll>
Loading <comctl32.dll>
Loading <comctl32.dll>
Loading <comctl32.dll>
Loading <C:\Windows\system32\shell32.dll>
Loading <C:\Windows\SYSTEM32\WINMM.dll>
Loading <C:\Windows\system32\ole32.dll>
Ask to load <ole32.dll>: exiting process
+1
View File
@@ -10,6 +10,7 @@ This sections describes them by group of relation.
:maxdepth: 3
process.rst
exception.rst
registry.rst
network.rst
com.rst
+37 -17
View File
@@ -3,42 +3,62 @@ import windows.test
from windows.generated_def.winstructs import *
#c = windows.test.pop_calc_64()
c = windows.test.pop_calc_64(dwCreationFlags=CREATE_SUSPENDED)
python_code = """
import windows
import ctypes
import windows
from windows.vectored_exception import VectoredException
from windows.exception import VectoredException
import windows.generated_def.windef as windef
from windows.generated_def.winstructs import *
windows.utils.create_console()
module_to_trace = "gdi32.dll"
nb_repeat = [5]
@VectoredException
def handler(exc):
print("POUET EXCEPTION")
if exc[0].ExceptionRecord[0].ExceptionCode == EXCEPTION_ACCESS_VIOLATION:
print("")
target_addr = ctypes.cast(exc[0].ExceptionRecord[0].ExceptionInformation[1], ctypes.c_void_p).value
print("Instr at {0} accessed to addr {1}".format(hex(exc[0].ExceptionRecord[0].ExceptionAddress), hex(target_addr)))
windows.winproxy.VirtualProtect(target_page, 0x1000, windef.PAGE_READWRITE)
print("Instr at {0} accessed to addr {1} ({2})".format(hex(exc[0].ExceptionRecord[0].ExceptionAddress), hex(target_addr), module_to_trace))
windows.winproxy.VirtualProtect(target_page, code_size, windef.PAGE_EXECUTE_READWRITE)
nb_repeat[0] -= 1
if nb_repeat[0]:
exc[0].ContextRecord[0].EEFlags.TF = 1
else:
print("No more tracing !")
return windef.EXCEPTION_CONTINUE_EXECUTION
else:
print("Exception of type {0}".format(exc[0].ExceptionRecord[0].ExceptionCode))
print("Resetting page protection to <PAGE_READWRITE>")
windows.winproxy.VirtualProtect(target_page, code_size, windef.PAGE_READWRITE)
return windef.EXCEPTION_CONTINUE_EXECUTION
return windef.EXCEPTION_CONTINUE_SEARCH
windows.winproxy.AddVectoredExceptionHandler(0, handler)
target_page = windows.current_process.virtual_alloc(0x1000)
print("Protected page is at {0}".format(hex(target_page)))
windows.winproxy.VirtualProtect(target_page, 0x1000, windef.PAGE_NOACCESS)
print("Tracing execution in module: <{0}>".format(module_to_trace))
print("YOLO <3")
print(ctypes.c_uint.from_address(target_page + 0x42).value)
module = [x for x in windows.current_process.peb.modules if x.name == module_to_trace][0]
target_page = module.baseaddr
code_size = module.pe.get_OptionalHeader().SizeOfCode
print("Protected page is at {0}".format(hex(target_page)))
windows.winproxy.VirtualProtect(target_page, code_size, windef.PAGE_READWRITE)
"""
c = windows.test.pop_calc_64(dwCreationFlags=CREATE_SUSPENDED)
x = c.execute_python(python_code)
c.threads[0].resume()
import time
time.sleep(0.1)
for t in c.threads:
t.suspend()
time.sleep(1)
c.exit()
x = c.execute_python(python_code)
+12 -21
View File
@@ -1,21 +1,23 @@
import ctypes
import windows
from windows.vectored_exception import VectoredException
from windows.exception import VectoredException
import windows.generated_def.windef as windef
from windows.generated_def.winstructs import *
@VectoredException
def handler(exc):
print("POUET")
print("==Entry of VEH handler==")
if exc[0].ExceptionRecord[0].ExceptionCode == EXCEPTION_ACCESS_VIOLATION:
target_addr = ctypes.cast(exc[0].ExceptionRecord[0].ExceptionInformation[1], ctypes.c_void_p).value
print("Instr at {0} accessed to addr {1}".format(hex(exc[0].ExceptionRecord[0].ExceptionAddress), hex(target_addr)))
print("Resetting page protection to <PAGE_READWRITE>")
windows.winproxy.VirtualProtect(target_page, 0x1000, windef.PAGE_READWRITE)
exc[0].ContextRecord[0].EEFlags.TF = 1
return windef.EXCEPTION_CONTINUE_EXECUTION
else:
print("HAHAH {0}".format(exc[0].ExceptionRecord[0].ExceptionCode))
print("Exception of type {0}".format(exc[0].ExceptionRecord[0].ExceptionCode))
print("Resetting page protection to <PAGE_NOACCESS>")
windows.winproxy.VirtualProtect(target_page, 0x1000, windef.PAGE_NOACCESS)
return windef.EXCEPTION_CONTINUE_EXECUTION
@@ -23,25 +25,14 @@ def handler(exc):
windows.winproxy.AddVectoredExceptionHandler(0, handler)
target_page = windows.current_process.virtual_alloc(0x1000)
print("Protected page is at {0}".format(hex(target_page)))
print("Protected page is at <{0}>".format(hex(target_page)))
print("Setting page protection to <PAGE_NOACCESS>")
windows.winproxy.VirtualProtect(target_page, 0x1000, windef.PAGE_NOACCESS)
print("")
v = ctypes.c_uint.from_address(target_page).value
print("POINT1")
print("Value 1 read")
print("")
v = ctypes.c_uint.from_address(target_page + 0x10).value
print("POINT2")
# (cmd) python.exe samples\veh_segv.py
#Protected page is at 0x3f0000
#POUET
#Instr at 0x1d1ab5f4 accessed to addr 0x3f0000
#POUET
#HAHAH EXCEPTION_SINGLE_STEP(0x80000004L)
#POINT1
#POUET
#Instr at 0x1d1ab5f4 accessed to addr 0x3f0010
#POUET
#HAHAH EXCEPTION_SINGLE_STEP(0x80000004L)
#POINT2
print("Value 2 read")
+2 -57
View File
@@ -32,7 +32,7 @@ class Debugger(object):
def __init__(self, target, already_debuggable=False):
"""``target`` must be a WinProcess.
``already_debuggable`` must be set to ``True`` if process is already expecting a debugger (created with DEBUG_PROCESS)"""
``already_debuggable`` must be set to ``True`` if process is already expecting a debugger (created with ``DEBUG_PROCESS``)"""
self._init_dispatch_handlers()
self.target = target
self.is_target_launched = False
@@ -45,7 +45,6 @@ class Debugger(object):
# List of breakpoints
self.breakpoints = {}
self._pending_breakpoints = {} #Breakpoints to put in new process / threads
self._pending_address = {} # Breakpoints that address have not been resolved yet
# Values rewritten by "\xcc"
self._memory_save = defaultdict(dict)
# Dict of {tid : {drx taken : BP}}
@@ -55,12 +54,6 @@ class Debugger(object):
self._module_by_process = {}
#TODO: remove this: THIS IS A TEST
self._breakpoints_new_targets = {}
self._breakpoint_resolvable_address = {}
self._pending_breakpoints_new = {}
self._pending_breakpoints_new = defaultdict(list)
@@ -103,7 +96,6 @@ class Debugger(object):
return x
def _resolve(self, addr, target):
print("Resolving <{0}> for {1}".format(addr, self.current_process))
if not isinstance(addr, basestring):
return addr
dll, api = addr.split("!")
@@ -397,58 +389,11 @@ class Debugger(object):
if not self.processes:
break
#def add_bp(self, bp, addr=None, type=None, target=None):
# """Add a breakpoint, bp can be:
#
# * a :class:`Breakpoint` (addr and type must be None)
# * any callable (addr and type must NOT be None)
#
# If the ``bp`` type is ``STANDARD_BP``, target can be None (all targets) or a process.
#
# If the ``bp`` type is ``HARDWARE_EXEC_BP``, target can be None (all targets), a process or a thread.
# """
# if getattr(bp, "addr", None) is None:
# if addr is None or type is None:
# raise ValueError("SUCK YOUR NONE")
# bp = ProxyBreakpoint(bp, addr, type)
# else:
# if addr is not None or type is not None:
# raise ValueError("Given <addr|type> by parameters but BP object have them")
# del addr
# del type
# if target is None:
# # Raise on multiple pending at same addr ?
# # We will add the pending breakpoint to other new processes
# if bp.addr in self._pending_breakpoints:
# raise ValueError("Pending breakpoint already at {0}".format(hex(bp.addr)))
# self._pending_breakpoints[bp.addr] = (bp, target)
# targets = self.processes.values()
# if targets is None:
# return
# else:
# targets = [target]
# if bp.addr in self.breakpoints:
# raise ValueError("Breakpoint already at {0}".format(hex(bp.addr)))
#
# #self.breakpoints[bp.addr] = bp
#
# if isinstance(bp.addr, basestring):
# dll, api = bp.addr.split("!")
# dll = dll.lower()
# if dll not in self._pending_address: #TODO: default dict
# self._pending_address[dll] = []
# self._pending_address[dll].append((api, bp))
#
# _setup_method = getattr(self, "_setup_breakpoint_" + bp.type)
# _setup_method(bp, targets)
# return True
def add_bp(self, bp, addr=None, type=None, target=None):
"""Add a breakpoint, bp can be:
* a :class:`Breakpoint` (addr and type must be None)
* any callable (addr and type must NOT be None)
* any callable (addr and type must NOT be None) (NON-TESTED)
If the ``bp`` type is ``STANDARD_BP``, target can be None (all targets) or a process.