Asynchronous pattern scanning using std::async. (#770)

* feat(pattern): add support for double ? IDA sigs

Co-authored-by: Yimura <24669514+Yimura@users.noreply.github.com>
This commit is contained in:
Marcezsa 2023-01-18 19:02:23 +00:00 committed by GitHub
parent 23b016f4c8
commit fd0b4ebd55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 29 deletions

View File

@ -29,6 +29,8 @@ namespace big
void detour_hook::create_hook() void detour_hook::create_hook()
{ {
if (!m_target) return;
fix_hook_address(); fix_hook_address();
if (auto status = MH_CreateHook(m_target, m_detour, &m_original); status != MH_OK) if (auto status = MH_CreateHook(m_target, m_detour, &m_original); status != MH_OK)
throw std::runtime_error(std::format("Failed to create hook '{}' at 0x{:X} (error: {})", m_name, uintptr_t(m_target), MH_StatusToString(status))); throw std::runtime_error(std::format("Failed to create hook '{}' at 0x{:X} (error: {})", m_name, uintptr_t(m_target), MH_StatusToString(status)));
@ -36,18 +38,24 @@ namespace big
detour_hook::~detour_hook() noexcept detour_hook::~detour_hook() noexcept
{ {
if (!m_target) return;
if (auto status = MH_RemoveHook(m_target); status != MH_OK) if (auto status = MH_RemoveHook(m_target); status != MH_OK)
LOG(FATAL) << "Failed to remove hook '" << m_name << "' at 0x" << HEX_TO_UPPER(uintptr_t(m_target)) << "(error: " << m_name << ")"; LOG(FATAL) << "Failed to remove hook '" << m_name << "' at 0x" << HEX_TO_UPPER(uintptr_t(m_target)) << "(error: " << m_name << ")";
} }
void detour_hook::enable() void detour_hook::enable()
{ {
if (!m_target) return;
if (auto status = MH_QueueEnableHook(m_target); status != MH_OK) if (auto status = MH_QueueEnableHook(m_target); status != MH_OK)
throw std::runtime_error(std::format("Failed to enable hook 0x{:X} ({})", uintptr_t(m_target), MH_StatusToString(status))); throw std::runtime_error(std::format("Failed to enable hook 0x{:X} ({})", uintptr_t(m_target), MH_StatusToString(status)));
} }
void detour_hook::disable() void detour_hook::disable()
{ {
if (!m_target) return;
if (auto status = MH_QueueDisableHook(m_target); status != MH_OK) if (auto status = MH_QueueDisableHook(m_target); status != MH_OK)
LOG(WARNING) << "Failed to disable hook '" << m_name << "'."; LOG(WARNING) << "Failed to disable hook '" << m_name << "'.";
} }

View File

@ -3,6 +3,11 @@
#include "batch.hpp" #include "batch.hpp"
#include "range.hpp" #include "range.hpp"
#include <future> //std::async
static std::mutex s_entry_mutex;
static std::vector<std::future<bool>> g_futures;
namespace memory namespace memory
{ {
void batch::add(std::string name, pattern pattern, std::function<void(handle)> callback) void batch::add(std::string name, pattern pattern, std::function<void(handle)> callback)
@ -10,38 +15,46 @@ namespace memory
m_entries.emplace_back(std::move(name), std::move(pattern), std::move(callback)); m_entries.emplace_back(std::move(name), std::move(pattern), std::move(callback));
} }
void batch::run(range region) bool scan_pattern_and_execute_callback(range region, memory::batch::entry entry)
{
bool all_found = true;
for (auto& entry : m_entries)
{ {
if (auto result = region.scan(entry.m_pattern)) if (auto result = region.scan(entry.m_pattern))
{ {
if (entry.m_callback) if (entry.m_callback)
{ {
std::lock_guard<std::mutex> lock(s_entry_mutex); // Acquire a lock on the mutex to synchronize access.
std::invoke(std::move(entry.m_callback), result); std::invoke(std::move(entry.m_callback), result);
std::stringstream file_out{}; //I hate this, but not logging it except on fail really helps on speed. LOG(INFO) << "Found '" << entry.m_name << "' GTA5.exe+" << HEX_TO_UPPER(result.as<DWORD64>() - region.begin().as<DWORD64>());
file_out << "Found '" << entry.m_name << "' GTA5.exe+" << HEX_TO_UPPER(result.as<DWORD64>() - region.begin().as<DWORD64>());
big::g_log->file_out(file_out); return true;
file_out.clear();
}
else
{
all_found = false;
LOG(WARNING) << "Failed to find '" << entry.m_name << "'.";
}
}
else
{
all_found = false;
LOG(WARNING) << "Failed to find '" << entry.m_name << "'.";
} }
} }
m_entries.clear(); LOG(WARNING) << "Failed to find '" << entry.m_name << "'.";
if (!all_found)
{ return false;
throw std::runtime_error("Failed to find some patterns.");
} }
bool batch::run(range region)
{
for (auto& entry : m_entries)
{
g_futures.emplace_back(
std::async(&scan_pattern_and_execute_callback, region, entry));
}
bool found_all_patterns = true;
for (auto& future : g_futures)
{
future.wait();
if (!future.get())
found_all_patterns = false;
}
m_entries.clear();
g_futures.clear();
return found_all_patterns;
} }
} }

View File

@ -12,7 +12,7 @@ namespace memory
~batch() noexcept = default; ~batch() noexcept = default;
void add(std::string name, pattern pattern, std::function<void(memory::handle)> callback); void add(std::string name, pattern pattern, std::function<void(memory::handle)> callback);
void run(range region); bool run(range region);
struct entry struct entry
{ {

View File

@ -79,6 +79,12 @@ namespace memory
else else
{ {
m_bytes.push_back({}); m_bytes.push_back({});
// add support for double question mark sigs
if (ida_sig[i + 1] == '?')
{
++i;
}
} }
} }
} }

View File

@ -811,7 +811,10 @@ namespace big
}); });
auto mem_region = memory::module("GTA5.exe"); auto mem_region = memory::module("GTA5.exe");
main_batch.run(mem_region); if (!main_batch.run(mem_region))
{
throw std::runtime_error("Failed to find some patterns.");
}
memory::batch socialclub_batch; memory::batch socialclub_batch;