diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ed5c69e..bd2732bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,17 +4,38 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased] +## [unreleased] - xxxx-xx-xx ### Added -- Implement DHT into node network code. +- Add host information to /info endpoint (request) + +## [0.6.0] - 2018-12-30 + +### Added + +- Implement unbanclient command. +- Implement /serverlist api endpoint on dedicated servers +- Add dvar to control the server query rate (net_serverQueryLimit & net_serverFrames) ### Changed +- Update dependencies + ### Fixed - Fix mods not working in private matches. +- Fix multiple game structures (map tools) +- Fix multiple vulnerability's +- Fix lag spikes on lower end PCs +- Fix invalid name check +- Fix openLink command crash issue +- Fix lobby server map downloading +- Fix steam integration + +### Known issues + +- HTTPS is not supported for fast downloads at the moment. ## [0.5.4] - 2017-07-09 diff --git a/deps/json11 b/deps/json11 index ec4e4521..8d33613e 160000 --- a/deps/json11 +++ b/deps/json11 @@ -1 +1 @@ -Subproject commit ec4e45219af1d7cde3d58b49ed762376fccf1ace +Subproject commit 8d33613ebde0e7756a026e3770330da11e741823 diff --git a/deps/libtomcrypt b/deps/libtomcrypt index d432b131..01c455c3 160000 --- a/deps/libtomcrypt +++ b/deps/libtomcrypt @@ -1 +1 @@ -Subproject commit d432b13139ced07e309552f2a4893116883d434a +Subproject commit 01c455c3d5f781312de84594a11e102a20d5b959 diff --git a/deps/libtommath b/deps/libtommath index 9ff526fa..2d80a97a 160000 --- a/deps/libtommath +++ b/deps/libtommath @@ -1 +1 @@ -Subproject commit 9ff526fa2218f8697dcd0c9821330fa04682eb75 +Subproject commit 2d80a97a2b48aa1ac6d8f0df29cc4dd6297b1fba diff --git a/deps/mongoose b/deps/mongoose index e2dfac94..c2a10601 160000 --- a/deps/mongoose +++ b/deps/mongoose @@ -1 +1 @@ -Subproject commit e2dfac946dd4e4fa2312fde0aae90b18e738ad12 +Subproject commit c2a10601b9486f28b75307f003f5d9078acdce10 diff --git a/deps/pdcurses b/deps/pdcurses index 03212c5e..3f2336ad 160000 --- a/deps/pdcurses +++ b/deps/pdcurses @@ -1 +1 @@ -Subproject commit 03212c5e1783cd41370860903149245bbe36b1fa +Subproject commit 3f2336ad818b394110494ccb6d0dafed54a13950 diff --git a/deps/zlib b/deps/zlib index 41d86c73..0d36ec47 160000 --- a/deps/zlib +++ b/deps/zlib @@ -1 +1 @@ -Subproject commit 41d86c73b21191a3fa9ea5f476fc9f1fc5e4f8b3 +Subproject commit 0d36ec47f310478549c0864f215ab5c0114c49ba diff --git a/premake/zlib.lua b/premake/zlib.lua index 6657b56e..08b55e7a 100644 --- a/premake/zlib.lua +++ b/premake/zlib.lua @@ -38,7 +38,6 @@ function zlib.project() } defines { - "ZLIB_DLL", "_CRT_SECURE_NO_DEPRECATE", } diff --git a/premake5.lua b/premake5.lua index 7363f218..09687acc 100644 --- a/premake5.lua +++ b/premake5.lua @@ -219,8 +219,7 @@ protobuf.setup zlib.setup { defines = { - "ZLIB_CONST", - "ssize_t=int" + "ZLIB_CONST" }, source = path.join(depsBasePath, "zlib"), } diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 10f487eb..19510b9a 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -72,9 +72,7 @@ namespace Components Loader::Register(new Renderer()); Loader::Register(new UIFeeder()); Loader::Register(new UIScript()); -#ifndef DISABLE_ANTICHEAT Loader::Register(new AntiCheat()); -#endif Loader::Register(new Changelog()); Loader::Register(new Dedicated()); Loader::Register(new Discovery()); diff --git a/src/Components/Modules/AntiCheat.cpp b/src/Components/Modules/AntiCheat.cpp index da9af5ee..d20b1925 100644 --- a/src/Components/Modules/AntiCheat.cpp +++ b/src/Components/Modules/AntiCheat.cpp @@ -824,6 +824,64 @@ namespace Components __VMProtectEnd; } + void AntiCheat::SystemTimeDiff(LPSYSTEMTIME stA, LPSYSTEMTIME stB, LPSYSTEMTIME stC) { + FILETIME ftA, ftB, ftC; + ULARGE_INTEGER uiA, uiB, uiC; + + SystemTimeToFileTime(stA, &ftA); + SystemTimeToFileTime(stB, &ftB); + uiA.HighPart = ftA.dwHighDateTime; + uiA.LowPart = ftA.dwLowDateTime; + uiB.HighPart = ftB.dwHighDateTime; + uiB.LowPart = ftB.dwLowDateTime; + + uiC.QuadPart = uiA.QuadPart - uiB.QuadPart; + + ftC.dwHighDateTime = uiC.HighPart; + ftC.dwLowDateTime = uiC.LowPart; + FileTimeToSystemTime(&ftC, stC); + } + + void AntiCheat::CheckStartupTime() + { + __VMProtectBeginUltra(""); + FILETIME creation, exit, kernel, user; + SYSTEMTIME current, creationSt, diffSt; + + GetSystemTime(¤t); + GetProcessTimes(GetCurrentProcess(), &creation, &exit, &kernel, &user); + + FileTimeToSystemTime(&creation, &creationSt); + AntiCheat::SystemTimeDiff(¤t, &creationSt, &diffSt); + +#ifdef DEBUG + char buf[512]; + snprintf(buf, 512, "creation: %d:%d:%d:%d\n", creationSt.wHour, creationSt.wMinute, creationSt.wSecond, creationSt.wMilliseconds); + OutputDebugStringA(buf); + + snprintf(buf, 512, "current: %d:%d:%d:%d\n", current.wHour, current.wMinute, current.wSecond, current.wMilliseconds); + OutputDebugStringA(buf); + + snprintf(buf, 512, "diff: %d:%d:%d:%d\n", diffSt.wHour, diffSt.wMinute, diffSt.wSecond, diffSt.wMilliseconds); + OutputDebugStringA(buf); +#endif + + // crash client if they are using process suspension to inject dlls during startup (aka before we got to here) + // maybe tweak this value depending on what the above logging reveals during testing, + // but 5 seconds seems about right for now + int time = diffSt.wMilliseconds + (diffSt.wSecond * 1000) + (diffSt.wMinute * 1000 * 60); + if (time > 5000) { + Components::AntiCheat::CrashClient(); + } + + // use below for logging when using StartSuspended.exe + // FILE* f = fopen("times.txt", "a"); + // fwrite(buf, 1, strlen(buf), f); + // fclose(f); + + __VMProtectEnd; + } + AntiCheat::AntiCheat() { __VMProtectBeginUltra(""); @@ -831,13 +889,12 @@ namespace Components time(nullptr); AntiCheat::Flags = NO_FLAG; -#ifdef DEBUG +#ifdef DISABLE_ANTICHEAT Command::Add("penis", [](Command::Params*) { AntiCheat::CrashClient(); }); #else - Utils::Hook(0x507BD5, AntiCheat::PatchWinAPI, HOOK_CALL).install()->quick(); Utils::Hook(0x5082FD, AntiCheat::LostD3DStub, HOOK_CALL).install()->quick(); Utils::Hook(0x51C76C, AntiCheat::CinematicStub, HOOK_CALL).install()->quick(); @@ -866,6 +923,7 @@ namespace Components // Set the integrity flag AntiCheat::Flags |= AntiCheat::IntergrityFlag::INITIALIZATION; + #endif __VMProtectEnd; diff --git a/src/Components/Modules/AntiCheat.hpp b/src/Components/Modules/AntiCheat.hpp index d2af2551..9cbb2ff3 100644 --- a/src/Components/Modules/AntiCheat.hpp +++ b/src/Components/Modules/AntiCheat.hpp @@ -54,6 +54,9 @@ namespace Components static void UninstallLibHook(); static void InstallLibHook(); + static void CheckStartupTime(); + static void SystemTimeDiff(LPSYSTEMTIME stA, LPSYSTEMTIME stB, LPSYSTEMTIME stC); + private: enum IntergrityFlag { @@ -114,3 +117,4 @@ namespace Components static Utils::Hook VirtualProtectHook[2]; }; } + diff --git a/src/Components/Modules/Auth.cpp b/src/Components/Modules/Auth.cpp index 4a0ea9fc..a4fbefd8 100644 --- a/src/Components/Modules/Auth.cpp +++ b/src/Components/Modules/Auth.cpp @@ -86,7 +86,7 @@ namespace Components return; } - if (Steam::Enabled() && !Dvar::Var("cl_anonymous").get() && Steam::Proxy::SteamUser_) + if (Steam::Enabled() && !Friends::IsInvisible() && !Dvar::Var("cl_anonymous").get() && Steam::Proxy::SteamUser_) { infostr.set("realsteamId", Utils::String::VA("%llX", Steam::Proxy::SteamUser_->GetSteamID().bits)); } diff --git a/src/Components/Modules/CardTitles.cpp b/src/Components/Modules/CardTitles.cpp index 135c1b00..00120a8f 100644 --- a/src/Components/Modules/CardTitles.cpp +++ b/src/Components/Modules/CardTitles.cpp @@ -220,6 +220,12 @@ namespace Components // Table lookup stuff Utils::Hook(0x62DCC1, CardTitles::TableLookupByRowHookStub).install()->quick(); Utils::Hook::Nop(0x62DCC6, 1); + + // This is placed here in case the anticheat has been disabled! + // This checks specifically for launching the process suspended to inject a dll +#if !defined(DISABLE_ANTICHEAT) + AntiCheat::CheckStartupTime(); +#endif } CardTitles::~CardTitles() diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 628f3652..a9d98774 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -701,9 +701,11 @@ namespace Components //if (!Download::VerifyPassword(nc, reinterpret_cast(ev_data))) return; Utils::InfoString status = ServerInfo::GetInfo(); + Utils::InfoString host = ServerInfo::GetHostInfo(); std::map info; info["status"] = status.to_json(); + info["host"] = host.to_json(); std::vector players; diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index 3e9905d5..820d70f1 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -232,53 +232,6 @@ namespace Components Logger::Print("Old exception handler was 0x%010X.\n", oldHandler); }); -#pragma warning(push) -#pragma warning(disable:4740) // flow in or out of inline asm code suppresses global optimization - Command::Add("debug_minidump", [](Command::Params*) - { - // The following code was taken from VC++ 8.0 CRT (invarg.c: line 104) - - CONTEXT ContextRecord; - EXCEPTION_RECORD ExceptionRecord; - ZeroMemory(&ContextRecord, sizeof(CONTEXT)); - - __asm - { - mov [ContextRecord.Eax], eax - mov [ContextRecord.Ecx], ecx - mov [ContextRecord.Edx], edx - mov [ContextRecord.Ebx], ebx - mov [ContextRecord.Esi], esi - mov [ContextRecord.Edi], edi - mov word ptr [ContextRecord.SegSs], ss - mov word ptr [ContextRecord.SegCs], cs - mov word ptr [ContextRecord.SegDs], ds - mov word ptr [ContextRecord.SegEs], es - mov word ptr [ContextRecord.SegFs], fs - mov word ptr [ContextRecord.SegGs], gs - - pushfd - pop [ContextRecord.EFlags] - } - - ContextRecord.ContextFlags = CONTEXT_CONTROL; - ContextRecord.Eip = reinterpret_cast(_ReturnAddress()); - ContextRecord.Esp = reinterpret_cast(_AddressOfReturnAddress()); - ContextRecord.Ebp = *reinterpret_cast(_AddressOfReturnAddress()) - 1; - - ZeroMemory(&ExceptionRecord, sizeof(EXCEPTION_RECORD)); - - ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT; - ExceptionRecord.ExceptionAddress = _ReturnAddress(); - - EXCEPTION_POINTERS eptr; - eptr.ExceptionRecord = &ExceptionRecord; - eptr.ContextRecord = &ContextRecord; - - Exception::ExceptionFilter(&eptr); - }); -#pragma warning(pop) - // Check if folder exists && crash-helper exists if (Utils::IO::DirectoryExists("minidumps\\") && Utils::IO::FileExists("crash-helper.exe")) diff --git a/src/Components/Modules/Friends.cpp b/src/Components/Modules/Friends.cpp index b065e6d2..3b4c1efc 100644 --- a/src/Components/Modules/Friends.cpp +++ b/src/Components/Modules/Friends.cpp @@ -124,7 +124,7 @@ namespace Components void Friends::UpdateState(bool force) { - if (Dvar::Var("cl_anonymous").get() || !Steam::Enabled()) return; + if (Dvar::Var("cl_anonymous").get() || Friends::IsInvisible() || !Steam::Enabled()) return; if (force) { @@ -228,7 +228,7 @@ namespace Components void Friends::SetPresence(const std::string& key, const std::string& value) { - if (Steam::Proxy::ClientFriends && Steam::Proxy::SteamUtils && !Dvar::Var("cl_anonymous").get() && Steam::Enabled()) + if (Steam::Proxy::ClientFriends && Steam::Proxy::SteamUtils && !Dvar::Var("cl_anonymous").get() && !Friends::IsInvisible() && Steam::Enabled()) { Friends::SetRawPresence(key.data(), value.data()); } @@ -494,6 +494,11 @@ namespace Components return appId; } + bool Friends::IsInvisible() + { + return Friends::InitialState == 7; + } + void Friends::UpdateTimeStamp() { Friends::SetPresence("iw4x_playing", Utils::String::VA("%d", Steam::SteamUtils()->GetServerRealTime())); @@ -696,10 +701,10 @@ namespace Components { if (Steam::Proxy::SteamFriends) { - Friends::InitialState = Steam::Proxy::SteamFriends->GetPersonaState(); + Friends::InitialState = Steam::Proxy::SteamFriends->GetFriendPersonaState(Steam::Proxy::SteamUser_->GetSteamID()); } - if (Dvar::Var("cl_anonymous").get() || !Steam::Enabled()) + if (Dvar::Var("cl_anonymous").get() || Friends::IsInvisible() || !Steam::Enabled()) { if (Steam::Proxy::ClientFriends) { diff --git a/src/Components/Modules/Friends.hpp b/src/Components/Modules/Friends.hpp index e9bdb469..db1ec171 100644 --- a/src/Components/Modules/Friends.hpp +++ b/src/Components/Modules/Friends.hpp @@ -23,6 +23,8 @@ namespace Components static int GetGame(SteamID user); + static bool IsInvisible(); + private: #pragma pack(push, 4) struct FriendRichPresenceUpdate diff --git a/src/Components/Modules/News.cpp b/src/Components/Modules/News.cpp index 0e2a0b1b..632f7a11 100644 --- a/src/Components/Modules/News.cpp +++ b/src/Components/Modules/News.cpp @@ -212,6 +212,11 @@ namespace Components Utils::OpenUrl(Utils::Cache::GetStaticUrl("/wiki/")); }); + UIScript::Add("visitDiscord", [](UIScript::Token) + { + Utils::OpenUrl("https://discord.gg/sKeVmR3"); + }); + Localization::Set("MPUI_CHANGELOG_TEXT", "Loading..."); Localization::Set("MPUI_MOTD_TEXT", NEWS_MOTD_DEFAULT); diff --git a/src/Components/Modules/Node.cpp b/src/Components/Modules/Node.cpp index 7639c97b..083d42a7 100644 --- a/src/Components/Modules/Node.cpp +++ b/src/Components/Modules/Node.cpp @@ -5,7 +5,7 @@ namespace Components std::recursive_mutex Node::Mutex; std::vector Node::Nodes; - bool Node::wasIngame; + bool Node::wasIngame = false; bool Node::Entry::isValid() { @@ -169,7 +169,7 @@ namespace Components { if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").get()) return; - if (Game::CL_IsCgameInitialized()) + if (!Dedicated::IsEnabled() && Game::CL_IsCgameInitialized()) { wasIngame = true; return; // don't run while ingame because it can still cause lag spikes on lower end PCs diff --git a/src/Components/Modules/ServerInfo.cpp b/src/Components/Modules/ServerInfo.cpp index 29bbe78c..c5b8ffe9 100644 --- a/src/Components/Modules/ServerInfo.cpp +++ b/src/Components/Modules/ServerInfo.cpp @@ -110,6 +110,19 @@ namespace Components } } + Utils::InfoString ServerInfo::GetHostInfo() + { + Utils::InfoString info; + + // TODO: Possibly add all Dvar starting with _ + info.set("admin", Dvar::Var("_Admin").get()); + info.set("website", Dvar::Var("_Website").get()); + info.set("email", Dvar::Var("_Email").get()); + info.set("location", Dvar::Var("_Location").get()); + + return info; + } + Utils::InfoString ServerInfo::GetInfo() { int maxclientCount = *Game::svs_numclients; diff --git a/src/Components/Modules/ServerInfo.hpp b/src/Components/Modules/ServerInfo.hpp index d7e0cf17..8fceb827 100644 --- a/src/Components/Modules/ServerInfo.hpp +++ b/src/Components/Modules/ServerInfo.hpp @@ -8,6 +8,7 @@ namespace Components ServerInfo(); ~ServerInfo(); + static Utils::InfoString GetHostInfo(); static Utils::InfoString GetInfo(); private: diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index babbc42a..dd07177c 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -207,6 +207,9 @@ namespace Components { Game::XAssetType type = Game::DB_GetXAssetNameType(typeName.data()); + if (name.find(" ", 0) != std::string::npos) + Logger::Print("Warning: asset with name '%s' contains spaces. Check your zone source file to ensure this is correct!\n", name.data()); + // Sanitize name for empty assets if (name[0] == ',') name.erase(name.begin()); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 29724f85..08b2d265 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1,6 +1,6 @@ #pragma once -#define PROTOCOL 0x95 +#define PROTOCOL 0x96 #define NUM_CUSTOM_CLASSES 15 #define SEMANTIC_WATER_MAP 11 #define FX_ELEM_FIELD_COUNT 90 diff --git a/src/Steam/Proxy.cpp b/src/Steam/Proxy.cpp index b834a423..36641634 100644 --- a/src/Steam/Proxy.cpp +++ b/src/Steam/Proxy.cpp @@ -86,7 +86,11 @@ namespace Steam if (ud_insn_mnemonic(&ud) == UD_Iret) { const ud_operand* operand = ud_insn_opr(&ud, 0); - if (!operand) break; + if (!operand) + { + *params = 0; + return true; + } if (operand->type == UD_OP_IMM && operand->size == 16) { @@ -110,6 +114,8 @@ namespace Steam } } } + + if (*reinterpret_cast(ud.pc) == 0xCC) break; } return false;