From 86892164eb0fbf5d67e251c0500a09cb4716b614 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Sat, 1 Mar 2014 13:26:04 -0600 Subject: [PATCH] Add reverse-engineered code for SrcDS launcher. --- dedicated_main/dedicated_main.rc | 72 +++++++ dedicated_main/dedicated_main.sln | 20 ++ dedicated_main/dedicated_main.vcxproj | 134 ++++++++++++ dedicated_main/dedicated_main.vcxproj.filters | 26 +++ dedicated_main/main.cpp | 201 ++++++++++++++++++ dedicated_main/resource.h | 23 ++ dedicated_main/srcds.ico | Bin 0 -> 29926 bytes linux_sdk/Makefile | 6 + linux_sdk/Makefile.srcds | 52 +++++ 9 files changed, 534 insertions(+) create mode 100644 dedicated_main/dedicated_main.rc create mode 100644 dedicated_main/dedicated_main.sln create mode 100644 dedicated_main/dedicated_main.vcxproj create mode 100644 dedicated_main/dedicated_main.vcxproj.filters create mode 100644 dedicated_main/main.cpp create mode 100644 dedicated_main/resource.h create mode 100644 dedicated_main/srcds.ico create mode 100644 linux_sdk/Makefile.srcds diff --git a/dedicated_main/dedicated_main.rc b/dedicated_main/dedicated_main.rc new file mode 100644 index 00000000..24c03a57 --- /dev/null +++ b/dedicated_main/dedicated_main.rc @@ -0,0 +1,72 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_DEDICATED ICON DISCARDABLE "srcds.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/dedicated_main/dedicated_main.sln b/dedicated_main/dedicated_main.sln new file mode 100644 index 00000000..03dcd48b --- /dev/null +++ b/dedicated_main/dedicated_main.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dedicated_main", "dedicated_main.vcxproj", "{E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}.Debug|Win32.ActiveCfg = Debug|Win32 + {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}.Debug|Win32.Build.0 = Debug|Win32 + {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}.Release|Win32.ActiveCfg = Release|Win32 + {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/dedicated_main/dedicated_main.vcxproj b/dedicated_main/dedicated_main.vcxproj new file mode 100644 index 00000000..e67fd592 --- /dev/null +++ b/dedicated_main/dedicated_main.vcxproj @@ -0,0 +1,134 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + dedicated_main + {E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720} + tier1 + + + + Application + + + Application + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + AllRules.ruleset + + + AllRules.ruleset + + + srcds + srcds + + + + + + + + Disabled + ..\public;..\public\tier0;..\public\tier1;..\public\interfaces;%(AdditionalIncludeDirectories) + _HAS_ITERATOR_DEBUGGING=0;_ALLOW_RUNTIME_LIBRARY_MISMATCH;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_MSC_VER_MISMATCH;_ITERATOR_DEBUG_LEVEL=0;WIN32;_WIN32;COMPILER_MSVC;COMPILER_MSVC32;_DEBUG;DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + true + true + + + EnableFastChecks + MultiThreadedDebug + false + Fast + + + + + + + Level3 + + + + + + + Rpcrt4.lib;%(AdditionalDependencies) + + + true + + + + + + + + + + ..\public;..\public\tier0;..\public\tier1;..\public\interfaces;%(AdditionalIncludeDirectories) + _HAS_ITERATOR_DEBUGGING=0;_ALLOW_RUNTIME_LIBRARY_MISMATCH;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_MSC_VER_MISMATCH;WIN32;_WIN32;COMPILER_MSVC;COMPILER_MSVC32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + + + + + + + Level3 + Fast + AnySuitable + true + Speed + + + + + + + + + + + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dedicated_main/dedicated_main.vcxproj.filters b/dedicated_main/dedicated_main.vcxproj.filters new file mode 100644 index 00000000..a7455685 --- /dev/null +++ b/dedicated_main/dedicated_main.vcxproj.filters @@ -0,0 +1,26 @@ + + + + + {aba1d919-d95c-4c3f-a495-be0375bab184} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {0295d938-2af6-4393-9785-4b7b122313c9} + h;hpp;hxx;hm;inl + + + + + Source Files + + + + + Header Files + + + + + + \ No newline at end of file diff --git a/dedicated_main/main.cpp b/dedicated_main/main.cpp new file mode 100644 index 00000000..841dcec1 --- /dev/null +++ b/dedicated_main/main.cpp @@ -0,0 +1,201 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +//===========================================================================// + +#if defined(WIN32) +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +// Reverse engineered file + +// Entry point of dedicated binary +#if defined(WIN32) +typedef int (*DedicatedMain_t)(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); +#else +typedef int (*DedicatedMain_t)(int argc, char **argv); +#endif + +#if defined(WIN32) +#define ENGINE_BIN(x) "bin\\" #x ".dll" +#elif defined(LINUX) +#define ENGINE_BIN(x) "bin/" #x "_srv.so" +#define ENGINE_BIN_ALT(x) "bin/" #x ".so" +#define LIB_PATH "LD_LIBRARY_PATH" +#elif defined(OSX) +#define ENGINE_BIN(x) "bin/" #x ".dylib" +#define LIB_PATH "DYLD_LIBRARY_PATH" +#endif + +#if defined(WANTS_DEBUGSTR_HACK) && !defined(WIN32) + +#if !defined(PAGE_SIZE) +#define PAGE_SIZE 4096 +#endif + +#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1)) + +void BlockDebugString() +{ + void *tier0; + void *func; + void *addr; + int ret; + const uint8_t OP_RET = 0xC3; + + tier0 = dlopen(ENGINE_BIN(libtier0), RTLD_NOW); + +#if defined(ENGINE_BIN_ALT) + if (!tier0) + tier0 = dlopen(ENGINE_BIN_ALT(libtier0), RTLD_NOW); +#endif + + if (!tier0) + return; + + func = dlsym(tier0, "Plat_DebugString"); + dlclose(tier0); + if (!func) + return; + + addr = (void *)ALIGN(func); + ret = mprotect(addr, sysconf(_SC_PAGESIZE), PROT_READ|PROT_WRITE|PROT_EXEC); + if (ret != 0) + return; + + *(uint8_t *)func = OP_RET; + + mprotect(addr, sysconf(_SC_PAGESIZE), PROT_READ|PROT_EXEC); +} +#endif + +#if defined(WIN32) +static const char *GetBaseDir(const char *file) +{ + static char basedir[MAX_PATH]; + + strcpy(basedir, file); + + char *rslash = strrchr(basedir, '\\'); + + if (rslash) + *(rslash + 1) = '\0'; + + return basedir; +} + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + char exeName[MAX_PATH]; + char pathBuf[4096]; + + char *path = getenv("PATH"); + + if (!GetModuleFileName(hInstance, exeName, sizeof(exeName))) + { + MessageBox(0, "Failed calling GetModuleFileName", "Launcher Error", MB_OK); + return 0; + } + + const char *root = GetBaseDir(exeName); + + _snprintf(pathBuf, sizeof(pathBuf) - 1, "PATH=%s\\bin\\;%s", root, path); + _putenv(pathBuf); + + HMODULE dedicated = LoadLibrary(ENGINE_BIN(dedicated)); + + if (!dedicated) + { + char *error; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&error, + 0, + NULL); + + char msg[1024]; + _snprintf(msg, sizeof(msg) - 1, "Failed to load the launcher DLL:\n\n%s", error); + MessageBox(0, msg, "Launcher Error", MB_OK); + + LocalFree(error); + return 0; + } + + DedicatedMain_t main = (DedicatedMain_t)GetProcAddress(dedicated, "DedicatedMain"); + + int ret = main(hInstance, hPrevInstance, lpCmdLine, nCmdShow); + + FreeLibrary(dedicated); + + return ret; +} + +#else + +int main(int argc, char **argv) +{ + char cwd[PATH_MAX]; + char pathBuf[4096]; + + char *path = getenv(LIB_PATH); + + if (!getcwd(cwd, sizeof(cwd))) + { + printf("getcwd failed (%s)\n", strerror(errno)); + return -1; + } + + snprintf(pathBuf, sizeof(pathBuf), LIB_PATH "=%s/bin:%s", cwd, path); + if (putenv(pathBuf) != 0) + { + printf("%s\n", strerror(errno)); + return -1; + } + + void *dedicated = dlopen(ENGINE_BIN(dedicated), RTLD_NOW); + +#if defined(ENGINE_BIN_ALT) + if (!dedicated) + dedicated = dlopen(ENGINE_BIN_ALT(dedicated), RTLD_NOW); +#endif + + if (!dedicated) + { + printf("Failed to open %s (%s)\n", ENGINE_BIN(dedicated), dlerror()); + return -1; + } + +#if defined(WANTS_DEBUGSTR_HACK) + BlockDebugString(); +#endif + + DedicatedMain_t main = (DedicatedMain_t)dlsym(dedicated, "DedicatedMain"); + if (!main) + { + printf("Failed to find dedicated server entry point (%s)\n", dlerror()); + return -1; + } + + int ret = main(argc, argv); + + dlclose(dedicated); + + return ret; +} +#endif diff --git a/dedicated_main/resource.h b/dedicated_main/resource.h new file mode 100644 index 00000000..5409fb68 --- /dev/null +++ b/dedicated_main/resource.h @@ -0,0 +1,23 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by dedicated_main.rc +// +#define IDI_DEDICATED 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/dedicated_main/srcds.ico b/dedicated_main/srcds.ico new file mode 100644 index 0000000000000000000000000000000000000000..bda52dd29d4649b5d9890db4643f1fc4adba72f8 GIT binary patch literal 29926 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