diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..417ebd4 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +* Hakril \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..76e811a --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# 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. +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. + + +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. + +You can find some examples of code in the `sample/` directory. + +## Overview + +### Processes / Threads + +PythonForWindows offer a object oriented around processes of the system and allow you to: + - Retrieve basic process informations (pid, name, ppid, bitness, ...) + - Perform basic interprocess operation (alloc, 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. +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) + + +### IAT Hook + +This codebase is born from my need to have IAT hooks implemented in Python. +So the features is present (see `sample`) + + +### Winproxy + +A pythonic 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 +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 + +Some code are just exploration and need improvement like: + - Wintrust + - WMI + - Registry access + - Exception + diff --git a/TODO b/TODO new file mode 100644 index 0000000..56be531 --- /dev/null +++ b/TODO @@ -0,0 +1,8 @@ +TODO: + - ProcessMemory object ? (metasm like) + +FIXME: + - WMI + - COM initialisation when injected in another process + - The CoInitialize might be already called + - Fix that \ No newline at end of file diff --git a/windows/winproxy.py b/windows/winproxy.py index 724e460..318f49b 100644 --- a/windows/winproxy.py +++ b/windows/winproxy.py @@ -27,7 +27,6 @@ class Kernel32Error(WindowsError): class IphlpapiError(Kernel32Error): - def __new__(cls, func_name, code): win_error = ctypes.WinError(code) api_error = super(Kernel32Error, cls).__new__(cls) @@ -146,6 +145,11 @@ class Advapi32Proxy(ApiProxy): default_error_check = staticmethod(kernel32_error_check) +class User32Proxy(ApiProxy): + APIDLL = "user32" + default_error_check = staticmethod(kernel32_error_check) + + class IphlpapiProxy(ApiProxy): APIDLL = "iphlpapi" default_error_check = staticmethod(iphlpapi_error_check) @@ -199,6 +203,7 @@ class TransparentApiProxy(object): TransparentKernel32Proxy = lambda func_name, error_check=kernel32_error_check: TransparentApiProxy("kernel32", func_name, error_check) TransparentAdvapi32Proxy = lambda func_name, error_check=kernel32_error_check: TransparentApiProxy("advapi32", func_name, error_check) +TransparentUser32Proxy = lambda func_name, error_check=kernel32_error_check: TransparentApiProxy("user32", func_name, error_check) TransparentIphlpapiProxy = lambda func_name, error_check=iphlpapi_error_check: TransparentApiProxy("iphlpapi", func_name, error_check) @@ -238,6 +243,11 @@ VirtualQueryEx = TransparentKernel32Proxy("VirtualQueryEx") GetExitCodeThread = TransparentKernel32Proxy("GetExitCodeThread") GetExitCodeProcess = TransparentKernel32Proxy("GetExitCodeProcess") +GlobalAlloc = TransparentKernel32Proxy("GlobalAlloc") +GlobalFree = TransparentKernel32Proxy("GlobalFree") +GlobalLock = TransparentKernel32Proxy("GlobalLock") +GlobalUnlock = TransparentKernel32Proxy("GlobalUnlock", error_check=no_error_check) + Wow64DisableWow64FsRedirection = OptionalExport(TransparentKernel32Proxy)("Wow64DisableWow64FsRedirection") Wow64RevertWow64FsRedirection = OptionalExport(TransparentKernel32Proxy)("Wow64RevertWow64FsRedirection") Wow64EnableWow64FsRedirection = OptionalExport(TransparentKernel32Proxy)("Wow64EnableWow64FsRedirection") @@ -583,3 +593,24 @@ def GetExtendedTcpTable(pTcpTable, pdwSize=None, bOrder=True, ulAf=NeededParamet if pdwSize is None: ctypes.sizeof(pTcpTable) return GetExtendedTcpTable.ctypes_function(pTcpTable, pdwSize, bOrder, ulAf, TableClass, Reserved) + + +# User32 # + +EmptyClipboard = TransparentUser32Proxy("EmptyClipboard") +CloseClipboard = TransparentUser32Proxy("CloseClipboard") +SetClipboardData = TransparentUser32Proxy("SetClipboardData") +GetClipboardData = TransparentUser32Proxy("GetClipboardData") +GetClipboardFormatNameA = TransparentUser32Proxy("GetClipboardFormatNameA") +GetClipboardFormatNameW = TransparentUser32Proxy("GetClipboardFormatNameW") + +def check_zero_and_getlasterror(func_name, result, func, args): + if not result and GetLastError() != 0: + raise Kernel32Error(func_name) + return args + +EnumClipboardFormats = TransparentUser32Proxy("EnumClipboardFormats", error_check=check_zero_and_getlasterror) + +@User32Proxy("OpenClipboard") +def OpenClipboard(hWndNewOwner=None): + return OpenClipboard.ctypes_function(hWndNewOwner) \ No newline at end of file