Skip to content

Commit

Permalink
Add scan_alignment parameter to find_pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
ZeroMemes committed Aug 16, 2023
1 parent 35ea12b commit a4495f3
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 72 deletions.
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ set(LIBHAT_SRC
src/arch/x86/AVX512.cpp
src/arch/x86/System.cpp

src/arch/arm/Neon.cpp
src/arch/arm/System.cpp)

add_library(libhat STATIC ${LIBHAT_SRC})
Expand Down
28 changes: 16 additions & 12 deletions include/libhat/Scanner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ namespace hat {
using rel_t = int32_t;
public:
constexpr scan_result() : result(nullptr) {}
constexpr scan_result(const std::byte* result) : result(result) {} // NOLINT(google-explicit-constructor)
constexpr scan_result(std::nullptr_t) : result(nullptr) {} // NOLINT(google-explicit-constructor)
constexpr scan_result(const std::byte* result) : result(result) {} // NOLINT(google-explicit-constructor)

/// Reads an integer of the specified type located at an offset from the signature result
template<std::integral Int>
Expand Down Expand Up @@ -50,29 +51,30 @@ namespace hat {
const std::byte* result;
};

enum class scan_alignment {
X1
};

namespace detail {

enum class scan_mode {
Auto, // Automatically choose the mode to use
Search, // std::search
FastFirst, // std::find + std::equal
SSE, // x86 SSE 4.1
AVX2, // x86 AVX2
AVX512, // x86 AVX512
Neon, // ARM Neon

// Fallback mode to use for SIMD remaining bytes
Single = FastFirst
};

template<scan_mode>
template<scan_mode, scan_alignment>
scan_result find_pattern(const std::byte* begin, const std::byte* end, signature_view signature);

template<>
scan_result find_pattern<scan_mode::Auto>(const std::byte* begin, const std::byte* end, signature_view signature);
template<scan_alignment alignment>
scan_result find_pattern(const std::byte* begin, const std::byte* end, signature_view signature);

template<>
constexpr scan_result find_pattern<scan_mode::FastFirst>(const std::byte* begin, const std::byte* end, signature_view signature) {
constexpr scan_result find_pattern<scan_mode::FastFirst, scan_alignment::X1>(const std::byte* begin, const std::byte* end, signature_view signature) {
const auto firstByte = *signature[0];
const auto scanEnd = end - signature.size() + 1;

Expand Down Expand Up @@ -111,29 +113,31 @@ namespace hat {
);

/// Perform a signature scan on the entirety of the process module or a specified module
template<scan_alignment alignment = scan_alignment::X1>
scan_result find_pattern(
signature_view signature,
process::module_t mod = process::get_process_module()
);

/// Perform a signature scan on a specific section of the process module or a specified module
template<scan_alignment alignment = scan_alignment::X1>
scan_result find_pattern(
signature_view signature,
std::string_view section,
process::module_t mod = process::get_process_module()
);

/// Root implementation of FindPattern
template<detail::byte_iterator Iter>
/// Root implementation of find_pattern
template<detail::byte_iterator Iter, scan_alignment alignment = scan_alignment::X1>
constexpr scan_result find_pattern(
Iter begin,
Iter end,
signature_view signature
) {
if LIBHAT_IF_CONSTEVAL {
return detail::find_pattern<detail::scan_mode::Single>(std::to_address(begin), std::to_address(end), signature);
return detail::find_pattern<detail::scan_mode::Single, alignment>(std::to_address(begin), std::to_address(end), signature);
} else {
return detail::find_pattern<detail::scan_mode::Auto>(std::to_address(begin), std::to_address(end), signature);
return detail::find_pattern<alignment>(std::to_address(begin), std::to_address(end), signature);
}
}
}
35 changes: 10 additions & 25 deletions src/Scanner.cpp
Original file line number Diff line number Diff line change
@@ -1,65 +1,50 @@
#include <libhat/Scanner.hpp>

#include <map>

#include <libhat/Defines.hpp>
#include <libhat/System.hpp>

namespace hat {

using namespace hat::process;

template<scan_alignment alignment>
scan_result find_pattern(signature_view signature, module_t mod) {
const auto data = get_module_data(mod);
if (data.empty()) {
return nullptr;
}
return find_pattern(data.begin(), data.end(), signature);
return find_pattern<alignment>(data.begin(), data.end(), signature);
}

template<scan_alignment alignment>
scan_result find_pattern(signature_view signature, std::string_view section, module_t mod) {
const auto data = get_section_data(mod, section);
if (data.empty()) {
return nullptr;
}
return find_pattern(data.begin(), data.end(), signature);
return find_pattern<alignment>(data.begin(), data.end(), signature);
}
}

namespace hat::detail {

template<>
[[deprecated]] scan_result find_pattern<scan_mode::Search>(const std::byte* begin, const std::byte* end, signature_view signature) {
auto it = std::search(
begin, end,
signature.begin(), signature.end(),
[](auto byte, auto opt) {
return !opt.has_value() || *opt == byte;
});
return it != end ? it : nullptr;
}

template<>
scan_result find_pattern<scan_mode::Auto>(const std::byte* begin, const std::byte* end, signature_view signature) {
template<scan_alignment alignment>
scan_result find_pattern(const std::byte* begin, const std::byte* end, signature_view signature) {
const auto size = signature.size();
#if defined(LIBHAT_X86)
const auto& ext = get_system().extensions;
if (ext.bmi1) {
if (size <= 65 && ext.avx512) {
return find_pattern<scan_mode::AVX512>(begin, end, signature);
return find_pattern<scan_mode::AVX512, alignment>(begin, end, signature);
} else if (size <= 33 && ext.avx2) {
return find_pattern<scan_mode::AVX2>(begin, end, signature);
return find_pattern<scan_mode::AVX512, alignment>(begin, end, signature);
}
}
if (size <= 17 && ext.sse41) {
return find_pattern<scan_mode::SSE>(begin, end, signature);
}
#elif defined(LIBHAT_ARM)
if (size <= 17) {
return find_pattern<scan_mode::Neon>(begin, end, signature);
return find_pattern<scan_mode::SSE, alignment>(begin, end, signature);
}
#endif
// If none of the vectorized implementations are available/supported, then fallback to scanning per-byte
return find_pattern<scan_mode::Single>(begin, end, signature);
return find_pattern<scan_mode::Single, alignment>(begin, end, signature);
}
}
28 changes: 0 additions & 28 deletions src/arch/arm/Neon.cpp

This file was deleted.

4 changes: 2 additions & 2 deletions src/arch/x86/AVX2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace hat::detail {
}

template<>
scan_result find_pattern<scan_mode::AVX2>(const std::byte* begin, const std::byte* end, signature_view signature) {
scan_result find_pattern<scan_mode::AVX2, scan_alignment::X1>(const std::byte* begin, const std::byte* end, signature_view signature) {
// 256 bit vector containing first signature byte repeated
const auto firstByte = _mm256_set1_epi8(static_cast<int8_t>(*signature[0]));
const auto [signatureBytes, signatureMask] = load_signature_256(signature);
Expand All @@ -53,7 +53,7 @@ namespace hat::detail {

// Look in remaining bytes that couldn't be grouped into 256 bits
begin = reinterpret_cast<const std::byte*>(vec);
return find_pattern<scan_mode::Single>(begin, end, signature);
return find_pattern<scan_mode::Single, scan_alignment::X1>(begin, end, signature);
}
}
#endif
4 changes: 2 additions & 2 deletions src/arch/x86/AVX512.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace hat::detail {
}

template<>
scan_result find_pattern<scan_mode::AVX512>(const std::byte* begin, const std::byte* end, signature_view signature) {
scan_result find_pattern<scan_mode::AVX512, scan_alignment::X1>(const std::byte* begin, const std::byte* end, signature_view signature) {
// 512 bit vector containing first signature byte repeated
const auto firstByte = _mm512_set1_epi8(static_cast<int8_t>(*signature[0]));
const auto [signatureBytes, signatureMask] = load_signature_512(signature);
Expand All @@ -51,7 +51,7 @@ namespace hat::detail {

// Look in remaining bytes that couldn't be grouped into 512 bits
begin = reinterpret_cast<const std::byte*>(vec);
return find_pattern<scan_mode::Single>(begin, end, signature);
return find_pattern<scan_mode::Single, scan_alignment::X1>(begin, end, signature);
}
}
#endif
4 changes: 2 additions & 2 deletions src/arch/x86/SSE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace hat::detail {
}

template<>
scan_result find_pattern<scan_mode::SSE>(const std::byte* begin, const std::byte* end, signature_view signature) {
scan_result find_pattern<scan_mode::SSE, scan_alignment::X1>(const std::byte* begin, const std::byte* end, signature_view signature) {
// 256 bit vector containing first signature byte repeated
const auto firstByte = _mm_set1_epi8(static_cast<int8_t>(*signature[0]));
const auto [signatureBytes, signatureMask] = load_signature_128(signature);
Expand All @@ -53,7 +53,7 @@ namespace hat::detail {

// Look in remaining bytes that couldn't be grouped into 128 bits
begin = reinterpret_cast<const std::byte*>(vec);
return find_pattern<scan_mode::Single>(begin, end, signature);
return find_pattern<scan_mode::Single, scan_alignment::X1>(begin, end, signature);
}
}
#endif

0 comments on commit a4495f3

Please sign in to comment.