fifa17-recon: the -4 rule is literally the ASCII prefix "RS4:"
The "4-byte header" that precedes every response class name in .rdata, which cost six failed class-to-deserializer resolutions before anyone noticed the offset, is not a length prefix or a refcount. It is the string RS4:. The full literal is RS4:FutXServerResponse, and searching for the bare class name lands four bytes in. Verified directly on three classes: FutDestroyMatchServerResponse name@0x18021d694 header = b'RS4:' FutGetDraftCurrentStateServerResponse name@0x180224204 header = b'RS4:' FutStickerBookStats2ServerResponse name@0x1802220cc header = b'RS4:' Found by a verification agent that had been instructed to distrust the rule. It did, and came back with the reason rather than the offset. A magic constant you have to remember is a rule you will eventually get wrong; a prefix you can read is not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUT92pz6RWKih9dSr8ZpxW
This commit is contained in:
@@ -165,12 +165,21 @@ def vtable(a, n=64):
|
||||
def class_deser(cls):
|
||||
"""FutXServerResponse class name -> [(deserializer, vtable, factory), ...].
|
||||
|
||||
THE -4 RULE. A response class's name literal is preceded by a 4-BYTE HEADER,
|
||||
and the factory's `lea r8,[rip+...]` points at THAT header, not at the text.
|
||||
So the reference to look up is `name_addr - 4`. Six attempts at class->deser
|
||||
resolution failed before this was noticed -- four of them returned zero
|
||||
candidates and were nearly written up as "the class has no deserializer".
|
||||
Ghidra does create the reference, so no manual instruction decoding is needed.
|
||||
THE -4 RULE, AND WHAT IT ACTUALLY IS. A response class's name literal is
|
||||
preceded by a 4-byte header, and the factory's `lea r8,[rip+...]` points at
|
||||
THAT header, not at the text, so the reference to look up is `name_addr - 4`.
|
||||
Six attempts at class->deser resolution failed before this was noticed; four of
|
||||
them returned zero candidates and were nearly written up as "the class has no
|
||||
deserializer". Ghidra does create the reference, so no manual instruction
|
||||
decoding is needed.
|
||||
|
||||
The "4-byte header" is not a length prefix or a refcount. It is literally the
|
||||
ASCII string `RS4:`. The full literal is `RS4:FutXServerResponse`, and searching
|
||||
for the bare class name lands four bytes into it. Knowing that, the rule stops
|
||||
being a magic constant to remember and becomes obvious, and it also means you
|
||||
can search for `RS4:` + the class name directly and skip the arithmetic.
|
||||
(Established 2026-08-04 by a verification agent that had been told to distrust
|
||||
the rule; it did, and found the reason instead of the offset.)
|
||||
|
||||
From the factory, the object's vtable is the .rdata address it references whose
|
||||
first two qwords are functions; the deserializer is vtable slot +0x08.
|
||||
|
||||
Reference in New Issue
Block a user