Adding more and more documentation

This commit is contained in:
Clement Rouault
2016-01-06 20:11:20 +01:00
parent b2eede98b1
commit 9c8a4dcfad
22 changed files with 467 additions and 30 deletions
+2 -1
View File
@@ -1 +1,2 @@
*.pyc
*.pyc
doc/build
+1
View File
@@ -1,6 +1,7 @@
TODO:
- Documentation
- ProcessMemory object ? (metasm like)
- Extend Registry feature (write + read 1 key)
FIXME:
- WMI
+11 -1
View File
@@ -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;
+2
View File
@@ -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 ------------------------------------------------
+113
View File
@@ -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
+3
View File
@@ -17,6 +17,9 @@ Contents:
utils.rst
native_exec.rst
various.rst
iat_hook.rst
wip.rst
internals.rst
sample.rst
+122
View File
@@ -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
+3 -2
View File
@@ -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
View File
@@ -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`
+25
View File
@@ -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
View File
@@ -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`
+25
View File
@@ -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
View File
@@ -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")
+28
View File
@@ -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()
+13
View File
@@ -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)
+15 -1
View File
@@ -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
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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,
+4 -4
View File
@@ -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
View File
@@ -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
+5
View File
@@ -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))