Resolve mappin system vtable during tracking probe
This commit is contained in:
@@ -91,9 +91,12 @@ namespace
|
|||||||
{
|
{
|
||||||
constexpr uint32_t kGameStateRunning = 2;
|
constexpr uint32_t kGameStateRunning = 2;
|
||||||
constexpr uintptr_t kGpsSystemTickRva = 0x0E6B62C;
|
constexpr uintptr_t kGpsSystemTickRva = 0x0E6B62C;
|
||||||
|
constexpr uintptr_t kMappinSystemResolverRva = 0x02BB840;
|
||||||
constexpr uintptr_t kTrackMappinWrapperRva = 0x27C4AB4;
|
constexpr uintptr_t kTrackMappinWrapperRva = 0x27C4AB4;
|
||||||
constexpr uintptr_t kTrackMappinCoreRva = 0x27C11D0;
|
constexpr uintptr_t kTrackMappinCoreRva = 0x27C11D0;
|
||||||
constexpr uintptr_t kSetMappinTrackingAlternativeWrapperRva = 0x1246794;
|
constexpr uintptr_t kSetMappinTrackingAlternativeWrapperRva = 0x1246794;
|
||||||
|
constexpr uintptr_t kMappinSetTrackedSlotOffset = 0x220;
|
||||||
|
constexpr uintptr_t kMappinClearTrackedSlotOffset = 0x228;
|
||||||
|
|
||||||
HMODULE gModule = nullptr;
|
HMODULE gModule = nullptr;
|
||||||
std::mutex gLogMutex;
|
std::mutex gLogMutex;
|
||||||
@@ -105,16 +108,27 @@ uint32_t gGpsTickLogCount = 0;
|
|||||||
uint32_t gTrackMappinWrapperLogCount = 0;
|
uint32_t gTrackMappinWrapperLogCount = 0;
|
||||||
uint32_t gTrackMappinCoreLogCount = 0;
|
uint32_t gTrackMappinCoreLogCount = 0;
|
||||||
uint32_t gSetMappinTrackingAlternativeLogCount = 0;
|
uint32_t gSetMappinTrackingAlternativeLogCount = 0;
|
||||||
|
uint32_t gMappinSystemSlotLogCount = 0;
|
||||||
|
uint32_t gMappinSetTrackedLogCount = 0;
|
||||||
|
uint32_t gMappinClearTrackedLogCount = 0;
|
||||||
uint64_t gLogStartTick = 0;
|
uint64_t gLogStartTick = 0;
|
||||||
uint64_t gLogFrequency = 0;
|
uint64_t gLogFrequency = 0;
|
||||||
|
void* gMappinSetTrackedTarget = nullptr;
|
||||||
|
void* gMappinClearTrackedTarget = nullptr;
|
||||||
|
bool gMappinSlotHookAttachAttempted = false;
|
||||||
|
|
||||||
using ProbeFunc = void (*)(void* aThis, void* a2, void* a3, void* a4);
|
using ProbeFunc = void (*)(void* aThis, void* a2, void* a3, void* a4);
|
||||||
using ScriptNativeVoidFunc = void (*)(void* aThis, void* aStack, void* aResult);
|
using ScriptNativeVoidFunc = void (*)(void* aThis, void* aStack, void* aResult);
|
||||||
|
using MappinSystemResolverFunc = void* (*)(void* aThis);
|
||||||
using TrackMappinCoreFunc = void (*)(void* aThis, void* aMappinHandle);
|
using TrackMappinCoreFunc = void (*)(void* aThis, void* aMappinHandle);
|
||||||
|
using MappinSetTrackedFunc = void (*)(void* aSystem, void* aMappinId);
|
||||||
|
using MappinClearTrackedFunc = void (*)(void* aSystem);
|
||||||
ProbeFunc gOriginalGpsSystemTick = nullptr;
|
ProbeFunc gOriginalGpsSystemTick = nullptr;
|
||||||
ScriptNativeVoidFunc gOriginalTrackMappinWrapper = nullptr;
|
ScriptNativeVoidFunc gOriginalTrackMappinWrapper = nullptr;
|
||||||
TrackMappinCoreFunc gOriginalTrackMappinCore = nullptr;
|
TrackMappinCoreFunc gOriginalTrackMappinCore = nullptr;
|
||||||
ScriptNativeVoidFunc gOriginalSetMappinTrackingAlternativeWrapper = nullptr;
|
ScriptNativeVoidFunc gOriginalSetMappinTrackingAlternativeWrapper = nullptr;
|
||||||
|
MappinSetTrackedFunc gOriginalMappinSetTracked = nullptr;
|
||||||
|
MappinClearTrackedFunc gOriginalMappinClearTracked = nullptr;
|
||||||
|
|
||||||
std::filesystem::path GetLogPath()
|
std::filesystem::path GetLogPath()
|
||||||
{
|
{
|
||||||
@@ -195,6 +209,28 @@ void LogTrackMappinCoreCall(uint32_t aCount, void* aThis, void* aMappinHandle)
|
|||||||
LogRed4ext(line.str());
|
LogRed4ext(line.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LogMappinSystemSlots(uint32_t aCount, void* aSystem, void* aVtable)
|
||||||
|
{
|
||||||
|
auto* vtable = reinterpret_cast<uint8_t*>(aVtable);
|
||||||
|
auto readSlot = [vtable](uintptr_t aOffset) -> void* {
|
||||||
|
if (!vtable)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *reinterpret_cast<void**>(vtable + aOffset);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "mappin-system slots call=" << aCount << " system=" << aSystem << " vtable=" << aVtable
|
||||||
|
<< " slot220=" << readSlot(0x220) << " slot228=" << readSlot(0x228)
|
||||||
|
<< " slot250=" << readSlot(0x250) << " slot2e0=" << readSlot(0x2E0)
|
||||||
|
<< " slot368=" << readSlot(0x368) << " slot3a8=" << readSlot(0x3A8);
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void InspectAndHookMappinSystem(void* aThis);
|
||||||
|
|
||||||
const char* ReasonToString(RED4ext::v1::EMainReason aReason)
|
const char* ReasonToString(RED4ext::v1::EMainReason aReason)
|
||||||
{
|
{
|
||||||
switch (aReason)
|
switch (aReason)
|
||||||
@@ -389,6 +425,8 @@ void DetourTrackMappinCore(void* aThis, void* aMappinHandle)
|
|||||||
++gTrackMappinCoreLogCount;
|
++gTrackMappinCoreLogCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InspectAndHookMappinSystem(aThis);
|
||||||
|
|
||||||
if (gOriginalTrackMappinCore)
|
if (gOriginalTrackMappinCore)
|
||||||
{
|
{
|
||||||
gOriginalTrackMappinCore(aThis, aMappinHandle);
|
gOriginalTrackMappinCore(aThis, aMappinHandle);
|
||||||
@@ -410,6 +448,40 @@ void DetourSetMappinTrackingAlternativeWrapper(void* aThis, void* aStack, void*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DetourMappinSetTracked(void* aSystem, void* aMappinId)
|
||||||
|
{
|
||||||
|
if (gMappinSetTrackedLogCount < 64)
|
||||||
|
{
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "hook MappinSystem::SetTracked slot220 call=" << gMappinSetTrackedLogCount
|
||||||
|
<< " system=" << aSystem << " mappinId=" << aMappinId;
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
++gMappinSetTrackedLogCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gOriginalMappinSetTracked)
|
||||||
|
{
|
||||||
|
gOriginalMappinSetTracked(aSystem, aMappinId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourMappinClearTracked(void* aSystem)
|
||||||
|
{
|
||||||
|
if (gMappinClearTrackedLogCount < 64)
|
||||||
|
{
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "hook MappinSystem::ClearTracked slot228 call=" << gMappinClearTrackedLogCount
|
||||||
|
<< " system=" << aSystem;
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
++gMappinClearTrackedLogCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gOriginalMappinClearTracked)
|
||||||
|
{
|
||||||
|
gOriginalMappinClearTracked(aSystem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AttachProbeHook(const char* aName, uintptr_t aRva, void* aDetour, void** aOriginal)
|
void AttachProbeHook(const char* aName, uintptr_t aRva, void* aDetour, void** aOriginal)
|
||||||
{
|
{
|
||||||
if (!gSdk || !gSdk->hooking || !gSdk->hooking->Attach)
|
if (!gSdk || !gSdk->hooking || !gSdk->hooking->Attach)
|
||||||
@@ -427,6 +499,30 @@ void AttachProbeHook(const char* aName, uintptr_t aRva, void* aDetour, void** aO
|
|||||||
LogRed4ext(line.str());
|
LogRed4ext(line.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AttachAbsoluteHook(const char* aName, void* aTarget, void* aDetour, void** aOriginal)
|
||||||
|
{
|
||||||
|
if (!gSdk || !gSdk->hooking || !gSdk->hooking->Attach)
|
||||||
|
{
|
||||||
|
LogRed4ext("absolute hook attach skipped: RED4ext hooking API unavailable");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aTarget)
|
||||||
|
{
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "absolute hook attach skipped " << aName << ": target=null";
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto attached = gSdk->hooking->Attach(gHandle, aTarget, aDetour, aOriginal);
|
||||||
|
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "absolute hook attach " << aName << " target=" << aTarget
|
||||||
|
<< " result=" << (attached ? "ok" : "failed") << " original=" << (aOriginal ? *aOriginal : nullptr);
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
}
|
||||||
|
|
||||||
void DetachProbeHook(const char* aName, uintptr_t aRva)
|
void DetachProbeHook(const char* aName, uintptr_t aRva)
|
||||||
{
|
{
|
||||||
if (!gSdk || !gSdk->hooking || !gSdk->hooking->Detach)
|
if (!gSdk || !gSdk->hooking || !gSdk->hooking->Detach)
|
||||||
@@ -442,6 +538,53 @@ void DetachProbeHook(const char* aName, uintptr_t aRva)
|
|||||||
LogRed4ext(line.str());
|
LogRed4ext(line.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DetachAbsoluteHook(const char* aName, void* aTarget)
|
||||||
|
{
|
||||||
|
if (!gSdk || !gSdk->hooking || !gSdk->hooking->Detach || !aTarget)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto detached = gSdk->hooking->Detach(gHandle, aTarget);
|
||||||
|
|
||||||
|
std::ostringstream line;
|
||||||
|
line << "absolute hook detach " << aName << " target=" << aTarget
|
||||||
|
<< " result=" << (detached ? "ok" : "failed");
|
||||||
|
LogRed4ext(line.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void InspectAndHookMappinSystem(void* aThis)
|
||||||
|
{
|
||||||
|
auto* resolver = reinterpret_cast<MappinSystemResolverFunc>(
|
||||||
|
reinterpret_cast<uintptr_t>(GetModuleHandleW(nullptr)) + kMappinSystemResolverRva);
|
||||||
|
void* system = resolver ? resolver(aThis) : nullptr;
|
||||||
|
auto* vtable = system ? *reinterpret_cast<void***>(system) : nullptr;
|
||||||
|
|
||||||
|
if (gMappinSystemSlotLogCount < 16)
|
||||||
|
{
|
||||||
|
LogMappinSystemSlots(gMappinSystemSlotLogCount, system, vtable);
|
||||||
|
++gMappinSystemSlotLogCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gMappinSlotHookAttachAttempted || !vtable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gMappinSlotHookAttachAttempted = true;
|
||||||
|
gMappinSetTrackedTarget =
|
||||||
|
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(vtable) + kMappinSetTrackedSlotOffset);
|
||||||
|
gMappinClearTrackedTarget =
|
||||||
|
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(vtable) + kMappinClearTrackedSlotOffset);
|
||||||
|
|
||||||
|
AttachAbsoluteHook("MappinSystem::SetTracked slot220", gMappinSetTrackedTarget,
|
||||||
|
reinterpret_cast<void*>(&DetourMappinSetTracked),
|
||||||
|
reinterpret_cast<void**>(&gOriginalMappinSetTracked));
|
||||||
|
AttachAbsoluteHook("MappinSystem::ClearTracked slot228", gMappinClearTrackedTarget,
|
||||||
|
reinterpret_cast<void*>(&DetourMappinClearTracked),
|
||||||
|
reinterpret_cast<void**>(&gOriginalMappinClearTracked));
|
||||||
|
}
|
||||||
|
|
||||||
bool OnRunningEnter(void* aApp)
|
bool OnRunningEnter(void* aApp)
|
||||||
{
|
{
|
||||||
std::ostringstream line;
|
std::ostringstream line;
|
||||||
@@ -531,6 +674,8 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
|||||||
DetachProbeHook("TrackMappinWrapper", kTrackMappinWrapperRva);
|
DetachProbeHook("TrackMappinWrapper", kTrackMappinWrapperRva);
|
||||||
DetachProbeHook("TrackMappinCore", kTrackMappinCoreRva);
|
DetachProbeHook("TrackMappinCore", kTrackMappinCoreRva);
|
||||||
DetachProbeHook("SetMappinTrackingAlternativeWrapper", kSetMappinTrackingAlternativeWrapperRva);
|
DetachProbeHook("SetMappinTrackingAlternativeWrapper", kSetMappinTrackingAlternativeWrapperRva);
|
||||||
|
DetachAbsoluteHook("MappinSystem::SetTracked slot220", gMappinSetTrackedTarget);
|
||||||
|
DetachAbsoluteHook("MappinSystem::ClearTracked slot228", gMappinClearTrackedTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user