diff options
Diffstat (limited to 'NorthstarDedicatedTest')
34 files changed, 1327 insertions, 0 deletions
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj new file mode 100644 index 00000000..8af2d3e0 --- /dev/null +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -0,0 +1,209 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>16.0</VCProjectVersion> + <Keyword>Win32Proj</Keyword> + <ProjectGuid>{cfad2623-064f-453c-8196-79ee10292e32}</ProjectGuid> + <RootNamespace>NorthstarDedicatedTest</RootNamespace> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + <ProjectName>Northstar</ProjectName> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;_DEBUG;NORTHSTARDEDICATEDTEST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <LanguageStandard>stdcpp17</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableUAC>false</EnableUAC> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;NDEBUG;NORTHSTARDEDICATEDTEST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <LanguageStandard>stdcpp17</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableUAC>false</EnableUAC> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>_DEBUG;NORTHSTARDEDICATEDTEST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <LanguageStandard>stdcpp17</LanguageStandard> + <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableUAC>false</EnableUAC> + <AdditionalDependencies>$(ProjectDir)include\MinHook.x64.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <PreBuildEvent> + <Command> + </Command> + </PreBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>NDEBUG;NORTHSTARDEDICATEDTEST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <LanguageStandard>stdcpp17</LanguageStandard> + <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableUAC>false</EnableUAC> + <AdditionalDependencies>$(ProjectDir)include\MinHook.x64.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <PreBuildEvent> + <Command> + </Command> + </PreBuildEvent> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="context.h" /> + <ClInclude Include="dedicated.h" /> + <ClInclude Include="hooks.h" /> + <ClInclude Include="hookutils.h" /> + <ClInclude Include="include\MinHook.h" /> + <ClInclude Include="logging.h" /> + <ClInclude Include="main.h" /> + <ClInclude Include="pch.h" /> + <ClInclude Include="sigscanning.h" /> + <ClInclude Include="sourceconsole.h" /> + <ClInclude Include="sourceinterface.h" /> + <ClInclude Include="squirrel.h" /> + <ClInclude Include="tier0.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="context.cpp" /> + <ClCompile Include="dedicated.cpp" /> + <ClCompile Include="dllmain.cpp" /> + <ClCompile Include="hooks.cpp" /> + <ClCompile Include="hookutils.cpp" /> + <ClCompile Include="logging.cpp" /> + <ClCompile Include="pch.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> + </ClCompile> + <ClCompile Include="sigscanning.cpp" /> + <ClCompile Include="sourceconsole.cpp" /> + <ClCompile Include="sourceinterface.cpp" /> + <ClCompile Include="squirrel.cpp" /> + <ClCompile Include="tier0.cpp" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters new file mode 100644 index 00000000..e9e523e8 --- /dev/null +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + <Filter Include="Header Files\include"> + <UniqueIdentifier>{d4199e4b-10d2-43ce-af9c-e1fa79e1e64e}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Shared"> + <UniqueIdentifier>{4d322431-dcaa-4f75-aee0-3b6371cf52a6}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Shared\Hooks"> + <UniqueIdentifier>{94259c8c-5411-48bf-af4f-46ca32b7d0bb}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Shared"> + <UniqueIdentifier>{4f525372-34a8-40b3-8a95-81d77cdfcf7f}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Shared\Hooks"> + <UniqueIdentifier>{4db0d1e9-9035-457f-87f1-5dc3f13b6b9e}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Dedicated"> + <UniqueIdentifier>{947835db-67d6-42c0-870d-62743f85231f}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Dedicated"> + <UniqueIdentifier>{8b8ed12a-9269-4dc3-b932-0daefdf6a388}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Client"> + <UniqueIdentifier>{b6f79919-9735-476d-8798-067a75cbeca0}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Client"> + <UniqueIdentifier>{ca657be5-c2d8-4322-a689-1154aaafe57b}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="pch.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="include\MinHook.h"> + <Filter>Header Files\include</Filter> + </ClInclude> + <ClInclude Include="hooks.h"> + <Filter>Header Files\Shared\Hooks</Filter> + </ClInclude> + <ClInclude Include="hookutils.h"> + <Filter>Header Files\Shared\Hooks</Filter> + </ClInclude> + <ClInclude Include="tier0.h"> + <Filter>Header Files\Shared</Filter> + </ClInclude> + <ClInclude Include="main.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="dedicated.h"> + <Filter>Header Files\Dedicated</Filter> + </ClInclude> + <ClInclude Include="sourceconsole.h"> + <Filter>Header Files\Client</Filter> + </ClInclude> + <ClInclude Include="squirrel.h"> + <Filter>Header Files\Shared</Filter> + </ClInclude> + <ClInclude Include="sigscanning.h"> + <Filter>Header Files\Shared\Hooks</Filter> + </ClInclude> + <ClInclude Include="logging.h"> + <Filter>Header Files\Shared</Filter> + </ClInclude> + <ClInclude Include="context.h"> + <Filter>Header Files\Shared</Filter> + </ClInclude> + <ClInclude Include="sourceinterface.h"> + <Filter>Header Files\Shared</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="dllmain.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="pch.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="hooks.cpp"> + <Filter>Source Files\Shared\Hooks</Filter> + </ClCompile> + <ClCompile Include="tier0.cpp"> + <Filter>Source Files\Shared</Filter> + </ClCompile> + <ClCompile Include="hookutils.cpp"> + <Filter>Source Files\Shared\Hooks</Filter> + </ClCompile> + <ClCompile Include="dedicated.cpp"> + <Filter>Source Files\Dedicated</Filter> + </ClCompile> + <ClCompile Include="sourceconsole.cpp"> + <Filter>Source Files\Client</Filter> + </ClCompile> + <ClCompile Include="squirrel.cpp"> + <Filter>Source Files\Shared</Filter> + </ClCompile> + <ClCompile Include="sigscanning.cpp"> + <Filter>Source Files\Shared\Hooks</Filter> + </ClCompile> + <ClCompile Include="logging.cpp"> + <Filter>Source Files\Shared</Filter> + </ClCompile> + <ClCompile Include="context.cpp"> + <Filter>Source Files\Shared</Filter> + </ClCompile> + <ClCompile Include="sourceinterface.cpp"> + <Filter>Source Files\Shared</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/NorthstarDedicatedTest/context.cpp b/NorthstarDedicatedTest/context.cpp new file mode 100644 index 00000000..6cd9d885 --- /dev/null +++ b/NorthstarDedicatedTest/context.cpp @@ -0,0 +1,16 @@ +#include "pch.h" +#include "context.h" + +const char* GetContextName(Context context) +{ + if (context == NONE) + return ""; + if (context == CLIENT) + return "CLIENT"; + else if (context == SERVER) + return "SERVER"; + else if (context == UI) + return "UI"; + + return nullptr; +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/context.h b/NorthstarDedicatedTest/context.h new file mode 100644 index 00000000..05506973 --- /dev/null +++ b/NorthstarDedicatedTest/context.h @@ -0,0 +1,11 @@ +#pragma once + +enum Context +{ + NONE, + CLIENT, + SERVER, + UI // this is used exclusively in scripts +}; + +const char* GetContextName(Context context);
\ No newline at end of file diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp new file mode 100644 index 00000000..ce4723cb --- /dev/null +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -0,0 +1,101 @@ +#include "pch.h" +#include "dedicated.h" +#include "hookutils.h" + +#include <iostream> + +bool IsDedicated() +{ + // temp: should get this from commandline + return false; +} + +void InitialiseDedicated(HMODULE engineAddress) +{ + std::cout << "InitialiseDedicated()" << std::endl; + + while (!IsDebuggerPresent()) + Sleep(100); + + // create binary patches + { + // CEngineAPI::SetStartupInfo + // prevents englishclient_frontend from loading + + char* ptr = (char*)engineAddress + 0x1C7CBE; + TempReadWrite rw(ptr); + + // je => jmp + *ptr = (char)0xEB; + } + + { + // CModAppSystemGroup::Create + // force the engine into dedicated mode by changing the first comparison to IsServerOnly to an assignment + char* ptr = (char*)engineAddress + 0x1C4EBD; + TempReadWrite rw(ptr); + + // cmp => mov + *(ptr + 1) = (char)0xC6; + *(ptr + 2) = (char)0x87; + + // 00 => 01 + *((char*)ptr + 7) = (char)0x01; + } + + { + // Some init that i'm not sure of that crashes + char* ptr = (char*)engineAddress + 0x156A63; + TempReadWrite rw(ptr); + + // nop the call to it + *ptr = (char)0x90; + *(ptr + 1) = (char)0x90; + *(ptr + 2) = (char)0x90; + *(ptr + 3) = (char)0x90; + *(ptr + 4) = (char)0x90; + } + + CDedicatedExports* dedicatedApi = new CDedicatedExports; + dedicatedApi->Sys_Printf = Sys_Printf; + dedicatedApi->RunServer = RunServer; + + // double ptr to dedicatedApi + intptr_t* ptr = (intptr_t*)((char*)engineAddress + 0x13F0B668); + + // ptr to dedicatedApi + intptr_t* doublePtr = new intptr_t; + *doublePtr = (intptr_t)dedicatedApi; + + // ptr to ptr + *ptr = (intptr_t)doublePtr; +} + +void Sys_Printf(CDedicatedExports* dedicated, char* msg) +{ + std::cout << msg << std::endl; +} + +void RunServer(CDedicatedExports* dedicated) +{ + Sys_Printf(dedicated, (char*)"CDedicatedServerAPI::RunServer(): starting"); + + HMODULE engine = GetModuleHandleA("engine.dll"); + CEngine__Frame engineFrame = (CEngine__Frame)((char*)engine + 0x1C8650); + CEngineAPI__ActivateSimulation engineApiStartSimulation = (CEngineAPI__ActivateSimulation)((char*)engine + 0x1C4370); + + void* cEnginePtr = (void*)((char*)engine + 0x7D70C8); + + CEngineAPI__SetMap engineApiSetMap = (CEngineAPI__SetMap)((char*)engine + 0x1C7B30); + + engineApiSetMap(nullptr, "mp_lobby; net_usesocketsforloopback 1"); + Sys_Printf(dedicated, (char*)"CDedicatedServerAPI::RunServer(): map mp_lobby"); + + while (true) + { + engineFrame(cEnginePtr); + //engineApiStartSimulation(nullptr, true); + Sys_Printf(dedicated, (char*)"engine->Frame()"); + Sleep(50); + } +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/dedicated.h b/NorthstarDedicatedTest/dedicated.h new file mode 100644 index 00000000..61d430ac --- /dev/null +++ b/NorthstarDedicatedTest/dedicated.h @@ -0,0 +1,30 @@ +#pragma once + +bool IsDedicated(); + +struct CDedicatedExports; // forward declare + +// functions for CDedicatedServerAPI +typedef void (*DedicatedSys_Printf)(CDedicatedExports* dedicated, char* msg); +typedef void (*DedicatedRunServer)(CDedicatedExports* dedicated); + +void Sys_Printf(CDedicatedExports* dedicated, char* msg); +void RunServer(CDedicatedExports* dedicated); + +// functions for running dedicated server +typedef bool (*CEngine__Frame)(void* engineSelf); +typedef void (*CEngineAPI__SetMap)(void* engineApiSelf, const char* pMapName); +typedef void (*CEngineAPI__ActivateSimulation)(void* engineApiSelf, bool bActive); + +// struct used internally +struct CDedicatedExports +{ + char unused[64]; + DedicatedSys_Printf Sys_Printf; // base + 64 + DedicatedRunServer RunServer; // base + 72 +}; + +// hooking stuff +extern bool bDedicatedHooksInitialised; +void InitialiseDedicated(HMODULE moduleAddress); + diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp new file mode 100644 index 00000000..f71a39a8 --- /dev/null +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -0,0 +1,49 @@ +#include "pch.h" +#include "hooks.h" +#include "main.h" +#include "squirrel.h" +#include "dedicated.h" +#include "sourceconsole.h" +#include <iostream> + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + DisableThreadLibraryCalls(hModule); + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + + InitialiseNorthstar(); + + return TRUE; +} + +// this is called from the injector and initialises stuff, dllmain is called multiple times while this should only be called once +void InitialiseNorthstar() +{ + AllocConsole(); + freopen("CONOUT$", "w", stdout); + AddLoggingSink(DefaultLoggingSink); + + // apply hooks + InstallInitialHooks(); + + if (IsDedicated()) + AddDllLoadCallback("engine.dll", InitialiseDedicated); + + if (!IsDedicated()) + { + AddDllLoadCallback("client.dll", InitialiseClientSquirrel); + AddDllLoadCallback("client.dll", InitialiseSourceConsole); + } + + AddDllLoadCallback("server.dll", InitialiseServerSquirrel); +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/hooks.cpp b/NorthstarDedicatedTest/hooks.cpp new file mode 100644 index 00000000..a3be154d --- /dev/null +++ b/NorthstarDedicatedTest/hooks.cpp @@ -0,0 +1,90 @@ +#include "pch.h" +#include "hooks.h" +#include "hookutils.h" +#include "dedicated.h" +#include "tier0.h" + +#include <wchar.h> +#include <iostream> +#include <vector> + +typedef HMODULE(*LoadLibraryExAType)(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); +HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); + +typedef HMODULE(*LoadLibraryExWType)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); +HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); + +LoadLibraryExAType LoadLibraryExAOriginal; +LoadLibraryExWType LoadLibraryExWOriginal; + +void InstallInitialHooks() +{ + //AllocConsole(); + + if (MH_Initialize() != MH_OK) + Error("MH_Initialize failed"); + + HookEnabler hook; + ENABLER_CREATEHOOK(hook, &LoadLibraryExA, &LoadLibraryExAHook, reinterpret_cast<LPVOID*>(&LoadLibraryExAOriginal)); + ENABLER_CREATEHOOK(hook, &LoadLibraryExW, &LoadLibraryExWHook, reinterpret_cast<LPVOID*>(&LoadLibraryExWOriginal)); +} + +// dll load callback stuff +// this allows for code to register callbacks to be run as soon as a dll is loaded, mainly to allow for patches to be made on dll load +struct DllLoadCallback +{ + std::string dll; + DllLoadCallbackFuncType callback; + bool called; +}; + +std::vector<DllLoadCallback*> dllLoadCallbacks; + +void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback) +{ + DllLoadCallback* callbackStruct = new DllLoadCallback; + callbackStruct->dll = dll; + callbackStruct->callback = callback; + callbackStruct->called = false; + + dllLoadCallbacks.push_back(callbackStruct); +} + +HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) +{ + HMODULE moduleAddress = LoadLibraryExAOriginal(lpLibFileName, hFile, dwFlags); + + if (moduleAddress) + { + for (auto& callbackStruct : dllLoadCallbacks) + { + if (!callbackStruct->called && strstr(lpLibFileName + (strlen(lpLibFileName) - strlen(callbackStruct->dll.c_str())), callbackStruct->dll.c_str()) != nullptr) + { + callbackStruct->callback(moduleAddress); + callbackStruct->called = true; + } + } + } + + return moduleAddress; +} + +HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) +{ + HMODULE moduleAddress = LoadLibraryExWOriginal(lpLibFileName, hFile, dwFlags); + + if (moduleAddress) + { + for (auto& callbackStruct : dllLoadCallbacks) + { + const wchar_t* callbackDll = std::wstring(callbackStruct->dll.begin(), callbackStruct->dll.end()).c_str(); + if (!callbackStruct->called && wcsstr(lpLibFileName + (wcslen(lpLibFileName) - wcslen(callbackDll)), callbackDll) != nullptr) + { + callbackStruct->callback(moduleAddress); + callbackStruct->called = true; + } + } + } + + return moduleAddress; +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/hooks.h b/NorthstarDedicatedTest/hooks.h new file mode 100644 index 00000000..972b38a6 --- /dev/null +++ b/NorthstarDedicatedTest/hooks.h @@ -0,0 +1,7 @@ +#pragma once +#include <string> + +void InstallInitialHooks(); + +typedef void(*DllLoadCallbackFuncType)(HMODULE moduleAddress); +void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback);
\ No newline at end of file diff --git a/NorthstarDedicatedTest/hookutils.cpp b/NorthstarDedicatedTest/hookutils.cpp new file mode 100644 index 00000000..c5472b57 --- /dev/null +++ b/NorthstarDedicatedTest/hookutils.cpp @@ -0,0 +1,57 @@ +#include "pch.h" +#include "hookutils.h" +#include "tier0.h" + +#include <iostream> + +TempReadWrite::TempReadWrite(void* ptr) +{ + m_ptr = ptr; + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery(m_ptr, &mbi, sizeof(mbi)); + VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect); + m_origProtection = mbi.Protect; +} + +TempReadWrite::~TempReadWrite() +{ + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery(m_ptr, &mbi, sizeof(mbi)); + VirtualProtect(mbi.BaseAddress, mbi.RegionSize, m_origProtection, &mbi.Protect); +} + + +void HookEnabler::CreateHook(LPVOID ppTarget, LPVOID ppDetour, LPVOID* ppOriginal, const char* targetName) +{ + if (MH_CreateHook(ppTarget, ppDetour, ppOriginal) == MH_OK) + { + HookTarget *target = new HookTarget; + target->targetAddress = ppTarget; + target->targetName = (char*)targetName; + + m_hookTargets.push_back(target); + } + else + { + if (targetName != nullptr) + Error("MH_CreateHook failed for function %s", targetName); + else + Error("MH_CreateHook failed for unknown function"); + } +} + +HookEnabler::~HookEnabler() +{ + for (auto& hook : m_hookTargets) + { + if (MH_EnableHook(hook->targetAddress) != MH_OK) + { + if (hook->targetName != nullptr) + Error("MH_EnableHook failed for function %s", hook->targetName); + else + Error("MH_EnableHook failed for unknown function"); + } + else + std::cout << "enabling hook " << hook->targetName << std::endl; + } +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/hookutils.h b/NorthstarDedicatedTest/hookutils.h new file mode 100644 index 00000000..dd3b15b1 --- /dev/null +++ b/NorthstarDedicatedTest/hookutils.h @@ -0,0 +1,34 @@ +#pragma once +#include <vector> + +// Sets an area of memory as writeable until the TempReadWrite object goes out of scope +class TempReadWrite +{ +private: + DWORD m_origProtection; + void* m_ptr; + +public: + TempReadWrite(void* ptr); + ~TempReadWrite(); +}; + +// Enables all hooks created with the HookEnabler object when it goes out of scope and handles hook errors +class HookEnabler +{ +private: + struct HookTarget + { + char* targetName; + LPVOID targetAddress; + }; + + std::vector<HookTarget*> m_hookTargets; + +public: + void CreateHook(LPVOID ppTarget, LPVOID ppDetour, LPVOID* ppOriginal, const char* targetName = nullptr); + ~HookEnabler(); +}; + +// macro to call HookEnabler::CreateHook with the hook's name +#define ENABLER_CREATEHOOK(enabler, ppTarget, ppDetour, ppOriginal) enabler.CreateHook(ppTarget, ppDetour, ppOriginal, #ppDetour)
\ No newline at end of file diff --git a/NorthstarDedicatedTest/include/MinHook.h b/NorthstarDedicatedTest/include/MinHook.h new file mode 100644 index 00000000..15c0a875 --- /dev/null +++ b/NorthstarDedicatedTest/include/MinHook.h @@ -0,0 +1,186 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) + #error MinHook supports only x86 and x64 systems. +#endif + +#include <windows.h> + +// MinHook Error Codes. +typedef enum MH_STATUS +{ + // Unknown error. Should not be returned. + MH_UNKNOWN = -1, + + // Successful. + MH_OK = 0, + + // MinHook is already initialized. + MH_ERROR_ALREADY_INITIALIZED, + + // MinHook is not initialized yet, or already uninitialized. + MH_ERROR_NOT_INITIALIZED, + + // The hook for the specified target function is already created. + MH_ERROR_ALREADY_CREATED, + + // The hook for the specified target function is not created yet. + MH_ERROR_NOT_CREATED, + + // The hook for the specified target function is already enabled. + MH_ERROR_ENABLED, + + // The hook for the specified target function is not enabled yet, or already + // disabled. + MH_ERROR_DISABLED, + + // The specified pointer is invalid. It points the address of non-allocated + // and/or non-executable region. + MH_ERROR_NOT_EXECUTABLE, + + // The specified target function cannot be hooked. + MH_ERROR_UNSUPPORTED_FUNCTION, + + // Failed to allocate memory. + MH_ERROR_MEMORY_ALLOC, + + // Failed to change the memory protection. + MH_ERROR_MEMORY_PROTECT, + + // The specified module is not loaded. + MH_ERROR_MODULE_NOT_FOUND, + + // The specified function is not found. + MH_ERROR_FUNCTION_NOT_FOUND +} +MH_STATUS; + +// Can be passed as a parameter to MH_EnableHook, MH_DisableHook, +// MH_QueueEnableHook or MH_QueueDisableHook. +#define MH_ALL_HOOKS NULL + +#ifdef __cplusplus +extern "C" { +#endif + + // Initialize the MinHook library. You must call this function EXACTLY ONCE + // at the beginning of your program. + MH_STATUS WINAPI MH_Initialize(VOID); + + // Uninitialize the MinHook library. You must call this function EXACTLY + // ONCE at the end of your program. + MH_STATUS WINAPI MH_Uninitialize(VOID); + + // Creates a Hook for the specified target function, in disabled state. + // Parameters: + // pTarget [in] A pointer to the target function, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a Hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszTarget [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApi( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a Hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszTarget [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + // ppTarget [out] A pointer to the target function, which will be used + // with other functions. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApiEx( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); + + // Removes an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); + + // Enables an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // enabled in one go. + MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); + + // Disables an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // disabled in one go. + MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); + + // Queues to enable an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be enabled. + MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); + + // Queues to disable an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be disabled. + MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); + + // Applies all queued changes in one go. + MH_STATUS WINAPI MH_ApplyQueued(VOID); + + // Translates the MH_STATUS to its name as a string. + const char * WINAPI MH_StatusToString(MH_STATUS status); + +#ifdef __cplusplus +} +#endif + diff --git a/NorthstarDedicatedTest/include/MinHook.x64.dll b/NorthstarDedicatedTest/include/MinHook.x64.dll Binary files differnew file mode 100644 index 00000000..b4f51c2e --- /dev/null +++ b/NorthstarDedicatedTest/include/MinHook.x64.dll diff --git a/NorthstarDedicatedTest/include/MinHook.x64.lib b/NorthstarDedicatedTest/include/MinHook.x64.lib Binary files differnew file mode 100644 index 00000000..909fe682 --- /dev/null +++ b/NorthstarDedicatedTest/include/MinHook.x64.lib diff --git a/NorthstarDedicatedTest/include/MinHook.x86.dll b/NorthstarDedicatedTest/include/MinHook.x86.dll Binary files differnew file mode 100644 index 00000000..d6167c83 --- /dev/null +++ b/NorthstarDedicatedTest/include/MinHook.x86.dll diff --git a/NorthstarDedicatedTest/include/MinHook.x86.lib b/NorthstarDedicatedTest/include/MinHook.x86.lib Binary files differnew file mode 100644 index 00000000..02f351c2 --- /dev/null +++ b/NorthstarDedicatedTest/include/MinHook.x86.lib diff --git a/NorthstarDedicatedTest/include/tier0.def b/NorthstarDedicatedTest/include/tier0.def new file mode 100644 index 00000000..6834b009 --- /dev/null +++ b/NorthstarDedicatedTest/include/tier0.def @@ -0,0 +1,10 @@ +LIBRARY tier0.dll +EXPORTS +CreateGlobalMemAlloc +g_pMemAllocSingleton +ThreadInMainThread + +Error + +LoggingSystem_RegisterLoggingListener +LoggingSystem_Log
\ No newline at end of file diff --git a/NorthstarDedicatedTest/include/tier0.exp b/NorthstarDedicatedTest/include/tier0.exp Binary files differnew file mode 100644 index 00000000..706b6de8 --- /dev/null +++ b/NorthstarDedicatedTest/include/tier0.exp diff --git a/NorthstarDedicatedTest/include/tier0.lib b/NorthstarDedicatedTest/include/tier0.lib Binary files differnew file mode 100644 index 00000000..6b0ffa5c --- /dev/null +++ b/NorthstarDedicatedTest/include/tier0.lib diff --git a/NorthstarDedicatedTest/logging.cpp b/NorthstarDedicatedTest/logging.cpp new file mode 100644 index 00000000..021613d9 --- /dev/null +++ b/NorthstarDedicatedTest/logging.cpp @@ -0,0 +1,52 @@ +#include "pch.h" +#include "logging.h" +#include "context.h" +#include "dedicated.h" +#include <vector> +#include <iostream> +#include <chrono> + +std::vector<LoggingSink> loggingSinks; + +void Log(Context context, char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + + Log(context, fmt, args); + va_end(args); +} + +void Log(Context context, char* fmt, va_list args) +{ + char buf[1024]; + vsnprintf_s(buf, _TRUNCATE, fmt, args); + + for (LoggingSink& sink : loggingSinks) + sink(context, fmt); +} + +void AddLoggingSink(LoggingSink sink) +{ + loggingSinks.push_back(sink); +} + +// default logging sink +void DefaultLoggingSink(Context context, char* message) +{ + time_t now = time(0); + tm* localTime = localtime(&now); + char timeBuf[10]; + strftime(timeBuf, sizeof(timeBuf), "%X", localTime); + + std::cout << "[" << timeBuf << "] "; + if (context != NONE) + std::cout << "[" << GetContextName(context) << "] "; + + std::cout << message; + + if (!IsDedicated()) + { + + } +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/logging.h b/NorthstarDedicatedTest/logging.h new file mode 100644 index 00000000..aa19b8f1 --- /dev/null +++ b/NorthstarDedicatedTest/logging.h @@ -0,0 +1,11 @@ +#pragma once +#include "context.h" + +typedef void(*LoggingSink)(Context context, char* fmt); + +void Log(Context context, char* fmt, ...); +void Log(Context context, char* fmt, va_list args); +void AddLoggingSink(LoggingSink sink); + +// default logging sink +void DefaultLoggingSink(Context context, char* message);
\ No newline at end of file diff --git a/NorthstarDedicatedTest/main.h b/NorthstarDedicatedTest/main.h new file mode 100644 index 00000000..ef5d86dc --- /dev/null +++ b/NorthstarDedicatedTest/main.h @@ -0,0 +1,3 @@ +#pragma once + +extern "C" __declspec(dllexport) void InitialiseNorthstar();
\ No newline at end of file diff --git a/NorthstarDedicatedTest/pch.cpp b/NorthstarDedicatedTest/pch.cpp new file mode 100644 index 00000000..64b7eef6 --- /dev/null +++ b/NorthstarDedicatedTest/pch.cpp @@ -0,0 +1,5 @@ +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. diff --git a/NorthstarDedicatedTest/pch.h b/NorthstarDedicatedTest/pch.h new file mode 100644 index 00000000..1ad845c9 --- /dev/null +++ b/NorthstarDedicatedTest/pch.h @@ -0,0 +1,11 @@ +#ifndef PCH_H +#define PCH_H + +#define _CRT_SECURE_NO_WARNINGS + +// add headers that you want to pre-compile here +#include <Windows.h> +#include "logging.h" +#include "include/MinHook.h" + +#endif
\ No newline at end of file diff --git a/NorthstarDedicatedTest/sigscanning.cpp b/NorthstarDedicatedTest/sigscanning.cpp new file mode 100644 index 00000000..c75c80f0 --- /dev/null +++ b/NorthstarDedicatedTest/sigscanning.cpp @@ -0,0 +1,39 @@ +#include "pch.h" +#include "sigscanning.h" +#include <map> + +// note: sigscanning is only really intended to be used for resolving stuff like shared function definitions +// we mostly use raw function addresses for stuff + +size_t GetDLLLength(HMODULE moduleHandle) +{ + // based on sigscn code from ttf2sdk, which is in turn based on CSigScan from https://wiki.alliedmods.net/Signature_Scanning + MEMORY_BASIC_INFORMATION mem; + VirtualQuery(moduleHandle, &mem, sizeof(mem)); + + IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)mem.AllocationBase; + IMAGE_NT_HEADERS* pe = (IMAGE_NT_HEADERS*)((unsigned char*)dos + dos->e_lfanew); + + return pe->OptionalHeader.SizeOfImage; +} + +void* FindSignature(std::string dllName, const char* sig, const char* mask) +{ + HMODULE dllAddress = GetModuleHandleA(dllName.c_str()); + char* dllEnd = (char*)(dllAddress + GetDLLLength(dllAddress)); + + size_t sigLength = strlen(mask); + + for (char* i = (char*)dllAddress; i < dllEnd - sigLength; i++) + { + int j = 0; + for (; j < sigLength; j++) + if (mask[j] != '?' && sig[j] != i[j]) + break; + + if (j == sigLength) // loop finished of its own accord + return (void*)i; + } + + return nullptr; +} diff --git a/NorthstarDedicatedTest/sigscanning.h b/NorthstarDedicatedTest/sigscanning.h new file mode 100644 index 00000000..56979fbc --- /dev/null +++ b/NorthstarDedicatedTest/sigscanning.h @@ -0,0 +1,7 @@ +#pragma once +#include <string> + +// note: sigscanning is only really intended to be used for resolving stuff like shared function definitions +// we mostly use raw function addresses for stuff + +void* FindSignature(std::string dllName, const char* sig, const char* mask);
\ No newline at end of file diff --git a/NorthstarDedicatedTest/sourceconsole.cpp b/NorthstarDedicatedTest/sourceconsole.cpp new file mode 100644 index 00000000..c862356e --- /dev/null +++ b/NorthstarDedicatedTest/sourceconsole.cpp @@ -0,0 +1,14 @@ +#include "pch.h" +#include "sourceconsole.h" +#include "sourceinterface.h" + +SourceInterface<CGameConsole>* g_SourceGameConsole; + +void InitialiseSourceConsole(HMODULE baseAddress) +{ + SourceInterface<CGameConsole> console = SourceInterface<CGameConsole>("client.dll", "CGameConsole"); + console->Initialize(); + console->Activate(); + + g_SourceGameConsole = &console; +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/sourceconsole.h b/NorthstarDedicatedTest/sourceconsole.h new file mode 100644 index 00000000..7f494dca --- /dev/null +++ b/NorthstarDedicatedTest/sourceconsole.h @@ -0,0 +1,90 @@ +#pragma once +#include "pch.h" +#include "sourceinterface.h" + +void InitialiseSourceConsole(HMODULE baseAddress); + +class EditablePanel +{ +public: + virtual ~EditablePanel() = 0; + unsigned char unknown[0x2B0]; +}; + +struct SourceColor +{ + unsigned char R; + unsigned char G; + unsigned char B; + unsigned char A; + + SourceColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a) + { + R = r; + G = g; + B = b; + A = a; + } + + SourceColor() + { + R = 0; + G = 0; + B = 0; + A = 0; + } +}; + +class IConsoleDisplayFunc +{ +public: + virtual void ColorPrint(const SourceColor& clr, const char* pMessage) = 0; + virtual void Print(const char* pMessage) = 0; + virtual void DPrint(const char* pMessage) = 0; +}; + +class CConsolePanel : public EditablePanel, public IConsoleDisplayFunc +{ + +}; + +class CConsoleDialog +{ +public: + struct VTable + { + void* unknown[298]; + void(*OnCommandSubmitted)(CConsoleDialog* consoleDialog, const char* pCommand); + }; + + VTable* m_vtable; + unsigned char unknown[0x398]; + CConsolePanel* m_pConsolePanel; +}; + +class CGameConsole +{ +public: + virtual ~CGameConsole() = 0; + + // activates the console, makes it visible and brings it to the foreground + virtual void Activate() = 0; + + virtual void Initialize() = 0; + + // hides the console + virtual void Hide() = 0; + + // clears the console + virtual void Clear() = 0; + + // return true if the console has focus + virtual bool IsConsoleVisible() = 0; + + virtual void SetParent(int parent) = 0; + + bool m_bInitialized; + CConsoleDialog* m_pConsole; +}; + +extern SourceInterface<CGameConsole>* g_SourceGameConsole;
\ No newline at end of file diff --git a/NorthstarDedicatedTest/sourceinterface.cpp b/NorthstarDedicatedTest/sourceinterface.cpp new file mode 100644 index 00000000..49a2f164 --- /dev/null +++ b/NorthstarDedicatedTest/sourceinterface.cpp @@ -0,0 +1,13 @@ +#include "pch.h" +#include "sourceinterface.h" +#include <string> +#include "tier0.h" + +template<typename T> SourceInterface<T>::SourceInterface(const std::string& moduleName, const std::string& interfaceName) +{ + HMODULE handle = GetModuleHandleA(moduleName.c_str()); + CreateInterfaceFn createInterface = (CreateInterfaceFn)GetProcAddress(handle, interfaceName.c_str()); + m_interface = (T*)createInterface(interfaceName.c_str(), NULL); + if (m_interface == nullptr) + Error("Failed to call CreateInterface for %s in %s", interfaceName, moduleName); +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/sourceinterface.h b/NorthstarDedicatedTest/sourceinterface.h new file mode 100644 index 00000000..bc4767f5 --- /dev/null +++ b/NorthstarDedicatedTest/sourceinterface.h @@ -0,0 +1,24 @@ +#pragma once +#include <string> + +// literally just copied from ttf2sdk definition +typedef void* (*CreateInterfaceFn)(const char* pName, int* pReturnCode); + +template<typename T> class SourceInterface +{ +private: + T* m_interface; + +public: + SourceInterface(const std::string& moduleName, const std::string& interfaceName); + + T* operator->() const + { + return m_interface; + } + + operator T* () const + { + return m_interface; + } +}; diff --git a/NorthstarDedicatedTest/squirrel.cpp b/NorthstarDedicatedTest/squirrel.cpp new file mode 100644 index 00000000..66bf755c --- /dev/null +++ b/NorthstarDedicatedTest/squirrel.cpp @@ -0,0 +1,67 @@ +#include "pch.h" +#include "squirrel.h" +#include "hooks.h" +#include "hookutils.h" +#include "sigscanning.h" +#include <iostream> + +// hook forward declarations +typedef SQInteger(*SQPrintType)(void* sqvm, char* fmt, ...); +SQPrintType ClientSQPrint; +SQPrintType UISQPrint; +SQPrintType ServerSQPrint; +template<Context context> SQInteger SQPrintHook(void* sqvm, char* fmt, ...); + + +// inits +SquirrelManager<CLIENT>* g_ClientSquirrelManager; +SquirrelManager<SERVER>* g_ServerSquirrelManager; + +void InitialiseClientSquirrel(HMODULE baseAddress) +{ + g_ClientSquirrelManager = new SquirrelManager<CLIENT>(); + + HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x12B00, &SQPrintHook<CLIENT>, reinterpret_cast<LPVOID*>(&ClientSQPrint)); + + // ui inits + // currently these are mostly incomplete + + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x12BA0, &SQPrintHook<UI>, reinterpret_cast<LPVOID*>(&UISQPrint)); +} + +void InitialiseServerSquirrel(HMODULE baseAddress) +{ + g_ServerSquirrelManager = new SquirrelManager<SERVER>(); + + HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1FE90, &SQPrintHook<SERVER>, reinterpret_cast<LPVOID*>(&ServerSQPrint)); +} + +// hooks +template<Context context> SQInteger SQPrintHook(void* sqvm, char* fmt, ...) +{ + va_list va; + va_start(va, fmt); + + SQChar buf[1024]; + int charsWritten = vsnprintf_s(buf, _TRUNCATE, fmt, va); + + if (charsWritten > 0) + { + if (buf[charsWritten - 1] == '\n') + buf[charsWritten - 1] == '\0'; + + Log(context, buf, ""); + } + + va_end(va); + return 0; +} + + +// manager +template<Context context> SquirrelManager<context>::SquirrelManager() +{ + +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/squirrel.h b/NorthstarDedicatedTest/squirrel.h new file mode 100644 index 00000000..627ceeaf --- /dev/null +++ b/NorthstarDedicatedTest/squirrel.h @@ -0,0 +1,26 @@ +#pragma once + +void InitialiseClientSquirrel(HMODULE baseAddress); +void InitialiseServerSquirrel(HMODULE baseAddress); + +// stolen from ttf2sdk: sqvm types +typedef float SQFloat; +typedef long SQInteger; +typedef unsigned long SQUnsignedInteger; +typedef char SQChar; + +typedef SQUnsignedInteger SQBool; +typedef SQInteger SQRESULT; + +template<Context context> class SquirrelManager +{ +public: + + +public: + SquirrelManager(); +}; + +extern SquirrelManager<CLIENT>* g_ClientSquirrelManager; +extern SquirrelManager<SERVER>* g_ServerSquirrelManager; +//extern SquirrelManager<UI> g_UISquirrelManager
\ No newline at end of file diff --git a/NorthstarDedicatedTest/tier0.cpp b/NorthstarDedicatedTest/tier0.cpp new file mode 100644 index 00000000..a52c72ce --- /dev/null +++ b/NorthstarDedicatedTest/tier0.cpp @@ -0,0 +1,33 @@ +#include "pch.h" +#include "tier0.h" +#include <stdio.h> +#include <iostream> + +void* ResolveTier0Function(const char* name) +{ + HMODULE tier0 = GetModuleHandle(L"tier0.dll"); + + // todo: maybe cache resolved funcs? idk the performance hit of getprocaddress + std::cout << "ResolveTier0Function " << name << " " << tier0 << "::" << GetProcAddress(tier0, name) << std::endl; + return GetProcAddress(tier0, name); +} + +typedef void(*Tier0Error)(const char* fmt, ...); +void Error(const char* fmt, ...) +{ + Tier0Error tier0Func = (Tier0Error)ResolveTier0Function("Error"); + + // reformat args because you can't pass varargs between funcs + char buf[1024]; + + va_list args; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + // tier0 isn't loaded yet + if (tier0Func) + tier0Func(buf); + else + std::cout << "FATAL ERROR " << buf << std::endl; +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/tier0.h b/NorthstarDedicatedTest/tier0.h new file mode 100644 index 00000000..dddd9479 --- /dev/null +++ b/NorthstarDedicatedTest/tier0.h @@ -0,0 +1,9 @@ +#pragma once +#include "pch.h" + +// get exported tier0 by name +void* ResolveTier0Function(const char* name); + +// actual function defs +// would've liked to resolve these at compile time, but we load before tier0 so not really possible +void Error(const char* fmt, ...);
\ No newline at end of file |