From ef07311ff903ed8370c3727da4c3ec4a0d4ebf34 Mon Sep 17 00:00:00 2001 From: LoRd_MuldeR Date: Sat, 11 Apr 2020 17:54:24 +0200 Subject: [PATCH] Initial commit. --- .gitignore | 2 + Makefile | 9 ++ setup-launcher.c | 334 +++++++++++++++++++++++++++++++++++++++++++++++++++++ setup-launcher.def | 3 + 4 files changed, 348 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 setup-launcher.c create mode 100644 setup-launcher.def diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c138f01 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.exe +*.dll diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e0204c9 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +APPNAME = setup-launcher + +.PHONY: all + +all: + gcc -O2 -static -DBUILD_EXE -o $(APPNAME).exe setup-launcher.c + gcc -O2 -shared -DBUILD_DLL -o $(APPNAME).dll -Wl,--enable-stdcall-fixup setup-launcher.c setup-launcher.def + strip $(APPNAME).exe + strip $(APPNAME).dll diff --git a/setup-launcher.c b/setup-launcher.c new file mode 100644 index 0000000..f02ff81 --- /dev/null +++ b/setup-launcher.c @@ -0,0 +1,334 @@ +/* ---------------------------------------------------------------------------------------------- */ +/* Setup Launcher Utility */ +/* Copyright(c) 2016-2020 LoRd_MuldeR */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy of this software */ +/* and associated documentation files (the "Software"), to deal in the Software without */ +/* restriction, including without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the */ +/* Software is furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING */ +/* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ +/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, */ +/* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/* ---------------------------------------------------------------------------------------------- */ + +#if !defined(BUILD_EXE) && !defined(BUILD_DLL) +#error Nothing to do! +#endif + +#if defined(BUILD_EXE) && defined(BUILD_DLL) +#error Inconsistent build flags! +#endif + +#include + +//--------------------------------------------------------------------------- +// COMMON FUNCTIONS +//--------------------------------------------------------------------------- + +#define MAX_PATHLEN 32768U +#define MAX_CMDNLEN 65536U + +#define MAX(A,B) \ +({ \ + const __typeof__((A)) _a = (A); \ + const __typeof__((B)) _b = (B); \ + _a > _b ? _a : _b; \ +}) + +static wchar_t *append(wchar_t *const buffer, const wchar_t *const str, const size_t buff_size) +{ + const size_t current_len = wcslen(buffer); + if(current_len < buff_size) + { + wcsncat(buffer, str, buff_size - current_len); + buffer[buff_size - 1U] = L'\0'; + } + return buffer; +} + +static size_t last_index(const wchar_t *const haystack, const wchar_t needle) +{ + const wchar_t *ptr; + if(ptr = wcsrchr(haystack, needle)) + { + return ptr - haystack; + } + return 0U; +} + +static BOOL contains_space(const wchar_t *str) +{ + for(; *str != L'\0'; ++str) + { + if(iswspace(*str)) + { + return TRUE; + } + } + return FALSE; +} + +static BOOL file_exists(const wchar_t *const path) +{ + const DWORD attributes = GetFileAttributesW(path); + return ((attributes != INVALID_FILE_ATTRIBUTES) && (!(attributes & FILE_ATTRIBUTE_DIRECTORY))); +} + +static BOOL get_executable_path(const wchar_t *ptr, wchar_t *const out, const size_t max_len) +{ + BOOL flag = FALSE; + const size_t limit = max_len - 1U; + size_t len = 0U; + while ((*ptr != L'\0') && iswspace(*ptr)) + { + ++ptr; + } + for (; *ptr != L'\0'; ++ptr) + { + if(*ptr == L'"') + { + flag = (!flag); + } + else + { + if((!flag) && iswspace(*ptr)) + { + break; + } + if(len < limit) + { + out[len++] = *ptr; + } + else + { + out[len] = L'\0'; + return FALSE; + } + } + } + out[len] = L'\0'; + return TRUE; +} + +static const wchar_t *get_parameters(const wchar_t *cmdLine) +{ + BOOL flag = FALSE; + if(!cmdLine) + { + return NULL; + } + while ((*cmdLine != L'\0') && iswspace(*cmdLine)) + { + ++cmdLine; + } + for (; *cmdLine != L'\0'; ++cmdLine) + { + if(*cmdLine == L'"') + { + flag = (!flag); + } + else + { + if((!flag) && iswspace(*cmdLine)) + { + break; + } + } + } + while ((*cmdLine != L'\0') && iswspace(*cmdLine)) + { + ++cmdLine; + } + return cmdLine; +} + +static void remove_file_extension(wchar_t *const path) +{ + const size_t pos_dot = last_index(path, L'.'); + const size_t pos_sep = MAX(last_index(path, L'/'), last_index(path, L'\\')); + if((pos_dot > 0U) && ((pos_sep == 0U) || (pos_dot > pos_sep))) + { + path[pos_dot] = L'\0'; + } +} + +static BOOL exec_shell(const wchar_t *const verb, const wchar_t *const file, const wchar_t *const params, const BOOL await, DWORD *const exit_code) +{ + SHELLEXECUTEINFOW shExecInfo; + SecureZeroMemory(&shExecInfo, sizeof(SHELLEXECUTEINFOW)); + shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW); + shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; + shExecInfo.lpVerb = verb; + shExecInfo.lpFile = file; + shExecInfo.lpParameters = params; + shExecInfo.nShow = SW_SHOW; + if(exit_code) + { + *exit_code = 0U; + } + if(ShellExecuteExW(&shExecInfo)) + { + if(await && (shExecInfo.hProcess != NULL)) + { + WaitForSingleObject(shExecInfo.hProcess, INFINITE); + if(exit_code) + { + if(!GetExitCodeProcess(shExecInfo.hProcess, exit_code)) + { + *exit_code = ((DWORD)(-1)); + } + } + CloseHandle(shExecInfo.hProcess); + } + return TRUE; + } + return FALSE; +} + +static void error_message(const wchar_t *const message) +{ + MessageBoxW(NULL, message, L"Setup Launcher", MB_ICONERROR|MB_SYSTEMMODAL); +} + +//--------------------------------------------------------------------------- +// EXE +//--------------------------------------------------------------------------- + +#ifdef BUILD_EXE + +static wchar_t library_path[MAX_PATHLEN], rundll32_path[MAX_PATHLEN], parameters[MAX_CMDNLEN]; + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow) +{ + /*get command-line arguments*/ + const wchar_t *const cmdLineArgs = get_parameters(GetCommandLineW()); + if((!cmdLineArgs) || (!(*cmdLineArgs))) + { + error_message(L"Required parameters are missing!\n\nUsage:\nsetup-launcher.exe [PARAMETERS]"); + return 1; + } + + /*get path of launcher EXE*/ + DWORD ret = GetSystemDirectoryW(rundll32_path, MAX_PATHLEN); + if((ret < 1U) || (ret >= MAX_PATHLEN)) + { + error_message(L"Error: Failed to determine system directory path!"); + return 1; + } + append(rundll32_path, L"\\rundll32.exe", MAX_PATHLEN); + + /*get path of launcher DLL*/ + ret = GetModuleFileNameW(NULL, library_path, MAX_PATHLEN); + if((ret < 1U) || (ret >= MAX_PATHLEN)) + { + error_message(L"Error: Failed to determine executable path!"); + return 1; + } + remove_file_extension(library_path); + append(library_path, L".dll", MAX_PATHLEN); + + /*make sure the launcher DLL exists*/ + if(!file_exists(library_path)) + { + error_message(L"Error: Launcher library file could not be found!"); + return 0x485; + } + + /*build parameter string for RunDLL*/ + if(contains_space(library_path)) + { + wcscpy(parameters, L"\""); + append(parameters, library_path, MAX_CMDNLEN); + append(parameters, L"\",startup ", MAX_CMDNLEN); + append(parameters, cmdLineArgs, MAX_CMDNLEN); + } + else + { + wcscpy(parameters, library_path); + append(parameters, L",startup ", MAX_CMDNLEN); + append(parameters, cmdLineArgs, MAX_CMDNLEN); + } + + /*now actually call the launcher DLL*/ + DWORD exit_code; + for(;;) + { + if(!exec_shell(L"runas", rundll32_path, parameters, TRUE, &exit_code)) + { + if(MessageBoxW(NULL, L"Failed to launch setup program. Please try again!", L"Setup Launcher", MB_OKCANCEL|MB_ICONWARNING|MB_SYSTEMMODAL) == IDCANCEL) + { + return 0x2E4; + } + } + else + { + break; /*success*/ + } + } + + return exit_code; +} + +#endif //BUILD_EXE + +//--------------------------------------------------------------------------- +// DLL +//--------------------------------------------------------------------------- + +#ifdef BUILD_DLL + +static wchar_t executable_path[MAX_PATHLEN]; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +void CALLBACK startup(HWND hwnd, HINSTANCE hAppInstance, LPSTR lpCmdLine, int nCmdShow) +{ + error_message(L"ANSI entry-point not supported. Please use Unicode entry-point!"); + ExitProcess((DWORD)(-1)); +} + +void CALLBACK startupW(HWND hwnd, HINSTANCE hAppInstance, LPWSTR lpCmdLine, int nCmdShow) +{ + /*get executable path*/ + if(!get_executable_path(lpCmdLine, executable_path, MAX_PATHLEN)) + { + error_message(L"Error: Failed to determine the executable path!"); + } + + /*make sure the launcher DLL exists*/ + if(!file_exists(executable_path)) + { + error_message(L"Error: Setup executable could not be found!"); + ExitProcess(0x490); + } + + /*now actually launch the executable*/ + DWORD exit_code; + if(!exec_shell(NULL, executable_path, get_parameters(lpCmdLine), TRUE, &exit_code)) + { + error_message(L"Error: Failed to launch the setup program!"); + ExitProcess(0x2E4); + } + + ExitProcess(exit_code); +} + +#endif //BUILD_DLL diff --git a/setup-launcher.def b/setup-launcher.def new file mode 100644 index 0000000..15ff8de --- /dev/null +++ b/setup-launcher.def @@ -0,0 +1,3 @@ +LIBRARY setup-launcher +EXPORTS + startupW startupW@16 -- 2.11.4.GIT