feat: document and stage FIFA 17 SBC hook workflow
This commit is contained in:
Executable
+252
@@ -0,0 +1,252 @@
|
||||
#!/usr/bin/env bash
|
||||
# FIFA 17 hook M1 staging/deployment helper.
|
||||
#
|
||||
# Safe defaults:
|
||||
# inspect (the default) is read-only;
|
||||
# stage writes only below the repository;
|
||||
# deploy and launch require separate, exact confirmation variables.
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
hook_root="${repo_root}/openfut-launcher/openfut-hook"
|
||||
default_dll="${hook_root}/target/x86_64-pc-windows-gnu/release/openfut_hook.dll"
|
||||
stage_root="${repo_root}/fifa17-recon/staging/fifa17-hook-m1"
|
||||
|
||||
game_dir="${OPENFUT_FIFA17_GAME_DIR:-/mnt/games/FIFA 17}"
|
||||
wine_prefix="${OPENFUT_FIFA17_WINEPREFIX:-/home/alex/Games/umu/fifa17}"
|
||||
proton_path="${OPENFUT_FIFA17_PROTONPATH:-UMU-Proton-10.0-4}"
|
||||
hook_dll="${OPENFUT_FIFA17_HOOK_DLL:-${default_dll}}"
|
||||
system_version="${wine_prefix}/drive_c/windows/system32/version.dll"
|
||||
deployed_dll="${game_dir}/version.dll"
|
||||
|
||||
required_exports=(
|
||||
GetFileVersionInfoA GetFileVersionInfoExA GetFileVersionInfoExW
|
||||
GetFileVersionInfoSizeA GetFileVersionInfoSizeExA GetFileVersionInfoSizeExW
|
||||
GetFileVersionInfoSizeW GetFileVersionInfoW VerFindFileA VerFindFileW
|
||||
VerInstallFileA VerInstallFileW VerLanguageNameA VerLanguageNameW
|
||||
VerQueryValueA VerQueryValueW
|
||||
)
|
||||
|
||||
die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }
|
||||
note() { printf '%s\n' "$*"; }
|
||||
need_file() { [[ -f "$1" ]] || die "missing file: $1"; }
|
||||
|
||||
sha256() { sha256sum -- "$1" | awk '{print $1}'; }
|
||||
|
||||
pe_exports() {
|
||||
x86_64-w64-mingw32-objdump -p "$1" |
|
||||
awk '/\[Ordinal\/Name Pointer\] Table/{in_names=1; next} in_names && /\+base\[/ {print $NF}'
|
||||
}
|
||||
|
||||
verify_pe64() {
|
||||
local dll=$1
|
||||
local format
|
||||
format="$(x86_64-w64-mingw32-objdump -f "$dll" | awk '/file format/{print $NF}')"
|
||||
[[ "$format" == "pei-x86-64" ]] || die "$dll is not a 64-bit PE DLL (format=${format:-unknown})"
|
||||
}
|
||||
|
||||
verify_exports() {
|
||||
local dll=$1 export_name
|
||||
local exports
|
||||
exports="$(pe_exports "$dll")"
|
||||
for export_name in "${required_exports[@]}"; do
|
||||
grep -Fxq "$export_name" <<<"$exports" ||
|
||||
die "$dll lacks VERSION export $export_name; refusing to stage/deploy"
|
||||
done
|
||||
}
|
||||
|
||||
verify_inputs() {
|
||||
command -v sha256sum >/dev/null || die "sha256sum is required"
|
||||
command -v x86_64-w64-mingw32-objdump >/dev/null ||
|
||||
die "x86_64-w64-mingw32-objdump is required"
|
||||
need_file "$hook_dll"
|
||||
need_file "$system_version"
|
||||
verify_pe64 "$hook_dll"
|
||||
}
|
||||
|
||||
inspect() {
|
||||
verify_inputs
|
||||
note "mode=inspect (read-only)"
|
||||
note "hook=$hook_dll"
|
||||
note "hook_sha256=$(sha256 "$hook_dll")"
|
||||
note "system_version=$system_version"
|
||||
note "system_version_sha256=$(sha256 "$system_version")"
|
||||
note "game_dir=$game_dir"
|
||||
if [[ -f "$deployed_dll" ]]; then
|
||||
note "deployed_version_sha256=$(sha256 "$deployed_dll")"
|
||||
else
|
||||
note "deployed_version=absent"
|
||||
fi
|
||||
verify_exports "$hook_dll"
|
||||
note "version_exports=complete"
|
||||
}
|
||||
|
||||
build() {
|
||||
command -v cargo >/dev/null || die "cargo is required"
|
||||
note "Building the inert FIFA 17 hook into the package-local staging source path."
|
||||
CARGO_TARGET_DIR="${hook_root}/target" \
|
||||
cargo build --offline --release --features fifa17 \
|
||||
--target x86_64-pc-windows-gnu --manifest-path "${hook_root}/Cargo.toml"
|
||||
inspect
|
||||
}
|
||||
|
||||
stage() {
|
||||
verify_inputs
|
||||
verify_exports "$hook_dll"
|
||||
need_file "${game_dir}/CardsDLL_Win64_retail.dll"
|
||||
need_file "${game_dir}/FIFA17.exe"
|
||||
mkdir -p "$stage_root"
|
||||
local staged="${stage_root}/version.dll"
|
||||
cp -- "$hook_dll" "$staged"
|
||||
{
|
||||
printf 'artifact=%s\n' "$staged"
|
||||
printf 'artifact_sha256=%s\n' "$(sha256 "$staged")"
|
||||
printf 'source=%s\n' "$hook_dll"
|
||||
printf 'source_sha256=%s\n' "$(sha256 "$hook_dll")"
|
||||
printf 'system_version=%s\n' "$system_version"
|
||||
printf 'system_version_sha256=%s\n' "$(sha256 "$system_version")"
|
||||
printf 'cards_dll_sha256=%s\n' "$(sha256 "${game_dir}/CardsDLL_Win64_retail.dll")"
|
||||
printf 'fifa17_exe_sha256=%s\n' "$(sha256 "${game_dir}/FIFA17.exe")"
|
||||
} >"${stage_root}/manifest.txt"
|
||||
note "staged=$staged"
|
||||
note "manifest=${stage_root}/manifest.txt"
|
||||
note "No game-directory file was changed."
|
||||
}
|
||||
|
||||
require_game_stopped() {
|
||||
if pgrep -fi '(FIFA17|_fifa17)\.exe' >/dev/null; then
|
||||
die "FIFA 17 appears to be running; close it before deployment"
|
||||
fi
|
||||
}
|
||||
|
||||
deploy() {
|
||||
[[ "${OPENFUT_FIFA17_DEPLOY:-}" == "I_ACCEPT_VERSION_DLL_REPLACEMENT" ]] ||
|
||||
die "deploy requires OPENFUT_FIFA17_DEPLOY=I_ACCEPT_VERSION_DLL_REPLACEMENT"
|
||||
require_game_stopped
|
||||
local staged="${stage_root}/version.dll"
|
||||
local manifest="${stage_root}/manifest.txt"
|
||||
need_file "$staged"
|
||||
need_file "$manifest"
|
||||
verify_pe64 "$staged"
|
||||
verify_exports "$staged"
|
||||
local recorded actual
|
||||
recorded="$(awk -F= '$1=="artifact_sha256"{print $2}' "$manifest")"
|
||||
actual="$(sha256 "$staged")"
|
||||
[[ -n "$recorded" && "$recorded" == "$actual" ]] || die "staged artifact hash does not match manifest"
|
||||
|
||||
local backup_dir="${game_dir}/openfut-backups"
|
||||
mkdir -p "$backup_dir"
|
||||
if [[ -f "$deployed_dll" ]]; then
|
||||
local old_hash backup
|
||||
old_hash="$(sha256 "$deployed_dll")"
|
||||
backup="${backup_dir}/version.dll.${old_hash}.bak"
|
||||
if [[ ! -e "$backup" ]]; then
|
||||
cp -- "$deployed_dll" "$backup"
|
||||
fi
|
||||
[[ "$(sha256 "$backup")" == "$old_hash" ]] || die "backup verification failed: $backup"
|
||||
note "backup=$backup"
|
||||
fi
|
||||
cp -- "$staged" "$deployed_dll"
|
||||
[[ "$(sha256 "$deployed_dll")" == "$actual" ]] || die "deployed DLL hash verification failed"
|
||||
note "deployed=$deployed_dll"
|
||||
note "deployed_sha256=$actual"
|
||||
}
|
||||
|
||||
launch() {
|
||||
local mode=${1:-baseline}
|
||||
local hook_enabled=0
|
||||
local trace_enabled=0
|
||||
local request_trace_enabled=0
|
||||
local notifier_trace_enabled=0
|
||||
case "$mode" in
|
||||
baseline)
|
||||
[[ "${OPENFUT_FIFA17_LAUNCH:-}" == "I_ACCEPT_M1_BASELINE_LAUNCH" ]] ||
|
||||
die "launch requires OPENFUT_FIFA17_LAUNCH=I_ACCEPT_M1_BASELINE_LAUNCH"
|
||||
;;
|
||||
resolve)
|
||||
[[ "${OPENFUT_FIFA17_RESOLVE:-}" == "I_ACCEPT_M2_RESOLVE_LAUNCH" ]] ||
|
||||
die "launch-resolve requires OPENFUT_FIFA17_RESOLVE=I_ACCEPT_M2_RESOLVE_LAUNCH"
|
||||
hook_enabled=1
|
||||
;;
|
||||
trace)
|
||||
[[ "${OPENFUT_FIFA17_TRACE:-}" == "I_ACCEPT_M3_PASSIVE_TRACE" ]] ||
|
||||
die "launch-trace requires OPENFUT_FIFA17_TRACE=I_ACCEPT_M3_PASSIVE_TRACE"
|
||||
hook_enabled=1
|
||||
trace_enabled=1
|
||||
request_trace_enabled=1
|
||||
notifier_trace_enabled=1
|
||||
;;
|
||||
*) die "unknown launch mode: $mode" ;;
|
||||
esac
|
||||
need_file "$deployed_dll"
|
||||
local staged="${stage_root}/version.dll"
|
||||
local manifest="${stage_root}/manifest.txt"
|
||||
need_file "$staged"
|
||||
need_file "$manifest"
|
||||
verify_pe64 "$deployed_dll"
|
||||
verify_exports "$deployed_dll"
|
||||
local recorded
|
||||
recorded="$(awk -F= '$1=="artifact_sha256"{print $2}' "$manifest")"
|
||||
[[ -n "$recorded" && "$(sha256 "$staged")" == "$recorded" ]] ||
|
||||
die "staged artifact hash does not match manifest"
|
||||
[[ "$(sha256 "$deployed_dll")" == "$recorded" ]] ||
|
||||
die "deployed version.dll does not match the staged M1 artifact"
|
||||
command -v umu-run >/dev/null || die "umu-run is required"
|
||||
for name in OPENFUT_SBC_DISPATCH OPENFUT_SBC_COMMIT OPENFUT_SBC_ARM_ONLY OPENFUT_SBC_POPULATE; do
|
||||
[[ -z "${!name:-}" || "${!name}" == "0" ]] || die "$name must be unset or 0 for this launch"
|
||||
done
|
||||
mkdir -p "${wine_prefix}/dosdevices"
|
||||
ln -sfn /mnt "${wine_prefix}/dosdevices/w:"
|
||||
note "Launching $mode mode (SBC_HOOK=$hook_enabled; SBC_TRACE=$trace_enabled; SBC_REQUEST_TRACE=$request_trace_enabled; SBC_NOTIFIER_TRACE=$notifier_trace_enabled; every mutation feature disabled); log=/tmp/fifa17-hook-m1-launch.log"
|
||||
cd "$game_dir"
|
||||
env \
|
||||
GAMEID=fifa17 \
|
||||
PROTONPATH="$proton_path" \
|
||||
WINEPREFIX="$wine_prefix" \
|
||||
WINEDLLOVERRIDES='version=n,b' \
|
||||
OPENFUT_SBC_HOOK="$hook_enabled" \
|
||||
OPENFUT_SBC_TRACE="$trace_enabled" \
|
||||
OPENFUT_SBC_REQUEST_TRACE="$request_trace_enabled" \
|
||||
OPENFUT_SBC_NOTIFIER_TRACE="$notifier_trace_enabled" \
|
||||
OPENFUT_SBC_DISPATCH=0 \
|
||||
OPENFUT_SBC_COMMIT=0 \
|
||||
OPENFUT_SBC_ARM_ONLY=0 \
|
||||
OPENFUT_SBC_POPULATE=0 \
|
||||
umu-run _fifa17.exe 2>&1 | tee /tmp/fifa17-hook-m1-launch.log
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: fifa17-hook-m1.sh [inspect|build|stage|deploy|launch|launch-resolve|launch-trace]
|
||||
|
||||
inspect Read-only PE/hash/export preflight (default).
|
||||
build Cross-build the inert FIFA17 hook, then run inspect.
|
||||
stage Copy a verified DLL into repo-local staging and write a hash manifest.
|
||||
deploy Back up and install version.dll; requires:
|
||||
OPENFUT_FIFA17_DEPLOY=I_ACCEPT_VERSION_DLL_REPLACEMENT
|
||||
launch Start the M1 inert-hook baseline; requires:
|
||||
OPENFUT_FIFA17_LAUNCH=I_ACCEPT_M1_BASELINE_LAUNCH
|
||||
launch-resolve
|
||||
Start M2 resolve-only mode (guarded reads/logging, no detours/writes); requires:
|
||||
OPENFUT_FIFA17_RESOLVE=I_ACCEPT_M2_RESOLVE_LAUNCH
|
||||
launch-trace
|
||||
Start the single M3 passive factory/deserializer trace; requires:
|
||||
OPENFUT_FIFA17_TRACE=I_ACCEPT_M3_PASSIVE_TRACE
|
||||
|
||||
Optional path overrides:
|
||||
OPENFUT_FIFA17_HOOK_DLL, OPENFUT_FIFA17_GAME_DIR,
|
||||
OPENFUT_FIFA17_WINEPREFIX, OPENFUT_FIFA17_PROTONPATH
|
||||
EOF
|
||||
}
|
||||
|
||||
case "${1:-inspect}" in
|
||||
inspect) inspect ;;
|
||||
build) build ;;
|
||||
stage) stage ;;
|
||||
deploy) deploy ;;
|
||||
launch) launch baseline ;;
|
||||
launch-resolve) launch resolve ;;
|
||||
launch-trace) launch trace ;;
|
||||
-h|--help|help) usage ;;
|
||||
*) usage >&2; die "unknown command: $1" ;;
|
||||
esac
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
# Launch x64dbg inside FIFA 17's UMU/Proton prefix.
|
||||
set -euo pipefail
|
||||
|
||||
x64dbg_root="${OPENFUT_X64DBG_ROOT:-/home/alex/Games/x64dbg}"
|
||||
wine_prefix="${OPENFUT_FIFA17_WINEPREFIX:-/home/alex/Games/umu/fifa17}"
|
||||
proton_path="${OPENFUT_FIFA17_PROTONPATH:-UMU-Proton-10.0-4}"
|
||||
debugger="${x64dbg_root}/release/x64/x64dbg-unsigned.exe"
|
||||
|
||||
[[ -f "$debugger" ]] || {
|
||||
printf 'ERROR: x64dbg executable not found: %s\n' "$debugger" >&2
|
||||
exit 1
|
||||
}
|
||||
command -v umu-run >/dev/null || {
|
||||
printf 'ERROR: umu-run is required\n' >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd "${x64dbg_root}/release/x64"
|
||||
exec env \
|
||||
GAMEID=fifa17 \
|
||||
PROTONPATH="$proton_path" \
|
||||
WINEPREFIX="$wine_prefix" \
|
||||
QT_OPENGL=desktop \
|
||||
umu-run "$debugger" "$@"
|
||||
Reference in New Issue
Block a user