2022-02-03 14:05:24 -05: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 )
{
component_loader : : post_unpack ( ) ;
return SystemParametersInfoA ( uiAction , uiParam , pvParam , fWinIni ) ;
}
launcher : : mode detect_mode_from_arguments ( )
{
if ( utils : : flags : : has_flag ( " dedicated " ) )
{
return launcher : : mode : : server ;
}
if ( utils : : flags : : has_flag ( " multiplayer " ) )
{
return launcher : : mode : : multiplayer ;
}
if ( utils : : flags : : has_flag ( " singleplayer " ) )
{
return launcher : : mode : : singleplayer ;
}
return launcher : : mode : : none ;
}
2022-05-28 06:15:17 -04:00
bool apply_aslr_patch ( std : : string * data )
2022-05-28 06:12:29 -04:00
{
if ( data - > size ( ) < 0x1EE | | ( data - > at ( 0x1EE ) ! = static_cast < char > ( 0x60 ) & & data - > at ( 0x1EE ) ! = static_cast < char > ( 0x20 ) ) )
{
// what the fuck is wrong with this binary data?
return false ;
}
data - > at ( 0x1EE ) = static_cast < char > ( 0x20 ) ;
return true ;
}
void get_aslr_patched_binary ( std : : string * binary , std : : string * data )
{
std : : string patched_binary = " h1-mod \\ " + * binary ;
2022-05-28 06:15:17 -04:00
if ( ! apply_aslr_patch ( data ) )
2022-05-28 06:12:29 -04:00
{
throw std : : runtime_error ( utils : : string : : va (
" Could not create aslr patched binary! \n (%s) " ,
* binary - > data ( )
) ) ;
}
if ( ! utils : : io : : file_exists ( patched_binary ) )
{
utils : : io : : write_file ( patched_binary , * data , false ) ;
}
* binary = patched_binary ;
}
2022-05-17 10:56:26 -04:00
FARPROC load_binary ( const launcher : : mode mode , uint64_t * base_address )
2022-02-03 14:05:24 -05:00
{
loader loader ;
utils : : nt : : library self ;
loader . set_import_resolver ( [ self ] ( const std : : string & library , const std : : string & function ) - > void *
{
2022-05-17 10:56:26 -04:00
if ( library = = " steam_api64.dll "
& & function ! = " SteamAPI_GetSteamInstallPath " ) // Arxan requires one valid steam api import - maybe SteamAPI_Shutdown is better?
2022-02-03 14:05:24 -05:00
{
return self . get_proc < FARPROC > ( function ) ;
}
else if ( function = = " ExitProcess " )
{
return exit_hook ;
}
else if ( function = = " SystemParametersInfoA " )
{
return system_parameters_info_a ;
}
return component_loader : : load_import ( library , function ) ;
} ) ;
std : : string binary ;
switch ( mode )
{
case launcher : : mode : : server :
case launcher : : mode : : multiplayer :
binary = " h1_mp64_ship.exe " ;
break ;
case launcher : : mode : : singleplayer :
binary = " h1_sp64_ship.exe " ;
break ;
case launcher : : mode : : none :
default :
throw std : : runtime_error ( " Invalid game mode! " ) ;
}
std : : string data ;
if ( ! utils : : io : : read_file ( binary , & data ) )
{
throw std : : runtime_error ( utils : : string : : va (
2022-03-01 22:27:42 -05:00
" Failed to read game binary (%s)! \n Please copy the h1-mod.exe into your Call of Duty: Modern Warfare Remastered installation folder and run it from there. " ,
2022-02-03 14:05:24 -05:00
binary . data ( ) ) ) ;
}
2022-05-28 06:12:29 -04:00
get_aslr_patched_binary ( & binary , & data ) ;
2022-05-17 10:56:26 -04:00
# ifdef INJECT_HOST_AS_LIB
return loader . load_library ( binary , base_address ) ;
# else
* base_address = 0x140000000 ;
return loader . load ( self , data ) ;
# endif
2022-02-03 14:05:24 -05:00
}
void remove_crash_file ( )
{
utils : : io : : remove_file ( " __h1Exe " ) ;
}
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 ) ;
}
2022-03-15 19:59:03 -04:00
// solution for other processes that may launch the mod
void apply_proper_directory ( )
{
char module_path [ MAX_PATH ] ;
GetModuleFileNameA ( nullptr , module_path , MAX_PATH ) ;
PathRemoveFileSpecA ( module_path ) ;
SetCurrentDirectoryA ( module_path ) ;
SetDllDirectoryA ( module_path ) ;
}
2022-02-03 14:05:24 -05:00
int main ( )
{
2022-05-17 10:56:26 -04:00
ShowWindow ( GetConsoleWindow ( ) , SW_HIDE ) ;
2022-02-03 14:05:24 -05:00
FARPROC entry_point ;
enable_dpi_awareness ( ) ;
// This requires admin privilege, but I suppose many
// people will start with admin rights if it crashes.
limit_parallel_dll_loading ( ) ;
srand ( uint32_t ( time ( nullptr ) ) ) ;
2022-05-17 10:56:26 -04:00
remove_crash_file ( ) ;
2022-02-03 14:05:24 -05:00
{
auto premature_shutdown = true ;
const auto _ = gsl : : finally ( [ & premature_shutdown ] ( )
{
if ( premature_shutdown )
{
component_loader : : pre_destroy ( ) ;
}
} ) ;
try
{
2022-05-17 10:56:26 -04:00
//apply_proper_directory();
2022-02-03 14:05:24 -05:00
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-05-17 10:56:26 -04:00
uint64_t base_address { } ;
entry_point = load_binary ( mode , & base_address ) ;
2022-02-03 14:05:24 -05:00
if ( ! entry_point )
{
throw std : : runtime_error ( " Unable to load binary into memory " ) ;
}
2022-05-17 10:56:26 -04:00
game : : base_address = base_address ;
2022-02-03 14:05:24 -05: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 ( ) ;
}