Sunday, July 14, 2013

Dark Age of Camelot : Credentials plain text

After login screen, the login.dll executable will launch game.dll, with the function ShellExecute, but :
 .text:0041D608         push  offset password  
 .text:0041D60D         push  offset user_name  
 .text:0041D612         jz   short loc_41D640  
 .text:0041D614         movzx  ecx, byte_46254C[eax]  
 .text:0041D61B         push  ecx  
 .text:0041D61C         push  edx  
 .text:0041D61D         lea   eax, unk_4624CC[eax]  
 .text:0041D623         push  eax  
 .text:0041D624         push  offset name_dll  
 .text:0041D629         lea   ecx, [esp+3968h+CmdLine]  
 .text:0041D630         push  offset aSSDDSS ; "%s %s %d %d %s %s"  
 .text:0041D635         push  ecx       ; char *  
 .text:0041D636         call  _sprintf  
Yes login and password are passed on the command line in plain text ...

Saturday, July 13, 2013

Dark Age of Camelot : Connection

Today I wanted to understand the protocol for sending credentials to Dark Age of Camelot server.
Here is the schema :

When a client connect on a DAOC server, he will receive the following packet :
 [  0000]  1B 1B 00 08 00 65 00 00  00 11 00 00  
Format
 [  0000]  1B 1B : Version 
 [  0002]  00 08 : Size  
 [  0004]  00 65 : Message Type   
 [  0006]  00 00 : Unknow  
 [  0008]  00 11 : Version Client ?(0x11)   
 [  000A]  00 00 : Unknow_02  
All the further communications will be encrypted using a rc4 key generated by the client :
  v0 = 0;  
  do  
   key[v0++] = rand();  
  while ( v0 < 59 );  
This key is then RSA encrypted and exchanged with the server.
DAOC client (client.dll), use a old version of libtomcrypt, here is an implementation of the code used for generating the buffer used to send the rc4 key to the server.
 unsigned char daoc_pub[] =   
 {  
      0x91, 0x00, 0x00, 0x00, 0x01, 0xC1, 0x00, 0x00, 0x00, 0x02, 0x15, 0xB3,  
      0x4E, 0xAF, 0x3A, 0x93, 0xA3, 0xC7, 0x4A, 0x6A, 0xFD, 0x69, 0x55, 0x45,  
      0x1D, 0x38, 0x6A, 0x8D, 0xA1, 0xDF, 0x70, 0x1F, 0x84, 0x93, 0x23, 0xE7,  
      0x95, 0x7F, 0xFD, 0xC5, 0x78, 0xCD, 0x42, 0x58, 0x71, 0x6B, 0xA4, 0xB5,  
      0x4D, 0xDD, 0xF1, 0xC6, 0xB9, 0xAE, 0xF2, 0x41, 0x65, 0xF7, 0xD9, 0x4D,  
      0x9C, 0xC5, 0xD6, 0xEE, 0x0D, 0x98, 0xFC, 0x23, 0x7E, 0x94, 0x84, 0xE2,  
      0xD1, 0x27, 0x8C, 0x67, 0xFC, 0xB6, 0x2C, 0x5D, 0xD6, 0x60, 0xA6, 0xA9,  
      0xC3, 0xA5, 0x04, 0x11, 0xFF, 0xFE, 0x9B, 0x90, 0x27, 0x69, 0x6A, 0x60,  
      0x1D, 0x89, 0x6F, 0xFD, 0x55, 0x96, 0x4A, 0xEA, 0x97, 0x34, 0x8F, 0x69,  
      0x79, 0xBF, 0x93, 0x26, 0x18, 0xB4, 0x7C, 0x7C, 0xD5, 0xAD, 0x0B, 0xC9,  
      0xC5, 0xB7, 0x8F, 0x06, 0xB4, 0x37, 0x67, 0x94, 0xE0, 0x2A, 0x7E, 0x38,  
      0x2F, 0x28, 0x60, 0x8A, 0xDC, 0x89, 0x7D, 0x08, 0xDD, 0xBE, 0x38, 0x34,  
      0xF5, 0x78, 0xD8, 0x81, 0x58, 0x9C, 0x2B, 0x03, 0x1A, 0xE0, 0xE3, 0xF3,  
      0x19, 0xE3, 0x63, 0x81, 0xE3, 0x7C, 0xE0, 0x5D, 0xBC, 0x8E, 0x9C, 0xDC,  
      0x93, 0x74, 0x24, 0xE0, 0xF4, 0x96, 0x65, 0xFA, 0x90, 0x21, 0x06, 0x03,  
      0xD2, 0x5A, 0xC3, 0x51, 0xBF, 0x5D, 0x03, 0xB2, 0xCD, 0xD3, 0xF1, 0x6E,  
      0xCB, 0xB0, 0x25, 0x71, 0x4B, 0xC6, 0x00, 0x44, 0x7A, 0xE7, 0x03, 0x00,  
      0x00, 0x00, 0x01, 0x00, 0x01  
 };  
 void daoc_rsa_encrypt_key(unsigned char *buf, int inlen, 
                  unsigned char *output, unsigned long *outlen)  
 {  
      rsa_key key;  
      int prng_idx;  
      prng_state statesprng;  
      int res;  
      unsigned char rsa_in[196];  
      unsigned long y, rsa_size;

      if (rsa_import(daoc_pub, sizeof (daoc_pub), &key) != CRYPT_OK)  
      {  
           fprintf(stderr, "[-] rsa_import() failed\n");  
           exit(EXIT_FAILURE);  
      }  
      prng_idx = find_prng("sprng");  
      if (prng_idx == -1)   
      {  
           fprintf(stderr, "[-] find_prng() failed\n");  
           exit(EXIT_FAILURE);  
      }  
      y = 193;  
      res = rsa_pad(buf, inlen, rsa_in, &y, prng_idx, &statesprng);  
      if (res != CRYPT_OK)  
      {  
           fprintf(stderr, "[-] rsa_pad() failed : %d\n", res);  
           exit(EXIT_FAILURE);  
      }  
      rsa_size = *outlen - 2;  
      res = rsa_exptmod(rsa_in, y, output + 2, &rsa_size, PK_PUBLIC, &key);  
      if (res != CRYPT_OK)  
      {  
           fprintf(stderr, "[-] rsa_exptmod() failed : %d\n", res);  
           exit(EXIT_FAILURE);  
      }  
      *output = 0;  
      *(output + 1) = rsa_size;  
      *outlen = rsa_size + 2;  
 }  
The client will send the rc4 key block encrypted with rsa, with the following type of packet :
 [ 0000] 1B 1B : Version   
 [ 0002] 00 C7 : Size   
 [ 0004] 01 54 : Message Type (ROL8(340))  
 [ 0006] 00    : Checksum (NULL because sym key is not yet set)   
 [ 0007] 00    : Sequence number of the paquet
 [ 0008] 00 C1 : Size encrypted RSA key  
 [ 000A] XX XX : RSA encrypted key  
 ...  
Then the client can communicate the credentials of the user using the following paquet :
 [ 0000] 1B 1B : Version   
 [ 0002] 00 1D : Size   
 [ 0004] 01 2C : Message Type (ROL8(300))  
 [ 0006] 21    : Checksum  
 [ 0007] 01    : Sequence number of the paquet  
 [ 0008] 00 06 : Name Size  
 [ 000A] XX XX : Str_Name[Name Size]  
 [ 00XX] 00 02 : Password Size  
 [ 00XX] XX XX : Str_Password[Password Size]  
 [ 00XX] 00 09 : Unknow  
 [ 00XX] 00    : Unknow_02  
This paquet will be encrypted using rc4 algorithm and the key generated, but not on all paquet ! It will start at position 0x0006.

Creating library signatures for IDA

 C:\ida\flair61\bin\win>pcf tomcrypt.lib  
 tomcrypt.lib: skipped 25, total 566  
 C:\ida\flair61\bin\win>sigmake.exe tomcrypt.pat tomcrypt  
 tomcrypt.sig: modules/leaves: 541/485, COLLISIONS: 3  
 See the documentation to learn how to resolve collisions.  
Resolve collisions and it's ok (collisions problems can be found in file *.exc)

Thursday, July 11, 2013

IDA : Add structur

Declaring field of structure when they are big is a pain in the ass into IDA, idapython to the rescue !
 name = "WHATEVERYOUWANT"  
 size = 4242  
 struc_id = GetStrucIdByName(name)  
 DelStruc(struc_id)  
 struct = AddStrucEx(-1, name, 0)  
 for i in xrange(0, size / 4):  
      AddStrucMember(struct, "field_" + str(i), i * 4, 0x20000400, -1, 4)  
 if (size % 4) != 0:  
      AddStrucMember(struct,"field_" + str(size / 4),(size / 4) * 4,0x000400,-1,size % 4)  

Wednesday, July 10, 2013

Age Of Empires III : Resources anti-cheat

If one day, you try to scan the memory of age3.exe for finding your resources like wood, or food, you will not find them in memory, because they use a lame "anti-cheat" technique.
All the value are xored with those different "secret" dword :
 .data:00BBE74C Key_XOR_Resources dd 2848AC4Fh            ; // GOLD  
 .data:00BBE750         dd 94F83A35h      ; // WOOD  
 .data:00BBE754         dd 8BD84C3Fh      ; // meat  
 .data:00BBE758         dd 0AB12FBAFh     ; ??
 .data:00BBE75C         dd 20B35BCAh      ; ??
 .data:00BBE760         dd 0F9ABC42Ah     ; // XP  
 .data:00BBE764         dd 0B1A1CFDAh     ; // LEVEL  
 .data:00BBE768         dd 0F2E48210h  

Wednesday, July 3, 2013

Anno 1602

This post is an introduction to the game Anno 1602, that I'm going to study during the next blog post.


Anno 1602: Creation of a New World is a game with both real time strategyand city building elements, developed by Max Design. It's a game like "Caesar", "Colonization", "Constructor", "Exploration".
This is game is an Abandonware, so you can download it for free.
 PS C:\> Get-ChildItem "C:\Games\ANNO 1602 Version Gold" -Include *.* -Recurse | Select-Object Extension | Sort-Object -Property Extension -Unique  
 Extension  
 ---------  
 .BSH  
 .cod  
 .COL  
 .dat  
 .dll  
 .EXE  
 .GAD  
 .INC  
 .pdf  
 .rtf  
 .SCP  
 .smk  
 .szm  
 .szs  
 .WAV  
 .ZEI  

  • .BSH
  • .cod
  • .COL
  • .dat
  • .dll
  • .EXE
  • .GAD
  • .INC
  • .pdf
  • .rtf
  • .SCP
  • .smk
  • .szm
  • .szs
  • .WAV
  • .ZEI

Tuesday, July 2, 2013

Desperados : Wanted Dead or Alive - .sxt files

List of files with extension .sxt :

 PS F:\> $Dir = get-childitem -recurse F:\Game\Infogrames\Desperados\Game  
 PS F:\> $List = $Dir | where {$_.extension -eq ".sxt"}  
 PS F:\> $List | ft fullname | Format-Table  
 FullName  
 --------  
 F:\Game\Infogrames\Desperados\Game\Data\Interface\Debriefing\GameOver1.sxt
 F:\Game\Infogrames\Desperados\Game\Data\Interface\Debriefing\GameOver2.sxt
 F:\Game\Infogrames\Desperados\Game\Data\Interface\Debriefing\Victory.sxt

Example : GameOver2.xst


Size file : 13 954 bytes (0x3682)

 Offset(h)  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  
 00000000   23 01 7E 00 01 00 00 00 76 36 00 00 78 9C ED 7D #.~.....v6..xϒ}  
 00000010   4D 74 1A 67 9A 2E 63 50 95 8C ED 44 E9 F4 9C A3 Mt.gš.cP•ŒíDéôœ£  

Format specification :

+0x00 : Width = 0x0123
+0x02 : Height = 0x007E
+0x04 : IsCompressed = 0x00000001  
+0x08 : SizeCompressedData = 0x00003676  
Then the data are simply image in 16 bits format, view this POST for more info.

GameOver1.sxt

GameOver2.sxt

Victory.sxt


Desperados : Wanted Dead or Alive - RDO Resource

Inside .res file there is 'RDO ' (0x204F4452, notice the space at the end) entry resources.
Those resources can be managed like PICC, this type is like TOLG but notice the loop iteration (7 <> 5)

Pseudo-Code

  unknow = read(4)    
  if (magic_number == 0x204F4452):    
   a = read(4)   
   b = read(4)   
   for i in xrange(0, 7):   
    if ((1 &lt;&lt; i) &amp; b):   
     width = read(4)    
     height = read(4)    
     is_compressed = read(4)    
     size = read(4)    
     data = read(size)    
     if is_compressed == 1:    
      data = zlib.decompress(data)    
Data is still 16bits image.
Few extracted images :




Desperados : Wanted Dead or Alive - SLID Resource

Inside .res file there is 'SLID' (0x44494C53).
Those resources are exactly the same things as NPTF.

Few extracted images :




Desperados : Wanted Dead or Alive - NPTF Resource

Inside .res file there is 'NPTF' entry resources.
Those resources can be managed like PICC, this type is like TOLG but notice the loop iteration (6 <> 5)

Pseudo-Code

  magic_number = read(4)   
  unknow = read(4)   
  if (magic_number == 0x4E545442):   
   a = read(4)  
   b = read(4)  
   for i in xrange(0, 6):  
     if ((1 << i) & b):  
       width = read(4)   
       height = read(4)   
       is_compressed = read(4)   
       size = read(4)   
       data = read(size)   
       if is_compressed == 1:   
         data = zlib.decompress(data)   
Data is still 16bits image.
Few extracted images :




Desperados : Wanted Dead or Alive - WAVE Resource

Inside .res file there is 'WAVE' (0x45564157) entry resources.
Those resources can be managed like TEXT, the only difference is that string are not of type wchar_t.

WAVE specification

 +0x00 : Unknow_00 (Maybe index)  
 +0x04 : Nb entry Text  
 +0x06 : Size Entry  
 +0x08 : Buffer [Size Entry]   

Pseudo-Code

  magic_number = read(4)    
  unknow = read(4)    
  if (magic_number == 0x45564157):    
   unknow = read(4)    
   nb_TEXT_entry = read(2)    
   for i in xrange(0, nb_TEXT_entry ):    
   size_str = read(2)    
   str = read(size_str)  
