Skip to content

Commit a4b3968

Browse files
authored
Merge pull request #1027 from UE4SS-RE/sigscanreadable
fix(scanner): updates the lua scanner to only scan readable memory
2 parents c68f4f7 + 7159254 commit a4b3968

File tree

1 file changed

+117
-71
lines changed

1 file changed

+117
-71
lines changed

deps/first/SinglePassSigScanner/src/SinglePassSigScanner.cpp

Lines changed: 117 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ namespace RC
329329
{
330330
std::vector<int> bytes;
331331
char* const start = const_cast<char*>(signature.data());
332-
char* const end = const_cast<char*>(signature.data()) + strlen(signature.data());
332+
char* const end = const_cast<char*>(signature.data()) + signature.size();
333333

334334
for (char* current = start; current < end; current++)
335335
{
@@ -367,11 +367,11 @@ namespace RC
367367
auto end_address = static_cast<uint8_t*>(module.lpBaseOfDll) + module.SizeOfImage;
368368

369369
MEMORY_BASIC_INFORMATION memory_info{};
370-
DWORD protect_flags = PAGE_GUARD | PAGE_NOCACHE | PAGE_NOACCESS;
370+
DWORD protect_flags = PAGE_GUARD | PAGE_NOACCESS;
371371

372372
void* address_found{};
373373

374-
for (uint8_t* i = start_address; i < end_address; ++i)
374+
for (uint8_t* i = start_address; i < end_address;)
375375
{
376376
if (VirtualQuery(i, &memory_info, sizeof(memory_info)))
377377
{
@@ -385,12 +385,16 @@ namespace RC
385385

386386
for (uint8_t* region_start = static_cast<uint8_t*>(memory_info.BaseAddress); region_start < region_end; ++region_start)
387387
{
388-
if (region_start > end_address || region_start + string_to_scan_for.size() > end_address)
388+
// Check boundaries - string_to_scan_for.size() is character count, need to multiply by sizeof(wchar_t) for bytes
389+
size_t string_size_bytes = string_to_scan_for.size() * sizeof(wchar_t);
390+
if (region_start > end_address ||
391+
region_start + string_size_bytes > end_address ||
392+
region_start + string_size_bytes > region_end)
389393
{
390394
break;
391395
}
392396

393-
std::wstring_view maybe_string = std::wstring_view((const wchar_t*)region_start, string_to_scan_for.size());
397+
std::wstring_view maybe_string = std::wstring_view(reinterpret_cast<const wchar_t*>(region_start), string_to_scan_for.size());
394398
if (maybe_string == string_to_scan_for)
395399
{
396400
address_found = region_start;
@@ -404,6 +408,10 @@ namespace RC
404408
}
405409
i = static_cast<uint8_t*>(memory_info.BaseAddress) + memory_info.RegionSize;
406410
}
411+
else
412+
{
413+
++i;
414+
}
407415
}
408416

409417
return address_found;
@@ -436,7 +444,7 @@ namespace RC
436444
}
437445
}
438446

439-
static auto make_mask(std::string_view pattern, SignatureContainer& signature_container, const size_t data_size) -> PatternData
447+
static auto make_mask(std::string_view pattern, SignatureContainer& signature_container) -> PatternData
440448
{
441449
PatternData pattern_data{};
442450

@@ -474,16 +482,6 @@ namespace RC
474482
++i;
475483
}
476484

477-
static constexpr size_t Alignment = 32;
478-
size_t count = (size_t)std::ceil((float)data_size / Alignment);
479-
size_t padding_size = count * Alignment - data_size;
480-
481-
for (size_t i = 0; i < padding_size; i++)
482-
{
483-
pattern_data.pattern.push_back(0x00);
484-
pattern_data.mask.push_back(0x00);
485-
}
486-
487485
pattern_data.signature_container = &signature_container;
488486
return pattern_data;
489487
}
@@ -519,11 +517,11 @@ namespace RC
519517
}
520518
if (!end_address)
521519
{
522-
start_address = static_cast<uint8_t*>(info.lpMaximumApplicationAddress);
520+
end_address = static_cast<uint8_t*>(info.lpMaximumApplicationAddress);
523521
}
524522

525523
MEMORY_BASIC_INFORMATION memory_info{};
526-
DWORD protect_flags = PAGE_GUARD | PAGE_NOCACHE | PAGE_NOACCESS;
524+
DWORD protect_flags = PAGE_GUARD | PAGE_NOACCESS;
527525

528526
// TODO: Nasty nasty nasty. Come up with a better solution... wtf
529527
// It should ideally be able to work with the char* directly instead of converting to to vectors of ints
@@ -557,7 +555,7 @@ namespace RC
557555
}
558556

559557
// Loop everything
560-
for (uint8_t* i = start_address; i < end_address; ++i)
558+
for (uint8_t* i = start_address; i < end_address;)
561559
{
562560
// Populate memory_info if VirtualQuery doesn't fail
563561
if (VirtualQuery(i, &memory_info, sizeof(memory_info)))
@@ -591,7 +589,13 @@ namespace RC
591589
}
592590

593591
// Skip if we're about to dereference uninitialized memory
594-
if (region_start + sig.size() > region_end)
592+
if (region_start >= end_address)
593+
{
594+
break;
595+
}
596+
597+
// Skip if signature would extend past boundaries
598+
if (region_start + (sig.size() / 2) > region_end || region_start + (sig.size() / 2) > end_address)
595599
{
596600
break;
597601
}
@@ -652,6 +656,10 @@ namespace RC
652656

653657
i = static_cast<uint8_t*>(memory_info.BaseAddress) + memory_info.RegionSize;
654658
}
659+
else
660+
{
661+
++i;
662+
}
655663
}
656664
}
657665

@@ -700,91 +708,119 @@ namespace RC
700708
}
701709
if (!end_address)
702710
{
703-
start_address = static_cast<uint8_t*>(info.lpMaximumApplicationAddress);
711+
end_address = static_cast<uint8_t*>(info.lpMaximumApplicationAddress);
704712
}
705713

706-
format_aob_strings(signature_containers);
707-
708714
std::vector<std::vector<PatternData>> pattern_datas{};
709715
for (auto& signature_container : signature_containers)
710716
{
711717
auto& pattern_data = pattern_datas.emplace_back();
712718
for (auto& signature : signature_container.signatures)
713719
{
714-
pattern_data.emplace_back(make_mask(signature.signature, signature_container, end_address - start_address));
720+
pattern_data.emplace_back(make_mask(signature.signature, signature_container));
715721
}
716722
}
717723

