-
-
Notifications
You must be signed in to change notification settings - Fork 223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fun fact: what is SteamStub32Var31Header::Unknown0001 #118
Comments
Hello there, most of the Over time I plan to rewrite Steamless to better handle all of the variants that exist and have it better handle properly deciding which variant is being used for the title that its being asked to unpack. But this is not a project I dedicate much time to currently, so that it is on the backburner along with a developer-mode I had started which goes into a lot more detail about the file, the header/stub and other information that is useful for someone wanting to learn more about SteamStub and what it has done to the file. There are other edge-cases on some sub-variants that modify the header or populate it in a different manner as well. The most common part of the header affected by this kind of thing is the RVA handling. Some games will only specifically use the ANSI variants of the API's it needs (ie. The string table handling you mentioned is also known and already reversed but not included inside of Steamless since it is not important to the unpacking process done by Steamless itself. I trimmed out extra nonsense that wasn't needed but left a few extra features (such as dumping the SteamDRMP.dll) for debugging purposes when its needed to review a potentially broken revision of the stub and needs manual review. To expand on one of your comments regarding the string table as well:
This function is the main function exported by the The mangling, however, does vary and so does the function prototype in general depending on the SteamStub variant/revision being used. It is not always the same call in regards to arguments and such. The mangling is also optional and will depend on the variant and how it was compiled. For example, the following are all observed:
The mangling also shows that the compiling has changed over time in how the function is coded/exported.
You can browse around the web to find more information in regards to how the mangling works, but as an example:
unsigned long __cdecl start(unsigned long, unsigned long); For the C style function In most cases though, the function is the same across an entire variant of SteamStub and has only changed between actual variants and generally not between revisions within a variant so the layout of the functions stay the same and are easily determined. |
Note: this does not help in decrypting, so it is only a "fun fact" ;)
I used Ghidra to analyze a wrapped program and found what it is. In short, it is an offset to an steam-xor-encrypted string data.
Steamless/Steamless.Unpacker.Variant31.x86/Classes/SteamStubHeader.cs
Line 43 in cd770bf
The position of string data can be represented as below:
After obtaining the data, we do a self steam-xor, represented as this code:
We also need to xor the first 4 bytes of string data with original (before-xor) last 4 bytes of the
0xf0
bytes of header data.Then, split it by
'\0'
, we'll get many parts, but number of strings is fixed34
:So what do we get? Let's see...
It's composed of 5 parts:
calloc
~FreeLibrary
)Steam DRM wrapper loads these functions dynamically so that the wrapped game is not easily detoured.
afterimports
~MessageBoxA
)Some critical dll and function names, put here so that we will not directly find them out.
Local\SteamStart_Shared*
)SteamDrmp.dll::_steam@12
will check the shared memory and write something. Sadly I haven't figured out what it does.Yes, exactly what is showed in error popups.
SteamDrmp.dll
main function name:_steam@12
(looks like__stdcall
mangled)It is later called by the wrapper with parameter
(entry_address, pointer_to_header, 0xf0)
.Another fun fact is how these strings are used. They have something to do with the dynamic function loading of the wrapper.
Steamless/Steamless.Unpacker.Variant31.x86/Classes/SteamStubHeader.cs
Lines 69 to 73 in cd770bf
It will check the first 4 function pointers and use the first non-null one to get the handle of
kernel32.dll
."kernel32.dll"
string comes from the string data above andL"kernel32.dll"
string is not encrypted.After getting the handle, it will check if
GetProcAddress
is available in header. If not, it will manually read PE structure ofkernel32.dll
and get the pointer toGetProcAddress
from its export table.Then, it will ensure
GetModuleHandleA
andLoadLibraryA
is available and loadmsvcrt.dll
withLoadLibraryA
."msvcrt.dll"
string comes from the string data above.Finally, it loads C stdlib functions and Win32 kernel32.dll functions mentioned above.
Wow, it is trying its best to avoid directly importing functions so that we cannot easily decompile it. I want to applause for its developers.
The text was updated successfully, but these errors were encountered: