Skip to content

Fix action tools build - #192

Closed
mmxlyo wants to merge 43 commits into
OpenSteam001:mainfrom
mmxlyo:fix_action_tools_build
Closed

mmxlyo wants to merge 43 commits into
OpenSteam001:mainfrom
mmxlyo:fix_action_tools_build

Conversation

@mmxlyo

@mmxlyo mmxlyo commented Sep 8, 2026

Copy link
Copy Markdown

No description provided.

H-Chris233 and others added 30 commits May 25, 2026 09:14
std::stol accepts strings like "12312abc" by parsing only the numeric
prefix. Use the pos parameter to verify the entire port substring was
consumed, and treat trailing garbage as invalid.
Add a third detection method, ProtectedBlobSection, reached when the two
existing methods (OEP DODENUVO pattern; legacy section + DENUVO string)
both miss. A runtime-decrypting protector must carry a large code section
that is simultaneously writable and executable (it decrypts itself in
place) and encrypted at rest, so scan every section for one with
IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE, rawSize >= 4 MiB, and Shannon
entropy >= 7.0.

This catches current Denuvo builds that ship no OEP pattern and no DENUVO
string, which otherwise leave ProtectionScan empty and break Denuvo auth
with 88500012. Measured on Sonic Forces (appid 637100): .arch is RWX,
103.9 MiB, entropy 7.247, while the OEP section is a clean read-only stub.
Clean binaries have no W+X section, so false positives are near zero.

Expose IMAGE_SECTION_HEADER::Characteristics on PE::Section (with
IsExecutable/IsWritable helpers) to support the flag check.
# Conflicts:
#	src/Utils/Config/Config.cpp
#	src/Utils/Config/Config.h
Three independent fixes that together let strict-Denuvo titles boot when
they currently fail with 88500012 — all opt-in via Lua config; default
behaviour for existing games is unchanged.

1. Env-less appid resolution (PipeManager)
   Games launched as a child of a third-party launcher (e.g. Suicide
   Squad: KTJL, NBA 2K26) come up with SteamAppId=0, so the existing
   env-derived resolution returns invalid → trackedApp=false →
   DenuvoAuth::Apply bails forever → 012. ResolveAppIdWithRetry adds two
   fallbacks after the env check:
     - GetAppIDForCurrentPipe with a brief 10×20ms retry (steamclient
       can take a few ms to bind the pipe's appid past the literal
       handshake instant);
     - LuaConfig::GetAppIdForProcess(imageName), populated by the new
       addprocess(appid, "Exe.exe") Lua function.
   gameProcess is now (likelyGameProcess || trackedApp) so a configured
   depot counts as a game even without the env vars that drive
   likelyGameProcess.

2. forcedenuvo(appid) Lua function (LuaConfig + DenuvoAuth)
   Some Denuvo builds fire neither the OEP pattern nor the structural
   RWX+entropy heuristic (no W+X section at all, or below entropy floor).
   For those games auth.denuvo stays false → the authorization window
   never opens → GetSteamID is never spoofed → 012. forcedenuvo() lets
   the user mark a known-Denuvo appid; EnsureScanned then skips the scan
   and forces denuvo=true. No effect on any appid the user doesn't list.

3. On-demand nonce-bound eticket + 858 ownership spoof
   Strict Denuvo titles bind their encrypted-app-ticket to a per-launch
   nonce passed into RequestEncryptedAppTicket; a static credential-store
   ticket can never carry that nonce → 012. EticketClient POSTs
   {app_id, nonce(hex)} to a user-configured backend (seteticketurl) and
   serves the fresh response from the IPC GetEncryptedAppTicket handler.
   Hooks_NetPacket also now intercepts ClientGetAppOwnershipTicketResponse
   (eMsg 858, protobuf {eresult, app_id, ticket}) and replaces a
   not-owned response with the matching owner ticket from the same mint —
   required for games that gate ownership over the CM network rather than
   via IPC. Both paths share one per-app cache so eticket and ownership
   ticket always align to the same account. Empty URL (the default)
   disables the whole feature; the DLL then serves the static
   credential-store ticket exactly as a stock build does.

