mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 15:03:27 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 568883ff1c | |||
| 97003b953a | |||
| 5646654317 | |||
| ee54e3de34 | |||
| 7b0af9cf66 | |||
| 563ae0a656 | |||
| b9e2307d7a | |||
| cd0a864e7c | |||
| 5c30f57c4c | |||
| 3dcd033616 | |||
| f10dc60772 | |||
| 37f624956b | |||
| 20dc4e6730 | |||
| f6c607d84c | |||
| 81ed5f80d7 | |||
|
|
e385686323 |
@@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
project(omath VERSION 3.8.2 LANGUAGES CXX)
|
||||
project(omath VERSION 3.9.2 LANGUAGES CXX)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CheckCXXCompilerFlag)
|
||||
@@ -28,22 +28,23 @@ if (OMATH_USE_AVX2 AND NOT COMPILER_SUPPORTS_AVX2)
|
||||
set(OMATH_USE_AVX2 OFF CACHE BOOL "Omath will use AVX2 to boost performance" FORCE)
|
||||
endif ()
|
||||
|
||||
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}, compiler ${CMAKE_CXX_COMPILER_ID}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Warnings as errors ${OMATH_THREAT_WARNING_AS_ERROR}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Build unit tests ${OMATH_BUILD_TESTS}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Build benchmark ${OMATH_BUILD_BENCHMARK}")
|
||||
message(STATUS "[${PROJECT_NAME}]: As dynamic library ${OMATH_BUILD_AS_SHARED_LIBRARY}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Static C++ runtime ${OMATH_STATIC_MSVC_RUNTIME_LIBRARY}")
|
||||
message(STATUS "[${PROJECT_NAME}]: CMake unity build ${OMATH_USE_UNITY_BUILD}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Example projects ${OMATH_BUILD_EXAMPLES}")
|
||||
message(STATUS "[${PROJECT_NAME}]: AVX2 feature status ${OMATH_USE_AVX2}")
|
||||
message(STATUS "[${PROJECT_NAME}]: ImGUI integration feature status ${OMATH_IMGUI_INTEGRATION}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Legacy features support ${OMATH_ENABLE_LEGACY}")
|
||||
if (${PROJECT_IS_TOP_LEVEL})
|
||||
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}, compiler ${CMAKE_CXX_COMPILER_ID}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Warnings as errors ${OMATH_THREAT_WARNING_AS_ERROR}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Build unit tests ${OMATH_BUILD_TESTS}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Build benchmark ${OMATH_BUILD_BENCHMARK}")
|
||||
message(STATUS "[${PROJECT_NAME}]: As dynamic library ${OMATH_BUILD_AS_SHARED_LIBRARY}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Static C++ runtime ${OMATH_STATIC_MSVC_RUNTIME_LIBRARY}")
|
||||
message(STATUS "[${PROJECT_NAME}]: CMake unity build ${OMATH_USE_UNITY_BUILD}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Example projects ${OMATH_BUILD_EXAMPLES}")
|
||||
message(STATUS "[${PROJECT_NAME}]: AVX2 feature status ${OMATH_USE_AVX2}")
|
||||
message(STATUS "[${PROJECT_NAME}]: ImGUI integration feature status ${OMATH_IMGUI_INTEGRATION}")
|
||||
message(STATUS "[${PROJECT_NAME}]: Legacy features support ${OMATH_ENABLE_LEGACY}")
|
||||
endif ()
|
||||
|
||||
file(GLOB_RECURSE OMATH_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
|
||||
file(GLOB_RECURSE OMATH_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
|
||||
|
||||
|
||||
if (OMATH_BUILD_AS_SHARED_LIBRARY)
|
||||
add_library(${PROJECT_NAME} SHARED ${OMATH_SOURCES} ${OMATH_HEADERS})
|
||||
else ()
|
||||
@@ -111,8 +112,8 @@ if (OMATH_USE_AVX2)
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC -msimd128 -mavx2)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC -mfma -mavx2)
|
||||
endif()
|
||||
endif()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ It provides the latest features, is highly customizable, has all for cheat devel
|
||||
- **Ready for meta-programming**: Omath use templates for common types like Vectors, Matrixes etc, to handle all types!
|
||||
- **Engine support**: Supports coordinate systems of Source, Unity, Unreal, IWEngine and canonical OpenGL.
|
||||
- **Cross platform**: Supports Windows, MacOS and Linux.
|
||||
- **Algorithms**: Has ability to scan for byte pattern with wildcards in PE files/modules, binary slices, works even with Wine apps.
|
||||
<div align = center>
|
||||
|
||||
# Gallery
|
||||
|
||||
@@ -245,15 +245,6 @@ namespace omath
|
||||
return std::make_tuple(this->x, this->y, z);
|
||||
}
|
||||
|
||||
[[nodiscard]] Vector3 view_angle_to(const Vector3& other) const noexcept
|
||||
{
|
||||
const auto distance = distance_to(other);
|
||||
const auto delta = other - *this;
|
||||
|
||||
return {angles::radians_to_degrees(std::asin(delta.z / distance)),
|
||||
angles::radians_to_degrees(std::atan2(delta.y, delta.x)), 0};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool operator<(const Vector3& other) const noexcept
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace omath::rev_eng
|
||||
#ifdef _MSC_VER
|
||||
using VirtualMethodType = ReturnType(__thiscall*)(void*, decltype(arg_list)...);
|
||||
#else
|
||||
using VirtualMethodType = ReturnType(__fastcall*)(void*, decltype(arg_list)...);
|
||||
using VirtualMethodType = ReturnType(*)(void*, decltype(arg_list)...);
|
||||
#endif
|
||||
return (*reinterpret_cast<VirtualMethodType**>(this))[id](this, arg_list...);
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
//
|
||||
// Created by Vlad on 10/8/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
@@ -1,32 +0,0 @@
|
||||
//
|
||||
// Created by Vlad on 10/7/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace omath::system::pe
|
||||
{
|
||||
struct DosHeader final
|
||||
{
|
||||
std::uint16_t e_magic;
|
||||
std::uint16_t e_cblp;
|
||||
std::uint16_t e_cp;
|
||||
std::uint16_t e_crlc;
|
||||
std::uint16_t e_cparhdr;
|
||||
std::uint16_t e_minalloc;
|
||||
std::uint16_t e_maxalloc;
|
||||
std::uint16_t e_ss;
|
||||
std::uint16_t e_sp;
|
||||
std::uint16_t e_csum;
|
||||
std::uint16_t e_ip;
|
||||
std::uint16_t e_cs;
|
||||
std::uint16_t e_lfarlc;
|
||||
std::uint16_t e_ovno;
|
||||
std::uint16_t e_res[4];
|
||||
std::uint16_t e_oemid;
|
||||
std::uint16_t e_oeminfo;
|
||||
std::uint16_t e_res2[10];
|
||||
std::uint32_t e_lfanew;
|
||||
};
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
//
|
||||
// Created by Vlad on 10/7/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace omath::system::pe
|
||||
{
|
||||
enum class MachineId : std::uint16_t
|
||||
{
|
||||
UNKNOWN = 0x0000,
|
||||
TARGET_HOST = 0x0001, // Useful for indicating we want to interact with the host and not a WoW guest.
|
||||
I386 = 0x014C, // Intel 386.
|
||||
R3000 = 0x0162, // MIPS little-endian, 0x160 big-endian
|
||||
R4000 = 0x0166, // MIPS little-endian
|
||||
R10000 = 0x0168, // MIPS little-endian
|
||||
WCEMIPSV2 = 0x0169, // MIPS little-endian WCE v2
|
||||
ALPHA = 0x0184, // Alpha_AXP
|
||||
SH3 = 0x01A2, // SH3 little-endian
|
||||
SH3DSP = 0x01A3,
|
||||
SH3E = 0x01A4, // SH3E little-endian
|
||||
SH4 = 0x01A6, // SH4 little-endian
|
||||
SH5 = 0x01A8, // SH5
|
||||
ARM = 0x01C0, // ARM Little-Endian
|
||||
THUMB = 0x01C2, // ARM Thumb/Thumb-2 Little-Endian
|
||||
ARMNT = 0x01C4, // ARM Thumb-2 Little-Endian
|
||||
AM33 = 0x01D3,
|
||||
POWERPC = 0x01F0, // IBM PowerPC Little-Endian
|
||||
POWERPCP = 0x01F1,
|
||||
IA64 = 0x0200, // Intel 64
|
||||
MIPS16 = 0x0266, // MIPS
|
||||
ALPHA64 = 0x0284, // ALPHA64
|
||||
MIPSFPU = 0x0366, // MIPS
|
||||
MIPSFPU16 = 0x0466, // MIPS
|
||||
AXP64 = 0x0284,
|
||||
TRICORE = 0x0520, // Infineon
|
||||
CEF = 0x0CEF,
|
||||
EBC = 0x0EBC, // EFI Byte Code
|
||||
AMD64 = 0x8664, // AMD64 (K8)
|
||||
M32R = 0x9041, // M32R little-endian
|
||||
ARM64 = 0xAA64, // ARM64 Little-Endian
|
||||
CEE = 0xC0EE,
|
||||
};
|
||||
|
||||
struct FileHeader final
|
||||
{
|
||||
MachineId machine;
|
||||
uint16_t num_sections;
|
||||
uint32_t timedate_stamp;
|
||||
uint32_t ptr_symbols;
|
||||
uint32_t num_symbols;
|
||||
uint16_t size_optional_header;
|
||||
std::uint16_t characteristics;
|
||||
};
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
//
|
||||
// Created by Vlad on 10/9/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "file_header.hpp"
|
||||
#include "optional_header.hpp"
|
||||
|
||||
namespace omath::system::pe
|
||||
{
|
||||
enum class NtArchitecture
|
||||
{
|
||||
x32_bit,
|
||||
x64_bit,
|
||||
};
|
||||
template<NtArchitecture architecture>
|
||||
struct ImageNtHeaders final
|
||||
{
|
||||
std::uint32_t signature;
|
||||
FileHeader file_header;
|
||||
OptionalHeader<architecture == NtArchitecture::x64_bit> optional_header;
|
||||
};
|
||||
} // namespace omath::system::pe
|
||||
@@ -1,118 +0,0 @@
|
||||
//
|
||||
// Created by Vlad on 10/8/2025.
|
||||
//
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace omath::system::pe
|
||||
{
|
||||
static constexpr std::uint16_t opt_hdr32_magic = 0x010B;
|
||||
static constexpr std::uint16_t opt_hdr64_magic = 0x020B;
|
||||
enum class SubsystemId : std::uint16_t
|
||||
{
|
||||
unknown = 0x0000,
|
||||
native = 0x0001,
|
||||
windows_gui = 0x0002,
|
||||
windows_cui = 0x0003,
|
||||
os2_cui = 0x0005,
|
||||
posix_cui = 0x0007,
|
||||
native_windows = 0x0008,
|
||||
windows_ce_gui = 0x0009,
|
||||
efi_application = 0x000A,
|
||||
efi_boot_service_driver = 0x000B,
|
||||
efi_runtime_driver = 0x000C,
|
||||
efi_rom = 0x000D,
|
||||
xbox = 0x000E,
|
||||
windows_boot_application = 0x0010,
|
||||
xbox_code_catalog = 0x0011,
|
||||
};
|
||||
|
||||
struct DataDirectory final
|
||||
{
|
||||
std::uint32_t rva;
|
||||
std::uint32_t size;
|
||||
};
|
||||
struct OptionalHeaderX64 final
|
||||
{
|
||||
// Standard fields.
|
||||
std::uint16_t magic;
|
||||
std::uint16_t linker_version;
|
||||
|
||||
std::uint32_t size_code;
|
||||
std::uint32_t size_init_data;
|
||||
std::uint32_t size_uninit_data;
|
||||
|
||||
std::uint32_t entry_point;
|
||||
std::uint32_t base_of_code;
|
||||
|
||||
// NT additional fields.
|
||||
std::uint64_t image_base;
|
||||
std::uint32_t section_alignment;
|
||||
std::uint32_t file_alignment;
|
||||
|
||||
std::uint32_t os_version;
|
||||
std::uint32_t img_version;
|
||||
std::uint32_t subsystem_version;
|
||||
std::uint32_t win32_version_value;
|
||||
|
||||
std::uint32_t size_image;
|
||||
std::uint32_t size_headers;
|
||||
|
||||
std::uint32_t checksum;
|
||||
SubsystemId subsystem;
|
||||
std::uint16_t characteristics;
|
||||
|
||||
std::uint64_t size_stack_reserve;
|
||||
std::uint64_t size_stack_commit;
|
||||
std::uint64_t size_heap_reserve;
|
||||
std::uint64_t size_heap_commit;
|
||||
|
||||
std::uint32_t ldr_flags;
|
||||
|
||||
std::uint32_t num_data_directories;
|
||||
DataDirectory data_directories[16];
|
||||
};
|
||||
struct OptionalHeaderX86 final
|
||||
{
|
||||
// Standard fields.
|
||||
uint16_t magic;
|
||||
uint16_t linker_version;
|
||||
|
||||
uint32_t size_code;
|
||||
uint32_t size_init_data;
|
||||
uint32_t size_uninit_data;
|
||||
|
||||
uint32_t entry_point;
|
||||
uint32_t base_of_code;
|
||||
uint32_t base_of_data;
|
||||
|
||||
// NT additional fields.
|
||||
uint32_t image_base;
|
||||
uint32_t section_alignment;
|
||||
uint32_t file_alignment;
|
||||
|
||||
std::uint32_t os_version;
|
||||
std::uint32_t img_version;
|
||||
std::uint32_t subsystem_version;
|
||||
uint32_t win32_version_value;
|
||||
|
||||
uint32_t size_image;
|
||||
uint32_t size_headers;
|
||||
|
||||
uint32_t checksum;
|
||||
SubsystemId subsystem;
|
||||
std::uint16_t characteristics;
|
||||
|
||||
uint32_t size_stack_reserve;
|
||||
uint32_t size_stack_commit;
|
||||
uint32_t size_heap_reserve;
|
||||
uint32_t size_heap_commit;
|
||||
|
||||
uint32_t ldr_flags;
|
||||
|
||||
uint32_t num_data_directories;
|
||||
DataDirectory data_directories[16];
|
||||
};
|
||||
template<bool x64 = true>
|
||||
using OptionalHeader = std::conditional_t<x64, OptionalHeaderX64, OptionalHeaderX86>;
|
||||
} // namespace omath::system::pe
|
||||
@@ -1,32 +0,0 @@
|
||||
//
|
||||
// Created by Vlad on 10/8/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// Section header
|
||||
//
|
||||
namespace omath::system::pe
|
||||
{
|
||||
struct SectionHeader final
|
||||
{
|
||||
char name[8];
|
||||
union
|
||||
{
|
||||
std::uint32_t physical_address;
|
||||
std::uint32_t virtual_size;
|
||||
};
|
||||
std::uint32_t virtual_address;
|
||||
|
||||
std::uint32_t size_raw_data;
|
||||
std::uint32_t ptr_raw_data;
|
||||
|
||||
std::uint32_t ptr_relocs;
|
||||
std::uint32_t ptr_line_numbers;
|
||||
std::uint32_t num_relocs;
|
||||
std::uint32_t num_line_numbers;
|
||||
|
||||
std::uint32_t characteristics;
|
||||
};
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
namespace omath
|
||||
{
|
||||
struct PeSectionScanResult
|
||||
@@ -18,26 +17,14 @@ namespace omath
|
||||
};
|
||||
class PePatternScanner final
|
||||
{
|
||||
private:
|
||||
struct Section
|
||||
{
|
||||
std::uint64_t virtual_base_addr;
|
||||
std::uint64_t raw_base_addr;
|
||||
std::vector<std::byte> data;
|
||||
};
|
||||
|
||||
public:
|
||||
[[nodiscard]]
|
||||
static std::optional<std::uintptr_t> scan_for_pattern_in_loaded_module(const std::string_view& module_name,
|
||||
static std::optional<std::uintptr_t> scan_for_pattern_in_loaded_module(const void* module_base_address,
|
||||
const std::string_view& pattern);
|
||||
|
||||
[[nodiscard]]
|
||||
static std::optional<PeSectionScanResult>
|
||||
scan_for_pattern_in_file(const std::filesystem::path& path_to_file, const std::string_view& pattern,
|
||||
const std::string_view& target_section_name = ".text");
|
||||
|
||||
[[nodiscard]]
|
||||
static std::optional<Section> extract_section_from_pe_file(const std::filesystem::path& path_to_file,
|
||||
const std::string_view& section_name);
|
||||
};
|
||||
} // namespace omath
|
||||
@@ -2,40 +2,227 @@
|
||||
// Created by Vlad on 10/7/2025.
|
||||
//
|
||||
#include "omath/utility/pe_pattern_scan.hpp"
|
||||
#include "omath/system/pe/image_nt_headers.hpp"
|
||||
#include "omath/system/pe/section_header.hpp"
|
||||
#include "omath/utility/pattern_scan.hpp"
|
||||
#include <fstream>
|
||||
#include <omath/system/pe/dos_header.hpp>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <variant>
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
using namespace omath::system::pe;
|
||||
using NtHeaderVariant = std::variant<ImageNtHeaders<NtArchitecture::x64_bit>, ImageNtHeaders<NtArchitecture::x32_bit>>;
|
||||
// Internal PE shit defines
|
||||
// Big thx for linuxpe sources as ref
|
||||
// Link: https://github.com/can1357/linux-pe
|
||||
namespace
|
||||
{
|
||||
constexpr std::uint16_t opt_hdr32_magic = 0x010B;
|
||||
constexpr std::uint16_t opt_hdr64_magic = 0x020B;
|
||||
|
||||
// Standard fields.
|
||||
// ReSharper disable CppDeclaratorNeverUsed
|
||||
struct DataDirectory final
|
||||
{
|
||||
std::uint32_t rva;
|
||||
std::uint32_t size;
|
||||
};
|
||||
struct OptionalHeaderX64 final
|
||||
{
|
||||
std::uint16_t magic;
|
||||
|
||||
std::uint16_t linker_version;
|
||||
|
||||
std::uint32_t size_code;
|
||||
std::uint32_t size_init_data;
|
||||
std::uint32_t size_uninit_data;
|
||||
|
||||
std::uint32_t entry_point;
|
||||
std::uint32_t base_of_code;
|
||||
|
||||
// NT additional fields.
|
||||
std::uint64_t image_base;
|
||||
std::uint32_t section_alignment;
|
||||
std::uint32_t file_alignment;
|
||||
|
||||
std::uint32_t os_version;
|
||||
std::uint32_t img_version;
|
||||
std::uint32_t subsystem_version;
|
||||
std::uint32_t win32_version_value;
|
||||
|
||||
std::uint32_t size_image;
|
||||
std::uint32_t size_headers;
|
||||
|
||||
std::uint32_t checksum;
|
||||
std::uint16_t subsystem;
|
||||
std::uint16_t characteristics;
|
||||
|
||||
std::uint64_t size_stack_reserve;
|
||||
std::uint64_t size_stack_commit;
|
||||
std::uint64_t size_heap_reserve;
|
||||
std::uint64_t size_heap_commit;
|
||||
|
||||
std::uint32_t ldr_flags;
|
||||
|
||||
std::uint32_t num_data_directories;
|
||||
DataDirectory data_directories[16];
|
||||
};
|
||||
struct OptionalHeaderX86 final
|
||||
{
|
||||
// Standard fields.
|
||||
std::uint16_t magic{};
|
||||
std::uint16_t linker_version{};
|
||||
|
||||
std::uint32_t size_code{};
|
||||
std::uint32_t size_init_data{};
|
||||
std::uint32_t size_uninit_data{};
|
||||
|
||||
std::uint32_t entry_point{};
|
||||
std::uint32_t base_of_code{};
|
||||
std::uint32_t base_of_data{};
|
||||
|
||||
// NT additional fields.
|
||||
std::uint32_t image_base{};
|
||||
std::uint32_t section_alignment{};
|
||||
std::uint32_t file_alignment{};
|
||||
|
||||
std::uint32_t os_version{};
|
||||
std::uint32_t img_version{};
|
||||
std::uint32_t subsystem_version{};
|
||||
std::uint32_t win32_version_value{};
|
||||
|
||||
std::uint32_t size_image{};
|
||||
std::uint32_t size_headers{};
|
||||
|
||||
std::uint32_t checksum{};
|
||||
std::uint16_t subsystem{};
|
||||
std::uint16_t characteristics{};
|
||||
|
||||
std::uint32_t size_stack_reserve{};
|
||||
std::uint32_t size_stack_commit{};
|
||||
std::uint32_t size_heap_reserve{};
|
||||
std::uint32_t size_heap_commit{};
|
||||
|
||||
std::uint32_t ldr_flags{};
|
||||
|
||||
std::uint32_t num_data_directories{};
|
||||
DataDirectory data_directories[16]{};
|
||||
};
|
||||
template<bool x64 = true>
|
||||
using OptionalHeader = std::conditional_t<x64, OptionalHeaderX64, OptionalHeaderX86>;
|
||||
|
||||
struct FileHeader final
|
||||
{
|
||||
std::uint16_t machine;
|
||||
std::uint16_t num_sections;
|
||||
std::uint32_t timedate_stamp;
|
||||
std::uint32_t ptr_symbols;
|
||||
std::uint32_t num_symbols;
|
||||
std::uint16_t size_optional_header;
|
||||
std::uint16_t characteristics;
|
||||
};
|
||||
|
||||
struct DosHeader final
|
||||
{
|
||||
std::uint16_t e_magic;
|
||||
std::uint16_t e_cblp;
|
||||
std::uint16_t e_cp;
|
||||
std::uint16_t e_crlc;
|
||||
std::uint16_t e_cparhdr;
|
||||
std::uint16_t e_minalloc;
|
||||
std::uint16_t e_maxalloc;
|
||||
std::uint16_t e_ss;
|
||||
std::uint16_t e_sp;
|
||||
std::uint16_t e_csum;
|
||||
std::uint16_t e_ip;
|
||||
std::uint16_t e_cs;
|
||||
std::uint16_t e_lfarlc;
|
||||
std::uint16_t e_ovno;
|
||||
std::uint16_t e_res[4];
|
||||
std::uint16_t e_oemid;
|
||||
std::uint16_t e_oeminfo;
|
||||
std::uint16_t e_res2[10];
|
||||
std::uint32_t e_lfanew;
|
||||
};
|
||||
|
||||
enum class NtArchitecture
|
||||
{
|
||||
x32_bit,
|
||||
x64_bit,
|
||||
};
|
||||
template<NtArchitecture architecture>
|
||||
struct ImageNtHeaders final
|
||||
{
|
||||
std::uint32_t signature;
|
||||
FileHeader file_header;
|
||||
OptionalHeader<architecture == NtArchitecture::x64_bit> optional_header;
|
||||
};
|
||||
|
||||
struct SectionHeader final
|
||||
{
|
||||
char name[8];
|
||||
union
|
||||
{
|
||||
std::uint32_t physical_address;
|
||||
std::uint32_t virtual_size;
|
||||
};
|
||||
std::uint32_t virtual_address;
|
||||
|
||||
std::uint32_t size_raw_data;
|
||||
std::uint32_t ptr_raw_data;
|
||||
|
||||
std::uint32_t ptr_relocs;
|
||||
std::uint32_t ptr_line_numbers;
|
||||
std::uint32_t num_relocs;
|
||||
std::uint32_t num_line_numbers;
|
||||
|
||||
std::uint32_t characteristics;
|
||||
};
|
||||
// ReSharper restore CppDeclaratorNeverUsed
|
||||
|
||||
using NtHeaderVariant =
|
||||
std::variant<ImageNtHeaders<NtArchitecture::x64_bit>, ImageNtHeaders<NtArchitecture::x32_bit>>;
|
||||
} // namespace
|
||||
|
||||
// Internal PE scanner functions
|
||||
namespace
|
||||
{
|
||||
[[nodiscard]]
|
||||
NtHeaderVariant get_nt_header_from_file(std::fstream& file, const DosHeader& dos_header)
|
||||
std::optional<NtHeaderVariant> get_nt_header_from_file(std::fstream& file, const DosHeader& dos_header)
|
||||
{
|
||||
ImageNtHeaders<NtArchitecture::x32_bit> x86_headers;
|
||||
ImageNtHeaders<NtArchitecture::x32_bit> x86_headers{};
|
||||
file.seekg(dos_header.e_lfanew, std::ios::beg);
|
||||
file.read(reinterpret_cast<char*>(&x86_headers), sizeof(x86_headers));
|
||||
|
||||
if (x86_headers.optional_header.magic == opt_hdr32_magic)
|
||||
return x86_headers;
|
||||
|
||||
ImageNtHeaders<NtArchitecture::x64_bit> x64_headers;
|
||||
if (x86_headers.optional_header.magic != opt_hdr64_magic)
|
||||
return std::nullopt;
|
||||
|
||||
ImageNtHeaders<NtArchitecture::x64_bit> x64_headers{};
|
||||
file.seekg(dos_header.e_lfanew, std::ios::beg);
|
||||
file.read(reinterpret_cast<char*>(&x64_headers), sizeof(x64_headers));
|
||||
|
||||
return x64_headers;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::optional<NtHeaderVariant> get_nt_header_from_loaded_module(const void* module_base_address)
|
||||
{
|
||||
const auto module_byte_ptr = static_cast<const std::byte*>(module_base_address);
|
||||
ImageNtHeaders<NtArchitecture::x32_bit> x86_headers{};
|
||||
const auto dos_header = static_cast<const DosHeader*>(module_base_address);
|
||||
|
||||
x86_headers = *reinterpret_cast<const ImageNtHeaders<NtArchitecture::x32_bit>*>(module_byte_ptr
|
||||
+ dos_header->e_lfanew);
|
||||
|
||||
if (x86_headers.optional_header.magic == opt_hdr32_magic)
|
||||
return x86_headers;
|
||||
|
||||
if (x86_headers.optional_header.magic != opt_hdr64_magic)
|
||||
return std::nullopt;
|
||||
|
||||
return *reinterpret_cast<const ImageNtHeaders<NtArchitecture::x64_bit>*>(module_byte_ptr
|
||||
+ dos_header->e_lfanew);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr bool invalid_dos_header_file(const DosHeader& dos_header)
|
||||
{
|
||||
@@ -48,39 +235,105 @@ namespace
|
||||
constexpr std::uint32_t nt_hdr_magic = 0x4550;
|
||||
return std::visit([](const auto& header) -> bool { return header.signature != nt_hdr_magic; }, variant);
|
||||
}
|
||||
|
||||
struct ExtractedSection
|
||||
{
|
||||
std::uint64_t virtual_base_addr;
|
||||
std::uint64_t raw_base_addr;
|
||||
std::vector<std::byte> data;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
std::optional<ExtractedSection> extract_section_from_pe_file(const std::filesystem::path& path_to_file,
|
||||
const std::string_view& section_name)
|
||||
{
|
||||
std::fstream file(path_to_file, std::ios::binary | std::ios::in);
|
||||
|
||||
if (!file.is_open()) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
DosHeader dos_header{};
|
||||
file.read(reinterpret_cast<char*>(&dos_header), sizeof(dos_header));
|
||||
|
||||
if (invalid_dos_header_file(dos_header)) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
const auto nt_headers = get_nt_header_from_file(file, dos_header);
|
||||
|
||||
if (!nt_headers)
|
||||
return std::nullopt;
|
||||
|
||||
if (invalid_nt_header_file(nt_headers.value())) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
return std::visit(
|
||||
[&file, &dos_header, §ion_name](auto& concrete_headers) -> std::optional<ExtractedSection>
|
||||
{
|
||||
constexpr std::size_t size_of_signature = sizeof(concrete_headers.signature);
|
||||
const auto offset_to_segment_table = dos_header.e_lfanew
|
||||
+ concrete_headers.file_header.size_optional_header
|
||||
+ sizeof(FileHeader) + size_of_signature;
|
||||
|
||||
file.seekg(static_cast<std::fstream::off_type>(offset_to_segment_table), std::ios::beg);
|
||||
|
||||
for (std::size_t i = 0; i < concrete_headers.file_header.num_sections; i++)
|
||||
{
|
||||
SectionHeader current_section{};
|
||||
file.read(reinterpret_cast<char*>(¤t_section), sizeof(current_section));
|
||||
|
||||
if (std::string_view(current_section.name) != section_name)
|
||||
continue;
|
||||
|
||||
std::vector<std::byte> section_data(current_section.size_raw_data);
|
||||
|
||||
file.seekg(current_section.ptr_raw_data, std::ios::beg);
|
||||
file.read(reinterpret_cast<char*>(section_data.data()),
|
||||
static_cast<std::streamsize>(section_data.size()));
|
||||
return ExtractedSection{.virtual_base_addr = current_section.virtual_address
|
||||
+ concrete_headers.optional_header.image_base,
|
||||
.raw_base_addr = current_section.ptr_raw_data,
|
||||
.data = std::move(section_data)};
|
||||
}
|
||||
return std::nullopt;
|
||||
},
|
||||
nt_headers.value());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace omath
|
||||
{
|
||||
|
||||
std::optional<std::uintptr_t>
|
||||
PePatternScanner::scan_for_pattern_in_loaded_module([[maybe_unused]] const std::string_view& module_name,
|
||||
[[maybe_unused]] const std::string_view& pattern)
|
||||
std::optional<std::uintptr_t> PePatternScanner::scan_for_pattern_in_loaded_module(const void* module_base_address,
|
||||
const std::string_view& pattern)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const auto base_address = reinterpret_cast<std::uintptr_t>(GetModuleHandleA(module_name.data()));
|
||||
const auto base_address = reinterpret_cast<std::uintptr_t>(module_base_address);
|
||||
|
||||
if (!base_address)
|
||||
return std::nullopt;
|
||||
|
||||
const auto dos_headers = reinterpret_cast<PIMAGE_DOS_HEADER>(base_address);
|
||||
const auto image_nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS>(base_address + dos_headers->e_lfanew);
|
||||
auto nt_header_variant = get_nt_header_from_loaded_module(module_base_address);
|
||||
|
||||
// Define .code segment as scan area
|
||||
const auto start = image_nt_headers->OptionalHeader.BaseOfCode;
|
||||
const auto scan_size = image_nt_headers->OptionalHeader.SizeOfCode;
|
||||
if (!nt_header_variant)
|
||||
return std::nullopt;
|
||||
|
||||
const auto scan_range = std::span{reinterpret_cast<std::byte*>(base_address) + start, scan_size};
|
||||
return std::visit(
|
||||
[base_address, &pattern](const auto& nt_header) -> std::optional<std::uintptr_t>
|
||||
{
|
||||
// Define .code segment as scan area
|
||||
const auto start = nt_header.optional_header.base_of_code;
|
||||
const auto scan_size = nt_header.optional_header.size_code;
|
||||
|
||||
const auto result = PatternScanner::scan_for_pattern(scan_range, pattern);
|
||||
const auto scan_range = std::span{reinterpret_cast<std::byte*>(base_address) + start, scan_size};
|
||||
|
||||
if (result != scan_range.cend())
|
||||
return reinterpret_cast<std::uintptr_t>(&*result);
|
||||
// ReSharper disable once CppTooWideScopeInitStatement
|
||||
const auto result = PatternScanner::scan_for_pattern(scan_range, pattern);
|
||||
|
||||
return std::nullopt;
|
||||
#else
|
||||
throw std::runtime_error("Pattern scan for loaded modules is only for windows platform");
|
||||
#endif
|
||||
if (result != scan_range.cend())
|
||||
return reinterpret_cast<std::uintptr_t>(&*result);
|
||||
|
||||
return std::nullopt;
|
||||
},
|
||||
nt_header_variant.value());
|
||||
}
|
||||
std::optional<PeSectionScanResult>
|
||||
PePatternScanner::scan_for_pattern_in_file(const std::filesystem::path& path_to_file,
|
||||
@@ -103,56 +356,4 @@ namespace omath
|
||||
.raw_base_addr = pe_section->raw_base_addr,
|
||||
.target_offset = offset};
|
||||
}
|
||||
std::optional<PePatternScanner::Section>
|
||||
PePatternScanner::extract_section_from_pe_file(const std::filesystem::path& path_to_file,
|
||||
const std::string_view& section_name)
|
||||
{
|
||||
std::fstream file(path_to_file, std::ios::binary | std::ios::in);
|
||||
|
||||
if (!file.is_open()) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
DosHeader dos_header{};
|
||||
file.read(reinterpret_cast<char*>(&dos_header), sizeof(dos_header));
|
||||
|
||||
if (invalid_dos_header_file(dos_header)) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
const auto nt_headers = get_nt_header_from_file(file, dos_header);
|
||||
|
||||
if (invalid_nt_header_file(nt_headers)) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
return std::visit(
|
||||
[&file, &dos_header, §ion_name](auto& concrete_headers) -> std::optional<Section>
|
||||
{
|
||||
constexpr std::size_t size_of_signature = sizeof(concrete_headers.signature);
|
||||
const auto offset_to_segment_table = dos_header.e_lfanew
|
||||
+ concrete_headers.file_header.size_optional_header
|
||||
+ sizeof(FileHeader) + size_of_signature;
|
||||
|
||||
file.seekg(static_cast<std::fstream::off_type>(offset_to_segment_table), std::ios::beg);
|
||||
|
||||
for (std::size_t i = 0; i < concrete_headers.file_header.num_sections; i++)
|
||||
{
|
||||
SectionHeader current_section{};
|
||||
file.read(reinterpret_cast<char*>(¤t_section), sizeof(current_section));
|
||||
|
||||
if (std::string_view(current_section.name) != section_name)
|
||||
continue;
|
||||
|
||||
std::vector<std::byte> section_data(current_section.size_raw_data);
|
||||
|
||||
file.seekg(current_section.ptr_raw_data, std::ios::beg);
|
||||
file.read(reinterpret_cast<char*>(section_data.data()),
|
||||
static_cast<std::streamsize>(section_data.size()));
|
||||
return Section{.virtual_base_addr = current_section.virtual_address
|
||||
+ concrete_headers.optional_header.image_base,
|
||||
.raw_base_addr = current_section.ptr_raw_data,
|
||||
.data = std::move(section_data)};
|
||||
}
|
||||
return std::nullopt;
|
||||
},
|
||||
nt_headers);
|
||||
}
|
||||
} // namespace omath
|
||||
@@ -16,5 +16,4 @@ set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE gtest gtest_main omath::omath)
|
||||
|
||||
gtest_discover_tests(${PROJECT_NAME})
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <omath/projectile_prediction/proj_pred_engine_legacy.hpp>
|
||||
|
||||
#include <omath/engines/source_engine/traits/camera_trait.hpp>
|
||||
TEST(UnitTestPrediction, PredictionTest)
|
||||
{
|
||||
constexpr omath::projectile_prediction::Target target{
|
||||
@@ -10,8 +10,9 @@ TEST(UnitTestPrediction, PredictionTest)
|
||||
const auto viewPoint =
|
||||
omath::projectile_prediction::ProjPredEngineLegacy(400, 1.f / 1000.f, 50, 5.f).maybe_calculate_aim_point(proj, target);
|
||||
|
||||
const auto [pitch, yaw, _] = proj.m_origin.view_angle_to(viewPoint.value()).as_tuple();
|
||||
|
||||
EXPECT_NEAR(42.547142, pitch, 0.01f);
|
||||
EXPECT_NEAR(-1.181189, yaw, 0.01f);
|
||||
const auto [pitch, yaw, _] =omath::source_engine::CameraTrait::calc_look_at_angle(proj.m_origin, viewPoint.value());
|
||||
|
||||
EXPECT_NEAR(-42.547142, pitch.as_degrees(), 0.01f);
|
||||
EXPECT_NEAR(-1.181189, yaw.as_degrees(), 0.01f);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user