Skip to content
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

Silent Hunter 3 fails to unpack #37

Closed
Ajaja opened this issue Jul 18, 2020 · 6 comments
Closed

Silent Hunter 3 fails to unpack #37

Ajaja opened this issue Jul 18, 2020 · 6 comments
Assignees
Labels
c: core Category: Core c: plugin Category: Plugin p: high Priority: High s: fixed Status: Fixed t: bug Type: Bug t: feature Type: Feature

Comments

@Ajaja
Copy link

Ajaja commented Jul 18, 2020

"Use Experimental Features" doesn't help.
Any advice?

http://s000.tinyupload.com/index.php?file_id=03808280615560158692

@atom0s
Copy link
Owner

atom0s commented Dec 18, 2020

Sorry for not seeing this sooner. This appears to be SteamStub 2.0 but, this does look like it could be the very first version of the stub 2.0 variant. This is not using the same setup as the more commonly seen variants for 2.0.

Support for this will hopefully come later, for now it won't be supported yet since it's a fully different version of 2 that is going to require some more work to implement support for.

@atom0s atom0s self-assigned this Dec 18, 2020
atom0s added a commit that referenced this issue Dec 18, 2020
…s version. I only have 1 sample with this version of the stub so it is solely based on this one exe. The full stub has been reversed for this file though. You can find more about that in issue #37)
@atom0s
Copy link
Owner

atom0s commented Dec 18, 2020

This is now supported via: 769232f


For those interested, this stub is pretty old and what I feel is the real 2.0 start. I've renamed the old 2.0's to 2.1 as they are newer and closer to what 3.x implements. So I feel like those are not the real 2.0 variants.

Here is my reversed notes for this stub if anyone is interested in checking it out:

