2021-09-06 18:40:37 -04:00
# include <std_include.hpp>
# include "launcher/launcher.hpp"
# include "loader/loader.hpp"
# include "loader/component_loader.hpp"
# include "game/game.hpp"
# include <utils/string.hpp>
# include <utils/flags.hpp>
# include <utils/io.hpp>
DECLSPEC_NORETURN void WINAPI exit_hook ( const int code )
{
component_loader : : pre_destroy ( ) ;
exit ( code ) ;
}
BOOL WINAPI system_parameters_info_a ( const UINT uiAction , const UINT uiParam , const PVOID pvParam , const UINT fWinIni )
{
return SystemParametersInfoA ( uiAction , uiParam , pvParam , fWinIni ) ;
}
FARPROC WINAPI get_proc_address ( const HMODULE hModule , const LPCSTR lpProcName )
{
if ( lpProcName = = " InitializeCriticalSectionEx " s )
{
component_loader : : post_unpack ( ) ;
}
return GetProcAddress ( hModule , lpProcName ) ;
}
launcher : : mode detect_mode_from_arguments ( )
{
if ( utils : : flags : : has_flag ( " singleplayer " ) )
{
return launcher : : mode : : singleplayer ;
}
return launcher : : mode : : none ;
}
2022-08-25 22:00:20 -04:00
void apply_aslr_patch ( std : : string * data )
{
// sp binary
if ( data - > size ( ) ! = 0xE1E0C8 )
{
throw std : : runtime_error ( " File size mismatch, bad game files " ) ;
}
auto * dos_header = reinterpret_cast < PIMAGE_DOS_HEADER > ( & data - > at ( 0 ) ) ;
auto * nt_headers = reinterpret_cast < PIMAGE_NT_HEADERS > ( & data - > at ( dos_header - > e_lfanew ) ) ;
auto * optional_header = & nt_headers - > OptionalHeader ;
if ( optional_header - > DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE )
{
optional_header - > DllCharacteristics & = ~ ( IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE ) ;
}
}
void get_aslr_patched_binary ( std : : string * binary , std : : string * data )
{
const auto patched_binary = " h2_sp_patched.exe " s ;
try
{
apply_aslr_patch ( data ) ;
if ( ! utils : : io : : file_exists ( patched_binary ) & & ! utils : : io : : write_file ( patched_binary , * data , false ) )
{
throw std : : runtime_error ( " Could not write file " ) ;
}
}
catch ( const std : : exception & e )
{
throw std : : runtime_error (
utils : : string : : va ( " Could not create aslr patched binary for %s! %s " ,
binary - > data ( ) , e . what ( ) )
) ;
}
* binary = patched_binary ;
}
2022-03-18 17:02:44 -04:00
FARPROC load_binary ( const launcher : : mode mode )
2021-09-06 18:40:37 -04:00
{
loader loader ;
utils : : nt : : library self ;
loader . set_import_resolver ( [ self ] ( const std : : string & library , const std : : string & function ) - > void *
{
if ( function = = " ExitProcess " )
{
return exit_hook ;
}
else if ( function = = " SystemParametersInfoA " )
{
return system_parameters_info_a ;
}
else if ( function = = " GetProcAddress " )
{
return get_proc_address ;
}
return component_loader : : load_import ( library , function ) ;
} ) ;
2022-08-25 22:00:20 -04:00
std : : string binary = " MW2CR.exe " ;
if ( ! utils : : io : : file_exists ( binary ) )
2021-09-06 18:40:37 -04:00
{
2022-08-25 22:00:20 -04:00
binary = " h2_sp64_bnet_ship.exe " ;
2021-09-06 18:40:37 -04:00
}
std : : string data ;
if ( ! utils : : io : : read_file ( binary , & data ) )
{
throw std : : runtime_error ( utils : : string : : va (
" Failed to read game binary (%s)! \n Please copy the h2-mod.exe into your Call of Duty: Modern Warfare 2 Campaign Remastered installation folder and run it from there. " ,
binary . data ( ) ) ) ;
}
2022-08-25 22:00:20 -04:00
# ifdef INJECT_HOST_AS_LIB
get_aslr_patched_binary ( & binary , & data ) ;
return loader . load_library ( binary ) ;
# else
2022-03-18 17:02:44 -04:00
return loader . load ( self , data ) ;
2022-08-25 22:00:20 -04:00
# endif
2021-09-06 18:40:37 -04:00
}
void remove_crash_file ( )
{
utils : : io : : remove_file ( " __h2Exe " ) ;
}
2021-09-06 21:22:52 -04:00
void verify_version ( )
{
2022-03-18 17:02:44 -04:00
const auto value = * reinterpret_cast < DWORD * > ( 0x140123456 ) ;
2021-09-06 21:22:52 -04:00
if ( value ! = 0xE465E151 )
{
throw std : : runtime_error ( " Unsupported Call of Duty: Modern Warfare 2 Campaign Remastered version " ) ;
}
}
2021-09-06 18:40:37 -04:00
void enable_dpi_awareness ( )
{
const utils : : nt : : library user32 { " user32.dll " } ;
const auto set_dpi = user32
? user32 . get_proc < BOOL ( WINAPI * ) ( DPI_AWARENESS_CONTEXT ) > ( " SetProcessDpiAwarenessContext " )
: nullptr ;
if ( set_dpi )
{
set_dpi ( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ) ;
}
}
void limit_parallel_dll_loading ( )
{
const utils : : nt : : library self ;
const auto registry_path = R " (Software \ Microsoft \ Windows NT \ CurrentVersion \ Image File Execution Options \ ) " + self .
get_name ( ) ;
HKEY key = nullptr ;
if ( RegCreateKeyA ( HKEY_LOCAL_MACHINE , registry_path . data ( ) , & key ) = = ERROR_SUCCESS )
{
RegCloseKey ( key ) ;
}
key = nullptr ;
if ( RegOpenKeyExA (
HKEY_LOCAL_MACHINE , registry_path . data ( ) , 0 ,
KEY_ALL_ACCESS , & key ) ! = ERROR_SUCCESS )
{
return ;
}
DWORD value = 1 ;
RegSetValueExA ( key , " MaxLoaderThreads " , 0 , REG_DWORD , reinterpret_cast < const BYTE * > ( & value ) , sizeof ( value ) ) ;
RegCloseKey ( key ) ;
}
int main ( )
{
ShowWindow ( GetConsoleWindow ( ) , SW_HIDE ) ;
FARPROC entry_point ;
enable_dpi_awareness ( ) ;
limit_parallel_dll_loading ( ) ;
srand ( uint32_t ( time ( nullptr ) ) ) ;
remove_crash_file ( ) ;
{
auto premature_shutdown = true ;
const auto _ = gsl : : finally ( [ & premature_shutdown ] ( )
{
if ( premature_shutdown )
{
component_loader : : pre_destroy ( ) ;
}
} ) ;
try
{
if ( ! component_loader : : post_start ( ) )
{
return 0 ;
}
auto mode = detect_mode_from_arguments ( ) ;
if ( mode = = launcher : : mode : : none )
{
const launcher launcher ;
mode = launcher . run ( ) ;
if ( mode = = launcher : : mode : : none )
{
return 0 ;
}
}
game : : environment : : set_mode ( mode ) ;
2022-03-18 17:02:44 -04:00
entry_point = load_binary ( mode ) ;
2021-09-06 18:40:37 -04:00
if ( ! entry_point )
{
throw std : : runtime_error ( " Unable to load binary into memory " ) ;
}
2021-09-06 21:22:52 -04:00
verify_version ( ) ;
2021-09-06 18:40:37 -04:00
if ( ! component_loader : : post_load ( ) )
{
return 0 ;
}
premature_shutdown = false ;
}
catch ( std : : exception & e )
{
MessageBoxA ( nullptr , e . what ( ) , " ERROR " , MB_ICONERROR ) ;
return 1 ;
}
}
return static_cast < int > ( entry_point ( ) ) ;
}
int __stdcall WinMain ( HINSTANCE , HINSTANCE , PSTR , int )
{
return main ( ) ;
}