diff --git a/src/doghook.cc b/src/doghook.cc index f8fb584..5ac54d2 100644 --- a/src/doghook.cc +++ b/src/doghook.cc @@ -25,14 +25,34 @@ #include "utils/profiler.hh" static sdk::Convar doghook_profiling_enabled{"doghook_profiling_enabled", false, nullptr}; +static sdk::Convar 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()->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() diff --git a/src/hooks/createmove.cc b/src/hooks/createmove.cc index a897980..7836106 100644 --- a/src/hooks/createmove.cc +++ b/src/hooks/createmove.cc @@ -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 +#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 *create_move_hook = nullptr; +std::unique_ptr> 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(***(uptr ***)ebp_address - 1); +#else + // kotm's method + uintptr_t **fp; + __asm__("mov %%ebp, %0" + : "=r"(fp)); + send_packet_ptr = reinterpret_cast(**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(IFace().get(), 21, 22, 22, reinterpret_cast(&hooked_create_move)); + create_move_hook = std::make_unique>(IFace().get(), 21, 22, 22, reinterpret_cast(&hooked_create_move)); } void level_shutdown() { logging::msg("<= Deleting hooks"); - delete create_move_hook; + create_move_hook.reset(); create_move_hook = nullptr; } diff --git a/src/hooks/createmove.hh b/src/hooks/createmove.hh index eed4009..eaed37b 100644 --- a/src/hooks/createmove.hh +++ b/src/hooks/createmove.hh @@ -3,4 +3,6 @@ namespace create_move { void level_init(); void level_shutdown(); + +bool *send_packet(); } // namespace create_move diff --git a/src/hooks/engine_vgui.cc b/src/hooks/engine_vgui.cc index 33a4212..b852369 100644 --- a/src/hooks/engine_vgui.cc +++ b/src/hooks/engine_vgui.cc @@ -11,7 +11,7 @@ using namespace sdk; namespace paint_hook { -hooks::HookFunction *engine_vgui_hook; +std::unique_ptr> 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(IFace().get(), 13, 14, 14, reinterpret_cast(&hooked_paint)); + engine_vgui_hook = std::make_unique>(IFace().get(), 13, 14, 14, reinterpret_cast(&hooked_paint)); } void shutdown_all() { - delete engine_vgui_hook; + engine_vgui_hook.reset(); } } // namespace paint_hook diff --git a/src/hooks/send_datagram.cc b/src/hooks/send_datagram.cc index 39d4ed5..edb13e3 100644 --- a/src/hooks/send_datagram.cc +++ b/src/hooks/send_datagram.cc @@ -12,7 +12,7 @@ class bf_write; namespace send_datagram { -hooks::HookFunction *send_datagram_hook; +std::unique_ptr> 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(IFace()->net_channel_info(), 46, 47, 47, reinterpret_cast(&hooked_send_datagram)); + send_datagram_hook = std::make_unique>(IFace()->net_channel_info(), 46, 47, 47, reinterpret_cast(&hooked_send_datagram)); } void level_shutdown() { - delete send_datagram_hook; + send_datagram_hook.reset(); send_datagram_hook = nullptr; } diff --git a/src/modules/aimbot.cc b/src/modules/aimbot.cc index e284a43..d6052ac 100644 --- a/src/modules/aimbot.cc +++ b/src/modules/aimbot.cc @@ -344,8 +344,11 @@ static auto try_autoshoot(sdk::UserCmd *cmd) { } if (autoshoot_allowed) cmd->buttons |= 1; + + return autoshoot_allowed; } +static Convar doghook_aimbot_always_aim = Convar{"doghook_aimbot_always_aim", false, nullptr}; static Convar doghook_aimbot_silent = Convar{"doghook_aimbot_silent", true, nullptr}; static Convar doghook_aimbot_autoshoot = Convar{"doghook_aimbot_autoshoot", true, nullptr}; static Convar doghook_aimbot_aim_if_not_attack = Convar{"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()->set_view_angles(new_angles); diff --git a/src/modules/anti_aim.cc b/src/modules/anti_aim.cc new file mode 100644 index 0000000..b93a574 --- /dev/null +++ b/src/modules/anti_aim.cc @@ -0,0 +1,88 @@ +#include + +#include "anti_aim.hh" + +#include + +#include +#include + +using namespace sdk; + +namespace anti_aim { + +Convar doghook_antiaim_enabled{"doghook_antiaim_enabled", true, nullptr}; + +Convar doghook_antiaim_real_angle{"doghook_antiaim_real_angle", 90, -1000, 1000, nullptr}; +Convar doghook_antiaim_fake_angle{"doghook_antiaim_fake_angle", -90, -1000, 1000, nullptr}; +Convar doghook_antiaim_pitch{"doghook_antiaim_pitch_angle", 0, -1000, 1000, nullptr}; + +Convar doghook_antiaim_force_sendpacket_false{"doghook_antiaim_force_sendpacket_false", false, nullptr}; +Convar doghook_antiaim_add_to_angles{"doghook_antiaim_add_to_angles", true, nullptr}; +Convar 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 diff --git a/src/modules/anti_aim.hh b/src/modules/anti_aim.hh new file mode 100644 index 0000000..7bfc20c --- /dev/null +++ b/src/modules/anti_aim.hh @@ -0,0 +1,9 @@ +#pragma once + +namespace sdk { +class UserCmd; +} + +namespace anti_aim { +void create_move(sdk::UserCmd *cmd); +} diff --git a/src/modules/misc.cc b/src/modules/misc.cc index b6fd9f0..bc9be98 100644 --- a/src/modules/misc.cc +++ b/src/modules/misc.cc @@ -4,6 +4,8 @@ #include #include +#include +#include #include 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 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()->in_game()) return; +} + } // namespace misc diff --git a/src/modules/misc.hh b/src/modules/misc.hh index c7aaf07..f457b21 100644 --- a/src/modules/misc.hh +++ b/src/modules/misc.hh @@ -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 diff --git a/src/sdk/convar.cc b/src/sdk/convar.cc index 503d00e..6131a26 100644 --- a/src/sdk/convar.cc +++ b/src/sdk/convar.cc @@ -329,6 +329,10 @@ ConvarBase::~ConvarBase() { auto modifiable = const_cast(c); if (c->next == this) modifiable->next = this->next; } + + // Cleanup tf_convar + // This unregisters itself + delete this->tf_convar; } void ConvarBase::init_all() { diff --git a/src/sdk/gamesystem.cc b/src/sdk/gamesystem.cc index 961d53c..a046ea8 100644 --- a/src/sdk/gamesystem.cc +++ b/src/sdk/gamesystem.cc @@ -9,27 +9,66 @@ GameSystem::GameSystem() { head = this; } +// TODO: remove +template +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("client", "55 8B EC 53 56 57 8B F9 33 D2 8B 77 0C", 0); + + static auto s_GameSystems = *signature::find_pattern **>("client", "A1 ? ? ? ? 8B 0C B8 8B 01", 1); + static auto s_GameSystemsPerFrame = *signature::find_pattern **>("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( - 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( - 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( - 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( + 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( + signature::resolve_callgate( + signature::find_pattern("client", "E8 ? ? ? ? 8B 5B 04 85 DB 75 C1"))); + } else if constexpr (doghook_platform::osx()) { + return reinterpret_cast( + signature::resolve_callgate( + signature::find_pattern("client", "E8 ? ? ? ? 8B 7F 04 85 FF 75 A1"))); + } + }(); assert(add_fn); diff --git a/src/sdk/hooks.hh b/src/sdk/hooks.hh index 62f3c64..5d5a821 100644 --- a/src/sdk/hooks.hh +++ b/src/sdk/hooks.hh @@ -115,10 +115,10 @@ public: template class HookFunction { - static std::vector *> hooks; + static std::vector>> hooks; auto create_hook_instance(T *instance) { - auto h = new HookInstance(instance); + auto h = std::make_shared>(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 *val = nullptr; + std::shared_ptr> val; for (auto &v : hooks) { if (v->get_instance() == instance) { @@ -186,6 +186,6 @@ public: }; template -std::vector *> HookFunction::hooks; +std::vector>> HookFunction::hooks; } // namespace hooks diff --git a/src/sdk/netvar.cc b/src/sdk/netvar.cc index 43aa24f..c1f4000 100644 --- a/src/sdk/netvar.cc +++ b/src/sdk/netvar.cc @@ -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(); 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()->get_all_classes(); while (cc != nullptr) { - const auto new_node = new node(); + const auto new_node = std::make_shared(); new_node->p = nullptr; populate_recursive(cc->recv_table, &new_node->children); diff --git a/src/sdk/netvar.hh b/src/sdk/netvar.hh index b9f10c1..29c91ce 100644 --- a/src/sdk/netvar.hh +++ b/src/sdk/netvar.hh @@ -10,17 +10,17 @@ class Netvar { class Tree { - struct node; - using netvar_tree = std::vector>; + struct Node; + using TreeNode = std::vector>>; - 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(static_cast(instance) + offset); } + void offset_delta(u32 d) { offset += d; } + static void init_all(); }; } // namespace sdk diff --git a/src/sdk/signature.cc b/src/sdk/signature.cc index f519bf9..1be1666 100644 --- a/src/sdk/signature.cc +++ b/src/sdk/signature.cc @@ -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; }