Conversation
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.
…le runtime paths
… RE Engine sections
…ate multi-language docs for portable mode
- 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
…r in Hooks_SteamUI
… 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
… compatibility under Diversion
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.