Probe route observer service lookup
This commit is contained in:
@@ -37,7 +37,9 @@ Current behavior:
|
|||||||
`0x286a85c`.
|
`0x286a85c`.
|
||||||
- Logs the route entry pointer and route object pointer passed to those
|
- Logs the route entry pointer and route object pointer passed to those
|
||||||
observers, including route object vtable slots and common fields such as the
|
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
|
- Resolves the native mappin system when one of those paths fires, logs relevant
|
||||||
vtable slot addresses, and temporarily hooks the route-adjacent slots.
|
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
|
route object, route object vtable slots, and the route object's active byte at
|
||||||
offset `0x84`.
|
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
|
The most route-building-looking static candidate currently in this chain is
|
||||||
`0x5625a4`, called once from the bridge at `0x5984ec`. The bridge resolves
|
`0x5625a4`, called once from the bridge at `0x5984ec`. The bridge resolves
|
||||||
journal route ids through virtual journal-manager calls, collects several route
|
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 kRouteObserver0DeactivateRva = 0x27B10C0;
|
||||||
constexpr uintptr_t kRouteObserver1DeactivateRva = 0x295D4A0;
|
constexpr uintptr_t kRouteObserver1DeactivateRva = 0x295D4A0;
|
||||||
constexpr uintptr_t kRouteObserver23DeactivateRva = 0x286A85C;
|
constexpr uintptr_t kRouteObserver23DeactivateRva = 0x286A85C;
|
||||||
|
constexpr uintptr_t kObserver1SystemTypeGlobalRva = 0x342F6A8;
|
||||||
|
|
||||||
HMODULE gModule = nullptr;
|
HMODULE gModule = nullptr;
|
||||||
std::mutex gLogMutex;
|
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)
|
void LogRouteObserverContext(const char* aName, uint32_t aCount, void* aObserver, void* aRouteEntry)
|
||||||
{
|
{
|
||||||
auto* observerInner = ReadPointerField(aObserver, 0x08);
|
auto* observerInner = ReadPointerField(aObserver, 0x08);
|
||||||
|
auto* observerInnerServiceOwner = ReadPointerField(observerInner, 0x18);
|
||||||
|
auto* observer1SystemType =
|
||||||
|
ReadPointerField(reinterpret_cast<void*>(GetImageBase() + kObserver1SystemTypeGlobalRva), 0x00);
|
||||||
auto* routeObject = ReadPointerField(aRouteEntry, 0x00);
|
auto* routeObject = ReadPointerField(aRouteEntry, 0x00);
|
||||||
|
|
||||||
std::ostringstream line;
|
std::ostringstream line;
|
||||||
line << "hook " << aName << " call=" << aCount;
|
line << "hook " << aName << " call=" << aCount;
|
||||||
AppendPointerWithRva(line, "observer", aObserver);
|
AppendPointerWithRva(line, "observer", aObserver);
|
||||||
AppendPointerWithRva(line, "observerInner", observerInner);
|
AppendPointerWithRva(line, "observerInner", observerInner);
|
||||||
|
AppendPointerWithRva(line, "observerInnerServiceOwner", observerInnerServiceOwner);
|
||||||
|
AppendPointerWithRva(line, "observer1SystemType342f6a8", observer1SystemType);
|
||||||
AppendPointerWithRva(line, "routeEntry", aRouteEntry);
|
AppendPointerWithRva(line, "routeEntry", aRouteEntry);
|
||||||
AppendPointerWithRva(line, "routeObject", routeObject);
|
AppendPointerWithRva(line, "routeObject", routeObject);
|
||||||
AppendPointerField(line, "routeEntry_f08", aRouteEntry, 0x08);
|
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});
|
AppendObjectVtableSlots(observerLine, aObserver, {0x48, 0x50});
|
||||||
LogRed4ext(observerLine.str());
|
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)
|
if (!routeObject)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -710,9 +741,13 @@ void LogRouteObserverContext(const char* aName, uint32_t aCount, void* aObserver
|
|||||||
AppendPointerField(routeLine, "field78", routeObject, 0x78);
|
AppendPointerField(routeLine, "field78", routeObject, 0x78);
|
||||||
AppendUint32Field(routeLine, "field80", routeObject, 0x80);
|
AppendUint32Field(routeLine, "field80", routeObject, 0x80);
|
||||||
AppendByteField(routeLine, "active84", routeObject, 0x84);
|
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, "field88", routeObject, 0x88);
|
||||||
AppendPointerField(routeLine, "fieldF8", routeObject, 0xF8);
|
AppendPointerField(routeLine, "fieldF8", routeObject, 0xF8);
|
||||||
AppendPointerField(routeLine, "field120", routeObject, 0x120);
|
AppendPointerField(routeLine, "field120", routeObject, 0x120);
|
||||||
|
AppendByteField(routeLine, "fieldE2", routeObject, 0xE2);
|
||||||
LogRed4ext(routeLine.str());
|
LogRed4ext(routeLine.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user