mirror of
https://github.com/a2x/cs2-dumper.git
synced 2025-04-02 12:15:35 +08:00
Refactored code
This commit is contained in:
parent
a3a3427561
commit
a8d3318d94
@ -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
|
||||
trim_trailing_whitespace = true
|
||||
|
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/**/CMakeLists.txt linguist-generated
|
||||
/**/cmkr.cmake linguist-vendored
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,7 +1,10 @@
|
||||
.idea/
|
||||
.vs/
|
||||
CMakeLists.txt
|
||||
CMakeSettings.json
|
||||
build/
|
||||
cmake-build-debug/
|
||||
cmake-build-release/
|
||||
CMakeSettings.json
|
||||
cmake-build/
|
||||
cmkr.cmake
|
||||
out/
|
||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -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
|
24
CMakeLists.txt
generated
24
CMakeLists.txt
generated
@ -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)
|
13
cmake.toml
Normal file
13
cmake.toml
Normal file
@ -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"]
|
44
config.json
Normal file
44
config.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
44
generated/config.json
Normal file
44
generated/config.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -310,6 +310,12 @@
|
||||
"nVertexMapIndex": 36,
|
||||
"vSphere": 0
|
||||
},
|
||||
"FeTaperedCapsuleStretch_t": {
|
||||
"flRadius": 8,
|
||||
"nCollisionMask": 4,
|
||||
"nDummy": 6,
|
||||
"nNode": 0
|
||||
},
|
||||
"FeTreeChildren_t": {
|
||||
"nChild": 0
|
||||
},
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 <cstddef>\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 {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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_;
|
||||
};
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -1,36 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "utility/address.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace process {
|
||||
bool attach(std::string_view process_name);
|
||||
bool attach(std::string_view process_name) noexcept;
|
||||
|
||||
[[nodiscard]] std::optional<std::uintptr_t> find_pattern(std::string_view module_name, std::string_view pattern) noexcept;
|
||||
[[nodiscard]] std::optional<utility::Address> find_pattern(std::string_view module_name, std::string_view pattern) noexcept;
|
||||
|
||||
[[nodiscard]] std::optional<std::uintptr_t> get_export(std::uintptr_t module_base, std::string_view function_name) noexcept;
|
||||
[[nodiscard]] std::optional<std::uintptr_t> get_module_base_by_name(std::string_view module_name) noexcept;
|
||||
|
||||
[[nodiscard]] std::optional<std::uintptr_t> get_export(std::string_view module_name, std::string_view function_name) noexcept;
|
||||
std::optional<std::uintptr_t> get_module_export_by_name(std::uintptr_t module_base, std::string_view function_name) noexcept;
|
||||
|
||||
[[nodiscard]] std::optional<std::vector<std::string>> get_loaded_modules() noexcept;
|
||||
|
||||
[[nodiscard]] std::optional<std::uintptr_t> get_module_base(std::string_view module_name) noexcept;
|
||||
|
||||
[[nodiscard]] std::optional<std::uintptr_t> resolve_jmp(std::uintptr_t address) noexcept;
|
||||
|
||||
[[nodiscard]] std::optional<std::uintptr_t> resolve_rip_relative_address(std::uintptr_t address) noexcept;
|
||||
[[nodiscard]] std::optional<std::vector<std::string>> 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 <typename T>
|
||||
T read_memory(const std::uintptr_t address) noexcept {
|
||||
T buffer = {};
|
||||
T buffer{};
|
||||
|
||||
read_memory(address, &buffer, sizeof(T));
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
@ -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<SchemaClassFieldData_t*> get_fields() const noexcept;
|
||||
};
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace sdk {
|
||||
class CSchemaSystemTypeScope;
|
||||
|
||||
class CSchemaSystem {
|
||||
public:
|
||||
static CSchemaSystem* get() noexcept;
|
||||
|
||||
[[nodiscard]] std::vector<CSchemaSystemTypeScope*> get_type_scopes() const noexcept;
|
||||
};
|
||||
}
|
@ -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<CSchemaType_DeclaredClass*> get_declared_classes() const noexcept;
|
||||
|
||||
[[nodiscard]] std::string get_module_name() const noexcept;
|
||||
};
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace sdk {
|
||||
class CSchemaType_DeclaredClass {
|
||||
public:
|
||||
[[nodiscard]] std::string get_class_name() const noexcept;
|
||||
};
|
||||
}
|
10
include/sdk/schema_class_field_data.hpp
Normal file
10
include/sdk/schema_class_field_data.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
namespace sdk {
|
||||
class SchemaClassFieldData {
|
||||
public:
|
||||
[[nodiscard]] std::string name() const noexcept;
|
||||
|
||||
[[nodiscard]] std::uint16_t offset() const noexcept;
|
||||
};
|
||||
}
|
10
include/sdk/schema_class_info.hpp
Normal file
10
include/sdk/schema_class_info.hpp
Normal file
@ -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<void(SchemaClassFieldData*)>& callback) const noexcept;
|
||||
};
|
||||
}
|
10
include/sdk/schema_system.hpp
Normal file
10
include/sdk/schema_system.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
namespace sdk {
|
||||
class SchemaSystem {
|
||||
public:
|
||||
static SchemaSystem* get() noexcept;
|
||||
|
||||
[[nodiscard]] std::vector<SchemaSystemTypeScope*> type_scopes() const noexcept;
|
||||
};
|
||||
}
|
10
include/sdk/schema_system_type_scope.hpp
Normal file
10
include/sdk/schema_system_type_scope.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
namespace sdk {
|
||||
class SchemaSystemTypeScope {
|
||||
public:
|
||||
void for_each_class(const std::function<void(std::pair<std::string, SchemaClassInfo*>)>& callback) const noexcept;
|
||||
|
||||
[[nodiscard]] std::string module_name() const noexcept;
|
||||
};
|
||||
}
|
10
include/sdk/schema_type_declared_class.hpp
Normal file
10
include/sdk/schema_type_declared_class.hpp
Normal file
@ -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;
|
||||
};
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#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"
|
||||
|
119
include/sdk/utl_ts_hash.hpp
Normal file
119
include/sdk/utl_ts_hash.hpp
Normal file
@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace sdk {
|
||||
template <class T, typename K>
|
||||
class HashBucketDataInternal {
|
||||
public:
|
||||
HashBucketDataInternal<T, K>* next() const noexcept {
|
||||
return process::read_memory<HashBucketDataInternal<T, K>*>(reinterpret_cast<std::uint64_t>(this) + 0x8);
|
||||
}
|
||||
|
||||
public:
|
||||
T data; // 0x0
|
||||
std::byte pad_0[0x8]; // 0x8
|
||||
K ui_key; // 0x10
|
||||
};
|
||||
|
||||
template <class T, typename K>
|
||||
class HashFixedDataInternal {
|
||||
public:
|
||||
HashFixedDataInternal<T, K>* next() const noexcept {
|
||||
return process::read_memory<HashFixedDataInternal<T, K>*>(reinterpret_cast<std::uint64_t>(this) + 0x8);
|
||||
}
|
||||
|
||||
public:
|
||||
K ui_key; // 0x0
|
||||
std::byte pad_0[0x8]; // 0x8
|
||||
T data; // 0x10
|
||||
};
|
||||
|
||||
template <class T, typename K>
|
||||
struct HashAllocatedData {
|
||||
std::array<HashFixedDataInternal<T, K>, 128> list() const noexcept {
|
||||
return process::read_memory<std::array<HashFixedDataInternal<T, K>, 128>>(reinterpret_cast<std::uint64_t>(this) + 0x18);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, typename K>
|
||||
class HashUnallocatedData {
|
||||
public:
|
||||
HashUnallocatedData<T, K>* next() const noexcept {
|
||||
return process::read_memory<HashUnallocatedData<T, K>*>(reinterpret_cast<std::uint64_t>(this));
|
||||
}
|
||||
|
||||
K ui_key() const noexcept {
|
||||
return process::read_memory<K>(reinterpret_cast<std::uint64_t>(this) + 0x10);
|
||||
}
|
||||
|
||||
std::array<HashBucketDataInternal<T, K>, 256> block_list() const noexcept {
|
||||
return process::read_memory<std::array<HashBucketDataInternal<T, K>, 256>>(reinterpret_cast<std::uint64_t>(this) + 0x20);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, typename K>
|
||||
struct HashBucket {
|
||||
std::byte pad_0[0x10]; // 0x0
|
||||
HashAllocatedData<T, K>* allocated_data; // 0x10
|
||||
HashUnallocatedData<T, K>* 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 T, typename K = std::uint64_t>
|
||||
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<T> elements() const noexcept {
|
||||
std::vector<T> 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<T, K> buckets; // 0x18
|
||||
};
|
||||
}
|
33
include/utility/address.hpp
Normal file
33
include/utility/address.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
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 <typename T>
|
||||
[[nodiscard]] T as() const noexcept {
|
||||
return reinterpret_cast<T>(address_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::uintptr_t address_;
|
||||
};
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace utility {
|
||||
std::uint32_t murmur_hash2(const void* key, std::uint32_t length, std::uint32_t seed);
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include <handleapi.h>
|
||||
|
||||
namespace base {
|
||||
namespace utility {
|
||||
namespace detail {
|
||||
struct HandleDisposer {
|
||||
using pointer = HANDLE;
|
12
include/utility/string.hpp
Normal file
12
include/utility/string.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <cctype>
|
||||
#include <string_view>
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
300
src/main.cpp
300
src/main.cpp
@ -1,15 +1,22 @@
|
||||
#include "builder/builder.hpp"
|
||||
#include "process.hpp"
|
||||
#include "sdk/sdk.hpp"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "utility/string.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
|
||||
using Entries = std::map<std::string, std::vector<std::pair<std::string, std::uint64_t>>>;
|
||||
using Entries = std::map<std::string, std::vector<std::pair<std::string, std::uint64_t>>, 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<std::pair<std::string_view, std::unique_ptr<builder::IFileBuilder>>, 4> builders = {
|
||||
{
|
||||
@ -28,264 +35,199 @@ std::string sanitize_module_name(const std::string& name) {
|
||||
|
||||
template <class IFileBuilder>
|
||||
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<std::uint64_t> get_entity_list() noexcept {
|
||||
const std::optional<std::uint64_t> 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<std::uint64_t> get_global_vars() noexcept {
|
||||
std::optional<std::uint64_t> 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<std::uint64_t> get_local_player() noexcept {
|
||||
std::optional<std::uint64_t> 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<std::uint64_t> get_view_angles() noexcept {
|
||||
std::optional<std::uint64_t> 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<std::uint64_t>(address.value()) + 0x4510;
|
||||
}
|
||||
|
||||
std::optional<std::uint64_t> get_view_matrix() noexcept {
|
||||
const std::optional<std::uint64_t> 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<std::uint64_t>(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<std::uint64_t>(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<std::vector<std::string>> 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<std::uint64_t> 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<std::uint64_t> 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<std::uint64_t> 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<std::uint64_t>(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<std::uint64_t>(interface_registry.value());
|
||||
|
||||
const std::string interface_version_name = process::read_string(process::read_memory<std::uint64_t>(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<std::uint64_t>(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<std::uint64_t> 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<std::uint64_t>(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<std::string, sdk::SchemaClassInfo*>& pair) {
|
||||
spdlog::info(" [{}] @ {:#x}", pair.first, reinterpret_cast<std::uint64_t>(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::milliseconds>(std::chrono::high_resolution_clock::now() - start).count());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
160
src/process.cpp
160
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 <charconv>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include <Windows.h>
|
||||
@ -11,67 +11,72 @@
|
||||
namespace process {
|
||||
std::uint32_t process_id = 0;
|
||||
|
||||
base::SafeHandle process_handle;
|
||||
utility::SafeHandle process_handle;
|
||||
|
||||
namespace detail {
|
||||
std::optional<std::uint32_t> 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<std::uint32_t> 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<std::uintptr_t> 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::int32_t> {
|
||||
std::optional<utility::Address> 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::int32_t> 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<std::uintptr_t> 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<std::int32_t> 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<std::uintptr_t> get_export(const std::uintptr_t module_base, const std::string_view function_name) noexcept {
|
||||
std::optional<std::uintptr_t> 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<std::uintptr_t>(module_entry.modBaseAddr);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::uintptr_t> get_module_export_by_name(const std::uintptr_t module_base, const std::string_view function_name) noexcept {
|
||||
const auto headers = std::make_unique<std::uint8_t[]>(0x1000);
|
||||
|
||||
if (!read_memory(module_base, headers.get(), 0x1000))
|
||||
@ -175,24 +198,15 @@ namespace process {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::uintptr_t> get_export(const std::string_view module_name, const std::string_view function_name) noexcept {
|
||||
const std::optional<std::uintptr_t> 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<std::vector<std::string>> get_loaded_modules() noexcept {
|
||||
const base::SafeHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, process_id));
|
||||
std::optional<std::vector<std::string>> 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<std::string> loaded_modules;
|
||||
|
||||
@ -202,53 +216,23 @@ namespace process {
|
||||
return loaded_modules;
|
||||
}
|
||||
|
||||
std::optional<std::uintptr_t> 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<std::uintptr_t>(module_entry.modBaseAddr);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::uintptr_t> resolve_jmp(const std::uintptr_t address) noexcept {
|
||||
const auto displacement = read_memory<std::int32_t>(address + 0x1);
|
||||
|
||||
return address + displacement + 0x5;
|
||||
}
|
||||
|
||||
std::optional<std::uintptr_t> resolve_rip_relative_address(const std::uintptr_t address) noexcept {
|
||||
const auto displacement = read_memory<std::int32_t>(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<LPCVOID>(address), buffer, size, nullptr);
|
||||
return ReadProcessMemory(process_handle.get(), reinterpret_cast<void*>(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<LPVOID>(address), buffer, size, nullptr);
|
||||
return WriteProcessMemory(process_handle.get(), reinterpret_cast<void*>(address), buffer, size, nullptr);
|
||||
}
|
||||
|
||||
std::string read_string(const std::uintptr_t address, const std::size_t length) noexcept {
|
||||
std::vector<char> 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;
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
#include "sdk/sdk.hpp"
|
||||
|
||||
namespace sdk {
|
||||
std::uint16_t CSchemaClassInfo::get_fields_count() const noexcept {
|
||||
return process::read_memory<std::uint16_t>(reinterpret_cast<std::uint64_t>(this) + 0x1C);
|
||||
}
|
||||
|
||||
std::vector<SchemaClassFieldData_t*> CSchemaClassInfo::get_fields() const noexcept {
|
||||
std::vector<SchemaClassFieldData_t*> fields;
|
||||
|
||||
for (std::size_t i = 0; i < get_fields_count(); ++i) {
|
||||
const auto field = reinterpret_cast<SchemaClassFieldData_t*>(process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x28) + (i * 0x20));
|
||||
|
||||
if (field == nullptr)
|
||||
continue;
|
||||
|
||||
fields.push_back(field);
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
#include "sdk/c_schema_system.hpp"
|
||||
#include "process.hpp"
|
||||
|
||||
namespace sdk {
|
||||
CSchemaSystem* CSchemaSystem::get() noexcept {
|
||||
std::optional<std::uintptr_t> 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<CSchemaSystem*>(address.value());
|
||||
}
|
||||
|
||||
std::vector<CSchemaSystemTypeScope*> CSchemaSystem::get_type_scopes() const noexcept {
|
||||
std::vector<CSchemaSystemTypeScope*> type_scopes;
|
||||
|
||||
type_scopes.resize(process::read_memory<std::uint32_t>(reinterpret_cast<std::uint64_t>(this) + 0x190));
|
||||
|
||||
process::read_memory(process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x198), type_scopes.data(), type_scopes.size() * sizeof(std::uint64_t));
|
||||
|
||||
return type_scopes;
|
||||
}
|
||||
}
|
@ -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<std::uint32_t>(class_name.length()), 0xBAADFEED);
|
||||
|
||||
const std::int32_t hash_transform1 = static_cast<std::uint8_t>(hash >> 0x10) - 0x2D6 + 0x21 * (0x21 * static_cast<std::uint8_t>(hash) + static_cast<std::uint8_t>(hash >> 0x8));
|
||||
const std::int32_t hash_transform2 = 0x21 * hash_transform1 + static_cast<std::uint8_t>(hash >> 0x18);
|
||||
|
||||
const auto hash_part = static_cast<std::uint32_t>(static_cast<std::uint8_t>(hash >> 0x18));
|
||||
|
||||
const std::int32_t hash_transform4 = (hash_transform2 ^ (hash_transform2 >> 0x10)) ^ (static_cast<std::uint16_t>(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<std::uint64_t>(0x28) * static_cast<std::uint8_t>(hash_transform4);
|
||||
|
||||
const auto initial_address = process::read_memory<std::uint64_t>(class_info_address + 0x58);
|
||||
|
||||
std::uint64_t class_address = initial_address;
|
||||
|
||||
if (initial_address != 0) {
|
||||
while (process::read_memory<std::uint32_t>(class_address) != hash) {
|
||||
class_address = process::read_memory<std::uint64_t>(class_address + 0x8);
|
||||
|
||||
if (class_address == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (class_address == 0) {
|
||||
const auto secondary_address = process::read_memory<std::uint64_t>(class_info_address + 0x60);
|
||||
|
||||
std::uint64_t final_address = 0;
|
||||
|
||||
if (secondary_address != 0 && secondary_address != initial_address) {
|
||||
auto current_address = process::read_memory<std::uint64_t>(class_info_address + 0x60);
|
||||
|
||||
const auto starting_address = process::read_memory<std::uint64_t>(class_info_address + 0x58);
|
||||
|
||||
if (current_address != starting_address) {
|
||||
while (process::read_memory<std::uint32_t>(current_address) != hash) {
|
||||
current_address = process::read_memory<std::uint64_t>(current_address + 0x8);
|
||||
|
||||
if (current_address == starting_address)
|
||||
break;
|
||||
}
|
||||
|
||||
final_address = current_address;
|
||||
}
|
||||
}
|
||||
|
||||
class_address = final_address;
|
||||
}
|
||||
|
||||
return reinterpret_cast<CSchemaClassInfo*>(class_address);
|
||||
};
|
||||
|
||||
const CSchemaClassInfo* class_info = get_class_info(reinterpret_cast<std::uint64_t>(this));
|
||||
|
||||
if (class_info != nullptr)
|
||||
return reinterpret_cast<CSchemaClassInfo*>(process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(class_info) + 0x10));
|
||||
|
||||
const auto secondary_class_info = process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x108);
|
||||
|
||||
return secondary_class_info != 0 ? reinterpret_cast<CSchemaClassInfo*>(process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(get_class_info(secondary_class_info)) + 0x10)) : nullptr;
|
||||
}
|
||||
|
||||
std::vector<CSchemaType_DeclaredClass*> CSchemaSystemTypeScope::get_declared_classes() const noexcept {
|
||||
std::vector<CSchemaType_DeclaredClass*> classes;
|
||||
|
||||
const std::uint64_t base = reinterpret_cast<std::uint64_t>(this) + 0x588;
|
||||
|
||||
const auto block_size = process::read_memory<std::uint32_t>(base + 0x4);
|
||||
const auto count = process::read_memory<std::uint32_t>(base + 0x10);
|
||||
const auto unallocated_data = process::read_memory<std::uint64_t>(base + 0x18 + 0x18);
|
||||
|
||||
std::uint32_t index = 0;
|
||||
|
||||
for (std::uint64_t element = unallocated_data; element != 0; element = process::read_memory<std::uint64_t>(element)) {
|
||||
for (std::size_t i = 0; i < block_size && i != count; ++i) {
|
||||
classes.push_back(reinterpret_cast<CSchemaType_DeclaredClass*>(process::read_memory<std::uint64_t>(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<std::uint64_t>(this) + 0x8, 256);
|
||||
}
|
||||
}
|
@ -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<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x8), 64);
|
||||
}
|
||||
}
|
@ -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<std::uint64_t>(reinterpret_cast<std::uint64_t>(this)), 64);
|
||||
}
|
||||
|
||||
std::uint16_t SchemaClassFieldData_t::get_offset() const noexcept {
|
||||
std::uint16_t SchemaClassFieldData::offset() const noexcept {
|
||||
return process::read_memory<std::uint16_t>(reinterpret_cast<std::uint64_t>(this) + 0x10);
|
||||
}
|
||||
}
|
18
src/sdk/schema_class_info.cpp
Normal file
18
src/sdk/schema_class_info.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "sdk/sdk.hpp"
|
||||
|
||||
namespace sdk {
|
||||
std::uint16_t SchemaClassInfo::fields_count() const noexcept {
|
||||
return process::read_memory<std::uint16_t>(reinterpret_cast<std::uint64_t>(this) + 0x1C);
|
||||
}
|
||||
|
||||
void SchemaClassInfo::for_each_field(const std::function<void(SchemaClassFieldData*)>& callback) const noexcept {
|
||||
for (std::size_t i = 0; i < fields_count(); ++i) {
|
||||
const auto field = reinterpret_cast<SchemaClassFieldData*>(process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x28) + (i * 0x20));
|
||||
|
||||
if (field == nullptr)
|
||||
continue;
|
||||
|
||||
callback(field);
|
||||
}
|
||||
}
|
||||
}
|
28
src/sdk/schema_system.cpp
Normal file
28
src/sdk/schema_system.cpp
Normal file
@ -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<SchemaSystem*>();
|
||||
}
|
||||
|
||||
std::vector<SchemaSystemTypeScope*> SchemaSystem::type_scopes() const noexcept {
|
||||
const auto count = process::read_memory<std::uint32_t>(reinterpret_cast<std::uint64_t>(this) + 0x190);
|
||||
const auto data = process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x198);
|
||||
|
||||
if (count == 0 || data == 0)
|
||||
return {};
|
||||
|
||||
std::vector<sdk::SchemaSystemTypeScope*> type_scopes;
|
||||
|
||||
type_scopes.resize(count);
|
||||
|
||||
process::read_memory(data, type_scopes.data(), count * sizeof(std::uint64_t));
|
||||
|
||||
return type_scopes;
|
||||
}
|
||||
}
|
14
src/sdk/schema_system_type_scope.cpp
Normal file
14
src/sdk/schema_system_type_scope.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include "sdk/sdk.hpp"
|
||||
|
||||
namespace sdk {
|
||||
void SchemaSystemTypeScope::for_each_class(const std::function<void(std::pair<std::string, SchemaClassInfo*>)>& callback) const noexcept {
|
||||
const auto classes = process::read_memory<UtlTsHash<SchemaTypeDeclaredClass*>>(reinterpret_cast<std::uint64_t>(this) + 0x588);
|
||||
|
||||
for (const auto& element : classes.elements())
|
||||
callback({ element->binary_name(), reinterpret_cast<SchemaClassInfo*>(element) });
|
||||
}
|
||||
|
||||
std::string SchemaSystemTypeScope::module_name() const noexcept {
|
||||
return process::read_string(reinterpret_cast<std::uint64_t>(this) + 0x8, 256);
|
||||
}
|
||||
}
|
11
src/sdk/schema_type_declared_class.cpp
Normal file
11
src/sdk/schema_type_declared_class.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "sdk/sdk.hpp"
|
||||
|
||||
namespace sdk {
|
||||
std::string SchemaTypeDeclaredClass::binary_name() const noexcept {
|
||||
return process::read_string(process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x8), 64);
|
||||
}
|
||||
|
||||
std::string SchemaTypeDeclaredClass::module_name() const noexcept {
|
||||
return process::read_string(process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x10), 256);
|
||||
}
|
||||
}
|
48
src/utility/address.cpp
Normal file
48
src/utility/address.cpp
Normal file
@ -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<std::uintptr_t>(base);
|
||||
|
||||
return Address(base);
|
||||
}
|
||||
|
||||
bool Address::is_valid() const noexcept {
|
||||
return address_ > static_cast<std::uintptr_t>(0x1000)
|
||||
&& address_ < static_cast<std::uintptr_t>(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<std::int32_t>(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<std::int32_t>(base + offset);
|
||||
|
||||
base += displacement;
|
||||
base += length;
|
||||
|
||||
return Address(base);
|
||||
}
|
||||
}
|
@ -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<const std::uint8_t*>(ptr);
|
||||
|
||||
return static_cast<std::uint32_t>(bytes[0]) | static_cast<std::uint32_t>(bytes[1]) << 0x8 | static_cast<std::uint32_t>(bytes[2]) << 0x10 | static_cast<std::uint32_t>(bytes[3]) << 0x18;
|
||||
};
|
||||
|
||||
constexpr std::uint32_t HASH_CONSTANT = 0x5BD1E995;
|
||||
|
||||
std::uint32_t hash = seed ^ length;
|
||||
|
||||
auto data = static_cast<const std::uint8_t*>(key);
|
||||
|
||||
while (length >= 4) {
|
||||
std::uint32_t block = get_block(reinterpret_cast<const std::uint32_t*>(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;
|
||||
}
|
||||
}
|
4
vendor/CMakeLists.txt
generated
vendored
4
vendor/CMakeLists.txt
generated
vendored
@ -1,4 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
add_subdirectory(nlohmann_json)
|
||||
add_subdirectory(spdlog)
|
1
vendor/nlohmann_json
vendored
1
vendor/nlohmann_json
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 836b7beca4b62e2a99465edef44066b7401fd704
|
1
vendor/spdlog
vendored
1
vendor/spdlog
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 3aceda041b2bfbccaf14d5c83eda16fc67bea364
|
Loading…
x
Reference in New Issue
Block a user