Luigi Auriemma

aluigi.org (ARCHIVE-ONLY FORUM!)
It is currently 19 Jul 2012 13:46

All times are UTC [ DST ]





Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 34 posts ]  Go to page Previous  1, 2
Author Message
 Post subject: Re: How Steampwd works
PostPosted: 06 Sep 2008 02:44 

Joined: 01 Sep 2008 07:40
Posts: 31
aluigi wrote:
desxor I need to correct you on some things.

The SteamDecryptDataForThisMachine function created by Valve has been exported in steam.dll in some recent versions, in fact when I started the steampwd project in the far 2005 it didn't existed... unfortunately for me

the hl2 source code doesn't contain info about this or other Steam related functions or AESPHM_Decrypt because this is part of the Steam program and not of the game.

for the rest I have already talked with Tughack and naturally he was wrong.
was enough to check the dates of my post and the one on nodereality.com... I'm not so good to travel in the future and returning 10 days back in time ih ih ih

the only thing that I don't like is having someone which says/accuses that I have "copied" a sizeof(pwd) and a &len from some places in the future that even I don't know.
with all the stuff I have reversed in my life I expect at least a bit more of estimation, not much but at least enough to avoid something so ridiculous as this thing of the 2 parameters moreover considering that Tughack contacted me in PM asking me to do this and I found all the 5 parameters (in two different occasions, I was completely uninterested to this thing since my steampwd is already complete)

i stand corrected.


Top
 Profile  
 
 
 Post subject: Re: How Steampwd works
PostPosted: 10 Sep 2008 06:05 

Joined: 01 Sep 2008 07:40
Posts: 31
I have combined Luigi's ClientRegistry.blob parsing function(s) with VALVe's exported SteamDecryptDataForThisMachine() function. This is just an example of how to combine the two since I have not seen anyone else post such yet besides Luigi's original steampwd v0.2.1 which uses its own decryption function. I also tried to insert comments where applicable to better explain what his code is doing step by step.

Note that '\x50\x68\x72\x61\x73\x65\x01\x50" represents "Phrase.P", I just thought it more simple than using a macro.

Enjoy.

gcc -s -O2 DecryptStoredSteamPassword.c

Code:
//
// DecryptStoredSteamPassword.c
//
// Combines Luigi's ClientRegistry.blob parsing function(s)
// with VALVe's exported SteamDecryptDataForThisMachine() function
//
// small code changes and comments added by desxor

#include <stdio.h>
#include <stdint.h>
#include <sys/stat.h>
#include <windows.h>

void SteamParseEncryptedPassPhrase(uint8_t *fname);
uint8_t *find_data(uint8_t *buff, int buffsz, uint8_t *str);

typedef int (__cdecl *SteamDecryptDataForThisMachine_t)(char *a, int b, char *c, int d, int *e);
SteamDecryptDataForThisMachine_t SteamDecryptDataForThisMachine;

int main(int argc, char *argv[]) {
   HANDLE hSteamDLL;

   // this path should be grabbed automatically from registry "InstallPath" value, but since
   // this is just an example, desxor is being lazy.
   hSteamDLL = LoadLibrary("C:\\Program Files\\Steam\\STEAM.DLL");
   if(!hSteamDLL) {
      printf("\nError: the file STEAM.DLL has not been found.\n");
      exit(1);
   }

   SteamDecryptDataForThisMachine = (void *)GetProcAddress(hSteamDLL, "SteamDecryptDataForThisMachine");
   if(!SteamDecryptDataForThisMachine) {
      printf("\nError: the function SteamDecryptDataForThisMachine has not been found.\n");
      exit(1);
   }

   // this path should be grabbed automatically from registry "InstallPath" value as well
   SteamParseEncryptedPassPhrase("C:\\Program Files\\Steam\\ClientRegistry.blob");

   FreeLibrary(hSteamDLL);
   return(0);
}

void SteamParseEncryptedPassPhrase(uint8_t *fname) {
   int len, fdsize, pwds;
   uint16_t nlen;
   uint8_t *fdbuff, *fdnext, *p, *buff;
   char decpass[100];
   struct stat xstat;
   FILE *fd;

   fd = fopen(fname, "rb");
   if(!fd) {
      printf("Could not open %s for reading/memory search.\n", fname);
      exit(1);
   } else {
      fstat(fileno(fd), &xstat);
      fdbuff = malloc(xstat.st_size);

      if(!fdbuff) {
         printf("Could not allocate file into memory.\n");

         // comments for the following are pretty much the same as below so look there for
         // a more detailed description of what's going on

         len = strlen(fname);
         fdsize = 64 + len;

         fdbuff = malloc(fdsize);

         p = fdbuff;
         p += sprintf(p, "%-30s", "\x50\x68\x72\x61\x73\x65\x01\x50");

         *(uint16_t *)p = 0;
         p += 2;

         *(uint32_t *)p = len;
         p += 4 + 0;

         strcpy(p, fname);

         fclose(fd);
         goto next;
      }

      // load our file into memory for searching and reading its data
      fread(fdbuff, 1, xstat.st_size, fd);
      fclose(fd);

      fdsize = xstat.st_size;
   }
next:
       fdnext = fdbuff;
       for(pwds = 0;; pwds++) {
      // search for unique phrase text using memcmp(), using a great little function provided by Luigi A.
      // his function will search the entire allocated memory for the data you specify and return with it
      // if its found, otherwise null

              p = find_data(fdnext, fdsize, "\x50\x68\x72\x61\x73\x65\x01\x50");

              if(!p) {
         if(pwds) break;
         printf("An encrypted and stored password could not be located, exiting.\n");
         exit(1);
              }

      // skip 30 bytes past the PHRASE text to the encrypted password until we come
      // to "04 00" or simply 4, (0x04 + (0x00 * 256)), we now have 24 bytes remaining
              p += 30;

      // this is the 16 bit number we are looking for, save it in the following format:
      // num = byte1 + (byte2 * 256)
              nlen = *(uint16_t *)p;

      // skip the next 2 bytes of the 16bit number we just saved
      p += 2;

      // after we skipped 2 bytes, we come to 32bit number (4 bytes) which should always be the
      // size of our encrypted string, it should appear as "5c 00 00 00", which equals 0x5c or simply, 92
      // save this in the same format as before
              len  = *(uint32_t *)p;

      // now we skip the 4 bytes that we _just read_ PLUS the amount of bytes specified by the first
      // 16 bit number we just saved, should be 2 bytes anyhow
      // this should now bring us to our encrypted password located in ClientRegistry.blob which should be
      // 92 (0x5c) characters long
      p += 4 + nlen;

      // an example of the data, provided by Luigi:
      // 50 68 72 61 73 65 01 50 7e 00 00 00 00 00 00 00   Phrase.P~.......
      // 04 00 04 00 00 00 01 00 00 00 02 00 00 00 04 00   ................
      // 5c 00 00 00 02 00 00 00 39 41 46 41 42 44 39 36   \.......9AFABD96
      // 32 30 43 45 43 34 39 31 46 38 33 44 43 45 31 32   20CEC491F83DCE12
      // 36 33 33 44 39 43 44 41 41 44 45 30 42 36 46 46   633D9CDAADE0B6FF
      // 41 32 42 42 45 30 31 32 45 38 39 32 37 33 36 39   A2BBE012E8927369
      // 35 32 35 37 43 44 43 45 39 35 37 32 41 37 30 38   5257CDCE9572A708
      // 38 42 32 43 41 43 30 33 37 44 43 38 33 33 36 33   8B2CAC037DC83363
      // 33 33 35 35 12 00 2a 00 00 00 43 6c 6f 63               3355..*...Cloc

              fdsize -= (p - fdnext);
              fdnext = p;

      // as long as our length is greater than zero but no bigger than fdsize, execute the exported decryption function
              if((len > 0) && (len < fdsize)) {
         // null terminate the end of our string, otherwise it will cause problems
         p[len] = 0;

         printf("Found stored encrypted password:\n \"%s\"\n\n", p);

         if(!SteamDecryptDataForThisMachine(p, strlen(p), decpass, sizeof(decpass), &len)) {
            printf("Password: %.*s\n", len, decpass);
         } else {
            printf("Unable to decrypt the stored password, is this the same machine it was encrypted on?\n");
         }
              }
       }

    free(fdbuff);
}

uint8_t *find_data(uint8_t *buff, int buffsz, uint8_t *str) {
    int     strsz;
    uint8_t      *limit;

    strsz = strlen(str);
    limit = buff + buffsz - strsz;

    for(; buff <= limit; buff++) {
        if(!memcmp(buff, str, strsz)) return(buff);
    }
    return(NULL);
}


Top
 Profile  
 
 Post subject: Re: How Steampwd works
PostPosted: 10 Sep 2008 11:49 

Joined: 13 Aug 2007 21:44
Posts: 4068
Location: http://aluigi.org
you can also skip the fixed path using the one specified in "HKEY_CURRENT_USER\Software\Valve\Steam\SteamPath", or you can add an autoswitcher which automatically uses "C:\Program Files\Steam" if there is not that registry key


Top
 Profile  
 
 Post subject: Re: How Steampwd works
PostPosted: 11 Sep 2008 01:08 

Joined: 16 Aug 2007 06:25
Posts: 367
Nice work on the combining desxor; code compiles and works fine. And nice work to everyone else who has contributed to the whole decryption of steam passwords. Always interesting to see how it works


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 34 posts ]  Go to page Previous  1, 2

All times are UTC [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for: