userinfo spam

This commit is contained in:
6arelyFuture 2021-12-26 18:45:48 +01:00
parent 1119a5e7a2
commit 45d7c3daf5
Signed by: Future
GPG Key ID: FA77F074E98D98A5
11 changed files with 443 additions and 43 deletions

View File

@ -91,6 +91,11 @@ namespace cheats
{
command::execute(utils::string::va("cmd mr %i 2 allies", *game::serverId), true);
});
key_catcher::on_key_press("8", [](const game::LocalClientNum_t&)
{
command::execute(utils::string::va("cmd mr %i -1 endround", *game::serverId), true);
});
}
};
}

170
src/component/scheduler.cpp Normal file
View File

@ -0,0 +1,170 @@
#include <stdinc.hpp>
#include "loader/component_loader.hpp"
#include "utils/concurrency.hpp"
#include "utils/hook.hpp"
#include "scheduler.hpp"
namespace scheduler
{
std::thread::id async_thread_id;
namespace
{
struct task
{
std::function<bool()> handler{};
std::chrono::milliseconds interval{};
std::chrono::high_resolution_clock::time_point last_call{};
};
using task_list = std::vector<task>;
class task_pipeline
{
public:
void add(task&& task)
{
new_callbacks_.access([&task, this](task_list& tasks)
{
tasks.emplace_back(std::move(task));
});
}
void clear()
{
callbacks_.access([&](task_list& tasks)
{
this->merge_callbacks();
tasks.clear();
});
}
void execute()
{
callbacks_.access([&](task_list& tasks)
{
this->merge_callbacks();
for (auto i = tasks.begin(); i != tasks.end();)
{
const auto now = std::chrono::high_resolution_clock::now();
const auto diff = now - i->last_call;
if (diff < i->interval)
{
++i;
continue;
}
i->last_call = now;
const auto res = i->handler();
if (res == cond_end)
{
i = tasks.erase(i);
}
else
{
++i;
}
}
});
}
private:
utils::concurrency::container<task_list> new_callbacks_;
utils::concurrency::container<task_list, std::recursive_mutex> callbacks_;
void merge_callbacks()
{
callbacks_.access([&](task_list& tasks)
{
new_callbacks_.access([&](task_list& new_tasks)
{
tasks.insert(tasks.end(), std::move_iterator<task_list::iterator>(new_tasks.begin()), std::move_iterator<task_list::iterator>(new_tasks.end()));
new_tasks = {};
});
});
}
};
std::thread thread;
task_pipeline pipelines[pipeline::count];
void execute(const pipeline type)
{
assert(type >= 0 && type < pipeline::count);
pipelines[type].execute();
}
void cl_frame_stub(game::LocalClientNum_t local)
{
reinterpret_cast<void (*)(game::LocalClientNum_t)>(0x041C9B0)(local);
execute(pipeline::client);
}
}
void clear_tasks(const pipeline type)
{
return pipelines[type].clear();
}
void schedule(const std::function<bool()>& callback, const pipeline type,
const std::chrono::milliseconds delay)
{
assert(type >= 0 && type < pipeline::count);
task task;
task.handler = callback;
task.interval = delay;
task.last_call = std::chrono::high_resolution_clock::now();
pipelines[type].add(std::move(task));
}
void loop(const std::function<void()>& callback, const pipeline type,
const std::chrono::milliseconds delay)
{
schedule([callback]()
{
callback();
return cond_continue;
}, type, delay);
}
void once(const std::function<void()>& callback, const pipeline type,
const std::chrono::milliseconds delay)
{
schedule([callback]()
{
callback();
return cond_end;
}, type, delay);
}
unsigned int thread_id;
class component final : public component_interface
{
public:
void post_unpack() override
{
thread = std::thread([]()
{
while (true)
{
execute(pipeline::async);
std::this_thread::sleep_for(10ms);
}
});
async_thread_id = thread.get_id();
utils::hook::call(0x04E4A0D, cl_frame_stub);
}
};
}
REGISTER_COMPONENT(scheduler::component)

View File

@ -0,0 +1,25 @@
#pragma once
namespace scheduler
{
extern std::thread::id async_thread_id;
enum pipeline
{
client,
async,
count,
};
static const bool cond_continue = false;
static const bool cond_end = true;
void clear_tasks(const pipeline type);
void schedule(const std::function<bool()>& callback, pipeline type = pipeline::client,
std::chrono::milliseconds delay = 0ms);
void loop(const std::function<void()>& callback, pipeline type = pipeline::client,
std::chrono::milliseconds delay = 0ms);
void once(const std::function<void()>& callback, pipeline type = pipeline::client,
std::chrono::milliseconds delay = 0ms);
}

