Error_Invalid_Parameter Error 57 when calling CreateRemoteThread with Python 3.2 CTypes

前端 未结 1 1271
面向向阳花
面向向阳花 2020-12-06 08:38

I\'m trying to perform DLL injection using Python\'s Ctypes. I attach Olly to the process that I\'m trying to inject and the thread that I\'m trying to creates gives the er

相关标签:
1条回答
  • 2020-12-06 09:08
    • Use ctypes.get_last_error instead of GetLastError. This requires the use_last_error option, e.g. WinDLL('kernel32.dll', use_last_error=True).
    • The GetModuleHandleW and GetProcAddress steps are unnecessary. ctypes already does this for you. Just use kernel32.LoadLibraryW. This depends on kernel32.dll always being mapped to the same base address in each process, which I think is true for existing versions of Windows.
    • In general you should factor in the null terminator when copying a string, e.g. use len(dll_path) + 1. In this case you're committing a new page of memory (4 KiB on x86 and x64 systems), which is initially all zeros.
    • I'm not sure how you've defined the VIRTUAL_MEM allocation type. Does that include MEM_COMMIT?
    • Watch out for spelling errors. You wrote retype instead of restype for the prototype of CreateRemoteThread, which means the return value is still the default 32-bit C int.

    The following works for me, loading a DLL into a Python process.

    dllinject.py (ctypes defintions):

    import ctypes
    from ctypes import wintypes
    
    kernel32 = ctypes.WinDLL('kernel32.dll', use_last_error=True)
    
    PROCESS_VM_OPERATION = 0x0008
    PROCESS_VM_WRITE = 0x0020
    PROCESS_CREATE_THREAD = 0x0002
    MEM_COMMIT = 0x1000
    MEM_RELEASE = 0x8000
    PAGE_READWRITE = 0x0004
    INFINITE = -1
    
    SIZE_T = ctypes.c_size_t
    LPSIZE_T = ctypes.POINTER(SIZE_T)
    WCHAR_SIZE = ctypes.sizeof(wintypes.WCHAR)
    LPSECURITY_ATTRIBUTES = wintypes.LPVOID
    LPTHREAD_START_ROUTINE = wintypes.LPVOID
    
    class BOOL_CHECKED(ctypes._SimpleCData):
        _type_ = "l"
        def _check_retval_(retval):
            if retval == 0:
                raise ctypes.WinError(ctypes.get_last_error())
            return retval
    
    class LPVOID_CHECKED(ctypes._SimpleCData):
        _type_ = "P"
        def _check_retval_(retval):
            if retval is None:
                raise ctypes.WinError(ctypes.get_last_error())
            return retval
    
    HANDLE_CHECKED = LPVOID_CHECKED  # not file handles
    
    kernel32.OpenProcess.restype = HANDLE_CHECKED
    kernel32.OpenProcess.argtypes = (
        wintypes.DWORD, # dwDesiredAccess
        wintypes.BOOL,  # bInheritHandle
        wintypes.DWORD) # dwProcessId
    
    kernel32.VirtualAllocEx.restype = LPVOID_CHECKED
    kernel32.VirtualAllocEx.argtypes = (
        wintypes.HANDLE, # hProcess
        wintypes.LPVOID, # lpAddress
        SIZE_T,          # dwSize
        wintypes.DWORD,  # flAllocationType
        wintypes.DWORD)  # flProtect
    
    kernel32.VirtualFreeEx.argtypes = (
        wintypes.HANDLE, # hProcess
        wintypes.LPVOID, # lpAddress
        SIZE_T,          # dwSize
        wintypes.DWORD)  # dwFreeType
    
    kernel32.WriteProcessMemory.restype = BOOL_CHECKED
    kernel32.WriteProcessMemory.argtypes = (
        wintypes.HANDLE,  # hProcess
        wintypes.LPVOID,  # lpBaseAddress
        wintypes.LPCVOID, # lpBuffer
        SIZE_T,           # nSize
        LPSIZE_T)         # lpNumberOfBytesWritten _Out_
    
    kernel32.CreateRemoteThread.restype = HANDLE_CHECKED
    kernel32.CreateRemoteThread.argtypes = (
        wintypes.HANDLE,        # hProcess
        LPSECURITY_ATTRIBUTES,  # lpThreadAttributes
        SIZE_T,                 # dwStackSize
        LPTHREAD_START_ROUTINE, # lpStartAddress
        wintypes.LPVOID,        # lpParameter
        wintypes.DWORD,         # dwCreationFlags
        wintypes.LPDWORD)       # lpThreadId _Out_
    
    kernel32.WaitForSingleObject.argtypes = (
        wintypes.HANDLE, # hHandle
        wintypes.DWORD)  # dwMilliseconds
    
    kernel32.CloseHandle.argtypes = (
        wintypes.HANDLE,) # hObject
    

    dllinject.py (injectdll):

    def injectdll(pid, dllpath):
        size = (len(dllpath) + 1) * WCHAR_SIZE
        hproc = hthrd = addr = None
        try:
            hproc = kernel32.OpenProcess(
                PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
                PROCESS_VM_WRITE, False, pid)
            addr = kernel32.VirtualAllocEx(
                hproc, None, size, MEM_COMMIT, PAGE_READWRITE)
            kernel32.WriteProcessMemory(
                hproc, addr, dllpath, size, None)
            hthrd = kernel32.CreateRemoteThread(
                hproc, None, 0, kernel32.LoadLibraryW, addr, 0, None)
            kernel32.WaitForSingleObject(hthrd, INFINITE)
        finally:
            if addr is not None:
                kernel32.VirtualFreeEx(hproc, addr, 0, MEM_RELEASE)
            if hthrd is not None:
                kernel32.CloseHandle(hthrd)
            if hproc is not None:
                kernel32.CloseHandle(hproc)
    

    test.c:

    #include <Windows.h>                  
    #include <stdio.h>                 
    
    BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, PVOID fImpLoad)
    {                                                
        switch (fdwReason) {
            case DLL_PROCESS_ATTACH:
                printf("DLL Attach\n");
                break;
            case DLL_PROCESS_DETACH:
                printf("DLL Detach\n");
        }                                                        
        return TRUE;               
    }
    

    demo:

    >>> import sys
    >>> from subprocess import Popen, PIPE
    >>> from dllinject import injectdll
    >>> cmd = [sys.executable, '-c', 'import time; time.sleep(10)']
    >>> p = Popen(cmd, stdout=PIPE); injectdll(p.pid, 'test.dll')
    >>> r = p.wait(); print(p.stdout.read().decode())
    DLL Attach
    DLL Detach
    
    0 讨论(0)
提交回复
热议问题