Skip to content

DllMain of a packed 32-bit DLL never returns (100% CPU) under Hangover's wowbox64 — reproduced on box64 0.4.2, 0.4.5 and a Nov-2024 build #4304

Description

@deltapath-eric

Summary

A packed/obfuscated 32-bit DLL never finishes DllMain(PROCESS_ATTACH) when running under
Hangover's box64 WoW64 backend (wowbox64.dll, box64cpu.dll in older Hangover). The thread
enters DllMain and never returns: ~100% CPU indefinitely, no further progress, no window.

It is not specific to Hangover: the same DLL also fails to initialize when box64 emulates a
complete x86_64 Wine (standalone box64 + Wine 11.0 with new-WoW64), which is a completely
different architecture. It reproduces across three box64 generations and also with the
interpreter (BOX64_DYNAREC=0), so I don't think it's codegen-only.

Environment

Device MANGMI Air X handheld — Qualcomm SM6115 (Snapdragon 662: 4x Cortex-A73 + 4x A53)
GPU Adreno 610, mesa 26.1.6 freedreno, GL 4.6 (device Vulkan is only 1.0)
OS ROCKNIX 20260820 (LibreELEC-derived), kernel 7.1.2 aarch64, glibc 2.41
Page size 4096
Display sway + Xwayland, Wine X11 driver

box64 versions tried, all via Hangover's prebuilt debian12_bookworm_arm64 tarballs:

Hangover box64 backend DLL name Result
9.22 (Nov 2024) version not printed by that build box64cpu.dll hang, c000001d ILLEGAL_INSTRUCTION
11.9 (upstream, May 2026) v0.4.2 wowbox64.dll hang, c0000094 INT_DIVIDE_BY_ZERO, flags=1
11.16 (mikugirls fork, Aug 2026) v0.4.5 wowbox64.dll hang, c000001d ILLEGAL_INSTRUCTION at pc=0x100fe9d9c

Also fails with standalone box64 emulating a full x86_64 Wine

To rule out Hangover's WoW64 shim, I ran the same game on a completely different stack:
ROCKNIX's own x86_64 Wine 11.0 executed entirely under box64 0.4.4 (new-WoW64 handling the
32-bit game). 32-bit cmd.exe works fine through it, so the stack is sound.

relocating ephinea.dll dynamic base 10000000 -> 76dd0000
process_attach (L"ephinea.dll",00000000) - START
MODULE_InitDLL (76DD0000 L"ephinea.dll",PROCESS_ATTACH,00000000) - CALL
MODULE_InitDLL (76DD0000 L"ephinea.dll",PROCESS_DETACH,00000000) - CALL
warn:module:process_attach Initialization of L"ephinea.dll" failed

Exceptions in that run: c000001d ILLEGAL_INSTRUCTION, 80000004 EXCEPTION_SINGLE_STEP,
c0000005 ACCESS_VIOLATION.

Timing detail that may be diagnostic: DllMain spins at ~100% CPU for 1-2 minutes before
failing (at t+1m the DLL is still mapped, no failure logged, CPU 101%; by t+2m the process has
exited). That is the same box64 0.4.4 which, used as Hangover's WoW64 backend, hangs in
DllMain indefinitely (verified over 10 minutes). Same engine and same DLL, but a different
integration produces a different endgame — which to me suggests exception delivery and
continuation semantics rather than instruction translation, though I may be wrong.

The single-step exception is probably the most useful clue in this report. A single-step
means the trap flag was set (or INT 1 executed). Combined with the deliberate divide-by-zero
and the illegal instruction seen in other runs, this looks like exception/trap-flag based
obfuscation: the packer raises faults on purpose and resumes from its own SEH handlers. If
box64's TF emulation or exception-continuation semantics differ from hardware, that would
explain both the hang (handler never resumes) and the crashes (resumed with wrong state).

The DLL

ephinea.dll from the Ephinea PSOBB client (free download, see repro below). 12.6 MB, clearly
packed:

  • a section named .banana (3.8 MB) plus several unnamed RWX sections
  • prefers base 0x10000000, has DYNAMIC_BASE so Wine relocates it (0x73300000 /
    0x74820000 / 0x73270000 in different runs)
  • Wine logs warn:module:alloc_module disabling no-exec because of L"ephinea.dll"

The host process is PsoBB.exe, a 32-bit PE which imports it.

What the failure looks like