View File

@ -0,0 +1,81 @@
#include <stdinc.hpp>
#include <loader/component_loader.hpp>
#include "utils/hook.hpp"
#include "utils/info_string.hpp"
#include "utils/string.hpp"
#include "scheduler.hpp"
namespace user_info
{
namespace
{
int a1 = 0;
void cl_check_user_info(int _a1, int force)
{
a1 = _a1;
if (*game::connectionState <= game::connstate_t::CA_CHALLENGING)
return;
if (game::cl_paused->current.enabled && !force)
return;
const std::string infoString = game::Dvar_InfoString(_a1, 0x200);
utils::info_string info(infoString);
const auto colorCode = rand() % 10;
char numbers[_MAX_U64TOSTR_BASE2_COUNT];
char name[16];
_itoa_s(rand() % 10000, numbers, sizeof(numbers), 10);
_snprintf_s(name, sizeof(name), _TRUNCATE, "^%d%s", colorCode, numbers);
info.set("name", name);
info.set("ec_usingTag", "1");
info.set("ec_TagText", utils::string::va("^%dGG", colorCode));
char bigTitle[_MAX_U64TOSTR_BASE2_COUNT];
_itoa_s(rand() % 512, bigTitle, sizeof(bigTitle), 10);
info.set("ec_TitleBg", bigTitle);
game::CL_AddReliableCommand(_a1, utils::string::va("userinfo \"%s\"", info.build().data()));
}
__declspec(naked) void cl_check_user_info_stub()
{
__asm
{
pushad
push 0
push esi
call cl_check_user_info
add esp, 8
popad
ret
}
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
utils::hook::call(0x41CA53, cl_check_user_info_stub);
scheduler::loop([]
{
cl_check_user_info(a1, TRUE);
}, scheduler::pipeline::client, 4s);
}
};
}
REGISTER_COMPONENT(user_info::component)

View File

@ -8,6 +8,7 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/,
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
srand(uint32_t(time(nullptr)));
component_loader::post_unpack();
}

View File

@ -204,9 +204,8 @@ namespace game
netadrtype_t type;
unsigned char ip[4];
unsigned __int16 port;
netsrc_t localNetID;
char __pad0[4];
unsigned int index;
unsigned char ipx[10];
unsigned int addrHandleIndex;
};
static_assert(sizeof(netadr_s) == 24);
@ -278,6 +277,21 @@ namespace game
LOCAL_CLIENT_COUNT = 4
};
typedef enum
{
CA_DISCONNECTED = 0,
CA_CINEMATIC = 1,
CA_LOGO = 2,
CA_CONNECTING = 3,
CA_CHALLENGING = 4,
CA_CONNECTED = 5,
CA_SENDINGSTATS = 6,
CA_REQUESTING_MATCH_RULES = 7,
CA_LOADING = 8,
CA_PRIMED = 9,
CA_ACTIVE = 10
} connstate_t;
struct msg_t
{
int overflowed;
@ -981,45 +995,6 @@ namespace game
int hintForcedString;
};
struct trace_t
{
float fraction;
float normal[3];
int surfaceFlags;
int contents;
char material[4];
TraceHitType hitType;
unsigned __int16 hitId;
float fractionForHitType;
unsigned __int16 modelIndex;
unsigned __int16 partName;
unsigned __int16 partGroup;
bool allsolid;
bool startsolid;
bool walkable;
};
static_assert(sizeof(trace_t) == 52);
struct pml_t
{
float forward[3];
float right[3];
float up[3];
float frametime;
int msec;
int walking;
int groundPlane;
int almostGroundPlane;
trace_t groundTrace;
float impactSpeed;
float previous_origin[3];
float previous_velocity[3];
int holdrand;
};
static_assert(sizeof(pml_t) == 140);
struct clientConnection_t
{
int qport; // 0

View File

@ -29,6 +29,7 @@ namespace game
Dvar_RegisterFloat{0x4A5CF0};
WEAK symbol<void(dvar_t* var, bool value)> Dvar_SetBool{0x46DD70};
WEAK symbol<void(const char* dvarName, bool value)> Dvar_SetBoolByName{0x48C7D0};
WEAK symbol<const char*(int, int)> Dvar_InfoString{0x4028C0};
WEAK symbol<int(const char* cmd)> Key_GetBindingForCmd{0x47D300};
WEAK symbol<int(const char* keyAsText)> Key_StringToKeynum{0x50A710}; // Virtual-Key Code
@ -49,6 +50,7 @@ namespace game
WEAK symbol<void(const msg_t*, unsigned __int64)> MSG_WriteInt64{0x4906B0};
WEAK symbol<void(const msg_t*, int)> MSG_WriteShort{0x4ACD80};
WEAK symbol<void(const msg_t*, const void*, int)> MSG_WriteData{0x4F8C20};
WEAK symbol<void(int, const char*)> CL_AddReliableCommand{0x4EE3A0};
WEAK symbol<unsigned __int64()> LiveSteam_GetUid{0x4A4050};
WEAK symbol<int(unsigned __int64, const void*, unsigned int)> LiveSteam_Client_ConnectToSteamServer{0x4D6980};
@ -60,4 +62,6 @@ namespace game
WEAK symbol<HWND> g_wv_hWnd{0x5A86AF0};
WEAK symbol<HWND> s_wcd_hWnd{0x5A86330};
WEAK symbol<int> serverId{0xFF5058};
WEAK symbol<connstate_t> connectionState{0x1060214};
WEAK symbol<dvar_t> cl_paused{0x1CE6190};
}

View File

@ -1,7 +1,11 @@
#pragma once
#define DLL_EXPORT extern "C" __declspec(dllexport)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <WinSock2.h>
#include <vector>
#include <cassert>
@ -10,7 +14,6 @@
#include <iostream>
#include <algorithm>
#include <functional>
#include <queue>
#include <unordered_set>
#include <map>
#include <vector>

46
src/utils/concurrency.hpp Normal file
View File

@ -0,0 +1,46 @@
#pragma once
#include <mutex>
namespace utils::concurrency
{
template <typename T, typename MutexType = std::mutex>
class container
{
public:
template <typename R = void, typename F>
R access(F&& accessor) const
{
std::lock_guard<MutexType> _{mutex_};
return accessor(object_);
}
template <typename R = void, typename F>
R access(F&& accessor)
{
std::lock_guard<MutexType> _{mutex_};
return accessor(object_);
}
template <typename R = void, typename F>
R access_with_lock(F&& accessor) const
{
std::unique_lock<MutexType> lock{mutex_};
return accessor(object_, lock);
}
template <typename R = void, typename F>
R access_with_lock(F&& accessor)
{
std::unique_lock<MutexType> lock{mutex_};
return accessor(object_, lock);
}
T& get_raw() { return object_; }
const T& get_raw() const { return object_; }
private:
mutable MutexType mutex_{};
T object_{};
};
}

66
src/utils/info_string.cpp Normal file
View File

@ -0,0 +1,66 @@
#include <stdinc.hpp>
#include "info_string.hpp"
#include "string.hpp"
namespace utils
{
info_string::info_string(const std::string& buffer)
{
this->parse(buffer);
}
info_string::info_string(const std::string_view& buffer)
: info_string(std::string{buffer})
{
}
void info_string::set(const std::string& key, const std::string& value)
{
this->key_value_pairs_[key] = value;
}
std::string info_string::get(const std::string& key) const
{
const auto value = this->key_value_pairs_.find(key);
if (value != this->key_value_pairs_.end())
{
return value->second;
}
return "";
}
void info_string::parse(std::string buffer)
{
if (buffer[0] == '\\')
{
buffer = buffer.substr(1);
}
auto key_values = string::split(buffer, '\\');
for (size_t i = 0; !key_values.empty() && i < (key_values.size() - 1); i += 2)
{
const auto& key = key_values[i];
const auto& value = key_values[i + 1];
this->key_value_pairs_[key] = value;
}
}
std::string info_string::build() const
{
//auto first = true;
std::string info_string;
for (auto i = this->key_value_pairs_.begin(); i != this->key_value_pairs_.end(); ++i)
{
//if (first) first = false;
/*else*/ info_string.append("\\");
info_string.append(i->first); // Key
info_string.append("\\");
info_string.append(i->second); // Value
}
return info_string;
}
}

24
src/utils/info_string.hpp Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <string>
#include <unordered_map>
namespace utils
{
class info_string
{
public:
info_string() = default;
info_string(const std::string& buffer);
info_string(const std::string_view& buffer);
void set(const std::string& key, const std::string& value);
std::string get(const std::string& key) const;
std::string build() const;
private:
std::unordered_map<std::string, std::string> key_value_pairs_{};
void parse(std::string buffer);
};
}