TOC

碎碎念

一共三道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系列实现的文章