Add unloading support + some broken antiaim (#39)

This commit is contained in:
F1ssi0N 2018-04-11 13:36:38 +01:00 committed by Marc
parent 8f6602ed3f
commit 86139daefe
16 changed files with 289 additions and 57 deletions

View File

@ -25,14 +25,34 @@
#include "utils/profiler.hh"
static sdk::Convar<bool> doghook_profiling_enabled{"doghook_profiling_enabled", false, nullptr};
static sdk::Convar<bool> doghook_unload_now{"doghook_unload_now", false, nullptr};
// Singleton for doing init / deinit of doghook
// and dealing with hooks from gamesystem
extern class Doghook doghook;
class Doghook : public GameSystem {
public:
bool inited = false;
public:
#if doghook_platform_windows()
HMODULE doghook_module_handle;
#endif
static void await_shutdown() {
while (!doghook_unload_now) std::this_thread::yield();
#if doghook_platform_windows()
// TODO: the CRT should be able to take care of all our hooks as they are all declared
// as unique_ptrs...
// All other memory should be cleaned up in destructors that happen at init_time or deinit_time!!
// TODO: make sure that all memory is getting cleaned properly!
FreeLibrary(doghook.doghook_module_handle);
#endif
}
bool init() override {
// Guard against having init() called by the game and our constructor
static bool init_happened = false;
@ -122,7 +142,6 @@ public:
// make sure that the profiler is inited first
profiler::init();
doghook_profiling_enabled = profiler::profiling_enabled();
// make sure that the netvars are initialised
// becuase their dynamic initialiser could be after the
@ -142,6 +161,14 @@ public:
// at this point we are now inited and ready to go!
inited = true;
std::thread{&await_shutdown}.detach();
// If we are already in game then do the level inits
if (IFace<sdk::Engine>()->in_game()) {
level_init_pre_entity();
level_init_post_entity();
}
}
void shutdown() override {}
@ -174,9 +201,11 @@ public:
// in theory we should be able to render here
// and be perfectly ok
// HOWEVER: it might be better to do this at frame_end()
void update([[maybe_unused]] float frametime) override {
void update(float frametime) override {
if (inited != true) return;
profiler::set_profiling_enabled(doghook_profiling_enabled);
misc::update(frametime);
}
Doghook() {
@ -187,10 +216,12 @@ public:
Doghook doghook;
#if doghook_platform_windows()
u32 __stdcall doghook_process_attach([[maybe_unused]] void *hmodule) {
u32 __stdcall doghook_process_attach(void *hmodule) {
// TODO: pass module over to the gamesystem
doghook.process_attach();
doghook.doghook_module_handle = (HMODULE)hmodule;
return 0;
}
#elif doghook_platform_linux()

View File

@ -2,22 +2,33 @@
#include "sdk/sdk.hh"
#include "modules/backtrack.hh"
#include "sdk/hooks.hh"
#include "sdk/log.hh"
#include "sdk/player.hh"
#include "modules/aimbot.hh"
#include "modules/anti_aim.hh"
#include "modules/backtrack.hh"
#include "modules/lagexploit.hh"
#include "modules/misc.hh"
#include "utils/math.hh"
#include "utils/profiler.hh"
#if doghook_platform_windows()
#include <intrin.h>
#endif
using namespace sdk;
namespace create_move {
bool *send_packet_ptr = nullptr;
bool *send_packet() {
return send_packet_ptr;
}
// TODO: should probably move elsewhere
static inline auto local_player_prediction(Player *local, UserCmd *cmd) {
char move_data_buffer[512];
@ -59,7 +70,7 @@ static inline auto local_player_prediction(Player *local, UserCmd *cmd) {
//local->tick_base() += 1;
}
hooks::HookFunction<ClientMode, 0> *create_move_hook = nullptr;
std::unique_ptr<hooks::HookFunction<ClientMode, 0>> create_move_hook;
#if doghook_platform_windows()
bool __fastcall hooked_create_move(void *instance, void *edx, float sample_framerate, UserCmd *user_cmd)
@ -69,6 +80,18 @@ bool hooked_create_move(void *instance, float sample_framerate, UserCmd *user_cm
{
profiler_profile_function();
#if doghook_platform_windows()
uptr ebp_address;
__asm mov ebp_address, ebp;
send_packet_ptr = reinterpret_cast<bool *>(***(uptr ***)ebp_address - 1);
#else
// kotm's method
uintptr_t **fp;
__asm__("mov %%ebp, %0"
: "=r"(fp));
send_packet_ptr = reinterpret_cast<bool *>(**fp - 8);
#endif
auto local_player = Player::local();
assert(local_player);
@ -97,12 +120,15 @@ bool hooked_create_move(void *instance, float sample_framerate, UserCmd *user_cm
aimbot::create_move(user_cmd);
backtrack::create_move(user_cmd);
lagexploit::create_move(user_cmd);
lagexploit::create_move(user_cmd);
anti_aim::create_move(user_cmd);
misc::create_move(user_cmd);
}
{
profiler_profile_scope("finish");
backtrack::create_move_finish(user_cmd);
}
return false;
}
@ -110,13 +136,13 @@ void level_init() {
logging::msg("=> Hooking up!");
assert(create_move_hook == nullptr);
create_move_hook = new hooks::HookFunction<ClientMode, 0>(IFace<ClientMode>().get(), 21, 22, 22, reinterpret_cast<void *>(&hooked_create_move));
create_move_hook = std::make_unique<hooks::HookFunction<ClientMode, 0>>(IFace<ClientMode>().get(), 21, 22, 22, reinterpret_cast<void *>(&hooked_create_move));
}
void level_shutdown() {
logging::msg("<= Deleting hooks");
delete create_move_hook;
create_move_hook.reset();
create_move_hook = nullptr;
}

View File

@ -3,4 +3,6 @@
namespace create_move {
void level_init();
void level_shutdown();
bool *send_packet();
} // namespace create_move

View File

@ -11,7 +11,7 @@
using namespace sdk;
namespace paint_hook {
hooks::HookFunction<EngineVgui, 0> *engine_vgui_hook;
std::unique_ptr<hooks::HookFunction<EngineVgui, 0>> engine_vgui_hook;
using StartDrawing = void(__thiscall *)(void *);
using FinishDrawing = void(__thiscall *)(void *);
@ -36,11 +36,11 @@ void hooked_paint(EngineVgui *instance, u32 paint_method)
void init_all() {
// hook up
engine_vgui_hook = new hooks::HookFunction<EngineVgui, 0>(IFace<EngineVgui>().get(), 13, 14, 14, reinterpret_cast<void *>(&hooked_paint));
engine_vgui_hook = std::make_unique<hooks::HookFunction<EngineVgui, 0>>(IFace<EngineVgui>().get(), 13, 14, 14, reinterpret_cast<void *>(&hooked_paint));
}
void shutdown_all() {
delete engine_vgui_hook;
engine_vgui_hook.reset();
}
} // namespace paint_hook

View File

@ -12,7 +12,7 @@ class bf_write;
namespace send_datagram {
hooks::HookFunction<NetChannel, 0> *send_datagram_hook;
std::unique_ptr<hooks::HookFunction<NetChannel, 0>> send_datagram_hook;
#if doghook_platform_windows()
u32 __fastcall hooked_send_datagram(NetChannel *channel, void *, bf_write *datagram)
@ -36,11 +36,11 @@ u32 hooked_send_datagram(NetChannel *channel, bf_write *datagram)
void level_init() {
assert(send_datagram_hook == nullptr);
send_datagram_hook = new hooks::HookFunction<NetChannel, 0>(IFace<Engine>()->net_channel_info(), 46, 47, 47, reinterpret_cast<void *>(&hooked_send_datagram));
send_datagram_hook = std::make_unique<hooks::HookFunction<NetChannel, 0>>(IFace<Engine>()->net_channel_info(), 46, 47, 47, reinterpret_cast<void *>(&hooked_send_datagram));
}
void level_shutdown() {
delete send_datagram_hook;
send_datagram_hook.reset();
send_datagram_hook = nullptr;
}

View File

@ -344,8 +344,11 @@ static auto try_autoshoot(sdk::UserCmd *cmd) {
}
if (autoshoot_allowed) cmd->buttons |= 1;
return autoshoot_allowed;
}
static Convar<bool> doghook_aimbot_always_aim = Convar<bool>{"doghook_aimbot_always_aim", false, nullptr};
static Convar<bool> doghook_aimbot_silent = Convar<bool>{"doghook_aimbot_silent", true, nullptr};
static Convar<bool> doghook_aimbot_autoshoot = Convar<bool>{"doghook_aimbot_autoshoot", true, nullptr};
static Convar<bool> doghook_aimbot_aim_if_not_attack = Convar<bool>{"doghook_aimbot_aim_if_not_attack", true, nullptr};
@ -372,18 +375,19 @@ void create_move(sdk::UserCmd *cmd) {
auto new_angles = delta.to_angle();
new_angles = clamp_angle(new_angles);
auto new_movement = fix_movement_for_new_angles({cmd->forwardmove, cmd->sidemove, 0}, cmd->viewangles, new_angles);
// TODO: shouldnt this be on the outside instead
if (local_weapon->can_shoot(local_player->tick_base())) {
cmd->viewangles = new_angles;
auto shot = (doghook_aimbot_autoshoot && try_autoshoot(cmd)) || (cmd->buttons & 1);
if (doghook_aimbot_autoshoot == true) try_autoshoot(cmd);
if (shot || doghook_aimbot_always_aim) {
auto new_movement = fix_movement_for_new_angles({cmd->forwardmove, cmd->sidemove, 0}, cmd->viewangles, new_angles);
cmd->viewangles = new_angles;
cmd->forwardmove = new_movement.x;
cmd->sidemove = new_movement.y;
cmd->forwardmove = new_movement.x;
cmd->sidemove = new_movement.y;
cmd->tick_count -= target.cmd_delta;
cmd->tick_count -= target.cmd_delta;
}
}
if (doghook_aimbot_silent == false) IFace<Engine>()->set_view_angles(new_angles);

88
src/modules/anti_aim.cc Normal file
View File

@ -0,0 +1,88 @@
#include <precompiled.hh>
#include "anti_aim.hh"
#include <hooks/createmove.hh>
#include <sdk/convar.hh>
#include <sdk/sdk.hh>
using namespace sdk;
namespace anti_aim {
Convar<bool> doghook_antiaim_enabled{"doghook_antiaim_enabled", true, nullptr};
Convar<float> doghook_antiaim_real_angle{"doghook_antiaim_real_angle", 90, -1000, 1000, nullptr};
Convar<float> doghook_antiaim_fake_angle{"doghook_antiaim_fake_angle", -90, -1000, 1000, nullptr};
Convar<float> doghook_antiaim_pitch{"doghook_antiaim_pitch_angle", 0, -1000, 1000, nullptr};
Convar<bool> doghook_antiaim_force_sendpacket_false{"doghook_antiaim_force_sendpacket_false", false, nullptr};
Convar<bool> doghook_antiaim_add_to_angles{"doghook_antiaim_add_to_angles", true, nullptr};
Convar<bool> doghook_antiaim_set_pitch{"doghook_antiaim_set_pitch", true, nullptr};
auto send_packet_flip = false;
inline static auto clamp_angle(const math::Vector &angles) {
math::Vector out;
out.x = angles.x;
out.y = angles.y;
out.z = 0;
while (out.x > 89.0f) out.x -= 180.0f;
while (out.x < -89.0f) out.x += 180.0f;
while (out.y > 180.0f) out.y -= 360.0f;
while (out.y < -180.0f) out.y += 360.0f;
out.y = std::clamp(out.y, -180.0f, 180.0f);
out.x = std::clamp(out.x, -90.0f, 90.0f);
return out;
}
inline static auto fix_movement_for_new_angles(const math::Vector &movement, const math::Vector &old_angles, const math::Vector &new_angles) {
math::Matrix3x4 rotate_matrix;
auto delta_angles = new_angles - old_angles;
delta_angles = clamp_angle(delta_angles);
rotate_matrix.from_angle(delta_angles);
return rotate_matrix.rotate_vector(movement);
}
void create_move(sdk::UserCmd *cmd) {
auto send_packet = create_move::send_packet();
if (!(cmd->buttons & IN_ATTACK) && doghook_antiaim_enabled) {
auto old_angles = cmd->viewangles;
if (send_packet_flip) {
if (doghook_antiaim_add_to_angles)
cmd->viewangles.y += doghook_antiaim_real_angle;
else
cmd->viewangles.y = doghook_antiaim_real_angle;
} else {
if (doghook_antiaim_add_to_angles)
cmd->viewangles.y += doghook_antiaim_fake_angle;
else
cmd->viewangles.y = doghook_antiaim_fake_angle;
}
if (doghook_antiaim_set_pitch)
cmd->viewangles.x = doghook_antiaim_pitch;
//cmd->viewangles.x = -90.0f;
//clamp_angle(cmd->viewangles);
auto new_movement = fix_movement_for_new_angles({cmd->forwardmove, cmd->sidemove, 0}, old_angles, cmd->viewangles);
cmd->forwardmove = new_movement.x;
cmd->sidemove = new_movement.y;
*send_packet = send_packet_flip;
send_packet_flip = !send_packet_flip;
if (doghook_antiaim_force_sendpacket_false) *send_packet = false;
}
}
} // namespace anti_aim

9
src/modules/anti_aim.hh Normal file
View File

@ -0,0 +1,9 @@
#pragma once
namespace sdk {
class UserCmd;
}
namespace anti_aim {
void create_move(sdk::UserCmd *cmd);
}

View File

@ -4,6 +4,8 @@
#include <sdk/convar.hh>
#include <sdk/interface.hh>
#include <sdk/netvar.hh>
#include <sdk/player.hh>
#include <sdk/sdk.hh>
using namespace sdk;
@ -53,6 +55,8 @@ enum cvar_flags {
// Note: IVEngineClient::ClientCmd_Unrestricted can run any client command.
};
Netvar local_angles{"DT_BasePlayer", "pl", "deadflag"};
void init_all() {
for (auto c : sdk::ConvarWrapper::get_range()) {
auto flags = c.flags();
@ -67,5 +71,20 @@ void init_all() {
c.set_flags(flags);
}
local_angles.offset_delta(4);
}
Convar<bool> doghook_misc_show_aa{"doghook_misc_show_aa", true, nullptr};
math::Vector last_viewangles;
void create_move(sdk::UserCmd *cmd) {
last_viewangles = cmd->viewangles;
}
void update(float frametime) {
if (!IFace<Engine>()->in_game()) return;
}
} // namespace misc

View File

@ -1,5 +1,11 @@
#pragma once
namespace sdk {
class UserCmd;
}
namespace misc {
void init_all();
}
void create_move(sdk::UserCmd *cmd);
void update(float frametime);
} // namespace misc

View File

@ -329,6 +329,10 @@ ConvarBase::~ConvarBase() {
auto modifiable = const_cast<ConvarBase *>(c);
if (c->next == this) modifiable->next = this->next;
}
// Cleanup tf_convar
// This unregisters itself
delete this->tf_convar;
}
void ConvarBase::init_all() {

View File

@ -9,27 +9,66 @@ GameSystem::GameSystem() {
head = this;
}
// TODO: remove
template <typename T>
struct UtlVector {
T * mem;
int alloc_count;
int grow_size;
int size;
T * dbg_elements;
};
GameSystem::~GameSystem() {
// TODO: remove the gamesystem!
// Check whether client was already unloaded
if (signature::resolve_library("client") == nullptr) return;
#if doghook_platform_windows()
// We are going to have to get a little creative here...
// Since no one except the destructors call Remove() it gets inlined into them
// We cant call those for obvious reasons...
// Recreate it !
// Windows:
// CUtlVector::FindAndRemove -> 55 8B EC 53 56 57 8B F9 33 D2 8B 77 0C
// s_GameSystemsPerFrame -> B9 ? ? ? ? E8 ? ? ? ? 5E 8B E5 5D C3
// s_GameSystems -> A1 ? ? ? ? 8B 0C B8 8B 01
using FindAndRemoveFn = void(__thiscall *)(void *, IGameSystem **);
static auto find_remove = signature::find_pattern<FindAndRemoveFn>("client", "55 8B EC 53 56 57 8B F9 33 D2 8B 77 0C", 0);
static auto s_GameSystems = *signature::find_pattern<UtlVector<IGameSystem *> **>("client", "A1 ? ? ? ? 8B 0C B8 8B 01", 1);
static auto s_GameSystemsPerFrame = *signature::find_pattern<UtlVector<IGameSystem *> **>("client", "A1 ? ? ? ? 8B 35 ? ? ? ? 8B CE 8B 04 B8", 1);
auto to_find = (IGameSystem *)this;
IGameSystem **mem = s_GameSystems->mem;
find_remove(s_GameSystems, &to_find);
find_remove(s_GameSystemsPerFrame, &to_find);
#else
#endif
}
void GameSystem::add_all() {
using AddFn = void (*)(IGameSystem *);
AddFn add_fn;
if constexpr (doghook_platform::windows()) {
add_fn = reinterpret_cast<AddFn>(
signature::resolve_callgate(
signature::find_pattern("client", "E8 ? ? ? ? 83 C4 04 8B 76 04 85 F6 75 D0")));
} else if constexpr (doghook_platform::linux()) {
add_fn = reinterpret_cast<AddFn>(
signature::resolve_callgate(
signature::find_pattern("client", "E8 ? ? ? ? 8B 5B 04 85 DB 75 C1")));
} else if constexpr (doghook_platform::osx()) {
add_fn = reinterpret_cast<AddFn>(
signature::resolve_callgate(
signature::find_pattern("client", "E8 ? ? ? ? 8B 7F 04 85 FF 75 A1")));
}
using AddFn = void (*)(IGameSystem *);
static AddFn add_fn = []() {
if constexpr (doghook_platform::windows()) {
return reinterpret_cast<AddFn>(
signature::resolve_callgate(
signature::find_pattern("client", "E8 ? ? ? ? 83 C4 04 8B 76 04 85 F6 75 D0")));
} else if constexpr (doghook_platform::linux()) {
return reinterpret_cast<AddFn>(
signature::resolve_callgate(
signature::find_pattern("client", "E8 ? ? ? ? 8B 5B 04 85 DB 75 C1")));
} else if constexpr (doghook_platform::osx()) {
return reinterpret_cast<AddFn>(
signature::resolve_callgate(
signature::find_pattern("client", "E8 ? ? ? ? 8B 7F 04 85 FF 75 A1")));
}
}();
assert(add_fn);

View File

@ -115,10 +115,10 @@ public:
template <typename T, u32 offset>
class HookFunction {
static std::vector<HookInstance<T, offset> *> hooks;
static std::vector<std::shared_ptr<HookInstance<T, offset>>> hooks;
auto create_hook_instance(T *instance) {
auto h = new HookInstance<T, offset>(instance);
auto h = std::make_shared<HookInstance<T, offset>>(instance);
hooks.push_back(h);
return h;
}
@ -130,7 +130,7 @@ class HookFunction {
public:
HookFunction(T *instance, u32 index_windows, u32 index_linux, u32 index_osx, void *f) {
assert(instance);
HookInstance<T, offset> *val = nullptr;
std::shared_ptr<HookInstance<T, offset>> val;
for (auto &v : hooks) {
if (v->get_instance() == instance) {
@ -186,6 +186,6 @@ public:
};
template <typename T, u32 offset>
std::vector<HookInstance<T, offset> *> HookFunction<T, offset>::hooks;
std::vector<std::shared_ptr<HookInstance<T, offset>>> HookFunction<T, offset>::hooks;
} // namespace hooks

View File

@ -8,10 +8,10 @@ using namespace sdk;
static Netvar *head;
void Netvar::Tree::populate_recursive(RecvTable *t, netvar_tree *nodes) {
void Netvar::Tree::populate_recursive(RecvTable *t, TreeNode *nodes) {
for (auto i = 0; i < t->prop_count; i++) {
auto * prop = t->prop(i);
const auto new_node = new node();
const auto new_node = std::make_shared<Node>();
new_node->p = prop;
if (prop->recv_type == 6) populate_recursive(prop->as_datatable(), &new_node->children);
@ -28,7 +28,7 @@ void Netvar::Tree::init() {
auto cc = IFace<Client>()->get_all_classes();
while (cc != nullptr) {
const auto new_node = new node();
const auto new_node = std::make_shared<Node>();
new_node->p = nullptr;
populate_recursive(cc->recv_table, &new_node->children);

View File

@ -10,17 +10,17 @@ class Netvar {
class Tree {
struct node;
using netvar_tree = std::vector<std::pair<const char *, node *>>;
struct Node;
using TreeNode = std::vector<std::pair<const char *, std::shared_ptr<Node>>>;
struct node {
netvar_tree children;
struct Node {
TreeNode children;
class RecvProp *p;
};
netvar_tree prop_tree;
TreeNode prop_tree;
void populate_recursive(class RecvTable *t, netvar_tree *nodes);
void populate_recursive(class RecvTable *t, TreeNode *nodes);
public:
Tree();
@ -53,6 +53,8 @@ public:
return *reinterpret_cast<T *>(static_cast<char *>(instance) + offset);
}
void offset_delta(u32 d) { offset += d; }
static void init_all();
};
} // namespace sdk

View File

@ -109,7 +109,9 @@ void *signature::resolve_library(const char *name) {
auto handle = GetModuleHandleA(buffer);
assert(handle);
// TODO: this is commented out to mimic linux behaviour
// TODO: do we really want this??
//assert(handle);
return handle;
@ -136,8 +138,8 @@ void *signature::resolve_library(const char *name) {
search_directory(name, "./bin", found)) {
auto handle = dlopen(found, RTLD_NOLOAD);
if (handle == nullptr) {
printf("force loading library %s\n", name);
handle = dlopen(found, RTLD_NOW);
//printf("force loading library %s\n", name);
//handle = dlopen(found, RTLD_NOW);
}
return handle;
}