Add/Update some doc

This commit is contained in:
Clement Rouault
2016-07-27 18:20:36 +02:00
parent bc4952d513
commit fe4d41db47
19 changed files with 186 additions and 85 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ Since 0.2:
* WinProcess.execute_python does not regenerate/reinject the python_exec_shellcode for each execution
* generate.py cleaned with class and stuff / usable for extern project (cc lkd)
* Added COMImplementation to com interface
* fix x86.assemble + add x64.assemble | fix some enconding problem in x64
* fix x86.assemble + add x64.assemble | fix some encoding problem in x64
* Add test_code.py sample
* Remove OptionExport from winproxy
* MemoryBP + single_step for windows.debug.Debugger
+2 -2
View File
@@ -55,7 +55,7 @@ True
# execute_python raise if process died
Traceback (most recent call last):
...
ValueError: Unknown exit code 0xc000004bL
WindowsError: <WinProcess "calc.exe" pid 6960 (DEAD) at 0x37391f0> died during execution of python command
>>> calc
<WinProcess "calc.exe" pid 6960 (DEAD) at 0x37391f0>
>>> calc.exit_code
@@ -238,7 +238,7 @@ func = windows.native_exec.create_function(code, [PVOID])
print("Code addr = 0x{0:x}".format(func.code_addr))
# Create a thread that will infinite loop
t = windows.current_process.create_thread(func.code_addr, 0)
# Add a breakpoint on the infitine loop
# Add a breakpoint on the infinite loop
d.add_bp(RewriteBreakpoint(func.code_addr))
t.wait()
print("Done!")
-12
View File
@@ -8,32 +8,20 @@ TODO:
- Verif multiple pending at same place
- Test !! (bp, BP_HX, bp on only on process, bp_hx on only one thread..)
- test breakpoint with specific target
- Add test for debugger with breakpoint that add another breakpoint on trigger
- Handle MemBP of multiple types of the same page..
- remotectypes
- pretty sur I can get rid of PointerToStruct64/PointerToStruct32
- Some test/doc on windows.system.handles
- registry
- test !
- processes
- TEST / DOC of Process.context_syswow
- Injection
- death of process in execute_python raise a WindowsError with explicit message (change sample in readme)
Documentation
* verif samples
* COMImplementation (example in LKD)
* MemoryBP + single_step() in Debugger
FIXME:
- setup.py build seems to raise an error
- Push("[ECX]") in simple_x64 as a "H" rex and i think it should not..
RESSOURCE
+18 -1
View File
@@ -13,8 +13,13 @@
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.
All Memory-breakpoint are disabled when callind a public callback or a breakpoint ``trigger()`` function.
This means that those methods see the original ``current_process`` memory access rights.
.. autoclass:: Debugger
:members:
:member-order: bysource
.. automethod:: __init__
@@ -64,4 +69,16 @@ When a breakpoint is hit, its ``trigger`` function is called with the debugger a
.. autoclass:: HXBreakpoint
:members:
:inherited-members:
:inherited-members:
.. autoclass:: MemoryBreakpoint
:members:
:inherited-members:
:special-members: __init__
.. note::
MemoryBreakpoint are triggered based on the fault address only (as I don't know a way to get the size of the read/write causing the fault without embeding a disassembler).
This means that a MEMBP at address ``X`` won't be triggered by a write of size 4 at address ``X - 1`` (it's sad I know :( )
+10
View File
@@ -0,0 +1,10 @@
Handle -- Processes handles
============================
.. note::
See sample :ref:`sample_system`
.. module:: windows.winobject.handle
.. autoclass:: Handle
+2 -5
View File
@@ -68,7 +68,7 @@ To be able to perform those operation we must be able to execute code in the ``6
.. note::
See `Knockin on Heavens Gate Dynamic Processor Mode Switching <heaven_gate>`_
See `Knockin on Heavens Gate Dynamic Processor Mode Switching <http://rce.co/knockin-on-heavens-gate-dynamic-processor-mode-switching/>`_
For that we need to jump to the 64bits segment of our process, execute some code then return.
@@ -122,7 +122,4 @@ Existing function are:
.. function:: NtSetContextThread_32_to_64
.. function:: LdrLoadDll_32_to_64
.. _heaven_gate: http://rce.co/knockin-on-heavens-gate-dynamic-processor-mode-switching/
.. function:: LdrLoadDll_32_to_64
+42 -20
View File
@@ -11,16 +11,15 @@ Samples of code
Output::
(cmd λ) python32.exe current_process.py
current process is <windows.winobject.CurrentProcess object at 0x026CD190>
current process is <windows.winobject.process.CurrentProcess object at 0x030A2590>
current process is a <32> bits process
current process is a SysWow64 process ? <True>
current process pid <7432> and ppid <5412>
Here are the current process threads: <[<WinThread 5264 owner "python.exe" at 0x28563f0>]>
current process pid <8264> and ppid <4100>
Here are the current process threads: <[<WinThread 13540 owner "python.exe" at 0x32d3210>]>
Let's execute some native code ! (0x41 + 1)
Waiting for execution to finish !
Native code returned <0x42L>
Native code returned <0x42>
Allocating memory in current process
Allocated memory is at <0x3f0000>
Allocated memory is at <0xd60000>
Writing 'SOME STUFF' in allocation memory
Reading memory : <'SOME STUFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'>
@@ -118,8 +117,8 @@ Output::
product_type = VER_NT_WORKSTATION(0x1L)
version_name = Windows 8.1
There is 95 processes
There is 1021 threads
There is 117 processes
There is 1246 threads
Dumping first logical drive:
<LogicalDrive "C:\" (DRIVE_FIXED)>
@@ -139,8 +138,16 @@ Output::
name = Appinfo
description = Application Information
status = ServiceStatus(type=SERVICE_WIN32_SHARE_PROCESS(0x20L), state=SERVICE_RUNNING(0x4L), control_accepted=129L, flags=0L)
process = <WinProcess "svchost.exe" pid 944 at 0x29d5290>
process = <WinProcess "svchost.exe" pid 988 at 0x2e64750>
Enumerating handles:
There are 40664 handles:
First handle is: <Handle value=<0x4> in process pid=4>
Enumerating handles of the current process:
There are 255 handles for this process
Looking for a File handle:
Handle is <Handle value=<0x4> in process pid=14340>
Name is <\Device\ConDrv>
.. _sample_iat_hook:
@@ -332,11 +339,11 @@ Debugging
:class:`Debugger`
'''''''''''''''''
.. literalinclude:: ..\..\samples\debugger.py
.. literalinclude:: ..\..\samples\debugger_print_LdrLoaddll.py
Ouput::
(cmd λ) python.exe .\samples\debugger.py
(cmd λ) python.exe .\samples\debugger_print_LdrLoaddll.py
Loading <KERNEL32.DLL>
Got exception EXCEPTION_BREAKPOINT(0x80000003L) at 0x77a73bad
Loading <C:\Windows\system32\IMM32.DLL>
@@ -355,6 +362,23 @@ Ouput::
Ask to load <ole32.dll>: exiting process
.. literalinclude:: ..\..\samples\debugger_membp_singlestep.py
Ouput::
(cmd λ) python.exe .\samples\debugger_membp_singlestep.py
Got exception EXCEPTION_BREAKPOINT(0x80000003L) at 0x77ae3c7d
Instruction at <0x8d0006> wrote at <0x8e0000>
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d000c
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d0011
Instruction at <0x8d0011> wrote at <0x8e0004>
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d0017
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d001c
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d0022
Got single_step EXCEPTION_SINGLE_STEP(0x80000004L) at 0x8d0023
No more single step: exiting
.. _sample_local_debugger:
:class:`LocalDebugger`
@@ -368,15 +392,13 @@ In current process
Ouput::
(cmd λ) python.exe .\samples\local_debugger.py
Your main thread is 3864
Code addr = 0x46000b
GOT AN HXBP <3 at 0x46000b
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0x46000c
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0x46000d
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0x46000e
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0x46000f
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0x460010
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0x460011
Code addr = 0xcf0002
GOT AN HXBP at 0xcf0002
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0xcf0003
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0xcf0004
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0xcf0005
EXCEPTION !!!! Got a EXCEPTION_SINGLE_STEP(0x80000004L) at 0x770d7c04
Done!
In remote process
+2 -1
View File
@@ -15,4 +15,5 @@ This sections describes them by group of relation.
network.rst
service.rst
volume.rst
wmi.rst
wmi.rst
handle.rst
+1
View File
@@ -137,6 +137,7 @@ Transparent proxies:
* Wow64RevertWow64FsRedirection(OldValue)
* lstrcmpA(lpString1, lpString2)
* lstrcmpW(lpString1, lpString2)
Functions:
* AddVectoredContinueHandler::
+2 -4
View File
@@ -27,13 +27,11 @@ else:
code += x64.Mov("RAX", 0x41)
code += x64.Inc("RAX")
code += x64.Ret()
native_code = code.get_code()
v = windows.current_process.execute(native_code)
print("Waiting for execution to finish !")
v.wait()
print("Native code returned <{0}>".format(hex(v.exit_code)))
print("Native code returned <{0}>".format(hex(v)))
print("Allocating memory in current process")
addr = cp.virtual_alloc(0x1000) # Default alloc is RWX (so secure !)
+5 -6
View File
@@ -28,20 +28,19 @@ class MyDebugger(windows.debug.Debugger):
self.single_step_counter -= 1
if self.single_step_counter > 0:
return self.single_step()
else:
print("No more single step: exiting")
self.current_process.exit()
class SingleStepOnWrite(windows.debug.MemoryBreakpoint):
DEFAULT_PROTECT = PAGE_READONLY
"""Check that BP/dbg can trigger single step and that instruction follows"""
def trigger(self, dbg, exc):
fault_addr = exc.ExceptionRecord.ExceptionInformation[1]
import pdb;pdb.set_trace()
eip = dbg.current_thread.context.pc
print("Instruction at <{0:#x}> wrote at <{1:#x}>".format(eip, fault_addr))
dbg.single_step_counter = 4
#import pdb;pdb.set_trace()
#if fault_addr == self.addr + 4:
# print("Delete self BP")
# dbg.del_bp(self)
return dbg.single_step()
@@ -63,7 +62,7 @@ injected += x86.Nop()
injected += x86.Ret()
calc.write_memory(code, injected.get_code())
d.add_bp(SingleStepOnWrite(data + 1, size=5))
d.add_bp(SingleStepOnWrite(data, size=8, events="W"))
calc.create_thread(code, 0)
d.loop()
+1 -1
View File
@@ -41,6 +41,6 @@ class PrintUnicodeString(windows.debug.Breakpoint):
calc = windows.test.pop_calc_32(dwCreationFlags=DEBUG_PROCESS)
d = MyDebugger(calc)
d.add_bp(PrintUnicodeString("ntdll.dll!LdrLoadDll", argument_position=2))
d.add_bp(PrintUnicodeString("ntdll!LdrLoadDll", argument_position=2))
d.loop()
+15 -1
View File
@@ -39,4 +39,18 @@ print(" " + str(serv))
print((" " * 8) + "name = {0}".format(serv.name))
print((" " * 8) + "description = {0}".format(serv.description))
print((" " * 8) + "status = {0}".format(serv.status))
print((" " * 8) + "process = {0}".format(repr(serv.process)))
print((" " * 8) + "process = {0}".format(repr(serv.process)))
print("")
print("Enumerating handles:")
handles = system.handles
print(" There are {0} handles:".format(len(handles)))
print(" First handle is: " + str(handles[0]))
print(" Enumerating handles of the current process:")
cp_handles = [h for h in system.handles if h.dwProcessId == windows.current_process.pid]
print(" There are {0} handles for this process".format(len(cp_handles)))
print(" Looking for a File handle:")
file_h = [h for h in cp_handles if h.type == "File"][0]
print(" Handle is {0}".format(file_h))
print(" Name is <{0}>".format(file_h.name))
+4
View File
@@ -42,10 +42,14 @@ class HXBreakpoint(Breakpoint):
return isinstance(target, WinThread)
class MemoryBreakpoint(Breakpoint):
"""A memory breakpoint (type == ``MEMORY_BREAKPOINT``)"""
type = MEMORY_BREAKPOINT
DEFAULT_EVENTS = "RWX"
DEFAULT_SIZE = 0x1000
def __init__(self, addr, size=None, events=None):
"""``size``: the size of the memory breakpoint.
``events``: a string representing the events that interest the BP (any of "RWX")"""
super(MemoryBreakpoint, self).__init__(addr)
self.size = size if size is not None else self.DEFAULT_SIZE
events = events if events is not None else self.DEFAULT_EVENTS
+41 -22
View File
@@ -35,11 +35,14 @@ WatchedPage = namedtuple('WatchedPage', ["original_prot", "bps"])
class Debugger(object):
"""A debugger based on standard Win32 API. Handle standard (int3) and Hardware-Exec Breakpoints"""
def __init__(self, target):
"""``target`` must be a WinProcess.
"""A debugger based on standard Win32 API. Handle :
``already_debuggable`` must be set to ``True`` if process is already expecting a debugger (created with ``DEBUG_PROCESS``)"""
* Standard BP (int3)
* Hardware-Exec BP (DrX)
* Memory BP (virtual_protect)"""
def __init__(self, target):
"""``target`` must be a debuggable :class:`WinProcess`."""
self._init_dispatch_handlers()
self.target = target
self.is_target_launched = False
@@ -73,11 +76,17 @@ class Debugger(object):
@classmethod
def attach(cls, target):
"""attach to ``target`` (must be a :class:`WinProcess`)
:rtype: :class:`Debugger`"""
winproxy.DebugActiveProcess(target.pid)
return cls(target)
@classmethod
def debug(cls, path, args=None, dwCreationFlags=0, show_windows=False):
"""Create a process and debug it.
:rtype: :class:`Debugger`"""
dwCreationFlags |= DEBUG_PROCESS
c = windows.utils.create_process(path, args=args, dwCreationFlags=dwCreationFlags, show_windows=show_windows)
return cls(c)
@@ -235,7 +244,7 @@ class Debugger(object):
pass
return True
## MemBP helpers
## MemBP internal helpers
def _compute_page_access_for_event(self, target, events):
if "R" in events:
return PAGE_NOACCESS
@@ -636,7 +645,7 @@ class Debugger(object):
with self.DisabledMemoryBreakpoint():
return self.on_rip(rip_info)
# Public API
## Public API
def loop(self):
"""Debugging loop: handle event / dispatch to breakpoint. Returns when all targets are dead"""
for debug_event in self._debug_event_generator():
@@ -650,12 +659,12 @@ class Debugger(object):
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) (NON-TESTED)
* a :class:`Breakpoint` (addr and type must 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.
If the ``bp`` type is ``STANDARD_BP`` or ``MEMORY_BREAKPOINT``, 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 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:
@@ -680,6 +689,7 @@ class Debugger(object):
return self._setup_breakpoint(bp, target)
def del_bp(self, bp, targets=None):
"""Delete a breakpoint, if targets is ``None``: delete it from all targets"""
#if targets is not None:
# raise NotImplementedError("TODO: DEL BP with targets")
original_target = targets
@@ -698,6 +708,7 @@ class Debugger(object):
return self.remove_pending_breakpoint(bp, original_target)
def single_step(self):
"""Make the ``current_thread`` ``single_step``. ``Debugger.on_single_step`` will be called after that"""
t = self.current_thread
ctx = t.context
ctx.EEFlags.TF = 1
@@ -705,9 +716,11 @@ class Debugger(object):
## Memory Breakpoint helper
def get_memory_breakpoint_at(self, addr, process=None):
"""Get the memory breakpoint the handle `addr`
"""Get the memory breakpoint that handle ``addr``
Return values are:
* ``False`` if the page as no memory breakpoint (real fault)
* ``False`` if the page has no memory breakpoint (real fault)
* ``None`` if the page as memBP but None handle ``addr``
* ``bp`` the MemBP that handle ``addr``
"""
@@ -724,6 +737,10 @@ class Debugger(object):
return None
def disable_all_memory_breakpoints(self, target=None):
"""Restore all pages to their original access rights.
If target is ``None``, use ``current_process``
:return: a mapping of all disabled breakpoints that must be passed to :func:`restore_all_memory_breakpoints`"""
if target is None:
target = self.current_process
res = {}
@@ -734,32 +751,34 @@ class Debugger(object):
res[page_addr] = page_protection.value
return res
def restore_all_memory_breakpoints(self, data, target=None):
if target is None:
target = self.current_process
for page_addr, protection in data.items():
target.virtual_protect(page_addr, PAGE_SIZE, protection, None)
return
#TODO: better stuff :DD
# default implem ? why would I reput the removed BP..
def restore_all_memory_breakpoints_verif_remove(self, data, target=None):
def restore_all_memory_breakpoints(self, data, target=None):
"""Re-setup all memory breakpoints, affecting pages access rights.
If target is ``None``, use ``current_process``
``data`` is the result of the corresponding call to :func:`disable_all_memory_breakpoints`"""
if target is None:
target = self.current_process
for page_addr, protection in data.items():
# Prevent restoring deleted breakpoints
if page_addr in self._watched_pages[target.pid]:
target.virtual_protect(page_addr, PAGE_SIZE, protection, None)
return
@contextmanager
def DisabledMemoryBreakpoint(self, target=None):
"""A context-manager that disable all memory breakpoints and restore them on exit"""
data = self.disable_all_memory_breakpoints(target)
try:
yield
finally:
self.restore_all_memory_breakpoints_verif_remove(data, target)
self.restore_all_memory_breakpoints(data, target)
def get_exception_bitness(self, exc):
"""Return the bitness in which the exception occured.
Useful when debugingg a 32b process from a 64bits one
:return: :class:`int` -- 32 or 64"""
if windows.current_process.bitness == 32:
return 32
if exc.ExceptionRecord.ExceptionCode in [STATUS_WX86_BREAKPOINT, STATUS_WX86_SINGLE_STEP]:
+8 -1
View File
@@ -11,7 +11,13 @@ from .breakpoints import *
class LocalDebugger(object):
"""A debugger interface around :func:`AddVectoredExceptionHandler`"""
"""A debugger interface around :func:`AddVectoredExceptionHandler`.
Handle:
* Standard BP (int3)
* Hardware-Exec BP (DrX)"""
def __init__(self):
self.breakpoints = {}
self._memory_save = {}
@@ -96,6 +102,7 @@ class LocalDebugger(object):
return windef.EXCEPTION_CONTINUE_EXECUTION
def del_bp(self, bp):
"""Delete a breakpoint"""
if bp.type == STANDARD_BP:
with windows.utils.VirtualProtected(bp.addr, 1, PAGE_EXECUTE_READWRITE):
windows.current_process.write_memory(bp.addr, self._memory_save[bp.addr])
+6 -3
View File
@@ -42,15 +42,17 @@ class SyswowTestCase(unittest.TestCase):
import windows
import windows.native_exec.simple_x64 as x64
windows.utils.create_console()
windows.current_process.write_qword({0}, 0x8877665544332211)
x64_code = x64.assemble("mov r11, 0x1122334455667788; label :loop; jmp :loop; nop; nop; ret")
res = windows.syswow64.execute_64bits_code_from_syswow(x64_code)
print("res = {{0}}".format(hex(res)))
windows.current_process.write_qword({0}, res)
import time
time.sleep(10)
""".format(addr)
t = calc.execute_python_unsafe(textwrap.dedent(remote_python_code))
# Wait for python execution
while calc.read_qword(addr) != 0x8877665544332211:
pass
ctx = t.context_syswow
# Check the get context
self.assertEqual(ctx.R11, 0x1122334455667788)
@@ -63,6 +65,7 @@ class SyswowTestCase(unittest.TestCase):
ctx.Rip += 2
t.set_syswow_context(ctx)
t.resume()
time.sleep(0.1)
t.wait()
self.assertEqual(RETURN_VALUE, calc.read_qword(addr))
+13 -1
View File
@@ -11,17 +11,27 @@ class EPUBLIC_OBJECT_TYPE_INFORMATION(ctypes.Structure):
class Handle(SYSTEM_HANDLE):
"""A handle of the system"""
@windows.utils.fixedpropety
def process(self):
"""The process possessing the handle
:type: :class:`WinProcess <windows.winobject.process.WinProcess>`"""
"TODO: something smart ? :D"
return [p for p in windows.system.processes if p.pid == self.dwProcessId][0]
@windows.utils.fixedpropety
def name(self):
"""The name of the handle
:type: :class:`str`"""
return self._get_object_name()
@windows.utils.fixedpropety
def type(self):
"""The type of the handle
:type: :class:`str`"""
return self._get_object_type()
def _get_object_name(self):
@@ -47,6 +57,9 @@ class Handle(SYSTEM_HANDLE):
@windows.utils.fixedpropety
def local_handle(self):
"""A local copy of the handle, acquired with ``DuplicateHandle``
:type: :class:`int`"""
if self.dwProcessId == windows.current_process.pid:
return self.wValue
res = HANDLE()
@@ -63,7 +76,6 @@ class Handle(SYSTEM_HANDLE):
return winproxy.CloseHandle(self._local_handle)
def enumerate_handles():
size_needed = ULONG()
size = 0x1000
+13 -4
View File
@@ -112,6 +112,10 @@ class WinThread(THREADENTRY32, AutoHandle):
@property
def context_syswow(self):
"""The 64 bits context of a syswow thread.
:type: :class:`windows.exception.ECONTEXT64`
"""
if not self.owner.is_wow_64:
raise ValueError("Not a syswow process")
x = exception.ECONTEXT64.new_aligned()
@@ -124,7 +128,7 @@ class WinThread(THREADENTRY32, AutoHandle):
def set_context(self, context):
"""Set the thread context to ``context``"""
"""Set the thread's context to ``context``"""
if self.owner.bitness == windows.current_process.bitness:
return winproxy.SetThreadContext(self.handle, context)
if windows.current_process.bitness == 64 and self.owner.bitness == 32:
@@ -133,6 +137,7 @@ class WinThread(THREADENTRY32, AutoHandle):
def set_syswow_context(self, context):
"""Set a syswow thread's 64 context to ``context``"""
if not self.owner.is_wow_64:
raise ValueError("Not a syswow process")
if windows.current_process.bitness == 64:
@@ -358,6 +363,7 @@ class Process(AutoHandle):
self.virtual_protect(addr, size, old_protect.value, old_protect)
def virtual_protect(self, addr, size, protect, old_protect):
"""Change the access right of one or more page of the process"""
if windows.current_process.bitness == 32 and self.bitness == 64:
#addr = (addr >> 12) << 12
#addr = ULONG64(addr)
@@ -570,9 +576,9 @@ class Process(AutoHandle):
@property
def time_info(self):
"""The time information of the process (creation, kernel/user time, exit time
"""The time information of the process (creation, kernel/user time, exit time)
:type: :class:`TimeInfo"""
:type: :class:`TimeInfo`"""
CreationTime = FILETIME()
ExitTime = FILETIME()
KernelTime = FILETIME()
@@ -734,6 +740,9 @@ class CurrentProcess(Process):
return WinThread._from_handle(handle)
def execute(self, code, parameter=0):
"""Execute native code ``code`` in the current thread.
:rtype: :class:`int` the return value of the native code"""
f = windows.native_exec.create_function(code, [PVOID, PVOID])
return f(parameter)
@@ -916,7 +925,7 @@ class WinProcess(Process):
def execute_python_unsafe(self, pycode):
"""Execute Python code into the remote process.
Unsafe means that no information are returned about the execution of the thread
:rtype: :rtype: :class:`WinThread` or :class:`DeadThread` : The thread executing the python code
"""
return injection.execute_python_code(self, pycode)