atom0s / Steamless

Steamless is a DRM remover of the SteamStub variants. The goal of Steamless is to make a single solution for unpacking all Steam DRM-packed files. Steamless aims to support as many games as possible.
Other
3.08k stars 195 forks source link

RPGVX ends up broken #101

Open Ruchian opened 1 year ago

Ruchian commented 1 year ago

Got an issue related to https://github.com/atom0s/Steamless/issues/16 When using Steamless on RPGVX.exe, it seems to completely break the exe.

Your software works seemingly correctly on the file when enabling the experimental features only. However, upon trying to run the now unpacked exe file within the installation directory of the original file, this unpacked file appears to be broken. You receive the following error message: Unknown software exception 0xc0000096 in the executable on location 0x00401005 The program stopped working. This error shows up the moment you launch the unpacked exe.

Since the software package containing this exe hasn't been updated for years, the file in the zip file provided in issue number 16 is still the latest and thus valid.

Disclaimer: I'm running windows 8.1, a system Valve decided to prevent the Steam Client from running at the end of the year. I realize that this software isn't intended for use by a customer who has a legitly bought copy, but this situation is a bit rediculous in my opinion. Hense I was looking for alternatives on how I could keep some of the stuff I bought without needing to buy it a second time, or something like that. Anyway, as such I was hoping it would work properly, but unfortunately it doesn't.

I was wondering if you could take a look at why this happens, since I have no clue. Thanks in advance.

Associated steam id: https://steamdb.info/app/521880/

atom0s commented 1 year ago

Hello there, I don't own this game so it's a bit rough to fully debug this title with just the exe. However, I do believe I have found the issue but at this time I am not able to fix it within Steamless. (Really busy IRL and with other projects.)

The issue stems from how this variant of SteamStub is handling the stolen bytes that are reused to build and decrypt the .text section.

The section will land up starting at 0x00401000 when the executable is running which this title makes use of as an expected function within the main window class vtable:

.rdata:0059799C ; const CRPGVXApp::`vftable'
.rdata:0059799C ??_7CRPGVXApp@@6B@ dd offset sub_4E148E ; DATA XREF: sub_401020+16↑o
.rdata:0059799C                                         ; sub_4010F0+2B↑o
.rdata:005979A0                 dd offset sub_403210
.rdata:005979A4                 dd offset unknown_libname_124 ; Microsoft VisualC 2-14/net runtime
.rdata:005979A4                                         ; MFC 3.1-14.0 32bit
.rdata:005979A8                 dd offset ?OnCmdMsg@CCmdTarget@@UAEHIHPAXPAUAFX_CMDHANDLERINFO@@@Z ; CCmdTarget::OnCmdMsg(uint,int,void *,AFX_CMDHANDLERINFO *)
.rdata:005979AC                 dd offset ?OnFinalRelease@CCmdTarget@@UAEXXZ ; CCmdTarget::OnFinalRelease(void)
.rdata:005979B0                 dd offset sub_4FA44D
.rdata:005979B4                 dd offset sub_4E253C
.rdata:005979B8                 dd offset sub_4FDFA3
.rdata:005979BC                 dd offset sub_4FDFA3
.rdata:005979C0                 dd offset ?GetTypeLib@CCmdTarget@@UAEJKPAPAUITypeLib@@@Z ; CCmdTarget::GetTypeLib(ulong,ITypeLib * *)
.rdata:005979C4                 dd offset dword_401000 <-- this is broken

Due the stole bytes not being restored and decrypted properly, that function is instead incorrect:

.text:00401000 dword_401000    dd 0E8B858BFh, 0E883FA9Ah, 0E593BA1Ch, 0CCE27C10h, 6CC0B537h
.text:00401000                                         ; DATA XREF: HEADER:00400134↑o
.text:00401000                                         ; HEADER:0040020C↑o ...
.text:00401000                 dd 2732FFEh, 77D7E702h, 34DD8E31h

In the meantime, you can manually fix this file by doing the following:

Next, run the game normally through Steam as you would. (Don't use the unpacked file, use the legit game files.) You will then need a memory editor like Cheat Engine for the next step.

You should then see the proper values for the first 16 to 32 bytes here that need to be put into the unpacked file via a hex editor. You will want to copy the bytes from 0x00401000 to 0x00401020.

In a hex editor, open the unpacked RPGVX.exe and within the hex editor, use its feature to go to a file offset. Go to the file offset: 0x0400

Here you will want to overwrite the data with the data you just copied from Cheat Engine. Be sure you are in overwrite mode in the hex editor and not insert mode. You DO NOT want to add extra junk to the file, you want to overwrite what is already there with the valid data/values.

Afterward, save the unpacked exe you just edited and try running it again.

atom0s commented 1 year ago

Alright so scratch what I said above about manually fixing the file. That was wrong as I didn't have the time earlier to really look at it better. I had time to look again tonight and the game is also on sale for a few dollars so I bought it to take a closer look.

The current 2.1 unpacker is currently handling this file wrong in multiple places. With the lack of 2.1 variant files, it makes it hard to determine what differences are across each version. But for now, this will require a handful of changes to fully fix properly.

Some of the things wrong at the moment:

I need to take a look at some other 2.1 samples I have to compare notes and see if things need to be broken into separate unpackers.

Ruchian commented 1 year ago

I found two other pieces of software packed with SteamStub 2.1 SteamStub21samples.zip I'll attach a zip. The zipfile contains 2 exe files; RPGXP and RPGVXAce. Both of these appear to have been packed with SteamStub 2.1, but there is a difference between them and the one used in RPGVX.exe namely that, I do not need to enable Experimental Features for the unpacking to be succesful. The unpacked versions of the exes also work like the normal (packed) exe files do.

So it seems that this failure only appears with RPGVX.exe, so far. Also I am surprised at how little in my library actually has SteamStub DRM, but that aside. If I find more, I'll let you know.

Thanks for the time you took to try and figure this out so far, as well as for explaining things.

Edit: never mind. Only RPG Maker XP's EXE file works normally. RPG Maker VX Ace's file breaks as well. [Instruction at 0x578cd6a0 refers to memory location 0x87b31f7c. A read or write action failed: read.] (localization of error messages, lol.) I am guessing it says 'couldn't read x from memory y.'

I tried unpacking it with experimental features, but that breaks the exe file even further. You don't get an error, it instantly closes as if you launched nothing.

atom0s commented 5 months ago

I've had a little more free time tonight to check this out again. I can get Steamless to properly unpack RPGVX now however it breaks compatibility with other titles in the process. The manner in which the 2.x stub variant works makes it pretty annoying to make a single one-size-fits-all solution that works on all packed games with it.

For the time being I am still going to not directly fix this yet until I have the time to come up with a better means of parsing out the information for all titles that works in a single go. I don't want to break compatibility with some stuff to fix 1 title.

If you wish to fix this in your own codebase to unpack RPGVX.exe, you can change the following: https://github.com/atom0s/Steamless/blob/cd770bf9749d3e4f438d23ac643917ad1a804257/Steamless.Unpacker.Variant21.x86/Main.cs#L418

Change the aesIv and codeStolen variables to:

                    var aesIv = this.PayloadData.Skip(this.SteamDrmpOffsets[7]).Take(16).ToArray();
                    var codeStolen = this.PayloadData.Skip(this.SteamDrmpOffsets[7]).Take(32).Skip(16).ToArray();

The issue here is that the SteamDMRP.dll offsets being used are wrong, this is annoying to deal with currently because the module has multiple variants for the different versions of SteamStub 2.x which changes the way things are compile down and the order they are stored. The AES encryption IV and the stolen bytes are stored together though within the payload data.

Hopefully I can eventually get to this and come up with a better permanent solution later.