├── .clang-format ├── .editorconfig ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── TODO.md ├── cheat ├── CMakeLists.txt ├── include │ └── imconfig_bw.h └── src │ ├── base │ ├── base.h │ ├── crash_handler.cpp │ ├── crash_handler.h │ ├── debug.h │ ├── logger.cpp │ ├── logger.h │ ├── math.cpp │ ├── math.h │ ├── types │ │ ├── angle.h │ │ ├── bounding_box.h │ │ ├── color.h │ │ ├── dimension.h │ │ ├── matrix.h │ │ ├── pattern.h │ │ ├── quaternion.h │ │ └── vector.h │ └── winapi.h │ ├── core │ ├── cheat.cpp │ ├── cheat.h │ ├── config.cpp │ ├── config.h │ ├── entity_cache.cpp │ ├── entity_cache.h │ ├── features │ │ ├── backtrack.cpp │ │ ├── esp.cpp │ │ ├── features.h │ │ └── misc.cpp │ ├── hooks.cpp │ ├── hooks.h │ ├── hooks │ │ ├── client_dll.cpp │ │ ├── client_mode.cpp │ │ ├── d3d11.cpp │ │ └── wnd_proc.cpp │ ├── input.cpp │ ├── input.h │ └── main.cpp │ ├── crypt │ ├── fnv1a.h │ └── xorstr.h │ ├── memory │ ├── address.h │ ├── dll.cpp │ ├── dll.h │ ├── hook_mgr.h │ ├── interfaces.cpp │ ├── interfaces.h │ ├── memory.h │ ├── netvars.cpp │ └── netvars.h │ ├── render │ ├── debug_overlay.cpp │ ├── debug_overlay.h │ ├── imgui_extra.h │ ├── menu.cpp │ ├── menu.h │ ├── render.cpp │ └── render.h │ └── valve │ ├── cs │ ├── cs.h │ ├── econ.h │ ├── entity.cpp │ ├── entity.h │ ├── player.h │ └── vdata.h │ └── se │ ├── animation_system.h │ ├── client.h │ ├── cvar.cpp │ ├── cvar.h │ ├── engine.h │ ├── inputsystem.h │ ├── localize.h │ ├── network_system.h │ ├── schema.h │ ├── se.h │ ├── util.cpp │ └── util.h ├── cspell.json ├── injector ├── CMakeLists.txt ├── LICENSE └── src │ ├── CapcomLoader.h │ ├── CapcomResource.h │ ├── DriverLoader.h │ ├── Error.h │ ├── KernelHelper.h │ ├── KernelRoutines.h │ ├── LICENSE │ ├── LockedMemory.h │ ├── MemoryController.h │ ├── NtDefines.h │ ├── PerfectInjector.cpp │ └── SimpleMapper.h └── vcpkg.json /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | IndentWidth: 4 3 | ColumnLimit: 120 4 | AllowShortFunctionsOnASingleLine: Empty -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = crlf 9 | indent_style = space 10 | indent_size = 4 11 | 12 | [*.yml] 13 | indent_size = 2 14 | end_of_line = lf 15 | 16 | [*.json] 17 | indent_size = 2 18 | end_of_line = lf 19 | insert_final_newline = false -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | build-type: ["Debug", "Release", "RelWithDebInfo"] 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | with: 19 | submodules: true 20 | 21 | - name: Install latest CMake. 22 | uses: lukka/get-cmake@latest 23 | 24 | - name: Setup vcpkg (it does not install any package yet) 25 | uses: lukka/run-vcpkg@v11 26 | 27 | - name: Run CMake consuming CMakePreset.json and run vcpkg to build dependencies 28 | uses: lukka/run-cmake@v10 29 | with: 30 | configurePreset: ${{ matrix.build-type == 'Debug' && 'x64-windows' || 'x64-windows-static' }} 31 | buildPreset: ${{matrix.build-type}} 32 | 33 | - uses: actions/upload-artifact@v3 34 | with: 35 | name: ${{matrix.build-type}} 36 | path: | 37 | ${{github.workspace}}/build/bin/${{matrix.build-type}} 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists.txt.user 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Testing 6 | Makefile 7 | cmake_install.cmake 8 | install_manifest.txt 9 | compile_commands.json 10 | CTestTestfile.cmake 11 | _deps 12 | build/ 13 | .vscode/ 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vcpkg"] 2 | path = vcpkg 3 | url = https://github.com/microsoft/vcpkg.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | set(VCPKG_TARGET_TRIPLET $ENV{VCPKG_TARGET_TRIPLET} CACHE STRING "target triplet" FORCE) 4 | message(STATUS "Target triplet is " ${VCPKG_TARGET_TRIPLET}) 5 | 6 | project(BakaWare4 VERSION 4.0.0) 7 | 8 | if(MSVC) 9 | # multi core parallel building 10 | include(ProcessorCount) 11 | ProcessorCount(PROCESSOR_COUNT) 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP${PROCESSOR_COUNT}") 13 | set(CMAKE_VS_MSBUILD_COMMAND "${CMAKE_VS_MSBUILD_COMMAND} /p:CL_MPCount=${PROCESSOR_COUNT} /m") 14 | endif() 15 | 16 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 17 | 18 | add_subdirectory(cheat) 19 | add_subdirectory(injector) -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 6, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 23, 6 | "patch": 0 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "x64-windows", 11 | "binaryDir": "${sourceDir}/build", 12 | "generator": "Visual Studio 17 2022", 13 | "architecture": { 14 | "value": "x64", 15 | "strategy": "set" 16 | }, 17 | "toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", 18 | "environment": { 19 | "VCPKG_ROOT": "./vcpkg", 20 | "VCPKG_TARGET_TRIPLET": "x64-windows" 21 | } 22 | }, 23 | { 24 | "name": "x64-windows-static", 25 | "inherits": "x64-windows", 26 | "environment": { 27 | "VCPKG_TARGET_TRIPLET": "x64-windows-static" 28 | } 29 | } 30 | ], 31 | "buildPresets": [ 32 | { 33 | "name": "Debug", 34 | "configurePreset": "x64-windows", 35 | "configuration": "Debug" 36 | }, 37 | { 38 | "name": "Release", 39 | "configurePreset": "x64-windows-static", 40 | "configuration": "Release" 41 | }, 42 | { 43 | "name": "RelWithDebInfo", 44 | "configurePreset": "x64-windows-static", 45 | "configuration": "RelWithDebInfo" 46 | } 47 | ] 48 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 nezu.cc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BakaWare4 2 | 3 | Counter-Strike 2 cheat 4 | 5 | ## Features 6 | 7 | check [TODO.md](TODO.md) for a list of current and potential new features 8 | 9 | **THIS CHEAT IS STILL WIP, MORE TO COME SOON:tm:** 10 | 11 | ## Technical "rules" 12 | 13 | for those that care 14 | 15 | - No modifying any read only memory sections 16 | - No hooks on globally exported interfaces 17 | - No SEH 18 | - No TLS 19 | - No persistent threads 20 | - Must load and function correctly when mapped above 0x7FFFFFFEFFFF ;) 21 | 22 | NOTE: the above only applies to release builds, anything is fair game 23 | in debug builds since they are only designed to be loaded in `-insecure` 24 | NOTE2: Debug builds must be able to be unloaded/unhooked for rapid iteration. 25 | 26 | ## Building 27 | 28 | This project uses [CMake](https://cmake.org/) to generate build files and [Visual Studio 17 2022](https://visualstudio.microsoft.com/) to compile it. 29 | 30 | When cloning the repository, make sure to clone it with the `--recursive` flag to also clone the vcpkg submodule. 31 | 32 | ### Example 33 | From the `Developer PowerShell for VS 2022` while in the project directory run: 34 | 35 | ```powershell 36 | # list configure presets 37 | cmake --list-presets 38 | # configure the project using the "x64-windows" preset 39 | # NOTE: this will also install the dependencies using vcpkg 40 | cmake --preset=x64-windows-static 41 | # list build presets 42 | cmake --build --list-presets 43 | # build the project using the "Release" preset 44 | cmake --build --preset=Release 45 | ``` 46 | 47 | Or just open it in your favorite IDE (that supports CMake and CMakePresets) and build it from there. 48 | 49 | ### Dependencies 50 | 51 | - [Dear ImGui](https://github.com/ocornut/imgui) (included using vcpkg) 52 | - [nlohmann JSON](https://github.com/nlohmann/json) (included using vcpkg) 53 | - [ThePerfectInjector](https://github.com/can1357/ThePerfectInjector) (included directly in the source tree) 54 | 55 | ## Contributing 56 | 57 | Fell free to improve it and make a pull request but there is no 58 | guarantee that I will like/agree with it and merge it. 59 | 60 | ## License 61 | 62 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 63 | 64 | ## Q&A 65 | 66 | - Q: Is this cheat undetected? 67 | A: Idk, you tell me. **I'm not responsible for any bans you get!** 68 | 69 | - Q: What version of the game does it work on? 70 | A: It's designed to work on the latest steam version, I do not support cracked/older versions. 71 | **THIS CHEAT REQUIRES THE STEAM OVERLAY TO BE ON FOR RENDERING** 72 | **THE VULKAN RENDERER IS NOT SUPPORTED YET** 73 | 74 | - Q: What is this? 75 | A: This is a forth instalment in my counter-strike cheat making adventure. 76 | 77 | - Q: Why that name? 78 | A: Idk, I'm bad at naming things and it was a long time ago when this name was chosen. 79 | 80 | - Q: What is the injector included? 81 | A: It's [ThePerfectInjector](https://github.com/can1357/ThePerfectInjector). It maps kernel space memory into 82 | usermode by manipulating page tables. Windows will actively refuse to interact with memory addresses above 83 | 0x7FFFFFFEFFFF through their APIs making it basically invisible to external usermode scanners. These pages 84 | are still perfectly valid though and the CPU will happily execute them. That's not to say it's fully undetectable. 85 | We register a VEH to nerf DEP that will sometimes get mad at us and think that the RWX page is in fact not executable. 86 | We just catch the exception and tell it to just continue execution. Another detection vector are of course the hooks, 87 | and while we try to stay stealthy with them, they still need to exist. Anything running directly inside cs can read 88 | our memory just fine, this injector only hides us from windows's virtual memory APIs. 89 | 90 | - Q: Why not just use X? 91 | A: Nothing out there is perfect, and neither is this. This is a cheat designed to be perfect for **ME**. 92 | If you find it useful that's great. Releasing it because why not, I'm not going to sell it anyway. 93 | 94 | - Q: What is the base? 95 | A: This cheat was heavily inspired by [lstrsrt/csgo_internal_base](https://github.com/lstrsrt/csgo_internal_base) but 96 | ported to CS2 and with some slight changes. Over time the layout will probably drift further and further away from it though. -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | 3 | a list of ideas that might be implemented (mostly based on the skeet features, feel free to add things skeet doesn't have) 4 | 5 | if you want to contribute then feel free to implement anything from this list and make a pull request 6 | 7 | entries with a `?` at the end are things that are random ideas and need to be discussed/thought about 8 | 9 | # RAGE 10 | 11 | - [ ] do we even want this to be a rage cheat? 12 | - [ ] maybe funny exploits? 13 | - [ ] anit-aim? 14 | 15 | # Legit 16 | 17 | - [ ] aimbot 18 | - [ ] speed 19 | - [ ] speed (in attack) 20 | - [ ] speed scale - FOV 21 | - [ ] maximum lock on time 22 | - [ ] reaction time 23 | - [ ] maximum FOV 24 | - [ ] recoil compensation 25 | - [ ] quick stop 26 | - [ ] checks 27 | - [ ] smoke check 28 | - [ ] flash check 29 | - [ ] hitbox groups 30 | - [ ] triggerbot 31 | - [ ] minimum hitchance 32 | - [ ] reaction time 33 | - [ ] burst fire 34 | - [ ] minimum damage 35 | - [ ] auto wall 36 | - [ ] checks 37 | - [ ] smoke check 38 | - [ ] flash check 39 | - [ ] hitboxes 40 | - [ ] hitbox groups 41 | - [ ] other 42 | - [ ] backtrack 43 | - [x] first shot 44 | - [ ] other shots 45 | - [x] stand-alone RCS 46 | 47 | # VISUALS 48 | 49 | - [ ] Player esp 50 | - [x] team check 51 | - [x] dormant (cs2 doesn't have this (for now at least)) 52 | - [x] bounding box 53 | - [x] health bar 54 | - [x] gradient 55 | - [ ] number 56 | - [x] name 57 | - [x] weapon 58 | - [ ] text 59 | - [ ] icon 60 | - [x] ammo 61 | - [x] bar 62 | - [ ] text 63 | - [ ] distance 64 | - [ ] glow 65 | - [ ] hit marker 66 | - [ ] hit marker sound 67 | - [ ] visualize aimbot 68 | - [ ] legit 69 | - [ ] rage? 70 | - [ ] visualize backtrack 71 | - [x] legit 72 | - [ ] rage 73 | - [ ] visualize sounds 74 | - [ ] line of sight 75 | - [ ] money 76 | - [x] skeleton 77 | - [ ] out of fov indicator 78 | - [ ] show nade prediction 79 | - [ ] chams 80 | - [ ] team check 81 | - [ ] behind wall 82 | - [ ] visible 83 | - [ ] modes 84 | - [ ] flat 85 | - [ ] textured 86 | - [ ] metallic 87 | - [ ] glow 88 | - [ ] wireframe 89 | - [ ] attachments 90 | - [ ] local player 91 | - [ ] hands 92 | - [ ] weapon 93 | - [ ] serwer hitboxes/aa? 94 | - [ ] on shot 95 | - [ ] ragdolls 96 | - [ ] disable occlusion/LOD (idk if we need this yet) 97 | - [ ] shadow fix (idk if we need this yet) 98 | - [ ] other 99 | - [ ] radar 100 | - [x] dropped weapons 101 | - [ ] icon 102 | - [x] bounding box 103 | - [x] text 104 | - [x] ammo 105 | - [ ] glow 106 | - [ ] distance 107 | - [ ] grenades 108 | - [ ] icon 109 | - [ ] text 110 | - [ ] glow 111 | - [ ] distance 112 | - [ ] trajectory 113 | - [ ] trails 114 | - [ ] proximity warning 115 | - [ ] molotov esp 116 | - [ ] smoke esp 117 | - [ ] penetration crosshair 118 | - [x] recoil crosshair 119 | - [ ] spectator list 120 | - [ ] hostages 121 | - [ ] ~~shared esp~~ (as long as cs2 doesn't have dormancy this is not needed) 122 | - [ ] maybe some other form of communication? 123 | - [ ] danger zone 124 | - [ ] upgrade tablet 125 | - [ ] esp for items and other things 126 | - [ ] scoreboard equipment (probably will be done in lua once implemented) 127 | - [ ] nade helper (also will probably be done in lua) 128 | - [ ] effects 129 | - [ ] removals 130 | - [ ] flash 131 | - [ ] smoke 132 | - [ ] fog 133 | - [ ] skybox 134 | - [ ] recoil 135 | - [ ] visual 136 | - [ ] shake 137 | - [ ] scope overlay 138 | - [ ] asus walls 139 | - [ ] fullbright 140 | - [ ] night mode 141 | - [ ] custom scope 142 | - [ ] third person 143 | - [ ] self 144 | - [ ] spectating 145 | - [ ] bullet tracers 146 | - [ ] team check 147 | - [ ] tracers 148 | - [ ] impacts 149 | 150 | # Misc 151 | 152 | - [ ] override fov 153 | - [ ] normal 154 | - [ ] scoped 155 | - [ ] knifebot 156 | - [ ] zeusbot 157 | - [ ] automatic weapons 158 | - [ ] custom delay 159 | - [ ] reveal ranks 160 | - [ ] reveal money 161 | - [ ] reveal overwatch suspect (assuming there will be overwatch in cs2) 162 | - [ ] auto accept 163 | - [ ] clan tag 164 | - [ ] log purchases 165 | - [ ] log damage 166 | - [ ] automatic grenade release 167 | - [ ] ping spike 168 | - [ ] persistent kill feed 169 | - [ ] sv_pure bypass 170 | - [ ] sv_cheats bypass???? 171 | - [ ] draw console output 172 | - [ ] discord rpc 173 | - [ ] lua support 174 | - [ ] panorama api 175 | - [ ] lobby ip grabber 176 | - [ ] protection for lobby ip grabber 177 | - [ ] force party members to accept (idk if that is still possible in cs2) 178 | - [ ] auto buy 179 | - [ ] cost based 180 | - [ ] movement 181 | - [ ] bunny hop 182 | - [ ] legit? 183 | - [ ] auto strafe 184 | - [ ] legit 185 | - [ ] rage 186 | - [ ] avoid collisions 187 | - [ ] edge jump 188 | - [ ] duck in air 189 | - [ ] block bot 190 | - [ ] custom walk speed (fast walk, slow walk) 191 | 192 | # player list 193 | 194 | idk what i want here, but if we ever want to add player specific exploits/toggles this will be useful 195 | 196 | - [ ] esp only for specific players? 197 | - [ ] aimbot only for specific players? 198 | - [ ] report bot? 199 | 200 | # config 201 | 202 | no idea yet, i like when it's always visible 203 | 204 | maybe a gear icon somewhere or even permanently displayed 205 | 206 | # lua 207 | 208 | - [ ] lua api 209 | - [ ] panorama api [probably as luv8](https://github.com/Shir0ha/luv8) 210 | - [ ] idk? 211 | 212 | # skins 213 | 214 | idk, don't care for now but feel free to implement 215 | 216 | - [ ] skin changer 217 | - [ ] sequence fix 218 | 219 | # other 220 | 221 | - [ ] custom menu system? 222 | - [ ] custom font? 223 | - [ ] keybindings for everything in the menu (something kinda like what NL has)? -------------------------------------------------------------------------------- /cheat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_definitions(-DBAKAWARE_VERSION="${PROJECT_VERSION}") 2 | add_definitions(-DIMGUI_USER_CONFIG=) 3 | 4 | find_package(imgui CONFIG REQUIRED) 5 | find_package(nlohmann_json CONFIG REQUIRED) 6 | 7 | file(GLOB_RECURSE SOURCES "src/*.cpp" ) 8 | add_library(BakaWare4 SHARED ${SOURCES}) 9 | 10 | target_include_directories(BakaWare4 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") 11 | target_link_libraries(BakaWare4 PRIVATE nlohmann_json::nlohmann_json imgui::imgui) 12 | 13 | target_compile_features(BakaWare4 PUBLIC c_std_17 cxx_std_20) 14 | target_compile_options(BakaWare4 PUBLIC /Zc:threadSafeInit- /sdl- /GS- /guard:cf-) 15 | 16 | if (VCPKG_TARGET_TRIPLET MATCHES "x64-windows-static") 17 | set_property(TARGET BakaWare4 PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") 18 | endif () -------------------------------------------------------------------------------- /cheat/include/imconfig_bw.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) 7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. 8 | //----------------------------------------------------------------------------- 9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp 10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 12 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. 13 | //----------------------------------------------------------------------------- 14 | 15 | 16 | //---- Define assertion handler. Defaults to calling assert(). 17 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 18 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 19 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 20 | 21 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 22 | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 23 | // DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() 24 | // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. 25 | //#define IMGUI_API __declspec( dllexport ) 26 | //#define IMGUI_API __declspec( dllimport ) 27 | 28 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 29 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 30 | //#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions. 31 | 32 | //---- Disable all of Dear ImGui or don't implement standard windows/tools. 33 | // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. 34 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 35 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. 36 | //#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88). 37 | 38 | //---- Don't implement some functions to reduce linkage requirements. 39 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) 40 | //#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) 41 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) 42 | #define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). 43 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 44 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 45 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 46 | #define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) 47 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 48 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 49 | //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available 50 | 51 | //---- Include imgui_user.h at the end of imgui.h as a convenience 52 | //#define IMGUI_INCLUDE_IMGUI_USER_H 53 | 54 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 55 | //#define IMGUI_USE_BGRA_PACKED_COLOR 56 | 57 | //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) 58 | //#define IMGUI_USE_WCHAR32 59 | 60 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 61 | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. 62 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 63 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 64 | //#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled 65 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 66 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 67 | 68 | //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 69 | // Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. 70 | //#define IMGUI_USE_STB_SPRINTF 71 | 72 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) 73 | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). 74 | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. 75 | //#define IMGUI_ENABLE_FREETYPE 76 | 77 | //---- Use stb_truetype to build and rasterize the font atlas (default) 78 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. 79 | //#define IMGUI_ENABLE_STB_TRUETYPE 80 | 81 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 82 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 83 | /* 84 | #define IM_VEC2_CLASS_EXTRA \ 85 | constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ 86 | operator MyVec2() const { return MyVec2(x,y); } 87 | 88 | #define IM_VEC4_CLASS_EXTRA \ 89 | constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ 90 | operator MyVec4() const { return MyVec4(x,y,z,w); } 91 | */ 92 | //---- ...Or use Dear ImGui's own very basic math operators. 93 | #define IMGUI_DEFINE_MATH_OPERATORS 94 | 95 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 96 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). 97 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 98 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 99 | //#define ImDrawIdx unsigned int 100 | 101 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) 102 | //struct ImDrawList; 103 | //struct ImDrawCmd; 104 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 105 | //#define ImDrawCallback MyImDrawCallback 106 | 107 | //---- Debug Tools: Macro to break in Debugger 108 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 109 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 110 | //#define IM_DEBUG_BREAK __debugbreak() 111 | 112 | //---- Debug Tools: Enable slower asserts 113 | //#define IMGUI_DEBUG_PARANOID 114 | 115 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 116 | /* 117 | namespace ImGui 118 | { 119 | void MyFunction(const char* name, const MyMatrix44& v); 120 | } 121 | */ 122 | 123 | #ifndef IMCONFIG_H 124 | #define IMCONFIG_H 125 | 126 | 127 | #endif /* IMCONFIG_H */ 128 | -------------------------------------------------------------------------------- /cheat/src/base/base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NOMINMAX 4 | 5 | #include 6 | using namespace std::chrono_literals; 7 | #include 8 | #include 9 | #include 10 | 11 | #include "logger.h" 12 | #include "types/angle.h" 13 | #include "types/quaternion.h" 14 | #include "types/color.h" 15 | #include "types/dimension.h" 16 | #include "types/matrix.h" 17 | #include "types/pattern.h" 18 | #include "types/vector.h" 19 | #include "types/bounding_box.h" 20 | #include "../crypt/xorstr.h" -------------------------------------------------------------------------------- /cheat/src/base/crash_handler.cpp: -------------------------------------------------------------------------------- 1 | #include "crash_handler.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "logger.h" 9 | 10 | static uintptr_t cheat_base{ }; 11 | 12 | void save_crash_log(std::string_view log) noexcept { 13 | auto file = std::ofstream(std::vformat(XOR("BakaWare_crash_{}.txt"), std::make_format_args(std::time(nullptr)))); 14 | file << log; 15 | } 16 | 17 | void copy_crash_log_to_clipboard(std::string_view log) noexcept { 18 | if (OpenClipboard(NULL)) { 19 | HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, log.size() + 1); 20 | if (!hg) { 21 | CloseClipboard(); 22 | return; 23 | } 24 | memcpy(GlobalLock(hg), log.data(), log.size() + 1); 25 | GlobalUnlock(hg); 26 | EmptyClipboard(); 27 | SetClipboardData(CF_TEXT, hg); 28 | CloseClipboard(); 29 | GlobalFree(hg); 30 | } 31 | } 32 | 33 | LONG CALLBACK veh_handler(EXCEPTION_POINTERS* ExceptionInfo) noexcept { 34 | auto exception_code = ExceptionInfo->ExceptionRecord->ExceptionCode; 35 | auto exception_address = ExceptionInfo->ExceptionRecord->ExceptionAddress; 36 | auto exception_info0 = ExceptionInfo->ExceptionRecord->ExceptionInformation[0]; 37 | auto exception_info1 = ExceptionInfo->ExceptionRecord->ExceptionInformation[1]; 38 | auto exception_info2 = ExceptionInfo->ExceptionRecord->ExceptionInformation[2]; 39 | 40 | // DEP bypass 41 | if (exception_code == EXCEPTION_ACCESS_VIOLATION) { 42 | // DEP Violation 43 | if (exception_info0 == 8) { 44 | // ignore DEP violation above 0x7FFFFFFEFFFF 45 | if (exception_info1 >= 0x7FFFFFFEFFFF) 46 | return EXCEPTION_CONTINUE_EXECUTION; 47 | } 48 | } 49 | 50 | if (exception_code != EXCEPTION_ACCESS_VIOLATION && exception_code != EXCEPTION_ARRAY_BOUNDS_EXCEEDED && 51 | exception_code != EXCEPTION_DATATYPE_MISALIGNMENT && exception_code != EXCEPTION_FLT_DENORMAL_OPERAND && 52 | exception_code != EXCEPTION_FLT_DIVIDE_BY_ZERO && exception_code != EXCEPTION_FLT_INEXACT_RESULT && 53 | exception_code != EXCEPTION_FLT_INVALID_OPERATION && exception_code != EXCEPTION_FLT_OVERFLOW && 54 | exception_code != EXCEPTION_FLT_STACK_CHECK && exception_code != EXCEPTION_FLT_UNDERFLOW && 55 | exception_code != EXCEPTION_ILLEGAL_INSTRUCTION && exception_code != EXCEPTION_IN_PAGE_ERROR && 56 | exception_code != EXCEPTION_INT_DIVIDE_BY_ZERO && exception_code != EXCEPTION_INT_OVERFLOW && 57 | exception_code != EXCEPTION_INVALID_DISPOSITION && exception_code != EXCEPTION_NONCONTINUABLE_EXCEPTION && 58 | exception_code != EXCEPTION_PRIV_INSTRUCTION && exception_code != EXCEPTION_STACK_OVERFLOW) 59 | return EXCEPTION_CONTINUE_SEARCH; 60 | 61 | std::stringstream ss; 62 | 63 | auto log = [&](std::string_view fmt, auto&&... args) { 64 | std::string str; 65 | if constexpr (sizeof...(args) > 0) 66 | str = std::vformat(fmt, std::make_format_args(std::forward(args)...)); 67 | else 68 | str = fmt; 69 | 70 | ss << str << '\n'; 71 | }; 72 | 73 | switch (exception_code) 74 | { 75 | case EXCEPTION_ACCESS_VIOLATION: 76 | log(XOR("Cause: EXCEPTION_ACCESS_VIOLATION")); 77 | if (exception_info0 == 0) log(XOR("Attempted to read from: 0x{:016x}"), exception_info1); 78 | else if (exception_info0 == 1) log(XOR("Attempted to write to: 0x{:016x}"), exception_info1); 79 | else if (exception_info0 == 8) log(XOR("Data Execution Prevention (DEP) at: 0x{:016x}"), exception_info1); 80 | else log(XOR("Unknown access violation at: 0x{:016x}"), exception_info1); 81 | break; 82 | case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: log(XOR("Cause: EXCEPTION_ARRAY_BOUNDS_EXCEEDED")); break; 83 | case EXCEPTION_DATATYPE_MISALIGNMENT: log(XOR("Cause: EXCEPTION_DATATYPE_MISALIGNMENT")); break; 84 | case EXCEPTION_FLT_DENORMAL_OPERAND: log(XOR("Cause: EXCEPTION_FLT_DENORMAL_OPERAND")); break; 85 | case EXCEPTION_FLT_DIVIDE_BY_ZERO: log(XOR("Cause: EXCEPTION_FLT_DIVIDE_BY_ZERO")); break; 86 | case EXCEPTION_FLT_INEXACT_RESULT: log(XOR("Cause: EXCEPTION_FLT_INEXACT_RESULT")); break; 87 | case EXCEPTION_FLT_INVALID_OPERATION: log(XOR("Cause: EXCEPTION_FLT_INVALID_OPERATION")); break; 88 | case EXCEPTION_FLT_OVERFLOW: log(XOR("Cause: EXCEPTION_FLT_OVERFLOW")); break; 89 | case EXCEPTION_FLT_STACK_CHECK: log(XOR("Cause: EXCEPTION_FLT_STACK_CHECK")); break; 90 | case EXCEPTION_FLT_UNDERFLOW: log(XOR("Cause: EXCEPTION_FLT_UNDERFLOW")); break; 91 | case EXCEPTION_ILLEGAL_INSTRUCTION: log(XOR("Cause: EXCEPTION_ILLEGAL_INSTRUCTION")); break; 92 | case EXCEPTION_IN_PAGE_ERROR: 93 | log( XOR("Cause: EXCEPTION_IN_PAGE_ERROR")); 94 | if (!exception_info0) log(XOR("Attempted to read from: 0x{:016x}"), exception_info1); 95 | else if (exception_info0 == 1) log(XOR("Attempted to write to: 0x{:016x}"), exception_info1); 96 | else if (exception_info0 == 8) log(XOR("Data Execution Prevention (DEP) at: 0x{:016x}"), exception_info1); 97 | else log(XOR("Unknown access violation at: 0x{:016x}"), exception_info1); 98 | log(XOR("NTSTATUS: 0x{:016x}"), exception_info2); 99 | break; 100 | case EXCEPTION_INT_DIVIDE_BY_ZERO: log(XOR("Cause: EXCEPTION_INT_DIVIDE_BY_ZERO")); break; 101 | case EXCEPTION_INT_OVERFLOW: log(XOR("Cause: EXCEPTION_INT_OVERFLOW")); break; 102 | case EXCEPTION_INVALID_DISPOSITION: log(XOR("Cause: EXCEPTION_INVALID_DISPOSITION")); break; 103 | case EXCEPTION_NONCONTINUABLE_EXCEPTION: log(XOR("Cause: EXCEPTION_NONCONTINUABLE_EXCEPTION")); break; 104 | case EXCEPTION_PRIV_INSTRUCTION: log(XOR("Cause: EXCEPTION_PRIV_INSTRUCTION")); break; 105 | case EXCEPTION_STACK_OVERFLOW: log(XOR("Cause: EXCEPTION_STACK_OVERFLOW")); break; 106 | } 107 | 108 | LPVOID allocation_Base = nullptr; 109 | MEMORY_BASIC_INFORMATION info = {}; 110 | if (VirtualQuery(exception_address, &info, sizeof info)) 111 | allocation_Base = info.AllocationBase; 112 | else if (cheat_base >= 0x7FFFFFFEFFFF) 113 | allocation_Base = (LPVOID)cheat_base; 114 | 115 | CHAR module_name[MAX_PATH] = ""; 116 | if (!GetModuleBaseNameA(GetCurrentProcess(), (HMODULE)allocation_Base, module_name, sizeof(module_name))) { 117 | if (!cheat_base) 118 | sprintf_s(module_name, XOR("Unknown(%p)"), allocation_Base); 119 | else if ((uintptr_t)allocation_Base == cheat_base) 120 | sprintf_s(module_name, XOR("BakaWare4")); 121 | else { 122 | //parse header of manual mapped module 123 | PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)cheat_base; 124 | if (dos_header->e_magic == 0x5A4D) { //MZ 125 | PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(cheat_base + dos_header->e_lfanew); 126 | auto image_size = ntHeader->OptionalHeader.SizeOfImage; 127 | if ((uintptr_t)exception_address >= cheat_base && (uintptr_t)exception_address <= cheat_base + image_size) { 128 | sprintf_s(module_name, XOR("BakaWare4")); 129 | } 130 | } 131 | } 132 | } 133 | 134 | log(XOR("Cheat base: 0x{}"), (void*)cheat_base); 135 | log(XOR("Crash at: 0x{:016x} ({}+0x{:x})"), (uintptr_t)ExceptionInfo->ContextRecord->Rip, module_name, (uintptr_t)ExceptionInfo->ContextRecord->Rip - (uintptr_t)allocation_Base); 136 | 137 | log(XOR("Registers:")); 138 | log(XOR("RAX: 0x{:016x}"), ExceptionInfo->ContextRecord->Rax); 139 | log(XOR("RCX: 0x{:016x}"), ExceptionInfo->ContextRecord->Rcx); 140 | log(XOR("RDX: 0x{:016x}"), ExceptionInfo->ContextRecord->Rdx); 141 | log(XOR("RBX: 0x{:016x}"), ExceptionInfo->ContextRecord->Rbx); 142 | log(XOR("RSP: 0x{:016x}"), ExceptionInfo->ContextRecord->Rsp); 143 | log(XOR("RBP: 0x{:016x}"), ExceptionInfo->ContextRecord->Rbp); 144 | log(XOR("RSI: 0x{:016x}"), ExceptionInfo->ContextRecord->Rsi); 145 | log(XOR("RDI: 0x{:016x}"), ExceptionInfo->ContextRecord->Rdi); 146 | log(XOR("R8 : 0x{:016x}"), ExceptionInfo->ContextRecord->R8); 147 | log(XOR("R9 : 0x{:016x}"), ExceptionInfo->ContextRecord->R9); 148 | log(XOR("R10: 0x{:016x}"), ExceptionInfo->ContextRecord->R10); 149 | log(XOR("R11: 0x{:016x}"), ExceptionInfo->ContextRecord->R11); 150 | log(XOR("R12: 0x{:016x}"), ExceptionInfo->ContextRecord->R12); 151 | log(XOR("R13: 0x{:016x}"), ExceptionInfo->ContextRecord->R13); 152 | log(XOR("R14: 0x{:016x}"), ExceptionInfo->ContextRecord->R14); 153 | log(XOR("R15: 0x{:016x}"), ExceptionInfo->ContextRecord->R15); 154 | 155 | crash_handler::handle_crash(ss.str()); 156 | 157 | return EXCEPTION_CONTINUE_SEARCH; 158 | } 159 | 160 | void crash_handler::initialize(const uintptr_t base) noexcept { 161 | cheat_base = base; 162 | PVOID handle = AddVectoredExceptionHandler(FALSE, veh_handler); 163 | LOG_INFO(XOR("VEH handler at: {}"), handle); 164 | } 165 | 166 | void crash_handler::end() noexcept { 167 | RemoveVectoredExceptionHandler(veh_handler); 168 | } 169 | 170 | void crash_handler::handle_crash(std::string_view crash_info) noexcept { 171 | // copy to clipboard first in case save_crash_log fails 172 | copy_crash_log_to_clipboard(crash_info); 173 | save_crash_log(crash_info); 174 | MessageBoxA(NULL, crash_info.data(), XOR("BakaWare4 has crashed!"), MB_OK | MB_ICONERROR); 175 | std::abort(); 176 | } 177 | -------------------------------------------------------------------------------- /cheat/src/base/crash_handler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace crash_handler { 5 | 6 | void initialize(const uintptr_t base) noexcept; 7 | void end() noexcept; 8 | void handle_crash(std::string_view msg) noexcept; 9 | 10 | } -------------------------------------------------------------------------------- /cheat/src/base/debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../crypt/xorstr.h" 7 | #include "../base/crash_handler.h" 8 | 9 | #ifdef NDEBUG 10 | [[noreturn]] 11 | #endif 12 | static void dbg_fail(std::string_view fn, std::string_view msg = "") noexcept { 13 | std::string message = msg.empty() ? 14 | std::vformat(XOR("An error occurred in {}!"), std::make_format_args(fn)) : 15 | std::vformat(XOR("{} ({})"), std::make_format_args(msg, fn)); 16 | 17 | crash_handler::handle_crash(message); 18 | } 19 | 20 | #ifdef _DEBUG 21 | #define ASSERT(expr) assert(expr); 22 | #define ASSERT_MSG(expr, msg) assert(((void)msg, expr)); 23 | #else 24 | #define ASSERT(expr) do { if (!(expr)) dbg_fail(XOR(__FUNCTION__)); } while (false) 25 | #define ASSERT_MSG(expr, msg) do { if (!(expr)) dbg_fail(XOR(__FUNCTION__), msg); } while (false) 26 | #endif 27 | -------------------------------------------------------------------------------- /cheat/src/base/logger.cpp: -------------------------------------------------------------------------------- 1 | #include "logger.h" 2 | #include "../memory/dll.h" 3 | 4 | void logger::valve_logger::initialize(const char* channel_name, logging_severity severity, clr4 color) noexcept { 5 | using function_t = logging_channel_id(__stdcall*)(const char*, void*, int, logging_severity, clr4); 6 | static function_t fn = dlls::tier0.get_export("LoggingSystem_RegisterLoggingChannel"_hash).cast(); 7 | ASSERT(fn); 8 | channel_id = fn(channel_name, nullptr, 0, severity, color); 9 | } 10 | 11 | bool logger::valve_logger::is_channel_enabled(logging_severity severity) noexcept { 12 | using function_t = bool(__stdcall*)(logging_channel_id, logging_severity); 13 | static function_t fn = dlls::tier0.get_export("LoggingSystem_IsChannelEnabled"_hash).cast(); 14 | ASSERT(fn); 15 | return fn(channel_id, severity); 16 | } 17 | 18 | void logger::valve_logger::log(logging_severity severity, const char *message) noexcept { 19 | using function_t = void(__stdcall*)(logging_channel_id, logging_severity, const char*, ...); 20 | static function_t fn = dlls::tier0.get_export("LoggingSystem_LogDirect"_hash).cast(); 21 | ASSERT(fn); 22 | fn(channel_id, severity, message); 23 | } -------------------------------------------------------------------------------- /cheat/src/base/logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace ch = std::chrono; 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "winapi.h" 11 | #include "types/color.h" 12 | #include "../crypt/xorstr.h" 13 | 14 | // #define EXTERNAL_CONSOLE 15 | 16 | // #ifdef EXTERNAL_CONSOLE 17 | #define LOG_INFO(fmt, ...) logger::add(fmt, __VA_ARGS__) 18 | #define LOG_ERROR(fmt, ...) logger::add(fmt, __VA_ARGS__) 19 | // #else 20 | // #define LOG_INFO 21 | // #define LOG_ERROR 22 | // #endif 23 | 24 | namespace logger { 25 | 26 | inline HANDLE console{ }; 27 | 28 | enum class level { 29 | info, 30 | error, 31 | }; 32 | 33 | namespace valve_logger { 34 | typedef int logging_channel_id; 35 | enum class logging_severity { 36 | LS_MESSAGE = 0, 37 | LS_WARNING = 1, 38 | LS_ASSERT = 2, 39 | LS_ERROR = 3, 40 | LS_HIGHEST_SEVERITY = 4, 41 | }; 42 | 43 | inline logging_channel_id channel_id; 44 | 45 | void initialize(const char* channel_name, logging_severity severity = logging_severity::LS_HIGHEST_SEVERITY, clr4 color = clr4(0x00, 0x77, 0xFF, 0xFF)) noexcept; 46 | 47 | void log(logging_severity severity, const char* message) noexcept; 48 | 49 | bool is_channel_enabled(logging_severity severity) noexcept; 50 | }; 51 | 52 | // Use the LOG macros instead of accessing these directly 53 | 54 | template 55 | void add(std::string_view fmt, va_args&&... args) noexcept 56 | { 57 | std::string str; 58 | if constexpr (sizeof...(args) > 0) 59 | str = std::vformat(fmt, std::make_format_args(std::forward(args)...)); 60 | else 61 | str = fmt; 62 | 63 | str += '\n'; 64 | #ifdef EXTERNAL_CONSOLE 65 | std::cout << "[ "; 66 | switch (lvl) { 67 | case level::info: 68 | SetConsoleTextAttribute(console, FOREGROUND_BLUE | FOREGROUND_INTENSITY); 69 | std::cout << '*'; 70 | break; 71 | case level::error: 72 | SetConsoleTextAttribute(console, FOREGROUND_RED); 73 | std::cout << '!'; 74 | break; 75 | } 76 | 77 | SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); 78 | const auto time = ch::system_clock::to_time_t(ch::system_clock::now()); 79 | std::tm tm{ }; 80 | localtime_s(&tm, &time); 81 | std::cout << " ] " << std::put_time(&tm, "[%T] "); 82 | 83 | std::cout << fmt; 84 | #else 85 | switch (lvl) { 86 | case level::info: 87 | valve_logger::log(valve_logger::logging_severity::LS_MESSAGE, str.data()); 88 | break; 89 | case level::error: 90 | valve_logger::log(valve_logger::logging_severity::LS_ERROR, str.data()); 91 | break; 92 | } 93 | #endif 94 | } 95 | 96 | inline void initialize(std::string_view console_title) noexcept 97 | { 98 | #ifdef EXTERNAL_CONSOLE 99 | AllocConsole(); 100 | AttachConsole(ATTACH_PARENT_PROCESS); 101 | SetConsoleTitleA(console_title.data()); 102 | 103 | freopen_s(reinterpret_cast(stdout), XOR("CONOUT$"), XOR("w"), stdout); 104 | console = GetStdHandle(STD_OUTPUT_HANDLE); 105 | #else 106 | valve_logger::initialize(console_title.data()); 107 | #endif 108 | LOG_INFO(XOR("Logger initialized.")); 109 | } 110 | 111 | inline void end() noexcept 112 | { 113 | #ifdef EXTERNAL_CONSOLE 114 | fclose(stdout); 115 | FreeConsole(); 116 | #endif 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /cheat/src/base/math.cpp: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #include "../memory/dll.h" 4 | #include "../core/cheat.h" 5 | #include 6 | 7 | static mat4x4 view_matrix; 8 | static bool view_matrix_initialized = false; 9 | 10 | void math::update_view_matrix() noexcept { 11 | SIG(world_to_projection_ptr, dlls::client, "48 8D 05 ? ? ? ? 48 8B D3 4C 8D 05") 12 | static auto world_to_projection = world_to_projection_ptr.absolute(3); 13 | view_matrix = *world_to_projection; 14 | view_matrix_initialized = true; 15 | } 16 | 17 | bool math::world_to_screen(const vec3 &world, vec2 &screen, bool floor) noexcept { 18 | if (!view_matrix_initialized) 19 | return false; 20 | 21 | const float z = view_matrix[3][0] * world.x + 22 | view_matrix[3][1] * world.y + 23 | view_matrix[3][2] * world.z + 24 | view_matrix[3][3]; 25 | 26 | if (z < 0.001f) 27 | return false; 28 | 29 | screen = cheat::screen_size / 2; 30 | screen.x *= 1.0f + ( 31 | view_matrix[0][0] * world.x + 32 | view_matrix[0][1] * world.y + 33 | view_matrix[0][2] * world.z + 34 | view_matrix[0][3] 35 | ) / z; 36 | screen.y *= 1.0f - ( 37 | view_matrix[1][0] * world.x + 38 | view_matrix[1][1] * world.y + 39 | view_matrix[1][2] * world.z + 40 | view_matrix[1][3] 41 | ) / z; 42 | 43 | if (floor) { 44 | screen.x = std::floor(screen.x); 45 | screen.y = std::floor(screen.y); 46 | } 47 | 48 | return true; 49 | } 50 | 51 | void math::angle_vector(const angle &angles, vec3 &forward) noexcept { 52 | const float x = angles.x * std::numbers::pi_v / 180.f; 53 | const float y = angles.y * std::numbers::pi_v / 180.f; 54 | const float sp = std::sin(x); 55 | const float cp = std::cos(x); 56 | const float sy = std::sin(y); 57 | const float cy = std::cos(y); 58 | forward.x = cp * cy; 59 | forward.y = cp * sy; 60 | forward.z = -sp; 61 | } 62 | 63 | vec3 math::angle_vector(const angle &angles) noexcept { 64 | vec3 forward; 65 | angle_vector(angles, forward); 66 | return forward; 67 | } 68 | 69 | // distance between to line segments 70 | float math::segment_dist(vec3 start1, vec3 end1, vec3 start2, vec3 end2) noexcept { 71 | vec3 u = end1 - start1; 72 | vec3 v = end2 - start2; 73 | vec3 w = start1 - start2; 74 | float a = u.dot_product(u); 75 | float b = u.dot_product(v); 76 | float c = v.dot_product(v); 77 | float d = u.dot_product(w); 78 | float e = v.dot_product(w); 79 | float D = a * c - b * b; 80 | float sc, sN, sD = D; 81 | float tc, tN, tD = D; 82 | 83 | if (D < 0.001f) { 84 | sN = 0.0f; 85 | sD = 1.0f; 86 | tN = e; 87 | tD = c; 88 | } else { 89 | sN = (b * e - c * d); 90 | tN = (a * e - b * d); 91 | if (sN < 0.0f) { 92 | sN = 0.0f; 93 | tN = e; 94 | tD = c; 95 | } else if (sN > sD) { 96 | sN = sD; 97 | tN = e + b; 98 | tD = c; 99 | } 100 | } 101 | 102 | if (tN < 0.0f) { 103 | tN = 0.0f; 104 | 105 | if (-d < 0.0f) { 106 | sN = 0.0f; 107 | } else if (-d > a) { 108 | sN = sD; 109 | } else { 110 | sN = -d; 111 | sD = a; 112 | } 113 | } else if (tN > tD) { 114 | tN = tD; 115 | 116 | if ((-d + b) < 0.0f) { 117 | sN = 0; 118 | } else if ((-d + b) > a) { 119 | sN = sD; 120 | } else { 121 | sN = (-d + b); 122 | sD = a; 123 | } 124 | } 125 | 126 | sc = (std::abs(sN) < 0.001f ? 0.0f : sN / sD); 127 | tc = (std::abs(tN) < 0.001f ? 0.0f : tN / tD); 128 | 129 | vec3 dP = w + (u * sc) - (v * tc); 130 | return dP.length(); 131 | } 132 | 133 | vec3 math::lerp(const vec3 &a, const vec3 &b, float t) noexcept { 134 | return vec3( 135 | std::lerp(a.x, b.x, t), 136 | std::lerp(a.y, b.y, t), 137 | std::lerp(a.z, b.z, t) 138 | ); 139 | } -------------------------------------------------------------------------------- /cheat/src/base/math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "base.h" 3 | 4 | namespace math { 5 | void update_view_matrix() noexcept; 6 | bool world_to_screen(const vec3& world, vec2& screen, bool floor = true) noexcept; 7 | void angle_vector(const angle& angles, vec3& forward) noexcept; 8 | vec3 angle_vector(const angle &angles) noexcept; 9 | float segment_dist(vec3 start1, vec3 end1, vec3 start2, vec3 end2) noexcept; 10 | vec3 lerp(const vec3 &a, const vec3 &b, float t) noexcept; 11 | } -------------------------------------------------------------------------------- /cheat/src/base/types/angle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct angle { 6 | float x{ }, y{ }, z{ }; 7 | 8 | constexpr angle() noexcept = default; 9 | constexpr angle(float x, float y, float z) noexcept 10 | : x(x), y(y), z(z) { } 11 | 12 | bool operator==(const angle& rhs) const noexcept 13 | { 14 | return (std::abs(x - rhs.x) <= std::numeric_limits::epsilon() && 15 | std::abs(y - rhs.y) <= std::numeric_limits::epsilon() && 16 | std::abs(z - rhs.z) <= std::numeric_limits::epsilon()); 17 | } 18 | 19 | bool operator!=(const angle& rhs) const noexcept 20 | { 21 | return (std::abs(x - rhs.x) > std::numeric_limits::epsilon() || 22 | std::abs(y - rhs.y) > std::numeric_limits::epsilon() || 23 | std::abs(z - rhs.z) > std::numeric_limits::epsilon()); 24 | } 25 | 26 | constexpr angle operator+(const angle& rhs) const noexcept 27 | { 28 | return angle(x + rhs.x, y + rhs.y, z + rhs.z); 29 | } 30 | 31 | constexpr angle operator-(const angle& rhs) const noexcept 32 | { 33 | return angle(x - rhs.x, y - rhs.y, z - rhs.z); 34 | } 35 | 36 | constexpr angle operator*(const angle& rhs) const noexcept 37 | { 38 | return angle(x * rhs.x, y * rhs.y, z * rhs.z); 39 | } 40 | 41 | constexpr angle operator/(const angle& rhs) const noexcept 42 | { 43 | return angle(x / rhs.x, y / rhs.y, z / rhs.z); 44 | } 45 | 46 | constexpr angle operator+(const float rhs) const noexcept 47 | { 48 | return angle(x + rhs, y + rhs, z + rhs); 49 | } 50 | 51 | constexpr angle operator-(const float rhs) const noexcept 52 | { 53 | return angle(x - rhs, y - rhs, z - rhs); 54 | } 55 | 56 | constexpr angle operator*(const float rhs) const noexcept 57 | { 58 | return angle(x * rhs, y * rhs, z * rhs); 59 | } 60 | 61 | constexpr angle operator/(const float rhs) const noexcept 62 | { 63 | return angle(x / rhs, y / rhs, z / rhs); 64 | } 65 | 66 | constexpr angle& operator=(const angle& rhs) noexcept 67 | { 68 | x = rhs.x; 69 | y = rhs.y; 70 | z = rhs.z; 71 | return *this; 72 | } 73 | 74 | constexpr angle& operator+=(const angle& rhs) noexcept 75 | { 76 | x += rhs.x; 77 | y += rhs.y; 78 | z += rhs.z; 79 | return *this; 80 | } 81 | 82 | constexpr angle& operator-=(const angle& rhs) noexcept 83 | { 84 | x -= rhs.x; 85 | y -= rhs.y; 86 | z -= rhs.z; 87 | return *this; 88 | } 89 | 90 | constexpr angle& operator*=(const angle& rhs) noexcept 91 | { 92 | x *= rhs.x; 93 | y *= rhs.y; 94 | z *= rhs.z; 95 | return *this; 96 | } 97 | 98 | constexpr angle& operator/=(const angle& rhs) noexcept 99 | { 100 | x /= rhs.x; 101 | y /= rhs.y; 102 | z /= rhs.z; 103 | return *this; 104 | } 105 | 106 | constexpr angle& operator+=(const float rhs) noexcept 107 | { 108 | x += rhs; 109 | y += rhs; 110 | z += rhs; 111 | return *this; 112 | } 113 | 114 | constexpr angle& operator-=(const float rhs) noexcept 115 | { 116 | x -= rhs; 117 | y -= rhs; 118 | z -= rhs; 119 | return *this; 120 | } 121 | 122 | constexpr angle& operator*=(const float rhs) noexcept 123 | { 124 | x *= rhs; 125 | y *= rhs; 126 | z *= rhs; 127 | return *this; 128 | } 129 | 130 | constexpr angle& operator/=(const float rhs) noexcept 131 | { 132 | x /= rhs; 133 | y /= rhs; 134 | z /= rhs; 135 | return *this; 136 | } 137 | 138 | constexpr void clamp() noexcept 139 | { 140 | x = std::clamp(x, -89.0f, 89.0f); 141 | y = std::clamp(y, -180.0f, 180.0f); 142 | z = 0.0f; 143 | } 144 | 145 | constexpr auto length_sqr() const noexcept 146 | { 147 | return (x * x + y * y + z * z); 148 | } 149 | 150 | constexpr auto length2d_sqr() const noexcept 151 | { 152 | return (x * x + y * y); 153 | } 154 | 155 | auto length() const noexcept 156 | { 157 | return sqrtf(length_sqr()); 158 | } 159 | 160 | auto length2d() const noexcept 161 | { 162 | return sqrtf(length2d_sqr()); 163 | } 164 | 165 | void normalize() noexcept 166 | { 167 | x = std::isfinite(x) ? std::remainder(x, 360.0f) : 0.0f; 168 | y = std::isfinite(y) ? std::remainder(y, 360.0f) : 0.0f; 169 | z = 0.0f; 170 | } 171 | }; 172 | 173 | #include 174 | 175 | template<> 176 | struct std::formatter : std::formatter { 177 | auto format(angle a, format_context& ctx) 178 | { 179 | return formatter::format(std::format("[{:.02f}, {:.02f}, {:.02f}]", a.x, a.y, a.z), ctx); 180 | } 181 | }; 182 | -------------------------------------------------------------------------------- /cheat/src/base/types/bounding_box.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct bbox { 4 | float x{ }, y{ }, w{ }, h{ }; 5 | 6 | float center_x() const noexcept { return x + ((w - x) * 0.5f); } 7 | float center_y() const noexcept { return y + ((h - y) * 0.5f); } 8 | 9 | void floor() noexcept { 10 | x = std::floor(x); 11 | y = std::floor(y); 12 | w = std::floor(w); 13 | h = std::floor(h); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /cheat/src/base/types/color.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct clr3; 4 | 5 | struct clr4 { 6 | union { 7 | struct { 8 | uint8_t r, g, b, a; 9 | }; 10 | uint32_t rgba{ }; 11 | }; 12 | 13 | constexpr clr4() noexcept = default; 14 | 15 | template 16 | constexpr clr4(ix r, ix g, ix b, ax a) noexcept 17 | : r(r), g(g), b(b), a(a) { } 18 | 19 | template 20 | constexpr clr4(fp r, fp g, fp b, fp a) noexcept 21 | : r(static_cast(r * 255)), g(static_cast(g * 255)), 22 | b(static_cast(b * 255)), a(static_cast(a * 255)) { } 23 | 24 | operator uint32_t() const noexcept { return rgba; } 25 | 26 | float r_base() const noexcept { return r / 255.f; } 27 | float g_base() const noexcept { return g / 255.f; } 28 | float b_base() const noexcept { return b / 255.f; } 29 | float a_base() const noexcept { return a / 255.f; } 30 | 31 | static clr4 white(uint8_t a = 255) noexcept { return clr4(255, 255, 255, a); } 32 | static clr4 black(uint8_t a = 255) noexcept { return clr4(0, 0, 0, a); } 33 | static clr4 red(uint8_t a = 255) noexcept { return clr4(255, 0, 0, a); } 34 | static clr4 green(uint8_t a = 255) noexcept { return clr4(0, 255, 0, a); } 35 | static clr4 blue(uint8_t a = 255) noexcept { return clr4(0, 0, 255, a); } 36 | static clr4 cyan (uint8_t a = 255) noexcept { return clr4(0, 255, 255, a); } 37 | static clr4 magenta (uint8_t a = 255) noexcept { return clr4(255, 0, 255, a); } 38 | static clr4 yellow (uint8_t a = 255) noexcept { return clr4(255, 255, 0, a); } 39 | 40 | static clr4 lerp(const clr4& a, const clr4& b, float t) noexcept { 41 | return clr4( 42 | std::lerp(a.r_base(), b.r_base(), t), 43 | std::lerp(a.g_base(), b.g_base(), t), 44 | std::lerp(a.b_base(), b.b_base(), t), 45 | std::lerp(a.a_base(), b.a_base(), t) 46 | ); 47 | } 48 | }; 49 | 50 | static_assert(sizeof(clr4) == 4); 51 | 52 | struct clr3 { 53 | uint8_t r{ }, g{ }, b{ }; 54 | 55 | constexpr clr3() noexcept = default; 56 | constexpr clr3(uint8_t r, uint8_t g, uint8_t b) noexcept 57 | : r(r), g(g), b(b) { } 58 | 59 | auto to_clr4(uint8_t alpha = 255) const noexcept 60 | { 61 | return clr4(r, g, b, alpha); 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /cheat/src/base/types/dimension.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct d2 { 4 | int x{ }, y{ }; 5 | 6 | constexpr d2() noexcept = default; 7 | constexpr d2(int x, int y) noexcept 8 | : x(x), y(y) { } 9 | 10 | constexpr bool operator==(d2 rhs) const noexcept 11 | { 12 | return x == rhs.x && y == rhs.y; 13 | } 14 | 15 | constexpr bool operator!=(d2 rhs) const noexcept 16 | { 17 | return x != rhs.x || y != rhs.y; 18 | } 19 | 20 | constexpr d2 operator+(d2 rhs) const noexcept 21 | { 22 | return d2(x + rhs.x, y + rhs.y); 23 | } 24 | 25 | constexpr d2 operator-(d2 rhs) const noexcept 26 | { 27 | return d2(x - rhs.x, y - rhs.y); 28 | } 29 | 30 | constexpr d2 operator*(d2 rhs) const noexcept 31 | { 32 | return d2(x * rhs.x, y * rhs.y); 33 | } 34 | 35 | constexpr d2 operator/(d2 rhs) const noexcept 36 | { 37 | return d2(x / rhs.x, y / rhs.y); 38 | } 39 | 40 | constexpr d2 operator+(const int rhs) const noexcept 41 | { 42 | return d2(x + rhs, y + rhs); 43 | } 44 | 45 | constexpr d2 operator-(const int rhs) const noexcept 46 | { 47 | return d2(x - rhs, y - rhs); 48 | } 49 | 50 | constexpr d2 operator*(const int rhs) const noexcept 51 | { 52 | return d2(x * rhs, y * rhs); 53 | } 54 | 55 | constexpr d2 operator/(const int rhs) const noexcept 56 | { 57 | return d2(x / rhs, y / rhs); 58 | } 59 | 60 | constexpr d2& operator+=(d2 rhs) noexcept 61 | { 62 | x += rhs.x; 63 | y += rhs.y; 64 | return *this; 65 | } 66 | 67 | constexpr d2& operator-=(d2 rhs) noexcept 68 | { 69 | x -= rhs.x; 70 | y -= rhs.y; 71 | return *this; 72 | } 73 | 74 | constexpr d2& operator*=(d2 rhs) noexcept 75 | { 76 | x *= rhs.x; 77 | y *= rhs.y; 78 | return *this; 79 | } 80 | 81 | constexpr d2& operator/=(d2 rhs) noexcept 82 | { 83 | x /= rhs.x; 84 | y /= rhs.y; 85 | return *this; 86 | } 87 | 88 | constexpr d2& operator+=(int rhs) noexcept 89 | { 90 | x += rhs; 91 | y += rhs; 92 | return *this; 93 | } 94 | 95 | constexpr d2& operator-=(int rhs) noexcept 96 | { 97 | x -= rhs; 98 | y -= rhs; 99 | return *this; 100 | } 101 | 102 | constexpr d2& operator*=(int rhs) noexcept 103 | { 104 | x *= rhs; 105 | y *= rhs; 106 | return *this; 107 | } 108 | 109 | constexpr d2& operator/=(int rhs) noexcept 110 | { 111 | x /= rhs; 112 | y /= rhs; 113 | return *this; 114 | } 115 | }; 116 | -------------------------------------------------------------------------------- /cheat/src/base/types/matrix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | using mat3x3 = float[3][3]; 4 | 5 | struct mat3x4 { 6 | float data[3][4]{ }; 7 | 8 | float* operator[](int i) noexcept 9 | { 10 | return data[i]; 11 | } 12 | 13 | const float* operator[](int i) const noexcept 14 | { 15 | return data[i]; 16 | } 17 | }; 18 | 19 | struct mat4x4 { 20 | float data[4][4]{ }; 21 | 22 | float* operator[](int i) noexcept 23 | { 24 | return data[i]; 25 | } 26 | 27 | const float* operator[](int i) const noexcept 28 | { 29 | return data[i]; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /cheat/src/base/types/pattern.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | struct string_literal { 7 | size_t length = len - 1; 8 | std::array value{ }; 9 | 10 | consteval string_literal(const char(&str)[len]) 11 | { 12 | for (size_t i{ }; i < len - 1; i++) 13 | value[i] = str[i]; 14 | } 15 | }; 16 | 17 | static consteval bool is_hex_char(char c) 18 | { 19 | return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'); 20 | } 21 | 22 | static consteval int hex_char_to_int(char c) 23 | { 24 | return (c > '9') ? (c & ~0x20) - 'A' + 10 : (c - '0'); 25 | } 26 | 27 | static consteval int make_hex_digits(char a, char b) 28 | { 29 | return 16 * hex_char_to_int(a) + hex_char_to_int(b); 30 | } 31 | 32 | template 33 | struct pattern { 34 | struct length_t { 35 | static consteval auto get() 36 | { 37 | size_t ret{ }; 38 | bool was_digit{ }; 39 | 40 | for (size_t i{ }; i < str.length; i++) { 41 | if (is_hex_char(str.value[i])) { 42 | if (!was_digit) 43 | ret++; 44 | was_digit = true; 45 | } else if (str.value[i] == '?') { 46 | ret++; 47 | was_digit = false; 48 | } else if (str.value[i] == ' ') 49 | was_digit = false; 50 | 51 | } 52 | return ret; 53 | } 54 | }; 55 | 56 | static consteval auto value() 57 | { 58 | constexpr auto len = length_t::get(); 59 | static_assert(len > 0); 60 | std::array ret{ }; 61 | 62 | for (size_t i{ }, j{ }; i < str.length; i++) { 63 | if (str.value[i] == ' ') 64 | continue; 65 | if (is_hex_char(str.value[i])) { 66 | i++; 67 | if (j < len) { 68 | if (is_hex_char(str.value[i])) 69 | ret[j++] = make_hex_digits(str.value[i - 1], str.value[i]); 70 | } 71 | } else if (str.value[i] == '?') 72 | ret[j++] = -1; 73 | } 74 | return ret; 75 | } 76 | }; 77 | 78 | #define PATTERN(str) pattern::value() 79 | -------------------------------------------------------------------------------- /cheat/src/base/types/quaternion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct quaternion { 4 | float x{ }, y{ }, z{ }, w{ }; 5 | }; -------------------------------------------------------------------------------- /cheat/src/base/winapi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base.h" 4 | #include 5 | namespace fs = std::filesystem; 6 | #include 7 | #include 8 | #include 9 | 10 | struct dll; 11 | 12 | namespace win { 13 | 14 | // Only usable for handles closed via CloseHandle()! 15 | struct scoped_handle { 16 | HANDLE handle{ }; 17 | 18 | scoped_handle(HANDLE handle) noexcept 19 | : handle(handle) { } 20 | ~scoped_handle() 21 | { 22 | if (handle) 23 | CloseHandle(handle); 24 | } 25 | 26 | operator bool() noexcept 27 | { 28 | return handle != nullptr && handle != INVALID_HANDLE_VALUE; 29 | } 30 | 31 | operator HANDLE() noexcept 32 | { 33 | return handle; 34 | } 35 | }; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /cheat/src/core/cheat.cpp: -------------------------------------------------------------------------------- 1 | #include "cheat.h" 2 | #include "../render/menu.h" 3 | #include "../valve/cs/cs.h" 4 | #include "../base/crash_handler.h" 5 | #include "entity_cache.h" 6 | #include "features/features.h" 7 | 8 | void cheat::initialize(uintptr_t base) noexcept { 9 | cheat::base = base; 10 | 11 | dlls::initialize(); 12 | logger::initialize(XOR("BakaWare")); 13 | crash_handler::initialize(base); 14 | dlls::add_to_trusted_list(base); 15 | memory::erase_pe_headers(base); 16 | interfaces::initialize(); 17 | cheat::update_global_vars(); 18 | render::initialize(); 19 | input::initialize(menu::is_open); 20 | hooks::initialize(); 21 | entity_cache::initialize(); 22 | features::initialize(); 23 | // config::initialize(); 24 | 25 | LOG_ERROR(XOR("BakaWare initialized. Base: {} Last full build: {} {}"), (void*)base, __DATE__, __TIME__); 26 | } 27 | 28 | DWORD cheat::end(LPVOID instance) noexcept { 29 | input::unlock_cursor(false); 30 | hooks::end(); 31 | logger::end(); 32 | crash_handler::end(); 33 | 34 | return EXIT_SUCCESS; 35 | } 36 | 37 | void cheat::update_global_vars() noexcept { 38 | SIG(globals_ptr, dlls::client, "48 89 15 ? ? ? ? 48 8D 05 ? ? ? ? 48 85") 39 | auto global_vars = globals_ptr.absolute(0x3); 40 | if (cheat::global_vars != *global_vars) { 41 | cheat::global_vars = *global_vars; 42 | LOG_INFO(XOR("Global vars updated: {}"), (void*)cheat::global_vars); 43 | } 44 | } 45 | 46 | void cheat::local_player::update() noexcept { 47 | controller = cs::get_local_player_controller(); 48 | if (!controller) { 49 | pawn = nullptr; 50 | return; 51 | } 52 | pawn = controller->m_hPawn().get(); 53 | } 54 | 55 | void cheat::local_player::reset() noexcept { 56 | controller = nullptr; 57 | pawn = nullptr; 58 | } 59 | -------------------------------------------------------------------------------- /cheat/src/core/cheat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../memory/interfaces.h" 4 | #include "../memory/hook_mgr.h" 5 | #include "../render/render.h" 6 | #include "../render/debug_overlay.h" 7 | #include "input.h" 8 | #include "config.h" 9 | 10 | namespace cheat { 11 | 12 | struct local_player { 13 | cs::player_controller* controller; 14 | cs::player_pawn* pawn; 15 | 16 | auto operator->() noexcept { return pawn; } 17 | operator bool() noexcept { return pawn; } 18 | operator cs::player_pawn*() noexcept { return pawn; } 19 | 20 | 21 | void update() noexcept; 22 | void reset() noexcept; 23 | 24 | inline bool valid() noexcept { 25 | return pawn && pawn->m_lifeState() == cs::life_state::LIFE_ALIVE; 26 | } 27 | 28 | inline bool void_move_type() noexcept { 29 | if (!pawn) 30 | return false; 31 | const auto move_type = pawn->m_MoveType(); 32 | return move_type != cs::move_type::MOVETYPE_NOCLIP 33 | && move_type != cs::move_type::MOVETYPE_LADDER; 34 | } 35 | }; 36 | 37 | inline uintptr_t base{ }; 38 | inline local_player local{ }; 39 | inline bool should_unhook{ }; 40 | inline d2 screen_size{ }; 41 | inline se::global_vars* global_vars{ }; 42 | 43 | void initialize(uintptr_t base) noexcept; 44 | DWORD end(LPVOID instance) noexcept; 45 | void update_global_vars() noexcept; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /cheat/src/core/config.cpp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include "../base/base.h" 3 | 4 | using json = nlohmann::json; 5 | 6 | void config::load(std::wstring_view file) noexcept {} 7 | 8 | void config::save(std::wstring_view file) noexcept { 9 | json j = cfg; 10 | LOG_INFO(XOR("config: {}"), j.dump(2)); 11 | } 12 | -------------------------------------------------------------------------------- /cheat/src/core/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../base/types/color.h" 5 | 6 | namespace config { 7 | 8 | class esp; 9 | 10 | class player_esp { 11 | public: 12 | bool enabled{ true }; 13 | bool teammates{ false }; 14 | bool box{ true }; 15 | bool health{ true }; 16 | bool skeleton{ true }; 17 | bool name{ true }; 18 | bool weapon_name{ true }; 19 | bool weapon_ammo{ true }; 20 | 21 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( 22 | player_esp, enabled, teammates, box, health, skeleton, name, weapon_name, weapon_ammo 23 | ) 24 | }; 25 | 26 | class weapon_esp { 27 | public: 28 | bool enabled{ true }; 29 | bool box{ true }; 30 | bool name{ true }; 31 | bool ammo{ true }; 32 | 33 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( 34 | weapon_esp, enabled, box, name, ammo 35 | ) 36 | }; 37 | 38 | class esp_config { 39 | public: 40 | player_esp players{ }; 41 | weapon_esp weapons{ }; 42 | 43 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( 44 | esp_config, players, weapons 45 | ) 46 | }; 47 | 48 | class rcs_config { 49 | public: 50 | bool enabled{ true }; 51 | // bool standalone{ false }; 52 | union { 53 | struct { 54 | float horizontal; 55 | float vertical; 56 | }; 57 | float axis[2] = { 100.0f, 100.0f }; 58 | }; 59 | 60 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( 61 | rcs_config, enabled, horizontal, vertical 62 | ) 63 | }; 64 | 65 | class backtrack_config { 66 | public: 67 | bool enabled{ true }; 68 | bool skeleton{ true }; 69 | float max_time_ms{ 1000 }; 70 | 71 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( 72 | backtrack_config, enabled, skeleton, max_time_ms 73 | ) 74 | }; 75 | 76 | class legit_config { 77 | public: 78 | backtrack_config backtrack{ }; 79 | rcs_config rcs { }; 80 | 81 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( 82 | legit_config, backtrack, rcs 83 | ) 84 | }; 85 | 86 | class misc_config { 87 | public: 88 | bool reoil_crosshair { true }; 89 | bool bunny_hop { false }; 90 | 91 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( 92 | misc_config, reoil_crosshair, bunny_hop 93 | ) 94 | }; 95 | 96 | class conf { 97 | public: 98 | esp_config esp{ }; 99 | legit_config legit{ }; 100 | misc_config misc{ }; 101 | 102 | NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( 103 | conf, esp, legit, misc 104 | ) 105 | }; 106 | 107 | class debug_config { 108 | public: 109 | uint32_t debug_flags{ 0 }; 110 | int32_t debug_int{ 0 }; 111 | float debug_float{ 0.0f }; 112 | clr4 debug_color = clr4::white(255); 113 | }; 114 | 115 | void load(std::wstring_view file) noexcept; 116 | void save(std::wstring_view file) noexcept; 117 | 118 | } 119 | 120 | inline config::conf cfg{ }; 121 | inline config::debug_config debug_cfg{ }; -------------------------------------------------------------------------------- /cheat/src/core/entity_cache.cpp: -------------------------------------------------------------------------------- 1 | #include "entity_cache.h" 2 | #include "../memory/interfaces.h" 3 | 4 | entity_cache::entity_type entity_cache::get_entity_type(cs::base_entity* entity) noexcept { 5 | if (entity->is_base_player_controller()) 6 | return entity_cache::entity_type::PLAYER; 7 | 8 | if (entity->is_base_player_weapon()) 9 | return entity_cache::entity_type::WEAPON; 10 | 11 | return entity_cache::entity_type::UNKNOWN; 12 | } 13 | 14 | void entity_cache::initialize() noexcept { 15 | if (!interfaces::engine->is_in_game()) 16 | return; 17 | 18 | int highest_index = interfaces::entity_list->get_highest_entity_index(); 19 | for (int i = 1; i <= highest_index; i++) { 20 | auto entity = interfaces::entity_list->get_base_entity(i); 21 | if (!entity) 22 | continue; 23 | 24 | // FIXME: not ideal since we lock the mutex inside the loop 25 | on_add_entity(entity, entity->get_ref_handle()); 26 | } 27 | } 28 | 29 | void entity_cache::on_add_entity(cs::base_entity *entity, cs::handle handle) noexcept { 30 | // https://developer.valvesoftware.com/wiki/Entity_limit#Source_2_limits 31 | const auto index = handle.get_index(); 32 | if (index >= 0x4000) 33 | return; 34 | 35 | // only cache useful entities 36 | entity_type type = get_entity_type(entity); 37 | if (type == entity_type::UNKNOWN) 38 | return; 39 | 40 | std::unique_lock lock(mutex); 41 | entities.insert_or_assign(index, cached_entity(handle, type)); 42 | 43 | // call callbacks 44 | for (auto& [callback_type, callbacks] : callbacks) { 45 | if (!callbacks.add || callback_type != type) 46 | continue; 47 | callbacks.add(index, handle); 48 | } 49 | } 50 | 51 | void entity_cache::on_remove_entity(cs::base_entity *entity, cs::handle handle) noexcept { 52 | std::unique_lock lock(mutex); 53 | const auto index = handle.get_index(); 54 | 55 | // call callbacks 56 | for (auto& [callback_type, callbacks] : callbacks) { 57 | if (!callbacks.remove) 58 | continue; 59 | 60 | if (callback_type != get_entity_type(entity)) 61 | continue; 62 | 63 | callbacks.remove(index, handle); 64 | } 65 | 66 | entities.erase(index); 67 | } 68 | 69 | void entity_cache::update_bounding_boxes() noexcept { 70 | std::unique_lock lock(mutex); 71 | 72 | for (auto& [index, cached_entity] : entities) { 73 | switch (cached_entity.type) 74 | { 75 | case entity_cache::entity_type::PLAYER: { 76 | auto controller = cached_entity.get(); 77 | if (!controller) 78 | continue; 79 | 80 | auto player = controller->m_hPawn().get(); 81 | if (!player) 82 | continue; 83 | 84 | cached_entity.draw = player->get_bounding_box(cached_entity.bb, cached_entity.scr_bones, cached_entity.visible_bone_count); 85 | break; 86 | } 87 | case entity_cache::entity_type::WEAPON: { 88 | auto weapon = cached_entity.get(); 89 | // FIXME: broken bomb bounding box 90 | cached_entity.draw = weapon->get_bounding_box(cached_entity.bb, true); 91 | break; 92 | } 93 | default: { 94 | cached_entity.draw = false; 95 | break; 96 | } 97 | } 98 | } 99 | } 100 | 101 | void entity_cache::register_callback(entity_type type, entity_callback add, entity_callback remove) noexcept { 102 | if (!add && !remove) 103 | return; 104 | 105 | std::unique_lock lock(mutex); 106 | callbacks.insert(std::make_pair(type, entity_callbacks{ add, remove })); 107 | 108 | if (!add) 109 | return; 110 | 111 | // add existing entities 112 | for (auto& [index, cached_entity] : entities) { 113 | if (cached_entity.type == type) 114 | add(index, cached_entity.handle); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /cheat/src/core/entity_cache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "../base/base.h" 6 | #include "../valve/cs/entity.h" 7 | #include 8 | 9 | namespace entity_cache { 10 | 11 | enum class entity_type : uint8_t { 12 | PLAYER = 0, 13 | WEAPON, 14 | // TODO: grenades 15 | // TODO: bomb 16 | // TODO: memes (chicken, fish, football, etc.) 17 | UNKNOWN, 18 | }; 19 | 20 | class cached_entity { 21 | public: 22 | cs::handle<> handle; 23 | entity_type type; 24 | bbox bb{ }; 25 | std::array, MAX_STUDIO_BONES> scr_bones{ }; 26 | int visible_bone_count{ }; 27 | bool draw{ }; 28 | 29 | cached_entity(cs::handle<> handle, entity_type type) noexcept 30 | : handle(handle), type(type) {} 31 | 32 | cached_entity(const cached_entity&) = delete; 33 | cached_entity(cached_entity&&) = default; 34 | cached_entity& operator=(const cached_entity&) = default; 35 | 36 | template requires std::derived_from 37 | std::add_pointer_t get() const noexcept { 38 | return handle.get(); 39 | } 40 | 41 | inline auto get_scr_bones() const noexcept { 42 | return std::span(scr_bones).first(visible_bone_count); 43 | } 44 | }; 45 | 46 | // typedef for entity callback 47 | using entity_callback = void(*)(int index, const cs::handle<> handle) noexcept; 48 | struct entity_callbacks { 49 | entity_callback add; 50 | entity_callback remove; 51 | }; 52 | 53 | inline std::shared_mutex mutex; 54 | inline std::unordered_map entities; 55 | inline std::unordered_multimap callbacks; 56 | 57 | entity_type get_entity_type(cs::base_entity *entity) noexcept; 58 | 59 | void initialize() noexcept; 60 | void on_add_entity(cs::base_entity* entity, cs::handle handle) noexcept; 61 | void on_remove_entity(cs::base_entity* entity, cs::handle handle) noexcept; 62 | void update_bounding_boxes() noexcept; 63 | void register_callback(entity_type type, entity_callback add, entity_callback remove) noexcept; 64 | 65 | } -------------------------------------------------------------------------------- /cheat/src/core/features/esp.cpp: -------------------------------------------------------------------------------- 1 | #include "features.h" 2 | #include "../entity_cache.h" 3 | 4 | void render_box(render::renderer* r, const bbox& bb, const clr4& clr) { 5 | r->rect( 6 | bb.x, bb.y, 7 | bb.w, bb.h, 8 | clr4::black(128), 9 | 3 10 | ); 11 | r->rect( 12 | bb.x, bb.y, 13 | bb.w, bb.h, 14 | clr 15 | ); 16 | } 17 | 18 | void render_health(render::renderer* r, const bbox& bb, const uint32_t heath) { 19 | // TODO: hp color config 20 | const clr4 top_clr = clr4::green(220); 21 | const clr4 bot_clr = clr4::red(220); 22 | 23 | const float hp = heath / 100.f; 24 | const clr4 hp_clr = clr4::lerp(bot_clr, top_clr, hp); 25 | const float hp_h = std::floor(std::lerp(bb.h, bb.y, hp)); 26 | 27 | r->rect_filled( 28 | bb.x - 6, bb.y - 1, 29 | bb.x - 2, bb.h + 1, 30 | clr4::black(128) 31 | ); 32 | r->rect_filled_multi_color( 33 | bb.x - 5, hp_h, 34 | bb.x - 3, bb.h, 35 | hp_clr, hp_clr, 36 | bot_clr, bot_clr 37 | ); 38 | } 39 | 40 | float render_ammo(render::renderer* r, const bbox& bb, int cur, int max) { 41 | if (max <= 0) 42 | return 0.f; 43 | 44 | // TODO: ammo color config 45 | const clr4 max_clr = clr4::cyan(); 46 | const clr4 min_clr = clr4::blue(); 47 | 48 | const float ratio = static_cast(cur) / max; 49 | const auto ammo_clr = clr4::lerp(min_clr, max_clr, ratio); 50 | const float ammo_w = std::floor(std::lerp(bb.x, bb.w, ratio)); 51 | 52 | r->rect_filled( 53 | bb.x - 1, bb.h + 2, 54 | bb.w + 1, bb.h + 6, 55 | clr4::black(128) 56 | ); 57 | r->rect_filled_multi_color( 58 | bb.x, bb.h + 3, 59 | ammo_w, bb.h + 5, 60 | min_clr, ammo_clr, 61 | ammo_clr, min_clr 62 | ); 63 | 64 | return 6; // size 65 | } 66 | 67 | void render_name(render::renderer* r, const bbox& bb, const char* name, const clr4& clr, bool bottom = false, float offset = 1.f) { 68 | if (!name || !strlen(name)) 69 | return; 70 | 71 | const auto name_size = r->calc_text_size(name); 72 | r->text( 73 | bb.center_x() - (name_size.x / 2), 74 | bottom ? bb.h + offset : bb.y - (offset + name_size.y + 2), 75 | clr, 76 | name 77 | ); 78 | } 79 | 80 | void render_skeleton(render::renderer* r, const entity_cache::cached_entity& cached_entity, const clr4& clr) { 81 | for (const auto& [start_scr, end_scr] : cached_entity.get_scr_bones()) { 82 | r->line( 83 | start_scr.x, start_scr.y, 84 | end_scr.x, end_scr.y, 85 | clr, 1 86 | ); 87 | } 88 | } 89 | 90 | void render_weapon_name(render::renderer* r, const bbox& bb, cs::base_player_weapon* weapon, const clr4& clr, bool bottom = false, float offset = 1.f) { 91 | auto static_data = weapon->m_AttributeManager().m_Item().get_static_data(); 92 | if (!static_data) 93 | return; 94 | 95 | auto weapon_name = interfaces::localize->find_safe(static_data->item_base_name); 96 | if (!weapon_name || !strlen(weapon_name)) 97 | return; 98 | 99 | render_name(r, bb, weapon_name, clr, bottom, offset); 100 | } 101 | 102 | float render_weapon_ammo(render::renderer* r, const bbox& bb, cs::base_player_weapon* weapon) { 103 | auto v_data = weapon->get_v_data(); 104 | if (!v_data) 105 | return 0.f; 106 | 107 | const auto ammo = weapon->m_iClip1(); 108 | const auto max_ammo = v_data->m_iMaxClip1(); 109 | 110 | return render_ammo(r, bb, ammo, max_ammo); 111 | } 112 | 113 | void render_player_weapon(render::renderer* r, const bbox& bb, cs::base_player_pawn* player, const clr4& clr) { 114 | auto weapon = player->get_active_weapon(); 115 | if (!weapon) 116 | return; 117 | 118 | float offset = 1.f; 119 | 120 | if (cfg.esp.players.weapon_ammo) 121 | offset += render_weapon_ammo(r, bb, weapon); 122 | 123 | if (cfg.esp.players.weapon_name) 124 | render_weapon_name(r, bb, weapon, clr, true, offset); 125 | } 126 | 127 | void render_player_esp(render::renderer* r, const entity_cache::cached_entity& cached_entity) { 128 | auto controller = cached_entity.get(); 129 | if (!controller || controller->m_bIsLocalPlayerController() || !controller->m_bPawnIsAlive()) 130 | return; 131 | 132 | auto player = controller->m_hPawn().get(); 133 | if (!player) 134 | return; 135 | 136 | if (cheat::local && !cheat::local->is_enemy(player) && !cfg.esp.players.teammates) 137 | return; 138 | 139 | if (cfg.esp.players.skeleton) 140 | render_skeleton(r, cached_entity, clr4::white(220)); // TODO: skeleton color config 141 | 142 | if (cfg.esp.players.box) 143 | render_box(r, cached_entity.bb, clr4::white(220)); // TODO: box color config 144 | 145 | if (cfg.esp.players.health) 146 | render_health(r, cached_entity.bb, std::min(controller->m_iPawnHealth(), 100u)); 147 | 148 | if (cfg.esp.players.name) { 149 | std::string name(controller->m_sSanitizedPlayerName()); 150 | if (controller->has_flag(cs::flags::fl_fakeclient)) 151 | name.insert(0, "BOT "); 152 | render_name(r, cached_entity.bb, name.c_str(), clr4::white(220)); // TODO: text color config 153 | } 154 | 155 | if (cfg.esp.players.weapon_name || cfg.esp.players.weapon_ammo) 156 | render_player_weapon(r, cached_entity.bb, player, clr4::white(220)); // TODO: text color config 157 | } 158 | 159 | void render_weapon_esp(render::renderer* r, const entity_cache::cached_entity& cached_entity) { 160 | auto weapon = cached_entity.get(); 161 | if (!weapon) 162 | return; 163 | 164 | if (weapon->m_iState() != cs::weapon_state::WEAPON_NOT_CARRIED) 165 | return; 166 | 167 | if (cfg.esp.weapons.box) 168 | render_box(r, cached_entity.bb, clr4::white(220)); // TODO: box color config 169 | 170 | if (cfg.esp.weapons.ammo) 171 | render_weapon_ammo(r, cached_entity.bb, weapon); 172 | 173 | if (cfg.esp.weapons.name) 174 | render_weapon_name(r, cached_entity.bb, weapon, clr4::white(220)); // TODO: text color config 175 | } 176 | 177 | void features::esp::render(render::renderer* r) noexcept { 178 | if (!interfaces::engine->is_valid()) 179 | return; 180 | 181 | std::shared_lock lock(entity_cache::mutex); 182 | for (const auto& [index, cached_entity] : entity_cache::entities) { 183 | if (!cached_entity.draw) 184 | continue; 185 | 186 | switch (cached_entity.type) 187 | { 188 | case entity_cache::entity_type::PLAYER: 189 | if (cfg.esp.players.enabled) 190 | render_player_esp(r, cached_entity); 191 | break; 192 | case entity_cache::entity_type::WEAPON: 193 | if (cfg.esp.weapons.enabled) 194 | render_weapon_esp(r, cached_entity); 195 | break; 196 | } 197 | } 198 | 199 | } -------------------------------------------------------------------------------- /cheat/src/core/features/features.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../base/base.h" 4 | #include "../../base/math.h" 5 | #include "../../memory/memory.h" 6 | #include "../../memory/interfaces.h" 7 | #include "../../render/render.h" 8 | #include "../../core/cheat.h" 9 | #include "../../valve/se/se.h" 10 | #include "../../valve/cs/cs.h" 11 | 12 | namespace features { 13 | 14 | namespace backtrack { 15 | void initialize() noexcept; 16 | void render(render::renderer* r) noexcept; 17 | void create_move(se::user_cmd* cmd) noexcept; 18 | } 19 | 20 | namespace esp { 21 | void render(render::renderer* r) noexcept; 22 | } 23 | 24 | namespace misc { 25 | void render(render::renderer* r) noexcept; 26 | void create_move(se::user_cmd* cmd) noexcept; 27 | void input(angle* va, se::move_input* input, float frame_time) noexcept; 28 | } 29 | 30 | inline void initialize() noexcept { 31 | backtrack::initialize(); 32 | } 33 | 34 | 35 | inline void render(render::renderer* r) noexcept { 36 | backtrack::render(r); 37 | esp::render(r); 38 | misc::render(r); 39 | } 40 | 41 | inline void create_move(se::user_cmd* cmd) noexcept { 42 | misc::create_move(cmd); 43 | backtrack::create_move(cmd); 44 | } 45 | 46 | inline void input(angle* va, se::move_input* input, float frame_time) noexcept { 47 | misc::input(va, input, frame_time); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /cheat/src/core/features/misc.cpp: -------------------------------------------------------------------------------- 1 | #include "features.h" 2 | 3 | void render_recoil_crosshair(render::renderer* r) noexcept { 4 | if (!cheat::local.valid()) 5 | return; 6 | 7 | auto weapon = cheat::local->get_active_weapon(); 8 | if (!weapon) 9 | return; 10 | 11 | if (weapon->m_flRecoilIndex() <= 1.1f) 12 | return; 13 | 14 | vec3 pos, forward_va; 15 | cheat::local->get_pos(&pos, &forward_va, nullptr, nullptr); 16 | 17 | vec2 va_screen; 18 | math::world_to_screen(pos + forward_va * 2000.f, va_screen); 19 | 20 | angle va, aim_punch; 21 | cheat::local->get_view_angles(&va); 22 | cheat::local->get_aim_punch(&aim_punch, true); 23 | 24 | vec3 forward = math::angle_vector(va + aim_punch); 25 | 26 | vec2 screen; 27 | math::world_to_screen(pos + forward * 2000.f, screen); 28 | 29 | if (screen.distance_to(va_screen) <= 25) 30 | return; 31 | 32 | const auto [x, y] = screen; 33 | const auto size = 3.f; // TODO: size config 34 | const auto color = clr4::cyan(); // TODO: crosshair color config 35 | const auto outline = clr4::black(220); 36 | 37 | // outline 38 | r->rect(x - size - 1, y - 1, x + size + 2, y + 2, outline); 39 | r->rect(x - 1, y - size - 1, x + 2, y + size + 2, outline); 40 | 41 | // crosshair 42 | r->rect_filled(x - size, y, x + size + 1, y + 1, color); 43 | r->rect_filled(x, y - size, x + 1, y + size + 1, color); 44 | 45 | } 46 | 47 | void run_bunny_hop(se::user_cmd* cmd) noexcept { 48 | if (!cheat::local.valid() || !cheat::local.void_move_type()) 49 | return; 50 | 51 | // if (!cheat::local->has_flag(cs::flags::fl_onground)) 52 | // cmd->buttons &= ~se::buttons::in_jump; 53 | } 54 | 55 | void run_rcs(angle* va) noexcept { 56 | if (!cheat::local.valid() || !cheat::local.void_move_type() || !cheat::global_vars) 57 | return; 58 | 59 | auto weapon = cheat::local->get_active_weapon(); 60 | if (!weapon) 61 | return; 62 | 63 | angle aim_punch; 64 | cheat::local->get_aim_punch(&aim_punch, true); 65 | 66 | static bool active = false; 67 | static angle old_aim_punch = aim_punch; 68 | 69 | if (active && aim_punch.length2d_sqr() < .01f) 70 | active = false; 71 | 72 | if (!active && cheat::local->m_iShotsFired() > 1) { 73 | old_aim_punch = angle{ 0.f, 0.f, 0.f }; 74 | active = true; 75 | } 76 | 77 | if (!active) { 78 | old_aim_punch = angle{ 0.f, 0.f, 0.f }; 79 | return; 80 | } 81 | 82 | angle delta = aim_punch - old_aim_punch; 83 | old_aim_punch = aim_punch; 84 | 85 | delta.x *= cfg.legit.rcs.vertical / 100.f; 86 | delta.y *= cfg.legit.rcs.horizontal / 100.f; 87 | 88 | *va -= delta; 89 | va->normalize(); 90 | } 91 | 92 | void features::misc::render(render::renderer* r) noexcept { 93 | if (!interfaces::engine->is_valid()) 94 | return; 95 | 96 | if (cfg.misc.reoil_crosshair) 97 | render_recoil_crosshair(r); 98 | } 99 | 100 | void features::misc::create_move(se::user_cmd *cmd) noexcept { 101 | if (cfg.misc.bunny_hop) 102 | run_bunny_hop(cmd); 103 | } 104 | 105 | void features::misc::input(angle *va, se::move_input *input, float frame_time) noexcept { 106 | if (cfg.legit.rcs.enabled) 107 | run_rcs(va); 108 | } 109 | -------------------------------------------------------------------------------- /cheat/src/core/hooks.cpp: -------------------------------------------------------------------------------- 1 | #include "hooks.h" 2 | #include "../memory/interfaces.h" 3 | #include "../memory/hook_mgr.h" 4 | #include "../core/hooks.h" 5 | #include "../render/render.h" 6 | 7 | void hooks::initialize() noexcept 8 | { 9 | if (render::game_window) 10 | original_wnd_proc = reinterpret_cast(SetWindowLongPtr(render::game_window, GWLP_WNDPROC, reinterpret_cast(wnd_proc))); 11 | else 12 | LOG_ERROR(XOR("Failed to hook window proc, game window HWND missing!")); 13 | 14 | // hook_func = dlls::cs2.find(PATTERN("48 8B C4 48 89 58 08 48 89 70 10 57")).cast(); 15 | // unhook_func = dlls::cs2.find(PATTERN("48 85 C9 0F 84 94")).cast(); 16 | 17 | auto present_ptr = dlls::game_overlay_renderer64.find(PATTERN("48 FF 25 ? ? ? ? 48 89 5C 24 30")).absolute(0x3); 18 | auto resize_buffers_ptr = dlls::game_overlay_renderer64.find(PATTERN("48 83 C4 30 41 5F 41 5E 5F 48 FF 25")).absolute(0xC); 19 | 20 | SET_PTR_HOOK(present_ptr, present); 21 | SET_PTR_HOOK(resize_buffers_ptr, resize_buffers); 22 | 23 | SET_VT_HOOK(interfaces::csgo_input, create_move, 5); 24 | SET_VT_HOOK(interfaces::csgo_input, on_input, 9); 25 | SET_VT_HOOK(interfaces::csgo_input, mouse_input_enabled, 10); 26 | 27 | SET_VT_HOOK(interfaces::client_mode, level_init, 23); 28 | SET_VT_HOOK(interfaces::client_mode, level_shutdown, 24); 29 | 30 | SET_VT_HOOK(interfaces::view_render, on_render_start, 4); 31 | 32 | SET_VT_HOOK(interfaces::entity_list, on_add_entity, 14); 33 | SET_VT_HOOK(interfaces::entity_list, on_remove_entity, 15); 34 | 35 | LOG_INFO(XOR("Hooks initialized.")); 36 | } 37 | 38 | void hooks::end() noexcept { 39 | for (auto a : interfaces::hooked_tables) 40 | static_cast*>(a)->restore(); 41 | 42 | // for (auto& a : hooked_fns) 43 | // unhook_func(a.second); 44 | 45 | for (auto& a : hooked_ptrs) 46 | *a.first = a.second; 47 | 48 | if (original_wnd_proc && render::game_window) 49 | SetWindowLongPtr(render::game_window, GWLP_WNDPROC, reinterpret_cast(original_wnd_proc)); 50 | } 51 | -------------------------------------------------------------------------------- /cheat/src/core/hooks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../base/base.h" 4 | #include 5 | #include 6 | 7 | #include "../valve/se/se.h" 8 | 9 | #define DECLARE_HOOK(name, ret, base, ... /* args */) namespace name { \ 10 | using ty = ret(__thiscall*)(base* ecx, __VA_ARGS__); \ 11 | inline ty original; \ 12 | ret WINAPI fn(base* ecx, __VA_ARGS__); \ 13 | } 14 | 15 | #define DECLARE_PROXY(name, prop_name) namespace name { \ 16 | inline cs::recv_proxy_fn original{ }; \ 17 | void proxy(cs::recv_proxy_data* data, void*, void*); \ 18 | } 19 | 20 | namespace hooks { 21 | 22 | inline WNDPROC original_wnd_proc{ }; 23 | 24 | extern LRESULT CALLBACK wnd_proc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam); 25 | DECLARE_HOOK(present, HRESULT, IDXGISwapChain, UINT, UINT); 26 | DECLARE_HOOK(resize_buffers, HRESULT, IDXGISwapChain, UINT, UINT, UINT, DXGI_FORMAT, UINT); 27 | DECLARE_HOOK(mouse_input_enabled, bool, se::csgo_input); 28 | DECLARE_HOOK(on_input, void, se::csgo_input, uint32_t, angle*, se::move_input*, void*, float) 29 | DECLARE_HOOK(create_move, bool, se::csgo_input, uint32_t, uint8_t); 30 | DECLARE_HOOK(level_init, void, se::client_mode, const char*); 31 | DECLARE_HOOK(level_shutdown, void, se::client_mode); 32 | DECLARE_HOOK(on_render_start, void, se::view_render); 33 | DECLARE_HOOK(on_add_entity, void, se::entity_list, cs::base_entity*, cs::handle); 34 | DECLARE_HOOK(on_remove_entity, void, se::entity_list, cs::base_entity*, cs::handle); 35 | 36 | } 37 | 38 | #undef DECLARE_HOOK 39 | #undef DECLARE_PROXY 40 | -------------------------------------------------------------------------------- /cheat/src/core/hooks/client_dll.cpp: -------------------------------------------------------------------------------- 1 | #include "../hooks.h" 2 | #include "../../core/input.h" 3 | #include "../../core/cheat.h" 4 | #include "../../core/features/features.h" 5 | #include "../../core/entity_cache.h" 6 | 7 | bool __fastcall hooks::mouse_input_enabled::fn(se::csgo_input* rcx) { 8 | if (input::cursor_unlocked) 9 | return false; 10 | 11 | return original(rcx); 12 | } 13 | 14 | void __fastcall hooks::on_input::fn(se::csgo_input* rcx, uint32_t split_screen_index, angle* viewangles, se::move_input* move, void* unk1, float frame_time) { 15 | original(rcx, split_screen_index, viewangles, move, unk1, frame_time); 16 | 17 | features::input(viewangles, move, frame_time); 18 | } 19 | 20 | bool __fastcall hooks::create_move::fn(se::csgo_input* cs_input, uint32_t split_screen_index, uint8_t a3) { 21 | bool ret = original(cs_input, split_screen_index, a3); 22 | 23 | cheat::local.update(); 24 | 25 | auto user_cmd = cs_input->get_user_cmd(split_screen_index); 26 | if (!user_cmd) 27 | return ret; 28 | 29 | features::create_move(user_cmd); 30 | 31 | return ret; 32 | } 33 | 34 | void __fastcall hooks::on_render_start::fn(se::view_render* rcx) { 35 | original(rcx); 36 | math::update_view_matrix(); 37 | entity_cache::update_bounding_boxes(); 38 | debug_overlay::w2s(); // has to be last 39 | } 40 | 41 | // NOTE: yes, this takes a entity_instance, but I'm lazy 42 | void __fastcall hooks::on_add_entity::fn(se::entity_list* rcx, cs::base_entity* entity, cs::handle handle) { 43 | if (entity) 44 | entity_cache::on_add_entity(entity, handle); 45 | 46 | original(rcx, entity, handle); 47 | } 48 | 49 | // NOTE: yes, this takes a entity_instance, but I'm lazy 50 | void __fastcall hooks::on_remove_entity::fn(se::entity_list* rcx, cs::base_entity* entity, cs::handle handle) { 51 | if (entity) 52 | entity_cache::on_remove_entity(entity, handle); 53 | 54 | original(rcx, entity, handle); 55 | } -------------------------------------------------------------------------------- /cheat/src/core/hooks/client_mode.cpp: -------------------------------------------------------------------------------- 1 | #include "../hooks.h" 2 | #include "../../core/cheat.h" 3 | 4 | void __stdcall hooks::level_init::fn(se::client_mode* rcx, const char* newmap) { 5 | cheat::update_global_vars(); 6 | original(rcx, newmap); 7 | } 8 | 9 | void __stdcall hooks::level_shutdown::fn(se::client_mode* rcx) { 10 | cheat::local.reset(); 11 | original(rcx); 12 | } -------------------------------------------------------------------------------- /cheat/src/core/hooks/d3d11.cpp: -------------------------------------------------------------------------------- 1 | #include "../hooks.h" 2 | #include "../../render/render.h" 3 | #include "../../core/cheat.h" 4 | 5 | HRESULT WINAPI hooks::present::fn(IDXGISwapChain *swap_chain, UINT SyncInterval, UINT Flags) { 6 | if (cheat::should_unhook) 7 | return original(swap_chain, SyncInterval, Flags); 8 | 9 | if (!render::render_target_view) 10 | render::set_swap_chain(swap_chain); 11 | 12 | render::render(); 13 | 14 | return original(swap_chain, SyncInterval, Flags); 15 | } 16 | 17 | HRESULT WINAPI hooks::resize_buffers::fn(IDXGISwapChain *swap_chain, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) { 18 | if (!cheat::should_unhook) 19 | render::cleanup_render_target(); 20 | 21 | return original(swap_chain, BufferCount, Width, Height, NewFormat, SwapChainFlags); 22 | } 23 | -------------------------------------------------------------------------------- /cheat/src/core/hooks/wnd_proc.cpp: -------------------------------------------------------------------------------- 1 | #include "../hooks.h" 2 | #include "../cheat.h" 3 | #include "../../core/input.h" 4 | #include "../../render/menu.h" 5 | 6 | LRESULT CALLBACK hooks::wnd_proc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) { 7 | input::process(msg, wparam, lparam); 8 | 9 | if (input::is_key_active({ VK_INSERT, input::key_type::toggle })) { 10 | menu::toggle(); 11 | } 12 | 13 | if (render::input(wnd, msg, wparam, lparam)) 14 | return 1; 15 | 16 | return CallWindowProcA(original_wnd_proc, wnd, msg, wparam, lparam); 17 | } 18 | -------------------------------------------------------------------------------- /cheat/src/core/input.cpp: -------------------------------------------------------------------------------- 1 | #include "input.h" 2 | #include "../memory/interfaces.h" 3 | #include "cheat.h" 4 | #include 5 | 6 | void input::initialize(bool unlock) noexcept 7 | { 8 | input_context = interfaces::input_stack_system->find_input_context(XOR("Mouse Control")); 9 | if (!input_context) { 10 | LOG_ERROR(XOR("Failed to find \"Mouse Control\" input context.")); 11 | return; 12 | } 13 | 14 | last_mouse_enabled = input_context->enabled; 15 | LOG_INFO(XOR("Input initialized. last_mouse_enabled = {}"), last_mouse_enabled); 16 | 17 | if (unlock) 18 | unlock_cursor(true); 19 | } 20 | 21 | void input::unlock_cursor(bool unlock) noexcept 22 | { 23 | if (!input_context) { 24 | LOG_ERROR(XOR("Failed to {} cursor, missing input context."), (unlock ? XOR("unlock") : XOR("lock"))); 25 | cursor_unlocked = unlock; 26 | return; 27 | } 28 | 29 | // we already are in the desired state 30 | if (unlock == cursor_unlocked) 31 | return; 32 | 33 | if (cursor_unlocked = unlock) { 34 | // save game state 35 | last_mouse_enabled = input_context->enabled; 36 | if (!last_mouse_enabled) { 37 | interfaces::input_stack_system->set_mouse_capture(input_context, true); 38 | interfaces::csgo_input->set_cursor_pos(cheat::screen_size.x / 2, cheat::screen_size.y / 2); 39 | } 40 | } else { 41 | // restore game state when unlocking 42 | interfaces::input_stack_system->set_mouse_capture(input_context, last_mouse_enabled); 43 | } 44 | } 45 | 46 | bool input::is_key_active(keybind key) noexcept 47 | { 48 | switch (key.type) { 49 | case key_type::always: 50 | return true; 51 | case key_type::hold: 52 | return key_states[key.code] == key_state::down || 53 | key_states[key.code] == key_state::toggled; 54 | case key_type::release: 55 | return key_states[key.code] == key_state::up; 56 | case key_type::toggle: 57 | if (key_states[key.code] == key_state::toggled) { 58 | key_states[key.code] = key_state::up; 59 | return true; 60 | } 61 | return false; 62 | case key_type::off: 63 | default: 64 | return false; 65 | } 66 | } 67 | 68 | bool input::is_hovering_item(d2 item_pos, d2 item_size) noexcept 69 | { 70 | return (mouse_pos.x >= item_pos.x && mouse_pos.y >= item_pos.y && 71 | mouse_pos.x <= item_pos.x + item_size.x && mouse_pos.y <= item_pos.y + item_size.y); 72 | } 73 | 74 | void input::process(UINT msg, WPARAM wparam, LPARAM lparam) noexcept 75 | { 76 | uint64_t key{ }; 77 | key_state state{ }; 78 | static key_state last_state{ }; 79 | 80 | switch (msg) { 81 | case WM_KEYDOWN: 82 | case WM_SYSKEYDOWN: 83 | key = wparam; 84 | state = key_state::down; 85 | break; 86 | case WM_KEYUP: 87 | case WM_SYSKEYUP: 88 | key = wparam; 89 | state = key_state::up; 90 | break; 91 | case WM_LBUTTONDOWN: 92 | case WM_LBUTTONUP: 93 | case WM_LBUTTONDBLCLK: 94 | key = VK_LBUTTON; 95 | state = msg == WM_LBUTTONUP ? key_state::up : key_state::down; 96 | break; 97 | case WM_RBUTTONDOWN: 98 | case WM_RBUTTONUP: 99 | case WM_RBUTTONDBLCLK: 100 | key = VK_RBUTTON; 101 | state = msg == WM_RBUTTONUP ? key_state::up : key_state::down; 102 | break; 103 | case WM_MOUSEMOVE: 104 | mouse_pos = { GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; 105 | break; 106 | default: 107 | return; 108 | } 109 | 110 | // ignore invalid keys 111 | if (key >= 0xFF) 112 | return; 113 | 114 | // TODO: this is retarded, rework needed to handle edge cases. 115 | if (key_states[key] == key_state::up && state == key_state::down) { 116 | if (last_state == key_state::down) 117 | key_states[key] = key_state::down; 118 | else 119 | key_states[key] = key_state::toggled; 120 | } 121 | else 122 | key_states[key] = state; 123 | 124 | last_state = state; 125 | } 126 | -------------------------------------------------------------------------------- /cheat/src/core/input.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../base/base.h" 4 | #include "../valve/se/inputsystem.h" 5 | #include 6 | #include 7 | #ifdef small 8 | #undef small 9 | #endif 10 | 11 | #include "../base/types/dimension.h" 12 | 13 | namespace input { 14 | 15 | enum class key_state { 16 | up, 17 | down, 18 | toggled 19 | }; 20 | 21 | enum class key_type { 22 | off, 23 | always, 24 | hold, 25 | toggle, 26 | release 27 | }; 28 | 29 | struct keybind { 30 | uint64_t code{ }; 31 | key_type type{ }; 32 | 33 | constexpr keybind() noexcept = default; 34 | constexpr keybind(uint64_t code, key_type type) noexcept 35 | : code(code), type(type) { } 36 | }; 37 | 38 | inline se::input_context* input_context{ }; 39 | inline std::array key_states{ }; 40 | inline d2 mouse_pos{ }; 41 | inline bool last_mouse_enabled{ }; 42 | inline bool cursor_unlocked{ }; 43 | 44 | void initialize(bool unlock = false) noexcept; 45 | void unlock_cursor(bool enable) noexcept; 46 | bool is_key_active(keybind key) noexcept; 47 | bool is_hovering_item(d2 item_pos, d2 item_size) noexcept; 48 | void process(UINT msg, WPARAM wparam, LPARAM lparam) noexcept; 49 | 50 | } 51 | 52 | using input::keybind; 53 | -------------------------------------------------------------------------------- /cheat/src/core/main.cpp: -------------------------------------------------------------------------------- 1 | #include "cheat.h" 2 | 3 | static DWORD WINAPI on_attach(LPVOID instance) noexcept 4 | { 5 | cheat::initialize(reinterpret_cast(instance)); 6 | 7 | #ifdef _DEBUG 8 | while (!cheat::should_unhook) 9 | std::this_thread::sleep_for(100ms); 10 | 11 | cheat::end(instance); 12 | #endif 13 | return TRUE; 14 | } 15 | 16 | 17 | BOOL APIENTRY DllMain(HMODULE instance, DWORD call_reason, LPVOID) 18 | { 19 | if (call_reason == DLL_PROCESS_ATTACH) { 20 | DisableThreadLibraryCalls(instance); 21 | #ifdef _DEBUG 22 | if (const auto thread = CreateThread(nullptr, 0, on_attach, instance, 0, nullptr)) 23 | CloseHandle(thread); 24 | #else 25 | on_attach(instance); 26 | #endif 27 | } 28 | 29 | return TRUE; 30 | } 31 | -------------------------------------------------------------------------------- /cheat/src/crypt/fnv1a.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | using hash_t = uint_fast32_t; 4 | 5 | template 6 | concept string_like = requires(ty t) { 7 | t.data(); 8 | t.substr(); 9 | }; 10 | 11 | inline namespace crypt { 12 | 13 | namespace fnv1a { 14 | 15 | constexpr hash_t basis = 0x811c9dc5; 16 | constexpr hash_t prime = 0x1000193; 17 | 18 | template 19 | constexpr hash_t hash(const ch* str) noexcept 20 | { 21 | const auto len = [str]() { 22 | size_t i{ }; 23 | while (str[i]) 24 | i++; 25 | return i; 26 | }(); 27 | 28 | auto hashed = basis; 29 | for (size_t i{ }; i < len; i++) { 30 | hashed ^= str[i]; 31 | hashed *= prime; 32 | } 33 | return hashed; 34 | } 35 | 36 | template 37 | inline hash_t hash(const st& str) noexcept 38 | { 39 | return hash(str.data()); 40 | } 41 | 42 | namespace literals { 43 | 44 | constexpr auto operator""_hash(const char* str, size_t len) noexcept 45 | { 46 | return hash(str); 47 | } 48 | 49 | constexpr auto operator""_hash(const wchar_t* str, size_t len) noexcept 50 | { 51 | return hash(str); 52 | } 53 | 54 | } 55 | 56 | } 57 | 58 | } 59 | 60 | using namespace fnv1a::literals; 61 | -------------------------------------------------------------------------------- /cheat/src/memory/address.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../base/debug.h" 7 | 8 | struct address { 9 | uintptr_t value{ }; 10 | 11 | address() = default; 12 | address(uintptr_t value) noexcept 13 | : value(value) { } 14 | address(uintptr_t* value) noexcept 15 | : value(reinterpret_cast(value)) { } 16 | address(uint8_t* value) noexcept 17 | : value(reinterpret_cast(value)) { } 18 | address(void* value) noexcept 19 | : value(reinterpret_cast(value)) { } 20 | address(std::nullptr_t value) noexcept 21 | : value(0) { } 22 | 23 | operator bool() const noexcept { return value != 0; } 24 | operator void*() noexcept { return reinterpret_cast(value); } 25 | 26 | template 27 | constexpr ty cast() noexcept 28 | { 29 | ASSERT(value != 0); 30 | return reinterpret_cast(value); 31 | } 32 | 33 | constexpr address& offset(ptrdiff_t offset) noexcept 34 | { 35 | value += offset; 36 | return *this; 37 | } 38 | 39 | template 40 | ty& dereference() noexcept 41 | { 42 | ASSERT(value != 0); 43 | return *reinterpret_cast(value); 44 | } 45 | 46 | template 47 | ty absolute(ptrdiff_t rel_offset = 0x1, ptrdiff_t abs_offset = 0x0) noexcept 48 | { 49 | ASSERT(value != 0); 50 | const auto jmp = value + rel_offset; 51 | const auto target = *reinterpret_cast(jmp); 52 | if (target) 53 | // Base address + offset + size of next instruction + target address. 54 | return reinterpret_cast(jmp + abs_offset + sizeof(int32_t) + target); 55 | return ty(); 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /cheat/src/memory/dll.cpp: -------------------------------------------------------------------------------- 1 | #include "dll.h" 2 | 3 | address dll::get_export(hash_t hash) const noexcept 4 | { 5 | const auto nt_hdrs = get_nt_headers(); 6 | if (!nt_hdrs) 7 | return address(); 8 | 9 | const auto optional_hdr = &nt_hdrs->OptionalHeader; 10 | const auto dir_addr = reinterpret_cast( 11 | base + optional_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 12 | const auto functions = reinterpret_cast(base + dir_addr->AddressOfFunctions); 13 | const auto names = reinterpret_cast(base + dir_addr->AddressOfNames); 14 | const auto ordinals = reinterpret_cast(base + dir_addr->AddressOfNameOrdinals); 15 | 16 | for (DWORD i{ }; i < dir_addr->NumberOfFunctions; i++) { 17 | const auto name = reinterpret_cast(base + names[i]); 18 | if (fnv1a::hash(name) == hash) 19 | return address(base + functions[ordinals[i]]); 20 | } 21 | 22 | return address(); 23 | } 24 | 25 | address dll::get_import(const dll& from, hash_t hash) const noexcept 26 | { 27 | const auto nt_hdrs = get_nt_headers(); 28 | if (!nt_hdrs) 29 | return address(); 30 | 31 | const auto optional_hdr = &nt_hdrs->OptionalHeader; 32 | auto import_desc = reinterpret_cast( 33 | base + optional_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); 34 | 35 | while (import_desc->Name) { 36 | auto cur_dll = reinterpret_cast(base) + import_desc->Name; 37 | if (!from.name.compare(cur_dll)) { 38 | auto thunk_data = reinterpret_cast(base + import_desc->OriginalFirstThunk); 39 | for (int i = 0; thunk_data->u1.Function; i++, thunk_data++) { 40 | char* cur_fn = reinterpret_cast(base + thunk_data->u1.AddressOfData)->Name; 41 | if (fnv1a::hash(cur_fn) == hash) { 42 | auto table = reinterpret_cast(base + import_desc->FirstThunk); 43 | return address(table[i]); 44 | } 45 | } 46 | return address(); 47 | } 48 | import_desc++; 49 | } 50 | 51 | return address(); 52 | } 53 | 54 | IMAGE_SECTION_HEADER* dll::get_section(hash_t hash) const noexcept 55 | { 56 | const auto nt_hdrs = get_nt_headers(); 57 | if (!nt_hdrs) 58 | return nullptr; 59 | 60 | auto section = IMAGE_FIRST_SECTION(nt_hdrs); 61 | if (!section) 62 | return nullptr; 63 | 64 | for (WORD i{ }; i <= nt_hdrs->FileHeader.NumberOfSections; i++, section++) { 65 | const auto name = reinterpret_cast(section->Name); 66 | if (fnv1a::hash(name) == hash) 67 | return section; 68 | } 69 | 70 | return nullptr; 71 | } 72 | 73 | bool dll::is_within_section(address addr, hash_t section_hash) const noexcept 74 | { 75 | auto section = get_section(section_hash); 76 | if (!section) 77 | return false; 78 | 79 | return is_within_section(addr, section); 80 | } 81 | 82 | bool dll::is_within_section(address addr, IMAGE_SECTION_HEADER* section) const noexcept 83 | { 84 | if (!section) 85 | return false; 86 | 87 | const auto start = base + section->VirtualAddress; 88 | const auto end = start + section->SizeOfRawData; 89 | 90 | return addr.value >= start && addr.value < end; 91 | } 92 | 93 | void dlls::add_to_trusted_list(uintptr_t base) noexcept 94 | { 95 | SIG(data_ptr, dlls::client, "48 8B 05 ? ? ? ? 49 8B F8 8B F2") 96 | auto data = *data_ptr.absolute(3); 97 | 98 | auto dos = reinterpret_cast(base); 99 | if (dos->e_magic != IMAGE_DOS_SIGNATURE) { 100 | LOG_ERROR(XOR("add_to_trusted_list: invalid DOS header")); 101 | return; 102 | } 103 | 104 | auto nt = reinterpret_cast(base + dos->e_lfanew); 105 | if (nt->Signature != IMAGE_NT_SIGNATURE) { 106 | LOG_ERROR(XOR("add_to_trusted_list: invalid NT header")); 107 | return; 108 | } 109 | 110 | const auto index = data->whitelist.size / 2; 111 | if (index >= std::size(data->whitelist.modules)) { 112 | LOG_ERROR(XOR("add_to_trusted_list: whitelist is full")); 113 | return; 114 | } 115 | 116 | auto& module_data = data->whitelist.modules[index]; 117 | module_data.start = base + nt->OptionalHeader.BaseOfCode; 118 | // yes, this will go past the end of the image, this is how valve does it as well /shrug 119 | module_data.end = module_data.start + nt->OptionalHeader.SizeOfImage; 120 | data->whitelist.size += 2; 121 | 122 | LOG_INFO(XOR("add_to_trusted_list: added {}-{} idx: {} to whitelist"), (void*)module_data.start, (void*)module_data.end, index); 123 | } -------------------------------------------------------------------------------- /cheat/src/memory/dll.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../base/base.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../crypt/fnv1a.h" 9 | #include "memory.h" 10 | 11 | struct dll; 12 | namespace dlls { inline std::vector list; } 13 | 14 | struct dll { 15 | std::string name{ }; 16 | uintptr_t base{ }; 17 | size_t size{ }; 18 | address create_interface{ }; // Only relevant to game DLLs 19 | 20 | explicit dll(std::string_view name) noexcept 21 | : name(name) 22 | { 23 | dlls::list.push_back(this); 24 | } 25 | 26 | template requires(len > 0) 27 | address find(std::array&& pattern) const noexcept 28 | { 29 | auto bytes = reinterpret_cast(base); 30 | for (size_t i{ }; i < size - len; i++) { 31 | for (size_t j{ }; j < len; j++) { 32 | if (bytes[i + j] != pattern[j] && pattern[j] != -1) 33 | break; 34 | if (j + 1 == len) 35 | return address(&bytes[i]); 36 | } 37 | } 38 | 39 | LOG_ERROR(XOR("{}: did not find pattern {}"), name, [&]() 40 | { 41 | /* Slow, but this only runs when something goes wrong. */ 42 | std::stringstream ss{ }; 43 | for (auto byte : pattern) { 44 | if (byte == -1) 45 | ss << '?'; 46 | else 47 | ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << byte; 48 | ss << ' '; 49 | } 50 | return ss.str(); 51 | }()); 52 | return address(); 53 | } 54 | 55 | inline IMAGE_NT_HEADERS* get_nt_headers() const noexcept 56 | { 57 | auto dos = reinterpret_cast(base); 58 | if (dos->e_magic != IMAGE_DOS_SIGNATURE) 59 | return nullptr; 60 | 61 | auto nt = reinterpret_cast(base + dos->e_lfanew); 62 | if (nt->Signature != IMAGE_NT_SIGNATURE) 63 | return nullptr; 64 | 65 | return nt; 66 | } 67 | 68 | address get_import(const dll& from, hash_t hash) const noexcept; 69 | address get_export(hash_t hash) const noexcept; 70 | IMAGE_SECTION_HEADER* get_section(hash_t hash) const noexcept; 71 | bool is_within_section(address addr, hash_t section_hash) const noexcept; 72 | bool is_within_section(address addr, IMAGE_SECTION_HEADER* section) const noexcept; 73 | 74 | }; 75 | 76 | struct return_address_data { 77 | struct whitelist { 78 | struct module { 79 | uintptr_t start; 80 | uintptr_t end; 81 | } modules[80]; 82 | int size; 83 | } whitelist; 84 | struct blacklist { 85 | uintptr_t addresses[32]; 86 | int size; 87 | } blacklist; 88 | }; 89 | 90 | static_assert(sizeof(return_address_data) == 0x610); 91 | 92 | namespace dlls { 93 | 94 | inline dll cs2{ XOR("cs2.exe") }; 95 | inline dll tier0{ XOR("tier0.dll") }; 96 | inline dll sdl2{ XOR("SDL2.dll") }; 97 | inline dll game_overlay_renderer64{ XOR("gameoverlayrenderer64.dll") }; 98 | inline dll render_system_dx11{ XOR("rendersystemdx11.dll") }; 99 | inline dll client{ XOR("client.dll") }; 100 | inline dll engine2{ XOR("engine2.dll") }; 101 | inline dll schemasystem{ XOR("schemasystem.dll") }; 102 | inline dll input_system{ XOR("inputsystem.dll") }; 103 | inline dll localize{ XOR("localize.dll") }; 104 | 105 | inline void initialize() noexcept 106 | { 107 | struct LDR_DATA_TABLE_ENTRY { 108 | LIST_ENTRY InLoadOrderLinks; 109 | LIST_ENTRY InMemoryOrderLinks; 110 | LIST_ENTRY InInitializationOrderLinks; 111 | PVOID DllBase; 112 | PVOID EntryPoint; 113 | ULONG SizeOfImage; 114 | UNICODE_STRING FullDllName; 115 | UNICODE_STRING BaseDllName; 116 | }; 117 | 118 | std::unordered_map loaded{ }; 119 | 120 | const auto peb = reinterpret_cast(__readgsqword(0x60)); 121 | auto cur = CONTAINING_RECORD(peb->Ldr->InMemoryOrderModuleList.Flink, 122 | LDR_DATA_TABLE_ENTRY, 123 | InMemoryOrderLinks); 124 | 125 | while (cur->BaseDllName.Length) { 126 | loaded.insert_or_assign(fnv1a::hash(cur->BaseDllName.Buffer), cur); 127 | cur = reinterpret_cast(cur->InLoadOrderLinks.Flink); 128 | } 129 | 130 | for (auto entry : list) { 131 | const auto res = loaded.find(fnv1a::hash(entry->name)); 132 | ASSERT_MSG(res != loaded.cend(), XOR("DLL not loaded yet?")); 133 | const auto dll = res->second; 134 | entry->base = reinterpret_cast(dll->DllBase); 135 | entry->size = dll->SizeOfImage; 136 | } 137 | } 138 | 139 | void add_to_trusted_list(uintptr_t base) noexcept; 140 | 141 | }; 142 | -------------------------------------------------------------------------------- /cheat/src/memory/hook_mgr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "memory.h" 5 | #include "../base/debug.h" 6 | 7 | #define SET_SIG_HOOK(dll, sig, name) set(dll, PATTERN(sig), reinterpret_cast(name::fn), reinterpret_cast(&name::original)) 8 | #define SET_VT_HOOK(inter, name, index) set(inter, index, name::fn, name::original) 9 | #define SET_PTR_HOOK(ptr, name) set(ptr, name::fn, name::original) 10 | 11 | namespace hooks { 12 | 13 | //inline std::add_pointer_t hook_func{ }; 14 | //inline std::add_pointer_t unhook_func{ }; 15 | 16 | //inline std::map hooked_fns{ }; /* Only contains signature hooks */ 17 | inline std::map hooked_ptrs{ }; /* Only contains pointer hooks */ 18 | 19 | void initialize() noexcept; 20 | void end() noexcept; 21 | 22 | template 23 | void set(interface_holder& vmt, int index, void* hook, fn& original) noexcept 24 | { 25 | ASSERT_MSG(vmt.replacement_vmt, XOR("Trying to set hook with replace_vmt = false!")); 26 | vmt.replacement_vmt[index + 1] = reinterpret_cast(hook); 27 | original = reinterpret_cast(vmt.real_vmt[index]); 28 | }; 29 | 30 | template 31 | void set(void** ptr, void* hook, fn& original) noexcept 32 | { 33 | hooked_ptrs[ptr] = *ptr; 34 | original = reinterpret_cast(*ptr); 35 | *ptr = hook; 36 | } 37 | 38 | // template 39 | // void set(dll& dll, std::array&& sig, void* hook, void** original) noexcept 40 | // { 41 | // auto target = dll.find(std::move(sig)); 42 | // ASSERT(target); 43 | // ASSERT(dll.is_within_section(target, ".text"_hash)); 44 | // hooked_fns[hook] = target; 45 | // *original = hook_func(target, hook, false); 46 | // if (!*original) 47 | // LOG_ERROR(XOR("Error while hooking function!")); /* Not fatal, but we should warn about it */ 48 | // }; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /cheat/src/memory/interfaces.cpp: -------------------------------------------------------------------------------- 1 | #include "interfaces.h" 2 | #include "dll.h" 3 | 4 | static void collect_interfaces(dll& dll) noexcept; 5 | template 6 | static void get_cached_interface(interface_holder& ptr, std::string_view version_string) noexcept; 7 | 8 | void interfaces::initialize() noexcept 9 | { 10 | collect_interfaces(dlls::tier0); 11 | collect_interfaces(dlls::client); 12 | collect_interfaces(dlls::engine2); 13 | collect_interfaces(dlls::schemasystem); 14 | collect_interfaces(dlls::input_system); 15 | collect_interfaces(dlls::localize); 16 | 17 | get_cached_interface(cvar, XOR("VEngineCvar007")); 18 | get_cached_interface(client, XOR("Source2Client002")); 19 | get_cached_interface(engine, XOR("Source2EngineToClient001")); 20 | get_cached_interface(game_resource, XOR("GameResourceServiceClientV001")); 21 | get_cached_interface(schema_system, XOR("SchemaSystem_001")); 22 | get_cached_interface(input_stack_system, XOR("InputStackSystemVersion001")); 23 | get_cached_interface(localize, XOR("Localize_001")); 24 | 25 | entity_list.initialize(game_resource->get_entity_list()); 26 | csgo_input.initialize(se::csgo_input::get()); 27 | client_mode.initialize(se::client_mode::get()); 28 | view_render.initialize(se::view_render::get()); 29 | 30 | LOG_INFO(XOR("Interfaces initialized.")); 31 | } 32 | 33 | namespace se { 34 | 35 | struct interface_reg { 36 | std::add_pointer_t create_fn{ }; 37 | const char* name{ }; 38 | interface_reg* next{ }; 39 | }; 40 | 41 | } 42 | 43 | static auto get_interface_regs(dll& dll) noexcept 44 | { 45 | if (!dll.create_interface) { 46 | dll.create_interface = dll.get_export("CreateInterface"_hash); 47 | ASSERT(dll.create_interface); 48 | } 49 | 50 | // Follow jmp instruction inside function to get to CreateInterfaceInternal(), where the global interface list is moved into ESI. 51 | const auto reg_list = *dll.create_interface.absolute(0x3); 52 | ASSERT(reg_list); 53 | return reg_list; 54 | } 55 | 56 | static void collect_interfaces(dll& dll) noexcept 57 | { 58 | for (auto cur = get_interface_regs(dll); cur; cur = cur->next) { 59 | LOG_INFO(XOR("{}: found interface: {}"), dll.name, cur->name); 60 | interfaces::list.push_back(std::make_pair(cur->name, cur->create_fn())); 61 | } 62 | } 63 | 64 | template 65 | static void get_cached_interface(interface_holder& ptr, std::string_view version_string) noexcept 66 | { 67 | for (const auto& [name, iface] : interfaces::list) { 68 | if (name.starts_with(version_string.data())) { 69 | ptr.template initialize(static_cast(iface)); 70 | return; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /cheat/src/memory/interfaces.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../valve/se/se.h" 4 | #include "memory.h" 5 | 6 | namespace interfaces { 7 | 8 | inline std::vector hooked_tables{ }; 9 | inline std::vector> list{ }; 10 | 11 | } 12 | 13 | template requires std::is_pointer_v 14 | struct interface_holder { 15 | ptr instance{ }; 16 | uintptr_t* real_vmt{ }; 17 | std::unique_ptr replacement_vmt{ }; 18 | 19 | constexpr ptr operator->() const noexcept { return instance; } 20 | constexpr void operator=(ptr rhs) noexcept { instance = rhs; } 21 | constexpr operator bool() const noexcept { return instance; } 22 | constexpr operator ptr() noexcept { return instance; } 23 | 24 | // Pass false to replace_vmt if you don't hook anything from the table or if get_vmt_length() is crashing 25 | template 26 | inline void initialize(ptr vptr) noexcept 27 | { 28 | ASSERT(vptr); 29 | constexpr int dynamic_cast_info_len = 1; 30 | 31 | instance = vptr; 32 | 33 | if constexpr (replace_vmt) { 34 | real_vmt = *reinterpret_cast(instance); 35 | 36 | const auto len = memory::get_vmt_length(real_vmt) + dynamic_cast_info_len; 37 | replacement_vmt = std::make_unique(len); 38 | std::ranges::copy(real_vmt - dynamic_cast_info_len, real_vmt + len - dynamic_cast_info_len, replacement_vmt.get()); 39 | 40 | *reinterpret_cast(instance) = replacement_vmt.get() + dynamic_cast_info_len; 41 | 42 | interfaces::hooked_tables.push_back(this); 43 | } 44 | } 45 | 46 | inline void restore() noexcept 47 | { 48 | *reinterpret_cast(instance) = real_vmt; 49 | } 50 | }; 51 | 52 | namespace interfaces { 53 | 54 | inline interface_holder client{ }; 55 | inline interface_holder engine{ }; 56 | inline interface_holder game_resource{ }; 57 | inline interface_holder entity_list{ }; 58 | inline interface_holder csgo_input{ }; 59 | inline interface_holder schema_system{ }; 60 | inline interface_holder input_stack_system{ }; 61 | inline interface_holder client_mode{ }; 62 | inline interface_holder localize{ }; 63 | inline interface_holder view_render{ }; 64 | inline interface_holder cvar{ }; 65 | 66 | void initialize() noexcept; 67 | 68 | } 69 | -------------------------------------------------------------------------------- /cheat/src/memory/memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define CONCAT_IMPL(x, y) x##y 4 | #define CONCAT(x, y) CONCAT_IMPL(x, y) 5 | #define PAD(size) private: [[maybe_unused]] std::byte CONCAT(pad, __COUNTER__)[size]{ }; public: 6 | 7 | #include 8 | 9 | #include "address.h" 10 | #include "dll.h" 11 | #include "netvars.h" 12 | 13 | template requires(len > 0) 14 | class signature { 15 | private: 16 | std::mutex mtx { }; 17 | bool found { }; 18 | address addr { }; 19 | dll &mod; 20 | std::array pattern { }; 21 | 22 | inline void find() noexcept { 23 | std::scoped_lock lock(mtx); 24 | if (found) 25 | return; 26 | 27 | addr = mod.find(std::move(pattern)); 28 | found = true; 29 | } 30 | 31 | public: 32 | signature(dll &mod, std::array pattern) noexcept : mod(mod), pattern(pattern) { } 33 | 34 | inline address get() noexcept { 35 | if (!found) 36 | find(); 37 | return addr; 38 | } 39 | }; 40 | 41 | #define SIG(name, dll, sig) \ 42 | static signature CONCAT(name, _static)(dll, PATTERN(sig)); \ 43 | auto name = CONCAT(name, _static).get(); 44 | 45 | namespace memory { 46 | 47 | template 48 | ty call_virtual(void* base, va_args... args) noexcept 49 | { 50 | return (*static_cast(base))[i](base, args...); 51 | } 52 | 53 | template 54 | ty get_virtual(void* base, int index) noexcept 55 | { 56 | return (*static_cast(base))[index]; 57 | } 58 | 59 | inline address get_frame_address() noexcept 60 | { 61 | return address(reinterpret_cast(_AddressOfReturnAddress()) - sizeof(uintptr_t)); 62 | } 63 | 64 | inline bool is_address_valid(address addr) noexcept 65 | { 66 | if (!addr) 67 | return false; 68 | 69 | MEMORY_BASIC_INFORMATION info{ }; 70 | if (!VirtualQuery(addr, &info, sizeof(info))) 71 | return false; 72 | 73 | return info.State & MEM_COMMIT && !(info.Protect & PAGE_NOACCESS); 74 | } 75 | 76 | inline size_t get_vmt_length(uintptr_t* vptr) noexcept 77 | { 78 | size_t length{ }; 79 | MEMORY_BASIC_INFORMATION info{ }; 80 | 81 | while (VirtualQuery(reinterpret_cast(vptr[length]), &info, sizeof(info)) && 82 | info.State & MEM_COMMIT && 83 | info.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) 84 | ++length; 85 | 86 | return length; 87 | } 88 | 89 | inline void erase_pe_headers(uintptr_t base) noexcept 90 | { 91 | #ifndef _DEBUG 92 | HMODULE mod; 93 | if (GetModuleHandleExA( 94 | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 95 | reinterpret_cast(base), 96 | &mod 97 | ) != 0) { 98 | LOG_ERROR(XOR("erase_pe_header: module is not manually mapped, ignoring")); 99 | return; 100 | } 101 | 102 | MEMORY_BASIC_INFORMATION info{ }; 103 | if (!VirtualQuery(reinterpret_cast(base), &info, sizeof(info))) { 104 | LOG_ERROR(XOR("erase_pe_header: VirtualQuery failed")); 105 | return; 106 | } 107 | 108 | if ((info.Protect & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) == 0) { 109 | LOG_ERROR(XOR("erase_pe_header: pe headers are not writable, ignoring")); 110 | return; 111 | } 112 | 113 | auto dos = reinterpret_cast(base); 114 | if (dos->e_magic != IMAGE_DOS_SIGNATURE) { 115 | LOG_ERROR(XOR("erase_pe_header: invalid DOS header")); 116 | return; 117 | } 118 | 119 | auto nt = reinterpret_cast(base + dos->e_lfanew); 120 | if (nt->Signature != IMAGE_NT_SIGNATURE) { 121 | LOG_ERROR(XOR("erase_pe_header: invalid NT header")); 122 | return; 123 | } 124 | 125 | std::memset(reinterpret_cast(base), 0, nt->OptionalHeader.SizeOfHeaders); 126 | #endif 127 | } 128 | 129 | } 130 | 131 | #define VIRTUAL_FUNCTION(name, ret, idx, args, ... /* params */) \ 132 | inline ret name(__VA_ARGS__) noexcept \ 133 | { \ 134 | return memory::call_virtualargs; \ 135 | } 136 | 137 | // Parameters and arguments are reversed, only way I could get this macro to work properly. 138 | #define VIRTUAL_FUNCTION_SIG(name, ret, dll, sig, args, ... /* params */) \ 139 | inline ret name(__VA_ARGS__) noexcept \ 140 | { \ 141 | SIG(addr, dll, sig) \ 142 | auto fn = addr.cast(); \ 143 | return fn args; \ 144 | } 145 | 146 | #define VIRTUAL_FUNCTION_SIG_ABSOLUTE(name, ret, dll, sig, offset, args, ... /* params */) \ 147 | inline ret name(__VA_ARGS__) noexcept \ 148 | { \ 149 | SIG(addr, dll, sig) \ 150 | auto fn = addr.absolute(offset); \ 151 | return fn args; \ 152 | } 153 | 154 | -------------------------------------------------------------------------------- /cheat/src/memory/netvars.cpp: -------------------------------------------------------------------------------- 1 | #include "netvars.h" 2 | #include "interfaces.h" 3 | #include 4 | 5 | std::mutex netvar_mutex; 6 | 7 | using NetvarKeyValueMap_t = std::unordered_map; 8 | using NetvarTableMap_t = std::unordered_map; 9 | 10 | static bool init_netvars_for_class(NetvarTableMap_t& table_map, const char* class_name, uint32_t class_key) noexcept { 11 | auto type = interfaces::schema_system->find_type_scope_for_module(XOR("client.dll")); 12 | if (!type) { 13 | LOG_ERROR(XOR("init_netvars_for_class: type scope not found for module client.dll")); 14 | return false; 15 | } 16 | 17 | auto class_info = type->find_declared_class(class_name); 18 | if (!class_info) { 19 | table_map.emplace(class_key, NetvarKeyValueMap_t{}); 20 | LOG_ERROR(XOR("init_netvars_for_class: class {} not found"), class_name); 21 | return false; 22 | } 23 | 24 | auto size = class_info->size(); 25 | auto field_data = class_info->get_field_data(); 26 | 27 | auto& kv_Map = table_map[class_key]; 28 | kv_Map.reserve(size); 29 | 30 | for (auto i = 0; i < size; i++) { 31 | auto& field = field_data[i]; 32 | kv_Map.emplace(fnv1a::hash(field.name), field.offset); 33 | } 34 | 35 | return true; 36 | } 37 | 38 | uintptr_t netvars::get_offset(const char *class_name, uint32_t class_key, const char *member_name, uint32_t member_key) noexcept { 39 | std::scoped_lock(netvar_mutex); 40 | 41 | static NetvarTableMap_t table_map; 42 | const auto& table_map_it = table_map.find(class_key); 43 | if (table_map_it == table_map.cend()) { 44 | init_netvars_for_class(table_map, class_name, class_key); 45 | return get_offset(class_name, class_key, member_name, member_key); 46 | } 47 | 48 | const auto& kv_map = table_map_it->second; 49 | const auto& kv_map_it = kv_map.find(member_key); 50 | if (kv_map_it == kv_map.cend()) { 51 | LOG_ERROR(XOR("netvars::get_offset: member {} not found in class {}"), member_name, class_name); 52 | return 0; 53 | } 54 | 55 | LOG_INFO(XOR("resolved netvar offset {}::{} -> {}"), class_name, member_name, kv_map_it->second); 56 | 57 | return kv_map_it->second; 58 | } 59 | -------------------------------------------------------------------------------- /cheat/src/memory/netvars.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../base/base.h" 4 | #include "../crypt/fnv1a.h" 5 | #include "../crypt/xorstr.h" 6 | 7 | namespace netvars { 8 | 9 | uintptr_t get_offset(const char* className, uint32_t classKey, const char* memberName, uint32_t memberKey) noexcept; 10 | 11 | } 12 | 13 | #define NETVAR_OFFSET(var_name, datatable, prop_name, extra_offset, type) \ 14 | std::add_lvalue_reference_t var_name() { \ 15 | \ 16 | static const auto offset = netvars::get_offset( \ 17 | XOR(datatable), datatable##_hash, XOR(prop_name), prop_name##_hash); \ 18 | \ 19 | return *reinterpret_cast>( \ 20 | (uintptr_t)(this) + offset + extra_offset); \ 21 | } 22 | 23 | #define NETVAR(var_name, datatable, prop_name, type) \ 24 | NETVAR_OFFSET(var_name, datatable, prop_name, 0, type) -------------------------------------------------------------------------------- /cheat/src/render/debug_overlay.cpp: -------------------------------------------------------------------------------- 1 | #include "debug_overlay.h" 2 | #include 3 | 4 | #ifdef _DEBUG 5 | 6 | void debug_overlay::render(render::renderer* r) noexcept { 7 | std::unique_lock lock(sections_mtx); 8 | if (sections.empty()) 9 | return; 10 | 11 | for (auto &[name, section] : sections) 12 | section.render(r); 13 | 14 | if (ImGui::Begin(XOR("Debug Overlay"))){ 15 | for (auto &[name, section] : sections) { 16 | if (section.log.empty()) 17 | continue; 18 | ImGui::SeparatorText(name.data()); 19 | ImGui::TextUnformatted(section.log.c_str(), section.log.c_str() + section.log.size()); 20 | } 21 | } 22 | ImGui::End(); 23 | } 24 | 25 | void debug_overlay::w2s() noexcept { 26 | std::unique_lock lock(sections_mtx); 27 | for (auto &[name, section] : sections) 28 | section.w2s(); 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /cheat/src/render/debug_overlay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../base/base.h" 3 | #include "../base/math.h" 4 | #include "../render/render.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // this is our debug overlay, not to be confused with the debug overlay in the game 12 | namespace debug_overlay { 13 | 14 | struct debug_line { 15 | vec3 start = { }, end = { }; 16 | clr4 color = { }; 17 | vec2 start_w2s { }, end_w2s { }; 18 | bool is_visible { }; 19 | bool is_2d { }; 20 | }; 21 | 22 | class debug_section { 23 | public: 24 | std::mutex mutex { }; 25 | std::string log { }; 26 | std::vector lines { }; 27 | 28 | public: 29 | debug_section() noexcept = default; 30 | debug_section(const debug_section &) = delete; 31 | debug_section &operator=(const debug_section &) = delete; 32 | 33 | inline void render(render::renderer* r) noexcept { 34 | for (const auto &line : lines) { 35 | if (!line.is_visible) 36 | continue; 37 | r->line(line.start_w2s.x, line.start_w2s.y, line.end_w2s.x, line.end_w2s.y, line.color); 38 | } 39 | } 40 | 41 | inline void w2s() noexcept { 42 | for (auto &line : lines) 43 | if (!line.is_2d) 44 | line.is_visible = math::world_to_screen(line.start, line.start_w2s) && math::world_to_screen(line.end, line.end_w2s); 45 | } 46 | 47 | inline void reset() noexcept { 48 | log.clear(); 49 | lines.clear(); 50 | } 51 | }; 52 | 53 | inline std::unordered_map sections { }; 54 | inline std::shared_mutex sections_mtx { }; 55 | 56 | class section_accessor { 57 | debug_section §ion; 58 | std::lock_guard lock; 59 | std::shared_lock render_lock; 60 | 61 | public: 62 | section_accessor(debug_section §ion) noexcept : section(section), lock(section.mutex), render_lock(sections_mtx) { 63 | section.reset(); 64 | } 65 | section_accessor(const section_accessor &) = delete; 66 | section_accessor &operator=(const section_accessor &) = delete; 67 | 68 | template 69 | void log(std::string_view fmt, va_args&&... args) const noexcept { 70 | std::string str; 71 | if constexpr (sizeof...(args) > 0) 72 | str = std::vformat(fmt, std::make_format_args(std::forward(args)...)); 73 | else 74 | str = fmt; 75 | 76 | str += '\n'; 77 | 78 | section.log.append(str); 79 | } 80 | 81 | void line(const vec3 &start, const vec3 &end, const clr4 &color) const noexcept { 82 | section.lines.emplace_back(debug_line{ start, end, color, vec2{ }, vec2{ }, false, false }); 83 | } 84 | 85 | void line2d(const vec2 &start, const vec2 &end, const clr4 &color) const noexcept { 86 | section.lines.emplace_back(debug_line{ vec3{ }, vec3{ }, color, start, end, true, true }); 87 | } 88 | }; 89 | 90 | using SectionFunction = std::function; 91 | 92 | #ifdef _DEBUG 93 | inline void section(const std::string_view name, const SectionFunction fn) noexcept { 94 | const auto section = section_accessor(sections[name]); 95 | fn(section); 96 | } 97 | 98 | void render(render::renderer* r) noexcept; 99 | void w2s() noexcept; 100 | 101 | #define DEBUG_SECTION(name, fn) debug_overlay::section(name, fn) 102 | #else 103 | #define DEBUG_SECTION(name, fn) 104 | inline void render(render::renderer* r) noexcept {}; 105 | inline void w2s() noexcept {}; 106 | #endif 107 | 108 | } -------------------------------------------------------------------------------- /cheat/src/render/imgui_extra.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../base/base.h" 3 | #include 4 | 5 | namespace ImGui 6 | { 7 | bool ColorEdit4(const char* label, uint32_t* col, ImGuiColorEditFlags flags = 0) { 8 | float col_f[4] = { 9 | ((*col >> 0 ) & 0xFF) / 255.0f, 10 | ((*col >> 8 ) & 0xFF) / 255.0f, 11 | ((*col >> 16) & 0xFF) / 255.0f, 12 | ((*col >> 24) & 0xFF) / 255.0f 13 | }; 14 | if (ColorEdit4(label, col_f, flags)) { 15 | *col = (((uint8_t)(col_f[3] * 255.0f)) << 24) | 16 | (((uint8_t)(col_f[2] * 255.0f)) << 16) | 17 | (((uint8_t)(col_f[1] * 255.0f)) << 8) | 18 | (((uint8_t)(col_f[0] * 255.0f)) << 0); 19 | return true; 20 | } 21 | return false; 22 | } 23 | 24 | bool ColorEdit4(const char* label, clr4* col, ImGuiColorEditFlags flags = 0) { 25 | return ColorEdit4(label, &col->rgba, flags); 26 | } 27 | } -------------------------------------------------------------------------------- /cheat/src/render/menu.cpp: -------------------------------------------------------------------------------- 1 | #include "menu.h" 2 | #include 3 | #include 4 | #include "imgui_extra.h" 5 | #include "../core/cheat.h" 6 | #include "../core/config.h" 7 | #include "../core/entity_cache.h" 8 | 9 | #define ADD_VERSION(str) (str " " BAKAWARE_VERSION) 10 | 11 | void menu::render() noexcept { 12 | if (!is_open) 13 | return; 14 | 15 | #ifdef _DEBUG 16 | ImGui::ShowDemoWindow(); 17 | 18 | if (ImGui::Button(XOR("Unhook"))) 19 | cheat::should_unhook = true; 20 | 21 | if (ImGui::Button(XOR("Unlock all cvars"))) { 22 | interfaces::cvar->unlock_all(); 23 | } 24 | 25 | ImGui::SeparatorText(XOR("Debug config")); 26 | 27 | ImGui::Text(XOR("debug_flags: 0x%X %d"), debug_cfg.debug_flags, debug_cfg.debug_flags); 28 | for (size_t i = 0; i < sizeof(debug_cfg.debug_flags) * CHAR_BIT; i++) { 29 | auto mask = (1 << i); 30 | bool val = (debug_cfg.debug_flags & mask) != 0; 31 | if (i % 8 != 0) 32 | ImGui::SameLine(); 33 | if (ImGui::Checkbox(std::format(XOR("{:02}"), i + 1).c_str(), &val)) 34 | debug_cfg.debug_flags ^= mask; 35 | } 36 | ImGui::SliderInt(XOR("debug_int"), &debug_cfg.debug_int, 0, 100); 37 | ImGui::SliderFloat(XOR("debug_float"), &debug_cfg.debug_float, 0, 100); 38 | ImGui::ColorEdit4(XOR("debug_color"), &debug_cfg.debug_color); 39 | 40 | ImGui::SeparatorText(XOR("Debug info")); 41 | 42 | ImGui::Text(XOR("Global vars: %p"), cheat::global_vars); 43 | ImGui::Text(XOR("Local controller: %p"), cheat::local.controller); 44 | ImGui::Text(XOR("Local player pawn: %p"), cheat::local.pawn); 45 | ImGui::Text(XOR("highest_entity_index: %d"), interfaces::entity_list->get_highest_entity_index()); 46 | ImGui::Text(XOR("last_mouse_enabled: %d"), input::last_mouse_enabled ? 1 : 0); 47 | { 48 | std::shared_lock lock(entity_cache::mutex); 49 | ImGui::Text(XOR("entity_cache size: %d"), entity_cache::entities.size()); 50 | } 51 | #endif 52 | 53 | ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); 54 | ImGui::SetNextWindowSize(ImVec2(800, 600)); 55 | if (ImGui::Begin(XOR(ADD_VERSION("BakaWare")), 0, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize)) { 56 | { 57 | ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 58 | ImGui::Columns(2, 0, true); 59 | ImGui::SetColumnWidth(-1, 150); 60 | ImGui::GetCurrentWindow()->DC.CurrentColumns->Flags |= ImGuiColumnsFlags_NoResize; 61 | const ImVec2 size(ImGui::GetContentRegionAvail().x, 50); 62 | for (int i = 0; i < tabs.size(); i++) { 63 | auto& tab = tabs[i]; 64 | if (tab->render_button(size, i == selected_tab)) 65 | selected_tab = i; 66 | } 67 | ImGui::PopStyleVar(); 68 | 69 | // TODO: configs 70 | 71 | ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 72 | ImGui::NextColumn(); 73 | ImGui::PopStyleVar(); 74 | } 75 | ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); 76 | if (ImGui::BeginChild(XOR("##settings"), ImVec2(), true)) { 77 | tabs[selected_tab]->render(); 78 | } 79 | ImGui::EndChild(); 80 | ImGui::PopStyleVar(); 81 | ImGui::Columns(); 82 | } 83 | ImGui::End(); 84 | ImGui::PopStyleVar(); 85 | 86 | } 87 | 88 | bool menu::menu_tab::render_button(const ImVec2 size, bool selected, bool vertical) noexcept { 89 | ImGuiID id = ImGui::GetID((label + "_back").c_str()); 90 | ImGuiStyle style = ImGui::GetStyle(); 91 | const ImVec2 label_size = ImGui::CalcTextSize(label.c_str(), NULL, true); 92 | const auto pos = ImGui::GetCurrentWindow()->DC.CursorPos; 93 | const ImRect rect(pos, pos + size); 94 | ImGui::ItemSize(size, style.FramePadding.y); 95 | if (!ImGui::ItemAdd(rect, id)) 96 | return false; 97 | bool hovered; 98 | bool pressed = ImGui::ButtonBehavior(rect, id, &hovered, 0); 99 | if (pressed) ImGui::MarkItemEdited(id); 100 | float delta = ImGui::GetIO().DeltaTime; 101 | float size_var = vertical ? size.y : size.x; 102 | if (hovered || selected) { 103 | if (btn_mode == 100) { 104 | btn_mode = 0; 105 | btn_speed = 15; 106 | } 107 | if (btn_mode != 2) { 108 | btn_speed += delta * 50; 109 | btn_width += btn_speed * delta * 100; 110 | } 111 | if (btn_width > size_var) { 112 | btn_width = size_var; 113 | btn_speed *= btn_mode == 0 ? -.3f : 0; 114 | btn_mode++; 115 | } 116 | } else { 117 | if (btn_mode != 100) btn_speed = 0; 118 | btn_mode = 100; 119 | btn_speed -= delta * 50; 120 | btn_width += btn_speed * delta * 100; 121 | if (btn_width < 0) { 122 | btn_speed = 0; 123 | btn_width = 0; 124 | } 125 | } 126 | const ImRect rect2(pos, pos + (vertical ? ImVec2(size.x, btn_width) : ImVec2(btn_width, size.y))); 127 | ImGui::RenderNavHighlight(rect, id); 128 | ImGui::RenderFrame(rect2.Min, rect2.Max, ImGui::GetColorU32(selected ? ImGuiCol_ButtonActive : ImGuiCol_Button), false, style.FrameRounding); 129 | ImGui::RenderTextClipped(rect.Min + style.FramePadding, rect.Max - style.FramePadding, label.c_str(), NULL, &label_size, style.ButtonTextAlign, &rect); 130 | 131 | return pressed; 132 | } 133 | 134 | void menu::menu_tab_visuals::render() noexcept { 135 | ImGui::SeparatorText(XOR("Players")); 136 | ImGui::Checkbox(XOR("Enabled##Players"), &cfg.esp.players.enabled); 137 | ImGui::Checkbox(XOR("Teammates##Players"), &cfg.esp.players.teammates); 138 | ImGui::Checkbox(XOR("Box##Players"), &cfg.esp.players.box); 139 | ImGui::Checkbox(XOR("Skeleton##Players"), &cfg.esp.players.skeleton); 140 | ImGui::Checkbox(XOR("Name##Players"), &cfg.esp.players.name); 141 | ImGui::Checkbox(XOR("Health##Players"), &cfg.esp.players.health); 142 | ImGui::Checkbox(XOR("Weapon name##Players"), &cfg.esp.players.weapon_name); 143 | ImGui::Checkbox(XOR("Weapon ammo##Players"), &cfg.esp.players.weapon_ammo); 144 | 145 | 146 | ImGui::SeparatorText(XOR("Weapons")); 147 | ImGui::Checkbox(XOR("Enabled##Weapons"), &cfg.esp.weapons.enabled); 148 | ImGui::Checkbox(XOR("Box##Weapons"), &cfg.esp.weapons.box); 149 | ImGui::Checkbox(XOR("Name##Weapons"), &cfg.esp.weapons.name); 150 | ImGui::Checkbox(XOR("Ammo##Weapons"), &cfg.esp.weapons.ammo); 151 | } 152 | 153 | void menu::menu_tab_misc::render() noexcept { 154 | ImGui::Checkbox(XOR("Bunny hop"), &cfg.misc.bunny_hop); 155 | ImGui::Checkbox(XOR("Recoil crosshair"), &cfg.misc.reoil_crosshair); 156 | 157 | if (ImGui::Button(XOR("CRASH!"))) 158 | *(uint32_t*)nullptr = 0xDEADBEEF; 159 | ImGui::SameLine(); 160 | ASSERT(!ImGui::Button(XOR("ASSERT!"))); 161 | ImGui::SameLine(); 162 | ASSERT_MSG(!ImGui::Button(XOR("ASSERT MSG!")), "This is a manual assert message!"); 163 | } 164 | 165 | void menu::menu_tab_legit::render() noexcept { 166 | ImGui::SeparatorText(XOR("RCS")); 167 | ImGui::Checkbox(XOR("Enabled##RCS"), &cfg.legit.rcs.enabled); 168 | ImGui::Text(XOR("Strength (horizontal/vertical)##RCS")); 169 | ImGui::SliderFloat2(XOR("##RCSStrength"), cfg.legit.rcs.axis, 0.0f, 100.0f, "%.1f%"); 170 | 171 | ImGui::SeparatorText(XOR("Backtrack")); 172 | ImGui::Checkbox(XOR("Enabled##Backtrack"), &cfg.legit.backtrack.enabled); 173 | ImGui::Checkbox(XOR("Skeleton##Backtrack"), &cfg.legit.backtrack.skeleton); 174 | ImGui::SliderFloat(XOR("Max delay##Backtrack"), &cfg.legit.backtrack.max_time_ms, 0, 1000, "%.0f ms"); 175 | } 176 | -------------------------------------------------------------------------------- /cheat/src/render/menu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../base/base.h" 3 | #include "../core/input.h" 4 | 5 | namespace menu { 6 | inline bool is_open{ true }; 7 | inline int selected_tab { 0 }; 8 | 9 | inline void toggle() { 10 | is_open = !is_open; 11 | input::unlock_cursor(is_open); 12 | }; 13 | void render() noexcept; 14 | 15 | class menu_tab { 16 | private: 17 | std::string label; 18 | float btn_width{ 0.f }; 19 | float btn_speed{ 0.f }; 20 | unsigned int btn_mode{ 0 }; 21 | public: 22 | menu_tab(std::string label) noexcept : label(label) { }; 23 | bool render_button(const ImVec2 size, bool selected = false, bool vertical = false) noexcept; 24 | virtual void render() noexcept = 0; 25 | }; 26 | 27 | class menu_tab_visuals : public menu_tab { 28 | public: 29 | menu_tab_visuals() noexcept : menu_tab(XOR("Visuals")) { }; 30 | void render() noexcept override; 31 | }; 32 | 33 | class menu_tab_misc : public menu_tab { 34 | public: 35 | menu_tab_misc() noexcept : menu_tab(XOR("Misc")) { }; 36 | void render() noexcept override; 37 | }; 38 | 39 | class menu_tab_legit : public menu_tab { 40 | public: 41 | menu_tab_legit() noexcept : menu_tab(XOR("Legit")) { }; 42 | void render() noexcept override; 43 | }; 44 | 45 | inline std::vector tabs { 46 | new menu_tab_visuals(), 47 | new menu_tab_misc(), 48 | new menu_tab_legit() 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /cheat/src/render/render.cpp: -------------------------------------------------------------------------------- 1 | #include "render.h" 2 | #include "../base/base.h" 3 | #include "../memory/memory.h" 4 | #include "../core/cheat.h" 5 | #include "menu.h" 6 | #include "../core/features/features.h" 7 | #include 8 | #include 9 | 10 | extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 11 | 12 | void render::initialize() noexcept { 13 | auto swap_chain_ptr = **dlls::render_system_dx11.find(PATTERN("66 0F 7F 05 ? ? ? ? 66 0F 7F 0D ? ? ? ? 48 89 35")).absolute(0x4); 14 | 15 | if (!set_swap_chain(swap_chain_ptr->pSwapChain)) 16 | return; 17 | 18 | ImGui::CreateContext(); 19 | ImGui_ImplWin32_Init(game_window); 20 | ImGui_ImplDX11_Init(device, context); 21 | 22 | ImVec4* colors = ImGui::GetStyle().Colors; 23 | colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); 24 | colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); 25 | colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); 26 | colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); 27 | colors[ImGuiCol_PopupBg] = ImVec4(0.03f, 0.03f, 0.03f, 1.00f); 28 | colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 1.00f, 0.50f); 29 | colors[ImGuiCol_BorderShadow] = ImVec4(0.29f, 0.29f, 0.29f, 0.50f); 30 | colors[ImGuiCol_FrameBg] = ImVec4(0.15f, 0.15f, 0.15f, 0.54f); 31 | colors[ImGuiCol_FrameBgHovered] = ImVec4(0.54f, 0.54f, 0.54f, 0.40f); 32 | colors[ImGuiCol_FrameBgActive] = ImVec4(0.54f, 0.54f, 0.54f, 0.40f); 33 | colors[ImGuiCol_TitleBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); 34 | colors[ImGuiCol_TitleBgActive] = ImVec4(0.00f, 0.41f, 1.00f, 1.00f); 35 | colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.46f, 0.51f); 36 | colors[ImGuiCol_MenuBarBg] = ImVec4(0.00f, 0.00f, 0.62f, 1.00f); 37 | colors[ImGuiCol_ScrollbarBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.53f); 38 | colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.00f, 0.26f, 0.65f, 1.00f); 39 | colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.00f, 0.37f, 0.94f, 1.00f); 40 | colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.00f, 0.37f, 0.94f, 1.00f); 41 | colors[ImGuiCol_CheckMark] = ImVec4(0.00f, 0.37f, 0.94f, 1.00f); 42 | colors[ImGuiCol_SliderGrab] = ImVec4(0.00f, 0.26f, 0.65f, 1.00f); 43 | colors[ImGuiCol_SliderGrabActive] = ImVec4(0.00f, 0.37f, 0.94f, 1.00f); 44 | colors[ImGuiCol_Button] = ImVec4(0.00f, 0.26f, 0.65f, 1.00f); 45 | colors[ImGuiCol_ButtonHovered] = ImVec4(0.00f, 0.37f, 0.94f, 1.00f); 46 | colors[ImGuiCol_ButtonActive] = ImVec4(0.00f, 0.37f, 0.94f, 1.00f); 47 | colors[ImGuiCol_Header] = ImVec4(0.00f, 0.26f, 0.65f, 1.00f); 48 | colors[ImGuiCol_HeaderHovered] = ImVec4(0.00f, 0.37f, 0.94f, 1.00f); 49 | colors[ImGuiCol_HeaderActive] = ImVec4(0.00f, 0.37f, 0.94f, 1.00f); 50 | colors[ImGuiCol_Separator] = ImVec4(0.00f, 0.00f, 1.00f, 0.50f); 51 | colors[ImGuiCol_SeparatorHovered] = ImVec4(0.00f, 0.00f, 1.00f, 0.50f); 52 | colors[ImGuiCol_SeparatorActive] = ImVec4(0.00f, 0.00f, 1.00f, 0.50f); 53 | colors[ImGuiCol_ResizeGrip] = ImVec4(0.00f, 0.00f, 0.44f, 0.49f); 54 | colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.00f, 0.00f, 1.00f, 0.49f); 55 | colors[ImGuiCol_ResizeGripActive] = ImVec4(0.00f, 0.00f, 1.00f, 0.49f); 56 | colors[ImGuiCol_Tab] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f); 57 | colors[ImGuiCol_TabHovered] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); 58 | colors[ImGuiCol_TabActive] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); 59 | colors[ImGuiCol_TabUnfocused] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f); 60 | colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); 61 | colors[ImGuiCol_PlotLines] = ImVec4(0.00f, 0.73f, 0.00f, 1.00f); 62 | colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.00f, 1.00f, 0.00f, 1.00f); 63 | colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f); 64 | colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); 65 | colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); 66 | colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 67 | colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); 68 | colors[ImGuiCol_PlotHistogram] = ImVec4(0.00f, 0.73f, 0.00f, 1.00f); 69 | colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.00f, 1.00f, 0.00f, 1.00f); 70 | colors[ImGuiCol_TextSelectedBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.35f); 71 | colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); 72 | colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 73 | colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.41f, 1.00f, 0.00f, 0.70f); 74 | colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 75 | colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 76 | 77 | ImGuiStyle& style = ImGui::GetStyle(); 78 | style.ChildRounding = .0f; 79 | style.FrameRounding = .0f; 80 | style.GrabRounding = .0f; 81 | style.PopupRounding = .0f; 82 | style.ScrollbarRounding = .0f; 83 | style.TabRounding = .0f; 84 | style.WindowRounding = .0f; 85 | style.WindowTitleAlign = ImVec2(0.5f, 0.5f); 86 | style.GrabMinSize = 20.f; 87 | 88 | LOG_INFO(XOR("Render initialized.")); 89 | } 90 | 91 | bool render::set_swap_chain(IDXGISwapChain* swap_chain) noexcept { 92 | render::swap_chain = swap_chain; 93 | 94 | DXGI_SWAP_CHAIN_DESC swapChainDesc; 95 | if (FAILED(swap_chain->GetDesc(&swapChainDesc))) { 96 | LOG_ERROR(XOR("Failed to get swap chain description.")); 97 | return false; 98 | } 99 | game_window = swapChainDesc.OutputWindow; 100 | 101 | if (FAILED(swap_chain->GetDevice(__uuidof(ID3D11Device), reinterpret_cast(&device)))) { 102 | LOG_ERROR(XOR("Failed to get device from swap chain.")); 103 | return false; 104 | } 105 | 106 | device->GetImmediateContext(&context); 107 | 108 | ID3D11Texture2D* back_buffer; 109 | if (FAILED(swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&back_buffer)))) { 110 | LOG_ERROR(XOR("Failed to get buffer from swap chain.")); 111 | return false; 112 | } 113 | 114 | D3D11_RENDER_TARGET_VIEW_DESC desc; 115 | desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 116 | desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; 117 | 118 | if (FAILED(device->CreateRenderTargetView(back_buffer, &desc, &render_target_view))) { 119 | back_buffer->Release(); 120 | LOG_ERROR(XOR("Failed to create render target view.")); 121 | return false; 122 | } 123 | back_buffer->Release(); 124 | 125 | interfaces::engine->get_screen_size(&cheat::screen_size.x, &cheat::screen_size.y); 126 | 127 | return true; 128 | } 129 | 130 | void render::cleanup_render_target() noexcept { 131 | if (render_target_view) { 132 | render_target_view->Release(); 133 | render_target_view = nullptr; 134 | } 135 | } 136 | 137 | void render::render() noexcept { 138 | if (!render_target_view) 139 | return; 140 | 141 | ImGui_ImplDX11_NewFrame(); 142 | ImGui_ImplWin32_NewFrame(); 143 | { 144 | std::scoped_lock lock(input_mutex); 145 | ImGui::NewFrame(); 146 | } 147 | 148 | auto r = render::renderer(ImGui::GetBackgroundDrawList()); 149 | 150 | features::render(&r); 151 | debug_overlay::render(&r); 152 | 153 | menu::render(); 154 | 155 | ImGui::Render(); 156 | context->OMSetRenderTargets(1, &render_target_view, nullptr); 157 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); 158 | } 159 | 160 | bool render::input(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept { 161 | { 162 | std::scoped_lock lock(input_mutex); 163 | ImGui_ImplWin32_WndProcHandler(wnd, msg, wparam, lparam); 164 | } 165 | if (!menu::is_open) 166 | return false; 167 | 168 | switch (msg) { 169 | case WM_MOUSEMOVE: 170 | case WM_NCMOUSEMOVE: 171 | case WM_MOUSELEAVE: 172 | case WM_NCMOUSELEAVE: 173 | case WM_LBUTTONDOWN: 174 | case WM_LBUTTONDBLCLK: 175 | case WM_RBUTTONDOWN: 176 | case WM_RBUTTONDBLCLK: 177 | case WM_MBUTTONDOWN: 178 | case WM_MBUTTONDBLCLK: 179 | case WM_XBUTTONDOWN: 180 | case WM_XBUTTONDBLCLK: 181 | case WM_LBUTTONUP: 182 | case WM_RBUTTONUP: 183 | case WM_MBUTTONUP: 184 | case WM_XBUTTONUP: 185 | case WM_MOUSEWHEEL: 186 | case WM_MOUSEHWHEEL: 187 | case WM_KEYDOWN: 188 | case WM_KEYUP: 189 | case WM_SYSKEYDOWN: 190 | case WM_SYSKEYUP: 191 | case WM_SETFOCUS: 192 | case WM_KILLFOCUS: 193 | case WM_CHAR: 194 | case WM_DEVICECHANGE: 195 | return true; 196 | default: 197 | return false; 198 | } 199 | } 200 | 201 | void render::end() noexcept { 202 | ImGui_ImplDX11_Shutdown(); 203 | ImGui_ImplWin32_Shutdown(); 204 | ImGui::DestroyContext(); 205 | 206 | cleanup_render_target(); 207 | } 208 | -------------------------------------------------------------------------------- /cheat/src/render/render.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../memory/memory.h" 6 | 7 | namespace render { 8 | 9 | class CSwapChainDx11 { 10 | public: 11 | PAD(0x178) 12 | IDXGISwapChain* pSwapChain; 13 | }; 14 | 15 | inline HWND game_window{ }; 16 | inline IDXGISwapChain* swap_chain{ }; 17 | inline ID3D11Device* device{ }; 18 | inline ID3D11RenderTargetView* render_target_view{ }; 19 | inline ID3D11DeviceContext* context{ }; 20 | inline std::recursive_mutex input_mutex{ }; 21 | 22 | void initialize() noexcept; 23 | bool set_swap_chain(IDXGISwapChain* swap_chain) noexcept; 24 | void cleanup_render_target() noexcept; 25 | void render() noexcept; 26 | bool input(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept; 27 | void end() noexcept; 28 | 29 | class renderer { 30 | public: 31 | renderer(ImDrawList* draw_list) noexcept : draw_list(draw_list) {} 32 | 33 | void rect(float x1, float y1, float x2, float y2, clr4 color, float t = 1.0f, float r = 0.0f) { 34 | draw_list->AddRect(ImVec2(x1, y1), ImVec2(x2, y2), color.rgba, r, ImDrawFlags_RoundCornersAll, t); 35 | } 36 | 37 | void rect_filled(float x1, float y1, float x2, float y2, clr4 color, float r = 0.0f) { 38 | draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), color.rgba, r, ImDrawFlags_RoundCornersAll); 39 | } 40 | 41 | void rect_filled_multi_color(float x1, float y1, float x2, float y2, clr4 upr_left, clr4 upr_right, clr4 btm_right, clr4 btm_left) { 42 | draw_list->AddRectFilledMultiColor(ImVec2(x1, y1), ImVec2(x2, y2), upr_left.rgba, upr_right.rgba, btm_right.rgba, btm_left.rgba); 43 | } 44 | 45 | vec2 calc_text_size(const char* text) { 46 | return ImGui::CalcTextSize(text); 47 | } 48 | 49 | void text(float x, float y, clr4 color, const char* text, bool outline = true) { 50 | draw_list->AddText(ImVec2(x + 1, y + 1), clr4::black(color.a).rgba, text); 51 | draw_list->AddText(ImVec2(x, y), color.rgba, text); 52 | } 53 | 54 | void line(float x1, float y1, float x2, float y2, clr4 color, float t = 1.0f) { 55 | draw_list->AddLine(ImVec2(x1, y1), ImVec2(x2, y2), color.rgba, t); 56 | } 57 | 58 | private: 59 | ImDrawList* draw_list; 60 | }; 61 | 62 | } 63 | -------------------------------------------------------------------------------- /cheat/src/valve/cs/cs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../base/base.h" 4 | 5 | #include "econ.h" 6 | #include "vdata.h" 7 | #include "entity.h" 8 | #include "player.h" -------------------------------------------------------------------------------- /cheat/src/valve/cs/econ.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../memory/memory.h" 4 | 5 | namespace cs { 6 | 7 | class econ_item_definition { 8 | public: 9 | PAD(0x8); // vtable 10 | void* kv_item; 11 | uint16_t def_index; 12 | se::util_vector associated_items_def_indexes; 13 | bool enabled; 14 | const char* prefab; 15 | uint8_t min_item_level; 16 | uint8_t max_item_level; 17 | uint8_t item_rarity; 18 | uint8_t item_quality; 19 | uint8_t forced_item_quality; 20 | uint8_t default_drop_item_quality; 21 | uint8_t default_drop_quantity; 22 | se::util_vector static_attributes; 23 | uint8_t popularity_seed; 24 | void* portraits_kv; 25 | const char* item_base_name; 26 | bool proper_name; 27 | const char* item_type_name; 28 | uint32_t item_type_id; 29 | const char* item_desc; 30 | 31 | auto get_simple_weapon_name() { 32 | return address(this).offset(0x210).dereference(); 33 | } 34 | }; 35 | 36 | class econ_item_view { 37 | public: 38 | VIRTUAL_FUNCTION(get_static_data, econ_item_definition*, 13, (this)) 39 | }; 40 | 41 | class attribute_container { 42 | public: 43 | NETVAR(m_Item, "C_AttributeContainer", "m_Item", econ_item_view); 44 | }; 45 | 46 | } -------------------------------------------------------------------------------- /cheat/src/valve/cs/entity.cpp: -------------------------------------------------------------------------------- 1 | #include "entity.h" 2 | #include "player.h" 3 | #include "../../memory/interfaces.h" 4 | #include "../../base/math.h" 5 | #include "../../core/input.h" 6 | #include "../../core/cheat.h" 7 | #include 8 | 9 | 10 | bool cs::base_entity::get_bounding_box(bbox &out, bool hitbox) noexcept { 11 | collision_property* collision = m_pCollision(); 12 | if (!collision) 13 | return false; 14 | 15 | game_scene_node* scene_node = m_pGameSceneNode(); 16 | if (!scene_node) 17 | return false; 18 | 19 | const se::transform node_to_world = scene_node->m_nodeToWorld(); 20 | mat3x4 trans; 21 | node_to_world.to_matrix(trans); 22 | 23 | vec3 min, max; 24 | if (hitbox) { 25 | if (!collision->outer) 26 | return false; 27 | 28 | cs::base_animating* base_animating = collision->outer->get_base_animating(); 29 | if (!base_animating) 30 | return false; 31 | 32 | se::hitbox_set* hb_set = base_animating->get_hitbox_set(0); 33 | if (!hb_set || hb_set->hit_boxes.size == 0) 34 | return false; 35 | 36 | ASSERT(hb_set->hit_boxes.size == 1); 37 | 38 | auto& hitbox = hb_set->hit_boxes[0]; 39 | min = hitbox.mins; 40 | max = hitbox.maxs; 41 | } else { 42 | min = collision->m_vecMins(); 43 | max = collision->m_vecMaxs(); 44 | } 45 | 46 | out.x = out.y = std::numeric_limits::max(); 47 | out.w = out.h = -std::numeric_limits::max(); 48 | 49 | for (size_t i = 0; i < 8; ++i) { 50 | const vec3 point = vec3( 51 | i & 1 ? max.x : min.x, 52 | i & 2 ? max.y : min.y, 53 | i & 4 ? max.z : min.z 54 | ).transform(trans); 55 | 56 | vec2 screen; 57 | if (!math::world_to_screen(point, screen)) 58 | return false; 59 | 60 | out.x = std::min(out.x, screen.x); 61 | out.y = std::min(out.y, screen.y); 62 | out.w = std::max(out.w, screen.x); 63 | out.h = std::max(out.h, screen.y); 64 | } 65 | 66 | const float width = out.w - out.x; 67 | if (width < 4.f) { 68 | const float half = (4.f - width) * 0.5f; 69 | out.x -= std::floor(half); 70 | out.w += std::ceil(half); 71 | } 72 | 73 | const float height = out.h - out.y; 74 | if (height < 4.f) { 75 | const float half = (4.f - height) * 0.5f; 76 | out.y -= std::floor(half); 77 | out.h += std::ceil(half); 78 | } 79 | 80 | return true; 81 | } 82 | 83 | bool cs::base_player_pawn::get_bounding_box(bbox &out, std::array, MAX_STUDIO_BONES>& bone_scrs, int& visible_bones_count) noexcept { 84 | visible_bones_count = 0; 85 | 86 | auto game_scene_node = m_pGameSceneNode(); 87 | if (!game_scene_node) 88 | return false; 89 | 90 | auto skeleton = game_scene_node->get_skeleton_instance(); 91 | if (!skeleton) 92 | return false; 93 | 94 | // do this first so we don't have to check every bone if the origin is offscreen 95 | constexpr float origin2_offset = 32.f; 96 | auto& origin = game_scene_node->m_vecAbsOrigin(); 97 | auto origin2 = origin + vec3(0, 0, origin2_offset); 98 | vec2 origin_scr, origin2_scr; 99 | if (!math::world_to_screen(origin, origin_scr, false) || !math::world_to_screen(origin2, origin2_scr, false)) 100 | return false; 101 | 102 | skeleton->calc_world_space_bones(cs::bone_flags::FLAG_HITBOX); 103 | 104 | auto& model_state = skeleton->m_modelState(); 105 | cs::model* model = model_state.m_hModel(); 106 | if (!model) 107 | return false; 108 | 109 | auto num_bones = model->num_bones(); 110 | auto bone_data = model_state.get_bone_data(); 111 | 112 | if (num_bones > MAX_STUDIO_BONES) 113 | num_bones = MAX_STUDIO_BONES; 114 | 115 | for (uint32_t i = 0; i < num_bones; i++) { 116 | if (!(model->bone_flags(i) & cs::bone_flags::FLAG_HITBOX)) { 117 | continue; 118 | } 119 | 120 | auto parent_index = model->bone_parent(i); 121 | if (parent_index == -1) 122 | continue; 123 | 124 | vec2 start_scr, end_scr; 125 | if ( 126 | !math::world_to_screen(bone_data[i].pos, start_scr, false) || 127 | !math::world_to_screen(bone_data[parent_index].pos, end_scr, false) 128 | ) { 129 | continue; 130 | } 131 | 132 | bone_scrs[visible_bones_count++] = std::make_pair(start_scr, end_scr); 133 | } 134 | 135 | out.x = out.y = std::numeric_limits::max(); 136 | out.w = out.h = -std::numeric_limits::max(); 137 | 138 | if (visible_bones_count == 0) 139 | return false; 140 | 141 | for (int i = 0; i < visible_bones_count; i++) { 142 | const auto& [start, end] = bone_scrs[i]; 143 | 144 | out.x = std::min(out.x, start.x); 145 | out.y = std::min(out.y, start.y); 146 | out.w = std::max(out.w, start.x); 147 | out.h = std::max(out.h, start.y); 148 | 149 | out.x = std::min(out.x, end.x); 150 | out.y = std::min(out.y, end.y); 151 | out.w = std::max(out.w, end.x); 152 | out.h = std::max(out.h, end.y); 153 | } 154 | 155 | out.floor(); 156 | 157 | const float scale = std::abs(origin_scr.y - origin2_scr.y) / origin2_offset; 158 | const float padding = std::floor(scale * 8); 159 | out.x -= padding; 160 | out.y -= padding; 161 | out.w += padding; 162 | out.h += padding; 163 | 164 | return true; 165 | } 166 | 167 | cs::entity_instance_by_class_iter::entity_instance_by_class_iter(base_entity* start_entity, const char* name) noexcept { 168 | entity = start_entity ? start_entity->m_pEntity() : nullptr; 169 | find_filter = nullptr; // haven't reversed yet, seems to always be null 170 | type = entity_iter_type::UNKNOWN; // haven't reversed yet, seems to always be 0 171 | unk1 = 0; // haven't reversed yet, hard coded to 0 172 | class_name = name; 173 | unk2 = nullptr; // haven't reversed yet, hard coded to nullptr 174 | 175 | // save cpu cycles in next() lmao 176 | if (!next_fn) { 177 | SIG(next_fn_ptr, dlls::client, "E8 ? ? ? ? 48 85 C0 75 2C 48 8B 0D") 178 | next_fn = next_fn_ptr.absolute(); 179 | } 180 | } 181 | 182 | cs::base_entity *cs::internal::get_entity_by_index(int index) noexcept { 183 | return interfaces::entity_list->get_base_entity(index); 184 | } 185 | 186 | cs::weapon_cs_base *cs::base_player_pawn::get_active_weapon() noexcept { 187 | auto weapon_services = m_pWeaponServices(); 188 | if (!weapon_services) 189 | return nullptr; 190 | 191 | return weapon_services->m_hActiveWeapon().get(); 192 | } 193 | 194 | float cs::base_player_weapon::get_next_primary_attack() noexcept { 195 | if (!cheat::global_vars) 196 | return std::numeric_limits::max(); 197 | 198 | const auto tick = m_nNextPrimaryAttackTick().m_Value; 199 | const auto ratio = m_flNextPrimaryAttackTickRatio(); 200 | return (tick + ratio) * cheat::global_vars->interval_per_tick; 201 | } 202 | -------------------------------------------------------------------------------- /cheat/src/valve/cs/player.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../memory/memory.h" 3 | #include "entity.h" 4 | 5 | namespace cs { 6 | 7 | class player_pawn_component { }; 8 | 9 | class player_weapon_services : public player_pawn_component { 10 | public: 11 | NETVAR(m_hActiveWeapon, "CPlayer_WeaponServices", "m_hActiveWeapon", handle); 12 | }; 13 | 14 | } -------------------------------------------------------------------------------- /cheat/src/valve/cs/vdata.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../memory/memory.h" 3 | 4 | class entity_subclass_v_data_base { 5 | public: 6 | template requires std::derived_from 7 | inline T* as() { 8 | return (T*)this; 9 | } 10 | }; 11 | 12 | class base_player_weapon_v_data : public entity_subclass_v_data_base { 13 | public: 14 | NETVAR(m_bIsFullAuto, "CBasePlayerWeaponVData", "m_bIsFullAuto", bool); 15 | NETVAR(m_iMaxClip1, "CBasePlayerWeaponVData", "m_iMaxClip1", int32_t); 16 | 17 | }; 18 | 19 | class weapon_cs_base_v_data : public base_player_weapon_v_data { 20 | public: 21 | NETVAR(m_bMeleeWeapon, "CWeaponCSBaseVData", "m_bMeleeWeapon", bool); 22 | NETVAR(m_flRange, "CWeaponCSBaseVData", "m_flRange", float); 23 | }; -------------------------------------------------------------------------------- /cheat/src/valve/se/animation_system.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace se { 4 | 5 | class hitbox { 6 | public: 7 | PAD(0x20) 8 | vec3 mins; 9 | vec3 maxs; 10 | const char* name; 11 | const char* surface_property; 12 | const char* bone_name; 13 | float shape_radius; 14 | uint32_t bone_name_hash; 15 | int32_t group_id; 16 | clr4 render_color; 17 | uint16_t hitBox_index; 18 | uint8_t shape_type; 19 | PAD(1) 20 | bool translation_only; 21 | bool visible; 22 | bool selected; 23 | PAD(2) 24 | }; 25 | 26 | static_assert(sizeof(hitbox) == 0x70); 27 | 28 | class hitbox_set { 29 | public: 30 | const char* name; 31 | uint32_t name_hash; 32 | PAD(0x4) 33 | util_vector hit_boxes; 34 | const char* source_filename; 35 | }; 36 | 37 | static_assert(sizeof(hitbox_set) == 0x30); 38 | 39 | } -------------------------------------------------------------------------------- /cheat/src/valve/se/client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../memory/memory.h" 4 | #include "../cs/entity.h" 5 | 6 | #define MAX_SPLITSCREEN_PLAYERS 1 7 | 8 | namespace se { 9 | 10 | enum buttons : uint32_t { 11 | in_attack = 1, 12 | in_jump = 2, 13 | in_duck = 4, 14 | in_attack2 = 2048, 15 | in_moveforward = 8, 16 | in_moveback = 16, 17 | in_moveleft = 512, 18 | in_moveright = 1024 19 | }; 20 | 21 | struct entity_list; 22 | 23 | struct client_dll { 24 | public: 25 | }; 26 | 27 | struct game_resource_service { 28 | entity_list* get_entity_list() { 29 | return address(this).offset(0x58).dereference(); 30 | } 31 | }; 32 | 33 | struct entity_list { 34 | template 35 | VIRTUAL_FUNCTION_SIG_ABSOLUTE(get_base_entity, ty*, dlls::client, "8B D3 E8 ? ? ? ? 48 8B F8 48 85 C0 74 76", 3, (this, index), int index) 36 | 37 | inline int32_t get_highest_entity_index() { 38 | int32_t max = -1; 39 | get_max_entities(&max); 40 | return max; 41 | } 42 | private: 43 | VIRTUAL_FUNCTION_SIG_ABSOLUTE(get_max_entities, int, dlls::client, "33 DB E8 ? ? ? ? 8B 08", 3, (this, max), int32_t* max) 44 | }; 45 | 46 | class pb_base { 47 | private: 48 | PAD(0x18) // 0x0 49 | }; 50 | 51 | class cmd_qangle : public pb_base { 52 | public: 53 | angle angles; // 0x18 54 | }; 55 | 56 | static_assert(sizeof(cmd_qangle) == 0x24); 57 | 58 | class cmd_vector : public pb_base { 59 | public: 60 | vec3 vector; // 0x18 61 | float w; // 0x24 62 | }; 63 | 64 | static_assert(sizeof(cmd_vector) == 0x28); 65 | 66 | class csgo_interpolation_info : public pb_base { 67 | public: 68 | float frac; // 0x18 69 | int src_tick; // 0x1C 70 | int dst_tick; // 0x20 71 | }; 72 | 73 | static_assert(sizeof(csgo_interpolation_info) == 0x24); 74 | 75 | class csgo_input_history_entry : public pb_base { 76 | public: 77 | cmd_qangle* view_angles; // 0x18 78 | cmd_vector* shoot_position; // 0x20 79 | cmd_vector* target_head_pos_check; // 0x28 80 | cmd_vector* target_abs_pos_check; // 0x30 81 | cmd_qangle* target_abs_ang_check; // 0x38 82 | csgo_interpolation_info* cl_interp; // 0x40 83 | csgo_interpolation_info* sv_interp0; // 0x48 84 | csgo_interpolation_info* sv_interp1; // 0x50 85 | csgo_interpolation_info* player_interp; // 0x58 86 | int render_tick_count; // 0x60 87 | float render_tick_fraction; // 0x64 88 | int player_tick_count; // 0x68 89 | float player_tick_fraction; // 0x6C 90 | int frame_number; // 0x70 91 | int target_ent_index; // 0x74 92 | }; 93 | 94 | static_assert(sizeof(csgo_input_history_entry) == 0x78); 95 | 96 | class sub_tick_container { 97 | public: 98 | std::int32_t tick_count; // 0x0 99 | PAD(0x4) // 0x4 100 | std::uint8_t* tick_pointer; // 0x8 101 | 102 | csgo_input_history_entry* get_history_entry(int32_t index) { 103 | if (index < this->tick_count) 104 | { 105 | csgo_input_history_entry** tick_list = reinterpret_cast(this->tick_pointer + 0x8); 106 | return tick_list[index]; 107 | } 108 | 109 | return nullptr; 110 | } 111 | }; 112 | 113 | static_assert(sizeof(sub_tick_container) == 0x10); 114 | 115 | class user_cmd_base { 116 | public: 117 | PAD(0x40) // 0x0 118 | cmd_qangle* view; // 0x40 119 | int command_number; // 0x48 120 | int tick_count; // 0x4C 121 | float forwardmove; // 0x50 122 | float leftmove; // 0x54 123 | float upmove; // 0x58 124 | 125 | // TODO: maybe more here 126 | }; 127 | 128 | struct in_button_state { 129 | PAD(sizeof(void*)) // 0x0 (vtable) 130 | uint64_t buttons1; // 0x8 131 | uint64_t buttons2; // 0x10 132 | uint64_t buttons3; // 0x18 133 | }; 134 | 135 | struct user_cmd { 136 | PAD(0x20) // 0x0 137 | sub_tick_container sub_tick_container; // 0x20 138 | user_cmd_base* base; // 0x30 139 | int attack3_start_history_index; // 0x38 (release attack1) 140 | int attack1_start_history_index; // 0x3C (press attack1) 141 | int attack2_start_history_index; // 0x40 (press attack2) 142 | PAD(0x4) // 0x44 143 | in_button_state button_state; // 0x48 144 | PAD(0x8) // 0x68 145 | }; 146 | 147 | static_assert(sizeof(user_cmd) == 0x70); 148 | 149 | struct subtick_move_step { 150 | uint64_t button; 151 | bool pressed; 152 | float when; 153 | }; 154 | 155 | static_assert(sizeof(subtick_move_step) == 0x10); 156 | 157 | // FIXME: bad name, idk how to call it 158 | struct move_input { 159 | float forwardmove; 160 | float leftmove; 161 | float upmove; 162 | }; 163 | 164 | struct per_user_input { 165 | user_cmd cmds[150]; // 0x0 166 | PAD(0x30) // 0x41A0 167 | int sequence_number; // 0x41D0 168 | PAD(0x4) // 0x41D4 169 | uint64_t button_state1; // 0x41D8 (is held in this tick) 170 | uint64_t button_state2; // 0x41E0 (has been pressed down in this tick) 171 | uint64_t button_state3; // 0x41E8 (has been released in this tick) 172 | uint64_t button_state4; // 0x41F0 (was held down in previous tick) 173 | PAD(0x80) // 0x41F8 174 | move_input move; // 0x4278 175 | angle viewangles; // 0x4284 176 | int16_t mousedx; // 0x4290 177 | PAD(0x2) // 0x4292 178 | int16_t mousedy; // 0x4294 179 | PAD(0x2) // 0x4296 180 | int subtick_count; // 0x4298 181 | subtick_move_step subticks[12]; // 0x429C 182 | }; 183 | 184 | static_assert(sizeof(per_user_input) == sizeof(user_cmd) * (150 + 4)); // 0x4360 185 | 186 | struct csgo_input { 187 | static csgo_input* get() noexcept { 188 | return *dlls::client.find(PATTERN("48 8B 0D ? ? ? ? 48 8B 01 FF 50 ? 8B DF")).absolute(3); 189 | } 190 | 191 | VIRTUAL_FUNCTION_SIG(set_cursor_pos, void, dlls::client, "44 89 44 24 18 89 54 24 10 48 83", (this, x, y), uint32_t x, uint32_t y) 192 | 193 | per_user_input* get_per_user_input(int split_screen_index) { 194 | if (split_screen_index >= MAX_SPLITSCREEN_PLAYERS) { 195 | return nullptr; 196 | } 197 | return &per_user[split_screen_index]; 198 | } 199 | 200 | user_cmd* get_user_cmd(int split_screen_index) { 201 | auto input = get_per_user_input(split_screen_index); 202 | if (!input) 203 | return nullptr; 204 | return &input->cmds[input->sequence_number % std::size(input->cmds)]; 205 | } 206 | private: 207 | PAD(0x10); // 0x0 208 | per_user_input per_user[MAX_SPLITSCREEN_PLAYERS]; // 0x10 209 | }; 210 | 211 | struct client_mode { 212 | static client_mode* get() noexcept { 213 | return dlls::client.find(PATTERN("48 8D 0D ? ? ? ? 48 69 C0 ? ? ? ? 48 03 C1 C3 CC CC")).absolute(3); 214 | } 215 | }; 216 | 217 | struct global_vars { 218 | public: 219 | float realtime; // 0x0 220 | std::int32_t frame_count; // 0x4 221 | PAD(0x8) // 0x8 222 | std::uint32_t max_clients; // 0x10 223 | float interval_per_tick; // 0x14 224 | PAD(0x14) // 0x18 225 | float curtime; // 0x2C 226 | float curtime2; // 0x30 227 | PAD(0xC) // 0x34 228 | std::int32_t tick_count; // 0x40 229 | float interval_per_tick2; // 0x44 230 | void* current_netchan; // 0x48 231 | PAD(0x130) // 0x50 232 | char* current_map; // 0x180 233 | char* current_mapname; // 0x188 234 | }; 235 | 236 | struct view_render { 237 | static view_render* get() noexcept { 238 | SIG(function_ptr, dlls::client, "E8 ? ? ? ? 44 8B CB 4C 8D 44 24") 239 | return function_ptr.absolute()(); 240 | } 241 | }; 242 | 243 | } -------------------------------------------------------------------------------- /cheat/src/valve/se/cvar.cpp: -------------------------------------------------------------------------------- 1 | #include "../../memory/memory.h" 2 | #include "../../memory/interfaces.h" 3 | #include "cvar.h" 4 | 5 | void se::static_convar::find() noexcept { 6 | std::scoped_lock lock(mtx); 7 | if (found) 8 | return; 9 | 10 | var = interfaces::cvar->find(name); 11 | ASSERT_MSG(var, std::vformat(XOR("Failed to find convar {}"), std::make_format_args(name))); 12 | 13 | LOG_INFO(XOR("Found convar {}"), name); 14 | found = true; 15 | } -------------------------------------------------------------------------------- /cheat/src/valve/se/cvar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../base/base.h" 3 | #include 4 | 5 | namespace se { 6 | 7 | // FIXME: https://cs2.poggu.me/reverse-engineering/ConVars 8 | class con_var { 9 | public: 10 | const char* name; // 0x0 11 | PAD(0x18); // 0x8 12 | const char* description; // 0x20 13 | uint32_t type; // 0x28 14 | uint32_t registered; // 0x2C 15 | uint32_t flags; // 0x30 16 | PAD(0xC); // 0x34 17 | uint64_t value; // 0x40 18 | uint64_t value_old; // 0x48 19 | 20 | template 21 | T GetValue() { 22 | return *reinterpret_cast(&value); 23 | } 24 | }; 25 | 26 | static_assert(sizeof(con_var) == 0x50); 27 | 28 | class cvar { 29 | public: 30 | PAD(0x40) 31 | utl_linked_list con_vars; 32 | 33 | void unlock_all() noexcept { 34 | int count = 0; 35 | for (int i = con_vars.first(); i != con_vars.invalid_index(); i = con_vars.next(i)) { 36 | auto var = con_vars.element(i); 37 | var->flags &= ~0x402; 38 | count++; 39 | } 40 | LOG_INFO(XOR("Unlocked {} cvars"), count); 41 | } 42 | 43 | con_var* find(const char* name) noexcept { 44 | for (int i = con_vars.first(); i != con_vars.invalid_index(); i = con_vars.next(i)) { 45 | auto var = con_vars.element(i); 46 | if (strcmp(var->name, name) == 0) 47 | return var; 48 | } 49 | return nullptr; 50 | } 51 | }; 52 | 53 | class static_convar { 54 | private: 55 | std::mutex mtx { }; 56 | bool found { }; 57 | con_var* var { }; 58 | const char* name { }; 59 | 60 | void find() noexcept; 61 | 62 | public: 63 | static_convar(const char* name) noexcept : name(name) { } 64 | 65 | inline con_var* get() noexcept { 66 | if (!found) 67 | find(); 68 | return var; 69 | } 70 | }; 71 | 72 | } 73 | 74 | #define CONVAR(name, type) \ 75 | static se::static_convar CONCAT(name, _static)(#name); \ 76 | type name = CONCAT(name, _static).get()->GetValue(); -------------------------------------------------------------------------------- /cheat/src/valve/se/engine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../memory/memory.h" 3 | #include "network_system.h" 4 | 5 | namespace se { 6 | 7 | struct engine_client { 8 | 9 | VIRTUAL_FUNCTION(is_in_game, bool, 30, (this)); 10 | VIRTUAL_FUNCTION(is_connected, bool, 31, (this)); 11 | VIRTUAL_FUNCTION(get_net_channel_info, net_channel_info*, 32, (this, split_screen_slot), int split_screen_slot); 12 | VIRTUAL_FUNCTION(get_screen_size, void, 48, (this, width, height), int* width, int* height); 13 | VIRTUAL_FUNCTION(get_level_name, const char*, 51, (this)); 14 | VIRTUAL_FUNCTION(get_level_name_short, const char*, 52, (this)); 15 | 16 | inline bool is_valid() noexcept { 17 | return is_in_game() && is_connected(); 18 | } 19 | }; 20 | 21 | } -------------------------------------------------------------------------------- /cheat/src/valve/se/inputsystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../memory/memory.h" 4 | 5 | namespace se { 6 | 7 | struct plat_window; 8 | 9 | struct input_context { 10 | const char* name; 11 | PAD(0x9C) 12 | bool enabled; 13 | }; 14 | 15 | struct input_stack_system { 16 | VIRTUAL_FUNCTION(set_mouse_capture, void, 16, (this, context, state), input_context* context, bool state); 17 | 18 | input_context* find_input_context(const char* name) { 19 | for (int i = 0; i < context_count; i++) { 20 | if (strcmp(contexts[i]->name, name) == 0) 21 | return contexts[i]; 22 | } 23 | return nullptr; 24 | } 25 | private: 26 | PAD(0x28) 27 | int context_count; 28 | input_context** contexts; 29 | }; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /cheat/src/valve/se/localize.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../memory/memory.h" 3 | 4 | namespace se { 5 | 6 | class localize { 7 | public: 8 | VIRTUAL_FUNCTION(find_safe, const char*, 17, (this, token), const char* token); 9 | }; 10 | 11 | } -------------------------------------------------------------------------------- /cheat/src/valve/se/network_system.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../memory/memory.h" 3 | 4 | namespace se { 5 | 6 | enum flow : int { 7 | FLOW_OUTGOING = 0, 8 | FLOW_INCOMING = 1, 9 | }; 10 | 11 | class net_channel_info { 12 | public: 13 | VIRTUAL_FUNCTION(get_latency, float, 10, (this, flow), flow flow); 14 | }; 15 | 16 | }; -------------------------------------------------------------------------------- /cheat/src/valve/se/schema.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../memory/memory.h" 4 | 5 | namespace se { 6 | 7 | struct type_scope; 8 | struct schema_class_info_data; 9 | struct schema_class_field_data; 10 | 11 | struct schema_system { 12 | VIRTUAL_FUNCTION(find_type_scope_for_module, type_scope*, 13, (this, module), const char* module) 13 | }; 14 | 15 | struct type_scope { 16 | VIRTUAL_FUNCTION(find_declared_class, schema_class_info_data*, 2, (this, name), const char* name) 17 | }; 18 | 19 | struct schema_class_info_data { 20 | short size() { 21 | return *address(this).offset(0x1C).cast(); 22 | } 23 | 24 | schema_class_field_data* get_field_data() { 25 | return *address(this).offset(0x28).cast(); 26 | } 27 | }; 28 | 29 | struct schema_class_field_data { 30 | const char* name; 31 | PAD(0x8); 32 | short offset; 33 | PAD(0xE); 34 | }; 35 | 36 | } -------------------------------------------------------------------------------- /cheat/src/valve/se/se.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../base/base.h" 4 | 5 | #include "client.h" 6 | #include "engine.h" 7 | #include "schema.h" 8 | #include "inputsystem.h" 9 | #include "util.h" 10 | #include "animation_system.h" 11 | #include "localize.h" 12 | #include "cvar.h" 13 | -------------------------------------------------------------------------------- /cheat/src/valve/se/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | void se::transform::to_matrix(mat3x4& matrix) const noexcept { 4 | matrix[0][0] = 1.0 - 2.0 * rot.y * rot.y - 2.0 * rot.z * rot.z; 5 | matrix[1][0] = 2.0 * rot.x * rot.y + 2.0 * rot.w * rot.z; 6 | matrix[2][0] = 2.0 * rot.x * rot.z - 2.0 * rot.w * rot.y; 7 | 8 | matrix[0][1] = 2.0f * rot.x * rot.y - 2.0f * rot.w * rot.z; 9 | matrix[1][1] = 1.0f - 2.0f * rot.x * rot.x - 2.0f * rot.z * rot.z; 10 | matrix[2][1] = 2.0f * rot.y * rot.z + 2.0f * rot.w * rot.x; 11 | 12 | matrix[0][2] = 2.0f * rot.x * rot.z + 2.0f * rot.w * rot.y; 13 | matrix[1][2] = 2.0f * rot.y * rot.z - 2.0f * rot.w * rot.x; 14 | matrix[2][2] = 1.0f - 2.0f * rot.x * rot.x - 2.0f * rot.y * rot.y; 15 | 16 | matrix[0][3] = pos.x; 17 | matrix[1][3] = pos.y; 18 | matrix[2][3] = pos.z; 19 | } -------------------------------------------------------------------------------- /cheat/src/valve/se/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../base/base.h" 4 | #include "../../base/debug.h" 5 | 6 | namespace se { 7 | 8 | struct resource_binding { 9 | void* data; 10 | // uint32_t last_bind_frame; 11 | // uint32_t flags; 12 | // interlocked_int ref_count; 13 | }; 14 | 15 | template 16 | class strong_handle { 17 | public: 18 | operator T*() noexcept { 19 | if (!binding) 20 | return nullptr; 21 | return (T*)binding->data; 22 | } 23 | T* operator->() noexcept { 24 | if (!binding) 25 | return nullptr; 26 | return (T*)binding->data; 27 | } 28 | private: 29 | const resource_binding *binding; 30 | }; 31 | 32 | class alignas(16) transform { 33 | public: 34 | alignas(16) vec3 pos; 35 | alignas(16) quaternion rot; 36 | 37 | void to_matrix(mat3x4& matrix) const noexcept; 38 | }; 39 | 40 | template 41 | class utl_memory { 42 | public: 43 | T* memory; 44 | int allocation_count; 45 | int grow_size; 46 | 47 | T& operator[](int i) noexcept { return memory[i]; } 48 | const T& operator[](int i) const noexcept { return memory[i]; } 49 | }; 50 | 51 | class util_string { 52 | public: 53 | const char* get() const noexcept { 54 | return (const char*)memory.memory; 55 | } 56 | 57 | operator const char *() const noexcept { return get(); } 58 | 59 | utl_memory memory; 60 | int actual_length; 61 | }; 62 | 63 | static_assert(sizeof(util_string) == 0x18); 64 | 65 | template 66 | class util_vector { 67 | public: 68 | int size; 69 | utl_memory data; 70 | 71 | T& operator[](int i) noexcept { return data.memory[i]; } 72 | const T& operator[](int i) const noexcept { return data.memory[i]; } 73 | }; 74 | 75 | static_assert(sizeof(util_vector) == 0x18); 76 | 77 | #define INVALID_LLIST_IDX ((I)~0) 78 | 79 | template 80 | class utl_linked_list { 81 | public: 82 | inline I first() const noexcept { return head; } 83 | inline I previous( I i ) const noexcept { return memory[i].previous; } 84 | inline I next( I i ) const noexcept { return memory[i].next; } 85 | inline T& element( I i ) noexcept { return memory[i].element; } 86 | inline const T& element( I i ) const noexcept { return memory[i].element; } 87 | inline static I invalid_index() noexcept { return INVALID_LLIST_IDX; } 88 | 89 | struct alignas(8) list_elem { 90 | T element; 91 | I previous; 92 | I next; 93 | }; 94 | 95 | utl_memory memory; 96 | I head; 97 | I tail; 98 | I first_free; 99 | I element_count; 100 | I total_elements; 101 | list_elem* elements; 102 | }; 103 | 104 | struct game_tick { 105 | int32_t m_Value; 106 | }; 107 | 108 | } -------------------------------------------------------------------------------- /cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2", 3 | "ignorePaths": [ 4 | "injector/src" 5 | ], 6 | "dictionaryDefinitions": [], 7 | "dictionaries": [], 8 | "words": [ 9 | "aimtarget", 10 | "atcontrols", 11 | "basevelocity", 12 | "BONEFLEXDRIVER", 13 | "buttonstate", 14 | "CONOUT", 15 | "cvars", 16 | "donttouch", 17 | "fakeclient", 18 | "FLYGRAVITY", 19 | "forwardmove", 20 | "gameoverlayrenderer", 21 | "godmode", 22 | "hitchance", 23 | "inrain", 24 | "inwater", 25 | "killme", 26 | "knifebot", 27 | "leftmove", 28 | "legitbot", 29 | "Maxs", 30 | "maxunlag", 31 | "mousedx", 32 | "mousedy", 33 | "moveback", 34 | "moveforward", 35 | "moveright", 36 | "MOVETYPE", 37 | "NOCLIP", 38 | "notarget", 39 | "onfire", 40 | "onground", 41 | "ontrain", 42 | "partialground", 43 | "PREALIGNED", 44 | "rendersystemdx", 45 | "RESPAWNABLE", 46 | "RESPAWNING", 47 | "RIGIDLENGTH", 48 | "scrs", 49 | "sidemove", 50 | "staticprop", 51 | "stepmovement", 52 | "subtick", 53 | "subticks", 54 | "transragdoll", 55 | "triggerbot", 56 | "unblockable", 57 | "updaterate", 58 | "upmove", 59 | "veorq", 60 | "waterjump", 61 | "worldbrush", 62 | "xored", 63 | "XORSTR", 64 | "zeusbot" 65 | ], 66 | "ignoreWords": [], 67 | "import": [] 68 | } 69 | -------------------------------------------------------------------------------- /injector/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(PerfectInjector "src/PerfectInjector.cpp") 2 | 3 | target_compile_features(PerfectInjector PUBLIC c_std_17 cxx_std_20) 4 | set_target_properties(PerfectInjector PROPERTIES LINK_FLAGS "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"") 5 | 6 | if (VCPKG_TARGET_TRIPLET MATCHES "x64-windows-static") 7 | set_property(TARGET PerfectInjector PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") 8 | endif () 9 | 10 | add_custom_command( 11 | TARGET PerfectInjector POST_BUILD 12 | COMMAND ${CMAKE_COMMAND} -E echo "@cd /D \"%~dp0\"" > run.bat 13 | COMMAND ${CMAKE_COMMAND} -E echo "@start $ cs2.exe $ waitkey" >> run.bat 14 | WORKING_DIRECTORY $ 15 | VERBATIM 16 | ) -------------------------------------------------------------------------------- /injector/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Can Bölük 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /injector/src/CapcomLoader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "CapcomResource.h" 7 | #include "DriverLoader.h" 8 | #include "LockedMemory.h" 9 | 10 | #define IOCTL_RunPayload64 0xAA013044 11 | 12 | #pragma pack(push, 1) 13 | struct CapcomContext 14 | { 15 | using FnCapcomCb = void( __stdcall*)( PVOID ); 16 | using FnCapcomCbNoCtx = void(__stdcall*)(); 17 | 18 | uint64_t BufferPointer; 19 | uint8_t MovabsRaxData[ 0x2 ] = { 0x48, 0xB8 }; // mov rax, data 20 | uint64_t DataSource; // - 21 | uint8_t MovRdxRax[ 0x3 ] = { 0x48, 0x89, 0xC1 }; // mov rcx, rax 22 | uint8_t MovabsRax[ 0x2 ] = { 0x48, 0xB8 }; // mov rax, destination 23 | uint64_t Destination; // - 24 | uint8_t JmpRax[ 0x2 ] = { 0xFF, 0xE0 }; // jmp rax 25 | 26 | HANDLE CapcomDevice; 27 | std::wstring CapcomDriverName; 28 | 29 | CapcomContext( std::wstring DriverName, HANDLE Device ) 30 | { 31 | this->CapcomDriverName = DriverName; 32 | this->CapcomDevice = Device; 33 | } 34 | 35 | void ExecuteInKernel( FnCapcomCb Destination, PVOID Ctx = 0 ) 36 | { 37 | this->Destination = ( uint64_t ) Destination; 38 | 39 | // STOP OPTIMIZING MY FUCKING VARIABLES AWAY DUMB CUNT 40 | if ( __rdtsc() == 0 ) 41 | Destination( 0 ); 42 | 43 | DWORD Status = 0x0; 44 | DWORD BytesReturned = 0x0; 45 | this->DataSource = ( uint64_t ) Ctx; 46 | this->BufferPointer = ( uint64_t ) ( &this->BufferPointer + 1 ); 47 | 48 | DeviceIoControl 49 | ( 50 | CapcomDevice, 51 | IOCTL_RunPayload64, 52 | &this->BufferPointer, 53 | sizeof( uint64_t ), 54 | &Status, 55 | sizeof( Status ), 56 | &BytesReturned, 57 | 0 58 | ); 59 | } 60 | 61 | void ExecuteInKernel( FnCapcomCbNoCtx Fn, PVOID Ctx = 0 ) 62 | { 63 | this->ExecuteInKernel( ( FnCapcomCb )( Fn ), Ctx ); 64 | } 65 | }; 66 | #pragma pack(pop) 67 | 68 | static void Cl_AssertDecrypted() 69 | { 70 | if ( CAPCOM_DRIVER[ 0 ] != 0x4D ) 71 | { 72 | for ( BYTE& b : CAPCOM_DRIVER ) 73 | b ^= CAPCOM_DRIVER_XOR_KEY; 74 | } 75 | } 76 | 77 | static std::wstring Cl_GetDriverPath() 78 | { 79 | wchar_t SystemDirectory[ 2048 ]; 80 | GetSystemDirectoryW( SystemDirectory, 2048 ); 81 | 82 | std::wstring DriverPath = SystemDirectory; 83 | DriverPath += L"\\drivers\\"; 84 | 85 | return DriverPath; 86 | } 87 | 88 | static NTSTATUS Cl_RemoveSimilarDrivers( BYTE* Driver ) 89 | { 90 | namespace fs = std::filesystem; 91 | 92 | std::wstring DriverPath = Cl_GetDriverPath(); 93 | 94 | NTSTATUS Status = STATUS_SUCCESS; 95 | 96 | for ( auto& File : fs::directory_iterator( DriverPath ) ) 97 | { 98 | std::wstring Path = File.path(); 99 | if ( Path.find( L".sys" ) != -1 ) 100 | { 101 | std::ifstream FileStr( File.path(), std::ios::binary ); 102 | char Data[ 1024 ]; 103 | FileStr.read( Data, 1024 ); 104 | FileStr.close(); 105 | 106 | if ( !memcmp( Driver, Data, 1024 ) ) 107 | { 108 | bool Deleted = DeleteFileW( Path.c_str() ); 109 | 110 | printf( "[+] DeleteFile (%ls) : %x\n", Path.c_str(), Deleted ); 111 | 112 | if ( !Deleted ) 113 | { 114 | size_t StrEnd = Path.find( L".sys" ); 115 | size_t StrStart = Path.rfind( L"\\", StrEnd ); 116 | std::wstring DriverName = Path.substr( StrStart + 1, StrEnd - StrStart - 1 ).c_str(); 117 | Dl_UnloadDriver( DriverName.c_str() ); 118 | 119 | Deleted = DeleteFileW( Path.c_str() ); 120 | printf( "[+] DeleteFile2 (%ls) : %x\n", Path.c_str(), Deleted ); 121 | } 122 | 123 | Status |= !Deleted; 124 | } 125 | } 126 | } 127 | 128 | return Status; 129 | } 130 | 131 | static BOOL Cl_FreeContext( CapcomContext* Ctx ) 132 | { 133 | Cl_AssertDecrypted(); 134 | CloseHandle( Ctx->CapcomDevice ); 135 | if ( Dl_UnloadDriver( Ctx->CapcomDriverName.c_str() ) ) 136 | return FALSE; 137 | if ( Cl_RemoveSimilarDrivers( CAPCOM_DRIVER ) ) 138 | return FALSE; 139 | VirtualFree( Ctx, 0, MEM_FREE ); 140 | return TRUE; 141 | } 142 | 143 | static CapcomContext* Cl_InitContext() 144 | { 145 | Cl_AssertDecrypted(); 146 | 147 | CapcomContext* AllocatedContext = ( CapcomContext* ) ( VirtualAlloc( 0, sizeof( CapcomContext ), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ) ); 148 | 149 | std::wstring CapcomDriverName = L""; 150 | 151 | srand( (DWORD)__rdtsc() ); 152 | 153 | for ( int i = 0; i < 12; i++ ) 154 | CapcomDriverName += wchar_t( L'A' + rand() % 20 ); 155 | 156 | std::wstring DriverPath = Cl_GetDriverPath() + CapcomDriverName + L".sys"; 157 | 158 | if ( Cl_RemoveSimilarDrivers( CAPCOM_DRIVER ) ) 159 | { 160 | printf( "[+] Failed to remove similar drivers!\n" ); 161 | VirtualFree( AllocatedContext, 0, MEM_FREE ); 162 | return 0; 163 | } 164 | 165 | std::ofstream file( DriverPath, std::ios::binary ); 166 | 167 | if ( !file.good() ) 168 | { 169 | printf( "[+] Failed to create file!\n" ); 170 | VirtualFree( AllocatedContext, 0, MEM_FREE ); 171 | return 0; 172 | } 173 | 174 | file.write( ( char* ) CAPCOM_DRIVER, sizeof( CAPCOM_DRIVER ) ); 175 | file.close(); 176 | 177 | if ( Dl_LoadDriver( CapcomDriverName.c_str() ) ) 178 | { 179 | printf( "[+] Failed to load driver!\n" ); 180 | while ( 1 ); 181 | Cl_RemoveSimilarDrivers( CAPCOM_DRIVER ); 182 | VirtualFree( AllocatedContext, 0, MEM_FREE ); 183 | return 0; 184 | } 185 | 186 | HANDLE Device = Dl_OpenDevice( "Htsysm72FB" ); 187 | 188 | if ( !Device ) 189 | { 190 | printf( "[+] Failed to open device!\n" ); 191 | Dl_UnloadDriver( CapcomDriverName.c_str() ); 192 | Cl_RemoveSimilarDrivers( CAPCOM_DRIVER ); 193 | VirtualFree( AllocatedContext, 0, MEM_FREE ); 194 | return 0; 195 | } 196 | 197 | new ( AllocatedContext ) CapcomContext( CapcomDriverName, Device ); 198 | return AllocatedContext; 199 | } 200 | -------------------------------------------------------------------------------- /injector/src/DriverLoader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "NtDefines.h" 7 | #pragma comment(lib, "Shlwapi.lib") 8 | 9 | static NTSTATUS Dl_RemoveDriverFromRegistry( const wchar_t* DriverName ) 10 | { 11 | NTSTATUS Status = STATUS_SUCCESS; 12 | 13 | std::wstring RegistryPath = std::wstring( L"System\\CurrentControlSet\\Services\\" ) + DriverName; 14 | 15 | Status = RegDeleteKeyW( HKEY_LOCAL_MACHINE, 16 | RegistryPath.c_str() ); 17 | if ( !Status || Status == ERROR_FILE_NOT_FOUND ) 18 | return STATUS_SUCCESS; 19 | 20 | Status = SHDeleteKeyW( HKEY_LOCAL_MACHINE, 21 | RegistryPath.c_str() ); 22 | if ( !Status || Status == ERROR_FILE_NOT_FOUND ) 23 | return STATUS_SUCCESS; 24 | 25 | Status = RegDeleteKeyW( HKEY_LOCAL_MACHINE, 26 | RegistryPath.c_str() ); 27 | if ( !Status || Status == ERROR_FILE_NOT_FOUND ) 28 | return STATUS_SUCCESS; 29 | 30 | return Status; 31 | } 32 | 33 | static NTSTATUS Dl_TryOpenServiceKey( const wchar_t* DriverName ) 34 | { 35 | std::wstring RegistryPath = std::wstring( L"System\\CurrentControlSet\\Services\\" ) + DriverName; 36 | HKEY Key; 37 | NTSTATUS Result = RegOpenKeyExW( HKEY_LOCAL_MACHINE, 38 | RegistryPath.c_str(), 39 | 0, 40 | KEY_ALL_ACCESS, 41 | &Key ); 42 | RegCloseKey( Key ); 43 | return Result; 44 | } 45 | 46 | static NTSTATUS Dl_AddServiceToRegistery( const wchar_t* DriverName ) 47 | { 48 | NTSTATUS Status = STATUS_SUCCESS; 49 | 50 | std::wstring RegistryPath = std::wstring( L"System\\CurrentControlSet\\Services\\" ) + DriverName; 51 | 52 | Dl_RemoveDriverFromRegistry( DriverName ); 53 | 54 | HKEY Key; 55 | Status = RegCreateKeyExW( HKEY_LOCAL_MACHINE, 56 | RegistryPath.c_str(), 57 | 0, 58 | NULL, 59 | 0, 60 | KEY_ALL_ACCESS, 61 | NULL, 62 | &Key, 63 | 0 ); 64 | 65 | if ( Status ) 66 | return Status; 67 | 68 | const auto RegWriteString = [ = ] ( const wchar_t* Name, const std::wstring& Data ) -> NTSTATUS 69 | { 70 | return RegSetValueExW( Key, 71 | Name, 72 | 0, 73 | REG_EXPAND_SZ, 74 | ( PBYTE ) Data.c_str(), 75 | (DWORD)Data.size() * sizeof( wchar_t ) ); 76 | }; 77 | const auto RegWriteDWORD = [ = ] ( const wchar_t* Name, DWORD Data ) -> NTSTATUS 78 | { 79 | return RegSetValueExW( Key, 80 | Name, 81 | 0, 82 | REG_DWORD, 83 | ( PBYTE ) &Data, 84 | sizeof( DWORD ) ); 85 | }; 86 | 87 | Status |= RegWriteString( L"ImagePath", std::wstring( L"\\SystemRoot\\System32\\drivers\\" ) + DriverName + L".sys" ); 88 | Status |= RegWriteDWORD( L"Type", 1 ); 89 | Status |= RegWriteDWORD( L"ErrorControl", 1 ); 90 | Status |= RegWriteDWORD( L"Start", 3 ); 91 | 92 | if ( Status ) 93 | { 94 | RegCloseKey( Key ); 95 | Dl_RemoveDriverFromRegistry( DriverName ); 96 | return Status; 97 | } 98 | 99 | 100 | RegCloseKey( Key ); 101 | return STATUS_SUCCESS; 102 | } 103 | 104 | static NTSTATUS Dl_UnloadDriver( const wchar_t* DriverName ) 105 | { 106 | if ( !AcquirePrivilege( SeLoadDriverPrivilege, AdjustCurrentProcess ) ) 107 | return 1; 108 | 109 | if ( Dl_TryOpenServiceKey( DriverName ) == 2 ) 110 | Dl_AddServiceToRegistery( DriverName ); 111 | std::wstring SourceRegistry = std::wstring( L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\" ) + DriverName; 112 | 113 | UNICODE_STRING SourceRegistryUnicode = { 0 }; 114 | SourceRegistryUnicode.Buffer = ( wchar_t* ) SourceRegistry.c_str(); 115 | SourceRegistryUnicode.Length = (USHORT)( SourceRegistry.size() ) * 2; 116 | SourceRegistryUnicode.MaximumLength = (USHORT)( SourceRegistry.size() + 1 ) * 2; 117 | 118 | NTSTATUS Status = NtUnloadDriver( &SourceRegistryUnicode ); 119 | 120 | printf( "[+] NtUnloadDriver(%ls) returned %08x\n", SourceRegistry.c_str(), Status ); 121 | 122 | Dl_RemoveDriverFromRegistry( DriverName ); 123 | 124 | return Status; 125 | } 126 | 127 | 128 | static NTSTATUS Dl_LoadDriver( const wchar_t* DriverName ) 129 | { 130 | if ( !AcquirePrivilege( SeLoadDriverPrivilege, AdjustCurrentProcess ) ) 131 | return 1; 132 | 133 | if ( Dl_AddServiceToRegistery( DriverName ) ) 134 | return 2; 135 | 136 | std::wstring SourceRegistry = std::wstring( L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\" ) + DriverName; 137 | 138 | UNICODE_STRING SourceRegistryUnicode = { 0 }; 139 | SourceRegistryUnicode.Buffer = ( wchar_t* ) SourceRegistry.c_str(); 140 | SourceRegistryUnicode.Length = (USHORT)( SourceRegistry.size() ) * 2; 141 | SourceRegistryUnicode.MaximumLength = (USHORT)( SourceRegistry.size() + 1 ) * 2; 142 | 143 | NTSTATUS Status = NtLoadDriver( &SourceRegistryUnicode ); 144 | 145 | printf( "[+] NtLoadDriver(%ls) returned %08x\n", SourceRegistry.c_str(), Status ); 146 | 147 | if ( Status ) 148 | { 149 | Dl_UnloadDriver( DriverName ); 150 | Dl_RemoveDriverFromRegistry( DriverName ); 151 | } 152 | 153 | return Status; 154 | } 155 | 156 | static HANDLE Dl_OpenDevice( std::string DriverName ) 157 | { 158 | char CompleteDeviceName[ 128 ]; 159 | sprintf_s( CompleteDeviceName, "\\\\.\\%s", DriverName.data() ); 160 | 161 | HANDLE DeviceHandle = CreateFileA 162 | ( 163 | CompleteDeviceName, 164 | GENERIC_READ | GENERIC_WRITE, 165 | FILE_SHARE_READ | FILE_SHARE_WRITE, 166 | NULL, 167 | OPEN_EXISTING, 168 | FILE_ATTRIBUTE_NORMAL, 169 | NULL 170 | ); 171 | 172 | if ( DeviceHandle == INVALID_HANDLE_VALUE ) 173 | DeviceHandle = 0; 174 | 175 | printf( "[+] CreateFileA(%s) returned %08llx\n", CompleteDeviceName, (uintptr_t)DeviceHandle ); 176 | 177 | return DeviceHandle; 178 | } -------------------------------------------------------------------------------- /injector/src/Error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #undef ERROR 6 | #define ERROR( msg ) \ 7 | {SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 12 ); \ 8 | printf( "\n[[[[[[ " msg " ]]]]]]\n\n" ); \ 9 | system( "pause" ); \ 10 | exit( 0 );} 11 | 12 | 13 | #define assert( cond ) if( !(cond) ) ERROR( "Assert Failed: " #cond ) -------------------------------------------------------------------------------- /injector/src/KernelHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "KernelRoutines.h" 5 | #include "LockedMemory.h" 6 | #include "CapcomLoader.h" 7 | 8 | // Not thread safe! 9 | using fnPassiveCall = uint64_t( *)( ... ); 10 | 11 | NON_PAGED_DATA static fnFreeCall Khk_ExAllocatePool = 0; 12 | NON_PAGED_DATA static fnPassiveCall Khk_PassiveCallStub = 0; 13 | 14 | static const uint32_t Kh_PassiveCallStubCallStoreOffset = 0x34; 15 | static const uint32_t Kh_PassiveCallStubSmepEnabledOffset = 0xB; 16 | 17 | NON_PAGED_DATA static UCHAR Kh_PassiveCallStubData[] = 18 | { 19 | 0x0F, 0x20, 0xE0, // mov rax,cr4 ; - 20 | 0x48, 0x0F, 0xBA, 0xE8, 0x14, // bts rax,0x14 ; | will be nop'd if no SMEP support 21 | 0x0F, 0x22, 0xE0, // mov cr4,rax ; - 22 | 0xFB, // sti 23 | 0x48, 0x8D, 0x05, 0x07, 0x00, 0x00, 0x00, // lea rax,[rip+0x7] ; continue 24 | 0x8F, 0x40, 0x12, // pop QWORD PTR [rax+0x12] ; ret_store 25 | 0x50, // push rax 26 | 0xFF, 0x60, 0x1A, // jmp QWORD PTR [rax+0x1a] ; call_store 27 | 0xFA, // cli 28 | 0x0F, 0x20, 0xE1, // mov rcx,cr4 29 | 0x48, 0x0F, 0xBA, 0xF1, 0x14, // btr rcx,0x14 30 | 0x0F, 0x22, 0xE1, // mov cr4,rcx 31 | 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp QWORD PTR [rip+0x0] ; ret_store 32 | 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ret_store: dq 0 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // call_store: dq 0 35 | }; 36 | 37 | 38 | // This function is the only _TRICKY_ part of this project. 39 | // ExAllocatePool does not require interrupts to be enabled WHEN the size is small and we are depending on that. 40 | NON_PAGED_CODE static void Khk_AllocatePassiveStub() 41 | { 42 | PVOID Out = ( PVOID ) Khk_ExAllocatePool( 0ull, sizeof( Kh_PassiveCallStubData ) ); 43 | Np_memcpy( Out, Kh_PassiveCallStubData, sizeof( Kh_PassiveCallStubData ) ); 44 | Khk_PassiveCallStub = ( fnPassiveCall ) Out; 45 | } 46 | 47 | template 48 | NON_PAGED_CODE static uint64_t Khk_CallPassive( PVOID Ptr, Params &&... params ) 49 | { 50 | *( PVOID* ) ( ( ( PUCHAR ) Khk_PassiveCallStub ) + Kh_PassiveCallStubCallStoreOffset ) = Ptr; 51 | return Khk_PassiveCallStub( std::forward( params ) ... ); 52 | } 53 | 54 | static void Khu_Init( CapcomContext* CpCtx, KernelContext* KrCtx ) 55 | { 56 | if ( Khk_PassiveCallStub ) 57 | return; 58 | 59 | int CpuInfo[ 4 ]; 60 | __cpuid( CpuInfo, 0x7 ); 61 | 62 | if ( !( CpuInfo[ 1 ] & ( 1 << 7 ) ) ) // EBX : 1 << 7 = SMEP 63 | { 64 | printf( "[+] No SMEP support!\n" ); 65 | memset( Kh_PassiveCallStubData, 0x90, Kh_PassiveCallStubSmepEnabledOffset ); 66 | } 67 | 68 | Khk_ExAllocatePool = KrCtx->GetProcAddress( "ExAllocatePool" ); 69 | CpCtx->ExecuteInKernel( Khk_AllocatePassiveStub ); 70 | } -------------------------------------------------------------------------------- /injector/src/KernelRoutines.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "NtDefines.h" 7 | 8 | struct KernelContext 9 | { 10 | HMODULE NtLib; 11 | uint64_t NtBase; 12 | 13 | template 14 | T GetProcAddress( const char* Proc ) 15 | { 16 | FARPROC LocProc = ::GetProcAddress( this->NtLib, Proc ); 17 | 18 | if ( !LocProc ) 19 | return ( T ) ( nullptr ); 20 | 21 | uintptr_t Delta = ( uintptr_t ) ( LocProc ) - ( uintptr_t ) ( this->NtLib ); 22 | 23 | return ( T ) ( this->NtBase + Delta ); 24 | } 25 | }; 26 | 27 | static KernelContext* Kr_InitContext() 28 | { 29 | KernelContext* Kc = new KernelContext; 30 | 31 | std::vector Buffer( 1024 * 1024 ); 32 | 33 | ULONG ReqSize = 0; 34 | 35 | do 36 | { 37 | if ( !NtQuerySystemInformation( SystemModuleInformation, Buffer.data(), Buffer.size(), &ReqSize ) ) 38 | break; 39 | 40 | Buffer.resize( ReqSize * 2 ); 41 | } 42 | while ( ReqSize > Buffer.size() ); 43 | 44 | SYSTEM_MODULE_INFORMATION* ModuleInfo = ( SYSTEM_MODULE_INFORMATION* ) Buffer.data(); 45 | 46 | char* KernelFileName = ( char* ) ModuleInfo->Module[ 0 ].FullPathName + ModuleInfo->Module[ 0 ].OffsetToFileName; 47 | 48 | Kc->NtBase = (uint64_t) ModuleInfo->Module[ 0 ].ImageBase; 49 | Kc->NtLib = LoadLibraryA( KernelFileName ); 50 | 51 | if ( !Kc->NtBase || !Kc->NtLib ) 52 | { 53 | delete Kc; 54 | printf( "[+] Failed to get kernel module information!\n" ); 55 | return 0; 56 | } 57 | 58 | printf( "[+] Kernel: %s @ %16llx\n", KernelFileName, Kc->NtBase ); 59 | 60 | return Kc; 61 | } 62 | 63 | static void Kr_FreeContext( KernelContext* Ctx ) 64 | { 65 | delete Ctx; 66 | } -------------------------------------------------------------------------------- /injector/src/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Can Bölük 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /injector/src/LockedMemory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "NtDefines.h" 5 | 6 | #pragma section(".LDATA", read, write) 7 | #pragma section(".LTEXT", read, execute) 8 | 9 | #pragma data_seg(".LDATA$1") 10 | #pragma data_seg(".LDATA$2") 11 | #pragma data_seg(".LDATA$3") 12 | #pragma data_seg() 13 | 14 | #pragma code_seg(".LTEXT$1") 15 | #pragma code_seg(".LTEXT$2") 16 | #pragma code_seg(".LTEXT$3") 17 | #pragma code_seg() 18 | 19 | __declspec( allocate( ".LDATA$1" ) ) static char Np_DataStart = 0x0; 20 | __declspec( allocate( ".LDATA$3" ) ) static char Np_DataEnd = 0x0; 21 | 22 | __declspec( allocate( ".LTEXT$1" ) ) static char Np_TextStart = 0x0; 23 | __declspec( allocate( ".LTEXT$3" ) ) static char Np_TextEnd = 0x0; 24 | 25 | 26 | #define NON_PAGED_DATA __declspec( allocate( ".LDATA$2" ) ) 27 | #define NON_PAGED_CODE __declspec( code_seg( ".LTEXT$2" ) ) __declspec(noinline) 28 | #define NON_PAGED_LAMBDA(...) []( __VA_ARGS__ ) NON_PAGED_CODE 29 | 30 | // Mini non-paged crt 31 | #define Np_memcpy(dst, src, size) __movsb( ( BYTE* ) dst, ( const BYTE* ) src, size ) 32 | #define Np_memset(dst, val, size) __stosb( ( BYTE* ) dst, val, size) 33 | #define Np_ZeroMemory(dst, size) __stosb( ( BYTE* ) dst, 0, size) 34 | 35 | #pragma comment(linker,"/MERGE:.LDATA=.data") 36 | #pragma comment(linker,"/MERGE:.LTEXT=.text") 37 | 38 | // Routines to lock the pages 39 | static BOOL Np_TryIncreaseWorkingSetSize( SIZE_T Size ) 40 | { 41 | SIZE_T Min, Max; 42 | if ( !GetProcessWorkingSetSize( NtCurrentProcess(), &Min, &Max ) ) 43 | return FALSE; 44 | if ( !SetProcessWorkingSetSize( NtCurrentProcess(), Min + Size, Max + Size ) ) 45 | return FALSE; 46 | printf( "[+] Increasing working set (%llu KB, %llu KB) -> (%llu KB, %llu KB)!\n", Min / 1024u, Max / 1024u, ( Min + Size ) / 1024u, ( Max + Size ) / 1024u ); 47 | return TRUE; 48 | } 49 | 50 | static BOOL Np_TryLockPage( PVOID Page ) 51 | { 52 | if ( !Np_TryIncreaseWorkingSetSize( 0x1000 ) ) 53 | return FALSE; 54 | if ( VirtualLock( Page, 0x1000 ) ) 55 | return TRUE; 56 | if ( !Np_TryIncreaseWorkingSetSize( 0x2000 ) ) 57 | return FALSE; 58 | return VirtualLock( Page, 0x1000 ); 59 | } 60 | 61 | static BOOL Np_LockRange( PVOID From, PVOID To ) 62 | { 63 | PBYTE FromPageAligned = ( PBYTE ) ( ( uintptr_t ) ( From ) & ( ~0xFFF ) ); 64 | PBYTE ToPageAligned = ( PBYTE ) ( ( uintptr_t ) ( To ) & ( ~0xFFF ) ); 65 | 66 | for ( PBYTE Current = FromPageAligned; Current <= ToPageAligned; Current += 0x1000 ) 67 | { 68 | if ( !Np_TryLockPage( Current ) ) 69 | { 70 | printf( "[+] Failed locking %16llx!\n", (uintptr_t)Current ); 71 | return FALSE; 72 | } 73 | else 74 | { 75 | printf( "[+] Locked %16llx successfully!\n", (uintptr_t)From ); 76 | } 77 | } 78 | return TRUE; 79 | } 80 | 81 | static BOOL Np_LockSections() 82 | { 83 | printf( "[+] .LDATA: %16llx -> %16llx!\n", (uintptr_t)&Np_DataStart, (uintptr_t)&Np_DataEnd ); 84 | printf( "[+] .LTEXT: %16llx -> %16llx!\n", (uintptr_t)&Np_TextStart, (uintptr_t)&Np_TextEnd ); 85 | 86 | return 87 | Np_LockRange( &Np_DataStart, &Np_DataEnd ) && 88 | Np_LockRange( &Np_TextStart, &Np_TextEnd ); 89 | } -------------------------------------------------------------------------------- /injector/src/NtDefines.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #pragma pack(push, 8) 4 | typedef struct _SYSTEM_MODULE_ENTRY 5 | { 6 | HANDLE Section; 7 | PVOID MappedBase; 8 | PVOID ImageBase; 9 | ULONG ImageSize; 10 | ULONG Flags; 11 | USHORT LoadOrderIndex; 12 | USHORT InitOrderIndex; 13 | USHORT LoadCount; 14 | USHORT OffsetToFileName; 15 | UCHAR FullPathName[ 256 ]; 16 | } SYSTEM_MODULE_ENTRY, *PSYSTEM_MODULE_ENTRY; 17 | 18 | #pragma warning(disable : 4200) 19 | typedef struct _SYSTEM_MODULE_INFORMATION 20 | { 21 | ULONG Count; 22 | SYSTEM_MODULE_ENTRY Module[ 0 ]; 23 | } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; 24 | 25 | typedef struct _UNICODE_STRING 26 | { 27 | USHORT Length; 28 | USHORT MaximumLength; 29 | PWSTR Buffer; 30 | } UNICODE_STRING; 31 | 32 | typedef UNICODE_STRING *PUNICODE_STRING; 33 | 34 | #define NtCurrentProcess() ( HANDLE(-1) ) 35 | #define SeLoadDriverPrivilege 10ull 36 | #define SystemModuleInformation 0xBull 37 | #define AdjustCurrentProcess 0ull 38 | #define STATUS_SUCCESS 0 39 | #pragma pack(pop) 40 | 41 | using fnFreeCall = uint64_t( __fastcall* )( ... ); 42 | 43 | template 44 | static NTSTATUS __NtRoutine( const char* Name, Params &&... params ) 45 | { 46 | auto fn = ( fnFreeCall ) GetProcAddress( GetModuleHandleA( "ntdll.dll" ), Name ); 47 | return (NTSTATUS)fn( std::forward( params ) ... ); 48 | } 49 | 50 | #define NtQuerySystemInformation(...) __NtRoutine("NtQuerySystemInformation", __VA_ARGS__) 51 | #define RtlAdjustPrivilege(...) __NtRoutine("RtlAdjustPrivilege", __VA_ARGS__) 52 | #define NtUnloadDriver(...) __NtRoutine("NtUnloadDriver", __VA_ARGS__) 53 | #define NtLoadDriver(...) __NtRoutine("NtLoadDriver", __VA_ARGS__) 54 | 55 | static BOOL AcquirePrivilege( DWORD Privilage, DWORD Proc ) 56 | { 57 | BOOLEAN Enabled = 0; 58 | return !RtlAdjustPrivilege( Privilage, 1ull, Proc, &Enabled ) || Enabled; 59 | } -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", 3 | "name": "bakaware", 4 | "dependencies": [ 5 | "nlohmann-json", 6 | { 7 | "name": "imgui", 8 | "features": [ 9 | "dx11-binding", 10 | "win32-binding" 11 | ] 12 | } 13 | ] 14 | } --------------------------------------------------------------------------------