美文网首页
钓鱼城杯-mobile题解

钓鱼城杯-mobile题解

作者: SamiraG | 来源:发表于2020-10-20 13:30 被阅读0次

    碎碎念

    一共三道re,只会一个...另外两个0解,这道mobile都知道算法了,可是临了了还是没解出来,都怪我RC5没咋了解过,稍微记录一下。

    AES

    前面是AES加密,把AES的四个步骤拼在一起了,然后S盒是动态生成的,可以调试的时候看一下是不是S盒的特征数字(当然也有时候会换掉标准的S盒)
    我稍微记一下这种AES的步骤

    1. 密钥生成
    long double __fastcall sub_7FA04C1AC4(unsigned int *a1, __int64 a2, __int128 *a3)
    {
      v3 = 0LL;
      v4 = bswap32(*a1);
      *(_DWORD *)a3 = v4;
      *((_DWORD *)a3 + 1) = bswap32(a1[1]);
      *((_DWORD *)a3 + 2) = bswap32(a1[2]);
      v5 = a3 + 1;
      *((_DWORD *)a3 + 3) = bswap32(a1[3]);
      do
      {
        v6 = *((unsigned int *)v5 - 1);
        v7 = unk_7FA04C5E20[0].n128_u32[v3];
        ++v3;
        v4 ^= v7 ^ (((stru_7FA04C5040[0].n128_u8[(v6 >> 16) & 0xFF] << 24) & 0xFF00FFFF | (stru_7FA04C5040[0].n128_u8[(unsigned __int16)v6 >> 8] << 16)) & 0xFFFF00FF | (stru_7FA04C5040[0].n128_u8[(unsigned __int8)v6] << 8) | stru_7FA04C5040[0].n128_u8[v6 >> 24]);
        v8 = *((_DWORD *)v5 - 2);
        v9 = v4 ^ *((_DWORD *)v5 - 3);
        *(_DWORD *)v5 = v4;
        *((_DWORD *)v5 + 1) = v9;
        v10 = v9 ^ v8;
        *((_DWORD *)v5 + 2) = v10;
        *((_DWORD *)v5 + 3) = v10 ^ v6;
        ++v5;
      }
      while ( v3 != 10 );
      v11 = a3[9];
      v13 = a3[7];
      v12 = a3[8];
      a3[11] = a3[10];
      a3[12] = v11;
      v14 = a3[5];
      v15 = a3[6];
      a3[13] = v12;
      a3[14] = v13;
      v17 = a3[3];
      result = *((long double *)a3 + 4);
      a3[15] = v15;
      a3[16] = v14;
      v18 = *a3;
      v20 = a3[1];
      v19 = a3[2];
      *((long double *)a3 + 17) = result;
      a3[18] = v17;
      a3[21] = v18;
      a3[19] = v19;
      a3[20] = v20;
      return result;
    }
    
    1. 加密
      if ( v7 )
      {
        v9 = 0;
        do
        {
          v10 = *v6;
          BYTE4(v75) = v6[1];
          v11 = v10 ^ (v79 >> 24);
          v12 = BYTE4(v75) ^ (v79 >> 16);
          v13 = 0LL;
          LOBYTE(v76) = v6[2];
          v14 = (unsigned __int8)v76 ^ (v79 >> 8);
          BYTE4(v76) = v6[3];
          v15 = BYTE4(v76) ^ v79;
          v16 = v6[4];
          v17 = v6[5];
          BYTE1(v76) = v6[6];
          v18 = v16 ^ (v80 >> 24);
          v19 = v17 ^ (v80 >> 16);
          v20 = BYTE1(v76) ^ (v80 >> 8);
          BYTE5(v76) = v6[7];
          v21 = BYTE5(v76) ^ v80;
          v22 = v6[8];
          v23 = v6[9];
          v24 = v6[10];
          BYTE6(v76) = v6[11];
          v25 = v22 ^ (v81 >> 24);
          v26 = v23 ^ (v81 >> 16);
          v27 = v24 ^ (v81 >> 8);
          v28 = BYTE6(v76) ^ v81;
          v29 = v6[14];
          v30 = v6[15];
          v31 = v6[12] ^ (v82 >> 24);
          v32 = v6[13] ^ (v82 >> 16);
          v33 = v29 ^ (v82 >> 8);
          v34 = v30 ^ v82;
          LOBYTE(v75) = v11;
          BYTE1(v75) = v18;
          BYTE2(v75) = v25;
          BYTE4(v75) ^= BYTE2(v79);
          BYTE5(v75) = v19;
          BYTE6(v75) = v26;
          LOBYTE(v76) = v76 ^ BYTE1(v79);
          BYTE1(v76) ^= BYTE1(v80);
          BYTE2(v76) = v27;
          BYTE4(v76) ^= v79;
          BYTE5(v76) ^= v80;
          BYTE6(v76) ^= v81;
          BYTE3(v75) = v31;
          HIBYTE(v75) = v32;
          BYTE3(v76) = v29 ^ BYTE1(v82);
          HIBYTE(v76) = v30 ^ v82;
          do
          {
            v35 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v11];
            v36 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v18];
            v37 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v25];
            v38 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v31];
            v39 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v12];
            v40 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v26];
            v41 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v32];
            v42 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v14];
            v43 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v20];
            v44 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v27];
            v45 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v33];
            v46 = stru_7FA04C5040[0].n128_u8[v15];
            v47 = stru_7FA04C5040[0].n128_u8[v21];
            v48 = stru_7FA04C5040[0].n128_u8[v28];
            v49 = stru_7FA04C5040[0].n128_u8[v34];
            BYTE4(v75) = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v19];
            LOBYTE(v75) = v35;
            BYTE1(v75) = v36;
            BYTE2(v75) = v37;
            BYTE3(v75) = v38;
            BYTE5(v75) = v40;
            BYTE6(v75) = v41;
            HIBYTE(v75) = v39;
            LOBYTE(v76) = v44;
            BYTE1(v76) = v45;
            BYTE2(v76) = v42;
            BYTE3(v76) = v43;
            BYTE4(v76) = v49;
            BYTE5(v76) = v46;
            BYTE6(v76) = v47;
            HIBYTE(v76) = v48;
            sub_7FA04C1EE0((__int128 *)&v75);
            v50 = *(unsigned int *)((char *)&v79 + v13 + 16);
            v51 = *(unsigned int *)((char *)&v79 + v13 + 20);
            v11 = (unsigned __int8)v75 ^ (v50 >> 24);
            v12 = BYTE4(v75) ^ (v50 >> 16);
            v14 = (unsigned __int8)v76 ^ (v50 >> 8);
            v15 = BYTE4(v76) ^ v50;
            v53 = *(unsigned int *)((char *)&v79 + v13 + 24);
            v52 = *(unsigned int *)((char *)&v79 + v13 + 28);
            v18 = BYTE1(v75) ^ (v51 >> 24);
            v19 = BYTE5(v75) ^ (v51 >> 16);
            v20 = BYTE1(v76) ^ (v51 >> 8);
            v21 = BYTE5(v76) ^ v51;
            v13 += 16LL;
            v25 = BYTE2(v75) ^ (v53 >> 24);
            v26 = BYTE6(v75) ^ (v53 >> 16);
            v27 = BYTE2(v76) ^ (v53 >> 8);
            v28 = BYTE6(v76) ^ v53;
            v31 = BYTE3(v75) ^ (v52 >> 24);
            v32 = HIBYTE(v75) ^ (v52 >> 16);
            v33 = BYTE3(v76) ^ (v52 >> 8);
            v34 = HIBYTE(v76) ^ v52;
            LOBYTE(v75) = v11;
            BYTE1(v75) = v18;
            BYTE2(v75) = v25;
            BYTE3(v75) ^= HIBYTE(v52);
            BYTE4(v75) = v12;
            BYTE5(v75) = v19;
            BYTE6(v75) = v26;
            HIBYTE(v75) ^= BYTE2(v52);
            LOBYTE(v76) = v14;
            BYTE1(v76) = v20;
            BYTE2(v76) = v27;
            BYTE3(v76) ^= BYTE1(v52);
            BYTE4(v76) = v15;
            BYTE5(v76) = v21;
            BYTE6(v76) = v28;
            HIBYTE(v76) ^= v52;
          }
          while ( (_DWORD)v13 != 144 );
          v54 = (char *)&v79 + v13;
          v55 = *(unsigned int *)((char *)&v79 + v13 + 16);
          v56 = *(unsigned int *)((char *)&v79 + v13 + 20);
          v57 = *((_DWORD *)v54 + 6);
          LODWORD(v54) = *((_DWORD *)v54 + 7);
          v9 += 16;
          v58 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v18] ^ (v56 >> 24);
          v59 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v25] ^ (v57 >> 24);
          v60 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v31] ^ ((unsigned int)v54 >> 24);
          v61 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v19] ^ (v55 >> 16);
          v62 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v26] ^ (v56 >> 16);
          v63 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v32] ^ (v57 >> 16);
          v64 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v12] ^ ((unsigned int)v54 >> 16);
          v65 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v27] ^ (v55 >> 8);
          v66 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v33] ^ (v56 >> 8);
          v67 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v14] ^ (v57 >> 8);
          v68 = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v20] ^ ((unsigned int)v54 >> 8);
          v69 = stru_7FA04C5040[0].n128_u8[v34] ^ v55;
          v70 = stru_7FA04C5040[0].n128_u8[v15] ^ v56;
          v71 = stru_7FA04C5040[0].n128_u8[v21] ^ v57;
          v72 = stru_7FA04C5040[0].n128_u8[v28] ^ (unsigned __int8)v54;
          LOBYTE(v75) = stru_7FA04C5040[0].n128_u8[(unsigned __int8)v11] ^ HIBYTE(v55);
          BYTE1(v75) = v58;
          BYTE2(v75) = v59;
          BYTE3(v75) = v60;
          BYTE4(v75) = v61;
          BYTE5(v75) = v62;
          BYTE6(v75) = v63;
          HIBYTE(v75) = v64;
          LOBYTE(v76) = v65;
          BYTE1(v76) = v66;
          BYTE2(v76) = v67;
          BYTE3(v76) = v68;
          BYTE4(v76) = v69;
          BYTE5(v76) = v70;
          BYTE6(v76) = v71;
          HIBYTE(v76) = v72;
          *v5 = v75;
          v5[1] = v61;
          v6 += 16;
          v5[2] = v76;
          v73 = BYTE4(v76);
          v5[4] = v58;
          v5[3] = v73;
          v5[5] = BYTE5(v75);
          v5[6] = BYTE1(v76);
          v5[7] = BYTE5(v76);
          v5[8] = BYTE2(v75);
          v5[9] = BYTE6(v75);
          v5[10] = BYTE2(v76);
          v5[11] = BYTE6(v76);
          v5[12] = BYTE3(v75);
          v5[13] = HIBYTE(v75);
          v5[14] = BYTE3(v76);
          v5[15] = HIBYTE(v76);
          v5 += 16;
        }
        while ( v9 < v7 );
      }
    

    这里是ECB模式加密,密钥是'\x01'*16

    RC5

    然后找到RC5的magic number以为自己要出了,结果一直解密到结束都没解密出来,菜狗罢了。
    RC5的magic number:

      v8 = 0xB7E15163; // 0xB7E15163就是-0x481EAE9D
      v9 = malloc(0x20u);
      v10 = vcvtmd_u64_f64((sqrt(5.0) + -1.0) * 2147483650.0); // 0x9E3779B9
      dword_7FA04C5E60[0] = 0xB7E15163;
      unk_7FA04C5E64 = v10 - 0x481EAE9D;
      unk_7FA04C5E68 = v10 - 0x481EAE9D + v10;
      unk_7FA04C5E6C = v10 - 0x481EAE9D + v10 + v10;
    

    RC5支持可变的块大小(32、64或128比特),密钥长度(0至2040位)和加密轮数(0~255)。最初建议选择的参数是64位的块大小,128位的密钥和12轮加密。

    RC5的一个关键特征是使用基于数据的置换。RC5的其中一个目标是促进对于这类作为原始密码的操作的研究和评估。RC5也包括一些的取模加法和逻辑异或(XOR)运算。这个加密的一般结构是一种类费斯妥网络。加密和解密程序可以用几行代码写完,但密钥的生成算法更复杂。密钥扩展使用了e黄金比例代入一个单向函数,将所得值作为“袖子里是空的”数字(即无任何来源依据的魔法数字)。算法的诱人的简洁性和基于数据的置换的特性,让RC5吸引了众多密码研究人员将其作为研究对象。 RC5通常被记为RC5-w/r/b,w=字的大小(以bit为单位),r=加密轮数,b=密钥的字节数。

    解RC5最主要的是确定密钥的长度,轮数,块大小以及padding的内容
    这里padding的方式是PKCS#7,基本长度是8。密钥长度是32字节(这里被坑了,以为是16,IDA里OWord表示16字节),轮数是12,块大小是32
    记一份标准RC5加解密的python算法:
    https://github.com/tbb/pyRC5

    class RC5:
    
        def __init__(self, w, R, key, strip_extra_nulls=False):
            self.w = w  # block size (32, 64 or 128 bits)
            self.R = R  # number of rounds (0 to 255)
            self.key = key  # key (0 to 2040 bits)
            self.strip_extra_nulls = strip_extra_nulls
            # some useful constants
            self.T = 2 * (R + 1)
            self.w4 = w // 4
            self.w8 = w // 8
            self.mod = 2 ** self.w
            self.mask = self.mod - 1
            self.b = len(key)
    
            self.__keyAlign()
            self.__keyExtend()
            self.__shuffle()
    
        def __lshift(self, val, n):
            n %= self.w
            return ((val << n) & self.mask) | ((val & self.mask) >> (self.w - n))
    
        def __rshift(self, val, n):
            n %= self.w
            return ((val & self.mask) >> n) | (val << (self.w - n) & self.mask)
    
        def __const(self):  # constants generation
            if self.w == 16:
                return 0xB7E1, 0x9E37  # return P, Q values
            elif self.w == 32:
                return 0xB7E15163, 0x9E3779B9
            elif self.w == 64:
                return 0xB7E151628AED2A6B, 0x9E3779B97F4A7C15
    
        def __keyAlign(self):
            if self.b == 0:  # key is empty
                self.c = 1
            elif self.b % self.w8:
                self.key += b'\x00' * (self.w8 - self.b % self.w8)  # fill key with \x00 bytes
                self.b = len(self.key)
                self.c = self.b // self.w8
            else:
                self.c = self.b // self.w8
            L = [0] * self.c
            for i in range(self.b - 1, -1, -1):
                L[i // self.w8] = (L[i // self.w8] << 8) + self.key[i]
            self.L = L
    
        def __keyExtend(self):
            P, Q = self.__const()
            self.S = [(P + i * Q) % self.mod for i in range(self.T)]
    
        def __shuffle(self):
            i, j, A, B = 0, 0, 0, 0
            for k in range(3 * max(self.c, self.T)):
                A = self.S[i] = self.__lshift((self.S[i] + A + B), 3)
                B = self.L[j] = self.__lshift((self.L[j] + A + B), A + B)
                i = (i + 1) % self.T
                j = (j + 1) % self.c
    
        def encryptBlock(self, data):
            A = int.from_bytes(data[:self.w8], byteorder='little')
            B = int.from_bytes(data[self.w8:], byteorder='little')
            A = (A + self.S[0]) % self.mod
            B = (B + self.S[1]) % self.mod
            for i in range(1, self.R + 1):
                A = (self.__lshift((A ^ B), B) + self.S[2 * i]) % self.mod
                B = (self.__lshift((A ^ B), A) + self.S[2 * i + 1]) % self.mod
            return (A.to_bytes(self.w8, byteorder='little')
                    + B.to_bytes(self.w8, byteorder='little'))
    
        def decryptBlock(self, data):
            A = int.from_bytes(data[:self.w8], byteorder='little')
            B = int.from_bytes(data[self.w8:], byteorder='little')
            for i in range(self.R, 0, -1):
                B = self.__rshift(B - self.S[2 * i + 1], A) ^ A
                A = self.__rshift(A - self.S[2 * i], B) ^ B
            B = (B - self.S[1]) % self.mod
            A = (A - self.S[0]) % self.mod
            return (A.to_bytes(self.w8, byteorder='little')
                    + B.to_bytes(self.w8, byteorder='little'))
    
        def encryptFile(self, inpFileName, outFileName):
            with open(inpFileName, 'rb') as inp, open(outFileName, 'wb') as out:
                run = True
                while run:
                    text = inp.read(self.w4)
                    if not text:
                        break
                    if len(text) != self.w4:
                        text = text.ljust(self.w4, b'\x00')
                        run = False
                    text = self.encryptBlock(text)
                    out.write(text)
    
        def decryptFile(self, inpFileName, outFileName):
            with open(inpFileName, 'rb') as inp, open(outFileName, 'wb') as out:
                while True:
                    text = inp.read(self.w4)
                    if not text:
                        break
                    text = self.decryptBlock(text)
                    if self.strip_extra_nulls:
                        text = text.rstrip(b'\x00')
                    out.write(text)
    
        def encryptBytes(self, data):
            res, run = b'', True
            while run:
                temp = data[:self.w4]
                if len(temp) != self.w4:
                    data = data.ljust(self.w4, b'\x00') # padding
                    run = False
                res += self.encryptBlock(temp)
                data = data[self.w4:]
                if not data:
                    break
            return res
    
        def decryptBytes(self, data):
            res, run = b'', True
            while run:
                temp = data[:self.w4]
                if len(temp) != self.w4:
                    run = False
                res += self.decryptBlock(temp)
                data = data[self.w4:]
                if not data:
                    break
            return res.rstrip(b'\x00') # padding
    

    exp

    #!/usr/bin/env python
    from Crypto.Cipher import AES
    from Crypto.Util.number import *
    from RC5 import RC5
    import struct
    
    datalist = [202 , 96 , 85 , 48 , 181 , 219 , 212 , 166 , 1 , 21 , 63 , 184 , 188 , 76 , 156 , 136 , 234 , 244 , 118 , 221 , 141 , 123 , 26 , 38 , 218 , 116 , 44 , 29 , 40 , 99 , 75 , 136 , 68 , 34 , 126 , 33 , 14 , 108 , 244 , 174 , 228 , 33 , 199 , 103 , 33 , 64 , 197 , 59 , 178 , 85 , 146 , 33 , 155 , 41 , 250 , 51]
    data = bytes(datalist)
    print(data,len(data))
    
    key = b'\x02'*32
    
    rc5 = RC5(32, 12, key)
    result = rc5.decryptBytes(data)
    print('xxx\n')
    for r in result:
        print(hex(int(r)), end=",")
    print('end\n')
    key = b'\x01'*16
    cipher = AES.new(key, AES.MODE_ECB)
    msg = cipher.decrypt(result)
    print(msg)
    # flag{AES_and_rc5_modified_in_jni_onloadXDDD}
    

    一个RC系列实现的文章:
    https://qianfei11.github.io/2019/09/03/C%E8%AF%AD%E8%A8%80%E5%AE%9E%E7%8E%B0RC2%E3%80%81RC5%E3%80%81RC6%E5%8A%A0%E5%AF%86%E8%A7%A3%E5%AF%86%E7%AE%97%E6%B3%95/#Intro

    相关文章

      网友评论

          本文标题:钓鱼城杯-mobile题解

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