Few extracted path :
 Dialogues\Phase1.wav  
 Dialogues\Phase2.wav  
 Dialogues\Phase3.wav  
 Dialogues\Phase4.wav  
 Dialogues\Phase5.wav  
 Dialogues\Phase6.wav  
 Dialogues\Phase7.wav  
 Dialogues\Phase8.wav  
 Dialogues\Phase9.wav  
 Dialogues\PhaseFake.wav  

Desperados : Wanted Dead or Alive - TEXT Resource

Inside .res file there is 'TEXT' (0x54584554) entry resources.

TEXT specification

 +0x00 : Unknow_00 (Maybe index)  
 +0x04 : Nb entry Text  
 +0x06 : Size Entry  
 +0x08 : wchar_t Buffer [Size Entry]   

Pseudo-Code

  magic_number = read(4)   
  unknow = read(4)   
  if (magic_number == 0x54584554):   
   unknow = read(4)   
   nb_TEXT_entry = read(2)   
   for i in xrange(0, nb_TEXT_entry ):   
    size_str = read(2)   
    str = read(size_str * 2)  
Few extracted strings :
 Bonjour vous tes avec le professeur Oscar Toffel pour votre 746ime leon de patois  
 Entrainez vous rptez la phrase qui suit puis enregistrez vous sur K7 et envoyez la nous donc.  
 Le meilleur accent il gagnera un disque.  
 Attention rptez aprs moi.  
 Truc incomprhensible, si vous comprenez envoyez moi une carte postale.  
 Allez ! Encore une fois pour voir.  
 Oh lalala ca c'est donc pas facile.  
 Tais toi donc et bosse un petit peu ! Rptes cette phrase non di diou  
 Allez la balle est dans votre camp maintenant, a vous de jouer. Bonne Chance.  
 Je vais pouvoir rcuprer mon matriel.  
 J'ai laiss mes clefs dans la cariole, peut tre qu'en crochetant la porte...  
 Attention ! Sam ! Derriere-toi il y a un crocodile !  
 Je vais essayer de l'endormir l'aide de mes fioles.  
 Est-ce que c'est vraiment efficace ? Je suis curieux de voir a...  
 Je vais te faire un pansement, un bisou sur le bobo et tout ira bien.  
 A quoi sert le porte manteau qu'il y a dans ton sac ?  
 Ca sert a tromper les cowboys qui veulent ma peau.  
 Pour les fioles, je peux mme endormir une cible lointaine.  
 Debout Sam ! Il est temps de se remettre en route mais auparavant, montres moi de quoi tu es capables.  
 Peut-tu faire exploser prcisement ton baton de dynamite de l'autre ct de la rivire ?  
 Belle chute.. On ferait mieux de le ligoter avant de le cacher.  
 Arrtes, on en aura peut-tre besoin plus tard, pour piger les ennemis ou effrayer les chevaux.  
 Le chemin est bloqu...  ...je m'en occupe, je vais tout dblayer...  
 WAHAHAHAHAHAHAHAHAHAH !  
 Nous voila, devant La Fortezza, la prison la plus sure de cet tat.  
 Et c'est ici ou ils ont emprisonne Sanchez. Mais on va le dlivrer...  
 Je ne comprends pas: On a fait pas mal d'efforts pour trouver ce bandit et pour le mettre sous les verroux.  
 Mais maintenant tu dis que l'on va le liberer de nouveau. Il est tout coup devenus ton pote, ou quoi?  

Desperados : Wanted Dead or Alive - CUR Resource

Inside .res file there is 'CUR ' (notice the space at the end) entry resources.
Those resources can be managed like PICC.

Pseudo-Code

  magic_number = read(4)   
  unknow = read(4)   
  if (magic_number == 0x20525543):   
   unknow_1 = read(4)  
   unknow_2 = read(2)  
   unknow_3 = read(2)  
   unknow_4 = read(2)  
   unknow_5 = read(2)  
   nb_CUR_entry = read(4)   
   for i in xrange(0, nb_CUR_entry ):   
    width = read(4)   
    height = read(4)   
    is_compressed = read(4)   
    size = read(4)   
    data = read(size)   
    if is_compressed == 1:   
     data = zlib.decompress(data)   
Data is still 16 bits image.
Few extracted images :




Desperados : Wanted Dead or Alive - BTTN Resource

Inside .res file there is 'BTTN' entry resources.
Those resources can be managed like PICC, this type is like TOLG but notice the loop iteration (4 <> 5)

Pseudo-Code

  magic_number = read(4)   
  unknow = read(4)   
  if (magic_number == 0x4654504E):   
   a = read(4)  
   b = read(4)  
   for i in xrange(0, 4):  
     if ((1 << i) & b):  
       width = read(4)   
       height = read(4)   
       is_compressed = read(4)   
       size = read(4)   
       data = read(size)   
       if is_compressed == 1:   
         data = zlib.decompress(data)   
Data is still 16bits image.
Few extracted images :




Desperados : Wanted Dead or Alive - TOGL Resource

Inside .res file there is 'TOGL' entry resources.
Those resources can be managed like PICC, but with few differences.

Pseudo-code

  magic_number = read(4)   
  unknow = read(4)   
  if (magic_number == 0x4C474F54):   
   a = read(4)  
   b = read(4)  
   for i in xrange(0, 5):  
     if ((1 << i) & b):  
       width = read(4)   
       height = read(4)   
       is_compressed = read(4)   
       size = read(4)   
       data = read(size)   
       if is_compressed == 1:   
         data = zlib.decompress(data)   
Data is still 16 bits image.
Few extracted images :




Desperados : Wanted Dead or Alive - PIC Resource

Inside .res file there is 'PIC ' (notice the space at the end) entry resources.
Those resources can be managed like PICC.
The only difference is this resource got only one entry.

Pseudo-code

  magic_number = read(4)   
  unknow = read(4)   
  if (magic_number == 0x20434950):   
   unknow = read(4)   
   width = read(4)   
   height = read(4)   
   is_compressed = read(4)   
   size = read(4)   
   data = read(size)   
   if is_compressed == 1:   
     data = zlib.decompress(data)   
Data is still 16 bits image.
Few extracted images :







Desperados : Wanted Dead or Alive - PICC Resource

Inside .res file there is 'PICC' entry resources.

PICC specification

 +0x00 : Unknow  
 +0x04 : Nb PICC entry  
 +0x08 : Entry Data (view class CResEntry)  

CResEntry

An entry can be represented by this structure :
 00000000 CResEntry    struc ; (sizeof=0xC)  
 00000000 Width      dw ?  
 00000002 Height     dw ?  
 00000004 IsCompressed  dd ?  
 00000008 SizeFile    dd ?  
 0000000C CResEntry    ends  
If the field IsCompressed is set to 1, data are compressed using zlib version 1.1.3.

Pseudo-Code to read PICC

 magic_number = read(4)  
 unknow = read(4)  
 if (magic_number == 0x43434950):  
   unknow = read(4)  
   nb_PICC_entry = read(4)  
   for i in xrange(0, nb_PICC_entry):  
     width = read(4)  
     height = read(4)  
     is_compressed = read(4)  
     size = read(4)  
     data = read(size)  
     if is_compressed == 1:  
       data = zlib.decompress(data)  
Then the data are simply image in 16 bits format, you can convert it into 24 bits, with the following pseudo-code :
 void setRGB(png_byte *ptr, unsigned char r,   
                unsigned char g, unsigned char b)  
 {  
     ptr[0] = r;  
     ptr[1] = g;  
     ptr[2] = b;  
 }  
 ...  
 int x, y;  
 for (y = 0 ; y < height ; y++)  
 {  
     for (x = 0 ; x < width ; x++)  
     {  
         int a;  
         unsigned short *tab;  
         unsigned short color;  
         a = = (x + (y * width)) * 2;  
         tab = (unsigned short*)(buffer + a);  
         color = *tab;  
         setRGB(&(row[x * 3]),   
                     (color >> 11 << 8) / 32,   
                     (((color >> 5) & 0x3F) << 8) / 64,   
                     ((color & 0x1F) << 8) / 32);  
     }  
     png_write_row(png_ptr, row);  
 }  

Monday, July 1, 2013

Desperados : Wanted Dead or Alive - Extracted Resources

Some randoms resources that I managed to extract :





more info coming soon...

Desperados : Wanted Dead or Alive - .res / .RES files

List of files with extension .res or .RES :
 PS F:\> $Dir = get-childitem -recurse F:\Game\Infogrames\Desperados\Game  
 PS F:\> $List = $Dir | where {$_.extension -eq ".res"}  
 PS F:\> $List | ft fullname | Format-Table  
 FullName  
 --------  
 F:\Game\Infogrames\Desperados\Game\Data\Interface\DEFAULT.RES  
 F:\Game\Infogrames\Desperados\Game\Data\Interface\Texts.res  
 F:\Game\Infogrames\Desperados\Game\Data\Sounds\Expressions\Expressions.res  

Method to open .res file :
 005D8270 ReadResFile proc near  

File format specification

 +0x00 : Magic Number  
 +0x04 : Archive Version  
 +0x08 : Nb Entry  
 +0x0C : Format  
 +0x10 : Unknow_0  
 ....
Magic number must be equal to 0x53455253 ('SERS').
ArchiveVersion must be equal to 0x100 (256).
Format can be equal to :

  • 0x45564157 ('EVAW') : 0x005D96A0 WaveResFile proc near
  • 0x43434950 ('CCIP') : 0x005D8D50 PiccResFile proc near
  • 0x44494C53 ('DILS') : 0x005DA0E0 SlidResFile proc near
  • 0x20525543 (' RUC') : 0x005D9CA0 CurResFile proc near
  • 0x20434950 (' CIP') : 0x005D8A10 PicResFile proc near
  • 0x204F4452 (' ODR') : 0x005DA800 RdoResFile proc near
  • 0x4E545442 ('NTTB') : 0x005DA470 BttnResFile proc near
  • 0x4654504E ('FTPN') : 0x005D8630 NptfResFile proc near
  • 0x4C474F54 ('LGOT') : 0x005DAB90 ToglResFile proc near
  • 0x54584554 ('TXET') : 0x005D90B0 TextResFile proc near
Refer to other articles to understand each entry type.

Sunday, June 30, 2013

Desperados : Wanted Dead or Alive - Files Extension

All files extensions find inside game folder :

 PS > Get-ChildItem -recurse F:\Game\Infogrames\Desperados\Game\* | Select-Object Extension | Sort-Object Extension | Get-Unique -asString  
 Extension  
 ---------  
 .cfg  
 .cpg  
 .dat  
 .dll  
 .dvd  
 .dvf  
 .dvm  
 .exe  
 .fnt  
 .fxg
 .log  
 .map  
 .pak  
 .res  
 .RES  
 .sbk  
 .scb  
 .stf  
 .sxt  
 .tmp  
 .wav  


Saturday, June 29, 2013

Desperados : Wanted Dead or Alive - Debug String

Inside the binary you can find "debug" strings, which are not related to the game Desperados...
If you know the game "Death Valley" or have more informations please leave a comment, thx.
 C:\\Projets\\Death Valley\\DVArmsTrader.cpp            
 C:\\Projets\\Death Valley\\DVArmsTrader.cpp            
 C:\\Projets\\Death Valley\\DVArtificialBonhomie.cpp        
 C:\\Projets\\Death Valley\\DVArtificialBonhomie.cpp        
 C:\\Projets\\Death Valley\\DVArtificialIntelligence.cpp      
 C:\\Projets\\Death Valley\\DVArtificialIntelligence.cpp      
 C:\\Projets\\Death Valley\\DVArtificialMalignity.cpp       
 C:\\Projets\\Death Valley\\DVArtificialMalignity.cpp       
 C:\\Projets\\Death Valley\\DVBeacon.cpp              
 C:\\Projets\\Death Valley\\DVCampaign.cpp             
 C:\\Projets\\Death Valley\\DVCharacterProfile.cpp         
 C:\\Projets\\Death Valley\\DVCooper.cpp              
 C:\\Projets\\Death Valley\\DVCustomSaveGame.cpp          
 C:\\Projets\\Death Valley\\DVDialogue.cpp             
 C:\\Projets\\Death Valley\\DVDialogue.cpp             
 C:\\Projets\\Death Valley\\DVDoc.cpp               
 C:\\Projets\\Death Valley\\DVDrawManager.cpp           
 C:\\Projets\\Death Valley\\DVDynamicSaveGame.cpp         
 C:\\Projets\\Death Valley\\DVDynamicSaveGame.cpp         
 C:\\Projets\\Death Valley\\DVElement.cpp             
 C:\\Projets\\Death Valley\\DVElementActor.cpp           
 C:\\Projets\\Death Valley\\DVElementActorAnimal.cpp        
 C:\\Projets\\Death Valley\\DVElementActorAnimal.cpp        
 C:\\Projets\\Death Valley\\DVElementActorHorse.cpp        
 C:\\Projets\\Death Valley\\DVElementActorHorse.cpp        
 C:\\Projets\\Death Valley\\DVElementActorHuman.cpp        
 C:\\Projets\\Death Valley\\DVElementActorNPC.cpp         
 C:\\Projets\\Death Valley\\DVElementActorNPC.cpp         
 C:\\Projets\\Death Valley\\DVElementFX.cpp            
 C:\\Projets\\Death Valley\\DVElementMobile.cpp          
 C:\\Projets\\Death Valley\\DVElementObject.cpp          
 C:\\Projets\\Death Valley\\DVElementObject.cpp          
 C:\\Projets\\Death Valley\\DVElementProjectile.cpp        
 C:\\Projets\\Death Valley\\DVElementProjectile.cpp        
 C:\\Projets\\Death Valley\\DVElementTarget.cpp          
 C:\\Projets\\Death Valley\\DVEngine.cpp              
 C:\\Projets\\Death Valley\\DVEngine.cpp              
 C:\\Projets\\Death Valley\\DVFastFindGrid.cpp           
 C:\\Projets\\Death Valley\\DVFastFindGrid.cpp           
 C:\\Projets\\Death Valley\\DVFirearm.cpp             
 C:\\Projets\\Death Valley\\DVFrameHolder.cpp           
 C:\\Projets\\Death Valley\\DVGame.cpp               
 C:\\Projets\\Death Valley\\DVGraphicConfig.cpp          
 C:\\Projets\\Death Valley\\DVGroundMark.cpp            
 C:\\Projets\\Death Valley\\DVHikingGuide.cpp           
 C:\\Projets\\Death Valley\\DVJane.cpp               
 C:\\Projets\\Death Valley\\DVKeyConfig.cpp            
 C:\\Projets\\Death Valley\\DVKung.cpp               
 C:\\Projets\\Death Valley\\DVLine.cpp               
 C:\\Projets\\Death Valley\\DVLoadingScreen.cpp          
 C:\\Projets\\Death Valley\\DVMenu.cpp               
 C:\\Projets\\Death Valley\\DVMinimap.cpp             
 C:\\Projets\\Death Valley\\DVOrder.cpp              
 C:\\Projets\\Death Valley\\DVPatch.cpp              
 C:\\Projets\\Death Valley\\DVPath.cpp               
 C:\\Projets\\Death Valley\\DVPathFinder.cpp            
 C:\\Projets\\Death Valley\\DVPlayerProfileManager.cpp       
 C:\\Projets\\Death Valley\\DVPositionInterface.cpp        
 C:\\Projets\\Death Valley\\DVPowderMark.cpp            
 C:\\Projets\\Death Valley\\DVPowderMark.cpp            
 C:\\Projets\\Death Valley\\DVPsychoanalyst.cpp          
 C:\\Projets\\Death Valley\\DVPsychoanalyst.cpp          
 C:\\Projets\\Death Valley\\DVSanchez.cpp             
 C:\\Projets\\Death Valley\\DVSaveGameManager.cpp         
 C:\\Projets\\Death Valley\\DVScript.cpp              
 C:\\Projets\\Death Valley\\DVSector.cpp              
 C:\\Projets\\Death Valley\\DVSequence.cpp             
 C:\\Projets\\Death Valley\\DVSequenceElement.cpp         
 C:\\Projets\\Death Valley\\DVSequenceManager.cpp         
 C:\\Projets\\Death Valley\\DVSequenceManager.cpp         
 C:\\Projets\\Death Valley\\DVShadowPolygon.cpp          
 C:\\Projets\\Death Valley\\DVSound.cpp              
 C:\\Projets\\Death Valley\\DVSound.cpp              
 C:\\Projets\\Death Valley\\DVSoundCache.cpp            
 C:\\Projets\\Death Valley\\DVSoundCache.cpp            
 C:\\Projets\\Death Valley\\DVSoundCacheEntry.cpp         
 C:\\Projets\\Death Valley\\DVSoundConfig.cpp           
 C:\\Projets\\Death Valley\\DVSoundGeometry.cpp          
 C:\\Projets\\Death Valley\\DVSoundSource.cpp           
 C:\\Projets\\Death Valley\\DVSoundSourceClock.cpp         
 C:\\Projets\\Death Valley\\DVSoundSourceManager.cpp        
 C:\\Projets\\Death Valley\\DVSprite.cpp              
 C:\\Projets\\Death Valley\\DVTitBit.cpp              
 C:\\Projets\\Death Valley\\DVUIRendererAlphaConstantCustom.cpp  
 C:\\Projets\\Death Valley\\DVUIRendererCustom.cpp         
 C:\\Projets\\Death Valley\\DVWill.cpp               
 C:\\Projets\\Death Valley\\Launcher.cpp              
 C:\\Projets\\Death Valley\\SBFramePannelFX.cpp          
 C:\\Projets\\Death Valley\\SBLIBNG\\SBDrawManager.cpp       
 C:\\Projets\\Death Valley\\SBLIBNG\\SBEvent.cpp          
 C:\\Projets\\Death Valley\\SBLIBNG\\SBFile.cpp          
 C:\\Projets\\Death Valley\\SBLIBNG\\SBFont.cpp          
 C:\\Projets\\Death Valley\\SBLIBNG\\SBGeoBoundingBox2D.cpp    
 C:\\Projets\\Death Valley\\SBLIBNG\\SBGeoPoint2D.cpp       
 C:\\Projets\\Death Valley\\SBLIBNG\\SBInput.cpp          
 C:\\Projets\\Death Valley\\SBLIBNG\\SBPicture.cpp         
 C:\\Projets\\Death Valley\\SBLIBNG\\SBResourceManager.cpp     
 C:\\Projets\\Death Valley\\SBLIBNG\\SBThreadedInput.cpp      
 C:\\Projets\\Death Valley\\SBLIBNG\\SBUIInputFieldText.cpp    
 C:\\Projets\\Death Valley\\SBLIBNG\\SBUIRenderer.cpp       
 C:\\Projets\\Death Valley\\SBLIBNG\\SBUIRendererInputField.cpp  
 C:\\Projets\\Death Valley\\SBLIBNG\\SBUIRendererListbox.cpp    
 C:\\Projets\\Death Valley\\SBLibNG/SBWidgetInputField.h      
 C:\\Projets\\Death Valley\\SBProfiler.cpp             
 C:\\Projets\\Death Valley\\dvelementactorpc.cpp          
If you are bored of the MessageBox about the CD, nop this :
 .text:005B5215         push  edi  
 .text:005B5216         call  eax ; dword_693224  

Friday, June 28, 2013

Desperados : Wanted Dead or Alive - Profiles file

This first blog post about the game "Desperados : Wanted Dead or Alive" will describe file format of saved game.
The main file can be found in the directory : "\Data\Savegame" under the name : "Profiles".
All this work was made with version 1.0 of the game.

File format specification :

 +0x00 : Magic Number  
 +0x04 : Version  
 +0x08 : Unknow_00  
 +0x0C : Number of profile's entry  
 +0x10 : Profiles entry  
 ...  

Magic number must be equal to 0x50524F46 ('PROF').
Version in our case is  0x305 (773).
At offset 0x10 start the first profile entry.

CProfile

The constructor of the class CProfile can be found at this address :
 00548EF0 ; void *__thiscall ctor_CProfile(CProfile *this)

The size of this class is 0xBC (188) :
 .text:0054A3BD push  0BCh  
 .text:0054A3C2 call  ??2@YAPAXI@Z  ; operator new  

Method for reading profile entry can be found at this address :
 005496D0 ; char __thiscall ReadProfile(CProfile *this, CFile *a2)  

Profile entry specification :

 +0x00  : Numero of directory entry  
 +0x04  : Current mission  
 +0x08  : Number of mission accomplished  
 +0x0C  : Time elapsed  
 +0x10  : Shortcut config number 1  
 +0xXX  : Shortcut config number 2  
 +0xXX  : Sound configuration  
 +0xXX  : Video configuration  
 +0xXX  : Name of the player  
 +0xXX  : Unknow_00  
 +0xXX  : Number of saved games  
 +0xXX  : Saved game entry  
Method to read profile :
005496D0 ; char __thiscall ReadProfile(CProfile *this, CFile *a2)

Numero of directory entry

Numero of directory entry describe the number of the folder ("Profile_%d") associated with the profile, for example directory "Profile_01", saved game file associated with the profile are saved here.

Shortcut config

Shortcut config is like a serialized class of type CShortcutConfig, the size of this member can change, there is 2 configuration for the shortcuts.
Method to read shortcut configuration :
005105F0 ; char __thiscall ReadProfileShortcutConfig(CShortcutConf *this, CFile *a2)

Sound configuration

Sound configuration is a class of type CSoundConfig :
 00000000 CSoundConf   struc ; (sizeof=0xC)  
 00000000 field_0     dw ?  
 00000002 field_2     dw ?  
 00000004 field_4     dw ?  
 00000006 field_6     dw ?  
 00000008 field_8     dw ?  
 0000000A field_A     db ?  
 0000000B field_B     db ?  
 0000000C CSoundConf   ends  
Method to read sound configuration :
00585D10 ; char __thiscall ReadProfileSoundConfig(CSoundConf *this, CFile *a2)

Video configuration is a class of type CVideoConfig :

 00000000 CVideoConf   struc ; (sizeof=0xC)  
 00000000 Animation    db ?  
 00000001 Shadow     db ?  
 00000002 Angle      db ?  
 00000003 Effect     db ?  
 00000004 CResolution   CVideoReso ?  
 0000000C CVideoConf   ends  
 0000000C  
 00000000 ; -----------------------------------  
 00000000  
 00000000 CVideoReso   struc ; (sizeof=0x8)  
 00000000 reso_X     dd ?  
 00000004 reso_Y     dd ?  
 00000008 CVideoReso   ends  
Method to read video configuration :
0050CBE0 ; char __thiscall ReadProfileVideoConfig(CVideoConf *this, CFile *a2)

Name of player

Name of player is stored under a structure :
 +0x00 : SizeName  
 +0x04 : wchar_t [SizeName]  

Then come the number of saved games, and entry of each saved game.

CFile

And for those wondering about the class CFile :
00000000 CFile           struc ; (sizeof=0x58)
00000000 stream          dd ?                    ; offset
00000004 mode_read       dd ?
00000008 SizeFile        dd ?
0000000C field_C         dd ?
00000010 ArchiveVersion  dd ?
00000014 error_status    dd ?
00000018 field_18        CString ?
00000028 field_28        dd ?
0000002C field_2C        dd ?
00000030 field_30        dd ?
00000034 field_34        dd ?
00000038 field_38        dd ?
0000003C field_3C        dd ?
00000040 lpCreationTime  _FILETIME ?
00000048 lpLastAccessTime _FILETIME ?
00000050 lpLastWriteTime _FILETIME ?