May 252020
 
Shoujo City logo

0. Introduction

Alright, first things first: If you a.) don’t like Anime-like games and b.) you don’t like Yuri (love between girls), you can likely stop reading here. That is unless you’re just interested in the technical part of this. Note: This article does not deal with getting Valve Steam to run on XP, which is a requirement though. For that, see [this article].

Like so often before, a [promotion] on the Yuri Empire made me buy another game, this time it’s “Shoujo City”. Not your usual (?) visual novel, but a 3D game also available for Google Android. I strongly dislike playing games on my smartphone, but now that it’s been officially released, I took a look at the PC version. In recent times, backporting Unity3D games to XP has become harder and harder, with really problematic Mono assembly dependencies and mostly the Direct3D 11 renderer, which is now the default for Unity on Windows. Mind you, OpenGL is still an option (and it can do modern D3D11-like stuff on XP, given new enough graphics card drivers), but in the Windows context, most developers simply don’t care and just use the defaults. But not all of them do.

Well, let us start with this pretty nasty backport hack!

1. Required software

The following software is required to apply the hack:

2. Analysis

Ok, first, let’s look at why the game isn’t working on Windows XP as-is. For this, we’ll take a look at it with CFF Explorer and Dependency Walker, just open ShoujoCity.exe in those programs:

ShoujoCity.exe in CFF Explorer

ShoujoCity.exe in CFF Explorer

Take a look at the fields MajorSubsystemVersion and MinorSubsystemVersion. Those are set to 6 and 0 respectively, which corresponds to the required kernel version: Windows NT 6.0, or in other words, Windows Vista. This will need resetting to 5.1. We won’t do that within CFF Explorer though, as Oleg’s Stellaris WinXP fix can handle that amongst other things. Without this, you’d see the “Not a valid Win32 application” error upon launch. Now, as for that dependency walk…

ShoujoCity.exe in Dependency Walker: This is the usual

ShoujoCity.exe in Dependency Walker: This is the usual stuff I came to expect

Alright, this is typical for a game made with a Unity engine in version 2018.4.22f1. InitializeCriticalSectionEx() and GetTickCount64() are things that Oleg’s fix could handle already when I first found it on the web many years ago. So, not an issue. The bcrypt.dll dependency is something Drako Pensulo has resolved, even if only for 32-bit programs. Luckily, Shoujo City is one such program.

But there is more:

The unusual: dwmapi.dll with DwmGetWindowAttribute()

The unusual: dwmapi.dll with function call DwmGetWindowAttribute()

Now this one is new! The game appears to be calling a Desktop Window Manager function here. That DWM stuff is something that doesn’t exist on XP, you’d need Windows Vista or newer for this. With this it’s getting interesting, as I’ve never handled this one before. I have of course immediately nagged Oleg about it, as he’s frequenting my IRC server (please don’t run away, ;) ), and he suggested ways to analyze, debug and properly resolve this by using legacy functions within a stub DLL. This is quite hard (for me) though, because C++.

But more on that later, as with this, the analysis phase is complete. We need to fix the PE32 header (the stuff in the first screenshot), give the game a modern cryptographic implementation in the form of bcrypt.dll, and fix the missing calls IntializeCriticalSectionEx(), GetTickCount64() and DwmGetWindowAttribute(), of which the latter should prove to be the most challenging.

Let’s get to it!

3. Fixing Shoujo City to work on XP

3a. BCRYPT

First, unpack the file ShoujoCity-DrakoPensulos-bcrypt.dll.7z that you downloaded in section 1 of this post with 7-Zip. Copy the resulting files Kernel35.dll and bcrypt.dll to the game directory. That’s the one where ShoujoCity.exe also resides. This will take care of the dependency on Microsoft’s modern cryptographic API.

3b. The Stellaris WinXP fix

Now, unpack Stellaris-WinXP-fix-for-ShoujoCity.7z, and from the game folder, copy the files ShoujoCity.exe and UnityPlayer.dll to the folder where you unpacked the Stellaris WinXP fix, so it looks like this:

Stellaris fix, file list

Stellaris fix, file list

Next, you’re going to have to double-click the batch script xp_ShoujoCity.bat to patch the necessary functionality into those two files. First, let’s review its source code though:

@ECHO OFF
rundll32.exe zernel32.dll,PatchFile ShoujoCity.exe
rundll32.exe zernel32.dll,PatchFile UnityPlayer.dll

Nothing out of the ordinary there, it’ll just patch the files with our stub DLL that will extend the Windows kernel API (and more) by a few functions. Also, it will modify the PE32 header of those binary programs to be XP-compatible. This takes care of the NT 6.0 requirement and of the function calls to InitializeCriticalSectionEx() and GetTickCount64().

