M2: flips fire but gate is async event (not a poll)

- Hook: force GetInternetConnectedState->connected (flags +0xCAB1A/+0xCAB1B) and
  flip GoOnline to report "1" (+0xAF530) instead of "0" (+0xADE64).
- protossl-scan: add `read` mode (hex/ascii dump at addr|module+off).
- Finding: neither flip unblocks the game; it keeps retrying GoOnline every ~7s.
  The FUT-online flow is event-driven -- the game waits for an async "online
  established" event anadius (offline-only) never pushes. Documented in
  connection-gate-findings.md. Next: trace FIFA-side flow (Ghidra) / anadius
  event-send to inject the online event.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
funman300
2026-06-29 19:45:15 -07:00
parent 550b23bb26
commit e2c6ae8e5b
3 changed files with 121 additions and 9 deletions
+44
View File
@@ -136,6 +136,50 @@ fn main() {
let _ = CloseHandle(process);
}
}
// read <hex-addr | module+0xoffset> [len] [pid|name]
// Dump raw bytes (hex + ASCII) at an address — to read short strings /
// data the disassembler doesn't resolve.
Some("read") => {
let arg = match args.get(1) {
Some(a) => a.clone(),
None => {
eprintln!("Usage: protossl-scan read <hex-addr | module+0xoffset> [len] [pid]");
std::process::exit(1);
}
};
let len = args
.get(2)
.and_then(|s| s.parse::<usize>().ok().or_else(|| parse_hex(s)))
.unwrap_or(64);
let pid = resolve_pid(args.get(3).map(|s| s.as_str()));
let process = open_for_read(pid);
let modules = enumerate_modules(pid);
let target = match resolve_target(&arg, &modules) {
Some(t) => t,
None => {
eprintln!("Could not resolve '{arg}'");
std::process::exit(1);
}
};
println!("== read {} len {len} ==", describe(target, &modules));
match read_bytes(process, target, len) {
Some(b) => {
for off in (0..b.len()).step_by(16) {
let row = &b[off..(off + 16).min(b.len())];
let hexp: String = row.iter().map(|x| format!("{x:02X} ")).collect();
let asc: String = row
.iter()
.map(|&x| if (0x20..=0x7e).contains(&x) { x as char } else { '.' })
.collect();
println!(" 0x{:016X} {:<48} {}", target + off, hexp, asc);
}
}
None => println!(" (could not read memory at that address)"),
}
unsafe {
let _ = CloseHandle(process);
}
}
// callers <hex-addr | module+0xoffset> [pid|name]
// Find direct call/jmp sites that target an address — walks up the call
// graph (e.g. from a connect helper to the code that gates it).