钓鱼城杯-mobile题解

碎碎念

一共三道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题解)