diff --git a/resources/win/file_dos_stub/build_file_dos_stub.bat b/resources/win/file_dos_stub/build_file_dos_stub.bat new file mode 100644 index 00000000..eccde699 --- /dev/null +++ b/resources/win/file_dos_stub/build_file_dos_stub.bat @@ -0,0 +1,223 @@ +@echo off + +setlocal +pushd "%~dp0" + +set /a last_code=0 + +set /a VERBOSE=1 +set "debug_info=/DEBUG:NONE" +set "debug_info_format=" +set "optimization_level=/Ox /Oi /Ob2 /Ot /O2 /Oy-" +set "dbg_defs=/DEMU_RELEASE_BUILD /DNDEBUG" + +set "build_root_dir=." + +:: common stuff +set "build_temp_dir=build" + +set "common_compiler_args=/std:c++17 /MP /DYNAMICBASE /errorReport:none /nologo /utf-8 /EHsc /GF /GL- /GS" +set "common_compiler_args_32=%common_compiler_args%" +set "common_compiler_args_64=%common_compiler_args%" + +:: "win" variables are used to build .dll and /SUBSYTEM:WINDOWS applications, +:: "exe" variables are used to build pure console applications +set "common_linker_args=/DYNAMICBASE /ERRORREPORT:NONE /NOLOGO /emittoolversioninfo:no" +set "common_win_linker_args_32=%common_linker_args%" +set "common_win_linker_args_64=%common_linker_args%" +set "common_exe_linker_args_32=%common_linker_args%" +set "common_exe_linker_args_64=%common_linker_args%" + +:: directories to use for #include +set release_incs_both=%ssq_inc% /I"../../../pe_helpers" +set release_incs32=%release_incs_both% +set release_incs64=%release_incs_both% + +:: libraries to link with +:: copied from Visual Studio 2022 +set "CoreLibraryDependencies=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib" +set "release_libs_both=%CoreLibraryDependencies% Ws2_32.lib Iphlpapi.lib Wldap32.lib Winmm.lib Bcrypt.lib Dbghelp.lib" +set release_libs32=%release_libs_both% +set release_libs64=%release_libs_both% + +:: common source files used everywhere, just for convinience, you still have to provide a complete list later +set release_src="file_dos_stub.cpp" "../../../pe_helpers/pe_helpers.cpp" + + +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: x32 +setlocal +call "../../../build_win_set_env.bat" 32 || ( + endlocal + call :err_msg "Couldn't find Visual Studio or build tools - 32" + set /a last_code=1 + goto :end_script +) + +echo // building exe - 32 +call :build_for 1 1 "%build_root_dir%\file_dos_stub_32.exe" release_src +set /a last_code+=%errorlevel% +endlocal & set /a last_code=%last_code% + + +timeout /t 3 /nobreak + + +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: x64 +setlocal +call "../../../build_win_set_env.bat" 64 || ( + endlocal + call :err_msg "Couldn't find Visual Studio or build tools - 64" + set /a last_code=1 + goto :end_script +) + +echo // building exe - 64 +call :build_for 1 1 "%build_root_dir%\file_dos_stub_64.exe" release_src +set /a last_code+=%errorlevel% +endlocal & set /a last_code=%last_code% + + +:: cleanup +echo // cleaning up +call :cleanup +echo: & echo: + + +goto :end_script + + +:: 1: is 32 bit build +:: 2: subsystem type [0: dll, 1: console app, 2: win32 app] +:: check this table: https://learn.microsoft.com/en-us/cpp/build/reference/entry-entry-point-symbol#remarks +:: 3: out filepath +:: 4: (ref) all source files +:: 5: (optional) (ref) extra inc dirs +:: 6: (optional) extra defs +:: 7: (optional) extra libs +:build_for + setlocal + set /a _is_32_bit_build=%~1 2>nul || ( + endlocal + call :err_msg "Missing build arch" + exit /b 1 + ) + set /a _subsys_type=%~2 2>nul || ( + endlocal + call :err_msg "Missing subsystem type" + exit /b 1 + ) + set "_out_filepath=%~3" + if "%_out_filepath%"=="" ( + endlocal + call :err_msg "Missing output filepath" + exit /b 1 + ) + set "_all_src=" + for /f "tokens=* delims=" %%A in (' if not "%~4" equ "" if defined %~4 echo %%%~4%%') do set _all_src=%%A + if not defined _all_src ( + endlocal + call :err_msg "Missing src files" + exit /b 1 + ) + set "_extra_inc_dirs=" + for /f "tokens=* delims=" %%A in (' if not "%~5" equ "" if defined %~5 echo %%%~5%%') do set _extra_inc_dirs=%%A + set "_extra_defs=%~6" + set "_extra_libs=%~7" + + set "_build_tmp=" + for /f "usebackq tokens=* delims=" %%A in ('"%_out_filepath%"') do ( + set "_build_tmp=%build_temp_dir%\%%~nA_%_is_32_bit_build%" + ) + if "%_build_tmp%"=="" ( + endlocal + call :err_msg "Unable to set build tmp dir from filename" + exit /b 1 + ) + mkdir "%_build_tmp%" + + set "_target_args=%common_compiler_args_64%" + if %_is_32_bit_build% equ 1 ( + set "_target_args=%common_compiler_args_32%" + ) + + set _target_inc_dirs=%release_incs64% + if %_is_32_bit_build% equ 1 ( + set _target_inc_dirs=%release_incs32% + ) + + set _target_libs=%release_libs64% + if %_is_32_bit_build% equ 1 ( + set _target_libs=%release_libs32% + ) + + :: https://learn.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library + :: https://learn.microsoft.com/en-us/cpp/build/reference/dll-build-a-dll + set "_runtime_type=/MT" + set "_target_linker_args=" + :: [0: dll, 1: console app, 2: win32 app] + if %_subsys_type% equ 0 ( + set "_runtime_type=/MT /LD" + if %_is_32_bit_build% equ 1 ( + set "_target_linker_args=%common_win_linker_args_32%" + ) else ( + set "_target_linker_args=%common_win_linker_args_64%" + ) + ) else if %_subsys_type% equ 1 ( + if %_is_32_bit_build% equ 1 ( + set "_target_linker_args=%common_exe_linker_args_32%" + ) else ( + set "_target_linker_args=%common_exe_linker_args_64%" + ) + ) else if %_subsys_type% equ 2 ( + if %_is_32_bit_build% equ 1 ( + set "_target_linker_args=%common_win_linker_args_32%" + ) else ( + set "_target_linker_args=%common_win_linker_args_64%" + ) + ) else ( + endlocal + call :err_msg "Unknown subsystem type" + exit /b 1 + ) + + if "%VERBOSE%" equ "1" ( + echo cl.exe %_target_args% /Fo%_build_tmp%\ /Fe%_build_tmp%\ %debug_info% %debug_info_format% %optimization_level% %release_defs% %_extra_defs% %_runtime_type% %_target_inc_dirs% %_extra_inc_dirs% %_all_src% %_target_libs% %_extra_libs% /link %_target_linker_args% /OUT:"%_out_filepath%" + echo: + ) + + cl.exe %_target_args% /Fo%_build_tmp%\ /Fe%_build_tmp%\ %debug_info% %debug_info_format% %optimization_level% %release_defs% %_extra_defs% %_runtime_type% %_target_inc_dirs% %_extra_inc_dirs% %_all_src% %_target_libs% %_extra_libs% /link %_target_linker_args% /OUT:"%_out_filepath%" + set /a _exit=%errorlevel% + rmdir /s /q "%_build_tmp%" +endlocal & exit /b %_exit% + + +:err_msg + 1>&2 echo [X] %~1 +exit /b + + +:cleanup + del /f /q *.exp >nul 2>&1 + del /f /q *.lib >nul 2>&1 + del /f /q *.a >nul 2>&1 + del /f /q *.obj >nul 2>&1 + del /f /q *.pdb >nul 2>&1 + del /f /q *.ilk >nul 2>&1 + rmdir /s /q "%build_temp_dir%" >nul 2>&1 + for %%A in ("ilk" "lib" "exp") do ( + del /f /s /q "%build_root_dir%\*.%%~A" >nul 2>&1 + ) +exit /b + + +:end_script +echo: +if %last_code% equ 0 ( + echo [GG] no failures +) else ( + 1>&2 echo [XX] general failure +) +popd +endlocal & ( + exit /b %last_code% +) diff --git a/resources/win/file_dos_stub/file_dos_stub.cpp b/resources/win/file_dos_stub/file_dos_stub.cpp new file mode 100644 index 00000000..1ff6f2c9 --- /dev/null +++ b/resources/win/file_dos_stub/file_dos_stub.cpp @@ -0,0 +1,96 @@ +#include +#include +#include + +#include "pe_helpers/pe_helpers.hpp" + +static size_t get_file_size(std::fstream &file) +{ + try + { + auto org_pos = file.tellg(); + file.seekg(0, std::ios::end); + auto size = file.tellg(); + file.seekg(org_pos, std::ios::beg); + return (size_t)size; + } + catch(...) + { + return 0; + } + +} + +static std::vector load_file(std::fstream &file, size_t size) +{ + try + { + auto org_pos = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector data(size, 0); + file.read((char *)&data[0], data.size()); + + file.seekg(org_pos, std::ios::beg); + return data; + } + catch(const std::exception& e) + { + return std::vector(); + } + +} + + +constexpr static size_t DOS_STUB_OOFSET = offsetof(IMAGE_DOS_HEADER, e_lfanew) + sizeof(IMAGE_DOS_HEADER::e_lfanew); +constexpr static const char DOS_STUB_SIGNATURE[] = "VLV"; +constexpr static uint32_t DOS_STUB_ONE = 1; // what is this? + + +int main(int argc, char* *argv) +{ + if (argc < 2) { + std::cerr << "Expected one or more binary files" << std::endl; + return 1; + } + + for (size_t i = 1; i < argc; ++i) { + auto arg = argv[i]; + std::fstream file(arg, std::ios::in | std::ios::out | std::ios::binary); + if (!file.is_open()) { + std::cerr << "Failed to open file: '" << arg << "'" << std::endl; + return 1; + } + + auto file_size = get_file_size(file); + if (!file_size) { + std::cerr << "Failed get file size for file: '" << arg << "'" << std::endl; + return 1; + } + auto data = load_file(file, file_size); + if (data.empty()) { + std::cerr << "Failed get file data for file: '" << arg << "'" << std::endl; + return 1; + } + uint32_t pe_size = (uint32_t)pe_helpers::get_pe_size((HMODULE)&data[0]); + if (!pe_size) { + std::cerr << "Failed get PE size for file: '" << arg << "'" << std::endl; + return 1; + } + + // std::cout << "File size = " << file_size << ", PE size = " << pe_size << std::endl; + + file.seekp(DOS_STUB_OOFSET, std::ios::beg); + + // 4 bytes: 'V' 'L' 'V' '\0' + file.write(DOS_STUB_SIGNATURE, sizeof(DOS_STUB_SIGNATURE)); + // 4 bytes: (uint32_t)1 + file.write((const char *)&DOS_STUB_ONE, sizeof(DOS_STUB_ONE)); + // 4 bytes: PE image size + file.write((const char *)&pe_size, sizeof(pe_size)); + + file.close(); + } + + return 0; +} diff --git a/resources/win/file_dos_stub/file_dos_stub_32.exe b/resources/win/file_dos_stub/file_dos_stub_32.exe new file mode 100644 index 00000000..b45b24e7 Binary files /dev/null and b/resources/win/file_dos_stub/file_dos_stub_32.exe differ diff --git a/resources/win/file_dos_stub/file_dos_stub_64.exe b/resources/win/file_dos_stub/file_dos_stub_64.exe new file mode 100644 index 00000000..f622283e Binary files /dev/null and b/resources/win/file_dos_stub/file_dos_stub_64.exe differ