mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
Adding more and more documentation
This commit is contained in:
+2
-1
@@ -1 +1,2 @@
|
||||
*.pyc
|
||||
*.pyc
|
||||
doc/build
|
||||
@@ -1,6 +1,7 @@
|
||||
TODO:
|
||||
- Documentation
|
||||
- ProcessMemory object ? (metasm like)
|
||||
- Extend Registry feature (write + read 1 key)
|
||||
|
||||
FIXME:
|
||||
- WMI
|
||||
|
||||
@@ -1459,4 +1459,14 @@ typedef struct _PROCESS_BASIC_INFORMATION {
|
||||
PVOID Reserved2[2];
|
||||
ULONG_PTR UniqueProcessId;
|
||||
PVOID Reserved3;
|
||||
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
|
||||
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
|
||||
|
||||
typedef struct _JIT_DEBUG_INFO {
|
||||
DWORD dwSize;
|
||||
DWORD dwProcessorArchitecture;
|
||||
DWORD dwThreadID;
|
||||
DWORD dwReserved0;
|
||||
ULONG64 lpExceptionAddress;
|
||||
ULONG64 lpExceptionRecord;
|
||||
ULONG64 lpContextRecord;
|
||||
} JIT_DEBUG_INFO, *LPJIT_DEBUG_INFO;
|
||||
@@ -24,6 +24,8 @@ sys.path.append(os.path.abspath(__file__ + "..\..\..\.."))
|
||||
|
||||
print("Adding <{0}>".format(sys.path[-1]))
|
||||
|
||||
os.environ["SPHINX_BUILD"] = "1"
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
IAT hooking
|
||||
"""""""""""
|
||||
|
||||
.. note::
|
||||
|
||||
See sample :ref:`sample_iat_hook`
|
||||
|
||||
Put a IAT hook
|
||||
''''''''''''''
|
||||
|
||||
To setup your IAT hook you just need:
|
||||
|
||||
* A callback that respect the :ref:`hook_protocol`
|
||||
* The :class:`windows.pe_parse.IATEntry` to hook
|
||||
|
||||
|
||||
You just need to use the function :func:`windows.pe_parse.IATEntry.set_hook`
|
||||
|
||||
Putting a hook::
|
||||
|
||||
import windows
|
||||
from windows.hooks import *
|
||||
|
||||
@CreateFileACallback
|
||||
def createfile_callback(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile, real_function):
|
||||
print("Trying to open {0}".format(lpFileName))
|
||||
if "secret" in lpFileName:
|
||||
return 0xffffffff
|
||||
return real_function()
|
||||
|
||||
my_exe = windows.current_process.peb.modules[0]
|
||||
imp = my_exe.pe.imports
|
||||
|
||||
iat_create_file = [entry for entry in imp['kernel32.dll'] if entry.name == "CreateFileA"]
|
||||
iat_create_file.set_hook(createfile_callback)
|
||||
|
||||
|
||||
.. _hook_protocol:
|
||||
|
||||
Hook protocol
|
||||
'''''''''''''
|
||||
|
||||
Callback arguments
|
||||
------------------
|
||||
|
||||
A hook callback must have the same number of argument as the hooked API, PLUS a last argument ``real_function``.
|
||||
|
||||
|
||||
|
||||
The ``real_function`` argument is a callable that represent the hooked API, it can be called in two ways:
|
||||
|
||||
* Without argument, the call will be done with the argument originaly passed to your callback. This allows simple redirection to the real API.
|
||||
|
||||
* With arguments it will simply call the API with these.
|
||||
|
||||
Example::
|
||||
|
||||
def createfile_callback(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile, real_function):
|
||||
print("Trying to open {0}".format(lpFileName))
|
||||
if "secret" in lpFileName:
|
||||
return 0xffffffff
|
||||
# Perform the real call
|
||||
return real_function()
|
||||
|
||||
|
||||
A hook callback must also embed some :ref:`Type Information <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.
|
||||
|
||||
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.
|
||||
|
||||
* Giving the type manualy using the decorator :class:`windows.hooks.Callback`::
|
||||
|
||||
from windows.hooks import *
|
||||
# First type is return type, others are parameters types
|
||||
@Callback(ctypes.c_void_p, ctypes.c_ulong)
|
||||
def exit_callback(x, real_function):
|
||||
print("Try to quit with {0} | {1}".format(x, type(x)))
|
||||
if x == 3:
|
||||
print("TRYING TO REAL EXIT")
|
||||
return real_function(1234)
|
||||
return 0x4242424243444546
|
||||
|
||||
* Using the `Callback` decorator generated from known functions::
|
||||
|
||||
from windows.hooks import *
|
||||
# Decorator name is always API_NAME + "CallBack"
|
||||
@CreateFileACallback
|
||||
def createfile_callback(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile, real_function):
|
||||
print("Trying to open {0}".format(lpFileName))
|
||||
if "secret" in lpFileName:
|
||||
return 0xffffffff
|
||||
return real_function()
|
||||
|
||||
.. note::
|
||||
|
||||
See the list of known functions
|
||||
|
||||
|
||||
:mod:`windows.hooks`
|
||||
''''''''''''''''''''
|
||||
|
||||
.. module:: windows.hooks
|
||||
|
||||
.. autoclass:: windows.hooks.Callback
|
||||
|
||||
.. autoclass:: windows.hooks.IATHook
|
||||
@@ -17,6 +17,9 @@ Contents:
|
||||
utils.rst
|
||||
native_exec.rst
|
||||
various.rst
|
||||
iat_hook.rst
|
||||
wip.rst
|
||||
internals.rst
|
||||
sample.rst
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
Internals
|
||||
=========
|
||||
|
||||
Because some horrible hacks of ``PythonForWindows`` are hidden and I wanted to talk about it.
|
||||
|
||||
remotectypes.py
|
||||
'''''''''''''''
|
||||
|
||||
.. module:: windows.remotectypes
|
||||
|
||||
Performing parsing of PEB / PE in remote process may be painful and i didn't want
|
||||
to have two versions of all my parsing code.
|
||||
|
||||
So I made a wrapper around :mod:`ctypes` that is able to do two things:
|
||||
|
||||
- Transform a 32bits ctypes structure into a 64bits one and reverse
|
||||
|
||||
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.
|
||||
|
||||
- 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``
|
||||
|
||||
We also need to be carreful about the inheritance, we need to inherit from "hidden"
|
||||
:class:`ctypes` classes to keep the magic working.
|
||||
|
||||
|
||||
This module exports the following API:
|
||||
|
||||
.. autofunction:: transform_type_to_remote32bits
|
||||
|
||||
.. autofunction:: transform_type_to_remote64bits
|
||||
|
||||
Both functions return a class that represent the structure in a remote process.
|
||||
The class.__init__ accept two arguments:
|
||||
|
||||
* ``base_addr``: the address of the object in the remote process
|
||||
* ``target``: an object with a method ``read_memory`` (so a :class:`windows.winobject.WinProcess` in our case)
|
||||
|
||||
Example ``WinProcess.peb``::
|
||||
|
||||
def peb(self):
|
||||
if windows.current_process.bitness == 32 and self.bitness == 64:
|
||||
return RemotePEB64(self.peb_addr, self)
|
||||
if windows.current_process.bitness == 64 and self.bitness == 32:
|
||||
return RemotePEB32(self.peb_addr, self)
|
||||
return RemotePEB(self.peb_addr, self)
|
||||
|
||||
I am pretty sure that this code does NOT handle all the cases, so it might break some day.
|
||||
|
||||
syswow64.py -- Crossing the heaven gate
|
||||
'''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
.. module:: windows.syswow64
|
||||
|
||||
One of my goal with ``PythonForWindows`` is to have some abstraction of the bitness of the processes.
|
||||
It means being able to work on a ``32bits Python`` or a ``64bits Python``.
|
||||
|
||||
In the case of a 32bits python on a ``64bits`` system (``SysWow64``) it's not trivial to perform operation on
|
||||
other ``64bits`` processes. For example directly calling :func:`CreateRemoteThread` will not work.
|
||||
|
||||
To be able to perform those operation we must be able to execute code in the ``64bits`` part of our
|
||||
``SysWow64`` process.
|
||||
|
||||
.. note::
|
||||
|
||||
TODO link to ``Heaven Gate``
|
||||
|
||||
For that we need to jump to the 64bits segment of our process, execute some code then return.
|
||||
To do so, we need to use some ``far jump`` / ``far ret`` with the segments selector ``0x23`` (CS_32bits) and ``0x33`` (CS_64bits).
|
||||
|
||||
The generation of this is quite ugly in my case.
|
||||
This code is in:
|
||||
|
||||
.. function:: execute_64bits_code_from_syswow
|
||||
|
||||
Once we are able to execute some code in the ``64bits`` part we need to create the code that will call our API (in NTDLL).
|
||||
To do that, I rely on the type information already present in the function of :mod:`windows.winproxy`.
|
||||
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:
|
||||
|
||||
.. function:: generate_syswow64_call
|
||||
|
||||
One problem I encountered is that our function must be able to pass values of 64bits, so passing arguments by register is not possible.
|
||||
|
||||
For now I allocate a buffer where a python wrapper copy the parameters and the x64 stub retrieves them from here.
|
||||
|
||||
(It might be possible to do something by creating a WINCFUNC with only ULONG64 parameters).
|
||||
|
||||
.. function:: try_generate_stub_target
|
||||
|
||||
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
|
||||
* 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.
|
||||
|
||||
.. class:: Syswow64ApiProxy
|
||||
|
||||
Existing function are:
|
||||
|
||||
.. function:: NtCreateThreadEx_32_to_64
|
||||
|
||||
.. function:: NtQueryInformationProcess_32_to_64
|
||||
|
||||
.. function:: NtQueryInformationThread_32_to_64
|
||||
|
||||
.. function:: NtQueryVirtualMemory_32_to_64
|
||||
|
||||
.. function:: NtGetContextThread_32_to_64
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
.. module:: windows.native_exec
|
||||
|
||||
``windows.native_exec`` -- Native Code Execution
|
||||
************************************************
|
||||
|
||||
.. currentmodule:: windows.native_exec
|
||||
|
||||
The :mod:`windows.native_exec` allows to create `Python` functions calling native code.
|
||||
it also provide a simple assembler for x86 and x64.
|
||||
|
||||
The :mod:`windows.native_exec` provides those functions:
|
||||
|
||||
.. automodule:: windows.native_exec
|
||||
.. autofunction:: windows.native_exec.create_function
|
||||
|
||||
The :mod:`windows.native_exec` also contains some submodules:
|
||||
* :mod:`windows.native_exec.cpuid`
|
||||
|
||||
+35
-2
@@ -65,8 +65,41 @@ The :class:`PEB` is accessible via ``process.peb`` and is of type :class:`PEB`.
|
||||
.. autoclass:: LoadedModule
|
||||
|
||||
|
||||
.. warning::
|
||||
PEFile
|
||||
""""""
|
||||
|
||||
TODO: pe_parse.PEFile (sorry) but example at :ref:`sample_peb_exploration`
|
||||
:mod:`windows.pe_parse`
|
||||
'''''''''''''''''''''''
|
||||
|
||||
.. module:: windows.pe_parse
|
||||
|
||||
.. autofunction:: windows.pe_parse.GetPEFile
|
||||
|
||||
.. autoclass:: PEFile
|
||||
|
||||
|
||||
.. autoclass:: IATEntry
|
||||
|
||||
.. data:: addr
|
||||
|
||||
:class:`int` : Address of the IAT Entry
|
||||
|
||||
.. data:: ord
|
||||
|
||||
:class:`int` : Ordinal of the imported function
|
||||
|
||||
.. data:: name
|
||||
|
||||
:class:`int` : Name of the imported function
|
||||
|
||||
.. data:: value
|
||||
|
||||
:class:`int` : The content (destination) of the IAT entry
|
||||
|
||||
.. warning::
|
||||
|
||||
`value` is a descriptor. Setting its value will actually CHANGE THE IAT ENTRY, resulting in a segfault if no VirtualProtect have been done.
|
||||
|
||||
.. note::
|
||||
|
||||
See: :class:`windows.utils.VirtualProtected`
|
||||
@@ -99,6 +99,31 @@ Output::
|
||||
Sections: [<PESection ".text">, <PESection ".rdata">, <PESection ".data">, <PESection ".rsrc">, <PESection ".reloc">]
|
||||
|
||||
|
||||
.. _sample_iat_hook:
|
||||
|
||||
IAT hooking
|
||||
"""""""""""
|
||||
|
||||
.. literalinclude:: ..\..\samples\iat_hook.py
|
||||
|
||||
Output::
|
||||
|
||||
(cmd λ) python iat_hook.py
|
||||
Asking for <MY_SECRET_KEY>
|
||||
<in hook> Hook called | hKey = 0x12d687 | lpSubKey = <MY_SECRET_KEY>
|
||||
<in hook> Secret key asked, returning magic handle 0x12345678
|
||||
Result = 0x12345678
|
||||
|
||||
Asking for <MY_FAIL_KEY>
|
||||
<in hook> Hook called | hKey = 0x12d687 | lpSubKey = <MY_FAIL_KEY>
|
||||
<in hook> Asked for a failing key: returning 0x2a
|
||||
WindowsError(42, 'Windows Error 0x2A')
|
||||
|
||||
Asking for <HKEY_CURRENT_USER/Software>
|
||||
<in hook> Hook called | hKey = 0x80000001L | lpSubKey = <Software>
|
||||
<in hook> Non-secret key : calling normal function
|
||||
Result = 0x108
|
||||
|
||||
.. _sample_network_exploration:
|
||||
|
||||
:class:`Network` - socket exploration
|
||||
|
||||
+10
-10
@@ -1,33 +1,33 @@
|
||||
The ``windows`` module
|
||||
**********************
|
||||
|
||||
The ``windows`` module is the module installed by :file:`setup.py` (that does not exists right now).
|
||||
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.
|
||||
|
||||
The defaults objects accessible in ``windows`` are:
|
||||
* ``system`` of type :class:`windows.winobject.System`
|
||||
* ``current_process`` of type :class:`CurrentProcess`
|
||||
* ``current_thread`` of type :class:`CurrentThread`
|
||||
|
||||
* ``current_process`` of type :class:`windows.winobject.CurrentProcess`
|
||||
* ``current_thread`` of type :class:`windows.winobject.CurrentThread`
|
||||
|
||||
The submodules that you might use by themself are:
|
||||
* :mod:`windows.native_exec`
|
||||
* :mod:`windows.winproxy`
|
||||
* :mod:`windows.utils`
|
||||
|
||||
|
||||
.. _object_system:
|
||||
|
||||
|
||||
The ``system`` object
|
||||
"""""""""""""""""""""
|
||||
|
||||
.. autoclass:: windows.winobject.System
|
||||
:no-show-inheritance:
|
||||
|
||||
|
||||
.. autoattribute:: windows.winobject.System.registry
|
||||
:annotation:
|
||||
|
||||
|
||||
Object of class :class:`windows.registry.Registry`
|
||||
|
||||
|
||||
.. autoattribute:: windows.winobject.System.network
|
||||
:annotation:
|
||||
|
||||
|
||||
Object of class :class:`windows.network.Network`
|
||||
@@ -0,0 +1,25 @@
|
||||
Early Work In Progress
|
||||
======================
|
||||
|
||||
Here are some features that are still work in progress. Code might be unstable and/or ultra-ugly.
|
||||
|
||||
Wintrust -- Signature check
|
||||
"""""""""""""""""""""""""""
|
||||
|
||||
Should it juste be part of :mod:`windows.utils` ?
|
||||
|
||||
.. module:: windows.wintrust
|
||||
|
||||
.. autofunction:: windows.wintrust.check_signature
|
||||
|
||||
|
||||
|
||||
WMI -- WMI request
|
||||
""""""""""""""""""
|
||||
|
||||
Unstable code: not fully tested, ugly COM initialisation
|
||||
|
||||
|
||||
.. module:: windows.wmi
|
||||
|
||||
.. autoclass:: windows.wmi.WmiRequester
|
||||
+5
-3
@@ -24,8 +24,8 @@ def open_reg_hook(hKey, lpSubKey, ulOptions, samDesired, phkResult, real_functio
|
||||
return 42
|
||||
print("<in hook> Non-secret key : calling normal function")
|
||||
return real_function()
|
||||
|
||||
|
||||
|
||||
|
||||
# Get the peb of our process
|
||||
peb = windows.current_process.peb
|
||||
|
||||
@@ -38,7 +38,7 @@ adv_imports = pythondll_module.pe.imports['advapi32.dll']
|
||||
# Get RegOpenKeyExA iat entry
|
||||
RegOpenKeyExA_iat = [n for n in adv_imports if n.name == "RegOpenKeyExA"][0]
|
||||
|
||||
# Setup our hook
|
||||
# Setup our hook
|
||||
|
||||
RegOpenKeyExA_iat.set_hook(open_reg_hook)
|
||||
|
||||
@@ -48,6 +48,7 @@ print("Asking for <MY_SECRET_KEY>")
|
||||
v = _winreg.OpenKey(1234567, "MY_SECRET_KEY")
|
||||
print("Result = " + hex(v.handle))
|
||||
|
||||
print("")
|
||||
print("Asking for <MY_FAIL_KEY>")
|
||||
try:
|
||||
v = _winreg.OpenKey(1234567, "MY_FAIL_KEY")
|
||||
@@ -55,6 +56,7 @@ try:
|
||||
except WindowsError as e:
|
||||
print(repr(e))
|
||||
|
||||
print("")
|
||||
print("Asking for <HKEY_CURRENT_USER/Software>")
|
||||
try:
|
||||
v = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software")
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import sys
|
||||
import os.path
|
||||
import pprint
|
||||
sys.path.append(os.path.abspath(__file__ + "\..\.."))
|
||||
|
||||
import windows
|
||||
|
||||
registry = windows.system.registry
|
||||
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("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 for the JIT Debugger")
|
||||
|
||||
jit_debug_key = registry["HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug"]
|
||||
|
||||
print("Key is {0}".format(jit_debug_key))
|
||||
|
||||
print("values are: {0}".format(pprint.pprint(jit_debug_key.values)))
|
||||
|
||||
print()
|
||||
@@ -27,3 +27,16 @@ import windows.wmi
|
||||
import windows.utils
|
||||
|
||||
__all__ = ["system", "VirtualProtected", 'current_process', 'current_thread', 'winproxy']
|
||||
|
||||
import os
|
||||
|
||||
if bool(os.environ.get("SPHINX_BUILD", 0)):
|
||||
# I know it's shameful
|
||||
# But it's the only way I can think of right know to get a full class
|
||||
# of PEFile for documentation purpose u_u
|
||||
|
||||
ppe = windows.current_process.peb.modules[0].pe
|
||||
windows.pe_parse.PEFile = type(ppe)
|
||||
iat_entry = ppe.imports.values()[0][0]
|
||||
windows.pe_parse.IATEntry = type(iat_entry)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ HCERTSTORE = PVOID
|
||||
HCRYPTMSG = PVOID
|
||||
VOID = DWORD
|
||||
|
||||
structs = ['_LIST_ENTRY', '_PEB_LDR_DATA', '_LSA_UNICODE_STRING', '_RTL_USER_PROCESS_PARAMETERS', '_PEB', '_SECURITY_ATTRIBUTES', '_SYSTEM_VERIFIER_INFORMATION', '_LDR_DATA_TABLE_ENTRY', '_IMAGE_FILE_HEADER', '_IMAGE_DATA_DIRECTORY', '_IMAGE_SECTION_HEADER', '_IMAGE_OPTIONAL_HEADER64', '_IMAGE_OPTIONAL_HEADER', '_IMAGE_NT_HEADERS64', '_IMAGE_NT_HEADERS', '_IMAGE_IMPORT_DESCRIPTOR', '_IMAGE_IMPORT_BY_NAME', '_IMAGE_EXPORT_DIRECTORY', '_MEMORY_BASIC_INFORMATION', '_MEMORY_BASIC_INFORMATION32', '_MEMORY_BASIC_INFORMATION64', '_STARTUPINFOA', '_STARTUPINFOW', '_PROCESS_INFORMATION', '_FLOATING_SAVE_AREA', '_CONTEXT32', '_WOW64_FLOATING_SAVE_AREA', '_WOW64_CONTEXT', '_M128A', '_CONTEXT64', 'tagPROCESSENTRY32W', 'tagPROCESSENTRY32', 'tagTHREADENTRY32', '_LUID', '_LUID_AND_ATTRIBUTES', '_TOKEN_PRIVILEGES', '_TOKEN_ELEVATION', '_OSVERSIONINFOA', '_OSVERSIONINFOW', '_OSVERSIONINFOEXA', '_OSVERSIONINFOEXW', '_OVERLAPPED', '_MIB_TCPROW_OWNER_PID', '_MIB_TCPTABLE_OWNER_PID', '_MIB_UDPROW_OWNER_PID', '_MIB_UDPTABLE_OWNER_PID', '_MIB_UDP6ROW_OWNER_PID', '_MIB_UDP6TABLE_OWNER_PID', '_MIB_TCP6ROW_OWNER_PID', '_MIB_TCP6TABLE_OWNER_PID', '_MIB_TCPROW', '_EXCEPTION_RECORD', '_EXCEPTION_RECORD32', '_EXCEPTION_RECORD64', '_EXCEPTION_POINTERS64', '_EXCEPTION_POINTERS32', '_DEBUG_PROCESSOR_IDENTIFICATION_ALPHA', '_DEBUG_PROCESSOR_IDENTIFICATION_AMD64', '_DEBUG_PROCESSOR_IDENTIFICATION_IA64', '_DEBUG_PROCESSOR_IDENTIFICATION_X86', '_DEBUG_PROCESSOR_IDENTIFICATION_ARM', '_DEBUG_PROCESSOR_IDENTIFICATION_ALL', '_SYMBOL_INFO', '_MODLOAD_DATA', '_SYSTEM_MODULE32', '_SYSTEM_MODULE64', '_SYSTEM_MODULE_INFORMATION32', '_SYSTEM_MODULE_INFORMATION64', 'tagSAFEARRAYBOUND', 'tagSAFEARRAY', '_DEBUG_BREAKPOINT_PARAMETERS', '_DEBUG_REGISTER_DESCRIPTION', '_DEBUG_STACK_FRAME', '_DEBUG_LAST_EVENT_INFO_BREAKPOINT', '_DEBUG_LAST_EVENT_INFO_EXCEPTION', '_DEBUG_LAST_EVENT_INFO_EXIT_THREAD', '_DEBUG_LAST_EVENT_INFO_EXIT_PROCESS', '_DEBUG_LAST_EVENT_INFO_LOAD_MODULE', '_DEBUG_LAST_EVENT_INFO_UNLOAD_MODULE', '_DEBUG_LAST_EVENT_INFO_SYSTEM_ERROR', '_DEBUG_SPECIFIC_FILTER_PARAMETERS', '_DEBUG_EXCEPTION_FILTER_PARAMETERS', '_GUID', '_CRYPTOAPI_BLOB', 'WINTRUST_FILE_INFO_', '_CRYPT_ATTRIBUTE', '_CTL_ENTRY', '_CRYPT_ATTRIBUTE', '_CRYPT_ATTRIBUTES', '_CRYPT_ALGORITHM_IDENTIFIER', '_CMSG_SIGNER_INFO', '_CERT_EXTENSION', '_CTL_USAGE', '_CTL_INFO', '_CTL_CONTEXT', 'WINTRUST_CATALOG_INFO_', 'WINTRUST_BLOB_INFO_', '_CRYPT_BIT_BLOB', '_CERT_PUBLIC_KEY_INFO', '_CERT_INFO', '_CERT_CONTEXT', 'WINTRUST_SGNR_INFO_', '_FILETIME', 'WINTRUST_CERT_INFO_', '_TMP_WINTRUST_UNION_TYPE', '_WINTRUST_DATA', '_PROCESS_BASIC_INFORMATION']
|
||||
structs = ['_LIST_ENTRY', '_PEB_LDR_DATA', '_LSA_UNICODE_STRING', '_RTL_USER_PROCESS_PARAMETERS', '_PEB', '_SECURITY_ATTRIBUTES', '_SYSTEM_VERIFIER_INFORMATION', '_LDR_DATA_TABLE_ENTRY', '_IMAGE_FILE_HEADER', '_IMAGE_DATA_DIRECTORY', '_IMAGE_SECTION_HEADER', '_IMAGE_OPTIONAL_HEADER64', '_IMAGE_OPTIONAL_HEADER', '_IMAGE_NT_HEADERS64', '_IMAGE_NT_HEADERS', '_IMAGE_IMPORT_DESCRIPTOR', '_IMAGE_IMPORT_BY_NAME', '_IMAGE_EXPORT_DIRECTORY', '_MEMORY_BASIC_INFORMATION', '_MEMORY_BASIC_INFORMATION32', '_MEMORY_BASIC_INFORMATION64', '_STARTUPINFOA', '_STARTUPINFOW', '_PROCESS_INFORMATION', '_FLOATING_SAVE_AREA', '_CONTEXT32', '_WOW64_FLOATING_SAVE_AREA', '_WOW64_CONTEXT', '_M128A', '_CONTEXT64', 'tagPROCESSENTRY32W', 'tagPROCESSENTRY32', 'tagTHREADENTRY32', '_LUID', '_LUID_AND_ATTRIBUTES', '_TOKEN_PRIVILEGES', '_TOKEN_ELEVATION', '_OSVERSIONINFOA', '_OSVERSIONINFOW', '_OSVERSIONINFOEXA', '_OSVERSIONINFOEXW', '_OVERLAPPED', '_MIB_TCPROW_OWNER_PID', '_MIB_TCPTABLE_OWNER_PID', '_MIB_UDPROW_OWNER_PID', '_MIB_UDPTABLE_OWNER_PID', '_MIB_UDP6ROW_OWNER_PID', '_MIB_UDP6TABLE_OWNER_PID', '_MIB_TCP6ROW_OWNER_PID', '_MIB_TCP6TABLE_OWNER_PID', '_MIB_TCPROW', '_EXCEPTION_RECORD', '_EXCEPTION_RECORD32', '_EXCEPTION_RECORD64', '_EXCEPTION_POINTERS64', '_EXCEPTION_POINTERS32', '_DEBUG_PROCESSOR_IDENTIFICATION_ALPHA', '_DEBUG_PROCESSOR_IDENTIFICATION_AMD64', '_DEBUG_PROCESSOR_IDENTIFICATION_IA64', '_DEBUG_PROCESSOR_IDENTIFICATION_X86', '_DEBUG_PROCESSOR_IDENTIFICATION_ARM', '_DEBUG_PROCESSOR_IDENTIFICATION_ALL', '_SYMBOL_INFO', '_MODLOAD_DATA', '_SYSTEM_MODULE32', '_SYSTEM_MODULE64', '_SYSTEM_MODULE_INFORMATION32', '_SYSTEM_MODULE_INFORMATION64', 'tagSAFEARRAYBOUND', 'tagSAFEARRAY', '_DEBUG_BREAKPOINT_PARAMETERS', '_DEBUG_REGISTER_DESCRIPTION', '_DEBUG_STACK_FRAME', '_DEBUG_LAST_EVENT_INFO_BREAKPOINT', '_DEBUG_LAST_EVENT_INFO_EXCEPTION', '_DEBUG_LAST_EVENT_INFO_EXIT_THREAD', '_DEBUG_LAST_EVENT_INFO_EXIT_PROCESS', '_DEBUG_LAST_EVENT_INFO_LOAD_MODULE', '_DEBUG_LAST_EVENT_INFO_UNLOAD_MODULE', '_DEBUG_LAST_EVENT_INFO_SYSTEM_ERROR', '_DEBUG_SPECIFIC_FILTER_PARAMETERS', '_DEBUG_EXCEPTION_FILTER_PARAMETERS', '_GUID', '_CRYPTOAPI_BLOB', 'WINTRUST_FILE_INFO_', '_CRYPT_ATTRIBUTE', '_CTL_ENTRY', '_CRYPT_ATTRIBUTE', '_CRYPT_ATTRIBUTES', '_CRYPT_ALGORITHM_IDENTIFIER', '_CMSG_SIGNER_INFO', '_CERT_EXTENSION', '_CTL_USAGE', '_CTL_INFO', '_CTL_CONTEXT', 'WINTRUST_CATALOG_INFO_', 'WINTRUST_BLOB_INFO_', '_CRYPT_BIT_BLOB', '_CERT_PUBLIC_KEY_INFO', '_CERT_INFO', '_CERT_CONTEXT', 'WINTRUST_SGNR_INFO_', '_FILETIME', 'WINTRUST_CERT_INFO_', '_TMP_WINTRUST_UNION_TYPE', '_WINTRUST_DATA', '_PROCESS_BASIC_INFORMATION', '_JIT_DEBUG_INFO']
|
||||
|
||||
enums = ['_SYSTEM_INFORMATION_CLASS', '_MEMORY_INFORMATION_CLASS', '_THREAD_INFORMATION_CLASS', '_TCP_TABLE_CLASS', '_VARENUM', '_UDP_TABLE_CLASS', '_MIB_TCP_STATE', '_TOKEN_INFORMATION_CLASS', '_IMAGEHLP_SYMBOL_TYPE_INFO', '_PROCESSINFOCLASS']
|
||||
|
||||
@@ -1881,3 +1881,17 @@ class _PROCESS_BASIC_INFORMATION(Structure):
|
||||
PPROCESS_BASIC_INFORMATION = POINTER(_PROCESS_BASIC_INFORMATION)
|
||||
PROCESS_BASIC_INFORMATION = _PROCESS_BASIC_INFORMATION
|
||||
|
||||
# Struct _JIT_DEBUG_INFO definitions
|
||||
class _JIT_DEBUG_INFO(Structure):
|
||||
_fields_ = [
|
||||
("dwSize", DWORD),
|
||||
("dwProcessorArchitecture", DWORD),
|
||||
("dwThreadID", DWORD),
|
||||
("dwReserved0", DWORD),
|
||||
("lpExceptionAddress", ULONG64),
|
||||
("lpExceptionRecord", ULONG64),
|
||||
("lpContextRecord", ULONG64),
|
||||
]
|
||||
LPJIT_DEBUG_INFO = POINTER(_JIT_DEBUG_INFO)
|
||||
JIT_DEBUG_INFO = _JIT_DEBUG_INFO
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from .generated_def.winstructs import *
|
||||
|
||||
|
||||
class Callback(object):
|
||||
"""Give type information to hook callback"""
|
||||
def __init__(self, *types):
|
||||
self.types = types
|
||||
|
||||
@@ -66,11 +67,13 @@ class IATHook(object):
|
||||
return res
|
||||
|
||||
def enable(self):
|
||||
"""Enable the IAT hook"""
|
||||
with utils.VirtualProtected(self.entry.addr, ctypes.sizeof(PVOID), PAGE_EXECUTE_READWRITE):
|
||||
self.entry.value = self.stub
|
||||
self.is_enable = True
|
||||
|
||||
def disable(self):
|
||||
"""Disable the IAT hook"""
|
||||
with utils.VirtualProtected(self.entry.addr, ctypes.sizeof(PVOID), PAGE_EXECUTE_READWRITE):
|
||||
self.entry.value = self.entry.nonhookvalue
|
||||
self.is_enable = False
|
||||
|
||||
+35
-4
@@ -47,7 +47,12 @@ def get_structure_transformer_for_target(target):
|
||||
return ctypes_structure_transformer, create_structure_at
|
||||
|
||||
|
||||
def PEFile(baseaddr, target=None):
|
||||
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
|
||||
|
||||
:rtype: :class:`PEFile`
|
||||
"""
|
||||
proc_bitness = windows.current_process.bitness
|
||||
if target is None:
|
||||
targetedbitness = proc_bitness
|
||||
@@ -100,9 +105,14 @@ def PEFile(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
|
||||
"""
|
||||
_fields_ = [
|
||||
("value", PVOID)]
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def create(cls, addr, ord, name):
|
||||
self = create_structure_at(cls, addr)
|
||||
@@ -117,12 +127,25 @@ def PEFile(baseaddr, target=None):
|
||||
return '<{0} "{1}" ordinal {2}>'.format(self.__class__.__name__, self.name, self.ord)
|
||||
|
||||
def set_hook(self, callback, types=None):
|
||||
"""Setup a hook on the entry and return it.
|
||||
|
||||
:param callback: the hook
|
||||
|
||||
.. note::
|
||||
|
||||
see :ref:`hook_protocol`
|
||||
|
||||
:rtype: :class:`windows.hooks.IATHook`
|
||||
"""
|
||||
|
||||
|
||||
hook = hooks.IATHook(self, callback, types)
|
||||
self.hook = hook
|
||||
hook.enable()
|
||||
return hook
|
||||
|
||||
def remove_hook(self):
|
||||
"""Remove the hook on the entry"""
|
||||
if self.hook is None:
|
||||
return False
|
||||
self.hook.disable()
|
||||
@@ -130,6 +153,7 @@ def PEFile(baseaddr, target=None):
|
||||
return True
|
||||
|
||||
class PEFile(object):
|
||||
"""Represent a PE loaded in a process (current or remote)"""
|
||||
def __init__(self):
|
||||
self.baseaddr = baseaddr
|
||||
|
||||
@@ -183,6 +207,10 @@ def PEFile(baseaddr, target=None):
|
||||
|
||||
@utils.fixedpropety
|
||||
def exports(self):
|
||||
"""The exports of the PE in a dict. Keys are ordinal (:class:`int`) and name (:class:`str`).
|
||||
The values are the addresses of the exports.
|
||||
|
||||
:type: {(:class:`int` or :class:`str`) : :class:`int`}"""
|
||||
res = {}
|
||||
exp_dir = self.get_EXPORT_DIRECTORY()
|
||||
if exp_dir is None:
|
||||
@@ -197,6 +225,11 @@ def PEFile(baseaddr, target=None):
|
||||
# TODO: get imports by parsing other modules exports if no INT
|
||||
@utils.fixedpropety
|
||||
def imports(self):
|
||||
"""The imports of the PE in a dict.
|
||||
Keys are the names of DLL to import from and values are :class:`list`
|
||||
of :class:`IATEntry`
|
||||
|
||||
:type: {:class:`str` : [:class:`IATEntry`]}"""
|
||||
res = {}
|
||||
for import_descriptor in self.get_IMPORT_DESCRIPTORS():
|
||||
INT = import_descriptor.get_INT()
|
||||
@@ -292,6 +325,4 @@ def PEFile(baseaddr, target=None):
|
||||
return create_structure_at(IMAGE_NT_HEADERS32, baseaddr + self.e_lfanew)
|
||||
return create_structure_at(IMAGE_NT_HEADERS64, baseaddr + self.e_lfanew)
|
||||
|
||||
return current_pe
|
||||
|
||||
tst = PEFile.__code__.co_consts[13]
|
||||
return current_pe
|
||||
+3
-1
@@ -40,6 +40,7 @@ class PyHKey(object):
|
||||
|
||||
@property
|
||||
def subkeys(self):
|
||||
"""The subkeys of the registry key"""
|
||||
res = []
|
||||
with ExpectWindowsError(259):
|
||||
for i in itertools.count():
|
||||
@@ -48,6 +49,7 @@ class PyHKey(object):
|
||||
|
||||
@property
|
||||
def values(self):
|
||||
"""The values of the registry key"""
|
||||
res = []
|
||||
with ExpectWindowsError(259):
|
||||
for i in itertools.count():
|
||||
@@ -78,7 +80,7 @@ HKEY_USERS = PyHKey(DummyPHKEY(_winreg.HKEY_USERS, "HKEY_USERS"), "", _winreg.KE
|
||||
|
||||
|
||||
class Registry(object):
|
||||
"""The ``Windows`` registry: a read only mapping"""
|
||||
"""The ``Windows`` registry: a read only (for now) mapping"""
|
||||
|
||||
registry_base_keys = {
|
||||
"HKEY_LOCAL_MACHINE" : HKEY_LOCAL_MACHINE,
|
||||
|
||||
@@ -685,7 +685,7 @@ class LoadedModule(LDR_DATA_TABLE_ENTRY):
|
||||
|
||||
:type: :class:`windows.pe_parse.PEFile`
|
||||
"""
|
||||
return pe_parse.PEFile(self.baseaddr)
|
||||
return pe_parse.GetPEFile(self.baseaddr)
|
||||
|
||||
|
||||
class WinUnicodeString(LSA_UNICODE_STRING):
|
||||
@@ -760,7 +760,7 @@ class RemoteLoadedModule(rctypes.RemoteStructure.from_structure(LoadedModule)):
|
||||
|
||||
:type: :class:`windows.pe_parse.PEFile`
|
||||
"""
|
||||
return pe_parse.PEFile(self.baseaddr, target=self._target)
|
||||
return pe_parse.GetPEFile(self.baseaddr, target=self._target)
|
||||
|
||||
|
||||
class RemotePEB(rctypes.RemoteStructure.from_structure(PEB)):
|
||||
@@ -793,7 +793,7 @@ if CurrentProcess().bitness == 32:
|
||||
|
||||
:type: :class:`windows.pe_parse.PEFile`
|
||||
"""
|
||||
return pe_parse.PEFile(self.baseaddr, target=self._target)
|
||||
return pe_parse.GetPEFile(self.baseaddr, target=self._target)
|
||||
|
||||
class RemotePEB64(rctypes.transform_type_to_remote64bits(PEB)):
|
||||
|
||||
@@ -825,7 +825,7 @@ if CurrentProcess().bitness == 64:
|
||||
|
||||
:type: :class:`windows.pe_parse.PEFile`
|
||||
"""
|
||||
return pe_parse.PEFile(self.baseaddr, target=self._target)
|
||||
return pe_parse.GetPEFile(self.baseaddr, target=self._target)
|
||||
|
||||
class RemotePEB32(rctypes.transform_type_to_remote32bits(PEB)):
|
||||
|
||||
|
||||
+4
-1
@@ -38,7 +38,10 @@ WTD_STATEACTION_AUTO_CACHE = 0x00000003
|
||||
WTD_STATEACTION_AUTO_CACHE_FLUSH = 0x00000004
|
||||
|
||||
def check_signature(filename):
|
||||
print("Filename is <{0}>".format(repr(filename)))
|
||||
"""Check if ``filename`` is a valid signed file
|
||||
|
||||
:return: 0 if file have a valid signature
|
||||
"""
|
||||
file_data = WINTRUST_FILE_INFO()
|
||||
file_data.cbStruct = ctypes.sizeof(WINTRUST_FILE_INFO)
|
||||
file_data.pcwszFilePath = filename
|
||||
|
||||
@@ -111,6 +111,7 @@ class SimpleVariant(ctypes.Structure):
|
||||
return bool(self.aslong)
|
||||
|
||||
class WmiRequester(object):
|
||||
"""Perform WMI request: NOT STABLE"""
|
||||
INSTANCE = None
|
||||
def __new__(cls):
|
||||
if cls.INSTANCE is not None:
|
||||
@@ -136,6 +137,10 @@ class WmiRequester(object):
|
||||
|
||||
|
||||
def select(self, frm, attrs):
|
||||
"""Select `attrs` from ``frm``
|
||||
|
||||
:rtype: list of dict
|
||||
"""
|
||||
enumerator = IEnumWbemClassObject()
|
||||
self.service.ExecQuery("WQL", "select * from {0}".format(frm), 0x20, 0, ctypes.byref(enumerator))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user