So, double-click it, and wait for the following two messages:

 

The patch will create backup copies of those files with a .bak extension, but still, before the copy-back, rename the two files in the actual game directory to something else, e.g. ShoujoCity.exe-STOCK & UnityPlayer.dll-STOCK or something similar.

Then, from the Stellaris WinXP fix directory, copy the following files back to the game directory: ShoujoCity.exe, UnityPlayer.dll, zernel32.dll, zdvapi32.dll & zs2_32.dll. If you’ve read some of my other XP backport articles, you may wonder why the D3D stub DLLs are not required in this case. Well, simple: This game thankfully doesn’t use Direct3D – it’s using OpenGL instead! Yay for free software!

We aren’t done yet though!

3c. That DWM stuff

Now, as said, Oleg Ovcharenko went to certain lengths to show me how to do this properly, but the stupid, lazy derp that I am, I did something.. quite unseemly instead. Now, we do know the code imports dwmapi.dll at load-time (so, when the program starts), and it appears to be calling DwmGetWindowAttribute() from it. Buuut, do we, like, really need it? In my attempt to work around having to do actually challenging things, I thought I’d just try to do the reverse of [what we did to Nekopara Extra] using the tool IIDKing. With IIDKing we added a load-time DLL and some of its function calls to the game, so that it would be able to locate them.

But the opposite, ripping them out of a program the hard way is possible as well… even if this is extremely dirty and really, really bad. For this, launch CFF Explorer again, and load the offending UnityPlayer.dll within the game directory. The one that is now patched with the Stellaris WinXP fix. Then, click on “Import Directory” in the list on the left. This will open the load-time import table of the program. Scroll down and locate dwmapi.dll:

"Reverse-IIDKinging" UnityPlayer.dll to remove a load-time DLL dependency

“Reverse-IIDKinging” UnityPlayer.dll to remove a load-time DLL dependency

Now, do something really hideous: Right-click it, and click “Delete Import Descriptor”. This will forcefully tear out the load-time import of that DLL and all of its functions from the PE32 header of the file. In essence, at least as far as I think I understand it, you’re breaking something that the linker did in the final stages after compiling the game. Typically, you should never, ever do something like this. This is all in the blind hope that the game would not really need this functionality, or that it would silently ignore whatever crap is happening by it just “not being there”.

But hey, I’m lazy, so… yeah, why not try it? After having committed this crime, save and overwrite the DLL. You’re now officially a software vandal.

With this, let’s get to the finale!

4. Running the game

Note that there are differences between the demo and release versions of this game when it comes to how the hack needs to be applied exactly. Well, not the hack itself actually, but the stuff that follows now.

Unpack or install Sizer now. Launch it, and keep it running. You should see the sizer icon in your system tray now. If yours is compacted, expand it. The icon looks like this:

Sizer icon

Sizer icon

Before launching the game, you should decide whether you want to run it in a window or in full screen. In any case, you will probably want to decide what resolution to run the game in. Why? That’ll be explained below, as this peculiarity is a part of why this hack is such an abomination. ;)

If you want to run it in full screen, but you don’t know your monitor’s resolution, let me show you how to determine that – the freaky way. Hit the key combination Alt+r and type cmd.exe, then hit Enter in the following window to launch a command line terminal:

Launch the Windows terminal

Launch the Windows terminal

When the terminal is open, run the following, rather lengthy Windows Management Instrumentation command, which should work on all versions of MS Windows, at least from XP onwards: wmic path Win32_VideoController get CurrentHorizontalResolution,CurrentVerticalResolution:

Getting the current screen resolution from the command line

Getting the current screen resolution from the command line

So, in my case it’s 2560×1600. Right click on the Sizer icon in the tray and pick “Configure Sizer…”. Then click “Add” and add your custom resolution, like this:

Sizer configuration

Sizer configuration

Click “OK” to confirm it. Mind you, if you want to run the game in windowed mode, just enter your desired window resolution here, but mind the aspect ratio! Might wanna keep it at 16:9! And – of course – smaller than your monitor’s native resolution.

Now, there is one obvious question here: Why?

Launch the game to learn the reason. Not by double-clicking ShoujoCity.exe though, that won’t really work (it’ll seem like it does, but it’ll terminate after the Unity Engine splash screen). Launch it directly from within Steam. You should be seeing this:

Shoujo City launcher

Shoujo City launcher – can you guess what’s wrong here?

As you can see, there is no screen resolution. Like.. none. If you click on that drop-down, the list will be empty. So this is what happens when you rip out the Desktop Window Manager functionality from it, heh.

If you launch it as-is by clicking on “Play!”, it may run in fullscreen, but the resolution might be horribly wrong or even square. Yes, square. Stuff happens.

