diff --git a/.editorconfig b/.editorconfig index 3039c81..677e36e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,6 +4,6 @@ root = true charset = utf-8 end_of_line = lf indent_size = 4 -indent_style = tab +indent_style = space insert_final_newline = true -trim_trailing_whitespace = true \ No newline at end of file +trim_trailing_whitespace = true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6177422 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +/**/CMakeLists.txt linguist-generated +/**/cmkr.cmake linguist-vendored diff --git a/.gitignore b/.gitignore index 5805a7e..fe2ab91 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ .idea/ .vs/ +CMakeLists.txt +CMakeSettings.json build/ cmake-build-debug/ cmake-build-release/ -CMakeSettings.json +cmake-build/ +cmkr.cmake out/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index b67b875..0000000 --- a/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule "vendor/nlohmann_json"] - path = vendor/nlohmann_json - url = https://github.com/nlohmann/json -[submodule "vendor/spdlog"] - path = vendor/spdlog - url = https://github.com/gabime/spdlog diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 5cdaf90..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -cmake_minimum_required(VERSION 3.26) - -project(cs2-dumper) - -set(CMAKE_CXX_STANDARD 23) - -add_compile_definitions(WIN32_LEAN_AND_MEAN) - -add_subdirectory(vendor) - -add_executable(${PROJECT_NAME} - src/main.cpp - src/process.cpp - src/sdk/c_schema_class_field_data.cpp - src/sdk/c_schema_class_info.cpp - src/sdk/c_schema_system.cpp - src/sdk/c_schema_system_type_scope.cpp - src/sdk/c_schema_type_declared_class.cpp - src/utility/murmur_hash.cpp -) - -target_link_libraries(${PROJECT_NAME} nlohmann_json::nlohmann_json spdlog::spdlog) - -target_include_directories(${PROJECT_NAME} PRIVATE include vendor/nlohmann_json/single_include vendor/spdlog/include) diff --git a/cmake.toml b/cmake.toml new file mode 100644 index 0000000..3eebcf9 --- /dev/null +++ b/cmake.toml @@ -0,0 +1,13 @@ +[project] +name = "cs2-dumper" + +[fetch-content] +nlohmann-json = { git = "https://github.com/nlohmann/json", tag = "v3.11.2" } +spdlog = { git = "https://github.com/gabime/spdlog", tag = "v1.12.0" } + +[target.cs2-dumper] +type = "executable" +sources = ["src/**.cpp"] +include-directories = ["include"] +compile-features = ["cxx_std_20"] +link-libraries = ["nlohmann_json::nlohmann_json", "spdlog::spdlog"] diff --git a/config.json b/config.json new file mode 100644 index 0000000..f268f8c --- /dev/null +++ b/config.json @@ -0,0 +1,44 @@ +{ + "signatures": [ + { + "name": "entity_list", + "module": "client.dll", + "pattern": "48 8B 0D ? ? ? ? 48 89 7C 24 ? 8B FA C1 EB", + "relative": true, + "levels": 0, + "offset": 0 + }, + { + "name": "global_vars", + "module": "client.dll", + "pattern": "48 89 0D ? ? ? ? 48 89 41", + "relative": true, + "levels": 0, + "offset": 0 + }, + { + "name": "local_player_controller", + "module": "client.dll", + "pattern": "48 8B 05 ? ? ? ? 48 85 C0 74 4F", + "relative": true, + "levels": 0, + "offset": 0 + }, + { + "name": "view_angles", + "module": "client.dll", + "pattern": "48 8B 0D ? ? ? ? 48 8B 01 48 FF 60 30", + "relative": true, + "levels": 1, + "offset": 17680 + }, + { + "name": "view_matrix", + "module": "client.dll", + "pattern": "48 8D 0D ? ? ? ? 48 C1 E0 06", + "relative": true, + "levels": 0, + "offset": 0 + } + ] +} diff --git a/generated/animationsystem.dll.cs b/generated/animationsystem.dll.cs index 61883aa..165801e 100644 --- a/generated/animationsystem.dll.cs +++ b/generated/animationsystem.dll.cs @@ -596,6 +596,14 @@ public static class CBoneConstraintPoseSpaceBone_Input_t { public const ulong m_outputTransformList = 0x10; } +public static class CBoneConstraintPoseSpaceMorph { + public const ulong m_sBoneName = 0x28; + public const ulong m_sAttachmentName = 0x30; + public const ulong m_outputMorph = 0x38; + public const ulong m_inputList = 0x50; + public const ulong m_bClamp = 0x68; +} + public static class CBoneConstraintPoseSpaceMorph_Input_t { public const ulong m_inputValue = 0x0; public const ulong m_outputWeightList = 0x10; diff --git a/generated/animationsystem.dll.hpp b/generated/animationsystem.dll.hpp index b976b64..8f3cb32 100644 --- a/generated/animationsystem.dll.hpp +++ b/generated/animationsystem.dll.hpp @@ -600,6 +600,14 @@ namespace CBoneConstraintPoseSpaceBone_Input_t { constexpr std::ptrdiff_t m_outputTransformList = 0x10; } +namespace CBoneConstraintPoseSpaceMorph { + constexpr std::ptrdiff_t m_sBoneName = 0x28; + constexpr std::ptrdiff_t m_sAttachmentName = 0x30; + constexpr std::ptrdiff_t m_outputMorph = 0x38; + constexpr std::ptrdiff_t m_inputList = 0x50; + constexpr std::ptrdiff_t m_bClamp = 0x68; +} + namespace CBoneConstraintPoseSpaceMorph_Input_t { constexpr std::ptrdiff_t m_inputValue = 0x0; constexpr std::ptrdiff_t m_outputWeightList = 0x10; diff --git a/generated/animationsystem.dll.json b/generated/animationsystem.dll.json index f197b7c..6accd3c 100644 --- a/generated/animationsystem.dll.json +++ b/generated/animationsystem.dll.json @@ -513,6 +513,13 @@ "m_inputValue": 0, "m_outputTransformList": 16 }, + "CBoneConstraintPoseSpaceMorph": { + "m_bClamp": 104, + "m_inputList": 80, + "m_outputMorph": 56, + "m_sAttachmentName": 48, + "m_sBoneName": 40 + }, "CBoneConstraintPoseSpaceMorph_Input_t": { "m_inputValue": 0, "m_outputWeightList": 16 diff --git a/generated/animationsystem.dll.rs b/generated/animationsystem.dll.rs index 3b6166c..84bf58f 100644 --- a/generated/animationsystem.dll.rs +++ b/generated/animationsystem.dll.rs @@ -598,6 +598,14 @@ pub mod CBoneConstraintPoseSpaceBone_Input_t { pub const m_outputTransformList: usize = 0x10; } +pub mod CBoneConstraintPoseSpaceMorph { + pub const m_sBoneName: usize = 0x28; + pub const m_sAttachmentName: usize = 0x30; + pub const m_outputMorph: usize = 0x38; + pub const m_inputList: usize = 0x50; + pub const m_bClamp: usize = 0x68; +} + pub mod CBoneConstraintPoseSpaceMorph_Input_t { pub const m_inputValue: usize = 0x0; pub const m_outputWeightList: usize = 0x10; diff --git a/generated/client.dll.cs b/generated/client.dll.cs index 156daf9..9f973eb 100644 --- a/generated/client.dll.cs +++ b/generated/client.dll.cs @@ -2606,6 +2606,18 @@ public static class C_FuncElectrifiedVolume { public const ulong m_bState = 0xcd0; } +public static class C_FuncLadder { + public const ulong m_vecLadderDir = 0xcc0; + public const ulong m_Dismounts = 0xcd0; + public const ulong m_vecLocalTop = 0xce8; + public const ulong m_vecPlayerMountPositionTop = 0xcf4; + public const ulong m_vecPlayerMountPositionBottom = 0xd00; + public const ulong m_flAutoRideSpeed = 0xd0c; + public const ulong m_bDisabled = 0xd10; + public const ulong m_bFakeLadder = 0xd11; + public const ulong m_bHasSlack = 0xd12; +} + public static class C_FuncMonitor { public const ulong m_targetCamera = 0xcc0; public const ulong m_nResolutionEnum = 0xcc8; diff --git a/generated/client.dll.hpp b/generated/client.dll.hpp index ae1f35e..0ccd943 100644 --- a/generated/client.dll.hpp +++ b/generated/client.dll.hpp @@ -2610,6 +2610,18 @@ namespace C_FuncElectrifiedVolume { constexpr std::ptrdiff_t m_bState = 0xcd0; } +namespace C_FuncLadder { + constexpr std::ptrdiff_t m_vecLadderDir = 0xcc0; + constexpr std::ptrdiff_t m_Dismounts = 0xcd0; + constexpr std::ptrdiff_t m_vecLocalTop = 0xce8; + constexpr std::ptrdiff_t m_vecPlayerMountPositionTop = 0xcf4; + constexpr std::ptrdiff_t m_vecPlayerMountPositionBottom = 0xd00; + constexpr std::ptrdiff_t m_flAutoRideSpeed = 0xd0c; + constexpr std::ptrdiff_t m_bDisabled = 0xd10; + constexpr std::ptrdiff_t m_bFakeLadder = 0xd11; + constexpr std::ptrdiff_t m_bHasSlack = 0xd12; +} + namespace C_FuncMonitor { constexpr std::ptrdiff_t m_targetCamera = 0xcc0; constexpr std::ptrdiff_t m_nResolutionEnum = 0xcc8; diff --git a/generated/client.dll.json b/generated/client.dll.json index 1a92b92..54c687a 100644 --- a/generated/client.dll.json +++ b/generated/client.dll.json @@ -2438,6 +2438,17 @@ "m_bState": 3280, "m_nAmbientEffect": 3264 }, + "C_FuncLadder": { + "m_Dismounts": 3280, + "m_bDisabled": 3344, + "m_bFakeLadder": 3345, + "m_bHasSlack": 3346, + "m_flAutoRideSpeed": 3340, + "m_vecLadderDir": 3264, + "m_vecLocalTop": 3304, + "m_vecPlayerMountPositionBottom": 3328, + "m_vecPlayerMountPositionTop": 3316 + }, "C_FuncMonitor": { "m_bDraw3DSkybox": 3293, "m_bEnabled": 3292, diff --git a/generated/client.dll.rs b/generated/client.dll.rs index 64b0283..6dee040 100644 --- a/generated/client.dll.rs +++ b/generated/client.dll.rs @@ -2608,6 +2608,18 @@ pub mod C_FuncElectrifiedVolume { pub const m_bState: usize = 0xcd0; } +pub mod C_FuncLadder { + pub const m_vecLadderDir: usize = 0xcc0; + pub const m_Dismounts: usize = 0xcd0; + pub const m_vecLocalTop: usize = 0xce8; + pub const m_vecPlayerMountPositionTop: usize = 0xcf4; + pub const m_vecPlayerMountPositionBottom: usize = 0xd00; + pub const m_flAutoRideSpeed: usize = 0xd0c; + pub const m_bDisabled: usize = 0xd10; + pub const m_bFakeLadder: usize = 0xd11; + pub const m_bHasSlack: usize = 0xd12; +} + pub mod C_FuncMonitor { pub const m_targetCamera: usize = 0xcc0; pub const m_nResolutionEnum: usize = 0xcc8; diff --git a/generated/config.json b/generated/config.json new file mode 100644 index 0000000..f268f8c --- /dev/null +++ b/generated/config.json @@ -0,0 +1,44 @@ +{ + "signatures": [ + { + "name": "entity_list", + "module": "client.dll", + "pattern": "48 8B 0D ? ? ? ? 48 89 7C 24 ? 8B FA C1 EB", + "relative": true, + "levels": 0, + "offset": 0 + }, + { + "name": "global_vars", + "module": "client.dll", + "pattern": "48 89 0D ? ? ? ? 48 89 41", + "relative": true, + "levels": 0, + "offset": 0 + }, + { + "name": "local_player_controller", + "module": "client.dll", + "pattern": "48 8B 05 ? ? ? ? 48 85 C0 74 4F", + "relative": true, + "levels": 0, + "offset": 0 + }, + { + "name": "view_angles", + "module": "client.dll", + "pattern": "48 8B 0D ? ? ? ? 48 8B 01 48 FF 60 30", + "relative": true, + "levels": 1, + "offset": 17680 + }, + { + "name": "view_matrix", + "module": "client.dll", + "pattern": "48 8D 0D ? ? ? ? 48 C1 E0 06", + "relative": true, + "levels": 0, + "offset": 0 + } + ] +} diff --git a/generated/vphysics2.dll.cs b/generated/vphysics2.dll.cs index 3b2e4f6..1056430 100644 --- a/generated/vphysics2.dll.cs +++ b/generated/vphysics2.dll.cs @@ -357,6 +357,13 @@ public static class FeTaperedCapsuleRigid_t { public const ulong nFlags = 0x26; } +public static class FeTaperedCapsuleStretch_t { + public const ulong nNode = 0x0; + public const ulong nCollisionMask = 0x4; + public const ulong nDummy = 0x6; + public const ulong flRadius = 0x8; +} + public static class FeTreeChildren_t { public const ulong nChild = 0x0; } diff --git a/generated/vphysics2.dll.hpp b/generated/vphysics2.dll.hpp index a4ea04b..1ae0b76 100644 --- a/generated/vphysics2.dll.hpp +++ b/generated/vphysics2.dll.hpp @@ -361,6 +361,13 @@ namespace FeTaperedCapsuleRigid_t { constexpr std::ptrdiff_t nFlags = 0x26; } +namespace FeTaperedCapsuleStretch_t { + constexpr std::ptrdiff_t nNode = 0x0; + constexpr std::ptrdiff_t nCollisionMask = 0x4; + constexpr std::ptrdiff_t nDummy = 0x6; + constexpr std::ptrdiff_t flRadius = 0x8; +} + namespace FeTreeChildren_t { constexpr std::ptrdiff_t nChild = 0x0; } diff --git a/generated/vphysics2.dll.json b/generated/vphysics2.dll.json index 01721c4..ba5a4c6 100644 --- a/generated/vphysics2.dll.json +++ b/generated/vphysics2.dll.json @@ -310,6 +310,12 @@ "nVertexMapIndex": 36, "vSphere": 0 }, + "FeTaperedCapsuleStretch_t": { + "flRadius": 8, + "nCollisionMask": 4, + "nDummy": 6, + "nNode": 0 + }, "FeTreeChildren_t": { "nChild": 0 }, diff --git a/generated/vphysics2.dll.rs b/generated/vphysics2.dll.rs index d01c1da..ef7963e 100644 --- a/generated/vphysics2.dll.rs +++ b/generated/vphysics2.dll.rs @@ -359,6 +359,13 @@ pub mod FeTaperedCapsuleRigid_t { pub const nFlags: usize = 0x26; } +pub mod FeTaperedCapsuleStretch_t { + pub const nNode: usize = 0x0; + pub const nCollisionMask: usize = 0x4; + pub const nDummy: usize = 0x6; + pub const flRadius: usize = 0x8; +} + pub mod FeTreeChildren_t { pub const nChild: usize = 0x0; } diff --git a/include/builder/cpp_file_builder.hpp b/include/builder/cpp_file_builder.hpp index deb426a..fc78dc6 100644 --- a/include/builder/cpp_file_builder.hpp +++ b/include/builder/cpp_file_builder.hpp @@ -3,7 +3,7 @@ namespace builder { class CppFileBuilder : public IFileBuilder { public: - std::string get_extension() noexcept override { + std::string extension() noexcept override { return "hpp"; } @@ -12,12 +12,12 @@ namespace builder { output << "#include \n\n"; } - void write_namespace(std::ofstream& output, const std::string& namespace_name) noexcept override { - output << "namespace " << namespace_name << " {\n"; + void write_namespace(std::ofstream& output, const std::string& name) noexcept override { + output << "namespace " << name << " {\n"; } - void write_variable(std::ofstream& output, const std::string& variable_name, const std::uint64_t variable_value) noexcept override { - output << " constexpr std::ptrdiff_t " << variable_name << " = 0x" << std::hex << variable_value << ";\n"; + void write_variable(std::ofstream& output, const std::string& name, const std::uintptr_t value) noexcept override { + output << " constexpr std::ptrdiff_t " << name << " = 0x" << std::hex << value << ";\n"; } void write_closure(std::ofstream& output, const bool eof) noexcept override { diff --git a/include/builder/csharp_file_builder.hpp b/include/builder/csharp_file_builder.hpp index a04df59..312a833 100644 --- a/include/builder/csharp_file_builder.hpp +++ b/include/builder/csharp_file_builder.hpp @@ -3,20 +3,18 @@ namespace builder { class CSharpFileBuilder : public IFileBuilder { public: - std::string get_extension() noexcept override { + std::string extension() noexcept override { return "cs"; } - void write_top_level(std::ofstream& output) noexcept override { - // Nothing needed here. + void write_top_level(std::ofstream& output) noexcept override {} + + void write_namespace(std::ofstream& output, const std::string& name) noexcept override { + output << "public static class " << name << " {\n"; } - void write_namespace(std::ofstream& output, const std::string& namespace_name) noexcept override { - output << "public static class " << namespace_name << " {\n"; - } - - void write_variable(std::ofstream& output, const std::string& variable_name, const std::uint64_t variable_value) noexcept override { - output << " public const ulong " << variable_name << " = 0x" << std::hex << variable_value << ";\n"; + void write_variable(std::ofstream& output, const std::string& name, const std::uintptr_t value) noexcept override { + output << " public const ulong " << name << " = 0x" << std::hex << value << ";\n"; } void write_closure(std::ofstream& output, const bool eof) noexcept override { diff --git a/include/builder/i_file_builder.hpp b/include/builder/i_file_builder.hpp index b54a4ff..5c9ca6f 100644 --- a/include/builder/i_file_builder.hpp +++ b/include/builder/i_file_builder.hpp @@ -7,10 +7,10 @@ namespace builder { class IFileBuilder { public: virtual ~IFileBuilder() noexcept = default; - virtual std::string get_extension() noexcept = 0; + virtual std::string extension() noexcept = 0; virtual void write_top_level(std::ofstream& output) noexcept = 0; - virtual void write_namespace(std::ofstream& output, const std::string& namespace_name) noexcept = 0; - virtual void write_variable(std::ofstream& output, const std::string& variable_name, std::uint64_t variable_value) noexcept = 0; + virtual void write_namespace(std::ofstream& output, const std::string& name) noexcept = 0; + virtual void write_variable(std::ofstream& output, const std::string& name, std::uintptr_t value) noexcept = 0; virtual void write_closure(std::ofstream& output, bool eof) noexcept = 0; }; } diff --git a/include/builder/json_file_builder.hpp b/include/builder/json_file_builder.hpp index 9862d85..21c3aa4 100644 --- a/include/builder/json_file_builder.hpp +++ b/include/builder/json_file_builder.hpp @@ -5,20 +5,18 @@ namespace builder { class JsonFileBuilder : public IFileBuilder { public: - std::string get_extension() noexcept override { + std::string extension() noexcept override { return "json"; } - void write_top_level(std::ofstream& output) noexcept override { - // Nothing needed here. + void write_top_level(std::ofstream& output) noexcept override {} + + void write_namespace(std::ofstream& output, const std::string& name) noexcept override { + namespace_name_ = name; } - void write_namespace(std::ofstream& output, const std::string& namespace_name) noexcept override { - current_namespace_name_ = namespace_name; - } - - void write_variable(std::ofstream& output, const std::string& variable_name, const std::uint64_t variable_value) noexcept override { - json[current_namespace_name_][variable_name] = variable_value; + void write_variable(std::ofstream& output, const std::string& name, const std::uintptr_t value) noexcept override { + json[namespace_name_][name] = value; } void write_closure(std::ofstream& output, const bool eof) noexcept override { @@ -33,6 +31,6 @@ namespace builder { nlohmann::json json; private: - std::string current_namespace_name_; + std::string namespace_name_; }; } diff --git a/include/builder/rust_file_builder.hpp b/include/builder/rust_file_builder.hpp index 9391305..d0e23b0 100644 --- a/include/builder/rust_file_builder.hpp +++ b/include/builder/rust_file_builder.hpp @@ -3,7 +3,7 @@ namespace builder { class RustFileBuilder : public IFileBuilder { public: - std::string get_extension() noexcept override { + std::string extension() noexcept override { return "rs"; } @@ -11,12 +11,12 @@ namespace builder { output << "#![allow(non_snake_case, non_upper_case_globals)]\n\n"; } - void write_namespace(std::ofstream& output, const std::string& namespace_name) noexcept override { - output << "pub mod " << namespace_name << " {\n"; + void write_namespace(std::ofstream& output, const std::string& name) noexcept override { + output << "pub mod " << name << " {\n"; } - void write_variable(std::ofstream& output, const std::string& variable_name, const std::uint64_t variable_value) noexcept override { - output << " pub const " << variable_name << ": usize = 0x" << std::hex << variable_value << ";\n"; + void write_variable(std::ofstream& output, const std::string& name, const std::uintptr_t value) noexcept override { + output << " pub const " << name << ": usize = 0x" << std::hex << value << ";\n"; } void write_closure(std::ofstream& output, const bool eof) noexcept override { diff --git a/include/process.hpp b/include/process.hpp index 2f87b45..de7d492 100644 --- a/include/process.hpp +++ b/include/process.hpp @@ -1,36 +1,31 @@ #pragma once -#include +#include "utility/address.hpp" + #include #include #include namespace process { - bool attach(std::string_view process_name); + bool attach(std::string_view process_name) noexcept; - [[nodiscard]] std::optional find_pattern(std::string_view module_name, std::string_view pattern) noexcept; + [[nodiscard]] std::optional find_pattern(std::string_view module_name, std::string_view pattern) noexcept; - [[nodiscard]] std::optional get_export(std::uintptr_t module_base, std::string_view function_name) noexcept; + [[nodiscard]] std::optional get_module_base_by_name(std::string_view module_name) noexcept; - [[nodiscard]] std::optional get_export(std::string_view module_name, std::string_view function_name) noexcept; + std::optional get_module_export_by_name(std::uintptr_t module_base, std::string_view function_name) noexcept; - [[nodiscard]] std::optional> get_loaded_modules() noexcept; - - [[nodiscard]] std::optional get_module_base(std::string_view module_name) noexcept; - - [[nodiscard]] std::optional resolve_jmp(std::uintptr_t address) noexcept; - - [[nodiscard]] std::optional resolve_rip_relative_address(std::uintptr_t address) noexcept; + [[nodiscard]] std::optional> loaded_modules() noexcept; bool read_memory(std::uintptr_t address, void* buffer, std::size_t size) noexcept; bool write_memory(std::uintptr_t address, const void* buffer, std::size_t size) noexcept; - std::string read_string(std::uintptr_t address, std::size_t length) noexcept; + [[nodiscard]] std::string read_string(std::uintptr_t address, std::size_t length) noexcept; template T read_memory(const std::uintptr_t address) noexcept { - T buffer = {}; + T buffer{}; read_memory(address, &buffer, sizeof(T)); diff --git a/include/sdk/c_schema_class_field_data.hpp b/include/sdk/c_schema_class_field_data.hpp deleted file mode 100644 index fb3b1e1..0000000 --- a/include/sdk/c_schema_class_field_data.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -namespace sdk { - class SchemaClassFieldData_t { - public: - [[nodiscard]] std::string get_name() const noexcept; - - [[nodiscard]] std::uint16_t get_offset() const noexcept; - }; -} diff --git a/include/sdk/c_schema_class_info.hpp b/include/sdk/c_schema_class_info.hpp deleted file mode 100644 index 6e59025..0000000 --- a/include/sdk/c_schema_class_info.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -namespace sdk { - class SchemaClassFieldData_t; - - class CSchemaClassInfo { - public: - [[nodiscard]] std::uint16_t get_fields_count() const noexcept; - - [[nodiscard]] std::vector get_fields() const noexcept; - }; -} diff --git a/include/sdk/c_schema_system.hpp b/include/sdk/c_schema_system.hpp deleted file mode 100644 index 7eb181c..0000000 --- a/include/sdk/c_schema_system.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -namespace sdk { - class CSchemaSystemTypeScope; - - class CSchemaSystem { - public: - static CSchemaSystem* get() noexcept; - - [[nodiscard]] std::vector get_type_scopes() const noexcept; - }; -} diff --git a/include/sdk/c_schema_system_type_scope.hpp b/include/sdk/c_schema_system_type_scope.hpp deleted file mode 100644 index 9e0fc83..0000000 --- a/include/sdk/c_schema_system_type_scope.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -namespace sdk { - class CSchemaClassInfo; - class CSchemaType_DeclaredClass; - - class CSchemaSystemTypeScope { - public: - [[nodiscard]] CSchemaClassInfo* find_declared_class(std::string_view class_name) const noexcept; - - [[nodiscard]] std::vector get_declared_classes() const noexcept; - - [[nodiscard]] std::string get_module_name() const noexcept; - }; -} diff --git a/include/sdk/c_schema_type_declared_class.hpp b/include/sdk/c_schema_type_declared_class.hpp deleted file mode 100644 index 9668799..0000000 --- a/include/sdk/c_schema_type_declared_class.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace sdk { - class CSchemaType_DeclaredClass { - public: - [[nodiscard]] std::string get_class_name() const noexcept; - }; -} diff --git a/include/sdk/schema_class_field_data.hpp b/include/sdk/schema_class_field_data.hpp new file mode 100644 index 0000000..b59b06c --- /dev/null +++ b/include/sdk/schema_class_field_data.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace sdk { + class SchemaClassFieldData { + public: + [[nodiscard]] std::string name() const noexcept; + + [[nodiscard]] std::uint16_t offset() const noexcept; + }; +} diff --git a/include/sdk/schema_class_info.hpp b/include/sdk/schema_class_info.hpp new file mode 100644 index 0000000..32342a0 --- /dev/null +++ b/include/sdk/schema_class_info.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace sdk { + class SchemaClassInfo { + public: + [[nodiscard]] std::uint16_t fields_count() const noexcept; + + void for_each_field(const std::function& callback) const noexcept; + }; +} diff --git a/include/sdk/schema_system.hpp b/include/sdk/schema_system.hpp new file mode 100644 index 0000000..b924d80 --- /dev/null +++ b/include/sdk/schema_system.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace sdk { + class SchemaSystem { + public: + static SchemaSystem* get() noexcept; + + [[nodiscard]] std::vector type_scopes() const noexcept; + }; +} diff --git a/include/sdk/schema_system_type_scope.hpp b/include/sdk/schema_system_type_scope.hpp new file mode 100644 index 0000000..e3374f3 --- /dev/null +++ b/include/sdk/schema_system_type_scope.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace sdk { + class SchemaSystemTypeScope { + public: + void for_each_class(const std::function)>& callback) const noexcept; + + [[nodiscard]] std::string module_name() const noexcept; + }; +} diff --git a/include/sdk/schema_type_declared_class.hpp b/include/sdk/schema_type_declared_class.hpp new file mode 100644 index 0000000..54053bd --- /dev/null +++ b/include/sdk/schema_type_declared_class.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace sdk { + class SchemaTypeDeclaredClass { + public: + [[nodiscard]] std::string binary_name() const noexcept; + + [[nodiscard]] std::string module_name() const noexcept; + }; +} diff --git a/include/sdk/sdk.hpp b/include/sdk/sdk.hpp index 34e257c..780fc3d 100644 --- a/include/sdk/sdk.hpp +++ b/include/sdk/sdk.hpp @@ -1,13 +1,13 @@ #pragma once -#include -#include +#include #include #include "process.hpp" -#include "c_schema_class_field_data.hpp" -#include "c_schema_class_info.hpp" -#include "c_schema_system.hpp" -#include "c_schema_system_type_scope.hpp" -#include "c_schema_type_declared_class.hpp" +#include "schema_class_field_data.hpp" +#include "schema_class_info.hpp" +#include "schema_type_declared_class.hpp" +#include "schema_system_type_scope.hpp" +#include "schema_system.hpp" +#include "utl_ts_hash.hpp" diff --git a/include/sdk/utl_ts_hash.hpp b/include/sdk/utl_ts_hash.hpp new file mode 100644 index 0000000..13513ea --- /dev/null +++ b/include/sdk/utl_ts_hash.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include + +namespace sdk { + template + class HashBucketDataInternal { + public: + HashBucketDataInternal* next() const noexcept { + return process::read_memory*>(reinterpret_cast(this) + 0x8); + } + + public: + T data; // 0x0 + std::byte pad_0[0x8]; // 0x8 + K ui_key; // 0x10 + }; + + template + class HashFixedDataInternal { + public: + HashFixedDataInternal* next() const noexcept { + return process::read_memory*>(reinterpret_cast(this) + 0x8); + } + + public: + K ui_key; // 0x0 + std::byte pad_0[0x8]; // 0x8 + T data; // 0x10 + }; + + template + struct HashAllocatedData { + std::array, 128> list() const noexcept { + return process::read_memory, 128>>(reinterpret_cast(this) + 0x18); + } + }; + + template + class HashUnallocatedData { + public: + HashUnallocatedData* next() const noexcept { + return process::read_memory*>(reinterpret_cast(this)); + } + + K ui_key() const noexcept { + return process::read_memory(reinterpret_cast(this) + 0x10); + } + + std::array, 256> block_list() const noexcept { + return process::read_memory, 256>>(reinterpret_cast(this) + 0x20); + } + }; + + template + struct HashBucket { + std::byte pad_0[0x10]; // 0x0 + HashAllocatedData* allocated_data; // 0x10 + HashUnallocatedData* unallocated_data; // 0x18 + }; + + class UtlMemoryPool { + public: + [[nodiscard]] std::int32_t block_size() const noexcept { + return blocks_per_blob_; + } + + [[nodiscard]] std::int32_t count() const noexcept { + return block_allocated_size_; + } + + private: + std::int32_t block_size_; // 0x0 + std::int32_t blocks_per_blob_; // 0x4 + std::int32_t grow_mode_; // 0x8 + std::int32_t blocks_allocated_; // 0xC + std::int32_t block_allocated_size_; // 0x10 + std::int32_t peak_alloc_; // 0x14 + }; + + template + class UtlTsHash { + public: + [[nodiscard]] std::int32_t block_size() const noexcept { + return entry_memory.block_size(); + } + + [[nodiscard]] std::int32_t count() const noexcept { + return entry_memory.count(); + } + + std::vector elements() const noexcept { + std::vector list; + + const auto& unallocated_data = buckets.unallocated_data; + + std::int32_t index = 0; + + for (auto element = unallocated_data; element != nullptr; element = element->next()) { + const auto block_list = element->block_list(); + + for (std::int32_t i = 0; i < block_size() && i != count(); ++i) { + list.emplace_back(block_list[i].data); + + ++index; + + if (index >= count()) + break; + } + } + + return list; + } + + private: + UtlMemoryPool entry_memory; // 0x0 + HashBucket buckets; // 0x18 + }; +} diff --git a/include/utility/address.hpp b/include/utility/address.hpp new file mode 100644 index 0000000..d276a85 --- /dev/null +++ b/include/utility/address.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +namespace utility { + class Address { + public: + Address() noexcept = default; + + explicit Address(const std::uintptr_t address) noexcept : address_(address) {} + + [[nodiscard]] Address add(std::ptrdiff_t offset) const noexcept; + + [[nodiscard]] std::uintptr_t address() const noexcept; + + [[nodiscard]] Address get(std::size_t times = 1) const noexcept; + + [[nodiscard]] bool is_valid() const noexcept; + + [[nodiscard]] Address jmp(std::ptrdiff_t offset = 0x1) const noexcept; + + [[nodiscard]] Address rip(std::ptrdiff_t offset = 0x3, std::size_t length = 7) const noexcept; + + template + [[nodiscard]] T as() const noexcept { + return reinterpret_cast(address_); + } + + private: + std::uintptr_t address_; + }; +} diff --git a/include/utility/murmur_hash.hpp b/include/utility/murmur_hash.hpp deleted file mode 100644 index 82d02bb..0000000 --- a/include/utility/murmur_hash.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -namespace utility { - std::uint32_t murmur_hash2(const void* key, std::uint32_t length, std::uint32_t seed); -} diff --git a/include/base/safe_handle.hpp b/include/utility/safe_handle.hpp similarity index 95% rename from include/base/safe_handle.hpp rename to include/utility/safe_handle.hpp index 6c7a802..15d0e58 100644 --- a/include/base/safe_handle.hpp +++ b/include/utility/safe_handle.hpp @@ -6,7 +6,7 @@ #include -namespace base { +namespace utility { namespace detail { struct HandleDisposer { using pointer = HANDLE; diff --git a/include/utility/string.hpp b/include/utility/string.hpp new file mode 100644 index 0000000..57e2737 --- /dev/null +++ b/include/utility/string.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +namespace utility::string { + inline bool equals_ignore_case(const std::string_view str_1, const std::string_view str_2) noexcept { + return (str_1.size() == str_2.size()) && std::equal(str_1.begin(), str_1.end(), str_2.begin(), [](const char a, const char b) { + return std::tolower(a) == std::tolower(b); + }); + } +} diff --git a/src/main.cpp b/src/main.cpp index 3c0c864..834ca30 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,15 +1,22 @@ #include "builder/builder.hpp" +#include "process.hpp" #include "sdk/sdk.hpp" - -#include +#include "utility/string.hpp" #include -#include -#include #include -using Entries = std::map>>; +using Entries = std::map>, std::less<>>; + +struct Signature { + std::string name; + std::string module; + std::string pattern; + bool relative; + std::uint32_t levels; + std::ptrdiff_t offset; +}; static const std::array>, 4> builders = { { @@ -28,264 +35,199 @@ std::string sanitize_module_name(const std::string& name) { template void generate_file(const std::string_view file_name, const Entries& entries, IFileBuilder& builder) { - const std::string output_file_path = std::format("generated/{}.{}", file_name, builder.get_extension()); + const std::string output_file_path = std::format("generated/{}.{}", file_name, builder.extension()); - std::ofstream output(output_file_path); + std::ofstream file(output_file_path); - if (!output.good()) { - spdlog::error("failed to open {}.", file_name); + if (!file.good()) { + spdlog::error("Failed to open {}.", file_name); return; } - const auto sanitize_namespace_name = [](const std::string& namespace_name) -> std::string { + const auto sanitize_namespace_name = [](const std::string& namespace_name) { static std::regex double_colon_pattern("\\::"); return std::regex_replace(namespace_name, double_colon_pattern, "_"); }; - builder.write_top_level(output); + builder.write_top_level(file); for (auto it = entries.begin(); it != entries.end(); ++it) { const auto& [namespace_name, variables] = *it; const std::string sanitized_namespace = sanitize_namespace_name(namespace_name); - builder.write_namespace(output, sanitized_namespace); + builder.write_namespace(file, sanitized_namespace); for (const auto& [variable_name, variable_value] : variables) - builder.write_variable(output, variable_name, variable_value); + builder.write_variable(file, variable_name, variable_value); - builder.write_closure(output, it == std::prev(entries.end())); + builder.write_closure(file, it == std::prev(entries.end())); } } -std::optional get_entity_list() noexcept { - const std::optional address = process::find_pattern("client.dll", "48 8B 0D ? ? ? ? 48 89 7C 24 ? 8B FA C1 EB"); - - if (!address.has_value()) - return std::nullopt; - - return process::resolve_rip_relative_address(address.value()).value_or(0); -} - -std::optional get_global_vars() noexcept { - std::optional address = process::find_pattern("client.dll", "48 89 0D ? ? ? ? 48 89 41"); - - if (!address.has_value()) - return std::nullopt; - - address = process::resolve_rip_relative_address(address.value()); - - if (!address.has_value()) - return std::nullopt; - - return address.value(); -} - -std::optional get_local_player() noexcept { - std::optional address = process::find_pattern("client.dll", "48 8B 05 ? ? ? ? 48 85 C0 74 4F"); - - if (!address.has_value()) - return std::nullopt; - - address = process::resolve_rip_relative_address(address.value()); - - if (!address.has_value()) - return std::nullopt; - - return address.value(); -} - -std::optional get_view_angles() noexcept { - std::optional address = process::find_pattern("client.dll", "48 8B 0D ? ? ? ? 48 8B 01 48 FF 60 30"); - - if (!address.has_value()) - return std::nullopt; - - address = process::resolve_rip_relative_address(address.value()); - - if (!address.has_value()) - return std::nullopt; - - return process::read_memory(address.value()) + 0x4510; -} - -std::optional get_view_matrix() noexcept { - const std::optional address = process::find_pattern("client.dll", "48 8D 0D ? ? ? ? 48 C1 E0 06"); - - if (!address.has_value()) - return std::nullopt; - - return process::resolve_rip_relative_address(address.value()).value_or(0); -} - -void dump_schema_classes() { - const auto schema_system = sdk::CSchemaSystem::get(); - - if (schema_system == nullptr) { - spdlog::error("failed to get schema system."); - - return; - } - - spdlog::info("schema system: {:#x}", reinterpret_cast(schema_system)); - - for (const sdk::CSchemaSystemTypeScope* type_scope : schema_system->get_type_scopes()) { - if (type_scope == nullptr) - continue; - - const std::string module_name = type_scope->get_module_name(); - - spdlog::info("generating files for {}...", module_name); - - Entries entries; - - for (const sdk::CSchemaType_DeclaredClass* declared_class : type_scope->get_declared_classes()) { - if (declared_class == nullptr) - continue; - - spdlog::info("[{}] @ {:#x}", declared_class->get_class_name(), reinterpret_cast(declared_class)); - - const sdk::CSchemaClassInfo* class_info = type_scope->find_declared_class(declared_class->get_class_name()); - - if (class_info == nullptr) - continue; - - for (const sdk::SchemaClassFieldData_t* field : class_info->get_fields()) { - if (field == nullptr) - continue; - - spdlog::info(" [{}] = {:#x}", field->get_name(), field->get_offset()); - - entries[declared_class->get_class_name()].emplace_back(field->get_name(), field->get_offset()); - } - } - - for (const auto& [extension, builder] : builders) { - generate_file(module_name, entries, *builder); - - spdlog::info(" > generated {}.{}!", module_name, extension); - } - } -} - -void dump_interfaces() noexcept { - const std::optional> loaded_modules = process::get_loaded_modules(); +void dump_interfaces() { + const auto loaded_modules = process::loaded_modules(); if (!loaded_modules.has_value()) { - spdlog::error("failed to get loaded modules."); + spdlog::critical("Failed to get loaded modules."); return; } - spdlog::info("generating interface files..."); + spdlog::info("Generating interface files..."); Entries entries; for (const auto& module_name : loaded_modules.value()) { - const std::optional module_base = process::get_module_base(module_name); + const auto module_base = process::get_module_base_by_name(module_name); if (!module_base.has_value()) continue; - const std::optional create_interface_address = process::get_export(module_base.value(), "CreateInterface"); + const auto create_interface_address = process::get_module_export_by_name(module_base.value(), "CreateInterface"); if (!create_interface_address.has_value()) continue; - std::optional interface_registry = process::resolve_rip_relative_address(create_interface_address.value()); + auto interface_registry = utility::Address(create_interface_address.value()).rip().get(); - if (!interface_registry.has_value()) + if (!interface_registry.is_valid()) continue; - interface_registry = process::read_memory(interface_registry.value()); + while (interface_registry.is_valid()) { + const std::uint64_t interface_ptr = interface_registry.get().address(); - if (!interface_registry.has_value()) - continue; - - while (interface_registry.value() != 0) { - const auto interface_ptr = process::read_memory(interface_registry.value()); - - const std::string interface_version_name = process::read_string(process::read_memory(interface_registry.value() + 0x8), 64); + const std::string interface_version_name = process::read_string(interface_registry.add(0x8).get().address(), 64); entries[sanitize_module_name(module_name)].emplace_back(interface_version_name, interface_ptr - module_base.value()); - interface_registry = process::read_memory(interface_registry.value() + 0x10); + interface_registry = interface_registry.add(0x10).get(); } } for (const auto& [extension, builder] : builders) { generate_file("interfaces", entries, *builder); - spdlog::info(" > generated {}.{}!", "interfaces", extension); + spdlog::info(" > Generated {}.{}", "interfaces", extension); } } -void dump_offsets() noexcept { - const std::optional client_base = process::get_module_base("client.dll"); +void dump_offsets() { + std::ifstream file("config.json"); - if (!client_base.has_value()) { - spdlog::error("failed to get client.dll base."); + if (!file.good()) { + spdlog::critical("Failed to open config.json."); return; } - const auto get_client_rva = [&client_base](const std::uint64_t address) -> std::uint64_t { - return address - client_base.value(); - }; + try { + const auto json = nlohmann::json::parse(file); - const std::uint64_t entity_list_rva = get_client_rva(get_entity_list().value_or(0)); - const std::uint64_t global_vars_rva = get_client_rva(get_global_vars().value_or(0)); - const std::uint64_t local_player_controller_rva = get_client_rva(get_local_player().value_or(0)); - const std::uint64_t view_angles_rva = get_client_rva(get_view_angles().value_or(0)); - const std::uint64_t view_matrix_rva = get_client_rva(get_view_matrix().value_or(0)); + Entries entries; - spdlog::info("found offsets!"); - spdlog::info(" > entity list: {:#x}", entity_list_rva); - spdlog::info(" > global vars: {:#x}", global_vars_rva); - spdlog::info(" > local player controller: {:#x}", local_player_controller_rva); - spdlog::info(" > view angles: {:#x}", view_angles_rva); - spdlog::info(" > view matrix: {:#x}", view_matrix_rva); + for (const auto& element : json["signatures"]) { + const Signature signature = { + .name = element["name"], + .module = element["module"], + .pattern = element["pattern"], + .relative = element["relative"], + .levels = element["levels"], + .offset = element["offset"] + }; - const Entries entries = { - { "client_dll", { - { "entity_list", entity_list_rva }, - { "global_vars", global_vars_rva }, - { "local_player_controller", local_player_controller_rva }, - { "view_angles", view_angles_rva }, - { "view_matrix", view_matrix_rva } - } } - }; + const auto module_base = process::get_module_base_by_name(signature.module); - spdlog::info("generating offset files..."); + if (!module_base.has_value()) + continue; - for (const auto& [extension, builder] : builders) { - generate_file("offsets", entries, *builder); + auto address = process::find_pattern(signature.module, signature.pattern); - spdlog::info(" > generated {}.{}!", "offsets", extension); + if (!address.has_value()) + continue; + + if (signature.relative) + address = address->rip(); + + if (signature.levels > 0) + address = address->get(signature.levels); + + address = address->add(signature.offset); + + spdlog::info("Found '{}' @ {:#x} (RVA: {:#x})", signature.name, address->address(), address->address() - module_base.value()); + + entries[sanitize_module_name(signature.module)].emplace_back(signature.name, address->address() - module_base.value()); + } + + spdlog::info("Generating offset files..."); + + for (const auto& [extension, builder] : builders) { + generate_file("offsets", entries, *builder); + + spdlog::info(" > Generated file: {}.{}", "offsets", extension); + } + } catch (const nlohmann::json::parse_error& ex) { + spdlog::critical("Failed to parse config.json: {}", ex.what()); + } +} + +void dump_schemas() { + const auto schema_system = sdk::SchemaSystem::get(); + + if (schema_system == nullptr) { + spdlog::critical("Failed to get schema system."); + + return; + } + + spdlog::info("Schema system: {:#x}", reinterpret_cast(schema_system)); + + for (const auto& type_scope : schema_system->type_scopes()) { + const std::string module_name = type_scope->module_name(); + + spdlog::info("Generating files for {}...", module_name); + + Entries entries; + + type_scope->for_each_class([&entries](const std::pair& pair) { + spdlog::info(" [{}] @ {:#x}", pair.first, reinterpret_cast(pair.second)); + + pair.second->for_each_field([&entries, &pair](const sdk::SchemaClassFieldData* field) { + spdlog::info(" [{}] = {:#x}", field->name(), field->offset()); + + entries[pair.first].emplace_back(field->name(), field->offset()); + }); + }); + + for (const auto& [extension, builder] : builders) { + generate_file(module_name, entries, *builder); + + spdlog::info(" > Generated file: {}.{}", module_name, extension); + } } } int main() { + const auto start = std::chrono::high_resolution_clock::now(); + if (!std::filesystem::exists("generated")) std::filesystem::create_directory("generated"); if (!process::attach("cs2.exe")) { - spdlog::error("failed to attach to process."); + spdlog::critical("Failed to attach to cs2.exe."); return 1; } - spdlog::info("attached to process!"); - - dump_schema_classes(); - dump_interfaces(); dump_offsets(); - spdlog::info("finished!"); + dump_schemas(); + + spdlog::info("Done! Took {}ms.", std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count()); return 0; } diff --git a/src/process.cpp b/src/process.cpp index 46ac79e..aa02fdc 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -1,8 +1,8 @@ #include "process.hpp" -#include "base/safe_handle.hpp" +#include "utility/safe_handle.hpp" +#include "utility/string.hpp" #include -#include #include #include @@ -11,67 +11,72 @@ namespace process { std::uint32_t process_id = 0; - base::SafeHandle process_handle; + utility::SafeHandle process_handle; - namespace detail { - std::optional get_process_id_by_name(const std::string_view process_name) noexcept { - const base::SafeHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); - - if (snapshot.get() == INVALID_HANDLE_VALUE) - return std::nullopt; - - PROCESSENTRY32 process_entry = {}; - - process_entry.dwSize = sizeof(PROCESSENTRY32); - - for (Process32First(snapshot.get(), &process_entry); Process32Next(snapshot.get(), &process_entry);) { - if (std::string_view(process_entry.szExeFile) == process_name) - return process_entry.th32ProcessID; - } + std::optional get_process_id_by_name(const std::string_view process_name) noexcept { + const utility::SafeHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); + if (snapshot.get() == INVALID_HANDLE_VALUE) return std::nullopt; + + PROCESSENTRY32 process_entry = { + .dwSize = sizeof(PROCESSENTRY32) + }; + + for (Process32First(snapshot.get(), &process_entry); Process32Next(snapshot.get(), &process_entry);) { + if (std::string_view(process_entry.szExeFile) == process_name) + return process_entry.th32ProcessID; } + + return std::nullopt; } - bool attach(const std::string_view process_name) { - process_id = detail::get_process_id_by_name(process_name).value_or(0); + bool attach(const std::string_view process_name) noexcept { + const auto id = get_process_id_by_name(process_name); - if (process_id == 0) + if (!id.has_value()) return false; - process_handle = base::SafeHandle(OpenProcess(PROCESS_ALL_ACCESS, 0, process_id)); + process_id = id.value(); + + process_handle = utility::SafeHandle(OpenProcess(PROCESS_ALL_ACCESS, 0, process_id)); return process_handle.get() != nullptr; } - std::optional find_pattern(const std::string_view module_name, const std::string_view pattern) noexcept { - constexpr auto pattern_to_bytes = [](const std::string_view pattern) -> std::vector { + std::optional find_pattern(const std::string_view module_name, const std::string_view pattern) noexcept { + constexpr auto pattern_to_bytes = [](const std::string_view pattern) { std::vector bytes; for (std::size_t i = 0; i < pattern.size(); ++i) { - if (pattern[i] == ' ') - continue; + switch (pattern[i]) { + case '?': + bytes.push_back(-1); + break; - if (pattern[i] == '?') { - bytes.push_back(-1); + case ' ': + break; - continue; - } + default: { + if (i + 1 < pattern.size()) { + std::int32_t value = 0; - if (i + 1 < pattern.size()) { - std::int32_t value = 0; + if (const auto [ptr, ec] = std::from_chars(pattern.data() + i, pattern.data() + i + 2, value, 16); ec == std::errc()) { + bytes.push_back(value); - if (const auto [ptr, ec] = std::from_chars(pattern.data() + i, pattern.data() + i + 2, value, 16); ec == std::errc()) - bytes.push_back(value); + ++i; + } + } - ++i; + break; + } } } return bytes; }; - const std::optional module_base = get_module_base(module_name); + const auto module_base = get_module_base_by_name(module_name); if (!module_base.has_value()) return std::nullopt; @@ -98,7 +103,7 @@ namespace process { if (!read_memory(module_base.value(), module_data.get(), module_size)) return std::nullopt; - const std::vector pattern_bytes = pattern_to_bytes(pattern); + const auto pattern_bytes = pattern_to_bytes(pattern); for (std::size_t i = 0; i < module_size - pattern.size(); ++i) { bool found = true; @@ -112,13 +117,31 @@ namespace process { } if (found) - return module_base.value() + i; + return utility::Address(module_base.value() + i); } return std::nullopt; } - std::optional get_export(const std::uintptr_t module_base, const std::string_view function_name) noexcept { + std::optional get_module_base_by_name(const std::string_view module_name) noexcept { + const utility::SafeHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, process_id)); + + if (snapshot.get() == INVALID_HANDLE_VALUE) + return std::nullopt; + + MODULEENTRY32 module_entry = { + .dwSize = sizeof(MODULEENTRY32) + }; + + for (Module32First(snapshot.get(), &module_entry); Module32Next(snapshot.get(), &module_entry);) { + if (utility::string::equals_ignore_case(module_entry.szModule, module_name)) + return reinterpret_cast(module_entry.modBaseAddr); + } + + return std::nullopt; + } + + std::optional get_module_export_by_name(const std::uintptr_t module_base, const std::string_view function_name) noexcept { const auto headers = std::make_unique(0x1000); if (!read_memory(module_base, headers.get(), 0x1000)) @@ -175,24 +198,15 @@ namespace process { return std::nullopt; } - std::optional get_export(const std::string_view module_name, const std::string_view function_name) noexcept { - const std::optional module_base = get_module_base(module_name); - - if (!module_base.has_value()) - return std::nullopt; - - return get_export(module_base.value(), function_name); - } - - std::optional> get_loaded_modules() noexcept { - const base::SafeHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, process_id)); + std::optional> loaded_modules() noexcept { + const utility::SafeHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, process_id)); if (snapshot.get() == INVALID_HANDLE_VALUE) return std::nullopt; - MODULEENTRY32 module_entry = {}; - - module_entry.dwSize = sizeof(MODULEENTRY32); + MODULEENTRY32 module_entry = { + .dwSize = sizeof(MODULEENTRY32) + }; std::vector loaded_modules; @@ -202,53 +216,23 @@ namespace process { return loaded_modules; } - std::optional get_module_base(const std::string_view module_name) noexcept { - const base::SafeHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, process_id)); - - if (snapshot.get() == INVALID_HANDLE_VALUE) - return std::nullopt; - - MODULEENTRY32 module_entry = {}; - - module_entry.dwSize = sizeof(MODULEENTRY32); - - for (Module32First(snapshot.get(), &module_entry); Module32Next(snapshot.get(), &module_entry);) { - if (_stricmp(module_entry.szModule, module_name.data()) == 0) - return reinterpret_cast(module_entry.modBaseAddr); - } - - return std::nullopt; - } - - std::optional resolve_jmp(const std::uintptr_t address) noexcept { - const auto displacement = read_memory(address + 0x1); - - return address + displacement + 0x5; - } - - std::optional resolve_rip_relative_address(const std::uintptr_t address) noexcept { - const auto displacement = read_memory(address + 0x3); - - return address + displacement + 0x7; - } - bool read_memory(const std::uintptr_t address, void* buffer, const std::size_t size) noexcept { - return ReadProcessMemory(process_handle.get(), reinterpret_cast(address), buffer, size, nullptr); + return ReadProcessMemory(process_handle.get(), reinterpret_cast(address), buffer, size, nullptr); } bool write_memory(const std::uintptr_t address, const void* buffer, const std::size_t size) noexcept { - return WriteProcessMemory(process_handle.get(), reinterpret_cast(address), buffer, size, nullptr); + return WriteProcessMemory(process_handle.get(), reinterpret_cast(address), buffer, size, nullptr); } std::string read_string(const std::uintptr_t address, const std::size_t length) noexcept { - std::vector buffer(length); + std::string buffer(length, '\0'); if (!read_memory(address, buffer.data(), length)) return {}; if (const auto it = std::ranges::find(buffer, '\0'); it != buffer.end()) - buffer.resize(std::distance(buffer.begin(), it)); + buffer.erase(it, buffer.end()); - return { buffer.begin(), buffer.end() }; + return buffer; } } diff --git a/src/sdk/c_schema_class_info.cpp b/src/sdk/c_schema_class_info.cpp deleted file mode 100644 index 4b4fd27..0000000 --- a/src/sdk/c_schema_class_info.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "sdk/sdk.hpp" - -namespace sdk { - std::uint16_t CSchemaClassInfo::get_fields_count() const noexcept { - return process::read_memory(reinterpret_cast(this) + 0x1C); - } - - std::vector CSchemaClassInfo::get_fields() const noexcept { - std::vector fields; - - for (std::size_t i = 0; i < get_fields_count(); ++i) { - const auto field = reinterpret_cast(process::read_memory(reinterpret_cast(this) + 0x28) + (i * 0x20)); - - if (field == nullptr) - continue; - - fields.push_back(field); - } - - return fields; - } -} diff --git a/src/sdk/c_schema_system.cpp b/src/sdk/c_schema_system.cpp deleted file mode 100644 index 5c861c8..0000000 --- a/src/sdk/c_schema_system.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "sdk/c_schema_system.hpp" -#include "process.hpp" - -namespace sdk { - CSchemaSystem* CSchemaSystem::get() noexcept { - std::optional address = process::find_pattern("schemasystem.dll", "48 8D 0D ? ? ? ? E9 ? ? ? ? CC CC CC CC 48 8D 0D ? ? ? ? E9 ? ? ? ? CC CC CC CC 48 83 EC 28"); - - if (!address.has_value()) - return nullptr; - - address = process::resolve_rip_relative_address(address.value()); - - if (!address.has_value()) - return nullptr; - - return reinterpret_cast(address.value()); - } - - std::vector CSchemaSystem::get_type_scopes() const noexcept { - std::vector type_scopes; - - type_scopes.resize(process::read_memory(reinterpret_cast(this) + 0x190)); - - process::read_memory(process::read_memory(reinterpret_cast(this) + 0x198), type_scopes.data(), type_scopes.size() * sizeof(std::uint64_t)); - - return type_scopes; - } -} diff --git a/src/sdk/c_schema_system_type_scope.cpp b/src/sdk/c_schema_system_type_scope.cpp deleted file mode 100644 index 809387e..0000000 --- a/src/sdk/c_schema_system_type_scope.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "sdk/sdk.hpp" -#include "utility/murmur_hash.hpp" - -namespace sdk { - CSchemaClassInfo* CSchemaSystemTypeScope::find_declared_class(const std::string_view class_name) const noexcept { - const std::uint32_t hash = utility::murmur_hash2(class_name.data(), static_cast(class_name.length()), 0xBAADFEED); - - const std::int32_t hash_transform1 = static_cast(hash >> 0x10) - 0x2D6 + 0x21 * (0x21 * static_cast(hash) + static_cast(hash >> 0x8)); - const std::int32_t hash_transform2 = 0x21 * hash_transform1 + static_cast(hash >> 0x18); - - const auto hash_part = static_cast(static_cast(hash >> 0x18)); - - const std::int32_t hash_transform4 = (hash_transform2 ^ (hash_transform2 >> 0x10)) ^ (static_cast(hash_transform2 ^ (hash_part >> 0x10)) >> 0x8); - - const auto get_class_info = [&](const std::uint64_t address) -> CSchemaClassInfo* { - const std::uint64_t class_info_address = address + 0x588 + static_cast(0x28) * static_cast(hash_transform4); - - const auto initial_address = process::read_memory(class_info_address + 0x58); - - std::uint64_t class_address = initial_address; - - if (initial_address != 0) { - while (process::read_memory(class_address) != hash) { - class_address = process::read_memory(class_address + 0x8); - - if (class_address == 0) - break; - } - } - - if (class_address == 0) { - const auto secondary_address = process::read_memory(class_info_address + 0x60); - - std::uint64_t final_address = 0; - - if (secondary_address != 0 && secondary_address != initial_address) { - auto current_address = process::read_memory(class_info_address + 0x60); - - const auto starting_address = process::read_memory(class_info_address + 0x58); - - if (current_address != starting_address) { - while (process::read_memory(current_address) != hash) { - current_address = process::read_memory(current_address + 0x8); - - if (current_address == starting_address) - break; - } - - final_address = current_address; - } - } - - class_address = final_address; - } - - return reinterpret_cast(class_address); - }; - - const CSchemaClassInfo* class_info = get_class_info(reinterpret_cast(this)); - - if (class_info != nullptr) - return reinterpret_cast(process::read_memory(reinterpret_cast(class_info) + 0x10)); - - const auto secondary_class_info = process::read_memory(reinterpret_cast(this) + 0x108); - - return secondary_class_info != 0 ? reinterpret_cast(process::read_memory(reinterpret_cast(get_class_info(secondary_class_info)) + 0x10)) : nullptr; - } - - std::vector CSchemaSystemTypeScope::get_declared_classes() const noexcept { - std::vector classes; - - const std::uint64_t base = reinterpret_cast(this) + 0x588; - - const auto block_size = process::read_memory(base + 0x4); - const auto count = process::read_memory(base + 0x10); - const auto unallocated_data = process::read_memory(base + 0x18 + 0x18); - - std::uint32_t index = 0; - - for (std::uint64_t element = unallocated_data; element != 0; element = process::read_memory(element)) { - for (std::size_t i = 0; i < block_size && i != count; ++i) { - classes.push_back(reinterpret_cast(process::read_memory(element + 0x20 + (i * 0x18)))); - - ++index; - - if (index >= count) - break; - } - } - - return classes; - } - - std::string CSchemaSystemTypeScope::get_module_name() const noexcept { - return process::read_string(reinterpret_cast(this) + 0x8, 256); - } -} diff --git a/src/sdk/c_schema_type_declared_class.cpp b/src/sdk/c_schema_type_declared_class.cpp deleted file mode 100644 index df75711..0000000 --- a/src/sdk/c_schema_type_declared_class.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "sdk/sdk.hpp" - -namespace sdk { - std::string CSchemaType_DeclaredClass::get_class_name() const noexcept { - return process::read_string(process::read_memory(reinterpret_cast(this) + 0x8), 64); - } -} diff --git a/src/sdk/c_schema_class_field_data.cpp b/src/sdk/schema_class_field_data.cpp similarity index 65% rename from src/sdk/c_schema_class_field_data.cpp rename to src/sdk/schema_class_field_data.cpp index fb36f3a..4418cb0 100644 --- a/src/sdk/c_schema_class_field_data.cpp +++ b/src/sdk/schema_class_field_data.cpp @@ -1,11 +1,11 @@ #include "sdk/sdk.hpp" namespace sdk { - std::string SchemaClassFieldData_t::get_name() const noexcept { + std::string SchemaClassFieldData::name() const noexcept { return process::read_string(process::read_memory(reinterpret_cast(this)), 64); } - std::uint16_t SchemaClassFieldData_t::get_offset() const noexcept { + std::uint16_t SchemaClassFieldData::offset() const noexcept { return process::read_memory(reinterpret_cast(this) + 0x10); } } diff --git a/src/sdk/schema_class_info.cpp b/src/sdk/schema_class_info.cpp new file mode 100644 index 0000000..9d0e8bc --- /dev/null +++ b/src/sdk/schema_class_info.cpp @@ -0,0 +1,18 @@ +#include "sdk/sdk.hpp" + +namespace sdk { + std::uint16_t SchemaClassInfo::fields_count() const noexcept { + return process::read_memory(reinterpret_cast(this) + 0x1C); + } + + void SchemaClassInfo::for_each_field(const std::function& callback) const noexcept { + for (std::size_t i = 0; i < fields_count(); ++i) { + const auto field = reinterpret_cast(process::read_memory(reinterpret_cast(this) + 0x28) + (i * 0x20)); + + if (field == nullptr) + continue; + + callback(field); + } + } +} diff --git a/src/sdk/schema_system.cpp b/src/sdk/schema_system.cpp new file mode 100644 index 0000000..8f0606b --- /dev/null +++ b/src/sdk/schema_system.cpp @@ -0,0 +1,28 @@ +#include "sdk/sdk.hpp" + +namespace sdk { + SchemaSystem* SchemaSystem::get() noexcept { + const auto address = process::find_pattern("schemasystem.dll", "48 8D 0D ? ? ? ? E9 ? ? ? ? CC CC CC CC 48 8D 0D ? ? ? ? E9 ? ? ? ? CC CC CC CC 48 83 EC 28"); + + if (!address.has_value()) + return nullptr; + + return address->rip().as(); + } + + std::vector SchemaSystem::type_scopes() const noexcept { + const auto count = process::read_memory(reinterpret_cast(this) + 0x190); + const auto data = process::read_memory(reinterpret_cast(this) + 0x198); + + if (count == 0 || data == 0) + return {}; + + std::vector type_scopes; + + type_scopes.resize(count); + + process::read_memory(data, type_scopes.data(), count * sizeof(std::uint64_t)); + + return type_scopes; + } +} diff --git a/src/sdk/schema_system_type_scope.cpp b/src/sdk/schema_system_type_scope.cpp new file mode 100644 index 0000000..6ab7535 --- /dev/null +++ b/src/sdk/schema_system_type_scope.cpp @@ -0,0 +1,14 @@ +#include "sdk/sdk.hpp" + +namespace sdk { + void SchemaSystemTypeScope::for_each_class(const std::function)>& callback) const noexcept { + const auto classes = process::read_memory>(reinterpret_cast(this) + 0x588); + + for (const auto& element : classes.elements()) + callback({ element->binary_name(), reinterpret_cast(element) }); + } + + std::string SchemaSystemTypeScope::module_name() const noexcept { + return process::read_string(reinterpret_cast(this) + 0x8, 256); + } +} diff --git a/src/sdk/schema_type_declared_class.cpp b/src/sdk/schema_type_declared_class.cpp new file mode 100644 index 0000000..9c918de --- /dev/null +++ b/src/sdk/schema_type_declared_class.cpp @@ -0,0 +1,11 @@ +#include "sdk/sdk.hpp" + +namespace sdk { + std::string SchemaTypeDeclaredClass::binary_name() const noexcept { + return process::read_string(process::read_memory(reinterpret_cast(this) + 0x8), 64); + } + + std::string SchemaTypeDeclaredClass::module_name() const noexcept { + return process::read_string(process::read_memory(reinterpret_cast(this) + 0x10), 256); + } +} diff --git a/src/utility/address.cpp b/src/utility/address.cpp new file mode 100644 index 0000000..3534a01 --- /dev/null +++ b/src/utility/address.cpp @@ -0,0 +1,48 @@ +#include "utility/address.hpp" +#include "process.hpp" + +namespace utility { + Address Address::add(const std::ptrdiff_t offset) const noexcept { + return Address(address_ + offset); + } + + std::uintptr_t Address::address() const noexcept { + return address_; + } + + Address Address::get(const std::size_t times) const noexcept { + std::uintptr_t base = address_; + + for (std::size_t i = 0; i < times; ++i) + base = process::read_memory(base); + + return Address(base); + } + + bool Address::is_valid() const noexcept { + return address_ > static_cast(0x1000) + && address_ < static_cast(sizeof(void*) == 4 ? 0x7FFEFFFF : 0x7FFFFFFEFFFF); + } + + Address Address::jmp(const std::ptrdiff_t offset) const noexcept { + std::uintptr_t base = address_ + offset; + + const auto displacement = process::read_memory(address_); + + base += displacement; + base += sizeof(std::uint32_t); + + return Address(base); + } + + Address Address::rip(const std::ptrdiff_t offset, const std::size_t length) const noexcept { + std::uintptr_t base = address_; + + const auto displacement = process::read_memory(base + offset); + + base += displacement; + base += length; + + return Address(base); + } +} diff --git a/src/utility/murmur_hash.cpp b/src/utility/murmur_hash.cpp deleted file mode 100644 index 15ba599..0000000 --- a/src/utility/murmur_hash.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "utility/murmur_hash.hpp" - -namespace utility { - std::uint32_t murmur_hash2(const void* key, std::uint32_t length, const std::uint32_t seed) { - constexpr auto get_block = [](const std::uint32_t* ptr) -> std::uint32_t { - const auto bytes = reinterpret_cast(ptr); - - return static_cast(bytes[0]) | static_cast(bytes[1]) << 0x8 | static_cast(bytes[2]) << 0x10 | static_cast(bytes[3]) << 0x18; - }; - - constexpr std::uint32_t HASH_CONSTANT = 0x5BD1E995; - - std::uint32_t hash = seed ^ length; - - auto data = static_cast(key); - - while (length >= 4) { - std::uint32_t block = get_block(reinterpret_cast(data)); - - block *= HASH_CONSTANT; - block ^= block >> 0x18; - block *= HASH_CONSTANT; - - hash *= HASH_CONSTANT; - hash ^= block; - - data += 0x4; - length -= 0x4; - } - - switch (length) { - case 3: - hash ^= data[2] << 0x10; - - case 2: - hash ^= data[1] << 0x8; - - case 1: { - hash ^= data[0]; - hash *= HASH_CONSTANT; - } - - default: - break; - } - - hash ^= hash >> 0xD; - hash *= HASH_CONSTANT; - hash ^= hash >> 0xF; - - return hash; - } -} diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt deleted file mode 100644 index c0bad9c..0000000 --- a/vendor/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -cmake_minimum_required(VERSION 3.26) - -add_subdirectory(nlohmann_json) -add_subdirectory(spdlog) diff --git a/vendor/nlohmann_json b/vendor/nlohmann_json deleted file mode 160000 index 836b7be..0000000 --- a/vendor/nlohmann_json +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 836b7beca4b62e2a99465edef44066b7401fd704 diff --git a/vendor/spdlog b/vendor/spdlog deleted file mode 160000 index 3aceda0..0000000 --- a/vendor/spdlog +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3aceda041b2bfbccaf14d5c83eda16fc67bea364