Probe route observer service lookup
This commit is contained in:
@@ -37,7 +37,9 @@ Current behavior:
|
||||
`0x286a85c`.
|
||||
- Logs the route entry pointer and route object pointer passed to those
|
||||
observers, including route object vtable slots and common fields such as the
|
||||
active byte at offset `0x84`.
|
||||
active byte at offset `0x84`, the service lookup key at offset `0x8c`, and
|
||||
the runtime observer1 service-owner path used before its vtable `0x220`
|
||||
lookup.
|
||||
- Resolves the native mappin system when one of those paths fires, logs relevant
|
||||
vtable slot addresses, and temporarily hooks the route-adjacent slots.
|
||||
|
||||
|
||||
@@ -337,6 +337,34 @@ The installed probe now hooks those callbacks directly and logs the route entry,
|
||||
route object, route object vtable slots, and the route object's active byte at
|
||||
offset `0x84`.
|
||||
|
||||
The first observer-object run separated three route-object vtable families:
|
||||
|
||||
```text
|
||||
vtable 0x142b31138: quest/objective route objects, key at +0x40
|
||||
vtable 0x142af1510: quest/objective route objects, key at +0x40
|
||||
vtable 0x142b30e20: custom/player pin route objects, key at +0x40
|
||||
```
|
||||
|
||||
`RouteActivate` and `RouteDeactivate` really do flip the route object's active
|
||||
byte at `+0x84`. The observer callbacks receive the same route entry after that
|
||||
flip.
|
||||
|
||||
Static disassembly of observer0 (`0xaa6610 -> 0xaa6678`) shows it consuming
|
||||
route-object virtuals at `+0x1a8`, `+0x188`, `+0x140`, and `+0x198`.
|
||||
`+0x198` returns a route enum from a nested descriptor; `+0x188` returns a
|
||||
descriptor payload pointer; and `+0x140` is a route-family-specific boolean.
|
||||
That observer stores derived route state into buckets under the observer object,
|
||||
choosing one bucket only when the enum is `0x8e`.
|
||||
|
||||
Static disassembly of observer1 (`0xaa6628`) is now the highest-value
|
||||
downstream branch. It resolves a route object, then calls a generic system
|
||||
getter with a runtime type/global at `.data` RVA `0x342f6a8`, calls the returned
|
||||
service's vtable slot `0x220` with `routeObject + 0x8c`, and stores generated
|
||||
handles/strings under its inner object at offsets around `+0x180`, `+0x1a0`,
|
||||
`+0x1c0`, and `+0x1e0`. The current probe logs that service-owner path and
|
||||
`routeObject + 0x8c` so the next runtime test can tell whether observer1 is
|
||||
crossing into GPS/path computation or just updating presentation state.
|
||||
|
||||
The most route-building-looking static candidate currently in this chain is
|
||||
`0x5625a4`, called once from the bridge at `0x5984ec`. The bridge resolves
|
||||
journal route ids through virtual journal-manager calls, collects several route
|
||||
|
||||
@@ -137,6 +137,7 @@ constexpr uintptr_t kRouteObserver23ActivateRva = 0x0AA63E0;
|
||||
constexpr uintptr_t kRouteObserver0DeactivateRva = 0x27B10C0;
|
||||
constexpr uintptr_t kRouteObserver1DeactivateRva = 0x295D4A0;
|
||||
constexpr uintptr_t kRouteObserver23DeactivateRva = 0x286A85C;
|
||||
constexpr uintptr_t kObserver1SystemTypeGlobalRva = 0x342F6A8;
|
||||
|
||||
HMODULE gModule = nullptr;
|
||||
std::mutex gLogMutex;
|
||||
@@ -677,12 +678,17 @@ void LogMappinRouteCollections(const char* aName, uint32_t aCount, void* aSystem
|
||||
void LogRouteObserverContext(const char* aName, uint32_t aCount, void* aObserver, void* aRouteEntry)
|
||||
{
|
||||
auto* observerInner = ReadPointerField(aObserver, 0x08);
|
||||
auto* observerInnerServiceOwner = ReadPointerField(observerInner, 0x18);
|
||||
auto* observer1SystemType =
|
||||
ReadPointerField(reinterpret_cast<void*>(GetImageBase() + kObserver1SystemTypeGlobalRva), 0x00);
|
||||
auto* routeObject = ReadPointerField(aRouteEntry, 0x00);
|
||||
|
||||
std::ostringstream line;
|
||||
line << "hook " << aName << " call=" << aCount;
|
||||
AppendPointerWithRva(line, "observer", aObserver);
|
||||
AppendPointerWithRva(line, "observerInner", observerInner);
|
||||
AppendPointerWithRva(line, "observerInnerServiceOwner", observerInnerServiceOwner);
|
||||
AppendPointerWithRva(line, "observer1SystemType342f6a8", observer1SystemType);
|
||||
AppendPointerWithRva(line, "routeEntry", aRouteEntry);
|
||||
AppendPointerWithRva(line, "routeObject", routeObject);
|
||||
AppendPointerField(line, "routeEntry_f08", aRouteEntry, 0x08);
|
||||
@@ -696,6 +702,31 @@ void LogRouteObserverContext(const char* aName, uint32_t aCount, void* aObserver
|
||||
AppendObjectVtableSlots(observerLine, aObserver, {0x48, 0x50});
|
||||
LogRed4ext(observerLine.str());
|
||||
|
||||
if (observerInner)
|
||||
{
|
||||
std::ostringstream innerLine;
|
||||
innerLine << "route-observer-inner " << aName << " call=" << aCount;
|
||||
AppendPointerWithRva(innerLine, "observerInner", observerInner);
|
||||
AppendObjectVtableSlots(innerLine, observerInner, {0x08});
|
||||
AppendPointerField(innerLine, "field18", observerInner, 0x18);
|
||||
AppendPointerField(innerLine, "field180", observerInner, 0x180);
|
||||
AppendPointerField(innerLine, "field1a0", observerInner, 0x1A0);
|
||||
AppendPointerField(innerLine, "field1c0", observerInner, 0x1C0);
|
||||
AppendPointerField(innerLine, "field1e0", observerInner, 0x1E0);
|
||||
AppendPointerField(innerLine, "field1e8", observerInner, 0x1E8);
|
||||
AppendPointerField(innerLine, "field1f0", observerInner, 0x1F0);
|
||||
LogRed4ext(innerLine.str());
|
||||
}
|
||||
|
||||
if (observerInnerServiceOwner)
|
||||
{
|
||||
std::ostringstream serviceOwnerLine;
|
||||
serviceOwnerLine << "route-observer-service-owner " << aName << " call=" << aCount;
|
||||
AppendPointerWithRva(serviceOwnerLine, "serviceOwner", observerInnerServiceOwner);
|
||||
AppendObjectVtableSlots(serviceOwnerLine, observerInnerServiceOwner, {0x08});
|
||||
LogRed4ext(serviceOwnerLine.str());
|
||||
}
|
||||
|
||||
if (!routeObject)
|
||||
{
|
||||
return;
|
||||
@@ -710,9 +741,13 @@ void LogRouteObserverContext(const char* aName, uint32_t aCount, void* aObserver
|
||||
AppendPointerField(routeLine, "field78", routeObject, 0x78);
|
||||
AppendUint32Field(routeLine, "field80", routeObject, 0x80);
|
||||
AppendByteField(routeLine, "active84", routeObject, 0x84);
|
||||
AppendUint32Field(routeLine, "field8C", routeObject, 0x8C);
|
||||
AppendUint32Field(routeLine, "field90", routeObject, 0x90);
|
||||
AppendPointerField(routeLine, "field98", routeObject, 0x98);
|
||||
AppendPointerField(routeLine, "field88", routeObject, 0x88);
|
||||
AppendPointerField(routeLine, "fieldF8", routeObject, 0xF8);
|
||||
AppendPointerField(routeLine, "field120", routeObject, 0x120);
|
||||
AppendByteField(routeLine, "fieldE2", routeObject, 0xE2);
|
||||
LogRed4ext(routeLine.str());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user