Snippets

Richard Yu VCMP Launcher

Created by Richard Yu last modified
void LaunchSteamVCMP(const char* IP, uint16_t port, const char* playerName, const char* password, const wchar_t* gtaExe, const wchar_t* vcmpDll)
{
    wchar_t commandLine[128];
    if (password != nullptr)
        swprintf_s(commandLine, std::size(commandLine), L"-c -h %hs -c -p %hu -n %hs -z %hs", IP, port, playerName, password);
    else
        swprintf_s(commandLine, std::size(commandLine), L"-c -h %hs -c -p %hu -n %hs", IP, port, playerName);

    // Get GTA directory.
    wchar_t GTADriectory[MAX_PATH];
    wcscpy_s(GTADriectory, MAX_PATH, gtaExe);
    wchar_t *pos = wcsrchr(GTADriectory, '\\');
    if (pos)
        pos[1] = 0;

    // Create GTA process.
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    if (CreateProcess(gtaExe, commandLine, nullptr, nullptr, FALSE, CREATE_SUSPENDED, nullptr, GTADriectory, &si, &pi))
    {
        // Alloc memory in GTA process.
        size_t dllLength = (wcslen(vcmpDll) + 1) * sizeof(wchar_t);
        size_t dataLength = dllLength + 19; // 19 = sizeof(code)
        LPVOID lpMem = VirtualAllocEx(pi.hProcess, nullptr, dataLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if (lpMem)
        {
            // Get kernel32.dll handle.
            HMODULE hKernel = GetModuleHandle(L"kernel32.dll");
            if (hKernel)
            {
                // Get LoadLibraryW address.
                FARPROC fnLoadLibraryW = GetProcAddress(hKernel, "LoadLibraryW");
                if (fnLoadLibraryW)
                {
                    uint8_t code[19];
                    code[0] = 0x68; *(int*)&code[1] = (int)lpMem + sizeof(code);				// push lpMem + 19
                    code[5] = 0xE8; *(int*)&code[6] = (int)fnLoadLibraryW - (int)lpMem - 10;	// call kernel32.LoadLibraryW
                    code[10] = 0x58; // pop eax ; get the OEP
                    code[11] = 0x5D; // pop ebp
                    code[12] = 0x5F; // pop edi
                    code[13] = 0x5E; // pop esi
                    code[14] = 0x5A; // pop edx
                    code[15] = 0x59; // pop ecx
                    code[16] = 0x5B; // pop ebx
                    code[17] = 0xFF; code[18] = 0xE0; // jmp eax ; jump to OEP

                    // Wirte mechine code to GTA process.
                    if (WriteProcessMemory(pi.hProcess, lpMem, code, sizeof(code), nullptr))
                    {
                        // Wirte VCMP dll path to GTA process.
                        if (WriteProcessMemory(pi.hProcess, (LPVOID)((size_t)lpMem + sizeof(code)), vcmpDll, dllLength, nullptr))
                        {
                            // CRC Check 00A405A5 74 07 je short testapp.00A405AE
                            // je->jmp 74->EB
                            DWORD oldProtect;
                            if (VirtualProtectEx(pi.hProcess, (LPVOID)0xA405A5, 1, PAGE_EXECUTE_READWRITE, &oldProtect))
                            {
                                static const uint8_t opcode = 0xEB;

                                BOOL success = WriteProcessMemory(pi.hProcess, (LPVOID)0xA405A5, &opcode, 1, nullptr);
                                VirtualProtectEx(pi.hProcess, (LPVOID)0xA405A5, 1, oldProtect, &oldProtect);

                                if (success)
                                {
                                    if (VirtualProtectEx(pi.hProcess, (LPVOID)0xA41298, 6, PAGE_EXECUTE_READWRITE, &oldProtect))
                                    {
                                        uint8_t code2[6];
                                        code2[0] = 0x50; // push eax ; save the OEP
                                        code2[1] = 0xB8; *(int*)&code2[2] = (int)lpMem; // mov eax,lpMem
                                        // The next code is "jmp eax", our code will be executed first.

                                        success = WriteProcessMemory(pi.hProcess, (LPVOID)0xA41298, code2, sizeof(code2), nullptr);
                                        VirtualProtectEx(pi.hProcess, (LPVOID)0xA41298, 6, oldProtect, &oldProtect);

                                        if (success)
                                        {
                                            ResumeThread(pi.hThread);
                                        }
                                        else
                                            MessageBoxPrintError(g_hMainWnd, L"WriteProcessMemory failed! (%u)", GetLastError());

                                    }
                                    else
                                        MessageBoxPrintError(g_hMainWnd, L"VirtualProtectEx failed! (%u)", GetLastError());
                                }
                                else
                                    MessageBoxPrintError(g_hMainWnd, L"WriteProcessMemory failed! (%u)", GetLastError());
                            }
                            else
                                MessageBoxPrintError(g_hMainWnd, L"VirtualProtectEx failed! (%u)", GetLastError());

                        }
                        else
                            MessageBoxPrintError(g_hMainWnd, L"WriteProcessMemory failed! (%u)", GetLastError());
                    }
                    else
                        MessageBoxPrintError(g_hMainWnd, L"WriteProcessMemory failed! (%u)", GetLastError());
                }
                else
                    MessageBoxPrintError(g_hMainWnd, L"GetProcAddress failed! (%u)", GetLastError());
            }
            else
                MessageBoxPrintError(g_hMainWnd, L"GetModuleHandle failed! (%u)", GetLastError());
        }
        else
            MessageBoxPrintError(g_hMainWnd, L"VirtualAllocEx failed! (%u)", GetLastError());

        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    else
        MessageBoxPrintError(g_hMainWnd, L"CreateProcess failed! (%u)", GetLastError());
}
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdbool.h>

#define IP "127.0.0.1"
#define PORT 8192
#define NAME "YSC"
#define PASSWORD "password"

#define GTA_VC_EXE ""
#define VCMP_GAME_DLL ""

int main()
{
    // Process the VCMP command line.
    char commandLine[128];
    bool password = false;
    if (password)
        sprintf_s(commandLine, 128, "-c -h %s -c -p %u -n %s -z %s", IP, PORT, NAME, PASSWORD);
    else
        sprintf_s(commandLine, 128, "-c -h %s -c -p %u -n %s", IP, PORT, NAME);

    // Get GTA directory.
    char GTADriectory[MAX_PATH];
    strcpy_s(GTADriectory, MAX_PATH, GTA_VC_EXE);
    char *pos = strrchr(GTADriectory, '\\');
    if (pos)
        pos[0] = 0;

    // Create GTA process.
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    if (CreateProcess(GTA_VC_EXE, commandLine, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, GTADriectory, &si, &pi))
    {
        // Alloc memory in GTA process.
        size_t dllLength = strlen(VCMP_GAME_DLL) + 1;
        LPVOID lpMem = VirtualAllocEx(pi.hProcess, NULL, dllLength, MEM_COMMIT, PAGE_READWRITE);
        if (lpMem)
        {
            // Wirte VCMP dll path to GTA process.
            if (WriteProcessMemory(pi.hProcess, lpMem, VCMP_GAME_DLL, dllLength, NULL))
            {
                // Get kernel32.dll handle.
                HMODULE hKernel = GetModuleHandle("kernel32.dll");
                if (hKernel)
                {
                    // Get LoadLibraryA address.
                    FARPROC fnLoadLibraryA = GetProcAddress(hKernel, "LoadLibraryA");
                    if (fnLoadLibraryA)
                    {
                        // Create remote thread in GTA process to inject VCMP dll.
                        HANDLE hInjectThread = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)fnLoadLibraryA, lpMem, 0, NULL);
                        if (hInjectThread)
                        {
                            // Wiat for the inject thread.
                            if (WaitForSingleObject(hInjectThread, 10000) == WAIT_OBJECT_0)
                            {
                                ResumeThread(pi.hThread);
                                printf("OK!\n");
                            }
                            else
                                printf("Injected thread hung!\n");

                            CloseHandle(hInjectThread);
                        }
                        else
                            printf("CreateRemoteThread failed! (%u)\n", GetLastError());
                    }
                    else
                        printf("GetProcAddress failed! (%u)\n", GetLastError());
                }
                else
                    printf("GetModuleHandle failed! (%u)\n", GetLastError());
            }
            else
                printf("WriteProcessMemory failed! (%u)\n", GetLastError());

            VirtualFreeEx(pi.hProcess, lpMem, 0, MEM_RELEASE);
        }
        else
            printf("VirtualAllocEx failed! (%u)\n", GetLastError());

        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    else
        printf("CreateProcess failed! (%u)\n", GetLastError());

    return 0;
}

Comments (0)