// bad sp value at call has been detected, the output may be wrong!
int start()
{
  int v0; // eax
  int v1; // eax
  int v2; // eax
  int v3; // eax
  int v4; // edx
  int v5; // ecx
  int v6; // eax
  int v8; // [esp-4h] [ebp-1004h]
  int v9; // [esp-4h] [ebp-1004h]
  int v11; // [esp+2E8h] [ebp-D18h]
  int v12; // [esp+2F4h] [ebp-D0Ch]
  signed int nn; // [esp+2F8h] [ebp-D08h]
  int *v14; // [esp+2FCh] [ebp-D04h]
  int v15[3]; // [esp+300h] [ebp-D00h] BYREF
  int v16; // [esp+30Ch] [ebp-CF4h]
  int v17; // [esp+31Ch] [ebp-CE4h] BYREF
  int v18; // [esp+320h] [ebp-CE0h] BYREF
  unsigned int kk; // [esp+324h] [ebp-CDCh]
  WINTRUST_DATA *v20; // [esp+328h] [ebp-CD8h]
  unsigned int jj; // [esp+32Ch] [ebp-CD4h]
  int *v22; // [esp+330h] [ebp-CD0h]
  int (__stdcall *ptr_WinVerifyTrust)(_DWORD, GUID *, WINTRUST_DATA *); // [esp+334h] [ebp-CCCh]
  int buff_SystemDirectory[65]; // [esp+338h] [ebp-CC8h] BYREF
  int handle_WinTrust; // [esp+43Ch] [ebp-BC4h]
  WINTRUST_DATA trustData; // [esp+440h] [ebp-BC0h] BYREF
  GUID trustGuidVerifyv2; // [esp+470h] [ebp-B90h] BYREF
  int v28[4]; // [esp+480h] [ebp-B80h] BYREF
  int v29; // [esp+490h] [ebp-B70h]
  char v30[520]; // [esp+494h] [ebp-B6Ch] BYREF
  int v31; // [esp+69Ch] [ebp-964h] BYREF
  void (__stdcall *ptr_IsWow64Process)(int); // [esp+6A0h] [ebp-960h]
  char v33; // [esp+6A7h] [ebp-959h]
  int ii; // [esp+6A8h] [ebp-958h]
  int v35; // [esp+6ACh] [ebp-954h]
  int v36; // [esp+6B0h] [ebp-950h]
  int i; // [esp+6B4h] [ebp-94Ch]
  int *v38; // [esp+6B8h] [ebp-948h]
  unsigned int n; // [esp+6BCh] [ebp-944h]
  int *v40; // [esp+6C0h] [ebp-940h]
  unsigned int m; // [esp+6C4h] [ebp-93Ch]
  stubheader_t *v42; // [esp+6C8h] [ebp-938h]
  unsigned int i3; // [esp+6CCh] [ebp-934h]
  int *v44; // [esp+6D0h] [ebp-930h]
  unsigned int i1; // [esp+6D4h] [ebp-92Ch]
  stubheader_t *v46; // [esp+6D8h] [ebp-928h]
  unsigned int mm; // [esp+6DCh] [ebp-924h]
  int *v48; // [esp+6E0h] [ebp-920h]
  unsigned int ll; // [esp+6E4h] [ebp-91Ch]
  stubheader_t *v50; // [esp+6E8h] [ebp-918h]
  int v51; // [esp+6ECh] [ebp-914h]
  int buff_CommandLine_Cleaned[66]; // [esp+6F0h] [ebp-910h] BYREF
  _BYTE *buff_CommandLine; // [esp+7F8h] [ebp-808h]
  void (__stdcall *ptr_ShellExecuteA)(_DWORD, _DWORD, char *, int *, _DWORD, int); // [esp+7FCh] [ebp-804h]
  int handle_Shell32; // [esp+800h] [ebp-800h]
  int (*ptr_GetCommandLineA)(void); // [esp+804h] [ebp-7FCh]
  int v57; // [esp+808h] [ebp-7F8h] BYREF
  int v58; // [esp+80Ch] [ebp-7F4h] BYREF
  unsigned int l; // [esp+814h] [ebp-7ECh]
  int *v61; // [esp+818h] [ebp-7E8h]
  int v62; // [esp+81Ch] [ebp-7E4h]
  int v63; // [esp+820h] [ebp-7E0h]
  unsigned int k; // [esp+824h] [ebp-7DCh]
  char *v65; // [esp+828h] [ebp-7D8h]
  char *v66; // [esp+82Ch] [ebp-7D4h]
  unsigned int j; // [esp+830h] [ebp-7D0h]
  char *v68; // [esp+834h] [ebp-7CCh]
  char *v69; // [esp+838h] [ebp-7C8h]
  int (__cdecl *ptr_ExitProcess)(_DWORD); // [esp+83Ch] [ebp-7C4h]
  int (__fastcall *ptr_OEP)(int, int); // [esp+840h] [ebp-7C0h]
  char str_AppLoadError[25]; // [esp+844h] [ebp-7BCh] BYREF
  char v73[18]; // [esp+85Dh] [ebp-7A3h] BYREF
  char v74; // [esp+86Fh] [ebp-791h]
  void (__cdecl *ptr_SteamCleanup)(int *); // [esp+870h] [ebp-790h]
  void (__stdcall *ptr_MessageBoxA)(_DWORD, char *, char *, int); // [esp+874h] [ebp-78Ch]
  stubheader_t *stub_HeaderStart_Copy; // [esp+878h] [ebp-788h]
  int (__cdecl *ptr_SteamStartup)(int, int *); // [esp+87Ch] [ebp-784h]
  stubheader_t stub_HeaderStart; // [esp+880h] [ebp-780h] BYREF
  int v80[66]; // [esp+C38h] [ebp-3C8h] BYREF
  int v81[69]; // [esp+D40h] [ebp-2C0h] BYREF
  char v82; // [esp+E57h] [ebp-1A9h]
  int handle_Steam; // [esp+E58h] [ebp-1A8h]
  int (__cdecl *ptr_SteamIsAppSubscribed)(int, int *, int *, int *); // [esp+E5Ch] [ebp-1A4h]
  char v85; // [esp+E63h] [ebp-19Dh]
  int v86; // [esp+E64h] [ebp-19Ch]
  char buff_ModuleFileName[268]; // [esp+E68h] [ebp-198h] BYREF
  int handle_User32; // [esp+F74h] [ebp-8Ch]
  unsigned int v89; // [esp+F78h] [ebp-88h]
  int i2; // [esp+F7Ch] [ebp-84h]
  char str_SteamError[16]; // [esp+F80h] [ebp-80h] BYREF
  int handle_Kernel32; // [esp+F90h] [ebp-70h] BYREF
  void (__stdcall *ptr_VirtualProtect)(int, int, int, int *); // [esp+F94h] [ebp-6Ch]
  void (__stdcall *ptr_VirtualQuery)(int, int *, int); // [esp+F98h] [ebp-68h]
  void (__stdcall *ptr_FlushInstructionCache)(int); // [esp+F9Ch] [ebp-64h]
  int (__stdcall *ptr_LoadLibraryExA)(char *, _DWORD, _DWORD); // [esp+FA0h] [ebp-60h]
  void (__stdcall *ptr_FreeLibrary)(int); // [esp+FA4h] [ebp-5Ch]
  void (__stdcall *ptr_GetModuleFileNameA)(_DWORD, char *, int); // [esp+FA8h] [ebp-58h]
  void (__stdcall *ptr_lstrcatA)(int *, char *); // [esp+FACh] [ebp-54h]
  void (__stdcall *ptr_Sleep)(int); // [esp+FB0h] [ebp-50h]
  void (__stdcall *ptr_MultiByteToWideChar)(_DWORD, _DWORD, int *, int, char *, int); // [esp+FB4h] [ebp-4Ch]
  int ptr_GetModuleHandleA; // [esp+FB8h] [ebp-48h]
  int (__stdcall *ptr_GetSystemDirectoryA)(int *, int); // [esp+FBCh] [ebp-44h]
  int ptr_GetStartupInfoA; // [esp+FC0h] [ebp-40h]
  int ptr_DuplicateHandle; // [esp+FC4h] [ebp-3Ch]
  int ptr_OpenProcess; // [esp+FC8h] [ebp-38h]
  int ptr_MapViewOfFile; // [esp+FCCh] [ebp-34h]
  int ptr_UnmapViewOfFile; // [esp+FD0h] [ebp-30h]
  int ptr_CloseHandle; // [esp+FD4h] [ebp-2Ch]
  int ptr_GetCurrentProcessId; // [esp+FD8h] [ebp-28h]
  int ptr_OutputDebugStringA; // [esp+FDCh] [ebp-24h]
  int ptr_CreateToolhelp32Snapshot; // [esp+FE0h] [ebp-20h]
  int ptr_Thread32First; // [esp+FE4h] [ebp-1Ch]
  int ptr_Thread32Next; // [esp+FE8h] [ebp-18h]
  int (*ptr_GetLastError)(void); // [esp+FECh] [ebp-14h]
  int (__stdcall *ptr_GetCurrentProcess)(int *); // [esp+FF0h] [ebp-10h]

  qmemcpy(&stub_HeaderStart, dword_6344D8, sizeof(stub_HeaderStart));
  stub_HeaderStart_Copy = &stub_HeaderStart;
  v35 = stub_HeaderStart.XorKey1;
  v38 = &stub_HeaderStart.XorKey2;
  for ( i = 0xED; i > 0; --i )
  {
    v36 = *v38;
    *v38 ^= v35;
    v35 = v36;
    ++v38;
  }
  v82 = 48;
  v69 = str_SteamError;
  v68 = &stub_HeaderStart.StubData[0x2AC];      // String: Steam Error
  for ( j = 0; j < 0x10; ++j )
    v69[j] = v68[j];
  v66 = str_AppLoadError;
  v65 = &stub_HeaderStart.StubData[0x314];      // String: Application load error X:XXXXXXXXXX
  for ( k = 0; k < 0x28; ++k )
    v66[k] = v65[k];
  if ( (stub_HeaderStart.Flags & 1) != 0 )
  {
    v63 = stub_HeaderStart.ValidationHash;
    stub_HeaderStart.ValidationHash = 0;
    v0 = sub_633266(stub_HeaderStart.BindSectionVirtualAddress, stub_HeaderStart.BindSectionCodeSize, 0);// Validates the .bind code section..
    v62 = sub_633266((int)stub_HeaderStart_Copy, 0x3B8, v0);// Validates the .bind stub header data..
    if ( v62 != v63 )
      v82 = 49;
  }
  v61 = &handle_Kernel32;
  for ( l = 0; l < 0x6C; ++l )
    *((_BYTE *)v61 + l) = 0;
  if ( stub_HeaderStart.GetModuleHandleA_idata )
    handle_Kernel32 = (*(int (__stdcall **)(char *))stub_HeaderStart.GetModuleHandleA_idata)(stub_HeaderStart.StubData);// GetModuleHandleA(kernel32.dll)
  else
    handle_Kernel32 = (*(int (__stdcall **)(char *))stub_HeaderStart.GetModuleHandleW_idata)(stub_HeaderStart.StubData);// GetModuleHandleW(kernel32.dll)
  if ( !stub_HeaderStart.GetProcAddress_idata )
    stub_HeaderStart.GetProcAddress_idata = (int)&stub_HeaderStart.GetProcAddress_bind;
  ptr_ExitProcess = (int (__cdecl *)(_DWORD))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[572]);// GetProcAddress(ExitProcess)
  if ( v82 != 48 )
    goto LABEL_153;
  ptr_GetModuleHandleA = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[152]);// GetProcAddress(GetModuleHandleA)
  ptr_LoadLibraryExA = (int (__stdcall *)(char *, _DWORD, _DWORD))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[80]);// GetProcAddress(LoadLibraryExA)
  ptr_FreeLibrary = (void (__stdcall *)(int))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[96]);// GetProcAddress(FreeLibrary)
  ptr_GetModuleFileNameA = (void (__stdcall *)(_DWORD, char *, int))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[128]);// GetProcAddress(GetModuleFileNameA)
  ptr_lstrcatA = (void (__stdcall *)(int *, char *))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[556]);// GetProcAddress(lstrcatA)
  ptr_Sleep = (void (__stdcall *)(int))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[676]);// GetProcAddress(Sleep)
  ptr_MultiByteToWideChar = (void (__stdcall *)(_DWORD, _DWORD, int *, int, char *, int))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[412]);// GetProcAddress(MultiByteToWideChar)
  ptr_GetSystemDirectoryA = (int (__stdcall *)(int *, int))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[284]);// GetProcAddress(GetSystemDirectoryA)
  ptr_GetStartupInfoA = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[308]);// GetProcAddress(GetStartupInfoA)
  ptr_DuplicateHandle = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[328]);// GetProcAddress(DuplicateHandle)
  ptr_OpenProcess = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[348]);// GetProcAddress(OpenProcess)
  ptr_CloseHandle = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[364]);// GetProcAddress(CloseHandle)
  ptr_GetCurrentProcessId = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[264]);// GetProcAddress(GetCurrentProcessId)
  ptr_MapViewOfFile = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[380]);// GetProcAddress(MapViewOfFile)
  ptr_UnmapViewOfFile = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[396]);// GetProcAddress(UnmapViewOfFile)
  ptr_VirtualProtect = (void (__stdcall *)(int, int, int, int *))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[176]);// GetProcAddress(VirtualProtect)
  ptr_VirtualQuery = (void (__stdcall *)(int, int *, int))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[192]);// GetProcAddress(VirtualQuery)
  ptr_FlushInstructionCache = (void (__stdcall *)(int))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[208]);// GetProcAddress(FlushInstructionCache)
  ptr_OutputDebugStringA = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[436]);// GetProcAddress(OutputDebugStringA)
  ptr_CreateToolhelp32Snapshot = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[460]);// GetProcAddress(CreateToolhelp32Snapshot)
  ptr_Thread32First = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[492]);// GetProcAddress(Thread32First)
  ptr_Thread32Next = (*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[508]);// GetProcAddress(Thread32Next)
  ptr_GetLastError = (int (*)(void))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[524]);// GetProcAddress(GetLastError)
  ptr_GetCurrentProcess = (int (__stdcall *)(int *))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[652]);// GetProcAddress(GetCurrentProcess)
  if ( !ptr_GetModuleHandleA
    || !ptr_LoadLibraryExA
    || !ptr_FreeLibrary
    || !ptr_GetModuleFileNameA
    || !ptr_lstrcatA
    || !ptr_Sleep
    || !ptr_MultiByteToWideChar
    || !ptr_GetSystemDirectoryA
    || !ptr_GetStartupInfoA
    || !ptr_DuplicateHandle
    || !ptr_OpenProcess
    || !ptr_CloseHandle
    || !ptr_GetCurrentProcessId
    || !ptr_MapViewOfFile
    || !ptr_UnmapViewOfFile
    || !ptr_VirtualProtect
    || !ptr_VirtualQuery
    || !ptr_FlushInstructionCache
    || !ptr_OutputDebugStringA
    || !ptr_CreateToolhelp32Snapshot
    || !ptr_Thread32First
    || !ptr_Thread32Next
    || !ptr_GetLastError )
  {
    v82 = 69;
LABEL_153:
    v89 = *(_DWORD *)&stub_HeaderStart.SteamAppIDString[8];// 0 value..
    if ( !*(_DWORD *)&stub_HeaderStart.SteamAppIDString[8] )
      v89 = ptr_GetLastError();                 // 0 value; check for last error..
    v89 += 0xFF98;                              // Encode the last error by adding junk to it..
    handle_User32 = ptr_LoadLibraryExA(&stub_HeaderStart.StubData[16], 0, 0);// LoadLibraryExA(user32.dll, 0, 0)
    ptr_MessageBoxA = (void (__stdcall *)(_DWORD, char *, char *, int))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_User32, &stub_HeaderStart.StubData[112]);// GetProcAddress(MessageBoxA)
    v42 = &stub_HeaderStart;                    // Null the header..
    for ( m = 0; m < 0x3B8; ++m )
      *((_BYTE *)&v42->XorKey1 + m) = 0;
    v40 = &handle_Kernel32;                     // Null locals..
    for ( n = 0; n < 0x6C; ++n )
      *((_BYTE *)v40 + n) = 0;
    if ( ptr_MessageBoxA )
    {
      str_AppLoadError[23] = v82;               // Append the error id based on the exit point of the stub..
      sub_633203(v89, (int)v73);                // Convert the encoded error id into a string..
      ptr_MessageBoxA(0, str_AppLoadError, str_SteamError, 16);// Display the application error message..
    }
    return ptr_ExitProcess(v82);                // Exit the process with the exit point of the stub..
  }

  // Thread Check Validation..
  if ( (stub_HeaderStart.Flags & 8) != 0 && sub_6333C0((int)&handle_Kernel32) != 1 )
  {
    v82 = 57;
    goto LABEL_153;
  }

  // Get the current module file name and build path to Steam.dll..
  handle_Steam = 0;
  ptr_GetModuleFileNameA(0, buff_ModuleFileName, 260);
  do
  {
    if ( buff_ModuleFileName && buff_ModuleFileName[0] )
    {
      for ( ii = 0; buff_ModuleFileName[ii]; ++ii )
        ;
      if ( *((_BYTE *)&v86 + ii + 3) == '\\' )
        --ii;
      while ( ii > 0 )
      {
        if ( *((_BYTE *)&v86 + ii + 3) == '\\' )
        {
          buff_ModuleFileName[ii] = 0;
          v33 = 1;
          goto LABEL_66;
        }
        --ii;
      }
      v33 = 0;
    }
    else
    {
      v33 = 0;
    }
LABEL_66:
    if ( !v33 )
      break;
    LOBYTE(v80[0]) = 0;
    ptr_lstrcatA(v80, buff_ModuleFileName);
    ptr_lstrcatA(v80, &stub_HeaderStart.StubData[700]);// String: Steam.dll
    handle_Steam = ptr_LoadLibraryExA((char *)v80, 0, 0);// LoadLibraryExA(full_path_to_Steam.dll, 0, 0);
  }
  while ( !handle_Steam );
  if ( !handle_Steam )
  {
    v82 = 50;
    goto LABEL_153;
  }

  // Get the Steam.dll API function pointers..
  ptr_SteamIsAppSubscribed = (int (__cdecl *)(int, int *, int *, int *))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Steam, &stub_HeaderStart.StubData[732]);// GetProcAddress(SteamIsAppSubscribed)
  ptr_SteamStartup = (int (__cdecl *)(int, int *))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Steam, &stub_HeaderStart.StubData[756]);// GetProcAddress(SteamStartup)
  ptr_SteamCleanup = (void (__cdecl *)(int *))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Steam, &stub_HeaderStart.StubData[772]);// GetProcAddress(SteamCleanup)
  if ( !ptr_SteamIsAppSubscribed || !ptr_SteamStartup || !ptr_SteamCleanup )
  {
    v82 = 52;
    goto LABEL_153;
  }

  // Validate the file via WinVerifyTrust..
  if ( (stub_HeaderStart.Flags & 2) != 0 )
  {
    v31 = 0;
    ptr_IsWow64Process = (void (__stdcall *)(int))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[636]);// GetProcAddress(IsWow64Process)
    if ( ptr_IsWow64Process )
    {
      v1 = ptr_GetCurrentProcess(&v31);
      ptr_IsWow64Process(v1);
    }
    if ( !v31 )
    {
      if ( ptr_GetSystemDirectoryA(buff_SystemDirectory, 260) )
      {
        ptr_lstrcatA(buff_SystemDirectory, &stub_HeaderStart.StubData[48]);// String: \wintrust.dll
        handle_WinTrust = ptr_LoadLibraryExA((char *)buff_SystemDirectory, 0, 0);// LoadLibraryExA(wintrust.dll, 0, 0);
        if ( handle_WinTrust )
        {
          ptr_WinVerifyTrust = (int (__stdcall *)(_DWORD, GUID *, WINTRUST_DATA *))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_WinTrust, &stub_HeaderStart.StubData[620]);// GetProcAddress(WinVerifyTrust)
          trustGuidVerifyv2.Data1 = 0xAAC56B;   // WINTRUST_ACTION_GENERIC_VERIFY_V2 
          trustGuidVerifyv2.Data2 = 0xCD44;
          trustGuidVerifyv2.Data3 = 0x11D0;
          trustGuidVerifyv2.Data4[0] = 0x8C;
          trustGuidVerifyv2.Data4[1] = 0xC2;
          trustGuidVerifyv2.Data4[2] = 0;
          trustGuidVerifyv2.Data4[3] = 0xC0;
          trustGuidVerifyv2.Data4[4] = 0x4F;
          trustGuidVerifyv2.Data4[5] = 0xC2;
          trustGuidVerifyv2.Data4[6] = 0x95;
          trustGuidVerifyv2.Data4[7] = 0xEE;
          if ( ptr_WinVerifyTrust )
          {
            ptr_MultiByteToWideChar(0, 0, v80, -1, v30, 260);
            v22 = v28;
            for ( jj = 0; jj < 0x10; ++jj )
              *((_BYTE *)v22 + jj) = 0;
            v28[0] = 16;
            v28[1] = (int)v30;
            v28[2] = 0;
            v28[3] = 0;
            v20 = &trustData;
            for ( kk = 0; kk < 0x30; ++kk )
              *((_BYTE *)&v20->cbStruct + kk) = 0;
            trustData.cbStruct = 48;            // WINTRUST_DATA
            trustData.pPolicyCallbackData = 0;
            trustData.pSIPClientData = 0;
            trustData.dwUIChoice = 2;
            trustData.fdwRevocationChecks = 0;
            trustData.dwUnionChoice = 1;
            trustData.dwStateAction = 0;
            trustData.hWVTStateData = 0;
            trustData.pwszURLReference = 0;
            trustData.dwProvFlags = 256;
            trustData.dwUIContext = 0;
            trustData.pFile = (WINTRUST_FILE_INFO_ *)v28;
            v29 = ptr_WinVerifyTrust(0, &trustGuidVerifyv2, &trustData);// WinVerifyTrust(0, WINTRUST_ACTION_GENERIC_VERIFY_V2, buffer);
            if ( v29 )
              *(_DWORD *)&stub_HeaderStart.SteamAppIDString[8] = ptr_GetLastError();
            ptr_FreeLibrary(handle_WinTrust);
            v82 = v29 != 0 ? 51 : 48;
          }
          else
          {
            ptr_FreeLibrary(handle_WinTrust);
            v82 = 67;
          }
        }
        else
        {
          v82 = 66;
        }
      }
      else
      {
        v82 = 65;
      }
      if ( v82 != 48 )
        goto LABEL_153;
    }
  }
  v74 = 0;
  v85 = 0;

  // Ensure that steam is loaded and the app is subscribed..
  if ( ptr_SteamStartup(14, v81) )
  {
    v58 = 0;
    v57 = 0;
    if ( ptr_SteamIsAppSubscribed(stub_HeaderStart.SteamAppID, &v58, &v57, v81) )
    {
      if ( !v81[0] && v58 )
        v74 = 1;
    }
    else
    {
      v85 = 1;
    }
    ptr_SteamCleanup(v81);
  }
  else
  {
    v85 = 1;
  }
  if ( v85 || !v74 )
  {
    handle_Shell32 = ptr_LoadLibraryExA(&stub_HeaderStart.StubData[32], 0, 0);// LoadLibraryExA(shell32.dll, 0, 0);
    ptr_ShellExecuteA = (void (__stdcall *)(_DWORD, _DWORD, char *, int *, _DWORD, int))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Shell32, &stub_HeaderStart.StubData[588]);// GetProcAddress(ShellExecuteA)
    ptr_GetCommandLineA = (int (*)(void))(*(int (__stdcall **)(int, char *))stub_HeaderStart.GetProcAddress_idata)(handle_Kernel32, &stub_HeaderStart.StubData[604]);// GetProcAddress(GetCommandLineA)
    if ( ptr_ShellExecuteA && ptr_GetCommandLineA )
    {
      if ( v85 )
      {
        // Build path to launch Steam with the app due to failing to validate it was launched with Steam..
        LOBYTE(buff_CommandLine_Cleaned[0]) = 0;
        ptr_lstrcatA((int *)buff_ModuleFileName, &stub_HeaderStart.StubData[716]);// String: Steam.exe
        ptr_lstrcatA(buff_CommandLine_Cleaned, &stub_HeaderStart.StubData[860]);// String: -applaunch 
        ptr_lstrcatA(buff_CommandLine_Cleaned, stub_HeaderStart.SteamAppIDString);
        buff_CommandLine = (_BYTE *)ptr_GetCommandLineA();
        if ( buff_CommandLine && *buff_CommandLine )
        {
          v51 = 0;
          if ( *buff_CommandLine == '"' )
          {
            ++v51;
            while ( buff_CommandLine[v51] && buff_CommandLine[v51] != '"' )
              ++v51;
            if ( buff_CommandLine[v51] )
              ++v51;
          }
          while ( buff_CommandLine[v51] && buff_CommandLine[v51] != ' ' )
            ++v51;
          if ( buff_CommandLine[v51] == ' ' )
            ptr_lstrcatA(buff_CommandLine_Cleaned, &buff_CommandLine[v51]);
        }
        ptr_ShellExecuteA(0, 0, buff_ModuleFileName, buff_CommandLine_Cleaned, 0, 1);// ShellExecuteA(0, 0, "Steam.exe -applaunch app_id_here", cmd_line_here, 0, 1);
      }
      else
      {
        // Open the store page if we don't own the game..
        ptr_lstrcatA((int *)&stub_HeaderStart.StubData[828], stub_HeaderStart.SteamAppIDString);// String: steam://store/
        ptr_ShellExecuteA(0, 0, &stub_HeaderStart.StubData[828], 0, 0, 1);// ShellExecuteA(0, 0, "steam://store/app_id_here", 0, 0, 1);
      }
    }
    if ( stub_HeaderStart.SteamAppID )
    {
      v50 = &stub_HeaderStart;
      for ( ll = 0; ll < 0x3B8; ++ll )
        *((_BYTE *)&v50->XorKey1 + ll) = 0;     // Null the header..
      v48 = &handle_Kernel32;
      for ( mm = 0; mm < 0x6C; ++mm )           // Null locals..
        *((_BYTE *)v48 + mm) = 0;
      ((void (__stdcall *)(_DWORD))ptr_ExitProcess)((char)(54 - (v85 != 0)));// Kill the process..
    }
  }

  // Validate startup inforamtion via memory mapped view..
  if ( (stub_HeaderStart.Flags & 0x10) != 0 && !sub_6332D9(&stub_HeaderStart, (int)&handle_Kernel32) )
  {
    v82 = 55;
    goto LABEL_153;
  }

  // Decrypt/Decode the .text (code) section..
  if ( (stub_HeaderStart.Flags & 4) != 0 )
  {
    ptr_VirtualQuery(stub_HeaderStart.CodeSectionVirtualAddress, v15, 28);
    v18 = 4;
    v17 = 0;
    ptr_VirtualProtect(v15[0], v16, 4, &v17);
    v11 = stub_HeaderStart.CodeSectionXorKey;
    v14 = (int *)stub_HeaderStart.CodeSectionVirtualAddress;
    for ( nn = (unsigned int)stub_HeaderStart.CodeSectionSize >> 2; nn > 0; --nn )
    {
      v12 = *v14;
      *v14 ^= v11;
      v11 = v12;
      ++v14;
    }
    ptr_VirtualProtect(v15[0], v16, v17, &v18);
    v2 = ((int (__stdcall *)(int, int))ptr_GetCurrentProcess)(v15[0], v16);
    ptr_FlushInstructionCache(v2);
  }
  ptr_OEP = (int (__fastcall *)(int, int))stub_HeaderStart.OEP;
  v46 = &stub_HeaderStart;
  for ( i1 = 0; i1 < 0x3B8; ++i1 )
    *((_BYTE *)&v46->XorKey1 + i1) = 0;         // Null the header..

  // Look for running threads and let them attempt to complete/finish..
  v86 = 0;
  v3 = sub_6333C0((int)&handle_Kernel32);
  v5 = v8;
  for ( i2 = v3; i2 > 1 && v86 < 1000; i2 = v6 )
  {
    ptr_Sleep(50);
    v86 += 50;
    v6 = sub_6333C0((int)&handle_Kernel32);
    v5 = v9;
  }
  if ( i2 <= 1 )
    ptr_FreeLibrary(handle_Steam);
  v44 = &handle_Kernel32;
  for ( i3 = 0; i3 < 0x6C; ++i3 )
    *((_BYTE *)v44 + i3) = 0;                   // Null locals..
  return ptr_OEP(v5, v4);                       // Invoke the real OEP..
}

@atom0s
Copy link
Owner

atom0s commented Dec 18, 2020

StubHeader.Flags & 0x01 - Stub code validation and stub header validation. This is used to check if the stub is tampered with via a hash check. The hasher is:

int __cdecl sub_633266(int a1, int a2, int a3)
{
  int j; // [esp+0h] [ebp-Ch]
  int i; // [esp+4h] [ebp-8h]

  for ( i = 0; i < a2; ++i )
  {
    a3 ^= *(char *)(i + a1) << 24;
    for ( j = 8; j > 0; --j )
    {
      if ( a3 >= 0 )
        a3 *= 2;
      else
        a3 = (2 * a3) ^ 0x488781ED;
    }
  }
  return a3;
}

StubHeader.Flags & 0x02 - PE validation via WinVerifyTrust API call. This will do a validation check on the Steam.dll file to ensure it's valid and not tampered with as well. Generally used to try and detect emulation of the Steam libraries.


StubHeader.Flags & 0x04 - PE code section encoding/encryption. This is used to state that the code section has been altered. In the stub header is an XOR key used when this is set to begin decoding the code section data.


StubHeader.Flags & 0x08 - Thread validation which is used to detect if things are running while the stub is executing it's stuff. This will check for owned threads by the local process and die out if there is more than just the main thread during the stubs execution. This is also then used to allow thread cleanup later at the end of the stub once other things have happened.


StubHeader.Flags & 0x10 - Memory mapped data validation. I did not have the ability to dig into this part, however, based on how it looks, it seems like the stub is expecting the startup information to contain data to be hashed and validated against inside of a memory-mapped file.

The handling for that looks like this:

bool __cdecl sub_6332D9(stubheader_t *header, int ptrs)
{
  int v2; // eax
  int v3; // eax
  int v5[4]; // [esp+0h] [ebp-78h] BYREF
  int v6; // [esp+10h] [ebp-68h]
  int v7; // [esp+14h] [ebp-64h]
  STARTUPINFOA startInfo; // [esp+18h] [ebp-60h] BYREF
  DWORD v9; // [esp+64h] [ebp-14h]
  int v10; // [esp+68h] [ebp-10h]
  bool v11; // [esp+6Fh] [ebp-9h]
  int v12; // [esp+70h] [ebp-8h] BYREF
  DWORD v13; // [esp+74h] [ebp-4h]

  startInfo.cb = 68;
  (*(void (__stdcall **)(STARTUPINFOA *))(ptrs + 48))(&startInfo);// ptr_GetStartupInfoA
  v11 = 0;
  v13 = startInfo.dwX;
  v12 = 0;
  v9 = startInfo.dwY;
  v10 = (*(int (__stdcall **)(int, _DWORD, DWORD))(ptrs + 56))(0x40, 0, startInfo.dwY);// ptr_OpenProcess(PROCESS_DUP_HANDLE, 0, procId);
  if ( v10 )
  {
    v2 = (*(int (__stdcall **)(int *, int, _DWORD, _DWORD))(ptrs + 96))(&v12, 4, 0, 0);// ptr_GetCurrentProcess
    if ( (*(int (__stdcall **)(int, DWORD, int))(ptrs + 52))(v10, v13, v2) )// ptr_DuplicateHandle
    {
      v7 = (*(int (__stdcall **)(int, int, _DWORD, _DWORD, _DWORD))(ptrs + 60))(v12, 4, 0, 0, 0);// ptr_MapViewOfFile
      if ( v7 )
      {
        v6 = *(_DWORD *)(v7 + 4 * (startInfo.dwXSize % 0x20) + 16);
        v5[1] = (*(int (__cdecl **)(DWORD))(ptrs + 72))(startInfo.dwXSize);// ptr_GetCurrentProcessId
        v5[2] = header->SteamAppID;
        v5[3] = header->Unknown0000;
        v3 = sub_633266((int)v5, 16, 0);
        v11 = v6 == v3;
        (*(void (__stdcall **)(int))(ptrs + 64))(v7);// ptr_UnmapViewOfFile
      }
    }
    (*(void (__stdcall **)(int))(ptrs + 68))(v10);// ptr_CloseHandle
  }
  return v11;
}

Since I cannot debug this file or have other samples with this stub version, I can't say for 100% certainty what's happening, but it looks like Steam may be overriding some of the startup info data returned from GetStartupInfoA to validate things are not tampered with. My guess is this is used for some means of injection detection.

@atom0s
Copy link
Owner

atom0s commented Dec 18, 2020

This is now fixed/closed with the release of 3.0.0.11:
https://github.com/atom0s/Steamless/releases/tag/v3.0.0.11

@atom0s atom0s closed this as completed Dec 18, 2020
@Ajaja
Copy link
Author

Ajaja commented Dec 18, 2020

Thank you very much, it works!

@OdinVex
Copy link

OdinVex commented Dec 18, 2020

Back in my day I created a loader that read any assembly around these variants (too lazy to build an unpacker) that walked through and halted execution and simply updated pointers and bypassed WinVerifyTrust and such. Feel old, eh. Edit I think I recall laughing at the 69 constant too in those old days. Might've been a different project with that constant. Ah who knows. :]

@atom0s atom0s added c: core Category: Core c: plugin Category: Plugin p: high Priority: High s: fixed Status: Fixed t: bug Type: Bug t: feature Type: Feature and removed enhancement labels Mar 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: core Category: Core c: plugin Category: Plugin p: high Priority: High s: fixed Status: Fixed t: bug Type: Bug t: feature Type: Feature
Projects
None yet
Development

No branches or pull requests

3 participants