美文网首页
菱菱邦sd字段白盒AES逆向

菱菱邦sd字段白盒AES逆向

作者: ever_hu | 来源:发表于2022-01-07 10:59 被阅读0次

    菱菱邦sd字段白盒AES逆向

    decheckcode逆向

    so初步分析

    ida打开libencrypt.so,函数窗口搜索Java

    image-20211230145549076

    说明是静态注册的,打开checkcode发现有近2000行代码,那还是先看decheckcode吧。

    image-20220106165938633

    77上按r将其转为字符

    image-20220106170045809

    这就很明显了,由于sd字符串都是以M开头的,所以调用的是aes_decrypt1_ptr

    image-20220106211253902 image-20220106170210672

    看起来是个AES-128-CBC解密,看看CWAESCipher::WBACRAES128_DecryptCBC

    image-20220106170323460

    结构很清晰了,继续看看

    image-20220106211733714 image-20220106211821169

    this的值是off_1ADC0

    image-20220106212010060 image-20220106212117547 image-20220106212202604
    unidbg分析

    so初步看完了,接下来就是结合unidbg进行分析

    先hook看看base64_decode

    image-20220106215444542

    由于base64_decode多次被调用到,所以选择先在sub_138AC下断点

    public LingLingBang() {
      //...
        emulator.attach().addBreakPoint(module.base + 0x138AC+1);
    }
    

    然后输入blr在函数返回处下断点,c继续运行到函数返回处,这时候输入b0xe535base64_decode函数下断点,c继续运行到base64_decode入口

    image-20220107093354896

    看看r0的数据

    image-20220107093023968

    blr在函数返回处下断点,c继续运行到函数返回处,看看原r1的值。

    image-20220107093448376

    和cyberchef对比一下

    image-20220107093512475

    是标准base64实现

    接下来就是看看aes的实现,尝试网上搜索WBACRAESWBACR AES

    image-20220106221231517 image-20220106221514540

    从搜索结果看,是白盒AES,这就有点麻烦了。这样一来,我们无法直接拿到AES的keyiv,然后验证。虽然块解密的过程和标准AES实现不太一样,但是整体流程还是一样的。

    AES-CBC-decrypt image-20220107095905688

    接下来hook一下CWAESCipher::WBACRAES_DecryptOneBlock,看看块解密的输入输出

    emulator.attach().addBreakPoint(module.base + 0x5910+1);
    
    image-20220107100254521

    和之前base64的结果对比可以看出,这就是最后一块的数据。

    blr在函数返回处下断点,c继续运行到函数返回处,看看原r1的值。

    image-20220107100416064

    这就是最后一块解密后的数据,我们根据AES-CBC的流程,把它和前一块的数据进行异或试试。

    s0 = bytes.fromhex('75 9E 38 5F F2 04 21 EC E9 11 8F EF C7 D9 BF 6D')
    s1 = bytes.fromhex('4D AC 0C 0F B6 31 56 AD A8 50 CE D2 C3 DD BB 69')
    s2 = bytes(map(lambda x:x[0]^x[1], zip(s0, s1)))
    
    image-20220107100853991

    数据正确,这样一来,我们只要解决块解密,就能逆向出算法了。

    C++还原块解密

    奈何想从白盒AES里找到key还是很困难的,所以我选择把块解密的方法抠出来,用C++实现,导出为dll文件,然后python再调用dll文件。实在是无能为力了。。

    
    #include <stdio.h>
    #include <string.h>
    
    typedef          char   int8;
    typedef   signed char   sint8;
    typedef unsigned char   uint8;
    typedef          short  int16;
    typedef   signed short  sint16;
    typedef unsigned short  uint16;
    typedef          int    int32;
    typedef   signed int    sint32;
    typedef unsigned int    uint32;
    
    #define _BYTE  uint8
    #define _WORD  uint16
    #define _DWORD uint32
    #define _QWORD uint64
    
    #define LOBYTE(x)   (*((_BYTE*)&(x)))   // low byte
    #define LOWORD(x)   (*((_WORD*)&(x)))   // low word
    #define LODWORD(x)  (*((_DWORD*)&(x)))  // low dword
    #define HIBYTE(x)   (*((_BYTE*)&(x)+1))
    #define HIWORD(x)   (*((_WORD*)&(x)+1))
    #define HIDWORD(x)  (*((_DWORD*)&(x)+1))
    #define BYTEn(x, n)   (*((_BYTE*)&(x)+n))
    #define WORDn(x, n)   (*((_WORD*)&(x)+n))
    #define BYTE1(x)   BYTEn(x,  1)         // byte 1 (counting from 0)
    #define BYTE2(x)   BYTEn(x,  2)
    #define BYTE3(x)   BYTEn(x,  3)
    #define BYTE4(x)   BYTEn(x,  4)
    #define BYTE5(x)   BYTEn(x,  5)
    #define BYTE6(x)   BYTEn(x,  6)
    #define BYTE7(x)   BYTEn(x,  7)
    #define BYTE8(x)   BYTEn(x,  8)
    #define BYTE9(x)   BYTEn(x,  9)
    #define BYTE10(x)  BYTEn(x, 10)
    #define BYTE11(x)  BYTEn(x, 11)
    #define BYTE12(x)  BYTEn(x, 12)
    #define BYTE13(x)  BYTEn(x, 13)
    #define BYTE14(x)  BYTEn(x, 14)
    #define BYTE15(x)  BYTEn(x, 15)
    #define WORD1(x)   WORDn(x,  1)
    #define WORD2(x)   WORDn(x,  2)         // third word of the object, unsigned
    #define WORD3(x)   WORDn(x,  3)
    #define WORD4(x)   WORDn(x,  4)
    #define WORD5(x)   WORDn(x,  5)
    #define WORD6(x)   WORDn(x,  6)
    #define WORD7(x)   WORDn(x,  7)
    
    
    _BYTE unk_18D8E[] = {0,0,1,3,2,2,3,1};
    
    _BYTE invFirstRoundTable_auth1[] = {0x8d,0xba,0xd5,/* 省略 */0xd9,0x62,0x74,0xb8}; // invFirstRoundTable_auth1
    
    _BYTE byte_invRoundTables_auth1[] = {0,0,0,0,/* 省略 */93,241,194,24,79};
    _DWORD* invRoundTables_auth1 = (_DWORD*)byte_invRoundTables_auth1;
    
    
    _BYTE invXorTables_auth1[] = {0, 0, 0, /* 省略 */6, 7, 13, 3, 11};
    
    // extern "C" _declspec(dllexport) int WBACRAES_DecryptOneBlock(unsigned __int8 *a2, unsigned __int8 *a3, int a4);
    
    int WBACRAES_DecryptOneBlock(unsigned __int8 *a2, unsigned __int8 *a3, int a4)
    {
      unsigned __int8 (*v5)[8]; // r3
      int v6; // r11
      char *v7; // r1
      int v8; // r3
      _DWORD *v9; // r6
      int j; // r2
      int v11; // r10
      int v12; // r0
      int v13; // r0
      void **v14; // r8
      int v15; // r0
      int k; // r2
      char *v17; // r3
      char v18; // r5
      int v19; // r0
      char v20; // r1
      int v21; // r6
      unsigned int v22; // r5
      int v23; // r1
      char v24; // r8
      _BYTE *v25; // r12
      int v26; // r12
      int v27; // r7
      _BYTE *v28; // r8
      int v29; // r8
      int v30; // r7
      int v31; // r2
      char *v32; // r1
      int i; // r3
      _BYTE *v34; // r5
      int v35; // r8
      char *v36; // r6
      int v37; // r8
      int l; // r3
      int m; // r2
      int v41; // [sp+0h] [bp-E0h]
      _BYTE *v42; // [sp+4h] [bp-DCh]
      int v43; // [sp+8h] [bp-D8h]
      int v44; // [sp+Ch] [bp-D4h]
      int v47; // [sp+1Ch] [bp-C4h]
      char v49[4]; // [sp+30h] [bp-B0h] BYREF
      int v50; // [sp+34h] [bp-ACh]
      _DWORD s[42]; // [sp+38h] [bp-A8h] BYREF
    
      memset(s, 0, 0x20u);
    //   v44 = CSecFunctProvider::PrepareAESMatrix((CSecFunctProvider *)a2, (unsigned __int8 *)&word_10, (int)s, v5);
      for (int i=0; i!=4; i++) {
        for(int j=0; j!=4; j++) {
          *((_BYTE *)s + i + 8 * j) = *((_BYTE *)a2 + 4 * i + j);
        }
      }
      // for (int i=0; i<2; i++) {
      //     for (int j=0; j<16; j++) {
      //         printf("%02x ", *((_BYTE *)s + i*16 + j));
      //     }
      //     printf("\n");
      // }
      //     printf("\n");
      
      v44 = 0;
      if ( !v44 )
      {
        v6 = 10;
        while ( v6 >= a4 )
        {
          if ( !--v6 )
          {
            if ( a4 == 1 )
            {
              s[8] = s[0];
              s[9] = s[1];
              s[10] = s[2];
              s[11] = s[3];
              s[12] = s[4];
              s[13] = s[5];
              s[14] = s[6];
              s[15] = s[7];
              v30 = 1;
              do
              {
                v31 = 0;
                v32 = (char *)&unk_18D8E;
                for ( i = 0; i != 4; ++i )
                {
                //if ( v30 == 1 || v30 != 2 )
                //{
                    v34 = invFirstRoundTable_auth1;
                    v35 = (v32[1] + (_BYTE)v6) & 3;
                //}
                //   else
                //   {
                //     v34 = &invFirstRoundTable_auth2_ptr;
                //     v35 = (v32[1] + (_BYTE)v6) & 3;
                //   }
                  v32 += 2;
                  v36 = (char *)&s[2 * i + 32] + v35;
                  v37 = i + 4 * v35;
                  *((_BYTE *)s + v6 + v31) = *((_BYTE *)v34 + 256 * v37 + (unsigned __int8)*(v36 - 96));
                  v31 += 8;
                }
                ++v6;
              }
              while ( v6 != 4 );
            }
            break;
          }
    
          v7 = (char *)&unk_18D8E;
          v8 = 0;
          v47 = 4 * v6;
          do
          {
            v9 = &s[2 * v8 + 32];
            for ( j = 0; j != 4; ++j )
            {
              v11 = 1;
              // if ( v11 == 1 )
              // {
                v15 = (v7[1] + (_BYTE)j) & 3;
                v50 = invRoundTables_auth1[256 * (v8 + 4 * (v15 + v47)) + *((unsigned __int8 *)v9 + v15 - 128)];
              // }
            //   else
            //   {
            //     v12 = (v7[1] + (_BYTE)j) & 3;
            //     v13 = *((unsigned __int8 *)v9 + v12 - 128) + ((v8 + 4 * (v12 + v47)) << 8);
            //     if ( v11 == 2 )
            //       v14 = &invRoundTables_auth2_ptr;
            //     else
            //       v14 = &invRoundTables_auth1_ptr;
            //     v50 = *((_DWORD *)*v14 + v13);
            //   }
              s[4 * v8 + 16 + j] = v50;
            }
            ++v8;
            v7 += 2;
          }
          while ( v8 != 4 );
    
          for ( k = 0; k != 4; ++k )
          {
            v17 = (char *)&s[16] + k;
            v41 = 0;
            do
            {
              v43 = 0;
              v49[1] = v17[16];
              v18 = *v17;
              v19 = 96 * v6 + 24 * v41;
              v49[2] = v17[32];
              v20 = v17[48];
              v21 = v18 & 0xF;
              v49[0] = v18;
              v22 = v18 & 0xF0;
              v49[3] = v20;
              v23 = 6 * k;
              do
              {
                v24 = v49[++v43];
                // if ( v11 == 1 || v11 != 2 )
                  v25 = invXorTables_auth1;
                // else
                //   v25 = &invXorTables_auth2_ptr;
                v42 = v25;
                v26 = v23 + 1;
                v27 = v24 & 0xF0 | (v22 >> 4);
                LOBYTE(v21) = v42[256 * (v19 + v23) + (v21 | (16 * (v24 & 0xF)))] & 0xF;
                // if ( v11 == 1 || v11 != 2 )
                  v28 = invXorTables_auth1;
                // else
                //   v28 = &invXorTables_auth2_ptr;
                v23 += 2;
                v22 = (unsigned __int8)(16 * *((_BYTE *)v28 + 256 * (v26 + v19) + v27));
              }
              while ( v43 != 3 );
              v29 = v41;
              v17 += 4;
              *((_BYTE *)&s[2 * k] + v41++) = v22 | v21;
            }
            while ( v29 != 3 );
          }
        }
        for ( l = 0; l != 4; ++l )
        {
          for ( m = 0; m != 4; ++m )
            a3[4 * l + m] = *((_BYTE *)&s[2 * m] + l);
        }
      }
      return v44;
    }
    
    int main() {
        _BYTE a2[16] = {0x8D, 0x63, 0xD7, 0x56, 0xDB, 0x55, 0xCD, 0x06, 0x56, 0x70, 0xB9, 0x74, 0xE6, 0x24, 0xB5, 0x86};
        _BYTE a3[16];
        int ret;
        
        for(int i=0; i<16; i++){
            printf("%02X ", a2[i]);
        }
        printf("\n");
        ret = WBACRAES_DecryptOneBlock(a2, a3, 1);
        
        // 75 9E 38 5F F2 04 21 EC E9 11 8F EF C7 D9 BF 6D
        for(int i=0; i<16; i++){
            printf("%02X ", a3[i]);
        }
        printf("\n");
    
        return 0;
    }
    

    其中有些分支由于入参的原因,是不会进入的,所以直接去掉

    image-20220107104958267

    然后就是编译,运行,看看代码有没有问题

    image-20220107105509651

    和unidbg上是一样的,接下来就是把它编译成dll文件,供python调用了。

    编译生成dll文件

    visual studio选择新建项目->动态连接库

    image-20220107102627044

    右键文件,选择属性,修改为不使用预编译头。

    image-20220107102934260

    接下来就是把之前的C++代码复制到文件里,需要添加一行代码

    extern "C" _declspec(dllexport) int WBACRAES_DecryptOneBlock(unsigned __int8 *a2, unsigned __int8 *a3, int a4);
    

    由于我的python和windows是64位版本的,所以还要设置一下生成的版本

    image-20220107104016304

    最后就是选择生成->生成解决方案就行了。

    python调用dll文件

    接下来就是用python调用dll文件

    import base64
    import gzip
    
    from ctypes import *
    
    dll_path = r".\Dll1.dll"
    
    cryptor = cdll.LoadLibrary(dll_path)
    decrypt_block = cryptor.WBACRAES_DecryptOneBlock
    decrypt_block.restype = c_int
    
    
    def aes_decrypt(data):
        previous = bytes([0]*16)
        bucket = []
        for idx in range(0, len(data), 16):
            block = data[idx: idx+16]
            din = c_char_p(block)
            dout = c_char_p(bytes([0]*16))
            decrypt_block(din, dout, 1)
            out = bytes(map(lambda x: x[0] ^ x[1], zip(dout._objects, previous)))
            print(out)
            bucket.append(out)
            previous = block
        output = b''.join(bucket)
        output = output[:-output[-1]]
        return output
    
    def decrypt(data):
        data1 = base64.b64decode(data[1:])
        data3 = aes_decrypt(data1)
        print(data3)
        data4 = base64.b64decode(data3)
        print(data4)
        data5 = gzip.decompress(data4)
        print(data5)
    
    def test():
        data = 'MLj4JOPMKPdGeytkeBPy/TvgGCgIOWegKndYgDVbmrctTnrov1z7Uei09BKfKhlW/xnLMOg1HaIN7llJqgPFjmayzV1OI2Rqd7heXxQw1VAmVCe6yXyiiyQ5OHaZ7hhRm5BRpmlFqgY1ebjsv8WPnnw+OZXydnPcySv4Lt5bwmHrOQfygHI7KhDFN40NU8/Csuumues12zRmtaQH9ycfD8fnu27yxX0UQeZBL/VPS+UVNrAwPtjFWrahQztLD3btpjWPXVttVzQZWcLl05iS1hg=='
        decrypt(data)
    
    
    if __name__ == '__main__':
        test()
    
    image-20220107103545173

    至此,AES-CBC-decrypt的逆向也就完成了,代码仅供把玩。

    相关文章

      网友评论

          本文标题:菱菱邦sd字段白盒AES逆向

          本文链接:https://www.haomeiwen.com/subject/xfljcrtx.html