Anyway, if it’s in fullscreen mode, wait for the game’s main menu to appear and then hit the key combination Alt+Enter to force it back into windowed mode. When that’s done, with Sizer still loaded, right-click on the title bar, and force it into the desired resolution:

Force a resolution on Shoujo City with Sizer

Force a resolution on Shoujo City with Sizer (Here, it’s still defaults, no 2560×1600 added yet)

If you want to play in fullscreen, set the now-configured native screen resolution of your monitor here and hit Alt+Enter again to switch back to actual fullscreen mode. Otherwise, keep it windowed at the resolution you desire. It’ll work from here on out:

Shoujo City running on Windows XP

Shoujo City running on Windows XP. Much Yuri. Such legacy. Wow.

Now, let me conclude this horror with a quote from Oleg Ovcharenko, as posted today on IRC in a reaction to what I had just done:

I wish every game could be ported
with such [an] act of vandalism!
     -Oleg Ovcharenko

Well, there you have it! Cheers! Beer Smilie

CC BY-NC-SA 4.0 How to make Shoujo City run on Windows XP (ugliest backport so far…) © 2020 by The GAT at XIN.at is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

  2 Responses to “How to make Shoujo City run on Windows XP (ugliest backport so far…)”

  1. hello,
    can you show how to make games with unity to run in windows 7? it seems that the problem comes from the unityplayer.dll

    • Hello thx,

      I have very little experience with Windows 7, but the basic answer would be “it depends”.

      If it’s only the PE32 / PE64 header that specifies e.g. Windows NT 10.0, then that is super-easy to fix. Change the 10 to a 6 in CFF Explorer, save the file, done. See point “2. Analysis”.

      If you’re unlucky, then UnityPlayer.dll may pull in functionality only present in Windows 10 / 11 systems. This part can easily require C++ programming skills.

      You would scan the program using Dependency Walker to find loadtime dependencies. In the worst cases, there are runtime dependencies as well; Use “Profile / Start Profiling…” to look for them as the target program is being launched and function calls traced by dependency walker.

      But this leaves you with the biggest problem: You must now read the documentation of the missing functions to learn what they do. And then, either you redirect the calls to replacement functions that Windows 7 already has (rarely possible), ooor you have to program the functions yourself, compile them into a .dll file and hook the .dll into your .exe.

      Say your new stub library is called zernel32.dll and is meant as a wrapper over the real kernel32.dll. Let’s say it contains the function InitialCriticalSectionEx(), that you need and hence wrote yourself. That library must redirect all other kernel32 API calls to the real kernel32.dll, implementing only the missing function InitialCriticalSectionEx(). The redirectional part is handled by #pragma code.

      To hook your little wrapper in, you place it next to the .exe file, open the .exe in a hex editor and change all KERNEL32.dll lines to ZERNEL32.dll (your stub library), then save the file.

      You might need to find yourself a capable C++ developer (=> not me, I suck).

 Leave a Reply

CC BY-NC-SA 4.0 logo GPLv3 logo All text and images/files you post here will be implicitly licensed under the free [CC BY-NC-SA 4.0] license, and all source code you post will be implicitly licensed under the free [GNU General Public License version 3.0] unless explicity stated otherwise by yourself in your comment!

Warning 1: This site runs very modern software on an [ancient server] with four Pentium II Overdrive 333MHz CPUs. It's really slow when handling comments! Please click on "Submit Comment" only once! Do not click repeatedly, or the spambot detection system may ban you! Even if you land on a "white page of death" or receive a timeout, do not re-send your comment, it'll likely still have gone through. Consider re-sending it only if I haven't approved it within a few days. Check the newest post on this weblog to make sure I'm not on vacation or something, increasing the time it'd take for me to approve comments.

Warning 2: This site uses [Akismet] to reduce spam. The following parts of your comment data need to be shared with its operator, [Automattic]: IP, nick name, eMail, user agent, referrer, URL and the comments' content. [Learn how your comment data is processed].

Note: Your eMail address will not be published!

You may use these HTML tags and attributes: <em>⋯</em> <i>⋯</i> <b>⋯</b> <s>⋯</s> <u>⋯</u> <sub>⋯</sub> <sup>⋯</sup> <strike>⋯</strike> <strong>⋯</strong> <p style="">⋯</p> <code>⋯</code> <pre lang="" line="" escaped="">⋯</pre> <a href="" title="">⋯</a> <abbr title="">⋯</abbr> <acronym title="">⋯</acronym> <blockquote cite="">⋯</blockquote> <cite>⋯</cite> <q cite="">⋯</q> <span style="">⋯</span>. You may also use the [spoiler][/spoiler] shortcode to insert spoilers.

(required)

(required)