Error_Invalid_Parameter Error 57 when calling CreateRemoteThread with Python 3.2 CTypes

安稳与你 提交于 2019-11-27 23:22:26
  • 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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!