# trace_login.gdb -- observe FIFA17's Origin login-event path while we push a # Event. Answers the 3-question ladder from the # repack-reverse workflow (REPACK_INTEL.md sec.3): # Q1 does the pushed frame even REACH the sender matcher / dispatcher? # Q2 what sender STRING does the matcher strcmp compare against? (dump the table entry) # Q3 does dispatcher case-2 execute and does m_isLoggedIn actually flip? # # Substitute PIDHERE (trace_login.sh does this) and run: # gdb -batch -x trace_login.gdb 2>&1 | tee /tmp/trace_login.log # Requires kernel.yama.ptrace_scope=0. All VAs are the Wine-flat-mapped FIFA17.exe # (base 0x140000000); stable across launches. set pagination off set confirm off set width 0 attach PIDHERE set architecture i386:x86-64 # CRITICAL for Wine: pass its scheduling signals silently or gdb halts on the # first SIGUSR1 and (-batch) detaches within seconds -> zero hits. handle SIGUSR1 nostop noprint pass handle SIGUSR2 nostop noprint pass handle SIGPIPE nostop noprint pass handle SIG32 nostop noprint pass handle SIG33 nostop noprint pass handle SIG34 nostop noprint pass handle SIG35 nostop noprint pass # helper: print a register both as pointer and as a best-effort C string define pstr printf " %s = %#lx", $arg1, $arg0 # try to read it as a string; if it faults, gdb prints nothing extra printf " ascii=" x/s $arg0 end # ---- Q2: the sender matcher / inline strcmp @0x147102880 ---- # The docstring: reads sender attr via vtbl+0x70 -> rax; test rax,rax; je fail; # then inline strcmp of that against the handler's registered service name. # We do not know a-priori which regs hold the two pointers, so dump the usual # candidates as strings; whichever are char* reveal BOTH sides of the compare. break *0x147102880 commands silent printf "\n>> [Q2] sender matcher 0x147102880 hit\n" pstr "rax" $rax pstr "rcx" $rcx pstr "rdx" $rdx pstr "rsi" $rsi pstr "rdi" $rdi pstr "r8 " $r8 pstr "r9 " $r9 continue end # ---- Q1/element: the element attribute parser @0x147138660 ---- # Reaching here proves the Event matched sender AND element == "Login". break *0x147138660 commands silent printf "\n>> [Q1] parser 0x147138660 ENTERED (sender+element matched)\n" continue end # ---- Q3: dispatcher case-2 (OriginEventT::Login) ---- # 0x146f1e09e: cmp DWORD PTR [r9],1 (r9 -> parsed IsLoggedIn value) break *0x146f1e09e commands silent printf "\n>> [Q3] dispatcher case-2 reached: IsLoggedIn(parsed)=%d OriginMgr(rcx)=%#lx\n", *(int*)$r9, $rcx printf " current m_isLoggedIn byte [rcx+0x13] = %d\n", *(unsigned char*)($rcx+0x13) continue end # 0x146f1e0ab: mov BYTE PTR [rcx+0x13],1 (SET logged-in = TRUE) break *0x146f1e0ab commands silent printf ">> [Q3] ARM set m_isLoggedIn = 1 *** SUCCESS PATH ***\n" continue end # 0x146f1e0b8: mov BYTE PTR [rcx+0x13],0 (SET logged-in = FALSE / bind failed) break *0x146f1e0b8 commands silent printf ">> [Q3] ARM set m_isLoggedIn = 0 (IsLoggedIn parsed as false / bind failed)\n" continue end printf "\n=== trace_login armed. Push a Login event now (heartbeat or navigate). Ctrl-C in gdb to detach. ===\n" continue