2023-06-06 17:36:00 +00:00
# include <stdio.h>
2023-06-25 09:32:19 +00:00
# include <inject.h>
2023-06-26 09:53:07 +00:00
# include <envs.h>
2023-06-05 21:23:08 +00:00
2023-06-25 09:32:19 +00:00
# include <game_p.h>
2023-06-05 21:23:08 +00:00
2023-07-02 20:21:17 +00:00
typedef char * ( * wgufn_t ) ( wchar_t * path ) ; // wine_get_unix_file_name
const char * J_MB_TITLE = " Jadeite Launcher Payload " ;
2023-06-05 21:23:08 +00:00
BOOL WINAPI DllMain ( HINSTANCE inst , DWORD reason , LPVOID reserved ) {
// Only listen for attach
if ( reason ! = DLL_PROCESS_ATTACH ) {
return TRUE ;
}
// Get target EXE path
2023-06-10 15:28:19 +00:00
char * targetExe = getenv ( ENV_EXE_PATH ) ;
2023-06-05 21:23:08 +00:00
// Get the path of the DLL to inject
2023-06-10 15:28:19 +00:00
char * injectDll = getenv ( ENV_DLL_PATH ) ;
2023-06-05 21:23:08 +00:00
2023-06-11 15:04:24 +00:00
// Get game commandline
char * cmdline = getenv ( ENV_PROC_CMD ) ;
2023-06-05 21:23:08 +00:00
// Compute the working directory path
char workdir [ MAX_PATH ] ;
strcpy ( workdir , targetExe ) ;
* ( strrchr ( workdir , ' \\ ' ) ) = ' \0 ' ;
2023-07-02 20:21:17 +00:00
// 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 startsWith = 0 ;
while ( * unixInjectDll ! = ' \0 ' & & * unixWorkdir ! = ' \0 ' ) {
startsWith = * unixInjectDll = = * unixWorkdir ;
if ( ! startsWith ) break ;
unixInjectDll + + , unixWorkdir + + ;
}
HANDLE heap = GetProcessHeap ( ) ;
HeapFree ( heap , 0 , unixInjectDll ) ;
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 ) ;
exit ( 1 ) ;
}
} else {
MessageBoxA ( NULL , " Could not find wine_get_unix_file_name! Wine version too old? " , J_MB_TITLE , MB_OK | MB_ICONWARNING ) ;
}
2023-06-05 21:23:08 +00:00
// Start the game
STARTUPINFO si ;
ZeroMemory ( & si , sizeof ( si ) ) ;
PROCESS_INFORMATION pi ;
si . cb = sizeof ( si ) ;
ZeroMemory ( & pi , sizeof ( pi ) ) ;
if ( ! CreateProcessA (
NULL ,
2023-06-11 15:04:24 +00:00
cmdline ,
2023-06-05 21:23:08 +00:00
NULL ,
NULL ,
FALSE ,
CREATE_SUSPENDED ,
NULL ,
workdir ,
& si ,
& pi
) ) {
2023-06-06 17:36:00 +00:00
char message [ 64 ] ;
sprintf ( message , " Failed to start game process: %ld " , GetLastError ( ) ) ;
2023-07-02 20:21:17 +00:00
MessageBoxA ( NULL , message , J_MB_TITLE , MB_OK | MB_ICONERROR ) ;
2023-06-06 17:36:00 +00:00
2023-06-05 21:23:08 +00:00
exit ( 1 ) ;
}
// Inject
2023-06-25 09:32:19 +00:00
void * payloadStart = & _binary_game_p_o_p_game_p_bin_start ;
size_t payloadSize = ( size_t ) & _binary_game_p_o_p_game_p_bin_size ;
2023-06-05 21:23:08 +00:00
inject ( pi . hProcess , payloadStart , payloadSize , injectDll ) ;
2023-06-10 15:23:43 +00:00
// 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 ) ;
2023-07-02 20:21:17 +00:00
MessageBoxA ( NULL , message , J_MB_TITLE , MB_OK | MB_ICONINFORMATION ) ;
2023-06-10 15:23:43 +00:00
}
2023-06-05 21:23:08 +00:00
// Resume the process
ResumeThread ( pi . hThread ) ;
// The launcher process should now hang untill the game terminates
WaitForSingleObject ( pi . hProcess , INFINITE ) ;
return TRUE ;
}