diff --git a/CMakeLists.txt b/CMakeLists.txt index ad7efdd..9bf0093 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ # CMakeList.txt : Top-level CMake project file, do global configuration # and include sub-projects here. # -cmake_minimum_required (VERSION 3.15) +cmake_minimum_required(VERSION 3.15) -project ("LightningScanner" VERSION 1.0.1 LANGUAGES CXX) +project("LightningScanner" VERSION 1.0.1 LANGUAGES CXX) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") @@ -16,71 +16,83 @@ set(LIGHTNING_SCANNER_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/cmake/Lightni if (MSVC) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) -endif() +endif () -add_library(LightningScanner "include/LightningScanner/LightningScanner.hpp" "include/LightningScanner/backends/Avx2.hpp" "include/LightningScanner/Pattern.hpp" "src/backends/Avx2.cpp" "src/CpuInfo.cpp" "src/backends/Sse42.cpp" "include/LightningScanner/allocator/AlignedAllocator.hpp" "src/backends/Scalar.cpp") +add_library(LightningScanner "include/LightningScanner/LightningScanner.hpp" + "include/LightningScanner/Pattern.hpp" + "src/CpuInfo.cpp" + "include/LightningScanner/allocator/AlignedAllocator.hpp" + "src/backends/Scalar.cpp" + "src/backends/StdFind.cpp") -if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - set_source_files_properties("src/backends/Avx2.cpp" PROPERTIES COMPILE_FLAGS /arch:AVX2) -else () - set_source_files_properties("src/backends/Avx2.cpp" PROPERTIES COMPILE_FLAGS -mavx2) - set_source_files_properties("src/backends/Sse42.cpp" PROPERTIES COMPILE_FLAGS -msse4.2) -endif() +if (NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + target_sources(LightningScanner PRIVATE + "src/backends/Avx2.cpp" + "src/backends/Sse42.cpp" + ) + + if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set_source_files_properties("src/backends/Avx2.cpp" PROPERTIES COMPILE_FLAGS /arch:AVX2) + else () + set_source_files_properties("src/backends/Avx2.cpp" PROPERTIES COMPILE_FLAGS -mavx2) + set_source_files_properties("src/backends/Sse42.cpp" PROPERTIES COMPILE_FLAGS -msse4.2) + endif () +endif () target_compile_features(LightningScanner PUBLIC cxx_std_17) -target_include_directories(LightningScanner PUBLIC - $ - $) +target_include_directories(LightningScanner PUBLIC + $ + $) option(LIGHTNING_SCANNER_BUILD_BENCH "Build Benchmarks" OFF) -if (LIGHTNING_SCANNER_BUILD_BENCH) - add_subdirectory("bench") -endif() +if (LIGHTNING_SCANNER_BUILD_BENCH) + add_subdirectory("bench") +endif () option(LIGHTNING_SCANNER_BUILD_DOCS "Build Docs" OFF) if (LIGHTNING_SCANNER_BUILD_DOCS) - add_subdirectory("docs") -endif() + add_subdirectory("docs") +endif () -option(LIGHTNING_SCANNER_BUILD_TESTS "Build Tests" OFF) +option(LIGHTNING_SCANNER_BUILD_TESTS "Build Tests" ON) if (LIGHTNING_SCANNER_BUILD_TESTS) - add_subdirectory("tests") -endif() + add_subdirectory("tests") +endif () ## Install if (LIGHTNING_SCANNER_INSTALL) - include(CMakePackageConfigHelpers) - - install( - DIRECTORY "${PROJECT_SOURCE_DIR}/include/LightningScanner" - DESTINATION "${LIGHTNING_SCANNER_INCLUDE_INSTALL_DIR}" - ) - install( - TARGETS LightningScanner - EXPORT LightningScannerTargets - INCLUDES DESTINATION "${LIGHTNING_SCANNER_INCLUDE_INSTALL_DIR}" - LIBRARY DESTINATION "${LIGHTNING_SCANNER_LIBRARY_INSTALL_DIR}" - ARCHIVE DESTINATION "${LIGHTNING_SCANNER_LIBRARY_INSTALL_DIR}" - RUNTIME DESTINATION "${LIGHTNING_SCANNER_BINARY_INSTALL_DIR}" - ) - export( - TARGETS LightningScanner - NAMESPACE LightningScanner:: - FILE "${LIGHTNING_SCANNER_CONFIG_INSTALL_DIR}/LightningScannerTargets.cmake" - ) - - write_basic_package_version_file( - "LightningScannerVersion.cmake" - COMPATIBILITY AnyNewerVersion - ) - install( - FILES "${CMAKE_CURRENT_BINARY_DIR}/LightningScannerVersion.cmake" "cmake/LightningScannerConfig.cmake" - DESTINATION "${LIGHTNING_SCANNER_CONFIG_INSTALL_DIR}" - ) - install( - EXPORT LightningScannerTargets - NAMESPACE LightningScanner:: - DESTINATION "${LIGHTNING_SCANNER_CONFIG_INSTALL_DIR}" - ) - -endif() \ No newline at end of file + include(CMakePackageConfigHelpers) + + install( + DIRECTORY "${PROJECT_SOURCE_DIR}/include/LightningScanner" + DESTINATION "${LIGHTNING_SCANNER_INCLUDE_INSTALL_DIR}" + ) + install( + TARGETS LightningScanner + EXPORT LightningScannerTargets + INCLUDES DESTINATION "${LIGHTNING_SCANNER_INCLUDE_INSTALL_DIR}" + LIBRARY DESTINATION "${LIGHTNING_SCANNER_LIBRARY_INSTALL_DIR}" + ARCHIVE DESTINATION "${LIGHTNING_SCANNER_LIBRARY_INSTALL_DIR}" + RUNTIME DESTINATION "${LIGHTNING_SCANNER_BINARY_INSTALL_DIR}" + ) + export( + TARGETS LightningScanner + NAMESPACE LightningScanner:: + FILE "${LIGHTNING_SCANNER_CONFIG_INSTALL_DIR}/LightningScannerTargets.cmake" + ) + + write_basic_package_version_file( + "LightningScannerVersion.cmake" + COMPATIBILITY AnyNewerVersion + ) + install( + FILES "${CMAKE_CURRENT_BINARY_DIR}/LightningScannerVersion.cmake" "cmake/LightningScannerConfig.cmake" + DESTINATION "${LIGHTNING_SCANNER_CONFIG_INSTALL_DIR}" + ) + install( + EXPORT LightningScannerTargets + NAMESPACE LightningScanner:: + DESTINATION "${LIGHTNING_SCANNER_CONFIG_INSTALL_DIR}" + ) + +endif () \ No newline at end of file diff --git a/bench/LightningBench.cpp b/bench/LightningBench.cpp index 390ca48..be34f13 100644 --- a/bench/LightningBench.cpp +++ b/bench/LightningBench.cpp @@ -15,6 +15,9 @@ std::ostream& operator<<(std::ostream& os, const ScanMode& mode) { case ScanMode::Sse42: os << "SSE4.2"; break; + case ScanMode::StdFind: + os << "StdFind"; + break; case ScanMode::Scalar: os << "Scalar"; break; @@ -66,6 +69,10 @@ int main() { largeBinary.data(), largeBinary.size(), "48 89 5c 24 ?? 48 89 6c 24 ?? 48 89 74 24 ?? 48 89 7c 24 ?? 41 56 41 " "57 4c 8b 79 38 aa bf cd"); + Bench( + largeBinary.data(), largeBinary.size(), + "48 89 5c 24 ?? 48 89 6c 24 ?? 48 89 74 24 ?? 48 89 7c 24 ?? 41 56 41 " + "57 4c 8b 79 38 aa bf cd"); Bench( largeBinary.data(), largeBinary.size(), "48 89 5c 24 ?? 48 89 6c 24 ?? 48 89 74 24 ?? 48 89 7c 24 ?? 41 56 41 " diff --git a/include/LightningScanner/LightningScanner.hpp b/include/LightningScanner/LightningScanner.hpp index 0d1702d..4e17fbd 100644 --- a/include/LightningScanner/LightningScanner.hpp +++ b/include/LightningScanner/LightningScanner.hpp @@ -6,10 +6,14 @@ #include #include +#include +#include + +#if !defined(__aarch64__) #include #include -#include #include +#endif namespace LightningScanner { @@ -56,12 +60,24 @@ class Scanner { * \endcode */ ScanResult Find(void* startAddr, size_t size) const { +#if !defined(__aarch64__) + return FindAMD64(startAddr, size); +#else + return FindAArch64(startAddr, size); +#endif + } + +private: +#if !defined(__aarch64__) + ScanResult FindAMD64(void* startAddr, size_t size) const { const CpuInfo& cpuInfo = CpuInfo::GetCpuInfo(); if (PreferredMode == ScanMode::Avx2 && cpuInfo.avx2Supported) return FindAvx2(m_Pattern, startAddr, size); else if (PreferredMode == ScanMode::Sse42 && cpuInfo.sse42Supported) return FindSse42(m_Pattern, startAddr, size); + else if (PreferredMode == ScanMode::StdFind) + return FindStdFind(m_Pattern, startAddr, size); else if (PreferredMode == ScanMode::Scalar) return FindScalar(m_Pattern, startAddr, size); @@ -72,6 +88,14 @@ class Scanner { return FindScalar(m_Pattern, startAddr, size); } +#else + ScanResult FindAArch64(void* startAddr, size_t size) const { + if (PreferredMode == ScanMode::StdFind) + return FindStdFind(m_Pattern, startAddr, size); + + return FindScalar(m_Pattern, startAddr, size); + } +#endif private: Pattern m_Pattern; diff --git a/include/LightningScanner/Pattern.hpp b/include/LightningScanner/Pattern.hpp index df36973..36e9369 100644 --- a/include/LightningScanner/Pattern.hpp +++ b/include/LightningScanner/Pattern.hpp @@ -23,7 +23,8 @@ struct Pattern { * * \tparam Len pattern string length. * - * \param pattern pattern string. + * \param pattern pattern string. The first byte of the pattern string must + * not be a wildcard. */ template constexpr Pattern(const char (&pattern)[Len]) : Pattern(pattern, Len - 1) {} @@ -31,7 +32,8 @@ struct Pattern { /** * Create a new Pattern instance from a `string_view` * - * \param pattern pattern string. + * \param pattern pattern string. The first byte of the pattern string must + * not be a wildcard. */ Pattern(const std::string_view pattern) : Pattern(pattern.data(), pattern.size()) {} @@ -39,7 +41,8 @@ struct Pattern { /** * Create a new Pattern instance from a c-string and its length * - * \param pattern pattern string. + * \param pattern pattern string. The first byte of the pattern string must + * not be a wildcard. * \param len pattern string length. */ Pattern(const char* pattern, const size_t len) { diff --git a/include/LightningScanner/ScanMode.hpp b/include/LightningScanner/ScanMode.hpp index d0f2936..3f166c0 100644 --- a/include/LightningScanner/ScanMode.hpp +++ b/include/LightningScanner/ScanMode.hpp @@ -12,4 +12,6 @@ enum class ScanMode { Sse42, /** Scan mode that uses AVX2 SIMD instructions */ Avx2, + /** Scan mode that uses std::find */ + StdFind }; \ No newline at end of file diff --git a/include/LightningScanner/backends/StdFind.hpp b/include/LightningScanner/backends/StdFind.hpp new file mode 100644 index 0000000..180a1b2 --- /dev/null +++ b/include/LightningScanner/backends/StdFind.hpp @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +namespace LightningScanner { + +/** + * Scan the binary using std::find scanning. + * + * \headerfile StdFind.hpp + * + * \param{in} data pattern data. + * \param{in} startAddr addres to start the search from. + * \param{in} size binary size of the search area + */ +ScanResult FindStdFind(const Pattern& data, void* startAddr, size_t size); + +} // namespace LightningScanner \ No newline at end of file diff --git a/src/CpuInfo.cpp b/src/CpuInfo.cpp index 2235393..662e0ce 100644 --- a/src/CpuInfo.cpp +++ b/src/CpuInfo.cpp @@ -7,13 +7,16 @@ namespace LightningScanner { #include #define cpuid(info, x) __cpuidex(info, x, 0) #else +#if !defined(__aarch64__) #include void cpuid(int info[4], int infoType) { __cpuid_count(infoType, 0, info[0], info[1], info[2], info[3]); } #endif +#endif CpuInfo::CpuInfo() { +#if !defined(__aarch64__) int32_t info[4]; cpuid(info, 0); int32_t idsAmount = info[0]; @@ -35,6 +38,7 @@ CpuInfo::CpuInfo() { avx2Supported = cpuInfo[1] & AVX2_MASK; } +#endif } const CpuInfo& CpuInfo::GetCpuInfo() { diff --git a/src/backends/StdFind.cpp b/src/backends/StdFind.cpp new file mode 100644 index 0000000..c2c1b4b --- /dev/null +++ b/src/backends/StdFind.cpp @@ -0,0 +1,34 @@ +#include +#include + +namespace LightningScanner { + +ScanResult FindStdFind(const Pattern& data, void* startAddr, size_t size) { + uint8_t* start = static_cast(startAddr); + uint8_t* end = + static_cast(startAddr) + size - data.unpaddedSize + 1; + + uint8_t element = data.data[0]; + while ((start = std::find(start, end, element)) != end) { + bool found = true; + + for (size_t i = 0; i < data.unpaddedSize; i++) { + uint8_t searchElement = data.data[i] & data.mask[i]; + uint8_t foundElement = start[i] & data.mask[i]; + if (searchElement != foundElement) { + found = false; + break; + } + } + + if (found) { + return ScanResult(start); + } + + start++; + } + + return ScanResult(nullptr); +} + +} // namespace LightningScanner \ No newline at end of file diff --git a/tests/LargePattern.cpp b/tests/LargePattern.cpp index 363f6bb..9c2e38f 100644 --- a/tests/LargePattern.cpp +++ b/tests/LargePattern.cpp @@ -47,6 +47,19 @@ TEST(LargePattern, Sse42) { ASSERT_EQ(offset, 0x40); } +TEST(LargePattern, StdFind) { + const Scanner scanner( + "42 cd e7 f8 21 5b d6 b8 d1 be 12 0e 85 34 c4 ?? 03 7e bc 7b b9 29 b6 " + "07 31 7e ?? dd 3e 0a e7 71 f3 b7 76 3f 36 e1 f3 3b c6 e5 ?? f8 97 67 " + "86 60 "); + + const uint8_t* pointer = + scanner.Find((void*)dataSet, dataSetSize).Get(); + const size_t offset = ((uint64_t)pointer - (uint64_t)dataSet); + + ASSERT_EQ(offset, 0x40); +} + TEST(LargePattern, Scalar) { const Scanner scanner( "42 cd e7 f8 21 5b d6 b8 d1 be 12 0e 85 34 c4 ?? 03 7e bc 7b b9 29 b6 " diff --git a/tests/SimilarPattern.cpp b/tests/SimilarPattern.cpp index 7f7e518..31d4314 100644 --- a/tests/SimilarPattern.cpp +++ b/tests/SimilarPattern.cpp @@ -53,6 +53,18 @@ TEST(SimilarPattern, Sse42) { ASSERT_EQ(offset, 0x24); } +TEST(SimilarPattern, StdFind) { + const Scanner scanner( + "40 57 48 83 EC ? 48 C7 44 24 ? ? ? ? ? 48 89 5C 24 ? 48 89 6C 24 ? 48 " + "89 74 24 ? 49 8B E9 48 8B F2"); + + const uint8_t* pointer = + scanner.Find((void*)dataSet, dataSetSize).Get(); + const size_t offset = ((uint64_t)pointer - (uint64_t)dataSet); + + ASSERT_EQ(offset, 0x24); +} + TEST(SimilarPattern, Scalar) { const Scanner scanner( "40 57 48 83 EC ? 48 C7 44 24 ? ? ? ? ? 48 89 5C 24 ? 48 89 6C 24 ? 48 " diff --git a/tests/SmallPattern.cpp b/tests/SmallPattern.cpp index 5f24c9b..7a1b950 100644 --- a/tests/SmallPattern.cpp +++ b/tests/SmallPattern.cpp @@ -39,6 +39,15 @@ TEST(SmallPattern, Sse42) { ASSERT_EQ(offset, 0x24); } +TEST(SmallPattern, StdFind) { + const Scanner scanner("a0 9e 87 00 ?? 5c"); + const uint8_t* pointer = + scanner.Find((void*)dataSet, dataSetSize).Get(); + const size_t offset = ((uint64_t)pointer - (uint64_t)dataSet); + + ASSERT_EQ(offset, 0x24); +} + TEST(SmallPattern, Scalar) { const Scanner scanner("a0 9e 87 00 ?? 5c"); const uint8_t* pointer =