Compare commits
1 Commits
5aec83ce97
...
c58e7326a1
| Author | SHA1 | Date | |
|---|---|---|---|
| c58e7326a1 |
@@ -231,7 +231,26 @@ FIFA23.exe via anadius's detour table, then `callers` to the online-flow; or
|
||||
(b) find anadius's LSX event-send path and reverse the online-event format. Both
|
||||
are deep. `TODO/CONFIRM`.
|
||||
|
||||
### M2 directions (superseded — see above)
|
||||
### Path A attempt: reach the FIFA-side online-flow (blocked with live toolkit)
|
||||
Goal: find `EbisuSDK::GoOnline` in FIFA23.exe → `callers` → the game's online-flow
|
||||
→ read what event it waits on. Every angle our live-memory toolkit offers is
|
||||
blocked:
|
||||
- **String xref:** FIFA23.exe contains no `"GoOnline"` string (typed SDK call,
|
||||
not a string-built command).
|
||||
- **Call-stack from the handler:** GoOnline runs on an anadius worker thread; a
|
||||
bounded stack scan finds zero FIFA frames.
|
||||
- **Detour scan (`jmpscan`):** scanning FIFA23.exe for function-entry `E9` jumps
|
||||
leaving the module yields ~3875 hits — overwhelmingly false positives, because
|
||||
the 505 MB image is mostly embedded *data* (not code), and the real detours
|
||||
don't cleanly cluster. (A .text-section-only scan would help but the chain
|
||||
after — isolate GoOnline → callers → event format → emulate — remains long and
|
||||
each link is gated by SDK abstraction / anadius indirection / worker threads.)
|
||||
|
||||
**Verdict:** crossing this gate to *playable* FUT is research-grade. It needs an
|
||||
interactive disassembler (IDA/Ghidra GUI, human-driven) to trace the EbisuSDK
|
||||
online-flow, and then a full EA-online + Blaze emulator. The live-memory toolkit
|
||||
(string/xref/disasm/callers/read/jmpscan) has been exhausted for the FIFA side.
|
||||
The clean-room spec (this document) is the finished, valuable artifact.
|
||||
- Check whether the flags at `+0xCAB1A` / `+0xCAB1B` are settable via anadius
|
||||
config / a hidden option (cheapest flip).
|
||||
- Else out-detour `GetInternetConnectedState` in our `version.dll` to force the
|
||||
|
||||
@@ -183,6 +183,20 @@ fn main() {
|
||||
// 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).
|
||||
// jmpscan [module] [pid|name]
|
||||
// Find E9 rel32 jumps inside a module whose target leaves the module —
|
||||
// i.e. inline-detour entry points (MS Detours hooks). Default module:
|
||||
// FIFA23.exe; targets reveal the detoured EbisuSDK functions.
|
||||
Some("jmpscan") => {
|
||||
let modname = args.get(1).cloned().unwrap_or_else(|| "FIFA23".to_string());
|
||||
let pid = resolve_pid(args.get(2).map(|s| s.as_str()));
|
||||
let process = open_for_read(pid);
|
||||
let modules = enumerate_modules(pid);
|
||||
run_jmpscan(process, &modules, &modname);
|
||||
unsafe {
|
||||
let _ = CloseHandle(process);
|
||||
}
|
||||
}
|
||||
Some("callers") => {
|
||||
let arg = match args.get(1) {
|
||||
Some(a) => a.clone(),
|
||||
@@ -471,6 +485,64 @@ fn dump_neighbours(process: HANDLE, at: usize, modules: &[ModuleInfo]) {
|
||||
/// Scan app-module executable memory for near `call`/`jmp` (E8/E9 + rel32)
|
||||
/// instructions whose target is `target`. This walks UP the call graph — e.g.
|
||||
/// from a connect helper to the code that decides whether to call it.
|
||||
/// Scan a module's executable memory for `E9 rel32` near-jumps whose target is
|
||||
/// OUTSIDE the module — the signature of an inline detour (function entry patched
|
||||
/// to jump to an external trampoline). Reports source -> target for each.
|
||||
fn run_jmpscan(process: HANDLE, modules: &[ModuleInfo], modname: &str) {
|
||||
let want = modname.to_ascii_lowercase();
|
||||
let want = want.strip_suffix(".dll").unwrap_or(&want);
|
||||
let want = want.strip_suffix(".exe").unwrap_or(want);
|
||||
let m = match modules.iter().find(|m| {
|
||||
let n = m.name.to_ascii_lowercase();
|
||||
n.starts_with(want)
|
||||
}) {
|
||||
Some(m) => m,
|
||||
None => {
|
||||
println!("module '{modname}' not found");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let base = m.base;
|
||||
let end = m.base + m.size;
|
||||
println!("== jmpscan {} [0x{base:X}..0x{end:X}] ==\n", m.name);
|
||||
|
||||
let allow = [(base, end)];
|
||||
let mut hits: Vec<(usize, usize)> = Vec::new();
|
||||
walk_regions(process, true, 4, Some(&allow), |chunk_base, bytes| {
|
||||
if bytes.len() < 5 {
|
||||
return;
|
||||
}
|
||||
for i in 1..=bytes.len() - 5 {
|
||||
// Real detours patch a function entry, which MSVC pads with int3
|
||||
// (0xCC) just before it. Requiring that preceding 0xCC filters out
|
||||
// the flood of 0xE9 data bytes that aren't real instructions.
|
||||
if bytes[i] != 0xE9 || bytes[i - 1] != 0xCC {
|
||||
continue;
|
||||
}
|
||||
let rel = i32::from_le_bytes([bytes[i + 1], bytes[i + 2], bytes[i + 3], bytes[i + 4]]);
|
||||
let src = chunk_base + i;
|
||||
let tgt = (src + 5).wrapping_add(rel as i64 as usize);
|
||||
if tgt < base || tgt >= end {
|
||||
hits.push((src, tgt));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
hits.sort_unstable();
|
||||
hits.dedup();
|
||||
if hits.is_empty() {
|
||||
println!(" no out-of-module E9 jumps found");
|
||||
return;
|
||||
}
|
||||
println!("-- {} out-of-module E9 jump(s) (detour entry candidates) --", hits.len());
|
||||
for (src, tgt) in hits.iter().take(80) {
|
||||
println!(" {} -> {}", describe(*src, modules), describe(*tgt, modules));
|
||||
}
|
||||
if hits.len() > 80 {
|
||||
println!(" ... and {} more", hits.len() - 80);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_callers(process: HANDLE, modules: &[ModuleInfo], target: usize) {
|
||||
println!("== protossl-scan : callers of 0x{target:X} ==");
|
||||
println!("({})\n", describe(target, modules));
|
||||
|
||||
Reference in New Issue
Block a user