碎碎念
一共三道re提岔,只會(huì)一個(gè)...另外兩個(gè)0解拆座,這道m(xù)obile都知道算法了主巍,可是臨了了還是沒解出來,都怪我RC5沒咋了解過挪凑,稍微記錄一下孕索。
AES
前面是AES加密,把AES的四個(gè)步驟拼在一起了躏碳,然后S盒是動(dòng)態(tài)生成的搞旭,可以調(diào)試的時(shí)候看一下是不是S盒的特征數(shù)字(當(dāng)然也有時(shí)候會(huì)換掉標(biāo)準(zhǔn)的S盒)
我稍微記一下這種AES的步驟
- 密鑰生成
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;
}
- 加密
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以為自己要出了菇绵,結(jié)果一直解密到結(jié)束都沒解密出來肄渗,菜狗罷了。
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比特)翎嫡,密鑰長(zhǎng)度(0至2040位)和加密輪數(shù)(0~255)。最初建議選擇的參數(shù)是64位的塊大小永乌,128位的密鑰和12輪加密惑申。
RC5的一個(gè)關(guān)鍵特征是使用基于數(shù)據(jù)的置換。RC5的其中一個(gè)目標(biāo)是促進(jìn)對(duì)于這類作為原始密碼的操作的研究和評(píng)估翅雏。RC5也包括一些的取模加法和邏輯異或(XOR)運(yùn)算圈驼。這個(gè)加密的一般結(jié)構(gòu)是一種類費(fèi)斯妥網(wǎng)絡(luò)。加密和解密程序可以用幾行代碼寫完望几,但密鑰的生成算法更復(fù)雜绩脆。密鑰擴(kuò)展使用了e和黃金比例代入一個(gè)單向函數(shù),將所得值作為“袖子里是空的”數(shù)字(即無任何來源依據(jù)的魔法數(shù)字)橄妆。算法的誘人的簡(jiǎn)潔性和基于數(shù)據(jù)的置換的特性衙伶,讓RC5吸引了眾多密碼研究人員將其作為研究對(duì)象。 RC5通常被記為RC5-w/r/b害碾,w=字的大惺妇ⅰ(以bit為單位),r=加密輪數(shù)慌随,b=密鑰的字節(jié)數(shù)芬沉。
解RC5最主要的是確定密鑰的長(zhǎng)度躺同,輪數(shù),塊大小以及padding的內(nèi)容
這里padding的方式是PKCS#7丸逸,基本長(zhǎng)度是8蹋艺。密鑰長(zhǎng)度是32字節(jié)(這里被坑了,以為是16黄刚,IDA里OWord表示16字節(jié))捎谨,輪數(shù)是12,塊大小是32
記一份標(biāo)準(zhǔn)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}
一個(gè)RC系列實(shí)現(xiàn)的文章:
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