mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
More doc + regitry PyPhKey.get()
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
# PythonForWindows
|
||||
|
||||
PythonForWindows is a base of code aimed to make interaction with Windows (on X86/X64) easier (with both 32 and 64 bits Python).
|
||||
It's goal is to offer abstractions around some of the OS features in a (I hope) pythonic way.
|
||||
PythonForWindows is a base of code aimed to make interaction with `Windows` (on X86/X64) easier (with both 32 and 64 bits Python).
|
||||
Its goal is to offer abstractions around some of the OS features in a (I hope) pythonic way.
|
||||
It also tries to make the barrier between python and native execution thiner in both ways.
|
||||
There is no external dependencies but it relies heavily on the ctypes modules.
|
||||
There is no external dependencies but it relies heavily on the `ctypes` modules.
|
||||
|
||||
|
||||
Some of this code is clean (IMHO) and some parts are just a wreck that work for now.
|
||||
Let say that the codebase evolves with my needs and my curiosity.
|
||||
Some of this code is clean (IMHO) and some parts are just a wreck that works for now.
|
||||
Let's say that the codebase evolves with my needs and my curiosity.
|
||||
|
||||
You can find some examples of code in the `samples/` directory.
|
||||
|
||||
@@ -15,48 +15,43 @@ You can find some examples of code in the `samples/` directory.
|
||||
|
||||
### Processes / Threads
|
||||
|
||||
PythonForWindows offer a object oriented around processes of the system and allow you to:
|
||||
PythonForWindows offers objects around processes and allows you to:
|
||||
- Retrieve basic process informations (pid, name, ppid, bitness, ...)
|
||||
- Perform basic interprocess operation (alloc, create thread, read/write memory)
|
||||
- Perform basic interprocess operation (allocation, create thread, read/write memory)
|
||||
- Explore the PEB (Process Environment Block)
|
||||
- Execute native and python code in the context of the process.
|
||||
|
||||
I try by best to make those features available for every cross-bitness processes (32 <-> 64 in both ways).
|
||||
This involve relying on non-documented Windows function/behaviour and also injecting code in the 64bits world of a Syswow64 process.
|
||||
- Execute `native` and `Python` code in the context of a process.
|
||||
|
||||
I try by best to make those features available for every cross-bitness processes (`32 <-> 64` in both ways).
|
||||
This involve relying on non-documented `Windows` function/behaviour and also injecting code in the 64bits world of a `Syswow64` process.
|
||||
All those operations are also available for the `current_process`.
|
||||
|
||||
You can also make some operation of threads (suspend/resume/wait/get( or set) context/ kill)
|
||||
You can also make some operation on threads (suspend/resume/wait/get(or set) context/ kill)
|
||||
|
||||
|
||||
### IAT Hook
|
||||
|
||||
This codebase is born from my need to have IAT hooks implemented in Python.
|
||||
So the features is present (see `samples/`)
|
||||
So the features is present (see online documentation)
|
||||
|
||||
|
||||
### Winproxy
|
||||
|
||||
A pythonic wrapper around some Windows functions. Arguments name and order are the same,
|
||||
A wrapper around some Windows functions. Arguments name and order are the same,
|
||||
but some have default values and the functions raise exception on call error (I don't like 'if' around all my call).
|
||||
|
||||
|
||||
### Native execution
|
||||
|
||||
To make the barrier beetwen native and python code,
|
||||
PythonForWindows allows you to create native function callable from Python (thanks ctypes) and also embded
|
||||
To make the barrier between `native` and `Python` code,
|
||||
PythonForWindows allows you to create native function callable from Python (thanks `ctypes`) and also embed
|
||||
a simple x86/x64 assembler.
|
||||
|
||||
|
||||
### COM on Python
|
||||
|
||||
Some code to call a COM interface from Python or create a COM object implemented in Python.
|
||||
|
||||
|
||||
### Other stuff
|
||||
## Other stuff
|
||||
|
||||
Some code are just exploration and need improvement like:
|
||||
- Wintrust
|
||||
- WMI
|
||||
- Registry access
|
||||
- Exception
|
||||
- COM
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
TODO:
|
||||
- Documentation
|
||||
- ProcessMemory object ? (metasm like)
|
||||
- Extend Registry feature (write + read 1 key)
|
||||
- Extend Registry feature (write)
|
||||
|
||||
FIXME:
|
||||
- WMI
|
||||
|
||||
@@ -538,4 +538,21 @@
|
||||
#define DEBUG_EVENT_CHANGE_SYMBOL_STATE 0x00001000
|
||||
|
||||
#define WOW64_MAXIMUM_SUPPORTED_EXTENSION 512
|
||||
#define WOW64_SIZE_OF_80387_REGISTERS 80
|
||||
#define WOW64_SIZE_OF_80387_REGISTERS 80
|
||||
|
||||
|
||||
#define REG_NONE ( 0 )
|
||||
#define REG_SZ ( 1 )
|
||||
#define REG_EXPAND_SZ ( 2 )
|
||||
|
||||
#define REG_BINARY ( 3 )
|
||||
#define REG_DWORD ( 4 )
|
||||
#define REG_DWORD_LITTLE_ENDIAN ( 4 )
|
||||
#define REG_DWORD_BIG_ENDIAN ( 5 )
|
||||
#define REG_LINK ( 6 )
|
||||
#define REG_MULTI_SZ ( 7 )
|
||||
#define REG_RESOURCE_LIST ( 8 )
|
||||
#define REG_FULL_RESOURCE_DESCRIPTOR ( 9 )
|
||||
#define REG_RESOURCE_REQUIREMENTS_LIST ( 10 )
|
||||
#define REG_QWORD ( 11 )
|
||||
#define REG_QWORD_LITTLE_ENDIAN ( 11 )
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
COM - Component Object Model
|
||||
""""""""""""""""""""""""""""
|
||||
|
||||
A module to call ``COM`` interfaces from `Python` or
|
||||
``COM`` vtable in python.
|
||||
|
||||
This code is only used in :mod:`windows.wmi`.
|
||||
The ability to create ``COM`` vtable is used in LKD
|
||||
|
||||
.. note::
|
||||
|
||||
TODO: link to LKD code
|
||||
+1
-1
@@ -43,7 +43,7 @@ extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
]
|
||||
|
||||
autodoc_default_flags = ['show-inheritance', 'inherited-members']
|
||||
autodoc_default_flags = ['inherited-members']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
@@ -5,8 +5,8 @@ IAT hooking
|
||||
|
||||
See sample :ref:`sample_iat_hook`
|
||||
|
||||
Put a IAT hook
|
||||
''''''''''''''
|
||||
Putting an IAT hook
|
||||
'''''''''''''''''''
|
||||
|
||||
To setup your IAT hook you just need:
|
||||
|
||||
@@ -71,7 +71,7 @@ A hook callback must also embed some :ref:`Type Information <type_information>`
|
||||
Callback type information
|
||||
--------------------------
|
||||
|
||||
In order make the magic behind Python Hook Callback, :mod:`ctypes` need to have type information about the API parameters.
|
||||
In order make the magic behind hook callback, :mod:`ctypes` needs to have type information about the API parameters.
|
||||
|
||||
There is (again) two ways to give those informations to your hook callback. Both techniques use a decorator to setup type information to the callback.
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ Contents:
|
||||
:numbered:
|
||||
|
||||
windows.rst
|
||||
various.rst
|
||||
native_exec.rst
|
||||
winproxy.rst
|
||||
utils.rst
|
||||
native_exec.rst
|
||||
various.rst
|
||||
iat_hook.rst
|
||||
wip.rst
|
||||
internals.rst
|
||||
@@ -28,4 +28,5 @@ Indices and tables
|
||||
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
* :ref:`genindex`
|
||||
|
||||
|
||||
@@ -17,13 +17,13 @@ So I made a wrapper around :mod:`ctypes` that is able to do two things:
|
||||
|
||||
This is done by replacing the ``c_void_p``/``c_char_p`` by ``DWORD`` or
|
||||
``QWORD`` and rewriting a wrapper around the :mod:`ctypes` ``POINTER`` and other stuff.
|
||||
I might not works for every structure by i didn't have any problem for now.
|
||||
It might not works for every structure by i didn't have any problem for now.
|
||||
|
||||
- Read the memory in another process
|
||||
|
||||
For this one I rewrote a class that use the standard :mod:`ctypes` structure
|
||||
offset-size calcultation, extract those information when asked for a field and read it from the target process.
|
||||
We just need to take care of special cases: ``POINTER`` / ``ARRAY`` / ``STRING``
|
||||
offset-size calculation, extracts those information when asked for a field and read it from the target process.
|
||||
We just need to take care of special cases: ``POINTER`` / ``ARRAY`` / ``STRING`` / ..
|
||||
|
||||
We also need to be carreful about the inheritance, we need to inherit from "hidden"
|
||||
:class:`ctypes` classes to keep the magic working.
|
||||
@@ -85,7 +85,7 @@ With these information we are able to know
|
||||
* The name of the API
|
||||
* The number of arguments
|
||||
|
||||
With that I generate the correct x64 stub (using :mod:`windows.native_exec.simple_x64`). With the function:
|
||||
Then I generate the correct x64 stub (using :mod:`windows.native_exec.simple_x64`) with the function:
|
||||
|
||||
.. function:: generate_syswow64_call
|
||||
|
||||
@@ -100,10 +100,10 @@ For now I allocate a buffer where a python wrapper copy the parameters and the x
|
||||
The final result is a ``Python`` function like the one in :mod:`windows.winproxy`
|
||||
|
||||
* It copies the arguments in the buffer
|
||||
* Jump on the 32->64 stub
|
||||
* Jumps on the 32->64 stub
|
||||
* X64 bits code retrieves the arguments in the buffer and setup the registers and the stack for the call
|
||||
* Call the API
|
||||
* Return to 32bits mode.
|
||||
* Calls the API
|
||||
* Returns to 32bits mode.
|
||||
|
||||
.. class:: Syswow64ApiProxy
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
************************************************
|
||||
|
||||
|
||||
The :mod:`windows.native_exec` allows to create `Python` functions calling native code.
|
||||
it also provide a simple assembler for x86 and x64.
|
||||
:mod:`windows.native_exec` allows to create `Python` functions calling native code.
|
||||
it also provides a simple assembler for x86 and x64.
|
||||
|
||||
The :mod:`windows.native_exec` provides those functions:
|
||||
:mod:`windows.native_exec` provides those functions:
|
||||
|
||||
.. autofunction:: windows.native_exec.create_function
|
||||
|
||||
@@ -47,7 +47,7 @@ Demo::
|
||||
The :mod:`windows.native_exec.simple_x86` module allows to create simple x86 code.
|
||||
|
||||
Its features are:
|
||||
* Forward - Backward jump (using label)
|
||||
* Forward - Backward jump (using labels)
|
||||
* Non-string interface for conditional/context dependent generation
|
||||
|
||||
|
||||
@@ -59,12 +59,13 @@ The assembler instructions are `Python` object that may accept arguments represe
|
||||
the mnemonic operands.
|
||||
|
||||
These parameters can be of type:
|
||||
* str (register)
|
||||
* int (int)
|
||||
* mem_access (memory access)
|
||||
* :class:`str` (register)
|
||||
* :class:`int` (int)
|
||||
* :class:`mem_access` (memory access)
|
||||
|
||||
.. autoclass:: windows.native_exec.simple_x86.mem_access
|
||||
:members: prefix, base, index, scale, disp
|
||||
:exclude-members: count
|
||||
|
||||
The :class:`mem_access` object can be created:
|
||||
* By hand
|
||||
@@ -72,6 +73,7 @@ The :class:`mem_access` object can be created:
|
||||
* Using :func:`mem`
|
||||
|
||||
.. autofunction:: windows.native_exec.simple_x86.create_displacement
|
||||
.. autofunction:: windows.native_exec.simple_x86.deref
|
||||
.. autofunction:: windows.native_exec.simple_x86.mem
|
||||
|
||||
Instruction assembling::
|
||||
@@ -116,6 +118,7 @@ Another example from a project::
|
||||
INPUT_BUFFER_PORT = x86.mem('[ECX + 4]')
|
||||
INPUT_BUFFER_VALUE = x86.mem('[ECX + 8]')
|
||||
|
||||
out_ioctl = x86.MultipleInstr()
|
||||
out_ioctl += x86.Cmp(IO_STACK_INPUT_BUFFER_LEN, 0xc) # size indicator / port / value
|
||||
out_ioctl += x86.Jnz(":FAIL")
|
||||
out_ioctl += x86.Mov('ECX', IO_STACK_INPUT_BUFFER)
|
||||
@@ -140,6 +143,9 @@ Another example from a project::
|
||||
out_ioctl += x86.Mov('EAX', 0x0C000000D)
|
||||
out_ioctl += x86.Ret()
|
||||
|
||||
out_ioctl.get_code()
|
||||
'\x81~\x08\x0c\x00\x00\x00u&\x8bN\x10\x8bQ\x04\x8bA\x08\x8b\t\x81\xf9\x01\x00\x00\x00u\x03\xee\xeb\r\x81\xf9\x02\x00\x00\x00u\x04f\xef\xeb\x01\xef1\xc0\xc3\xc7\xc0\r\x00\x00\xc0\xc3'
|
||||
|
||||
|
||||
:mod:`windows.native_exec.simple_x64` -- X64 Assembler
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
@@ -8,14 +8,12 @@ Network
|
||||
See sample :ref:`sample_network_exploration`
|
||||
|
||||
|
||||
:class:`Network` class
|
||||
""""""""""""""""""""""
|
||||
|
||||
.. autoclass:: windows.network.Network
|
||||
|
||||
Connection classes
|
||||
""""""""""""""""""
|
||||
Connections
|
||||
"""""""""""
|
||||
|
||||
.. autoclass:: windows.network.TCP4Connection
|
||||
|
||||
|
||||
.. autoclass:: windows.network.TCP6Connection
|
||||
+18
-2
@@ -12,6 +12,7 @@ CurrentProcess
|
||||
|
||||
.. autoclass:: CurrentProcess
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
|
||||
CurrentThread
|
||||
@@ -19,6 +20,7 @@ CurrentThread
|
||||
|
||||
.. autoclass:: CurrentThread
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
|
||||
WinProcess
|
||||
@@ -30,6 +32,7 @@ WinProcess
|
||||
|
||||
.. autoclass:: WinProcess
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
|
||||
|
||||
@@ -38,11 +41,13 @@ WinThread
|
||||
|
||||
.. autoclass:: WinThread
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
|
||||
|
||||
.. autoclass:: DeadThread
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
|
||||
|
||||
@@ -56,17 +61,23 @@ The :class:`PEB` is accessible via ``process.peb`` and is of type :class:`PEB`.
|
||||
|
||||
See sample :ref:`sample_peb_exploration`
|
||||
|
||||
PEB
|
||||
'''
|
||||
|
||||
.. autoclass:: PEB
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: WinUnicodeString
|
||||
|
||||
LoadedModule
|
||||
''''''''''''
|
||||
|
||||
.. autoclass:: LoadedModule
|
||||
|
||||
|
||||
PEFile
|
||||
""""""
|
||||
PEFile - Parsing loaded PE
|
||||
""""""""""""""""""""""""""
|
||||
|
||||
:mod:`windows.pe_parse`
|
||||
'''''''''''''''''''''''
|
||||
@@ -75,8 +86,13 @@ PEFile
|
||||
|
||||
.. autofunction:: windows.pe_parse.GetPEFile
|
||||
|
||||
PEFile
|
||||
^^^^^^
|
||||
|
||||
.. autoclass:: PEFile
|
||||
|
||||
IATEntry
|
||||
^^^^^^^^
|
||||
|
||||
.. autoclass:: IATEntry
|
||||
|
||||
|
||||
+21
-1
@@ -3,8 +3,28 @@ Registry
|
||||
|
||||
.. module:: windows.registry
|
||||
|
||||
.. note::
|
||||
|
||||
See sample :ref:`sample_registry`
|
||||
|
||||
Registry
|
||||
""""""""
|
||||
|
||||
.. autoclass:: Registry
|
||||
:special-members: __getitem__
|
||||
|
||||
.. autoclass:: PyHKey
|
||||
|
||||
PyHKey
|
||||
""""""
|
||||
|
||||
.. autoclass:: PyHKey
|
||||
|
||||
.. function:: __getitem__(name)
|
||||
|
||||
Alias for :func:`open_subkey`
|
||||
|
||||
KeyValue
|
||||
""""""""
|
||||
|
||||
.. autoclass:: KeyValue
|
||||
:exclude-members: count, index
|
||||
+40
-1
@@ -148,4 +148,43 @@ Output::
|
||||
Traceback (most recent call last):
|
||||
File ".\network.py", line 45, in <module>
|
||||
s.send("LAIT")
|
||||
socket.error: [Errno 10054] An existing connection was forcibly closed by the remote host
|
||||
socket.error: [Errno 10054] An existing connection was forcibly closed by the remote host
|
||||
|
||||
|
||||
.. _sample_registry:
|
||||
|
||||
:class:`Registry`
|
||||
"""""""""""""""""
|
||||
|
||||
.. literalinclude:: ..\..\samples\registry.py
|
||||
|
||||
Output::
|
||||
|
||||
(cmd λ) python.exe registry.py
|
||||
Registry is <<windows.registry.Registry object at 0x02941290>>
|
||||
HKEY_CURRENT_USER is <<PyHKey "HKEY_CURRENT_USER">>
|
||||
HKEY_CURRENT_USER subkeys names are:
|
||||
['AppEvents',
|
||||
'AppXBackupContentType',
|
||||
'Console',
|
||||
'Control Panel',
|
||||
'Environment',
|
||||
'EUDC',
|
||||
'Identities',
|
||||
'Keyboard Layout',
|
||||
'Network',
|
||||
'Printers',
|
||||
'Software',
|
||||
'System',
|
||||
'Volatile Environment']
|
||||
Opening 'Software' in HKEY_CURRENT_USER: <PyHKey "HKEY_CURRENT_USER\Software">
|
||||
We can also open it in one access: <PyHKey "HKEY_CURRENT_USER\Sofware">
|
||||
Looking at CurrentVersion
|
||||
Key is <PyHKey "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion">
|
||||
values are:
|
||||
[KeyValue(name='SoftwareType', value=u'System', type=1),
|
||||
KeyValue(name='RegisteredOwner', value=u'hakril', type=1),
|
||||
KeyValue(name='InstallDate', value=0, type=4),
|
||||
...
|
||||
KeyValue(name='PathName', value=u'C:\\Windows', type=1)]
|
||||
registered owner = <KeyValue(name='RegisteredOwner', value=u'hakril', type=1)>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
``windows.utils`` -- Pythonic Windows Utilities
|
||||
``windows.utils`` -- Windows Utilities
|
||||
***********************************************
|
||||
|
||||
.. module:: windows.utils
|
||||
@@ -14,13 +14,13 @@ VirtualProtected
|
||||
|
||||
.. autoclass:: windows.utils.VirtualProtected
|
||||
:no-show-inheritance:
|
||||
|
||||
|
||||
DisableWow64FsRedirection
|
||||
'''''''''''''''''''''''''
|
||||
|
||||
.. autoclass:: windows.utils.DisableWow64FsRedirection
|
||||
:no-show-inheritance:
|
||||
|
||||
|
||||
Helper functions
|
||||
""""""""""""""""
|
||||
|
||||
|
||||
@@ -2,13 +2,14 @@ The :mod:`windows` objects
|
||||
==========================
|
||||
|
||||
Through the :ref:`system <object_system>` object many classes representing various `Windows`
|
||||
part are accessible.
|
||||
parts are accessible.
|
||||
|
||||
This sections describes them by group of relation.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:maxdepth: 3
|
||||
|
||||
process.rst
|
||||
registry.rst
|
||||
network.rst
|
||||
network.rst
|
||||
com.rst
|
||||
@@ -2,7 +2,9 @@ The ``windows`` module
|
||||
**********************
|
||||
|
||||
The ``windows`` module is the module installed by :file:`setup.py` (that does not exists right now).
|
||||
This module export some object representing the current state of the system. It also offers some submodules aimed to help the interface with ``Windows`` and native code exection.
|
||||
|
||||
This module exports some objects representing the current state of the system.
|
||||
It also offers some submodules aimed to help the interfacing with ``Windows`` and native code execution.
|
||||
|
||||
The defaults objects accessible in ``windows`` are:
|
||||
* ``system`` of type :class:`windows.winobject.System`
|
||||
@@ -19,6 +21,8 @@ The submodules that you might use by themself are:
|
||||
The ``system`` object
|
||||
"""""""""""""""""""""
|
||||
|
||||
.. currentmodule:: windows.winobject
|
||||
|
||||
.. autoclass:: windows.winobject.System
|
||||
:no-show-inheritance:
|
||||
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
|
||||
.. module:: windows.winproxy
|
||||
|
||||
The :mod:`windows.winproxy` module tries to be a pythontic wrapper around windows API of various DLL.
|
||||
It also hevily relies on :mod:`ctypes`.
|
||||
:mod:`windows.winproxy` tries to be a pythontic wrapper around windows API of various DLL.
|
||||
It also heavily relies on :mod:`ctypes` and :mod:`windows.generated_def.winfuncs`
|
||||
|
||||
Here are the thing to know about :mod:`windows.winproxy`
|
||||
* All of this is based on :mod:`windows.generated_def.winfunc`
|
||||
Here are the things to know about :mod:`windows.winproxy`
|
||||
* All of this is based on :mod:`windows.generated_def.winfuncs`
|
||||
* DLL is loaded the first time an API of it is called
|
||||
* All parameters can be passed by ordinal or keyword
|
||||
* The call with fail if an argument with default value ``NeededParamater`` have be called without another value.
|
||||
* The call will raise a subclasse of :class:`WindowsError` if it fail.
|
||||
* The call will fail if an argument with default value ``NeededParamater`` have been called without another value.
|
||||
* The call will raise a subclass of :class:`WindowsError` if it fails.
|
||||
* Some functions are 'transparent proxy' it means that all parameters are mandatory
|
||||
|
||||
Example: ``VirtualAlloc``
|
||||
@@ -60,7 +60,7 @@ Calling it
|
||||
TypeError: VirtualAlloc: Missing Mandatory parameter <dwSize>
|
||||
"""
|
||||
|
||||
# Error raise exception
|
||||
# Error raises exception
|
||||
windows.winproxy.VirtualAlloc(dwSize=0xffffffff)
|
||||
"""
|
||||
Traceback (most recent call last):
|
||||
|
||||
+1
-3
@@ -13,13 +13,11 @@ Should it juste be part of :mod:`windows.utils` ?
|
||||
.. autofunction:: windows.wintrust.check_signature
|
||||
|
||||
|
||||
.. module:: windows.wmi
|
||||
|
||||
WMI -- WMI request
|
||||
""""""""""""""""""
|
||||
|
||||
Unstable code: not fully tested, ugly COM initialisation
|
||||
|
||||
|
||||
.. module:: windows.wmi
|
||||
|
||||
.. autoclass:: windows.wmi.WmiRequester
|
||||
+1
-3
@@ -13,7 +13,7 @@ import windows
|
||||
@windows.hooks.RegOpenKeyExACallback
|
||||
def open_reg_hook(hKey, lpSubKey, ulOptions, samDesired, phkResult, real_function):
|
||||
print("<in hook> Hook called | hKey = {0} | lpSubKey = <{1}>".format(hex(hKey), lpSubKey.value))
|
||||
# Out hook can choose to call the real_function or not
|
||||
# Our hook can choose to call the real_function or not
|
||||
if "SECRET" in lpSubKey.value:
|
||||
print("<in hook> Secret key asked, returning magic handle 0x12345678")
|
||||
# We must respect the hooked method return-value interface
|
||||
@@ -39,11 +39,9 @@ adv_imports = pythondll_module.pe.imports['advapi32.dll']
|
||||
RegOpenKeyExA_iat = [n for n in adv_imports if n.name == "RegOpenKeyExA"][0]
|
||||
|
||||
# Setup our hook
|
||||
|
||||
RegOpenKeyExA_iat.set_hook(open_reg_hook)
|
||||
|
||||
# Use python native module _winreg that call 'RegOpenKeyExA'
|
||||
|
||||
print("Asking for <MY_SECRET_KEY>")
|
||||
v = _winreg.OpenKey(1234567, "MY_SECRET_KEY")
|
||||
print("Result = " + hex(v.handle))
|
||||
|
||||
+1
-8
@@ -10,30 +10,23 @@ if not windows.utils.check_is_elevated():
|
||||
print("!!! Demo will fail because closing a connection require elevated process !!!")
|
||||
|
||||
print("Working on ipv4")
|
||||
|
||||
conns = windows.system.network.ipv4
|
||||
print("== Listening ==")
|
||||
|
||||
print("== Listening ==")
|
||||
print("Some listening connections: {0}".format([c for c in conns if not c.established][:3]))
|
||||
print("Listening ports are : {0}".format([c.local_port for c in conns if not c.established]))
|
||||
|
||||
|
||||
print("== Established ==")
|
||||
|
||||
print("Some established connections: {0}".format([c for c in conns if c.established][:3]))
|
||||
|
||||
TARGET_HOST = "localhost"
|
||||
TARGET_PORT = 80
|
||||
|
||||
print("== connection to {0}:{1} ==".format(TARGET_HOST, TARGET_PORT))
|
||||
|
||||
s = socket.create_connection((TARGET_HOST, TARGET_PORT))
|
||||
|
||||
|
||||
our_connection = [c for c in windows.system.network.ipv4 if c.established and c.remote_port == TARGET_PORT and c.remote_addr == s.getpeername()[0]]
|
||||
|
||||
print("Our connection is {0}".format(our_connection))
|
||||
|
||||
print("Sending YOP")
|
||||
s.send("YOP")
|
||||
print("Closing socket")
|
||||
|
||||
+9
-9
@@ -11,18 +11,18 @@ print("Registry is <{0}>".format(registry))
|
||||
current_user = registry["HKEY_CURRENT_USER"]
|
||||
print("HKEY_CURRENT_USER is <{0}>".format(current_user))
|
||||
subkeys_name = [s.name for s in current_user.subkeys]
|
||||
print("HKEY_CURRENT_USER subkeys names are is <{0}>".format(pprint.pprint(subkeys_name)))
|
||||
print("HKEY_CURRENT_USER subkeys names are:")
|
||||
pprint.pprint(subkeys_name)
|
||||
|
||||
print("Opening 'Software' in HKEY_CURRENT_USER: {0}".format(current_user["Software"]))
|
||||
|
||||
print("We can also open it in one access: {0}".format(registry[r"HKEY_CURRENT_USER\Sofware"]))
|
||||
print("Looking at CurrentVersion")
|
||||
|
||||
print("Looking for the JIT Debugger")
|
||||
windows_info = registry["HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion"]
|
||||
print("Key is {0}".format(windows_info))
|
||||
|
||||
jit_debug_key = registry["HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug"]
|
||||
print("values are:")
|
||||
pprint.pprint(windows_info.values)
|
||||
|
||||
print("Key is {0}".format(jit_debug_key))
|
||||
|
||||
print("values are: {0}".format(pprint.pprint(jit_debug_key.values)))
|
||||
|
||||
print()
|
||||
registered_owner = windows_info.get("RegisteredOwner")
|
||||
print("registered owner = <{0}>".format(registered_owner))
|
||||
@@ -40,7 +40,7 @@ print("Reading allocated memory : <{0}>".format(repr(calc.read_memory(addr, 20))
|
||||
|
||||
# Remote Execution
|
||||
|
||||
print("Execution some native code in our calc (write 0x424242 at allocated address + return 0x1337")
|
||||
print("Execution some native code in our calc (write 0x424242 at allocated address + return 0x1337)")
|
||||
|
||||
if calc.bitness == 32:
|
||||
# Let's generate some native code
|
||||
@@ -54,7 +54,7 @@ else:
|
||||
code += x64.Mov(x64.mem("[RAX]"), 0x42424242)
|
||||
code += x64.Mov("RAX", 0x1337)
|
||||
code += x64.Ret()
|
||||
|
||||
|
||||
print("Executing native code !")
|
||||
t = calc.execute(code.get_code())
|
||||
t.wait()
|
||||
@@ -80,10 +80,10 @@ try:
|
||||
except windows.injection.RemotePythonError as e:
|
||||
print("Remote ERROR !")
|
||||
print(e)
|
||||
|
||||
|
||||
print("That's all ! killing the calc")
|
||||
calc.exit()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -490,4 +490,18 @@ DEBUG_EVENT_CHANGE_DEBUGGEE_STATE = Flag("DEBUG_EVENT_CHANGE_DEBUGGEE_STATE", 0x
|
||||
DEBUG_EVENT_CHANGE_ENGINE_STATE = Flag("DEBUG_EVENT_CHANGE_ENGINE_STATE", 0x00000800)
|
||||
DEBUG_EVENT_CHANGE_SYMBOL_STATE = Flag("DEBUG_EVENT_CHANGE_SYMBOL_STATE", 0x00001000)
|
||||
WOW64_MAXIMUM_SUPPORTED_EXTENSION = Flag("WOW64_MAXIMUM_SUPPORTED_EXTENSION", 512)
|
||||
WOW64_SIZE_OF_80387_REGISTERS = Flag("WOW64_SIZE_OF_80387_REGISTERS", 80)
|
||||
WOW64_SIZE_OF_80387_REGISTERS = Flag("WOW64_SIZE_OF_80387_REGISTERS", 80)
|
||||
REG_NONE = Flag("REG_NONE", ( 0 ))
|
||||
REG_SZ = Flag("REG_SZ", ( 1 ))
|
||||
REG_EXPAND_SZ = Flag("REG_EXPAND_SZ", ( 2 ))
|
||||
REG_BINARY = Flag("REG_BINARY", ( 3 ))
|
||||
REG_DWORD = Flag("REG_DWORD", ( 4 ))
|
||||
REG_DWORD_LITTLE_ENDIAN = Flag("REG_DWORD_LITTLE_ENDIAN", ( 4 ))
|
||||
REG_DWORD_BIG_ENDIAN = Flag("REG_DWORD_BIG_ENDIAN", ( 5 ))
|
||||
REG_LINK = Flag("REG_LINK", ( 6 ))
|
||||
REG_MULTI_SZ = Flag("REG_MULTI_SZ", ( 7 ))
|
||||
REG_RESOURCE_LIST = Flag("REG_RESOURCE_LIST", ( 8 ))
|
||||
REG_FULL_RESOURCE_DESCRIPTOR = Flag("REG_FULL_RESOURCE_DESCRIPTOR", ( 9 ))
|
||||
REG_RESOURCE_REQUIREMENTS_LIST = Flag("REG_RESOURCE_REQUIREMENTS_LIST", ( 10 ))
|
||||
REG_QWORD = Flag("REG_QWORD", ( 11 ))
|
||||
REG_QWORD_LITTLE_ENDIAN = Flag("REG_QWORD_LITTLE_ENDIAN", ( 11 ))
|
||||
@@ -8,7 +8,7 @@ from windows.generated_def.winstructs import *
|
||||
|
||||
|
||||
def _bitness():
|
||||
"""Return 32 or 64"""
|
||||
"""Returns 32 or 64"""
|
||||
import platform
|
||||
bits = platform.architecture()[0]
|
||||
return int(bits[:2])
|
||||
@@ -82,7 +82,7 @@ do_cpuid64 = native_function.create_function(cpuid64_code.get_code(), [DWORD, DW
|
||||
|
||||
|
||||
def x86_cpuid(req):
|
||||
"""Perform a CPUID in 32bits mode
|
||||
"""Performs a CPUID in 32bits mode
|
||||
|
||||
:rtype: :class:`X86CpuidResult`
|
||||
"""
|
||||
@@ -92,7 +92,7 @@ def x86_cpuid(req):
|
||||
|
||||
|
||||
def x64_cpuid(req):
|
||||
"""Perform a CPUID in 64bits mode
|
||||
"""Performs a CPUID in 64bits mode
|
||||
|
||||
:rtype: :class:`X86CpuidResult`
|
||||
"""
|
||||
@@ -108,7 +108,7 @@ else:
|
||||
_do_cpuid = x64_cpuid
|
||||
|
||||
def do_cpuid(req):
|
||||
"""Perform a CPUID for the current process bitness
|
||||
"""Performs a CPUID for the current process bitness
|
||||
|
||||
:rtype: :class:`X86CpuidResult`
|
||||
"""
|
||||
@@ -116,7 +116,7 @@ def do_cpuid(req):
|
||||
|
||||
|
||||
def get_vendor_id():
|
||||
"""Extract the VendorId string from CPUID
|
||||
"""Extracts the VendorId string from CPUID
|
||||
|
||||
:rtype: :class:`str`
|
||||
"""
|
||||
@@ -136,7 +136,7 @@ def is_amd_proc():
|
||||
|
||||
|
||||
def get_proc_family_model():
|
||||
"""Extract the family and model based on vendorId
|
||||
"""Extracts the family and model based on vendorId
|
||||
|
||||
:rtype: (ComputedFamily, ComputedModel)
|
||||
"""
|
||||
|
||||
@@ -1059,7 +1059,7 @@ if in_IDA:
|
||||
def test_code():
|
||||
s = MultipleInstr()
|
||||
s += Mov('r8', 'r14')
|
||||
s += Label(':SUCE')
|
||||
s += Label(':A_POLITICALLY_CORRECT_LABEL_NAME')
|
||||
s += Jnz(':END')
|
||||
s += Add('r14', 0x12345678)
|
||||
s += Dec('r9')
|
||||
@@ -1068,7 +1068,7 @@ if in_IDA:
|
||||
s += Mov('r8', 'rdx')
|
||||
s += Jnz(':END')
|
||||
s += Mov('r8', 'rdx')
|
||||
s += Jnz(':SUCE')
|
||||
s += Jnz(':A_POLITICALLY_CORRECT_LABEL_NAME')
|
||||
s += Mov('r9', 'r10')
|
||||
s += Label(':END')
|
||||
s += Ret()
|
||||
|
||||
@@ -136,7 +136,7 @@ class X86(object):
|
||||
|
||||
|
||||
def create_displacement(base=None, index=None, scale=None, disp=0, prefix=None):
|
||||
"""Create an X86 memory access description"""
|
||||
"""Creates a X86 memory access description"""
|
||||
if index is not None and scale is None:
|
||||
scale = 1
|
||||
if scale and index is None:
|
||||
@@ -147,12 +147,14 @@ def create_displacement(base=None, index=None, scale=None, disp=0, prefix=None):
|
||||
|
||||
|
||||
def deref(disp):
|
||||
"""Create a memory access for an immediate value ``Ex: [0x42424242]``"""
|
||||
return create_displacement(disp=disp)
|
||||
|
||||
|
||||
def mem(data):
|
||||
"""Parse a memory access string of format [EXPR] or seg:[EXPR]
|
||||
EXPR may describe: BASE | INDEX * SCALE | DISPLACEMENT or any combinaison (in this order)
|
||||
"""Parse a memory access string of format ``[EXPR]`` or ``seg:[EXPR]``
|
||||
|
||||
``EXPR`` may describe: ``BASE | INDEX * SCALE | DISPLACEMENT`` or any combinaison (in this order)
|
||||
"""
|
||||
if not isinstance(data, str):
|
||||
raise TypeError("mem need a string to parse")
|
||||
|
||||
+3
-3
@@ -58,7 +58,7 @@ class TCP4Connection(MIB_TCPROW_OWNER_PID):
|
||||
@property
|
||||
def remote_host(self):
|
||||
"""Identification of the remote hostname.
|
||||
Equals ``remote_addr`` if resolution fail
|
||||
Equals ``remote_addr`` if the resolution fails
|
||||
|
||||
:type: :class:`str` or :class:`int`
|
||||
"""
|
||||
@@ -124,12 +124,12 @@ class TCP6Connection(MIB_TCP6ROW_OWNER_PID):
|
||||
|
||||
@property
|
||||
def remote_proto(self):
|
||||
"""Equals to self.remote_port for Ipv6"""
|
||||
"""Equals to ``self.remote_port`` for Ipv6"""
|
||||
return self.remote_port
|
||||
|
||||
@property
|
||||
def remote_host(self):
|
||||
"""Equals to self.remote_addr for Ipv6"""
|
||||
"""Equals to ``self.remote_addr`` for Ipv6"""
|
||||
return self.remote_addr
|
||||
|
||||
def close(self):
|
||||
|
||||
+12
-4
@@ -48,10 +48,13 @@ def get_structure_transformer_for_target(target):
|
||||
|
||||
|
||||
def GetPEFile(baseaddr, target=None):
|
||||
"""Return a :class:`PEFile` to explore a PE loaded at `baseaddr` in process `target`.
|
||||
If target is ``None`` it refers the curent process
|
||||
"""Returns a :class:`PEFile` to explore a PE loaded at `baseaddr` in process `target`.
|
||||
|
||||
:rtype: :class:`PEFile`
|
||||
|
||||
.. note::
|
||||
|
||||
If target is ``None`` it refers to the curent process
|
||||
"""
|
||||
proc_bitness = windows.current_process.bitness
|
||||
if target is None:
|
||||
@@ -106,7 +109,7 @@ def GetPEFile(baseaddr, target=None):
|
||||
|
||||
class IATEntry(ctypes.Structure):
|
||||
"""Represent an entry in the IAT of a module
|
||||
| Can be used to get resolved value and setup hook
|
||||
Can be used to get resolved value and setup hook
|
||||
"""
|
||||
_fields_ = [
|
||||
("value", PVOID)]
|
||||
@@ -136,8 +139,13 @@ def GetPEFile(baseaddr, target=None):
|
||||
see :ref:`hook_protocol`
|
||||
|
||||
:rtype: :class:`windows.hooks.IATHook`
|
||||
"""
|
||||
|
||||
.. warning::
|
||||
|
||||
This works only for PEFile with the current process as target.
|
||||
"""
|
||||
if target is not None:
|
||||
raise NotImplementedError("Setting hook in remote process (use python code injection)")
|
||||
|
||||
hook = hooks.IATHook(self, callback, types)
|
||||
self.hook = hook
|
||||
|
||||
+28
-7
@@ -1,7 +1,10 @@
|
||||
import _winreg
|
||||
import windows
|
||||
import itertools
|
||||
import collections
|
||||
from collections import namedtuple
|
||||
|
||||
import windows
|
||||
from windows.generated_def.windef import KEY_READ
|
||||
|
||||
|
||||
|
||||
class ExpectWindowsError(object):
|
||||
@@ -14,11 +17,14 @@ class ExpectWindowsError(object):
|
||||
def __exit__(self, etype, e, tb):
|
||||
return (etype == WindowsError and e.winerror == self.errornumber)
|
||||
|
||||
KeyValue = collections.namedtuple("KeyValue", ["name", "value", "type"])
|
||||
|
||||
KeyValue = namedtuple("KeyValue", ["name", "value", "type"])
|
||||
"""A registry value (name, value, type)"""
|
||||
|
||||
|
||||
class PyHKey(object):
|
||||
"""A windows registry key"""
|
||||
def __init__(self, surkey, name, sam=_winreg.KEY_READ):
|
||||
def __init__(self, surkey, name, sam=KEY_READ):
|
||||
self.surkey = surkey
|
||||
self.name = name
|
||||
self.fullname = self.surkey.fullname + "\\" + self.name if self.name else self.surkey.name
|
||||
@@ -40,7 +46,9 @@ class PyHKey(object):
|
||||
|
||||
@property
|
||||
def subkeys(self):
|
||||
"""The subkeys of the registry key"""
|
||||
"""The subkeys of the registry key
|
||||
|
||||
:type: [:class:`PyHKey`] - A list of keys"""
|
||||
res = []
|
||||
with ExpectWindowsError(259):
|
||||
for i in itertools.count():
|
||||
@@ -49,14 +57,28 @@ class PyHKey(object):
|
||||
|
||||
@property
|
||||
def values(self):
|
||||
"""The values of the registry key"""
|
||||
"""The values of the registry key
|
||||
|
||||
:type: [:class:`KeyValue`] - A list of values"""
|
||||
res = []
|
||||
with ExpectWindowsError(259):
|
||||
for i in itertools.count():
|
||||
res.append(_winreg.EnumValue(self.phkey, i))
|
||||
return [KeyValue(*r) for r in res]
|
||||
|
||||
def get(self, value_name):
|
||||
"""Retrieves the value ``value_name``
|
||||
|
||||
:rtype: :class:`KeyValue`
|
||||
"""
|
||||
data = _winreg.QueryValueEx(self.phkey, value_name)
|
||||
return KeyValue(value_name, data[0], data[1])
|
||||
|
||||
def open_subkey(self, name):
|
||||
"""Open the subkey ``name``
|
||||
|
||||
:rtype: :class:`PyHKey`
|
||||
"""
|
||||
return PyHKey(self, name, self.sam)
|
||||
|
||||
def reopen(self, new_sam):
|
||||
@@ -108,4 +130,3 @@ class Registry(object):
|
||||
if base_name not in self.registry_base_keys:
|
||||
raise ValueError("Unknow registry base key <{0}>".format(base_name))
|
||||
return self.registry_base_keys[base_name][subkey]
|
||||
|
||||
|
||||
@@ -202,7 +202,6 @@ get_syswow_ntdll_exports.value = None
|
||||
|
||||
|
||||
class Syswow64ApiProxy(object):
|
||||
APIDLL = None
|
||||
"""Create a python wrapper around a function"""
|
||||
def __init__(self, winproxy_function):
|
||||
self.winproxy_function = winproxy_function
|
||||
|
||||
+48
-34
@@ -119,7 +119,9 @@ class WinThread(THREADENTRY32, AutoHandle):
|
||||
"""Represent a thread """
|
||||
@utils.fixedpropety
|
||||
def tid(self):
|
||||
"""Thread ID"""
|
||||
"""Thread ID
|
||||
|
||||
:type: :class:`int`"""
|
||||
return self.th32ThreadID
|
||||
|
||||
@utils.fixedpropety
|
||||
@@ -166,7 +168,7 @@ class WinThread(THREADENTRY32, AutoHandle):
|
||||
@property
|
||||
def start_address(self):
|
||||
"""The start address of the thread
|
||||
|
||||
|
||||
:type: :class:`int`
|
||||
"""
|
||||
if windows.current_process.bitness == 32 and self.owner.bitness == 64:
|
||||
@@ -199,7 +201,7 @@ class WinThread(THREADENTRY32, AutoHandle):
|
||||
@property
|
||||
def is_exit(self):
|
||||
"""Is ``True`` if the thread is terminated
|
||||
|
||||
|
||||
:type: :class:`bool`
|
||||
"""
|
||||
return self.exit_code != STILL_ACTIVE
|
||||
@@ -207,7 +209,7 @@ class WinThread(THREADENTRY32, AutoHandle):
|
||||
@property
|
||||
def exit_code(self):
|
||||
"""The exit code of the thread : ``STILL_ACTIVE`` means the process is not dead
|
||||
|
||||
|
||||
:type: :class:`int`
|
||||
"""
|
||||
res = DWORD()
|
||||
@@ -246,7 +248,7 @@ class DeadThread(AutoHandle):
|
||||
@property
|
||||
def is_exit(self):
|
||||
"""Is ``True`` if the thread is terminated
|
||||
|
||||
|
||||
:type: :class:`bool`
|
||||
"""
|
||||
return self.exit_code != STILL_ACTIVE
|
||||
@@ -254,7 +256,7 @@ class DeadThread(AutoHandle):
|
||||
@property
|
||||
def exit_code(self):
|
||||
"""The exit code of the thread : ``STILL_ACTIVE`` means the process is not dead
|
||||
|
||||
|
||||
:type: :class:`int`
|
||||
"""
|
||||
res = DWORD()
|
||||
@@ -265,7 +267,7 @@ class DeadThread(AutoHandle):
|
||||
class Process(AutoHandle):
|
||||
@utils.fixedpropety
|
||||
def is_wow_64(self):
|
||||
"""Is ``True`` if the process is a SysWow64 process (32bit process on 64bits system).
|
||||
"""``True`` if the process is a SysWow64 process (32bit process on 64bits system).
|
||||
|
||||
:type: :class:`bool`
|
||||
"""
|
||||
@@ -296,7 +298,7 @@ class Process(AutoHandle):
|
||||
@property
|
||||
def exit_code(self):
|
||||
"""The exit code of the process : ``STILL_ACTIVE`` means the process is not dead
|
||||
|
||||
|
||||
:type: :class:`int`
|
||||
"""
|
||||
res = DWORD()
|
||||
@@ -305,21 +307,24 @@ class Process(AutoHandle):
|
||||
|
||||
@property
|
||||
def is_exit(self):
|
||||
"""Is ``True`` if the process is terminated
|
||||
|
||||
"""``True`` if the process is terminated
|
||||
|
||||
:type: :class:`bool`
|
||||
"""
|
||||
return self.exit_code == STILL_ACTIVE
|
||||
|
||||
def execute(self, code):
|
||||
"""Execute some raw code in the context of the process"""
|
||||
"""Execute some native code in the context of the process
|
||||
|
||||
:return: The return value of the native code
|
||||
:rtype: :class:`int`"""
|
||||
x = self.virtual_alloc(len(code))
|
||||
self.write_memory(x, code)
|
||||
return self.create_thread(x, 0)
|
||||
|
||||
def query_memory(self, addr):
|
||||
"""Query the memory informations about page at ```addr``
|
||||
|
||||
"""Query the memory informations about page at ``addr``
|
||||
|
||||
:rtype: :class:`MEMORY_BASIC_INFORMATION`
|
||||
"""
|
||||
if windows.current_process.bitness == 32 and self.bitness == 64:
|
||||
@@ -340,7 +345,7 @@ class Process(AutoHandle):
|
||||
|
||||
def memory_state(self):
|
||||
"""Yield the memory information for the whole address space of the process
|
||||
|
||||
|
||||
:yield: :class:`MEMORY_BASIC_INFORMATION`
|
||||
"""
|
||||
addr = 0
|
||||
@@ -358,7 +363,9 @@ class CurrentThread(AutoHandle):
|
||||
"""The current thread"""
|
||||
@utils.fixedpropety
|
||||
def tid(self):
|
||||
"""Thread ID"""
|
||||
"""Thread ID
|
||||
|
||||
:type: :class:`int`"""
|
||||
return winproxy.GetCurrentThreadId()
|
||||
|
||||
@utils.fixedpropety
|
||||
@@ -380,7 +387,7 @@ class CurrentThread(AutoHandle):
|
||||
return winproxy.ExitThread(code)
|
||||
|
||||
def wait(self):
|
||||
"""Raise ValueError to prevent deadlock :D"""
|
||||
"""Raise ``ValueError`` to prevent deadlock :D"""
|
||||
raise ValueError("wait() on current thread")
|
||||
|
||||
|
||||
@@ -451,9 +458,10 @@ class CurrentProcess(Process):
|
||||
return int(bits[:2])
|
||||
|
||||
def virtual_alloc(self, size):
|
||||
"""Allocate memory in the current process
|
||||
"""Allocate memory in the process
|
||||
|
||||
:returns: :class:`int`
|
||||
:return: The address of the allocated memory
|
||||
:rtype: :class:`int`
|
||||
"""
|
||||
return winproxy.VirtualAlloc(dwSize=size)
|
||||
|
||||
@@ -464,7 +472,11 @@ class CurrentProcess(Process):
|
||||
return True
|
||||
|
||||
def read_memory(self, addr, size):
|
||||
"""Read size from addr"""
|
||||
"""Read ``size`` from ``addr``
|
||||
|
||||
:return: The data read
|
||||
:rtype: :class:`str`
|
||||
"""
|
||||
dbgprint('Read CurrentProcess Memory', 'READMEM')
|
||||
buffer = (c_char * size).from_address(addr)
|
||||
return buffer[:]
|
||||
@@ -472,10 +484,7 @@ class CurrentProcess(Process):
|
||||
def create_thread(self, lpStartAddress, lpParameter, dwCreationFlags=0):
|
||||
"""Create a new thread
|
||||
|
||||
.. note::
|
||||
CreateThread https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453%28v=vs.85%29.aspx
|
||||
|
||||
:rtype: :class:`WinThread` or :class:`DeadThread`
|
||||
:rtype: :class:`WinThread` or :class:`DeadThread`
|
||||
"""
|
||||
handle = winproxy.CreateThread(lpStartAddress=lpStartAddress, lpParameter=lpParameter, dwCreationFlags=dwCreationFlags)
|
||||
return WinThread._from_handle(handle)
|
||||
@@ -485,7 +494,7 @@ class CurrentProcess(Process):
|
||||
return winproxy.ExitProcess(code)
|
||||
|
||||
def wait(self):
|
||||
"""Raise ValueError to prevent deadlock :D"""
|
||||
"""Raise ``ValueError`` to prevent deadlock :D"""
|
||||
raise ValueError("wait() on current thread")
|
||||
|
||||
|
||||
@@ -527,7 +536,8 @@ class WinProcess(PROCESSENTRY32, Process):
|
||||
def virtual_alloc(self, size):
|
||||
"""Allocate memory in the process
|
||||
|
||||
:rtype: :class:`int`
|
||||
:return: The address of the allocated memory
|
||||
:rtype: :class:`int`
|
||||
"""
|
||||
return winproxy.VirtualAllocEx(self.handle, dwSize=size)
|
||||
|
||||
@@ -544,7 +554,11 @@ class WinProcess(PROCESSENTRY32, Process):
|
||||
return winproxy.ReadProcessMemory(self.handle, addr, lpBuffer=buffer_addr, nSize=size)
|
||||
|
||||
def read_memory(self, addr, size):
|
||||
"""Read `size` from `addr`"""
|
||||
"""Read ``size`` from ``addr``
|
||||
|
||||
:return: The data read
|
||||
:rtype: :class:`str`
|
||||
"""
|
||||
buffer = ctypes.create_string_buffer(size)
|
||||
self.low_read_memory(addr, ctypes.byref(buffer), size)
|
||||
return buffer[:]
|
||||
@@ -569,14 +583,14 @@ class WinProcess(PROCESSENTRY32, Process):
|
||||
|
||||
def read_memory_into(self, addr, struct):
|
||||
"""Read a :mod:`ctypes` struct from `addr`
|
||||
|
||||
|
||||
:returns: struct"""
|
||||
self.low_read_memory(addr, ctypes.byref(struct), ctypes.sizeof(struct))
|
||||
return struct
|
||||
|
||||
def create_thread(self, addr, param):
|
||||
"""Create a remote thread
|
||||
|
||||
|
||||
:rtype: :class:`WinThread` or :class:`DeadThread`
|
||||
"""
|
||||
if windows.current_process.bitness == 32 and self.bitness == 64:
|
||||
@@ -593,15 +607,15 @@ class WinProcess(PROCESSENTRY32, Process):
|
||||
return self.create_thread(LoadLibrary, x)
|
||||
|
||||
def execute_python(self, pycode):
|
||||
"""Execute Python code into the remote process.
|
||||
|
||||
"""Execute Python code into the remote process.
|
||||
|
||||
This function waits for the remote process to end and
|
||||
raises an exception if the remote thread raised one"""
|
||||
return injection.safe_execute_python(self, pycode)
|
||||
|
||||
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
|
||||
"""
|
||||
return injection.execute_python_code(self, pycode)
|
||||
@@ -609,7 +623,7 @@ class WinProcess(PROCESSENTRY32, Process):
|
||||
@utils.fixedpropety
|
||||
def peb_addr(self):
|
||||
"""The address of the PEB
|
||||
|
||||
|
||||
:type: :class:`int`
|
||||
"""
|
||||
if windows.current_process.bitness == 32 and self.bitness == 64:
|
||||
@@ -636,7 +650,7 @@ class WinProcess(PROCESSENTRY32, Process):
|
||||
@utils.fixedpropety
|
||||
def peb(self):
|
||||
"""The PEB of the remote process (see :mod:`remotectypes`)
|
||||
|
||||
|
||||
:type: :class:`PEB`
|
||||
"""
|
||||
if windows.current_process.bitness == 32 and self.bitness == 64:
|
||||
@@ -692,7 +706,7 @@ class WinUnicodeString(LSA_UNICODE_STRING):
|
||||
"""LSA_UNICODE_STRING with a nice `__repr__`"""
|
||||
fields = [f[0] for f in LSA_UNICODE_STRING._fields_]
|
||||
"""The fields of the structure"""
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return """<{0} "{1}" at {2}>""".format(type(self).__name__, self.Buffer, hex(id(self)))
|
||||
|
||||
|
||||
+1
-1
@@ -573,7 +573,7 @@ def RegGetValueA(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData):
|
||||
|
||||
|
||||
@Advapi32Proxy('RegGetValueW', kernel32_zero_check)
|
||||
def RegGetValueW(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData):
|
||||
def RegGetValueW(hkey, lpSubKey=None, lpValue=NeededParameter, dwFlags=0, pdwType=None, pvData=None, pcbData=None):
|
||||
return RegGetValueW.ctypes_function(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user