200 lines
No EOL
8.7 KiB
Markdown
200 lines
No EOL
8.7 KiB
Markdown
# Japanese No Remorse Windows 9x Investigation
|
|
|
|
## Question
|
|
|
|
Investigate the claim that the Japanese build of Crusader: No Remorse supports Windows 9x and can run natively on Windows 95 instead of requiring a DOS boot path.
|
|
|
|
Active Ghidra target for this note: `/ja/CRUSADER.EXE`.
|
|
|
|
## Verdict
|
|
|
|
Current static-analysis verdict: **strongly supports the claim**.
|
|
|
|
The loaded Japanese executable is not just a DOS executable with a small helper around it. It is a native flat Win32 image with Windows API startup, Windows registry configuration, DirectDraw/DirectSound initialization, and one explicit Win9x-aware compatibility branch.
|
|
|
|
What is proven from static analysis:
|
|
|
|
- the Japanese binary is a PE-style Win32 program loaded at `00400000`, with sections such as `BEGTEXT`, `DGROUP`, `.idata`, `.reloc`, and `.rsrc`
|
|
- it creates a real top-level Windows game window and runs through Win32 startup code
|
|
- it initializes DirectDraw and DirectSound directly
|
|
- it reads and writes settings in the Windows registry
|
|
- it contains Japanese/Win9x-facing support clues, including IME handling and a `GetVersion`-based compatibility branch
|
|
|
|
What is **not** proven by this pass:
|
|
|
|
- an actual runtime launch on real Windows 95 hardware or emulation
|
|
- whether extra runtime prerequisites such as the expected DirectX version are always present on a bare Windows 95 install
|
|
- whether every shipped JP build variant behaves the same way
|
|
|
|
So the safest wording is:
|
|
|
|
> The claim that the Japanese release has a native Windows 9x execution path is strongly supported by the code. The stricter claim that it will always run on a stock Windows 95 machine without additional runtime requirements is not fully closed by static analysis alone.
|
|
|
|
## Main Evidence
|
|
|
|
### 1. The loaded JP executable is a Win32 image, not the old DOS/NE game binary
|
|
|
|
Ghidra reports the active program as `/ja/CRUSADER.EXE` with entry at `004729e0`.
|
|
|
|
Relevant image layout recovered from Ghidra:
|
|
|
|
- `Headers: 00400000 - 004003ff`
|
|
- `BEGTEXT: 00401000 - 0047afff`
|
|
- `DGROUP: 0047b000 - 00481bff`
|
|
- `.bss: 00482000 - 00495fff`
|
|
- `.idata: 00496000 - 00496dff`
|
|
- `.reloc: 00497000 - 0049e3ff`
|
|
- `.rsrc: 0049f000 - 004a03ff`
|
|
|
|
That is a normal PE/Win32 layout, not the segmented NE or DOS-extender layout used by the original DOS executable.
|
|
|
|
### 2. The import table is decisively Windows-native
|
|
|
|
Recovered imports include all the major Windows subsystems expected of a native Win9x game executable:
|
|
|
|
- process and OS: `GetVersion`, `CreateThread`, `ExitProcess`, `TlsAlloc`, `VirtualAlloc`, `GetCommandLineA`, `GetModuleHandleA`, `GetModuleFileNameA`
|
|
- window/UI: `CreateWindowExA`, `RegisterClassA`, `DefWindowProcA`, `DispatchMessageA`, `PeekMessageA`, `ShowWindow`, `RegisterWindowMessageA`, `MessageBoxA`
|
|
- graphics: `DirectDrawCreate`, `CreateBitmap`, `CreateCompatibleDC`, `CreatePalette`, `TextOutA`
|
|
- audio/timing/input: `DirectSoundCreate`, `DirectSoundEnumerateA/W`, `timeGetTime`, `joyGetDevCapsA`, `joyGetPosEx`
|
|
- configuration/storage: `RegCreateKeyExA`, `RegOpenKeyExA`, `RegQueryValueExA`, `RegSetValueExA`, `CreateFileA`, `ReadFile`, `WriteFile`
|
|
- Japanese text/input support: `IsDBCSLeadByte`, `GetCPInfo`, `WINNLSEnableIME`
|
|
|
|
This is not a DOS launcher plus one or two helper calls. It is a full Windows application stack.
|
|
|
|
### 3. The main window path is explicit and native
|
|
|
|
`00445f40` is now named `win32_create_main_window`.
|
|
|
|
Key behavior recovered from decompilation:
|
|
|
|
- registers a window class with `RegisterClassA`
|
|
- creates a fullscreen popup window with `CreateWindowExA`
|
|
- uses the title string `"Crusader: No Remorse"`
|
|
- calls `ShowWindow(..., 10)`
|
|
- calls `WINNLSEnableIME(0,0)` immediately after successful creation
|
|
- registers `"MSWHEEL_ROLLMSG"`
|
|
|
|
This is direct evidence of a native Windows UI path. The IME call is especially relevant in a Japanese build because it shows the executable is consciously managing Windows-side JP text/input behavior.
|
|
|
|
### 4. DirectDraw and DirectSound are initialized directly by the game
|
|
|
|
`004459b0` is now named `video_init_directdraw_and_directsound`.
|
|
|
|
Recovered behavior:
|
|
|
|
- calls `DirectDrawCreate()`
|
|
- sets cooperative level and display mode on the DirectDraw object
|
|
- creates the palette and primary surface
|
|
- calls `DirectSoundCreate()`
|
|
- hides the cursor with `ShowCursor(0)`
|
|
|
|
This is a classic Windows 9x era DirectX setup path. It strongly supports the idea that this build was intended to run as a native Windows game executable.
|
|
|
|
### 5. Registry-backed configuration is built in
|
|
|
|
String at `0047b178`:
|
|
|
|
- `Software\Electronic Arts\Crusader: No Remorse\J1.21`
|
|
|
|
`004138e8` is now named `config_load_registry_and_cfg`.
|
|
|
|
Recovered behavior:
|
|
|
|
- reads `installpath`, `cdpath`, and `flicpath` from `HKEY_LOCAL_MACHINE`
|
|
- reads user preferences such as `video`, `subtitles`, `limitblasts`, `animation`, `frameskip`, `musicvolume`, `soundvolume`, and `mousespeed` from `HKEY_CURRENT_USER`
|
|
- falls back to parsing `crusader.cfg`
|
|
|
|
`00413760` is now named `config_write_registry_string` and writes string values back into the same registry branch.
|
|
|
|
This is strong evidence of a normal Windows-installed configuration model rather than a DOS-only setup flow.
|
|
|
|
### 6. There is a real Win9x-specific compatibility branch
|
|
|
|
`00472c41` is now named `win32_runtime_capture_process_context`.
|
|
|
|
Recovered behavior:
|
|
|
|
- captures environment strings
|
|
- captures module filename and command line
|
|
- calls `GetVersion()`
|
|
- stores split version fields into globals at `0x47c09f`, `0x47c0a0`, and `0x47c0a1`
|
|
|
|
The more important follow-up is `00476616`, now named `win32_tls_alloc_with_win9x_guard`.
|
|
|
|
Recovered behavior:
|
|
|
|
- calls `TlsAlloc()`
|
|
- checks the saved `GetVersion()` word
|
|
- if the version word has the high `0x8000` bit set, it retries while the TLS slot is less than `3`
|
|
|
|
That is not generic Windows code. It is exactly the kind of branch you expect when a program needs to behave differently on the Win9x line, where `GetVersion()` reports the platform using the high bit and some low TLS slots are treated specially.
|
|
|
|
This is the strongest single code-level clue that the executable was designed with Win9x behavior in mind, not just NT-family Windows.
|
|
|
|
## Secondary Evidence
|
|
|
|
### Japanese-specific Windows integration
|
|
|
|
The import set and main-window path together show several JP-specific Windows integration points:
|
|
|
|
- `WINNLSEnableIME`
|
|
- `IsDBCSLeadByte`
|
|
- `GetCPInfo`
|
|
|
|
That does not by itself prove Windows 95 compatibility, but it does reinforce that this is a localized Windows build, not a DOS build being loosely wrapped.
|
|
|
|
### WinMM and joystick APIs
|
|
|
|
The import table also includes:
|
|
|
|
- `joyGetDevCapsA`
|
|
- `joyGetPosEx`
|
|
- `timeGetTime`
|
|
|
|
These are ordinary Windows multimedia/input APIs and fit the same native-executable picture.
|
|
|
|
## Interpretation
|
|
|
|
The claim can be split into two parts.
|
|
|
|
### Part A: "The Japanese version supports Windows 9x"
|
|
|
|
This is strongly supported.
|
|
|
|
The binary:
|
|
|
|
- is a Win32 image
|
|
- uses Win32 startup and window management
|
|
- uses DirectX-era Windows multimedia APIs
|
|
- uses Windows registry storage
|
|
- has a `GetVersion` branch that specifically distinguishes Win9x-style version reporting
|
|
|
|
### Part B: "It can run on Windows 95 natively without switching to DOS first"
|
|
|
|
This is also strongly supported, but with one caveat.
|
|
|
|
The executable is clearly built to run as a native Windows application, and the version/TLS branch is the best evidence that Win9x behavior was considered explicitly. The remaining uncertainty is practical, not architectural: an actual Windows 95 runtime may still need the expected DirectX/runtime environment installed.
|
|
|
|
So the architectural answer is yes; the deployment answer is very likely yes, but not fully closed until runtime-tested on a Win95 environment.
|
|
|
|
## Ghidra Changes Made During This Pass
|
|
|
|
Renamed and commented in the active `/ja/CRUSADER.EXE` database:
|
|
|
|
- `00472c41` -> `win32_runtime_capture_process_context`
|
|
- `00476616` -> `win32_tls_alloc_with_win9x_guard`
|
|
- `00445f40` -> `win32_create_main_window`
|
|
- `004459b0` -> `video_init_directdraw_and_directsound`
|
|
- `004138e8` -> `config_load_registry_and_cfg`
|
|
- `00413760` -> `config_write_registry_string`
|
|
|
|
Each of those now has a decompiler comment explaining why it matters to the Win9x/native-Windows investigation.
|
|
|
|
## Remaining Follow-Up
|
|
|
|
1. Run the JP executable under an actual Windows 95 target or a faithful Win95 VM to confirm runtime behavior.
|
|
2. Identify the expected DirectX version from installer files or runtime error strings.
|
|
3. Trace the message pump and main game loop entry after window creation for a fuller WinMain reconstruction.
|
|
4. Locate the import thunks or callsites for `GetCPInfo` and `IsDBCSLeadByte` to document the JP text path more precisely.
|
|
5. Check whether the JP installer writes the same `J1.21` registry branch or whether the executable can self-heal missing keys.
|
|
6. Compare the JP Windows binary against the English DOS binary to isolate which subsystems were ported versus shared. |