ZenHAX

Free Game Research Forum | Official QuickBMS support | twitter @zenhax | SSL HTTPS://zenhax.com
It is currently Sun Sep 24, 2017 8:37 am

All times are UTC




Post new topic  Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Wed Sep 13, 2017 7:15 pm 

Joined: Wed Aug 13, 2014 6:43 pm
Posts: 22
I'm trying to decrypt a save game via QuickBMS. Thankfully, it's a Unity game so it's easy to check how the game does it. Here's some disassembled code from it:
Code:
      TripleDESCryptoServiceProvider tripleDESCryptoServiceProvider = new TripleDESCryptoServiceProvider();
      tripleDESCryptoServiceProvider.Key = key;
      tripleDESCryptoServiceProvider.IV = array;
      tripleDESCryptoServiceProvider.Mode = CipherMode.CFB;
      tripleDESCryptoServiceProvider.Padding = PaddingMode.PKCS7;
      ICryptoTransform cryptoTransform = tripleDESCryptoServiceProvider.CreateDecryptor();
      byte[] decrypted = cryptoTransform.TransformFinalBlock(data, 0, data.Length);

I know how to get the key and IV, but i can't seem to get valid output, no matter which Encryption command i use.

Here's a sample encrypted save game, base64 encoded:
https://pastebin.com/hZrvK4Gu

And here's the sample save game decrypted, read from game memory during run-time:
https://pastebin.com/X4h5cpXX
(keep in mind that THIS IS how it should look immediately after decryption; the game does base64 encode before encryption)

So this is what my script looks like so far to get the key and IV, but as i said, the final file doesn't match up:
Code:
string KEY = "=(*&^%$#@%^**^((*(())=bc=_-420@@#$#9-2@@#$#11_)00xyz2*(*(*((=)(&"
log MEMORY_FILE 0 0
get FILESIZE asize 0
ComType base64
clog MEMORY_FILE 0 FILESIZE FILESIZE 0  # decrypt base64
get MSIZE1 asize MEMORY_FILE

get KEYADD byte MEMORY_FILE  # first byte gets added to key
string KEYADD = KEYADD
string KEY + KEYADD
print "New Key: %KEY%"

Encryption sha1 KEY
print "SHA-1 hash: %QUICKBMS_HEXHASH%"
print "SHA-1 hash binary: %QUICKBMS_HASH%"
set KEY string QUICKBMS_HASH
string KEY - 4  # 16 byte key from hash

xmath POS "MSIZE1 - 1"
goto POS MEMORY_FILE
get IVSIZE byte MEMORY_FILE  # last byte is IV size
print "IV size: %IVSIZE%"
math POS - IVSIZE
goto POS MEMORY_FILE
getdstring IVECTOR IVSIZE MEMORY_FILE

xmath DATASIZE "MSIZE1 - IVSIZE - 2"  # exclude the IV, IV size and key salt in data size
print "Data size: %DATASIZE%"

Encryption 3des-112 KEY IVECTOR 0 16
log "112key-decrypt.bin" 1 DATASIZE MEMORY_FILE


What's strange is that the actual encrypted data size is 440 bytes (without the first and last byte and the IV), but the properly decrypted file size ends up being 432 bytes. All the QuickBMS algorithms i've tried return 440 bytes.


Top
   
PostPosted: Thu Sep 14, 2017 4:06 pm 
Site Admin
User avatar

Joined: Wed Jul 30, 2014 9:32 pm
Posts: 6694
Asymmetric encryption is ever painful to understand and implement. Sorry.


Top
   
PostPosted: Thu Sep 14, 2017 4:34 pm 

Joined: Wed Aug 13, 2014 6:43 pm
Posts: 22
What's strange is that this should be a symmetric algorithm, and the full decryption routine from the game isn't all that complex: https://pastebin.com/a8ZVYEGj

It does basically what i did in the script above, then feeds it to this .NET class: https://msdn.microsoft.com/en-us/librar ... ceprovider
The CreateDecryptor() basically just creates an object of this TripleDESTransform: https://pastebin.com/Pj7SqB10

It doesn't seem to do anything out of the ordinary, and i triple-checked the Key and IV used, they're the same as the ones in game memory during run-time.
When i use the "des_ede_cfb64" OpenSSL algorithm in QuickBMS (or the "tomcrypt des3 cfb" one), at least the FIRST byte of the result is correct. The rest, however...


Top
   
PostPosted: Thu Sep 14, 2017 5:09 pm 
Site Admin
User avatar

Joined: Wed Jul 30, 2014 9:32 pm
Posts: 6694
I don't know, 3des requires a 24 bytes key.
Anyway this is the code as far as I can see but obviously doesn't work:
Code:
set KEY string "=(*&^%$#@%^**^((*(())=bc=_-420@@#$#9-2@@#$#11_)00xyz2*(*(*((=)(&"
comtype base64
get TMP asize
clog MEMORY_FILE 0 TMP TMP

get array_Length asize MEMORY_FILE
get b byte MEMORY_FILE
goto -1 MEMORY_FILE
get b2 byte MEMORY_FILE
math array_Length - 1
xmath TMP "array_Length - b2"
goto TMP MEMORY_FILE
getdstring IVEC b2 MEMORY_FILE
math TMP - 1
log MEMORY_FILE3 1 TMP MEMORY_FILE
strlen KEYSZ KEY
putvarchr KEY KEYSZ b
encryption sha1 ""
string KEY E KEY
print "KEY %QUICKBMS_HEXHASHL%"
encryption "tomcrypt des3 cfb" QUICKBMS_HASH IVEC 0 16
log "dump.dat" 0 TMP MEMORY_FILE3


Top
   
PostPosted: Thu Sep 14, 2017 7:49 pm 

Joined: Wed Aug 13, 2014 6:43 pm
Posts: 22
Wikipedia tells me that 3des can work with 16 byte keys, where key1 = first 8 bytes, key2 = last 8 bytes, and key3 = key1. That's how 3des-112 works, as opposed to 3des-168 which uses the full 24 bytes.

I made a test file via hijacking the game's encrypt function:
Code:
Ou1YIRIIK0QAqhgUCoyDwP3zoTn65+XcCqN9ASO28fU2cQXDOc/utK7viZZPkNAi7Ag=

De-Base64'd and taking the key salt and IV out of it, it should decrypt into this:

Code:
QuickBMS TripleDES encryption test!


It's easier to check immediate success with this. As i noticed before, The first byte decrypts correctly ('Q'), the rest ends up garbage. I wonder why, the triple DES implementation is standard .NET.


Top
   
PostPosted: Thu Sep 14, 2017 8:04 pm 
Site Admin
User avatar

Joined: Wed Jul 30, 2014 9:32 pm
Posts: 6694
That's interesting because by using the "3des-112" encryption the result starts with 0x8c which is, indeed, used for PKCS but also in that case all the rest is garbage.
Since the same happens also with your last test it doesn't seem a coincidence.


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 6 posts ] 

All times are UTC


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:
Powered by phpBB® Forum Software © phpBB Limited