From dc60780e2715fd224a501eb7c493e198e5fe2c1b Mon Sep 17 00:00:00 2001 From: Forever Gone <78507032+Faint0002@users.noreply.github.com> Date: Sat, 15 Oct 2022 19:50:28 -0400 Subject: [PATCH] Improved pattern scanner (#470) --- BigBaseV2/src/logger.hpp | 4 ++ BigBaseV2/src/memory/batch.cpp | 5 +- BigBaseV2/src/memory/pattern.cpp | 109 ++++++++++++++++--------------- BigBaseV2/src/memory/range.cpp | 79 ++++++++++++++++++---- BigBaseV2/src/pointers.cpp | 10 --- 5 files changed, 131 insertions(+), 76 deletions(-) diff --git a/BigBaseV2/src/logger.hpp b/BigBaseV2/src/logger.hpp index 0c69d141..e5c7ace2 100644 --- a/BigBaseV2/src/logger.hpp +++ b/BigBaseV2/src/logger.hpp @@ -95,6 +95,10 @@ namespace big FreeConsole(); } + void file_out(std::stringstream& str) + { + m_file_out << str.str() << '\n'; + } private: void create_backup() { diff --git a/BigBaseV2/src/memory/batch.cpp b/BigBaseV2/src/memory/batch.cpp index 1409cc6f..38bfc1e1 100644 --- a/BigBaseV2/src/memory/batch.cpp +++ b/BigBaseV2/src/memory/batch.cpp @@ -20,7 +20,10 @@ namespace memory if (entry.m_callback) { std::invoke(std::move(entry.m_callback), result); - LOG(INFO) << "Found '" << entry.m_name << "' GTA5.exe+" << HEX_TO_UPPER(result.as() - region.begin().as()); + std::stringstream file_out{}; //I hate this, but not logging it except on fail really helps on speed. + file_out << "Found '" << entry.m_name << "' GTA5.exe+" << HEX_TO_UPPER(result.as() - region.begin().as()); + big::g_log->file_out(file_out); + file_out.clear(); } else { diff --git a/BigBaseV2/src/memory/pattern.cpp b/BigBaseV2/src/memory/pattern.cpp index ac454238..371472a7 100644 --- a/BigBaseV2/src/memory/pattern.cpp +++ b/BigBaseV2/src/memory/pattern.cpp @@ -3,59 +3,66 @@ namespace memory { + std::optional to_hex(char const c) + { + switch (c) + { + case '0': + return static_cast(0x0); + case '1': + return static_cast(0x1); + case '2': + return static_cast(0x2); + case '3': + return static_cast(0x3); + case '4': + return static_cast(0x4); + case '5': + return static_cast(0x5); + case '6': + return static_cast(0x6); + case '7': + return static_cast(0x7); + case '8': + return static_cast(0x8); + case '9': + return static_cast(0x9); + case 'a': + return static_cast(0xa); + case 'b': + return static_cast(0xb); + case 'c': + return static_cast(0xc); + case 'd': + return static_cast(0xd); + case 'e': + return static_cast(0xe); + case 'f': + return static_cast(0xf); + case 'A': + return static_cast(0xA); + case 'B': + return static_cast(0xB); + case 'C': + return static_cast(0xC); + case 'D': + return static_cast(0xD); + case 'E': + return static_cast(0xE); + case 'F': + return static_cast(0xF); + default: + return std::nullopt; + } + } + pattern::pattern(std::string_view ida_sig) { - auto to_upper = [](char c) -> char - { - return c >= 'a' && c <= 'z' ? static_cast(c + ('A' - 'a')) : static_cast(c); - }; - - auto to_hex = [&](char c) -> std::optional - { - switch (to_upper(c)) - { - case '0': - return static_cast(0); - case '1': - return static_cast(1); - case '2': - return static_cast(2); - case '3': - return static_cast(3); - case '4': - return static_cast(4); - case '5': - return static_cast(5); - case '6': - return static_cast(6); - case '7': - return static_cast(7); - case '8': - return static_cast(8); - case '9': - return static_cast(9); - case 'A': - return static_cast(10); - case 'B': - return static_cast(11); - case 'C': - return static_cast(12); - case 'D': - return static_cast(13); - case 'E': - return static_cast(14); - case 'F': - return static_cast(15); - default: - return std::nullopt; - } - }; - - for (std::size_t i = 0; i < ida_sig.size(); ++i) + const auto size = ida_sig.size(); + for (std::size_t i{}; i != size; ++i) { if (ida_sig[i] == ' ') continue; - bool last = (i == ida_sig.size() - 1); if (ida_sig[i] != '?') { @@ -63,7 +70,6 @@ namespace memory { auto c1 = to_hex(ida_sig[i]); auto c2 = to_hex(ida_sig[i + 1]); - if (c1 && c2) { m_bytes.emplace_back(static_cast((*c1 * 0x10) + *c2)); @@ -72,14 +78,15 @@ namespace memory } else { - m_bytes.push_back(std::nullopt); + m_bytes.push_back({}); } } } pattern::pattern(const void *bytes, std::string_view mask) { - for (std::size_t i = 0; i < mask.size(); ++i) + const auto size = mask.size(); + for (std::size_t i{}; i != size; ++i) { if (mask[i] != '?') m_bytes.emplace_back(static_cast(bytes)[i]); diff --git a/BigBaseV2/src/memory/range.cpp b/BigBaseV2/src/memory/range.cpp index 9e03e5f8..2f5affbf 100644 --- a/BigBaseV2/src/memory/range.cpp +++ b/BigBaseV2/src/memory/range.cpp @@ -29,39 +29,90 @@ namespace memory return h.as() >= begin().as() && h.as() <= end().as(); } - static bool pattern_matches(std::uint8_t* target, const std::optional* sig, std::size_t length) + // https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm + // https://www.youtube.com/watch?v=AuZUeshhy-s + handle scan_pattern(const std::optional* sig, std::size_t length, handle begin, std::size_t module_size) { - for (std::size_t i = 0; i < length; ++i) + std::size_t maxShift = length; + std::size_t max_idx = length - 1; + + //Get wildcard index, and store max shiftable byte count + std::size_t wild_card_idx{ static_cast(-1) }; + for (int i{ static_cast(max_idx - 1) }; i >= 0; --i) { - if (sig[i] && *sig[i] != target[i]) - return false; + if (!sig[i]) + { + maxShift = max_idx - i; + wild_card_idx = i; + break; + } } - return true; - }; + //Store max shiftable bytes for non wildcards. + std::size_t shift_table[UINT8_MAX + 1]{}; + for (std::size_t i{}; i <= UINT8_MAX; ++i) + { + shift_table[i] = maxShift; + } + + //Fill shift table with sig bytes + for (std::size_t i{ wild_card_idx + 1 }; i != max_idx; ++i) + { + shift_table[*sig[i]] = max_idx - i; + } + + //Loop data + for (std::size_t current_idx{}; current_idx != module_size - length;) + { + for (std::size_t sig_idx{ max_idx }; sig_idx >= 0; --sig_idx) + { + if (sig[sig_idx] && *begin.add(current_idx + sig_idx).as() != *sig[sig_idx]) + { + current_idx += shift_table[*begin.add(current_idx + max_idx).as()]; + break; + } + else if (sig_idx == NULL) + { + return begin.add(sig_idx); + } + } + } + return nullptr; + } handle range::scan(pattern const &sig) { auto data = sig.m_bytes.data(); auto length = sig.m_bytes.size(); - for (std::uintptr_t i = 0; i < m_size - length; ++i) + + if (auto result = scan_pattern(data, length, m_base, m_size); result) { - if (pattern_matches(m_base.add(i).as(), data, length)) - { - return m_base.add(i); - } + return result; } return nullptr; } + bool pattern_matches(std::uint8_t* target, const std::optional* sig, std::size_t length) + { + for (std::size_t i{}; i != length; ++i) + { + if (sig[i] && *sig[i] != target[i]) + { + return false; + } + } + + return true; + } std::vector range::scan_all(pattern const &sig) { - std::vector result; - + std::vector result{}; auto data = sig.m_bytes.data(); auto length = sig.m_bytes.size(); - for (std::uintptr_t i = 0; i < m_size - length; ++i) + + const auto search_end = m_size - length; + for (std::uintptr_t i{}; i != search_end; ++i) { if (pattern_matches(m_base.add(i).as(), data, length)) { diff --git a/BigBaseV2/src/pointers.cpp b/BigBaseV2/src/pointers.cpp index 299c319c..9818a2ca 100644 --- a/BigBaseV2/src/pointers.cpp +++ b/BigBaseV2/src/pointers.cpp @@ -30,8 +30,6 @@ namespace big main_batch.add("PF", "48 8B 05 ? ? ? ? 48 8B 48 08 48 85 C9 74 52 8B 81", [this](memory::handle ptr) { m_ped_factory = ptr.add(3).rip().as(); - - LOG(G3LOG_DEBUG) << "CPedFactory => [" << HEX_TO_UPPER(m_ped_factory) << "]"; }); // Network Player Manager @@ -70,8 +68,6 @@ namespace big main_batch.add("SG", "48 8D 15 ? ? ? ? 4C 8B C0 E8 ? ? ? ? 48 85 FF 48 89 1D", [this](memory::handle ptr) { m_script_globals = ptr.add(3).rip().as(); - - LOG(G3LOG_DEBUG) << "ScriptGlobals => [" << HEX_TO_UPPER(m_script_globals) << "]"; }); // Game Script Handle Manager @@ -217,8 +213,6 @@ namespace big main_batch.add("RI", "0F B7 44 24 ? 66 89 44 4E", [this](memory::handle ptr) { m_replay_interface = ptr.add(0x1F).rip().as(); - - LOG(G3LOG_DEBUG) << "rage::CReplayInterface => [" << HEX_TO_UPPER(m_replay_interface) << "]"; }); // Pointer to Handle @@ -261,8 +255,6 @@ namespace big main_batch.add("FR", "3B 0D ? ? ? ? 73 17", [this](memory::handle ptr) { m_friend_registry = ptr.add(2).rip().as(); - - LOG(G3LOG_DEBUG) << "FriendRegistry => [" << HEX_TO_UPPER(m_friend_registry) << "]"; }); // GET_SCREEN_COORDS_FROM_WORLD_COORDS @@ -326,8 +318,6 @@ namespace big main_batch.add("MHT", "4C 03 05 ? ? ? ? EB 03", [this](memory::handle ptr) { m_model_table = ptr.add(3).rip().as*>(); - - LOG(G3LOG_DEBUG) << "HashTable => [" << HEX_TO_UPPER(m_model_table) << "]"; }); // Get Label Text