Skip to content

feat(AscNativeLogon): native reconstruction of Ascension's own logon protocol (build-gated) - #13

Merged
firstoni-dev merged 3 commits into
firstoni-dev:mainfrom
CoinThrow:native-logon
Oct 12, 2026
Merged

firstoni-dev merged 3 commits into
firstoni-dev:mainfrom
CoinThrow:native-logon

Conversation

@CoinThrow

@CoinThrow CoinThrow commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Summary

A native, build-gated reconstruction of Ascension's own logon protocol — the client side of the
handshake the genuine DLL installs by hot-patching three exe thunks. It lets the client speak that
protocol against a server that implements it (the feature/ascension-native-login branch of an
AzerothCore CoA fork), with no runtime byte-patching — everything ships inside the DLL, behind a
build option that defaults to OFF.

What's in the branch

  • src/Ascension/AscNativeLogon.cpp / .hpp — the protocol module (crypto self-test, three thunk
    replacements, four length gates).
  • tools/ascension-auth-keygen.ps1 — X25519 key-pair generator (RFC 7748 self-test included).
  • CMakeLists.txt + PatchConfig.hpp.in — -DASCENSION_NATIVE_LOGON=ON (default OFF) and
    -DASCENSION_NATIVE_LOGON_SERVER_KEY=<64 hex> (the server's public key / KC1 slot value).
  • src/Ascension/AscMain.cpp — DllMain install call, option-gated.
  • README + DLL_REFERENCE — build section, live-validation record, and the server requirement found
    during validation.

What it installs (only with the option ON)

site stock behaviour reconstruction
0x8CCE00 hello serializer appends the custom hello record verified live: [size][FC F4 F4 E6][tag16][masked payload][trailer]; payload carries login, X25519 public key, nonce, password tag, ChaCha20-encrypted password
0x9A83E0 SRP6 K from challenge copies the 40-byte key_session into the auth object (lands at auth-context+0xC8)
0x9A88C0 SRP6 M2 compare verifies the 32-byte HMAC-SHA256(key_derived, "OK")
0x8CC7FA, 0x8CC856, 0xDFC024, 0xDFC034 0x14-byte proof field length gates to 0x20 so the reply handler reads the 32-byte proof

Crypto (byte-exact copies of the live-verified values): X25519(secret, server public) → HMAC-SHA256
KDF → key_derived (32B) / key_session (40B); ChaCha20 record + password encryption; HMAC proof.
The module runs a crypto self-test first and refuses to install on failure.

Verification (2026-10-10, live end-to-end)

Against a server with the custom auth toggle on and the matching key pair:

  • client: native-logon: proof check PASSED (HMAC-SHA256(key_derived, "OK"))
  • server: Ascension custom auth: proof replied, session authorised
  • client: COP_AUTHENTICATE ... AUTH_OK → COP_GET_CHARACTERS ... result=TRUE → character list rendered
  • world handoff completed after the server-side fix below; no client-side patches involved

Server requirement found during validation

After the custom proof, the authserver must persist the handshake's 40-byte key_session as
account.session_key — the worldserver's CMSG_AUTH_SESSION digest and header cipher depend on it,
and without it the client drops right after auth. That fix lives on the server branch
(AuthSession.cpp, Ascension client branch), not in this PR.

Build / try it

cmake -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DASCENSION_NATIVE_LOGON=ON ^
      -DASCENSION_NATIVE_LOGON_SERVER_KEY=<64 hex chars> -S . -B build\nl
cmake --build build\nl

Run the client with -extlog 1 and watch Logs\Extensions.log for the native-logon: lines.

Deliberate limits (test/translation build, not a match for the obfuscated original)

  • No device fingerprinting. The original's hello derivation mixes unique machine identifiers into
    the handshake — the NVMe disk serial (Win32_DiskDrive.SerialNumber) and a CPUID.1 snapshot — via
    its token pipeline. This reconstruction deliberately does not reproduce them: the module
    collects no device data (no disk, CPUID or SMBIOS queries anywhere in it), and every
    per-connection field — the 16-byte record tag, the 12-byte nonce, the 16-byte password tag —
    carries fresh rand_s randomness, matching the original's measured per-connection RNG behaviour
    for the tag and password tag. The server treats these fields as opaque, as the live validation
    shows.
  • Record-constant fields (platform, locale, timezone bias, IP) are the verified reference values; the
    server does not read them.
  • The stock SRP6 fallbacks on the patched sites are not kept when the option is ON — it is installed
    only for servers that speak the custom handshake.
  • Option OFF (the default): nothing is compiled in; behaviour is exactly as before (SRP6 restore,
    hooks not installed).

Stacking note: this branch currently sits on the callback-order line (#12). Once #12 lands, the diff
here narrows to the single logon commit; I can rebase on request.

…ed order

Aura application, effect filtering and visual hiding still inserted by call site, which does not reproduce the original: registration execution order does not follow the call sites (the aura list registers AscSpellMods before AscSpellVisuals, AscSpawnVisibility before AscAppearance).

Measured the three lists from the original's live list links in two independent game sessions; they now rank by the captured site order (InsertByCapturedOrder), like the two lists added earlier. The aura-application list carries one original-only sixth callback (runtime-registered, no static call site, not reconstructed) that runs after the five captured entries.

Fixture, portable test (all registration permutations, vetoes, duplicates, an off-array unknown site, visual-hide consumer short-circuit) and docs/CALLBACK-ORDER-MEASURED.md extended; 3367 checks, 0 failures locally.
…protocol (build-gated)

AscNativeLogon.cpp/.hpp installs the original DLL's three logon hooks (0x8CCE00, 0x9A83E0, 0x9A88C0) and the four handshake length gates (0x14 -> 0x20), replacing stock SRP6 with X25519 + ChaCha20 + HMAC-SHA256. Compiled only with -DASCENSION_NATIVE_LOGON=ON; the default stays SRP6-restore.

tools/ascension-auth-keygen.ps1: X25519 key pair tool (RFC 7748 self-test plus the project's live-test pair).

README/docs: native-logon build section, the 2026-10-10 live-validation record (proof check PASSED -> COP_AUTHENTICATE AUTH_OK -> COP_GET_CHARACTERS result=TRUE) and the server requirement found during it (authserver must persist key_session as account.session_key for the world handoff).
@firstoni-dev
firstoni-dev merged commit 0cc6f56 into firstoni-dev:main Oct 12, 2026
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.

2 participants