Auto stash before checking out "origin/main"

This commit is contained in:
2026-03-10 20:06:00 +03:00
parent 3ccbb0b25b
commit 1341ef9925
3 changed files with 181 additions and 2 deletions

View File

@@ -10,7 +10,6 @@
#include <omath/utility/pe_pattern_scan.hpp>
#include <omath/utility/section_scan_result.hpp>
#include <sol/sol.hpp>
#endif
namespace omath::lua
{
@@ -101,4 +100,5 @@ namespace omath::lua
return *result;
};
}
} // namespace omath::lua
} // namespace omath::lua
#endif

View File

@@ -0,0 +1,66 @@
-- PatternScanner tests: generic scan over a Lua string buffer
function PatternScanner_FindsExactPattern()
local buf = "\x90\x01\x02\x03\x04"
local offset = omath.PatternScanner.scan(buf, "90 01 02")
assert(offset ~= nil, "expected pattern to be found")
assert(offset == 0, "expected offset 0, got " .. tostring(offset))
end
function PatternScanner_FindsPatternAtNonZeroOffset()
local buf = "\x00\x00\xAB\xCD\xEF"
local offset = omath.PatternScanner.scan(buf, "AB CD EF")
assert(offset ~= nil, "expected pattern to be found")
assert(offset == 2, "expected offset 2, got " .. tostring(offset))
end
function PatternScanner_WildcardMatches()
local buf = "\xDE\xAD\xBE\xEF"
local offset = omath.PatternScanner.scan(buf, "DE ?? BE")
assert(offset ~= nil, "expected wildcard match")
assert(offset == 0)
end
function PatternScanner_ReturnsNilWhenNotFound()
local buf = "\x01\x02\x03"
local offset = omath.PatternScanner.scan(buf, "AA BB CC")
assert(offset == nil, "expected nil for not-found pattern")
end
function PatternScanner_ReturnsNilForEmptyBuffer()
local offset = omath.PatternScanner.scan("", "90 01")
assert(offset == nil)
end
-- PePatternScanner tests: scan_in_module uses FAKE_MODULE_BASE injected from C++
-- The fake module contains {0x90, 0x01, 0x02, 0x03, 0x04} placed at raw offset 0x200
function PeScanner_FindsExactPattern()
local addr = omath.PePatternScanner.scan_in_module(FAKE_MODULE_BASE, "90 01 02")
assert(addr ~= nil, "expected pattern to be found in module")
local offset = addr - FAKE_MODULE_BASE
assert(offset == 0x200, string.format("expected offset 0x200, got 0x%X", offset))
end
function PeScanner_WildcardMatches()
local addr = omath.PePatternScanner.scan_in_module(FAKE_MODULE_BASE, "90 ?? 02")
assert(addr ~= nil, "expected wildcard match in module")
local offset = addr - FAKE_MODULE_BASE
assert(offset == 0x200, string.format("expected offset 0x200, got 0x%X", offset))
end
function PeScanner_ReturnsNilWhenNotFound()
local addr = omath.PePatternScanner.scan_in_module(FAKE_MODULE_BASE, "AA BB CC DD")
assert(addr == nil, "expected nil for not-found pattern")
end
function PeScanner_CustomSectionFallsBackToNil()
-- Request a section that doesn't exist in our fake module
local addr = omath.PePatternScanner.scan_in_module(FAKE_MODULE_BASE, "90 01 02", ".rdata")
assert(addr == nil, "expected nil for wrong section name")
end
-- SectionScanResult: verify the type is registered and tostring works on a C++-returned value
function SectionScanResult_TypeIsRegistered()
assert(omath.SectionScanResult ~= nil, "SectionScanResult type should be registered")
end

View File