718-
// Loop everything
719-
for (size_t container_index = 0; const auto& patterns : pattern_datas)
724+
MEMORY_BASIC_INFORMATION memory_info{};
725+
DWORD readable_flags = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY |
726+
PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
727+
728+
for (uint8_t* i = start_address; i < end_address;)
720729
{
721-
for (size_t signature_index = 0; const auto& pattern_data : patterns)
730+
if (!VirtualQuery(i, &memory_info, sizeof(memory_info)))
722731
{
723-
// If the container is refusing more calls then skip to the next container
724-
if (pattern_data.signature_container->ignore)
725-
{
726-
break;
727-
}
732+
++i;
733+
continue;
734+
}
728735

729-
auto it = start_address;
730-
auto end = it + (end_address - start_address) - (pattern_data.pattern.size()) + 1;
731-
uint8_t needle = pattern_data.pattern[0];
736+
if (!(memory_info.Protect & readable_flags) || !(memory_info.State & MEM_COMMIT) || (memory_info.Protect & PAGE_GUARD))
737+
{
738+
i += memory_info.RegionSize;
739+
continue;
740+
}
732741

733-
bool skip_to_next_container{};
734-
while (end != (it = std::find(it, end, needle)))
742+
uint8_t* region_start = static_cast<uint8_t*>(memory_info.BaseAddress);
743+
uint8_t* region_end = region_start + memory_info.RegionSize;
744+
745+
auto scan_start = (region_start > start_address) ? region_start : start_address;
746+
auto scan_end = (region_end < end_address) ? region_end : end_address;
747+
748+
// Loop everything
749+
for (size_t container_index = 0; const auto& patterns : pattern_datas)
750+
{
751+
for (size_t signature_index = 0; const auto& pattern_data : patterns)
735752
{
736-
bool found = true;
737-
for (size_t pattern_offset = 0; pattern_offset < pattern_data.pattern.size(); ++pattern_offset)
753+
// If the container is refusing more calls then skip to the next container
754+
if (pattern_data.signature_container->ignore)
738755
{
739-
if ((it[pattern_offset] & pattern_data.mask[pattern_offset]) != pattern_data.pattern[pattern_offset])
740-
{
741-
found = false;
742-
break;
743-
}
756+
break;
744757
}
745758

746-
if (found)
759+
auto it = scan_start;
760+
if (static_cast<size_t>(scan_end - scan_start) < pattern_data.pattern.size())
747761
{
748-
{
749-
std::lock_guard<std::mutex> safe_scope(m_scanner_mutex);
762+
continue; // Skip if pattern is larger than region
763+
}
764+
auto end = scan_end - pattern_data.pattern.size() + 1;
765+
uint8_t needle = pattern_data.pattern[0];
750766

751-
// Checking for the second time if the container is refusing more calls
752-
// This is required when multi-threading is enabled
753-
if (pattern_data.signature_container->ignore)
767+
bool skip_to_next_container{};
768+
while (end != (it = std::find(it, end, needle)))
769+
{
770+
bool found = true;
771+
for (size_t pattern_offset = 0; pattern_offset < pattern_data.pattern.size(); ++pattern_offset)
772+
{
773+
if ((it[pattern_offset] & pattern_data.mask[pattern_offset]) != pattern_data.pattern[pattern_offset])
754774
{
755-
skip_to_next_container = true;
775+
found = false;
756776
break;
757777
}
778+
}
758779

759-
// One of the signatures have found a full match so lets forward the details to the callable
760-
pattern_data.signature_container->index_into_signatures = signature_index;
761-
pattern_data.signature_container->match_address = it;
762-
pattern_data.signature_container->match_signature_size = pattern_data.pattern.size();
780+
if (found)
781+
{
782+
{
783+
std::lock_guard<std::mutex> safe_scope(m_scanner_mutex);
763784

764-
skip_to_next_container = pattern_data.signature_container->on_match_found(*pattern_data.signature_container);
765-
pattern_data.signature_container->ignore = skip_to_next_container;
785+
// Checking for the second time if the container is refusing more calls
786+
// This is required when multi-threading is enabled
787+
if (pattern_data.signature_container->ignore)
788+
{
789+
skip_to_next_container = true;
790+
break;
791+
}
766792

767-
// Store results if the container at the containers request
768-
if (pattern_data.signature_container->store_results)
769-
{
770-
pattern_data.signature_container->result_store.emplace_back(
771-
SignatureContainerLight{.index_into_signatures = signature_index, .match_address = it});
793+
// One of the signatures have found a full match so lets forward the details to the callable
794+
pattern_data.signature_container->index_into_signatures = signature_index;
795+
pattern_data.signature_container->match_address = it;
796+
pattern_data.signature_container->match_signature_size = pattern_data.pattern.size();
797+
798+
skip_to_next_container = pattern_data.signature_container->on_match_found(*pattern_data.signature_container);
799+
pattern_data.signature_container->ignore = skip_to_next_container;
800+
801+
// Store results if the container at the containers request
802+
if (pattern_data.signature_container->store_results)
803+
{
804+
pattern_data.signature_container->result_store.emplace_back(
805+
SignatureContainerLight{.index_into_signatures = signature_index, .match_address = it});
806+
}
772807
}
773808
}
809+
810+
it++;
774811
}
775812

776-
it++;
777-
}
813+
if (skip_to_next_container)
814+
{
815+
// A match was found and signaled to skip to the next container
816+
break;
817+
}
778818

779-
if (skip_to_next_container)
780-
{
781-
// A match was found and signaled to skip to the next container
782-
break;
819+
++signature_index;
783820
}
784-
785-
++signature_index;
821+
++container_index;
786822
}
787-
++container_index;
823+
i = region_end;
788824
}
789825
}
790826

@@ -818,6 +854,11 @@ namespace RC
818854
return;
819855
}
820856

857+
if (m_scan_method == ScanMethod::StdFind)
858+
{
859+
format_aob_strings(merged_containers);
860+
}
861+
821862
uint8_t* module_start_address = static_cast<uint8_t*>(merged_module_info.lpBaseOfDll);
822863

823864
if (merged_module_info.SizeOfImage >= m_multithreading_module_size_threshold)
@@ -867,6 +908,11 @@ namespace RC
867908
// Right now it can't be auto& or const auto& because the do_scan function takes a non-const since it needs to mutate the values inside the vector
868909
for (auto& [scan_target, signature_container] : signature_containers)
869910
{
911+
if (m_scan_method == ScanMethod::StdFind)
912+
{
913+
format_aob_strings(signature_container);
914+
}
915+
870916
uint8_t* module_start_address = static_cast<uint8_t*>(SigScannerStaticData::m_modules_info[scan_target].lpBaseOfDll);
871917
uint8_t* module_end_address = static_cast<uint8_t*>(module_start_address + SigScannerStaticData::m_modules_info[scan_target].SizeOfImage);
872918

0 commit comments

Comments
 (0)