Kelsidavis-WoWee/include/game/warden_memory.hpp
Kelsi a3279ea1ad fix: async Warden PAGE_A/PAGE_B checks to prevent main-loop stalls
Move 5-second brute-force HMAC-SHA1 code pattern searches to a
background thread via std::async. The main loop now detects PAGE_A/B
checks, launches the response builder async, and drains the result
in update() — encrypting and sending on the main thread to keep
wardenCrypto_ RC4 state thread-safe.

Also adds Turtle WoW PE binary support (isTurtle flag, dedicated exe
search, runtime patches), searchCodePattern with result caching,
writeLE32 public API, and Warden scan entry verification.
2026-03-16 16:46:29 -07:00

78 lines
2.7 KiB
C++

#pragma once
#include <vector>
#include <cstdint>
#include <string>
#include <unordered_map>
namespace wowee {
namespace game {
/**
* Provides WoW.exe PE memory image for Warden MEM_CHECK responses.
* Parses PE headers to build a flat virtual memory image, then serves
* readMemory() calls with real bytes. Also mocks KUSER_SHARED_DATA.
*/
class WardenMemory {
public:
WardenMemory();
~WardenMemory();
/** Search standard candidate dirs for WoW.exe and load it.
* @param build Client build number (e.g. 5875 for Classic 1.12.1) to select the right exe.
* @param isTurtle If true, prefer the Turtle WoW custom exe (different code bytes). */
bool load(uint16_t build = 0, bool isTurtle = false);
/** Load PE image from a specific file path. */
bool loadFromFile(const std::string& exePath);
/**
* Read bytes from virtual address space.
* Handles PE sections + KUSER_SHARED_DATA mock.
*/
bool readMemory(uint32_t va, uint8_t length, uint8_t* outBuf) const;
bool isLoaded() const { return loaded_; }
/**
* Search PE image for a byte pattern matching HMAC-SHA1(seed, pattern).
* Used for FIND_MEM_IMAGE_CODE_BY_HASH and FIND_CODE_BY_HASH scans.
* @param seed 4-byte HMAC key
* @param expectedHash 20-byte expected HMAC-SHA1 digest
* @param patternLen Length of the pattern to search for
* @param imageOnly If true, search only executable sections (.text)
* @return true if a matching pattern was found in the PE image
*/
bool searchCodePattern(const uint8_t seed[4], const uint8_t expectedHash[20],
uint8_t patternLen, bool imageOnly) const;
/** Write a little-endian uint32 at the given virtual address in the PE image. */
void writeLE32(uint32_t va, uint32_t value);
private:
bool loaded_ = false;
uint32_t imageBase_ = 0;
uint32_t imageSize_ = 0;
std::vector<uint8_t> image_;
// KUSER_SHARED_DATA mock (0x7FFE0000 - 0x7FFE0FFF)
static constexpr uint32_t KUSER_BASE = 0x7FFE0000;
static constexpr uint32_t KUSER_SIZE = 0x1000;
uint8_t kuserData_[KUSER_SIZE] = {};
bool parsePE(const std::vector<uint8_t>& fileData);
void initKuserSharedData();
void patchRuntimeGlobals();
void patchTurtleWowBinary();
void verifyWardenScanEntries();
bool isTurtle_ = false;
std::string findWowExe(uint16_t build) const;
static uint32_t expectedImageSizeForBuild(uint16_t build, bool isTurtle);
// Cache for searchCodePattern results to avoid repeated 5-second brute-force searches.
// Key: hex string of seed(4)+hash(20)+patLen(1)+imageOnly(1) = 26 bytes.
mutable std::unordered_map<std::string, bool> codePatternCache_;
};
} // namespace game
} // namespace wowee