@@ -0,0 +1,113 @@
//
// Created by orange on 10.03.2026.
//
#include <gtest/gtest.h>
#include <lua.hpp>
#include <omath/lua/lua.hpp>
#include <cstdint>
#include <cstring>
#include <vector>
namespace
{
std::vector<std::uint8_t> make_fake_pe_module(std::uint32_t base_of_code, std::uint32_t size_code,
const std::vector<std::uint8_t>& code_bytes)
{
constexpr std::uint32_t e_lfanew = 0x80;
constexpr std::uint32_t nt_sig = 0x4550;
constexpr std::uint16_t opt_magic = 0x020B; // PE32+
constexpr std::uint16_t num_sections = 1;
constexpr std::uint16_t opt_hdr_size = 0xF0;
constexpr std::uint32_t section_table_off = e_lfanew + 4 + 20 + opt_hdr_size;
constexpr std::uint32_t section_hdr_size = 40;
constexpr std::uint32_t text_chars = 0x60000020;
const std::uint32_t headers_end = section_table_off + section_hdr_size;
const std::uint32_t code_end = base_of_code + size_code;
const std::uint32_t total_size = std::max(headers_end, code_end) + 0x100;
std::vector<std::uint8_t> buf(total_size, 0);
auto w16 = [&](std::size_t off, std::uint16_t v) { std::memcpy(buf.data() + off, &v, 2); };
auto w32 = [&](std::size_t off, std::uint32_t v) { std::memcpy(buf.data() + off, &v, 4); };
auto w64 = [&](std::size_t off, std::uint64_t v) { std::memcpy(buf.data() + off, &v, 8); };
w16(0x00, 0x5A4D);
w32(0x3C, e_lfanew);
w32(e_lfanew, nt_sig);
const std::size_t fh = e_lfanew + 4;
w16(fh + 2, num_sections);
w16(fh + 16, opt_hdr_size);
const std::size_t opt = fh + 20;
w16(opt + 0, opt_magic);
w32(opt + 4, size_code);
w32(opt + 20, base_of_code);
w64(opt + 24, 0);
w32(opt + 32, 0x1000);
w32(opt + 36, 0x200);
w32(opt + 56, code_end);
w32(opt + 60, headers_end);
w32(opt + 108, 0);
const std::size_t sh = section_table_off;
std::memcpy(buf.data() + sh, ".text", 5);
w32(sh + 8, size_code);
w32(sh + 12, base_of_code);
w32(sh + 16, size_code);
w32(sh + 20, base_of_code);
w32(sh + 36, text_chars);
if (base_of_code + code_bytes.size() <= buf.size())
std::memcpy(buf.data() + base_of_code, code_bytes.data(), code_bytes.size());
return buf;
}
} // namespace
class LuaPeScanner : public ::testing::Test
{
protected:
lua_State* L = nullptr;
std::vector<std::uint8_t> m_fake_module;
void SetUp() override
{
const std::vector<std::uint8_t> code = {0x90, 0x01, 0x02, 0x03, 0x04};
m_fake_module = make_fake_pe_module(0x200, static_cast<std::uint32_t>(code.size()), code);
L = luaL_newstate();
luaL_openlibs(L);
omath::lua::LuaInterpreter::register_lib(L);
lua_pushinteger(L, static_cast<lua_Integer>(
reinterpret_cast<std::uintptr_t>(m_fake_module.data())));
lua_setglobal(L, "FAKE_MODULE_BASE");
if (luaL_dofile(L, LUA_SCRIPTS_DIR "/pe_scanner_tests.lua") != LUA_OK)
FAIL() << lua_tostring(L, -1);
}
void TearDown() override { lua_close(L); }
void check(const char* func_name)
{
lua_getglobal(L, func_name);
if (lua_pcall(L, 0, 0, 0) != LUA_OK)
{
FAIL() << lua_tostring(L, -1);
lua_pop(L, 1);
}
}
};
TEST_F(LuaPeScanner, PatternScanner_FindsExactPattern) { check("PatternScanner_FindsExactPattern"); }
TEST_F(LuaPeScanner, PatternScanner_FindsPatternAtOffset) { check("PatternScanner_FindsPatternAtNonZeroOffset"); }
TEST_F(LuaPeScanner, PatternScanner_WildcardMatches) { check("PatternScanner_WildcardMatches"); }
TEST_F(LuaPeScanner, PatternScanner_ReturnsNilWhenNotFound) { check("PatternScanner_ReturnsNilWhenNotFound"); }
TEST_F(LuaPeScanner, PatternScanner_ReturnsNilForEmptyBuffer){ check("PatternScanner_ReturnsNilForEmptyBuffer"); }
TEST_F(LuaPeScanner, PeScanner_FindsExactPattern) { check("PeScanner_FindsExactPattern"); }
TEST_F(LuaPeScanner, PeScanner_WildcardMatches) { check("PeScanner_WildcardMatches"); }
TEST_F(LuaPeScanner, PeScanner_ReturnsNilWhenNotFound) { check("PeScanner_ReturnsNilWhenNotFound"); }
TEST_F(LuaPeScanner, PeScanner_CustomSectionFallsBackToNil) { check("PeScanner_CustomSectionFallsBackToNil"); }
TEST_F(LuaPeScanner, SectionScanResult_TypeIsRegistered) { check("SectionScanResult_TypeIsRegistered"); }