Scan executable for GPS route strings
This commit is contained in:
@@ -8,7 +8,10 @@
|
|||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cstring>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -87,6 +90,7 @@ std::mutex gLogMutex;
|
|||||||
RED4ext::v1::PluginHandle gHandle = nullptr;
|
RED4ext::v1::PluginHandle gHandle = nullptr;
|
||||||
const RED4ext::v1::Sdk* gSdk = nullptr;
|
const RED4ext::v1::Sdk* gSdk = nullptr;
|
||||||
uint32_t gUpdateLogCount = 0;
|
uint32_t gUpdateLogCount = 0;
|
||||||
|
bool gScannedExecutable = false;
|
||||||
|
|
||||||
std::filesystem::path GetLogPath()
|
std::filesystem::path GetLogPath()
|
||||||
{
|
{
|
||||||
@@ -142,11 +146,156 @@ const char* ReasonToString(RED4ext::v1::EMainReason aReason)
|
|||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsReadablePage(DWORD aProtect)
|
||||||
|
{
|
||||||
|
if ((aProtect & PAGE_GUARD) != 0 || (aProtect & PAGE_NOACCESS) != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto baseProtect = aProtect & 0xFF;
|
||||||
|
return baseProtect == PAGE_READONLY || baseProtect == PAGE_READWRITE || baseProtect == PAGE_WRITECOPY ||
|
||||||
|
baseProtect == PAGE_EXECUTE_READ || baseProtect == PAGE_EXECUTE_READWRITE ||
|
||||||
|
baseProtect == PAGE_EXECUTE_WRITECOPY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScanRegionForString(const uint8_t* aRegionBegin, size_t aRegionSize, uintptr_t aImageBase, const char* aNeedle,
|
||||||
|
uint32_t& aMatches)
|
||||||
|
{
|
||||||
|
constexpr uint32_t kMaxMatchesPerNeedle = 8;
|
||||||
|
|
||||||
|
const auto needleSize = std::strlen(aNeedle);
|
||||||
|
if (needleSize == 0 || aRegionSize < needleSize || aMatches >= kMaxMatchesPerNeedle)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* cursor = aRegionBegin;
|
||||||
|
const auto* regionEnd = aRegionBegin + aRegionSize;
|
||||||
|
|
||||||
|
while (cursor + needleSize <= regionEnd && aMatches < kMaxMatchesPerNeedle)
|
||||||
|
{
|
||||||
|
if (std::memcmp(cursor, aNeedle, needleSize) == 0)
|
||||||
|
{
|
||||||
|
const auto rva = reinterpret_cast<uintptr_t>(cursor) - aImageBase;
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "exe-string match needle=\"" << aNeedle << "\" rva=0x" << std::hex << rva << std::dec;
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
++aMatches;
|
||||||
|
cursor += needleSize;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
++cursor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScanExecutableStrings()
|
||||||
|
{
|
||||||
|
if (gScannedExecutable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gScannedExecutable = true;
|
||||||
|
|
||||||
|
const auto imageBase = reinterpret_cast<uintptr_t>(GetModuleHandleW(nullptr));
|
||||||
|
if (!imageBase)
|
||||||
|
{
|
||||||
|
LogRed4ext("exe-string scan skipped: main module unavailable");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* dos = reinterpret_cast<const IMAGE_DOS_HEADER*>(imageBase);
|
||||||
|
if (dos->e_magic != IMAGE_DOS_SIGNATURE)
|
||||||
|
{
|
||||||
|
LogRed4ext("exe-string scan skipped: bad DOS header");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* nt = reinterpret_cast<const IMAGE_NT_HEADERS*>(imageBase + dos->e_lfanew);
|
||||||
|
if (nt->Signature != IMAGE_NT_SIGNATURE)
|
||||||
|
{
|
||||||
|
LogRed4ext("exe-string scan skipped: bad NT header");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto imageSize = static_cast<size_t>(nt->OptionalHeader.SizeOfImage);
|
||||||
|
std::ostringstream header;
|
||||||
|
header << "exe-string scan begin base=0x" << std::hex << imageBase << " size=0x" << imageSize << std::dec;
|
||||||
|
LogRed4ext(header.str());
|
||||||
|
|
||||||
|
constexpr std::array<const char*, 18> kNeedles{
|
||||||
|
"GPSSystem/Tick",
|
||||||
|
"GPSSystem",
|
||||||
|
"GPSSettings",
|
||||||
|
"OnSetHasGPSPortal",
|
||||||
|
"IsGPSPortal",
|
||||||
|
"m_cookedGpsData",
|
||||||
|
"gameCookedGpsMappinData",
|
||||||
|
"GetNavigationFunctionalTests",
|
||||||
|
"TrafficSystem_Pathfinding",
|
||||||
|
"TrafficSystem_PathMap",
|
||||||
|
"Pathfinding Algorithm Failed",
|
||||||
|
"No Path Found in Traffic",
|
||||||
|
"PathFindingFailed",
|
||||||
|
"StartPathfinding",
|
||||||
|
"StopPathfinding",
|
||||||
|
"worldTrafficLanePlayerGPSInfo",
|
||||||
|
"worldTrafficPersistentResource",
|
||||||
|
"worldTrafficConnectivityOutLane",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto* needle : kNeedles)
|
||||||
|
{
|
||||||
|
uint32_t matches = 0;
|
||||||
|
uintptr_t cursor = imageBase;
|
||||||
|
const uintptr_t end = imageBase + imageSize;
|
||||||
|
|
||||||
|
while (cursor < end)
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION mbi{};
|
||||||
|
if (!VirtualQuery(reinterpret_cast<const void*>(cursor), &mbi, sizeof(mbi)))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto regionBegin = reinterpret_cast<uintptr_t>(mbi.BaseAddress);
|
||||||
|
const auto regionEnd = regionBegin + mbi.RegionSize;
|
||||||
|
if (mbi.State == MEM_COMMIT && mbi.Type == MEM_IMAGE && IsReadablePage(mbi.Protect))
|
||||||
|
{
|
||||||
|
const auto scanBegin = std::max(regionBegin, imageBase);
|
||||||
|
const auto scanEnd = std::min(regionEnd, end);
|
||||||
|
if (scanBegin < scanEnd)
|
||||||
|
{
|
||||||
|
ScanRegionForString(reinterpret_cast<const uint8_t*>(scanBegin), scanEnd - scanBegin, imageBase,
|
||||||
|
needle, matches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regionEnd <= cursor)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cursor = regionEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches == 0)
|
||||||
|
{
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "exe-string no match needle=\"" << needle << "\"";
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogRed4ext("exe-string scan end");
|
||||||
|
}
|
||||||
|
|
||||||
bool OnRunningEnter(void* aApp)
|
bool OnRunningEnter(void* aApp)
|
||||||
{
|
{
|
||||||
std::ostringstream line;
|
std::ostringstream line;
|
||||||
line << "GameState Running OnEnter app=" << aApp;
|
line << "GameState Running OnEnter app=" << aApp;
|
||||||
LogRed4ext(line.str());
|
LogRed4ext(line.str());
|
||||||
|
ScanExecutableStrings();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user