0

I'm reverse engineering a game's .pak file format and trying to reconstruct its decryption process in C or Python.

Here’s what I extracted from IDA pseudocode. The function DecryptPak() uses a custom 16-byte key and two main routines: dec_data() to expand the key, and dec_block2() to decrypt 16-byte blocks.

This is the full decompiled code:

Keys3           DCD 0x46970E9C, 0x4BC0685E, 0x59056186, 0xBCA2491E

dword_106D1CB50 DCD 0xEB92B, 0x3A0AE783, 0x9E3B5C67, 0xADDBDABF, 0x7B7484CB
__const:0000000106D1CB50                                         ; DATA XREF: dec_data+7C↑o
__const:0000000106D1CB50                 DCD 0x49156C63, 0xC79AB5E7, 0x79EC9CFF, 0x1725BEAB, 0x2FB89CA3
__const:0000000106D1CB50                 DCD 0x24808AD7, 0xDDD28B1F, 0x4740DA4B, 0xBBC3EA73, 0x247B30E7
__const:0000000106D1CB50                 DCD 0x91BE385F, 0x401248B, 0x45FCD3A3, 0x530B4CE7, 0xC68DD35F
__const:0000000106D1CB50                 DCD 0xE3D16C2B, 0x4F698C13, 0x6B92C747, 0x769EFB1F, 0x4C73BE9B
__const:0000000106D1CB50                 DCD 0xC942B193, 0xAD80D827, 0x372FB33F, 0x13CB6AAB, 0x2BDC0AA3
__const:0000000106D1CB50                 DCD 0x17A4A247, 0xD5E96CAF

keys1           DCB 0x34, 0x66, 0x25, 0x74, 0x89, 0x78, 0xE4, 0xA9, 0x5A
__const:0000000106D1CA3E                                         ; DATA XREF: decrypt_uint32_t+8↑o
__const:0000000106D1CA3E                                         ; decrypt_uint32_t2+8↑o
__const:0000000106D1CA3E                 DCB 0x41, 0xBC, 0x7A, 0xD6, 0x16, 0x21, 0x23, 0x4D, 0x61
__const:0000000106D1CA3E                 DCB 0xDA, 0x94, 0x9B, 0xDF, 0x13, 0x3C, 0x69, 0x3A, 0x31
__const:0000000106D1CA3E                 DCB 0xA, 0x5F, 0xD7, 0x99, 0x95, 0xF1, 0xAE, 0x72, 0x3D
__const:0000000106D1CA3E                 DCB 7, 0x60, 0x24, 0xB6, 0x98, 0xEE, 0xC4, 0xA2, 0x2D
__const:0000000106D1CA3E                 DCB 0x88, 0xDD, 0x8D, 4, 0xEA, 0xBB, 0x11, 0xCA, 0x3E
__const:0000000106D1CA3E                 DCB 0x5D, 0xA1, 0xF6, 0x3F, 0xB0, 0x97, 0x80, 0x47, 0x2B
__const:0000000106D1CA3E                 DCB 0xA6, 0xE6, 0xF7, 0xD9, 0xB1, 0x59, 0xC0, 0x7C, 0xBE
__const:0000000106D1CA3E                 DCB 0x54, 0x28, 0xB7, 0x7E, 0x4F, 0xF8, 0x43, 0x6E, 0xA0
__const:0000000106D1CA3E                 DCB 0x50, 0xE, 0xF5, 0x90, 0xB8, 0xFB, 0xA3, 0x7B, 0x62
__const:0000000106D1CA3E                 DCB 0x19, 0x46, 3, 0x2A, 0xB9, 0x8F, 0x9F, 0x77, 0xB4
__const:0000000106D1CA3E                 DCB 0x5B, 0x83, 0x87, 8, 0xEB, 0xE2, 0x1E, 0x42, 0xF0
__const:0000000106D1CA3E                 DCB 0xF, 0xE8, 0x71, 0x6A, 0x75, 0xAD, 0x55, 0x1F, 0xB5
__const:0000000106D1CA3E                 DCB 0xAB, 0x33, 0xFA, 0x7F, 0x15, 0xBD, 0x85, 0xD8, 6
__const:0000000106D1CA3E                 DCB 0x68, 0xB3, 0x52, 0x30, 0x48, 0xB, 0, 0xED, 0xEF, 0xB2
__const:0000000106D1CA3E                 DCB 0x57, 0x8E, 0xE7, 0x6C, 0xD5, 0xE5, 0x2E, 0x53, 0x82
__const:0000000106D1CA3E                 DCB 5, 0xF9, 0x81, 0xF4, 0x56, 0xBF, 0x8C, 0x4B, 0xE3
__const:0000000106D1CA3E                 DCB 0xDB, 0x4A, 0x91, 0x4C, 0x2C, 0xD3, 0x40, 0x29, 0x4E
__const:0000000106D1CA3E                 DCB 0x20, 0x14, 0x36, 0x79, 9, 0x6F, 0xD1, 0x37, 0xE0
__const:0000000106D1CA3E                 DCB 0x39, 0xC, 0x8A, 0x92, 0x38, 0x12, 0x35, 0x6D, 0xE1
__const:0000000106D1CA3E                 DCB 0xFD, 0x93, 0x9A, 0x17, 0xD4, 0xC9, 0x9C, 0x6B, 0x84
__const:0000000106D1CA3E                 DCB 0x26, 0x9D, 0xAF, 0x76, 0xC1, 0x9E, 0xD0, 0x96, 0xC5
__const:0000000106D1CA3E                 DCB 0xCB, 0xE9, 0x73, 0x49, 0xD2, 0xCD, 0x64, 0xC3, 0xC7
__const:0000000106D1CA3E                 DCB 1, 0x7D, 0xF3, 0xAC, 0xFC, 0xDE, 0xA4, 0x44, 0x32
__const:0000000106D1CA3E                 DCB 0x1B, 0xC2, 0xBA, 0x1C, 2, 0xC6, 0x27, 0x45, 0x8B
__const:0000000106D1CA3E                 DCB 0xF2, 0x18, 0xA7, 0x10, 0x51, 0x1D, 0xC8, 0xCF, 0x63
__const:0000000106D1CA3E                 DCB 0xFF, 0x2F, 0xD, 0x58, 0xCE, 0x65, 0xA5, 0xDC, 0x1A
__const:0000000106D1CA3E                 DCB 0x3B, 0x86, 0xFE, 0x22, 0x5C, 0xA8, 0x5E, 0x67, 0xAA
__const:0000000106D1CA3E                 DCB 0xEC, 0x70, 0xCC, 0, 0

__int64 __fastcall dec_data(__int64 result, __int64 a2)
{
  __int64 v3; // x20
  __int64 i; // x21
  __int64 v5; // x21
  __int64 v6; // x20
  __int64 *v7; // x21
  int v8; // w9
  __int64 v9[2]; // [xsp+8h] [xbp-48h] BYREF

  v9[0] = 0LL;
  v9[1] = 0LL;
  if ( result && a2 )
  {
    v3 = result;
    for ( i = 0LL; i != 4; i = v5 + 1 )
    {
      result = swap_end(v3, i);
      *((_DWORD *)v9 + v5) = Keys3[v5] ^ result;
    }
    v6 = 0LL;
    v7 = v9;
    while ( v6 != 32 )
    {
      result = decrypt_uint32_t2(*((_DWORD *)v7 + (((_BYTE)v6 + 2) & 3)) ^ *((_DWORD *)v7 + ((v6 + 1) & 3)) ^ (unsigned int)(*((_DWORD *)v7 + (((_BYTE)v6 - 1) & 3)) ^ dword_106D1CB50[v6]));
      v8 = *((_DWORD *)v7 + (v6 & 3)) ^ result;
      *((_DWORD *)v7 + (v6 & 3)) = v8;
      *(_DWORD *)(a2 + 4 * v6++) = v8;
    }
  }
  return result;
}

__int64 __fastcall decrypt_uint32_t2(unsigned int a1)
{
  int v1; // w9
  int v2; // w8
  unsigned __int64 v3; // t2

  v1 = 0;
  v2 = 0;
  while ( v1 != 32 )
  {
    v2 |= keys1[(unsigned __int8)(a1 >> v1)] << v1;
    v1 += 8;
  }
  HIDWORD(v3) = v2;
  LODWORD(v3) = v2;
  return (unsigned int)(v3 >> 9) ^ __ROR4__(v2, 19) ^ v2;
}

__int64 __fastcall dec_block2(__int64 result, __int64 a2, __int64 a3)
{
  __int64 v5; // x21
  __int64 i; // x22
  __int64 v7; // x22
  unsigned int *v8; // x20
  __int64 *v9; // x21
  unsigned int v10; // t1
  __int64 v11; // x8
  __int64 j; // x9
  __int64 v13[2]; // [xsp+8h] [xbp-48h] BYREF

  v13[0] = 0LL;
  v13[1] = 0LL;
  if ( result && a2 && a3 )
  {
    v5 = result;
    for ( i = 0LL; i != 4; ++i )
    {
      result = swap_end(v5, i);
      *((_DWORD *)v13 + i) = result;
    }
    v7 = 0LL;
    v8 = (unsigned int *)(a2 + 124);
    v9 = v13;
    while ( v7 != 32 )
    {
      v10 = *v8--;
      result = decrypt_uint32_t(*((_DWORD *)v9 + (((_BYTE)v7 + 2) & 3)) ^ *((_DWORD *)v9 + ((v7 + 1) & 3)) ^ *((_DWORD *)v9 + (((_BYTE)v7 - 1) & 3)) ^ v10);
      *((_DWORD *)v9 + (v7++ & 3)) ^= result;
    }
    v11 = a3 + 1;
    for ( j = 12LL; j != -4; j -= 4LL )
    {
      *(_DWORD *)(v11 - 1) = bswap32(*(_DWORD *)((char *)v13 + j));
      v11 += 4LL;
    }
  }
  return result;
}

__int64 __fastcall decrypt_with_key(unsigned int a1)
{
  int v1; // w9
  int v2; // w8
  unsigned __int64 v3; // t2

  v1 = 0;
  v2 = 0;
  while ( v1 != 32 )
  {
    v2 |= keys1[(unsigned __int8)(a1 >> v1)] << v1;
    v1 += 8;
  }
  HIDWORD(v3) = v2;
  LODWORD(v3) = v2;
  return (unsigned int)(v3 >> 22) ^ __ROR4__(v2, 30) ^ __ROR4__(v2, 14) ^ __ROR4__(v2, 8) ^ v2;
}

__int64 __fastcall DecryptPak(__int64 a1, unsigned int a2, __int64 a3)
{
  __int64 result; // x0
  unsigned int i; // w21
  int v7; // w21
  __int128 v8[8]; // [xsp+0h] [xbp-B0h] BYREF

  memset(v8, 0, sizeof(v8));
  result = dec_data(a3, (__int64)v8);
  for ( i = 0; i < a2; i = v7 + 16 )
    result = dec_block2(a1 + i, (__int64)v8, a1 + i);
  return result;
}


My goal: How should I implement this decryption chain in clean C or Python? Does the logic of key expansion and the round loop look similar to known lightweight ciphers, or is it a custom algorithm?

3
  • I'm still waiting for answer 😞 Commented Jul 26 at 9:13
  • where is the lib that gets this pseudocode located? Commented Oct 18 at 7:30
  • "I'm still waiting for answer": Well, apparently no visitor found a match between what you show us and some known algorithms. You could invest some time to clean up the automatically recompiled source and make it easier for us to grasp. Commented Oct 20 at 5:54

1 Answer 1

0

I found it. it is the SM4 cipher, but with a custom substitution table (S-box) instead of the standard one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.