boiii arxan bypass

https://github.com/momo5502/boiii
This commit is contained in:
quaK 2022-09-17 20:25:07 +03:00
parent 58dc53850b
commit 7b1a343014
5 changed files with 471 additions and 80 deletions

View File

@ -3,9 +3,11 @@
#include "game/game.hpp" #include "game/game.hpp"
#include "game_module.hpp"
#include "scheduler.hpp" #include "scheduler.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp>
namespace arxan namespace arxan
{ {
@ -18,6 +20,11 @@ namespace arxan
#define ProcessDebugObjectHandle 30 // WinXP source says 31? #define ProcessDebugObjectHandle 30 // WinXP source says 31?
#define ProcessDebugFlags 31 // WinXP source says 32? #define ProcessDebugFlags 31 // WinXP source says 32?
HANDLE process_id_to_handle(const DWORD pid)
{
return reinterpret_cast<HANDLE>(static_cast<DWORD64>(pid));
}
NTSTATUS WINAPI nt_query_information_process_stub(const HANDLE handle, const PROCESSINFOCLASS info_class, NTSTATUS WINAPI nt_query_information_process_stub(const HANDLE handle, const PROCESSINFOCLASS info_class,
const PVOID info, const PVOID info,
const ULONG info_length, const PULONG ret_length) const ULONG info_length, const PULONG ret_length)
@ -71,6 +78,13 @@ namespace arxan
return STATUS_INVALID_HANDLE; return STATUS_INVALID_HANDLE;
} }
void hide_being_debugged()
{
auto* const peb = PPEB(__readgsqword(0x60));
peb->BeingDebugged = false;
*reinterpret_cast<PDWORD>(LPSTR(peb) + 0xBC) &= ~0x70;
}
LONG WINAPI exception_filter(const LPEXCEPTION_POINTERS info) LONG WINAPI exception_filter(const LPEXCEPTION_POINTERS info)
{ {
if (info->ExceptionRecord->ExceptionCode == STATUS_INVALID_HANDLE) if (info->ExceptionRecord->ExceptionCode == STATUS_INVALID_HANDLE)
@ -78,19 +92,185 @@ namespace arxan
return EXCEPTION_CONTINUE_EXECUTION; return EXCEPTION_CONTINUE_EXECUTION;
} }
if (info->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION)
{
//MessageBoxA(0, 0, "AV", 0);
}
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;
} }
void hide_being_debugged() struct integrity_handler_context
{ {
auto* const peb = PPEB(__readgsqword(0x60)); uint32_t* computed_checksum;
peb->BeingDebugged = false; uint32_t* original_checksum;
*reinterpret_cast<PDWORD>(LPSTR(peb) + 0xBC) &= ~0x70; };
// Pretty trashy, but working, heuristic to search integrity the handler context
bool is_handler_context(uint8_t* stack_frame, const uint32_t computed_checksum, const uint32_t frame_offset)
{
auto* potential_address = *reinterpret_cast<uint32_t**>(stack_frame + frame_offset);
int64_t diff = reinterpret_cast<uint64_t>(stack_frame) - reinterpret_cast<uint64_t>(potential_address);
diff = std::abs(diff);
return diff < 0x1000 && *potential_address == computed_checksum;
}
integrity_handler_context* search_handler_context(uint8_t* stack_frame, const uint32_t computed_checksum)
{
for (uint32_t frame_offset = 24; frame_offset < 64; frame_offset += 8)
{
if (is_handler_context(stack_frame, computed_checksum, frame_offset))
{
return reinterpret_cast<integrity_handler_context*>(stack_frame + frame_offset);
}
}
return nullptr;
}
uint32_t adjust_integrity_checksum(const uint64_t return_address, uint8_t* stack_frame,
const uint32_t current_checksum)
{
const auto handler_address = return_address - 5;
const auto* context = search_handler_context(stack_frame, current_checksum);
if (!context)
{
OutputDebugStringA(utils::string::va("Unable to find frame offset for: %llX", return_address));
return current_checksum;
}
const auto correct_checksum = *context->original_checksum;
*context->computed_checksum = correct_checksum;
if (current_checksum != correct_checksum)
{
#ifdef _DEBUG
OutputDebugStringA(utils::string::va("Adjusting checksum (%llX): %X -> %X", handler_address,
current_checksum, correct_checksum));
#endif
}
return correct_checksum;
}
void patch_intact_basic_block_integrity_check(void* address)
{
const auto game_address = reinterpret_cast<uint64_t>(address);
constexpr auto inst_len = 3;
const auto next_inst_addr = game_address + inst_len;
const auto next_inst = *reinterpret_cast<uint32_t*>(next_inst_addr);
if ((next_inst & 0xFF00FFFF) != 0xFF004583)
{
throw std::runtime_error(utils::string::va("Unable to patch intact basic block: %llX", game_address));
}
const auto other_frame_offset = static_cast<uint8_t>(next_inst >> 16);
static const auto stub = utils::hook::assemble([](utils::hook::assembler& a)
{
a.push(rax);
a.mov(rax, qword_ptr(rsp, 8));
a.sub(rax, 2); // Skip the push we inserted
a.push(rax);
a.pushad64();
a.mov(r8, qword_ptr(rsp, 0x88));
a.mov(rcx, rax);
a.mov(rdx, rbp);
a.call_aligned(adjust_integrity_checksum);
a.mov(qword_ptr(rsp, 0x80), rax);
a.popad64();
a.pop(rax);
a.add(rsp, 8);
a.mov(dword_ptr(rdx, rcx, 4), eax);
a.pop(rax); // return addr
a.xchg(rax, qword_ptr(rsp)); // switch with push
a.add(dword_ptr(rbp, rax), 0xFFFFFFFF);
a.mov(rax, dword_ptr(rdx, rcx, 4)); // restore rax
a.ret();
});
// push other_frame_offset
utils::hook::set<uint16_t>(game_address, static_cast<uint16_t>(0x6A | (other_frame_offset << 8)));
utils::hook::call(game_address + 2, stub);
}
void patch_split_basic_block_integrity_check(void* address)
{
const auto game_address = reinterpret_cast<uint64_t>(address);
constexpr auto inst_len = 3;
const auto next_inst_addr = game_address + inst_len;
if (*reinterpret_cast<uint8_t*>(next_inst_addr) != 0xE9)
{
throw std::runtime_error(utils::string::va("Unable to patch split basic block: %llX", game_address));
}
const auto jump_target = utils::hook::extract<void*>(reinterpret_cast<void*>(next_inst_addr + 1));
const auto stub = utils::hook::assemble([jump_target](utils::hook::assembler& a)
{
a.push(rax);
a.mov(rax, qword_ptr(rsp, 8));
a.push(rax);
a.pushad64();
a.mov(r8, qword_ptr(rsp, 0x88));
a.mov(rcx, rax);
a.mov(rdx, rbp);
a.call_aligned(adjust_integrity_checksum);
a.mov(qword_ptr(rsp, 0x80), rax);
a.popad64();
a.pop(rax);
a.add(rsp, 8);
a.mov(dword_ptr(rdx, rcx, 4), eax);
a.add(rsp, 8);
a.jmp(jump_target);
});
utils::hook::call(game_address, stub);
}
void search_and_patch_integrity_checks()
{
// There seem to be 670 results.
// Searching them is quite slow.
// Maybe precomputing that might be better?
const auto intact_results = "89 04 8A 83 45 ? FF"_sig;
const auto split_results = "89 04 8A E9"_sig;
int results = 0;
for (auto* i : intact_results)
{
patch_intact_basic_block_integrity_check(i);
results++;
}
for (auto* i : split_results)
{
patch_split_basic_block_integrity_check(i);
results++;
}
OutputDebugStringA(utils::string::va("integrity check amount: %d\n", results));
} }
} }
@ -103,12 +283,10 @@ namespace arxan
scheduler::loop(hide_being_debugged, scheduler::pipeline::async); scheduler::loop(hide_being_debugged, scheduler::pipeline::async);
const utils::nt::library ntdll("ntdll.dll"); const utils::nt::library ntdll("ntdll.dll");
nt_close_hook.create(ntdll.get_proc<void*>("NtClose"), nt_close_stub); nt_close_hook.create(ntdll.get_proc<void*>("NtClose"), nt_close_stub);
const auto nt_query_information_process = ntdll.get_proc<void*>("NtQueryInformationProcess"); const auto nt_query_information_process = ntdll.get_proc<void*>("NtQueryInformationProcess");
nt_query_information_process_hook.create(nt_query_information_process, nt_query_information_process_hook.create(nt_query_information_process, nt_query_information_process_stub);
nt_query_information_process_stub);
nt_query_information_process_hook.move(); nt_query_information_process_hook.move();
AddVectoredExceptionHandler(1, exception_filter); AddVectoredExceptionHandler(1, exception_filter);
@ -116,7 +294,12 @@ namespace arxan
void post_unpack() override void post_unpack() override
{ {
search_and_patch_integrity_checks();
}
int priority() override
{
return COMPONENT_MAX_PRIORITY;
} }
}; };
} }