trace:module:map_image_into_view relocating L"...\ephinea.dll" dynamic base 10000000 -> 73300000
warn:module:alloc_module disabling no-exec because of L"ephinea.dll"
trace:module:process_attach (L"ephinea.dll",00000000) - START
trace:module:MODULE_InitDLL (73300000 L"ephinea.dll",PROCESS_ATTACH,00000000) - CALL
trace:seh:dispatch_exception code=c0000094 (EXCEPTION_INT_DIVIDE_BY_ZERO) flags=1 addr=000000007A8CF894
   <no matching RETURN — ~100% CPU indefinitely>

The DLL is mapped (grep -c ephinea /proc/<pid>/maps = 1) but DllMain never completes.
Over a 10-minute run: 100% CPU on one thread, read_bytes advanced only ~11 KB, no window.

On box64 0.4.5 the exception becomes c000001d EXCEPTION_ILLEGAL_INSTRUCTION at
pc=0x100fe9d9c — above the 4 GB boundary, so not inside the DLL (mapped at 0x73270000).
If I'm reading that right it's in box64's own JIT region, but I may be misreading it.

Steps to reproduce

The client is a free download and the installer does not need to be run:

curl -O https://files.pioneer2.net/Ephinea_PSOBB_Installer.exe    # NSIS, ~855 MB
7z x Ephinea_PSOBB_Installer.exe -o/path/to/psobb
cd /path/to/psobb

export WINEPREFIX=~/.psobb-prefix
export WINEDLLOVERRIDES="mscoree=d;mshtml=d"
wine wineboot -u

# PSOBB only accepts 16-bit display modes; without this it exits before loading the DLL:
wine reg add 'HKCU\Software\Wine\X11 Driver' /v ScreenDepth /t REG_SZ /d 16 /f

HODLL=wowbox64.dll WINEDEBUG=+loaddll,+module,+seh \
  wine explorer /desktop=pso,1280x720 PsoBB.exe

Then watch for MODULE_InitDLL ... ephinea.dll ... PROCESS_ATTACH - CALL with no matching
return, and a process pinned at 100% CPU.

What I've ruled out

  • Not codegen alone: BOX64_DYNAREC=0 (interpreter) hangs identically.
  • Not dynarec tuning: BOX64_DYNAREC_SAFEFLAGS=2 BIGBLOCK=0 CALLRET=0 STRONGMEM=3 — still
    hangs. [BOX64] BOX64ENV: Variables overridden: confirms the variables were applied.
  • No missing opcodes reported: BOX64_DYNAREC_MISSING=1 printed none.
  • Not general 32-bit breakage: wine C:\windows\syswow64\cmd.exe /c echo hi works on all
    three versions, and the rest of this 32-bit game runs fine — it renders D3D8 through
    wined3d/GL, reaches its network login screen, and accepts input.
  • Not the Windows version: winecfg /v win7 and /v winxp behave identically.
  • Not fixed by newer box64: 0.4.2 -> 0.4.5 changes only the exception type.

Possibly relevant (second-hand)

The PSOBB community reports that standalone box64 0.2.6–0.2.9 boots this game under
Winlator (box64 + a full x86 Wine + box86), while newer versions do not:
https://www.pioneer2.net/community/threads/ephinea-pso-bb-natively-on-android-via-winlator.28655/

I have not verified that myself, and it's a different architecture from Hangover's WoW64 use of
box64, so it may be unrelated — but if it is the same underlying bug, that range might make it
bisectable.

Speculation, flagged as such

box64 0.4.2 reports the divide-by-zero with flags=1 (EXCEPTION_NONCONTINUABLE). Packers
commonly use exception-based control flow — raise a deliberate fault, catch it in SEH, resume —
so I wondered whether a continuable guest exception is reaching the handler as non-continuable,
which would explain a hang. I have not verified this, and 0.4.5's illegal-instruction symptom
doesn't fit it neatly.

FEX (Hangover's other backend) fails differently on the same DLL: EXCEPTION_ACCESS_VIOLATION
inside the DLL's own range, at a nearly identical address on two versions (0x779CD33C and
0x7790D33C), after which Wine logs Initialization of ephinea.dll failed and the app
continues without the DLL.

Happy to help

The device has SSH access and I can run any env vars, log levels, or patched builds and report
back. If there's a preferred way to capture a useful trace of the hang (BOX64_LOG=2, dynarec
dumps, etc.), tell me what would help most and I'll produce it. I can also try building a
minimal 32-bit PE that raises a continuable divide-by-zero, catches it in __try/__except and
resumes, if a small repro would be more useful than an 855 MB game.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions