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.12k stars 195 forks source link

Ground Zeroes fails to unpack #20

Closed jackson2k2 closed 2 years ago

jackson2k2 commented 5 years ago

Detected as SteamStub 3.0, but unknown if there are any additional layers of protection such as Denuvo; which The Phantom Pain does have. "Failed to unpack file."

"Use Experimental Features" is no help, either.

atom0s commented 5 years ago

If you can, please upload the games exe's somewhere.

jackson2k2 commented 5 years ago

@atom0s http://s000.tinyupload.com/index.php?file_id=40434177493364351682

jackson2k2 commented 5 years ago

Executable's here, API dll too, if need is necessary. As for the quick response.... thanks.

atom0s commented 5 years ago

Ah, a sample that has a TLS callback! Haven't had any of these thrown my way that I can recall. This is failing to unpack because of the TLS callback being replaced into the .bind section ahead of the actual entry point. Due to this, it fails to unpack because the current setup to get the stub header fails if a TLS callback is present.

When I have some free time I'll adjust the unpacker to work with this sample too. Thanks for this exe. :)

atom0s commented 5 years ago

This is now fixed and the file should be unpacking properly in the latest release, thanks for the file submission! :) https://github.com/atom0s/Steamless/releases/latest

jackson2k2 commented 5 years ago

Unpacked files. They have no guarantee of working? Bind kept, I get "Application load error 3:0000065432". Without bind, nothing. No error, but no sign of life either.

Which one is also recommended for static analysis? Bind kept?

atom0s commented 5 years ago

If the bind section is still there then either you had the option left on to keep it or it failed something. Make sure that you fully updated all your Steamless files and not just the exe.

Outside of that it may be something else with the TLS causing it to fail still.

jackson2k2 commented 5 years ago

Nothing failed, I was describing the problem I had with the "keep bind" option on and off. I only did the former because the captions said I should keep the bind when unpacking executables. All Steamless files were fully updated.

atom0s commented 5 years ago

Ok looking at the unpacked file, it seems to have replaced the OEP after being unpacked with the TLS callback, so it seems the stub holds the TLS callback address as the OEP if its present.

I'll have to take another look when I get some more time to see if the actual OEP is present elsewhere in the header then to see where it may be storing that vs. using the TLS itself and see if that needs to be rebuilt too.

Edit - Another note to myself, appears the TLS will have to be rebuilt to some degree, at least the callback address as it is invalid after unpacking.

jackson2k2 commented 5 years ago

Have you made any progress since you began investigating?

atom0s commented 5 years ago

Hey there, didn't forget about this, just super busy with some real life things at the moment so I haven't had much free time lately. Once things settle down I'll take another look at this to get the TLS stuff fixed.

jackson2k2 commented 5 years ago

i, rather suggest you to investigate it for yourself if u are impatient @kazblox or just wait till he fixes.

Sorry if I showed a false impression that I was being impatient. It wasn't evident to me at first, but asking for any status update when the author is busy gives out such a sign.

Once again, my condolences.

jackson2k2 commented 5 years ago

Not trying to be impatient, but still waiting... Take your time, if you must.

lagseeing commented 4 years ago

Seems to unpack now, but the unpacked exe does not launch at all

atom0s commented 2 years ago

I finally had some free time to take a look at this again, and sadly I'm still at a bit of a loss on how this file is supposed to unpack correctly for now. (When I get more free time to fully debug the file, I can figure out the real way it's handling this setup.)

There are a few things going on with this file that causes it to unpack partially 'incorrect'.

Firstly, this file uses a TlsCallback to call the .bind stub. This is the first file I've seen do this. This also causes Steamless to not handle the Tls properly because I've not accounted for this happening. So this file has a weird setup where:

When unpacked, the file will be in an semi-invalid state. Since the TlsCallback is inside of the .bind section, its caller address gets left in the Tls section information but the pointer is invalid. However, along with that, the OriginalEntryPoint address stored in the SteamStub header is also incorrect. This is actually the original TlsCallback address that is supposed to be put back into the unpacked files TlsCallback.

Because of this, the true OEP doesn't seem stored anywhere that I see without debugging. However, since the game does compile with Visual Studio, it's easy to find it manually.

To fix this file after unpacking, you need to do the following:

To restore the TlsCallback, open the unpacked file in CFF Explorer, go to TLS Directory, copy the AddressOfCallbacks value. Go to the Address Converter page and enter that address you copied into the top VA entry.

In the hex window, change the first 8 bytes to: 60 96 00 40 01 00 00 00

To fix the files OEP, go to Optional Header, and change AddressOfEntryPoint to 00D34EBC.

These are the values for the file given here and what appears to still be the latest version on Steam.

I do own this game so when I get more time to look I will try to find how the true OEP is actually handled in this, I will also need to make adjustments to Steamless to handle this kind of TLS usage.

atom0s commented 2 years ago

Had some time tonight to debug this and figure it out now. The way this file works is very different than normal stub handling because of the usage of a TlsCallback. When a TlsCallback is present, the stub injection is performed differently to account for the need to deal with the original TlsCallback after the .text is unpacked. Because of this, the stub is injected as a new TlsCallback itself instead. When this happens, the way the file is rebuilt is done differently to account for the different adjustments needed.

Here's a rundown of what is happening when a TlsCallback is present:

When this setup happens, the .bind section stub that is used to do the unpacking/processing is turned into a TlsCallback and injected into PE header as the first callback. It must run before the original callbacks can run because their parent section may be encrypted at the time of trying to execute otherwise. The original entry point is overwritten with a new stub as well that is used to decrypt the true OEP address via an XOR key. (They use the headers XorKey value to hold the 2nd half of the calculation when this happens.)

This is what the new OEP stub looks like that decrypts the real original OEP:

.bind:000000014209B350 ; void start()
.bind:000000014209B350                 public start
.bind:000000014209B350 start           proc near
.bind:000000014209B350
.bind:000000014209B350 var_8           = qword ptr -8
.bind:000000014209B350
.bind:000000014209B350                 call    $+5
.bind:000000014209B355                 push    rax
.bind:000000014209B356                 push    rdx
.bind:000000014209B357                 mov     rax, [rsp+18h+var_8]
.bind:000000014209B35C                 sub     rax, 5
.bind:000000014209B362                 mov     rdx, rax
.bind:000000014209B365                 sub     rdx, 130h
.bind:000000014209B36C                 mov     edx, [rdx]
.bind:000000014209B36E                 xor     edx, 0B6AE239Dh
.bind:000000014209B374                 movsxd  rdx, edx
.bind:000000014209B377                 add     rax, rdx
.bind:000000014209B37A                 mov     [rsp+18h+var_8], rax
.bind:000000014209B37F                 pop     rdx
.bind:000000014209B380                 pop     rax
.bind:000000014209B381                 retn
.bind:000000014209B381 start           endp

What this is doing is:

In this case that would be this:

So then when this file is ran, the following happens:

Now that I got this figured out I can adjust the unpacker variant for this file to work with this setup. I'll wait til samples of other variants are submitted or found before adding this setup to the others to ensure the logic is the same

atom0s commented 2 years ago

This is now fixed in the latest code push. will be in the next update as well.

SilentMRG commented 1 year ago

If you can, please upload the games exe's somewhere.

Taking advantage of the topic...

Hey man, what is the "Keep Bind Section" option for? I used the latest version of Steamless to remove protection from Final Fantasy VII and VIII games and did not check this option. In this case, I removed the protection from Launchers and "Game.exe" (if that's what I can call it). Can I have problems with these executables at some point because I didn't check the "Keep Bind Section" option?

Thanks in advance!

atom0s commented 1 year ago

The option is there because some games actively look for the .bind section to exist as another layer of 'protection' from being unpacked. (Grim Dawn for example does this.) Some titles also use a variant of SteamStub that moves the import section into the .bind section, so it is (at this time) required to keep the section after unpacking for the file to still run properly.

SilentMRG commented 1 year ago

The option is there because some games actively look for the .bind section to exist as another layer of 'protection' from being unpacked. (Grim Dawn for example does this.) Some titles also use a variant of SteamStub that moves the import section into the .bind section, so it is (at this time) required to keep the section after unpacking for the file to still run properly.

Well, I ended up not checking the option "Keep Bind Section." But apparently FFs VII and VIII are working properly. Thanks for the clarification and attention! And thanks for the excellent work!

Cheers and Happy Holidays!