View File

@ -1,12 +1,171 @@
#include "hook.hpp" #include "hook.hpp"
#include "string.hpp"
#include <map>
#include <MinHook.h> #include <MinHook.h>
#include "concurrency.hpp"
#include "string.hpp"
#include "nt.hpp"
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
namespace utils::hook namespace utils::hook
{ {
namespace namespace
{ {
uint8_t* allocate_somewhere_near(const void* base_address, const size_t size)
{
size_t offset = 0;
while (true)
{
offset += size;
auto* target_address = static_cast<const uint8_t*>(base_address) - offset;
if (is_relatively_far(base_address, target_address))
{
return nullptr;
}
const auto res = VirtualAlloc(const_cast<uint8_t*>(target_address), size, MEM_RESERVE | MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if (res)
{
if (is_relatively_far(base_address, target_address))
{
VirtualFree(res, 0, MEM_RELEASE);
return nullptr;
}
return static_cast<uint8_t*>(res);
}
}
}
class memory
{
public:
memory() = default;
memory(const void* ptr)
: memory()
{
this->length_ = 0x1000;
this->buffer_ = allocate_somewhere_near(ptr, this->length_);
if (!this->buffer_)
{
throw std::runtime_error("Failed to allocate");
}
}
~memory()
{
if (this->buffer_)
{
VirtualFree(this->buffer_, 0, MEM_RELEASE);
}
}
memory(memory&& obj) noexcept
: memory()
{
this->operator=(std::move(obj));
}
memory& operator=(memory&& obj) noexcept
{
if (this != &obj)
{
this->~memory();
this->buffer_ = obj.buffer_;
this->length_ = obj.length_;
this->offset_ = obj.offset_;
obj.buffer_ = nullptr;
obj.length_ = 0;
obj.offset_ = 0;
}
return *this;
}
void* allocate(const size_t length)
{
if (!this->buffer_)
{
return nullptr;
}
if (this->offset_ + length > this->length_)
{
return nullptr;
}
const auto ptr = this->get_ptr();
this->offset_ += length;
return ptr;
}
void* get_ptr() const
{
return this->buffer_ + this->offset_;
}
private:
uint8_t* buffer_{};
size_t length_{};
size_t offset_{};
};
void* get_memory_near(const void* address, const size_t size)
{
static concurrency::container<std::vector<memory>> memory_container{};
return memory_container.access<void*>([&](std::vector<memory>& memories)
{
for (auto& memory : memories)
{
if (!is_relatively_far(address, memory.get_ptr()))
{
const auto buffer = memory.allocate(size);
if (buffer)
{
return buffer;
}
}
}
memories.emplace_back(address);
return memories.back().allocate(size);
});
}
concurrency::container<std::map<const void*, uint8_t>>& get_original_data_map()
{
static concurrency::container<std::map<const void*, uint8_t>> og_data{};
return og_data;
}
void store_original_data(const void* /*data*/, size_t /*length*/)
{
/*get_original_data_map().access([data, length](std::map<const void*, uint8_t>& og_map)
{
const auto data_ptr = static_cast<const uint8_t*>(data);
for (size_t i = 0; i < length; ++i)
{
const auto pos = data_ptr + i;
if (!og_map.contains(pos))
{
og_map[pos] = *pos;
}
}
});*/
}
void* initialize_min_hook() void* initialize_min_hook()
{ {
static class min_hook_init static class min_hook_init
@ -140,6 +299,7 @@ namespace utils::hook
{ {
this->clear(); this->clear();
this->place_ = place; this->place_ = place;
store_original_data(place, 14);
if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK) if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK)
{ {
@ -192,6 +352,8 @@ namespace utils::hook
auto* const ptr = library.get_iat_entry(target_library, process); auto* const ptr = library.get_iat_entry(target_library, process);
if (!ptr) return false; if (!ptr) return false;
store_original_data(ptr, sizeof(*ptr));
DWORD protect; DWORD protect;
VirtualProtect(ptr, sizeof(*ptr), PAGE_EXECUTE_READWRITE, &protect); VirtualProtect(ptr, sizeof(*ptr), PAGE_EXECUTE_READWRITE, &protect);
@ -203,6 +365,8 @@ namespace utils::hook
void nop(void* place, const size_t length) void nop(void* place, const size_t length)
{ {
store_original_data(place, length);
DWORD old_protect{}; DWORD old_protect{};
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
@ -219,6 +383,8 @@ namespace utils::hook
void copy(void* place, const void* data, const size_t length) void copy(void* place, const void* data, const size_t length)
{ {
store_original_data(place, length);
DWORD old_protect{}; DWORD old_protect{};
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
@ -233,6 +399,16 @@ namespace utils::hook
copy(reinterpret_cast<void*>(place), data, length); copy(reinterpret_cast<void*>(place), data, length);
} }
void copy_string(void* place, const char* str)
{
copy(reinterpret_cast<void*>(place), str, strlen(str) + 1);
}
void copy_string(const size_t place, const char* str)
{
copy_string(reinterpret_cast<void*>(place), str);
}
bool is_relatively_far(const void* pointer, const void* data, const int offset) bool is_relatively_far(const void* pointer, const void* data, const int offset)
{ {
const int64_t diff = size_t(data) - (size_t(pointer) + offset); const int64_t diff = size_t(data) - (size_t(pointer) + offset);
@ -244,12 +420,23 @@ namespace utils::hook
{ {
if (is_relatively_far(pointer, data)) if (is_relatively_far(pointer, data))
{ {
throw std::runtime_error("Too far away to create 32bit relative branch"); auto* trampoline = get_memory_near(pointer, 14);
if (!trampoline)
{
throw std::runtime_error("Too far away to create 32bit relative branch");
}
call(pointer, trampoline);
jump(trampoline, data, true, true);
return;
} }
uint8_t copy_data[5];
copy_data[0] = 0xE8;
*reinterpret_cast<int32_t*>(&copy_data[1]) = int32_t(size_t(data) - (size_t(pointer) + 5));
auto* patch_pointer = PBYTE(pointer); auto* patch_pointer = PBYTE(pointer);
set<uint8_t>(patch_pointer, 0xE8); copy(patch_pointer, copy_data, sizeof(copy_data));
set<int32_t>(patch_pointer + 1, int32_t(size_t(data) - (size_t(pointer) + 5)));
} }
void call(const size_t pointer, void* data) void call(const size_t pointer, void* data)
@ -274,7 +461,14 @@ namespace utils::hook
if (!use_far && is_relatively_far(pointer, data)) if (!use_far && is_relatively_far(pointer, data))
{ {
throw std::runtime_error("Too far away to create 32bit relative branch"); auto* trampoline = get_memory_near(pointer, 14);
if (!trampoline)
{
throw std::runtime_error("Too far away to create 32bit relative branch");
}
jump(pointer, trampoline, false, false);
jump(trampoline, data, true, true);
return;
} }
auto* patch_pointer = PBYTE(pointer); auto* patch_pointer = PBYTE(pointer);
@ -283,19 +477,28 @@ namespace utils::hook
{ {
if (use_safe) if (use_safe)
{ {
copy(patch_pointer, jump_data_safe, sizeof(jump_data_safe)); uint8_t copy_data[sizeof(jump_data_safe) + sizeof(data)];
copy(patch_pointer + sizeof(jump_data_safe), &data, sizeof(data)); memcpy(copy_data, jump_data_safe, sizeof(jump_data_safe));
memcpy(copy_data + sizeof(jump_data_safe), &data, sizeof(data));
copy(patch_pointer, copy_data, sizeof(copy_data));
} }
else else
{ {
copy(patch_pointer, jump_data, sizeof(jump_data)); uint8_t copy_data[sizeof(jump_data)];
copy(patch_pointer + 2, &data, sizeof(data)); memcpy(copy_data, jump_data, sizeof(jump_data));
memcpy(copy_data + 2, &data, sizeof(data));
copy(patch_pointer, copy_data, sizeof(copy_data));
} }
} }
else else
{ {
set<uint8_t>(patch_pointer, 0xE9); uint8_t copy_data[5];
set<int32_t>(patch_pointer + 1, int32_t(size_t(data) - (size_t(pointer) + 5))); copy_data[0] = 0xE9;
*reinterpret_cast<int32_t*>(&copy_data[1]) = int32_t(size_t(data) - (size_t(pointer) + 5));
copy(patch_pointer, copy_data, sizeof(copy_data));
} }
} }
@ -386,4 +589,26 @@ namespace utils::hook
return extract<void*>(data + 1); return extract<void*>(data + 1);
} }
std::vector<uint8_t> query_original_data(const void* data, const size_t length)
{
std::vector<uint8_t> og_data{};
og_data.resize(length);
memcpy(og_data.data(), data, length);
get_original_data_map().access([data, length, &og_data](const std::map<const void*, uint8_t>& og_map)
{
auto* ptr = static_cast<const uint8_t*>(data);
for (size_t i = 0; i < length; ++i)
{
auto entry = og_map.find(ptr + i);
if (entry != og_map.end())
{
og_data[i] = entry->second;
}
}
});
return og_data;
}
} }

View File

@ -22,9 +22,9 @@ namespace utils::hook
{ {
auto functions = get_iota_functions<Entries - 1>(); auto functions = get_iota_functions<Entries - 1>();
functions.emplace_back([]() functions.emplace_back([]()
{ {
return Entries - 1; return Entries - 1;
}); });
return functions; return functions;
} }
} }
@ -155,6 +155,9 @@ namespace utils::hook
void copy(void* place, const void* data, size_t length); void copy(void* place, const void* data, size_t length);
void copy(size_t place, const void* data, size_t length); void copy(size_t place, const void* data, size_t length);
void copy_string(void* place, const char* str);
void copy_string(size_t place, const char* str);
bool is_relatively_far(const void* pointer, const void* data, int offset = 5); bool is_relatively_far(const void* pointer, const void* data, int offset = 5);
void call(void* pointer, void* data); void call(void* pointer, void* data);
@ -184,19 +187,13 @@ namespace utils::hook
void* follow_branch(void* address); void* follow_branch(void* address);
template <typename T> template <typename T>
static void set(void* place, T value) static void set(void* place, T value = false)
{ {
DWORD old_protect; copy(place, &value, sizeof(value));
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect);
*static_cast<T*>(place) = value;
VirtualProtect(place, sizeof(T), old_protect, &old_protect);
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
} }
template <typename T> template <typename T>
static void set(const size_t place, T value) static void set(const size_t place, T value = false)
{ {
return set<T>(reinterpret_cast<void*>(place), value); return set<T>(reinterpret_cast<void*>(place), value);
} }
@ -212,4 +209,6 @@ namespace utils::hook
{ {
return static_cast<T(*)(Args ...)>(func)(args...); return static_cast<T(*)(Args ...)>(func)(args...);
} }
std::vector<uint8_t> query_original_data(const void* data, size_t length);
} }

View File

@ -4,6 +4,14 @@
#include <intrin.h> #include <intrin.h>
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
namespace utils::hook namespace utils::hook
{ {
void signature::load_pattern(const std::string& pattern) void signature::load_pattern(const std::string& pattern)
@ -29,7 +37,7 @@ namespace utils::hook
throw std::runtime_error("Invalid pattern"); throw std::runtime_error("Invalid pattern");
} }
char str[] = {val, 0}; char str[] = { val, 0 };
const auto current_nibble = static_cast<uint8_t>(strtol(str, nullptr, 16)); const auto current_nibble = static_cast<uint8_t>(strtol(str, nullptr, 16));
if (!has_nibble) if (!has_nibble)
@ -68,15 +76,15 @@ namespace utils::hook
} }
} }
std::vector<size_t> signature::process_range(uint8_t* start, const size_t length) const signature::signature_result signature::process_range(uint8_t* start, const size_t length) const
{ {
if (this->has_sse_support()) return this->process_range_vectorized(start, length); if (this->has_sse_support()) return this->process_range_vectorized(start, length);
return this->process_range_linear(start, length); return this->process_range_linear(start, length);
} }
std::vector<size_t> signature::process_range_linear(uint8_t* start, const size_t length) const signature::signature_result signature::process_range_linear(uint8_t* start, const size_t length) const
{ {
std::vector<size_t> result; std::vector<uint8_t*> result;
for (size_t i = 0; i < length; ++i) for (size_t i = 0; i < length; ++i)
{ {
@ -93,17 +101,17 @@ namespace utils::hook
if (j == this->mask_.size()) if (j == this->mask_.size())
{ {
result.push_back(size_t(address)); result.push_back(address);
} }
} }
return result; return result;
} }
std::vector<size_t> signature::process_range_vectorized(uint8_t* start, const size_t length) const signature::signature_result signature::process_range_vectorized(uint8_t* start, const size_t length) const
{ {
std::vector<size_t> result; std::vector<uint8_t*> result;
__declspec(align(16)) char desired_mask[16] = {0}; __declspec(align(16)) char desired_mask[16] = { 0 };
for (size_t i = 0; i < this->mask_.size(); i++) for (size_t i = 0; i < this->mask_.size(); i++)
{ {
@ -118,14 +126,14 @@ namespace utils::hook
const auto address = start + i; const auto address = start + i;
const auto value = _mm_loadu_si128(reinterpret_cast<const __m128i*>(address)); const auto value = _mm_loadu_si128(reinterpret_cast<const __m128i*>(address));
const auto comparison = _mm_cmpestrm(value, 16, comparand, static_cast<int>(this->mask_.size()), const auto comparison = _mm_cmpestrm(value, 16, comparand, static_cast<int>(this->mask_.size()),
_SIDD_CMP_EQUAL_EACH); _SIDD_CMP_EQUAL_EACH);
const auto matches = _mm_and_si128(mask, comparison); const auto matches = _mm_and_si128(mask, comparison);
const auto equivalence = _mm_xor_si128(mask, matches); const auto equivalence = _mm_xor_si128(mask, matches);
if (_mm_test_all_zeros(equivalence, equivalence)) if (_mm_test_all_zeros(equivalence, equivalence))
{ {
result.push_back(size_t(address)); result.push_back(address);
} }
} }
@ -144,7 +152,7 @@ namespace utils::hook
signature::signature_result signature::process_serial() const signature::signature_result signature::process_serial() const
{ {
const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); const auto sub = this->has_sse_support() ? 16 : this->mask_.size();
return {this->process_range(this->start_, this->length_ - sub)}; return { this->process_range(this->start_, this->length_ - sub) };
} }
signature::signature_result signature::process_parallel() const signature::signature_result signature::process_parallel() const
@ -156,7 +164,7 @@ namespace utils::hook
const auto grid = range / cores; const auto grid = range / cores;
std::mutex mutex; std::mutex mutex;
std::vector<size_t> result; std::vector<uint8_t*> result;
std::vector<std::thread> threads; std::vector<std::thread> threads;
for (auto i = 0u; i < cores; ++i) for (auto i = 0u; i < cores; ++i)
@ -165,7 +173,7 @@ namespace utils::hook
const auto length = (i + 1 == cores) ? (this->start_ + this->length_ - sub) - start : grid; const auto length = (i + 1 == cores) ? (this->start_ + this->length_ - sub) - start : grid;
threads.emplace_back([&, start, length]() threads.emplace_back([&, start, length]()
{ {
auto local_result = this->process_range(start, length); const auto local_result = this->process_range(start, length);
if (local_result.empty()) return; if (local_result.empty()) return;
std::lock_guard _(mutex); std::lock_guard _(mutex);
@ -185,7 +193,7 @@ namespace utils::hook
} }
std::sort(result.begin(), result.end()); std::sort(result.begin(), result.end());
return {std::move(result)}; return { std::move(result) };
} }
bool signature::has_sse_support() const bool signature::has_sse_support() const

View File

@ -7,33 +7,9 @@ namespace utils::hook
class signature final class signature final
{ {
public: public:
class signature_result using signature_result = std::vector<uint8_t*>;
{
public:
signature_result(std::vector<size_t>&& matches) : matches_(std::move(matches))
{
}
[[nodiscard]] uint8_t* get(const size_t index) const explicit signature(const std::string& pattern, const nt::library& library = {})
{
if (index >= this->count())
{
throw std::runtime_error("Invalid index");
}
return reinterpret_cast<uint8_t*>(this->matches_[index]);
}
[[nodiscard]] size_t count() const
{
return this->matches_.size();
}
private:
std::vector<size_t> matches_;
};
explicit signature(const std::string& pattern, const nt::library library = {})
: signature(pattern, library.get_ptr(), library.get_optional_header()->SizeOfImage) : signature(pattern, library.get_ptr(), library.get_optional_header()->SizeOfImage)
{ {
} }
@ -62,9 +38,9 @@ namespace utils::hook
signature_result process_parallel() const; signature_result process_parallel() const;
signature_result process_serial() const; signature_result process_serial() const;
std::vector<size_t> process_range(uint8_t* start, size_t length) const; signature_result process_range(uint8_t* start, size_t length) const;
std::vector<size_t> process_range_linear(uint8_t* start, size_t length) const; signature_result process_range_linear(uint8_t* start, size_t length) const;
std::vector<size_t> process_range_vectorized(uint8_t* start, size_t length) const; signature_result process_range_vectorized(uint8_t* start, size_t length) const;
bool has_sse_support() const; bool has_sse_support() const;
}; };