Also includes a ProtectionScan refinement: lower the protector-blob
entropy floor from 7.0 → 6.0 after observing Demon Slayer (Unreal
Shipping .bss, RWX, 405 MB) shows uniform entropy 6.651 across the
whole section. The decisive signal remains W+X-on-disk + ≥4 MB; the
entropy floor is now a sparse/zero guard, not a "looks encrypted"
test. A separate high-confidence label is logged when entropy ≥ 7.0.

Verified working end-to-end:
  Sonic Forces (637100)             — structural section, entropy 7.247
  Demon Slayer (1490890)            — structural section, entropy 6.651
  Suicide Squad: KTJL (315210)      — addprocess + forcedenuvo, env=0
Updated README.md to reflect new features and usage instructions.
Strict Denuvo titles validate a launch nonce that the static registry ticket
doesn't carry, so the DLL mints a fresh nonce-bound eticket from the backend.
Minting from an arbitrary pool account breaks the other half of Denuvo's
identity checks: GetSteamID and the IPC ownership ticket still point at the
account in the credential store while the eticket and network ownership ticket
point elsewhere, which surfaces as 88500012.

Thread the credential store's SteamID through FetchFreshEticket and
FetchOwnershipTicket as existingSteamId so the backend pins the mint to that
same account, and refuses outright when the ticket belongs to an account it
doesn't control (a real owner's own ticket, or one shared peer to peer).
Callers still fall back to the static credential-store ticket on any failure,
so titles that don't need this keep working unchanged.

Adds AppTicket::ExtractSteamIdFromTicketBytes so callers can identify a
ticket's owner without duplicating the layout offset.

Drops the seteticketurl Lua knob added in 42b7a7d: the mint endpoint is fixed,
and making it user-configurable was never useful.
092e90f hardcoded the mint URL. Fine for a private build, but it bakes one
deployment's backend into every binary, and an unauthenticated endpoint sitting
in plain sight in a public tree invites anyone who reads it to mint against that
deployment's pool accounts.

Resolve the URL in two steps instead:

  1. seteticketurl() in the Lua config, restored from 42b7a7d (runtime override)
  2. OST_ETICKET_URL, baked in at configure time:
       cmake -B build -DOST_ETICKET_URL="https://your-host/eticket"

Empty when neither is set, and EnsureFetched returns early on empty, so a stock
build never makes a network request and behaves exactly like upstream.

The compile-time default matters: a build that only honoured the Lua knob would
silently disable the feature for every existing install, since nothing writes
seteticketurl() into the shipped configs, and strict Denuvo titles would regress
to 88500012. With the define, an operator's DLL stays self-contained exactly as
it is today while the public source carries no endpoint at all.

Verified on rebuilt Release DLLs: without the define no endpoint string is
present; with it, only the configured URL appears.
- Clone steamclient64.dll into bin\diversion64.dll and load as client_hModule with graceful fallback
- Intercept LoadModuleWithPath in SteamUI to redirect steamclient64 to diversion module
- Add g_HooksInstalled atomic synchronization barrier between UI and client hooks
… false positives

- Switch ost-Injector to native Windows GUI subsystem (WIN32_EXECUTABLE) with wWinMain
- Remove ShowWindow(SW_HIDE) call that triggered malware heuristics
- Implement EnsureInteractiveConsole for dynamic console attachment in manual mode
- Add ost-Injector.rc and app.ico with full PE version metadata and icon
- Add standalone zero-dependency C# source Injector.cs and build_injector.bat
@mmxlyo mmxlyo closed this Sep 8, 2026
@mmxlyo
mmxlyo deleted the fix_action_tools_build branch September 8, 2026 07:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants