Probe journal listener route callbacks
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <initializer_list>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
@@ -115,6 +116,15 @@ constexpr uintptr_t kMappinPositionQuerySlotOffset = 0x2E0;
|
||||
constexpr uintptr_t kMappinCreateCustomPositionSlotOffset = 0x2F0;
|
||||
constexpr uintptr_t kMappinReleaseQuerySlotOffset = 0x368;
|
||||
constexpr uintptr_t kMappinActiveRouteSlotOffset = 0x3A8;
|
||||
constexpr uintptr_t kJournalListenerObjectiveVt28Rva = 0x0EA89A8;
|
||||
constexpr uintptr_t kJournalListenerObjectiveVt30Rva = 0x0EA8958;
|
||||
constexpr uintptr_t kJournalListenerRouteVt28Rva = 0x0E63F80;
|
||||
constexpr uintptr_t kJournalListenerRouteVt30Rva = 0x0E63E6C;
|
||||
constexpr uintptr_t kJournalListenerRouteAltVt28Rva = 0x0E63F00;
|
||||
constexpr uintptr_t kJournalListenerRouteAltVt30Rva = 0x08D136C;
|
||||
constexpr uintptr_t kJournalListenerUiVt28Rva = 0x0431A34;
|
||||
constexpr uintptr_t kJournalListenerUiVt30Rva = 0x055A4E4;
|
||||
constexpr uintptr_t kJournalListenerTrackerVt28Rva = 0x14DE238;
|
||||
|
||||
HMODULE gModule = nullptr;
|
||||
std::mutex gLogMutex;
|
||||
@@ -146,6 +156,15 @@ uint32_t gMappinPositionQueryLogCount = 0;
|
||||
uint32_t gMappinCreateCustomPositionLogCount = 0;
|
||||
uint32_t gMappinReleaseQueryLogCount = 0;
|
||||
uint32_t gMappinActiveRouteLogCount = 0;
|
||||
uint32_t gJournalListenerObjectiveVt28LogCount = 0;
|
||||
uint32_t gJournalListenerObjectiveVt30LogCount = 0;
|
||||
uint32_t gJournalListenerRouteVt28LogCount = 0;
|
||||
uint32_t gJournalListenerRouteVt30LogCount = 0;
|
||||
uint32_t gJournalListenerRouteAltVt28LogCount = 0;
|
||||
uint32_t gJournalListenerRouteAltVt30LogCount = 0;
|
||||
uint32_t gJournalListenerUiVt28LogCount = 0;
|
||||
uint32_t gJournalListenerUiVt30LogCount = 0;
|
||||
uint32_t gJournalListenerTrackerVt28LogCount = 0;
|
||||
uint64_t gLogStartTick = 0;
|
||||
uint64_t gLogFrequency = 0;
|
||||
void* gMappinSetTrackedTarget = nullptr;
|
||||
@@ -174,6 +193,7 @@ using MappinPositionQueryFunc = void* (*)(void* aSystem, void* a2, void* a3, voi
|
||||
using MappinCreateCustomPositionFunc = void* (*)(void* aSystem, void* aName, void* aParams, void* aPositionData);
|
||||
using MappinReleaseQueryFunc = void (*)(void* aSystem, void* aHandle);
|
||||
using MappinActiveRouteFunc = void* (*)(void* aSystem);
|
||||
using JournalListenerCallbackFunc = void (*)(void* aListener, void* aEvent);
|
||||
ProbeFunc gOriginalGpsSystemTick = nullptr;
|
||||
JournalTrackEntryFunc gOriginalJournalTrackEntry = nullptr;
|
||||
ScriptNativeVoidFunc gOriginalFrameMappinPathWrapper = nullptr;
|
||||
@@ -196,6 +216,15 @@ MappinPositionQueryFunc gOriginalMappinPositionQuery = nullptr;
|
||||
MappinCreateCustomPositionFunc gOriginalMappinCreateCustomPosition = nullptr;
|
||||
MappinReleaseQueryFunc gOriginalMappinReleaseQuery = nullptr;
|
||||
MappinActiveRouteFunc gOriginalMappinActiveRoute = nullptr;
|
||||
JournalListenerCallbackFunc gOriginalJournalListenerObjectiveVt28 = nullptr;
|
||||
JournalListenerCallbackFunc gOriginalJournalListenerObjectiveVt30 = nullptr;
|
||||
JournalListenerCallbackFunc gOriginalJournalListenerRouteVt28 = nullptr;
|
||||
JournalListenerCallbackFunc gOriginalJournalListenerRouteVt30 = nullptr;
|
||||
JournalListenerCallbackFunc gOriginalJournalListenerRouteAltVt28 = nullptr;
|
||||
JournalListenerCallbackFunc gOriginalJournalListenerRouteAltVt30 = nullptr;
|
||||
JournalListenerCallbackFunc gOriginalJournalListenerUiVt28 = nullptr;
|
||||
JournalListenerCallbackFunc gOriginalJournalListenerUiVt30 = nullptr;
|
||||
JournalListenerCallbackFunc gOriginalJournalListenerTrackerVt28 = nullptr;
|
||||
|
||||
std::filesystem::path GetLogPath()
|
||||
{
|
||||
@@ -463,6 +492,72 @@ bool TryReadMemory(const void* aPointer, T& aValue)
|
||||
return true;
|
||||
}
|
||||
|
||||
void* ReadPointerField(void* aObject, uintptr_t aOffset)
|
||||
{
|
||||
void* value = nullptr;
|
||||
if (!aObject)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aObject) + aOffset), value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void AppendObjectVtableSlots(std::ostringstream& aLine, void* aObject, std::initializer_list<uintptr_t> aSlots)
|
||||
{
|
||||
auto* vtable = ReadPointerField(aObject, 0);
|
||||
AppendPointerWithRva(aLine, "vtable", vtable);
|
||||
|
||||
for (const auto slot : aSlots)
|
||||
{
|
||||
auto* target = vtable ? ReadPointerField(vtable, slot) : nullptr;
|
||||
std::ostringstream label;
|
||||
label << "slot" << std::hex << slot;
|
||||
AppendPointerWithRva(aLine, label.str().c_str(), target);
|
||||
}
|
||||
}
|
||||
|
||||
void LogJournalListenerContext(const char* aName, uint32_t aCount, void* aListener, void* aEvent)
|
||||
{
|
||||
std::ostringstream line;
|
||||
line << "hook " << aName << " call=" << aCount;
|
||||
AppendPointerWithRva(line, "listener", aListener);
|
||||
AppendPointerWithRva(line, "event", aEvent);
|
||||
AppendReturnRva(line, __builtin_return_address(0));
|
||||
|
||||
auto* field08 = ReadPointerField(aListener, 0x08);
|
||||
auto* field18 = ReadPointerField(aListener, 0x18);
|
||||
auto* field20 = ReadPointerField(aListener, 0x20);
|
||||
auto* field70 = ReadPointerField(aListener, 0x70);
|
||||
auto* field78 = ReadPointerField(aListener, 0x78);
|
||||
AppendPointerWithRva(line, "field08", field08);
|
||||
AppendPointerWithRva(line, "field18", field18);
|
||||
AppendPointerWithRva(line, "field20", field20);
|
||||
AppendPointerWithRva(line, "field70", field70);
|
||||
AppendPointerWithRva(line, "field78", field78);
|
||||
LogRed4ext(line.str());
|
||||
|
||||
if (field70)
|
||||
{
|
||||
std::ostringstream owner;
|
||||
owner << "journal-listener-context " << aName << " call=" << aCount;
|
||||
AppendPointerWithRva(owner, "field70", field70);
|
||||
AppendObjectVtableSlots(owner, field70, {0x1C8, 0x218, 0x230, 0x238, 0x240, 0x248, 0x340, 0x348, 0x358});
|
||||
LogRed4ext(owner.str());
|
||||
}
|
||||
|
||||
if (field78 && field78 != field70)
|
||||
{
|
||||
std::ostringstream service;
|
||||
service << "journal-listener-context " << aName << " call=" << aCount;
|
||||
AppendPointerWithRva(service, "field78", field78);
|
||||
AppendObjectVtableSlots(service, field78,
|
||||
{0x1C8, 0x218, 0x220, 0x230, 0x238, 0x240, 0x248, 0x340, 0x348, 0x358});
|
||||
LogRed4ext(service.str());
|
||||
}
|
||||
}
|
||||
|
||||
void ScanRegionForString(const uint8_t* aRegionBegin, size_t aRegionSize, uintptr_t aImageBase, const char* aNeedle,
|
||||
uint32_t& aMatches)
|
||||
{
|
||||
@@ -697,6 +792,77 @@ void DetourJournalTrackEntry(void* aThis, void* aEntryHandle)
|
||||
}
|
||||
}
|
||||
|
||||
void DispatchJournalListenerCallback(const char* aName, uint32_t& aCounter, JournalListenerCallbackFunc aOriginal,
|
||||
void* aListener, void* aEvent)
|
||||
{
|
||||
constexpr uint32_t kMaxCalls = 64;
|
||||
|
||||
if (aCounter < kMaxCalls)
|
||||
{
|
||||
LogJournalListenerContext(aName, aCounter, aListener, aEvent);
|
||||
++aCounter;
|
||||
}
|
||||
|
||||
if (aOriginal)
|
||||
{
|
||||
aOriginal(aListener, aEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void DetourJournalListenerObjectiveVt28(void* aListener, void* aEvent)
|
||||
{
|
||||
DispatchJournalListenerCallback("JournalListener::Objective vt28", gJournalListenerObjectiveVt28LogCount,
|
||||
gOriginalJournalListenerObjectiveVt28, aListener, aEvent);
|
||||
}
|
||||
|
||||
void DetourJournalListenerObjectiveVt30(void* aListener, void* aEvent)
|
||||
{
|
||||
DispatchJournalListenerCallback("JournalListener::Objective vt30", gJournalListenerObjectiveVt30LogCount,
|
||||
gOriginalJournalListenerObjectiveVt30, aListener, aEvent);
|
||||
}
|
||||
|
||||
void DetourJournalListenerRouteVt28(void* aListener, void* aEvent)
|
||||
{
|
||||
DispatchJournalListenerCallback("JournalListener::Route vt28", gJournalListenerRouteVt28LogCount,
|
||||
gOriginalJournalListenerRouteVt28, aListener, aEvent);
|
||||
}
|
||||
|
||||
void DetourJournalListenerRouteVt30(void* aListener, void* aEvent)
|
||||
{
|
||||
DispatchJournalListenerCallback("JournalListener::Route vt30", gJournalListenerRouteVt30LogCount,
|
||||
gOriginalJournalListenerRouteVt30, aListener, aEvent);
|
||||
}
|
||||
|
||||
void DetourJournalListenerRouteAltVt28(void* aListener, void* aEvent)
|
||||
{
|
||||
DispatchJournalListenerCallback("JournalListener::RouteAlt vt28", gJournalListenerRouteAltVt28LogCount,
|
||||
gOriginalJournalListenerRouteAltVt28, aListener, aEvent);
|
||||
}
|
||||
|
||||
void DetourJournalListenerRouteAltVt30(void* aListener, void* aEvent)
|
||||
{
|
||||
DispatchJournalListenerCallback("JournalListener::RouteAlt vt30", gJournalListenerRouteAltVt30LogCount,
|
||||
gOriginalJournalListenerRouteAltVt30, aListener, aEvent);
|
||||
}
|
||||
|
||||
void DetourJournalListenerUiVt28(void* aListener, void* aEvent)
|
||||
{
|
||||
DispatchJournalListenerCallback("JournalListener::UI vt28", gJournalListenerUiVt28LogCount,
|
||||
gOriginalJournalListenerUiVt28, aListener, aEvent);
|
||||
}
|
||||
|
||||
void DetourJournalListenerUiVt30(void* aListener, void* aEvent)
|
||||
{
|
||||
DispatchJournalListenerCallback("JournalListener::UI vt30", gJournalListenerUiVt30LogCount,
|
||||
gOriginalJournalListenerUiVt30, aListener, aEvent);
|
||||
}
|
||||
|
||||
void DetourJournalListenerTrackerVt28(void* aListener, void* aEvent)
|
||||
{
|
||||
DispatchJournalListenerCallback("JournalListener::Tracker vt28", gJournalListenerTrackerVt28LogCount,
|
||||
gOriginalJournalListenerTrackerVt28, aListener, aEvent);
|
||||
}
|
||||
|
||||
void DetourFrameMappinPathWrapper(void* aThis, void* aStack, void* aResult)
|
||||
{
|
||||
if (gFrameMappinPathWrapperLogCount < 64)
|
||||
@@ -1294,6 +1460,33 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
||||
AttachProbeHook("JournalManager::TrackEntry impl", kJournalTrackEntryImplRva,
|
||||
reinterpret_cast<void*>(&DetourJournalTrackEntry),
|
||||
reinterpret_cast<void**>(&gOriginalJournalTrackEntry));
|
||||
AttachProbeHook("JournalListener::Objective vt28", kJournalListenerObjectiveVt28Rva,
|
||||
reinterpret_cast<void*>(&DetourJournalListenerObjectiveVt28),
|
||||
reinterpret_cast<void**>(&gOriginalJournalListenerObjectiveVt28));
|
||||
AttachProbeHook("JournalListener::Objective vt30", kJournalListenerObjectiveVt30Rva,
|
||||
reinterpret_cast<void*>(&DetourJournalListenerObjectiveVt30),
|
||||
reinterpret_cast<void**>(&gOriginalJournalListenerObjectiveVt30));
|
||||
AttachProbeHook("JournalListener::Route vt28", kJournalListenerRouteVt28Rva,
|
||||
reinterpret_cast<void*>(&DetourJournalListenerRouteVt28),
|
||||
reinterpret_cast<void**>(&gOriginalJournalListenerRouteVt28));
|
||||
AttachProbeHook("JournalListener::Route vt30", kJournalListenerRouteVt30Rva,
|
||||
reinterpret_cast<void*>(&DetourJournalListenerRouteVt30),
|
||||
reinterpret_cast<void**>(&gOriginalJournalListenerRouteVt30));
|
||||
AttachProbeHook("JournalListener::RouteAlt vt28", kJournalListenerRouteAltVt28Rva,
|
||||
reinterpret_cast<void*>(&DetourJournalListenerRouteAltVt28),
|
||||
reinterpret_cast<void**>(&gOriginalJournalListenerRouteAltVt28));
|
||||
AttachProbeHook("JournalListener::RouteAlt vt30", kJournalListenerRouteAltVt30Rva,
|
||||
reinterpret_cast<void*>(&DetourJournalListenerRouteAltVt30),
|
||||
reinterpret_cast<void**>(&gOriginalJournalListenerRouteAltVt30));
|
||||
AttachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva,
|
||||
reinterpret_cast<void*>(&DetourJournalListenerUiVt28),
|
||||
reinterpret_cast<void**>(&gOriginalJournalListenerUiVt28));
|
||||
AttachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva,
|
||||
reinterpret_cast<void*>(&DetourJournalListenerUiVt30),
|
||||
reinterpret_cast<void**>(&gOriginalJournalListenerUiVt30));
|
||||
AttachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva,
|
||||
reinterpret_cast<void*>(&DetourJournalListenerTrackerVt28),
|
||||
reinterpret_cast<void**>(&gOriginalJournalListenerTrackerVt28));
|
||||
AttachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva,
|
||||
reinterpret_cast<void*>(&DetourFrameMappinPathWrapper),
|
||||
reinterpret_cast<void**>(&gOriginalFrameMappinPathWrapper));
|
||||
@@ -1335,6 +1528,15 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
|
||||
{
|
||||
DetachProbeHook("GPSSystem/Tick", kGpsSystemTickRva);
|
||||
DetachProbeHook("JournalManager::TrackEntry impl", kJournalTrackEntryImplRva);
|
||||
DetachProbeHook("JournalListener::Objective vt28", kJournalListenerObjectiveVt28Rva);
|
||||
DetachProbeHook("JournalListener::Objective vt30", kJournalListenerObjectiveVt30Rva);
|
||||
DetachProbeHook("JournalListener::Route vt28", kJournalListenerRouteVt28Rva);
|
||||
DetachProbeHook("JournalListener::Route vt30", kJournalListenerRouteVt30Rva);
|
||||
DetachProbeHook("JournalListener::RouteAlt vt28", kJournalListenerRouteAltVt28Rva);
|
||||
DetachProbeHook("JournalListener::RouteAlt vt30", kJournalListenerRouteAltVt30Rva);
|
||||
DetachProbeHook("JournalListener::UI vt28", kJournalListenerUiVt28Rva);
|
||||
DetachProbeHook("JournalListener::UI vt30", kJournalListenerUiVt30Rva);
|
||||
DetachProbeHook("JournalListener::Tracker vt28", kJournalListenerTrackerVt28Rva);
|
||||
DetachProbeHook("FrameMappinPathWrapper", kFrameMappinPathWrapperRva);
|
||||
DetachProbeHook("FrameMappinPathCore", kFrameMappinPathCoreRva);
|
||||
DetachProbeHook("SetSelectedMappinWrapper", kSetSelectedMappinWrapperRva);
|
||||
|
||||
Reference in New Issue
Block a user