#!/usr/bin/env python3 """Dump the DECRYPTED FIFA17 login machinery from live /proc/PID/mem. FIFA17.exe's .data-region code is packed/encrypted on disk (objdump of the file is garbage); the real instructions only exist decrypted in memory at runtime. This grabs generous windows around the known login-path VAs (from prior live recon) plus the resolved OriginMgr / session objects, then disassembles each window at its true VA so a follow-up reversing pass works on real code. Run while FIFA17 is running (ptrace_scope=0). Output -> ./login_dump/ + manifest.txt. """ import glob, os, subprocess, struct, sys OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "login_dump") os.makedirs(OUT, exist_ok=True) # (name, VA, bytes_before, bytes_after) — code windows around the login machinery. CODE = [ ("dispatch_case2", 0x146f1e080, 0x120, 0x180), # event dispatcher; case-2 sets m_isLoggedIn ("event_matcher", 0x147102880, 0x40, 0x400), # sender/element matcher ("login_parser", 0x147138660, 0x40, 0x400), # element parser (reads IsLoggedIn) ("loginstate_pclogin", 0x1471b58e0, 0x40, 0x600), # LoginStatePCLogin entry ("txt_not_login_ebisu", 0x1471b5b00, 0x40, 0x400), # TXT_NOT_LOGIN_TO_EBISU write site(s) ("pclogin_callsite", 0x1471b6780, 0x60, 0x120), # session-object call: ff 50 60 (vtbl+0x60) ] # Data pointers to resolve (name, ptr_VA, deref_chain_offsets, dump_span). # We read *[ptr_VA], then optionally add offsets, then dump `span` bytes there. DATA = [ ("originmgr", 0x1448acf50, [], 0x80), # OriginMgr; m_isLoggedIn @+0x13, loginError @+0x14 ("online_flags", 0x1448a3ac0, [], 0x40), # "internet reachable" byte lives here ("auth_block", 0x1448a3b20, [0x4e98], 0x60), # auth slots +0x08/+0x10 ("session_obj", 0x144b86bf8, [], 0x80), # LoginStatePCLogin session object (vtbl @+0) ] def find_pid(): for d in glob.glob('/proc/[0-9]*'): try: if open(d + '/comm').read().strip() == 'FIFA17.exe': return int(os.path.basename(d)) except Exception: pass return None def read(f, va, n): f.seek(va); return f.read(n) def rd_u64(f, va): b = read(f, va, 8) return struct.unpack(' {os.path.basename(p)}[.asm]" print(line); man.write(line + "\n") man.write("\n") for name, ptr, chain, span in DATA: base = rd_u64(f, ptr) addr = base trail = f"*[{ptr:#x}]={base:#x}" for off in chain: nxt = rd_u64(f, addr + off) if off and base else base # for a single deref-with-offset we dump AT base+off, not deref again: addr = base target = base + (chain[0] if chain else 0) data = read(f, target, span) if base else b"" p = os.path.join(OUT, f"{name}_{target:x}.bin") open(p, "wb").write(data) # hex preview hexp = " ".join("%02x" % x for x in data[:0x40]) line = f"DATA {name:22s} {trail} dump@{target:#x} ({len(data)}B) -> {os.path.basename(p)}\n first64: {hexp}" print(line); man.write(line + "\n") man.close() print("\nWrote dumps + manifest to", OUT) if __name__ == "__main__": main()