From 7ca813e24fac20e54f18f0bb465dee2f0c585bb4 Mon Sep 17 00:00:00 2001 From: nastys <@> Date: Wed, 12 Feb 2020 22:24:17 +0100 Subject: [PATCH] Add DSCRemote --- source-code/PD-Loader.sln | 6 + source-code/data/plugins/config.ini | 1 + .../plugins/DSCRemote/DSCRemote.vcxproj | 98 +++++++++ .../DSCRemote/DSCRemote.vcxproj.filters | 10 + .../plugins/DSCRemote/PluginConfigApi.h | 168 +++++++++++++++ .../source/plugins/DSCRemote/dllmain.cpp | 201 ++++++++++++++++++ .../source/plugins/DSCRemote/framework.h | 17 ++ 7 files changed, 501 insertions(+) create mode 100644 source-code/source/plugins/DSCRemote/DSCRemote.vcxproj create mode 100644 source-code/source/plugins/DSCRemote/DSCRemote.vcxproj.filters create mode 100644 source-code/source/plugins/DSCRemote/PluginConfigApi.h create mode 100644 source-code/source/plugins/DSCRemote/dllmain.cpp create mode 100644 source-code/source/plugins/DSCRemote/framework.h diff --git a/source-code/PD-Loader.sln b/source-code/PD-Loader.sln index 7ebb452..1d85914 100644 --- a/source-code/PD-Loader.sln +++ b/source-code/PD-Loader.sln @@ -23,6 +23,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShaderPatch", "source\plugi EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DivaWig", "source\plugins\DivaWig\DivaWig.vcxproj", "{2394C586-F73B-4EF2-BA3E-2A0FC3034B1A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DSCRemote", "source\plugins\DSCRemote\DSCRemote.vcxproj", "{8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -69,6 +71,10 @@ Global {2394C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.Build.0 = Debug|x64 {2394C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.ActiveCfg = Release|x64 {2394C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.Build.0 = Release|x64 + {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.ActiveCfg = Debug|x64 + {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.Build.0 = Debug|x64 + {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.ActiveCfg = Release|x64 + {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/source-code/data/plugins/config.ini b/source-code/data/plugins/config.ini index ef1e02f..9a2d80a 100644 --- a/source-code/data/plugins/config.ini +++ b/source-code/data/plugins/config.ini @@ -102,3 +102,4 @@ r.Height=1080 [plugins] DivaWig.dva=0 +DSCRemote.dva=0 diff --git a/source-code/source/plugins/DSCRemote/DSCRemote.vcxproj b/source-code/source/plugins/DSCRemote/DSCRemote.vcxproj new file mode 100644 index 0000000..1f6bd1b --- /dev/null +++ b/source-code/source/plugins/DSCRemote/DSCRemote.vcxproj @@ -0,0 +1,98 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {8544C599-F73B-4EF2-BA3E-2A0FC3034B1A} + DSCRemote + 10.0 + + + + DynamicLibrary + true + v142 + MultiByte + + + DynamicLibrary + false + v142 + true + MultiByte + + + + + + + + + + + + + + + .dva + + + .dva + + + + Level3 + Disabled + true + true + ..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) + -d2FH4- %(AdditionalOptions) + + + Console + ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) + detours.lib;evr.lib;mfplat.lib;mfuuid.lib;strmiids.lib;syelog.lib;%(AdditionalDependencies) + -d2:-FH4- %(AdditionalOptions) + + + + + Level3 + MaxSpeed + true + true + true + true + ..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories) + MultiThreaded + -d2FH4- %(AdditionalOptions) + + + Console + true + true + detours.lib;evr.lib;mfplat.lib;mfuuid.lib;syelog.lib;%(AdditionalDependencies) + ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories) + -d2:-FH4- %(AdditionalOptions) + + + + + + + + + + + + + \ No newline at end of file diff --git a/source-code/source/plugins/DSCRemote/DSCRemote.vcxproj.filters b/source-code/source/plugins/DSCRemote/DSCRemote.vcxproj.filters new file mode 100644 index 0000000..ce68d0f --- /dev/null +++ b/source-code/source/plugins/DSCRemote/DSCRemote.vcxproj.filters @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/source-code/source/plugins/DSCRemote/PluginConfigApi.h b/source-code/source/plugins/DSCRemote/PluginConfigApi.h new file mode 100644 index 0000000..d0ffd94 --- /dev/null +++ b/source-code/source/plugins/DSCRemote/PluginConfigApi.h @@ -0,0 +1,168 @@ +#pragma once +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#include +#include + +// resolution class to store and sort the width and height easily +class resolution +{ +public: + unsigned int width; + unsigned int height; + + resolution() + { + width = 0; + height = 0; + } + + resolution(unsigned int width, unsigned int height) + { + resolution::width = width; + resolution::height = height; + } + + bool operator ==(const resolution &res2) + { + return width == res2.width && height == res2.height; + } + + // in comparisons width takes priority because it's usually displayed first + bool operator <(const resolution &res2) + { + if (width == res2.width) + return height < res2.height; + else + return width < res2.width; + } + bool operator >(const resolution &res2) + { + if (width == res2.width) + return height > res2.height; + else + return width > res2.width; + } +}; + +namespace PluginConfig +{ +#pragma pack(push, 1) + enum ConfigType { + CONFIG_BOOLEAN, + CONFIG_NUMERIC, + CONFIG_STRING, + CONFIG_DROPDOWN_INDEX, + CONFIG_DROPDOWN_TEXT, + CONFIG_DROPDOWN_NUMBER, + CONFIG_RESOLUTION, + CONFIG_GROUP_START, + CONFIG_GROUP_END, + CONFIG_BUTTON, + CONFIG_SPACER + }; + + struct PluginConfigBooleanData { + LPCWSTR iniVarName; + LPCWSTR iniSectionName; + LPCWSTR iniFilePath; + LPCWSTR friendlyName; + LPCWSTR description; + bool defaultVal; + bool saveAsString; + }; + + struct PluginConfigNumericData { + LPCWSTR iniVarName; + LPCWSTR iniSectionName; + LPCWSTR iniFilePath; + LPCWSTR friendlyName; + LPCWSTR description; + int defaultVal; + int minVal; + int maxVal; + }; + + struct PluginConfigStringData { + LPCWSTR iniVarName; + LPCWSTR iniSectionName; + LPCWSTR iniFilePath; + LPCWSTR friendlyName; + LPCWSTR description; + LPCWSTR defaultVal; + bool useUtf8; + }; + + struct PluginConfigDropdownIndexData { + LPCWSTR iniVarName; + LPCWSTR iniSectionName; + LPCWSTR iniFilePath; + LPCWSTR friendlyName; + LPCWSTR description; + int defaultVal; + std::vector valueStrings; + }; + + struct PluginConfigDropdownTextData { + LPCWSTR iniVarName; + LPCWSTR iniSectionName; + LPCWSTR iniFilePath; + LPCWSTR friendlyName; + LPCWSTR description; + LPCWSTR defaultVal; + std::vector valueStrings; + bool editable; + bool useUtf8; + }; + + struct PluginConfigDropdownNumberData { + LPCWSTR iniVarName; + LPCWSTR iniSectionName; + LPCWSTR iniFilePath; + LPCWSTR friendlyName; + LPCWSTR description; + int defaultVal; + std::vector valueInts; + bool editable; + }; + + struct PluginConfigResolutionData { + LPCWSTR iniVarName; + LPCWSTR iniVarName2; + LPCWSTR iniSectionName; + LPCWSTR iniFilePath; + LPCWSTR friendlyName; + LPCWSTR description; + resolution defaultVal; + std::vector valueResolutions; + bool editable; + }; + + struct PluginConfigGroupData + { + LPCWSTR name; + int height; + }; + + struct PluginConfigButtonData { + LPCWSTR friendlyName; + LPCWSTR description; + void(*func)(); + }; + + struct PluginConfigSpacerData { + int height; + }; + + struct PluginConfigOption + { + ConfigType cfgType; + void* data; + }; + + struct PluginConfigArray + { + int len; + PluginConfigOption* options; + }; +#pragma pack(pop) +} \ No newline at end of file diff --git a/source-code/source/plugins/DSCRemote/dllmain.cpp b/source-code/source/plugins/DSCRemote/dllmain.cpp new file mode 100644 index 0000000..9f5a635 --- /dev/null +++ b/source-code/source/plugins/DSCRemote/dllmain.cpp @@ -0,0 +1,201 @@ +#include +#pragma comment(lib, "Ws2_32.lib") +#include +#include +#include +#include "framework.h" +#include "PluginConfigApi.h" +#include + +bool(__cdecl* DSC_EXECUTE_COMMAND)(__int64 dsc_address, float delta_time, __int64 start_time, void* wait_timer, int* a5, int a6, int a7) += (bool(__cdecl*)(__int64 dsc_address, float delta_time, __int64 start_time, void* wait_timer, int* a5, int a6, int a7)) +0x14011CBA0; +bool hookedDSC_EXECUTE_COMMAND(__int64 dsc_address, float delta_time, __int64 start_time, void* wait_timer, int* a5, int a6, int a7); +void serve(); + +bool debug = false; +unsigned short port = 8139; + +void loadConfig() +{ + port = GetPrivateProfileIntW(L"general", L"port", 8139, CONFIG_FILE); + debug = GetPrivateProfileIntW(L"general", L"debug", 0, CONFIG_FILE) > 0; + + return; +} + +float last_delta_time = 0.0; +__int64 last_start_time = 0i64; +void* last_wait_timer = nullptr; +int* last_a5 = nullptr; +int last_a6 = 0; +int last_a7 = 0; + +bool hookedDSC_EXECUTE_COMMAND(__int64 dsc_address, float delta_time, __int64 start_time, void* wait_timer, int* a5, int a6, int a7) +{ + last_delta_time = delta_time; + last_start_time = start_time; + last_wait_timer = wait_timer; + last_a5 = a5; + last_a6 = a6; + last_a7 = a7; + + return DSC_EXECUTE_COMMAND(dsc_address, delta_time, start_time, wait_timer, a5, a6, a7); +} + +void serve() +{ + using namespace std; + + cout << "[DSCRemote] Staring server..." << endl; + + WSADATA wsadata; + int result = WSAStartup(MAKEWORD(2, 2), &wsadata); + if (result) // error + { + cout << "[DSCRemote] E: WSAStartup error " << result << '.' << endl; + return; + } + + SOCKET sock; + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (result == INVALID_SOCKET) + { + cout << "[DSCRemote] E: Invalid socket." << endl; + WSACleanup(); + return; + } + + sockaddr_in saddrin; + saddrin.sin_family = AF_INET; + saddrin.sin_addr.s_addr = 0; + saddrin.sin_port = htons(port); + + result = bind(sock, (sockaddr*)&saddrin, sizeof(sockaddr_in)); + if (result) // error + { + cout << "[DSCRemote] E: Couldn't bind port " << port << '.' << endl; + closesocket(sock); + WSACleanup(); + return; + } + + result = listen(sock, 1); + if (result) // error + { + cout << "[DSCRemote] E: Couldn't listen." << endl; + closesocket(sock); + WSACleanup(); + return; + } + while (true) + { + cout << "[DSCRemote] Waiting for client..." << endl; + SOCKET client_sock; + client_sock = accept(sock, NULL, NULL); + cout << "[DSCRemote] Client accepted." << endl; + + char buff_recv[64]; + vector cmdStack; + do + { + result = recv(client_sock, buff_recv, sizeof(buff_recv), 0); + if (result > 0) + { + if (debug) cout << "[DSCRemote] D: Received: " << buff_recv << endl; + if (buff_recv[0] != 'i') + { + long stack = stol(buff_recv); + for (int i = 0; i < sizeof(buff_recv); i++) buff_recv[i] = '\0'; + cmdStack.push_back(stack); + const char buff_out[] = "Stacking command/parameter. Send 'i' to inject."; + send(client_sock, buff_out, sizeof(buff_out), 0); + continue; + } + for (int i = 0; i < sizeof(buff_recv); i++) buff_recv[i] = '\0'; + + const char buff_out[] = "Injecting stack."; + send(client_sock, buff_out, sizeof(buff_out), 0); + + const int64_t dscbaseaddr = 0x140CDD978i64; + int* currentpos = (int*)(dscbaseaddr + 0x2bf2c); + int* command = (int*)(dscbaseaddr + 0xc); + + int posbk = *currentpos; + vector cmdbk; + for (int i=0; i 0); + closesocket(client_sock); + cout << "[DSCRemote] Restarting..." << endl; + } + + cout << "[DSCRemote] Bye!" << endl; + closesocket(sock); + WSACleanup(); +} + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + + if (ul_reason_for_call == DLL_PROCESS_ATTACH) + { + using namespace std; + + loadConfig(); + DisableThreadLibraryCalls(hModule); + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + cout << "[DSCRemote] Hooking functions..." << endl; + DetourAttach(&(PVOID&)DSC_EXECUTE_COMMAND, (PVOID)hookedDSC_EXECUTE_COMMAND); + cout << "[DSCRemote] Functions hooked." << endl; + DetourTransactionCommit(); + + thread* server_thread = new thread(serve); + } + + return TRUE; +} + +PluginConfig::PluginConfigOption config[] = { + { PluginConfig::CONFIG_NUMERIC, new PluginConfig::PluginConfigNumericData{ L"port", L"general", CONFIG_FILE, L"Port", L"TCP/IP port.", 8139, 1, USHRT_MAX } }, + { PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"debug", L"general", CONFIG_FILE, L"Debug", L"Print extra information.", false } }, +}; + +extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) +{ + return L"DSCRemote"; +} + +extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) +{ + return L"Allows external applications to send DSC commands via TCP/IP."; +} + +extern "C" __declspec(dllexport) PluginConfig::PluginConfigArray GetPluginOptions(void) +{ + return PluginConfig::PluginConfigArray{ _countof(config), config }; +} diff --git a/source-code/source/plugins/DSCRemote/framework.h b/source-code/source/plugins/DSCRemote/framework.h new file mode 100644 index 0000000..e9b2d2b --- /dev/null +++ b/source-code/source/plugins/DSCRemote/framework.h @@ -0,0 +1,17 @@ +#include +#include + +std::wstring ExePath() { + WCHAR buffer[MAX_PATH]; + GetModuleFileNameW(NULL, buffer, MAX_PATH); + return std::wstring(buffer); +} + +std::wstring DirPath() { + std::wstring exepath = ExePath(); + std::wstring::size_type pos = exepath.find_last_of(L"\\/"); + return exepath.substr(0, pos); +} + +std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\DSCRemote.ini"; +LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str();