diff --git a/injector/include/envs.h b/injector/include/envs.h index ea47afc..3c32624 100644 --- a/injector/include/envs.h +++ b/injector/include/envs.h @@ -1,6 +1,6 @@ #pragma once -#define EPFX "__JADEITE_" +#define EPFX L"__JADEITE_" #define ENV_EXE_PATH EPFX"TARGET_EXE_PATH" #define ENV_DLL_PATH EPFX"INJECT_DLL_PATH" diff --git a/injector/include/inject.h b/injector/include/inject.h index aab03c2..82e9888 100644 --- a/injector/include/inject.h +++ b/injector/include/inject.h @@ -2,4 +2,4 @@ #include -void inject(HANDLE process, const void *payload, size_t payloadSize, const char *dllPath); +void inject(HANDLE process, const void *payload, size_t payloadSize, const wchar_t *dllPath); diff --git a/injector/meson.build b/injector/meson.build index 8335fc3..64c6568 100644 --- a/injector/meson.build +++ b/injector/meson.build @@ -34,7 +34,8 @@ executable( 'src/inject.c', exe_res_files, include_directories: include_dir, - name_prefix: '' + name_prefix: '', + link_args: '-municode' ) # Dll that will be injected into the launcher @@ -44,5 +45,6 @@ shared_library( 'src/inject.c', dll_res_files, include_directories: include_dir, - name_prefix: '' + name_prefix: '', + link_args: '-municode' ) diff --git a/injector/src/dll.c b/injector/src/dll.c index bd4d06c..56f9dae 100644 --- a/injector/src/dll.c +++ b/injector/src/dll.c @@ -7,7 +7,7 @@ typedef char *(*wgufn_t)(wchar_t* path); // wine_get_unix_file_name -const char *J_MB_TITLE = "Jadeite Launcher Payload"; +const wchar_t *J_MB_TITLE = L"Jadeite Launcher Payload"; BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { // Only listen for attach @@ -16,30 +16,29 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { } // Get target EXE path - char *targetExe = getenv(ENV_EXE_PATH); + wchar_t targetExe[MAX_PATH]; + GetEnvironmentVariableW(ENV_EXE_PATH, targetExe, MAX_PATH); // Get the path of the DLL to inject - char *injectDll = getenv(ENV_DLL_PATH); + wchar_t injectDll[MAX_PATH]; + GetEnvironmentVariableW(ENV_DLL_PATH, injectDll, MAX_PATH); // Get game commandline - char *cmdline = getenv(ENV_PROC_CMD); + wchar_t cmdline[8192]; + GetEnvironmentVariableW(ENV_PROC_CMD, cmdline, sizeof(cmdline) / sizeof(wchar_t)); // Compute the working directory path - char workdir[MAX_PATH]; - strcpy(workdir, targetExe); - *(strrchr(workdir, '\\')) = '\0'; + wchar_t workdir[MAX_PATH]; + wcscpy(workdir, targetExe); + *(wcsrchr(workdir, '\\')) = '\0'; // SAFETY: verify that the injector is not inside the game directory HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); wgufn_t wine_get_unix_file_name = (wgufn_t)GetProcAddress(kernel32, "wine_get_unix_file_name"); if (wine_get_unix_file_name) { - wchar_t wInjectDll[MAX_PATH], wWorkdir[MAX_PATH]; - MultiByteToWideChar(CP_UTF8, 0, injectDll, strlen(injectDll) + 1, wInjectDll, MAX_PATH); - MultiByteToWideChar(CP_UTF8, 0, workdir, strlen(workdir) + 1, wWorkdir, MAX_PATH); - - char *unixInjectDll = wine_get_unix_file_name(wInjectDll); - char *unixWorkdir = wine_get_unix_file_name(wWorkdir); + char *unixInjectDll = wine_get_unix_file_name(injectDll); + char *unixWorkdir = wine_get_unix_file_name(workdir); char *i = unixInjectDll, *w = unixWorkdir; char startsWith = 0; @@ -55,22 +54,22 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { HeapFree(heap, 0, unixWorkdir); if (startsWith) { - MessageBoxA(NULL, "Putting the patcher (or any other foreign PE binaries) inside the game directory is dangerous! Please move it elsewhere.", J_MB_TITLE, MB_OK | MB_ICONERROR); + MessageBoxW(NULL, L"Putting the patcher (or any other foreign PE binaries) inside the game directory is dangerous! Please move it elsewhere.", J_MB_TITLE, MB_OK | MB_ICONERROR); exit(1); } } else { - MessageBoxA(NULL, "Could not find wine_get_unix_file_name! Wine version too old?", J_MB_TITLE, MB_OK | MB_ICONWARNING); + MessageBoxW(NULL, L"Could not find wine_get_unix_file_name! Wine version too old?", J_MB_TITLE, MB_OK | MB_ICONWARNING); } // Start the game - STARTUPINFO si; + STARTUPINFOW si; ZeroMemory(&si, sizeof(si)); PROCESS_INFORMATION pi; si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); - if (!CreateProcessA( + if (!CreateProcessW( NULL, cmdline, NULL, @@ -82,9 +81,9 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { &si, &pi )) { - char message[64]; - sprintf(message, "Failed to start game process: %ld", GetLastError()); - MessageBoxA(NULL, message, J_MB_TITLE, MB_OK | MB_ICONERROR); + wchar_t message[1024]; + wsprintfW(message, L"Failed to start game process: %ld", GetLastError()); + MessageBoxW(NULL, message, J_MB_TITLE, MB_OK | MB_ICONERROR); exit(1); } @@ -97,9 +96,9 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { // Optional: wait for user input before resuming (useful for debugging) char *waitEnabled = getenv("WAIT_BEFORE_RESUME"); if (waitEnabled && strcmp(waitEnabled, "") != 0) { - char message[64]; - sprintf(message, "PID: %ld. Press OK to continue", pi.dwProcessId); - MessageBoxA(NULL, message, J_MB_TITLE, MB_OK | MB_ICONINFORMATION); + wchar_t message[64]; + wsprintfW(message, L"PID: %ld. Press OK to continue", pi.dwProcessId); + MessageBoxW(NULL, message, J_MB_TITLE, MB_OK | MB_ICONINFORMATION); } // Resume the process diff --git a/injector/src/exe.c b/injector/src/exe.c index 387b337..5d9f12e 100644 --- a/injector/src/exe.c +++ b/injector/src/exe.c @@ -5,28 +5,28 @@ #include -const char LAUNCHER_INJECT_DLL[] = "launcher_payload.dll"; -const char GAME_INJECT_DLL[] = "game_payload.dll"; +const wchar_t *LAUNCHER_INJECT_DLL = L"launcher_payload.dll"; +const wchar_t *GAME_INJECT_DLL = L"game_payload.dll"; #define SHIFT(argc, argv) argc--, argv++ -int main(int argc, char **argv) { +int wmain(int argc, wchar_t **argv) { // Read arguments - char *gamePath = NULL; - char *launcherPath = NULL; + wchar_t *gamePath = NULL; + wchar_t *launcherPath = NULL; // Skip executable SHIFT(argc, argv); switch (argc) { case 0: - printf("Usage: wine jadeite.exe [game path] \n"); + wprintf(L"Usage: wine jadeite.exe [game path] \n"); return 0; case 1: gamePath = argv[0]; SHIFT(argc, argv); - launcherPath = "--"; + launcherPath = L"--"; break; default: @@ -40,57 +40,57 @@ int main(int argc, char **argv) { } // Default launcher path - if (strcmp(launcherPath, "--") == 0) { - printf("No launcher process specified! Using explorer.exe\n"); - launcherPath = "C:\\Windows\\explorer.exe"; + if (wcscmp(launcherPath, L"--") == 0) { + wprintf(L"No launcher process specified! Using explorer.exe\n"); + launcherPath = L"C:\\Windows\\explorer.exe"; } // cd into the injector directory - char injectorPath[MAX_PATH]; - GetModuleFileNameA(GetModuleHandleA(NULL), injectorPath, sizeof(injectorPath)); + wchar_t injectorPath[MAX_PATH]; + GetModuleFileNameW(GetModuleHandleW(NULL), injectorPath, MAX_PATH); - *(strrchr(injectorPath, '\\')) = '\0'; + *(wcsrchr(injectorPath, L'\\')) = L'\0'; - SetCurrentDirectoryA(injectorPath); + SetCurrentDirectoryW(injectorPath); // Compute absolute paths - char gameExePath[MAX_PATH]; - GetFullPathNameA(gamePath, sizeof(gameExePath), gameExePath, NULL); + wchar_t gameExePath[MAX_PATH]; + GetFullPathNameW(gamePath, MAX_PATH, gameExePath, NULL); - char gamePayloadPath[MAX_PATH]; - GetFullPathNameA(GAME_INJECT_DLL, sizeof(gamePayloadPath), gamePayloadPath, NULL); + wchar_t gamePayloadPath[MAX_PATH]; + GetFullPathNameW(GAME_INJECT_DLL, MAX_PATH, gamePayloadPath, NULL); - char launcherPayloadPath[MAX_PATH]; - GetFullPathNameA(LAUNCHER_INJECT_DLL, sizeof(launcherPayloadPath), launcherPayloadPath, NULL); + wchar_t launcherPayloadPath[MAX_PATH]; + GetFullPathNameW(LAUNCHER_INJECT_DLL, MAX_PATH, launcherPayloadPath, NULL); // Construct commandline for the game process - char cmdline[8192]; - sprintf(cmdline, "\"%s\"", gameExePath); + wchar_t cmdline[8192]; + wsprintfW(cmdline, L"\"%ls\"", gameExePath); while (argc) { - char arg[8192]; - sprintf(arg, " \"%s\"", argv[0]); - strcat(cmdline, arg); + wchar_t arg[8192]; + wsprintfW(arg, L" \"%ls\"", argv[0]); + wcscat(cmdline, arg); SHIFT(argc, argv); } // Set envvars - SetEnvironmentVariableA(ENV_EXE_PATH, gameExePath); - SetEnvironmentVariableA(ENV_DLL_PATH, gamePayloadPath); - SetEnvironmentVariableA(ENV_PROC_CMD, cmdline); + SetEnvironmentVariableW(ENV_EXE_PATH, gameExePath); + SetEnvironmentVariableW(ENV_DLL_PATH, gamePayloadPath); + SetEnvironmentVariableW(ENV_PROC_CMD, cmdline); // Start the launcher - printf("Starting '%s' via '%s'\n", gameExePath, launcherPath); + wprintf(L"Starting '%ls' via '%ls'\n", gameExePath, launcherPath); - STARTUPINFO si; + STARTUPINFOW si; ZeroMemory(&si, sizeof(si)); PROCESS_INFORMATION pi; si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); - if (!CreateProcessA( + if (!CreateProcessW( launcherPath, NULL, NULL, @@ -102,11 +102,11 @@ int main(int argc, char **argv) { &si, &pi )) { - fprintf(stderr, "Could not start process! (%ld)\n", GetLastError()); + fwprintf(stderr, L"Could not start process! (%ld)\n", GetLastError()); exit(1); } - printf("Started launcher process (%ld)\n", pi.dwProcessId); + wprintf(L"Started launcher process (%ld)\n", pi.dwProcessId); // Inject void *payloadStart = &_binary_launcher_p_o_p_launcher_p_bin_start; diff --git a/injector/src/game_p.asm b/injector/src/game_p.asm index 36830f0..b1ad7c8 100644 --- a/injector/src/game_p.asm +++ b/injector/src/game_p.asm @@ -17,11 +17,11 @@ main: ; Replacement entry point mov rcx, rsi ; kernel32.dll - lea rdx, [rel s_LoadLibraryA] - call rdi ; rax = *LoadLibraryA + lea rdx, [rel s_LoadLibraryW] + call rdi ; rax = *LoadLibraryW lea rcx, [rel dllPath] - call rax ; LoadLibraryA(dllPath) + call rax ; LoadLibraryW(dllPath) mov rcx, rsi ; kernel32.dll @@ -67,7 +67,7 @@ main: ; Replacement entry point ; Strings -s_LoadLibraryA: db "LoadLibraryA", 0 +s_LoadLibraryW: db "LoadLibraryW", 0 s_GetModuleHandleA: db "GetModuleHandleA", 0 s_GetCommandLineW: db "GetCommandLineW", 0 s_UnityPlayer.dll: db "UnityPlayer.dll", 0 diff --git a/injector/src/inject.c b/injector/src/inject.c index ecf2256..422d995 100644 --- a/injector/src/inject.c +++ b/injector/src/inject.c @@ -10,11 +10,11 @@ static inline void write_protected_process_memory(HANDLE process, void *address, VirtualProtectEx(process, address, size, oldProtect, &oldProtect); } -void inject(HANDLE process, const void *payload, size_t payloadSize, const char *dllPath) { +void inject(HANDLE process, const void *payload, size_t payloadSize, const wchar_t *dllPath) { size_t _; // Contrary to the docs, {Write,Read}ProcessMemory likes to crash if the last arg is NULL // Inject the loader into the module - size_t dllPathLen = strlen(dllPath) + 1; + size_t dllPathLen = (wcslen(dllPath) + 1) * sizeof(wchar_t); char *remoteAlloc = VirtualAllocEx(process, NULL, payloadSize + dllPathLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); WriteProcessMemory(process, remoteAlloc, payload, payloadSize, &_); diff --git a/injector/src/launcher_p.asm b/injector/src/launcher_p.asm index 73d4033..a8bf51d 100644 --- a/injector/src/launcher_p.asm +++ b/injector/src/launcher_p.asm @@ -12,8 +12,8 @@ main: ; Replacement entry point mov rcx, rsi ; kernel32.dll - lea rdx, [rel s_LoadLibraryA] - call rax ; rax = *LoadLibraryA + lea rdx, [rel s_LoadLibraryW] + call rax ; rax = *LoadLibraryW lea rcx, [rel dllPath] call rax ; LoadLibraryA(dllPath) @@ -27,7 +27,7 @@ main: ; Replacement entry point ; Strings -s_LoadLibraryA: db "LoadLibraryA", 0 +s_LoadLibraryW: db "LoadLibraryW", 0 dllPath: ; This will be filled out by the injector