在 CTF 題目中,有些算法出現的頻率很高,記錄一下常見算法的識別技巧
常見算法介紹
base64
base64 主要是將輸入中的每 3 字節(共 24 比特)按每 6 比特分成一組,變成 4 個小於 64 的索引值,然后通過一個索引表得到 4 個可見字符。
索引表為一個 64 字節的字符串,如果在代碼中發現引用了索引表"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",那么基本上就可以確定用了 base64,此外還有一些變種的 base64,主要是改變了索引表
TEA
TEA 是一種常見的分組加密算法,密鑰為 128 比特位,嗎,明文為 64 比特位,主要做了 32 輪變換,每輪變換中都涉及移位和變換。
識別方法為:TEA 算法中有一個固定的常數 0x9e3779b9 或者 0x61c88647
TEA 的源碼如下:
void encrypt(uint32_t*v,unint32_t*k) {
uint32_t v0 = v[0], v1 = v[1], sum = 0, i;
uint32_t delta = 0x9e3779b9;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for(i=0;i<32;i++) {
sum += delta;
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
}
v[0] = v0;
v[1] = v1;
}
void decrypt(uint32_t*v,unint32_t*k) {
uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i;
uint32_t delta = 0x9e3779b9;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for(i=0;i<32;i++) {
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
sum -= delta;
}
v[0] = v0;
v[1] = v1;
}
AES
AES 也是常見的分組加密算法,AES 加解密流程如圖所示:
其中,字節替代過程是通過 S 盒完成一個字節到另一個字節的映射。S 盒和逆 S 盒具體如下:
0 1 2 3 4 5 6 7 8 9 A B C D E F
0 63 7c 77 7b f2 6b 6f c5 30 1 67 2b fe d7 ab 76
1 ca 82 c9 7d fa 59 47 f0 ad d4 a2 af 9c a4 72 c0
2 b7 fd 93 26 36 3f f7 cc 34 a5 e5 f1 71 d8 31 15
3 4 c7 23 c3 18 96 5 9a 7 12 80 e2 eb 27 b2 75
4 9 83 2c 1a 1b 6e 5a a0 52 3b d6 b3 29 e3 2f 84
5 53 d1 0 ed 20 fc b1 5b 6a cb be 39 4a 4c 58 cf
6 d0 ef aa fb 43 4d 33 85 45 f9 2 7f 50 3c 9f a8
7 51 a3 40 8f 92 9d 38 f5 bc b6 da 21 10 ff f3 d2
8 cd c 13 ec 5f 97 44 17 c4 a7 7e 3d 64 5d 19 73
9 60 81 4f dc 22 2a 90 88 46 ee b8 14 de 5e b db
a e0 32 3a a 49 6 24 5c c2 d3 ac 62 91 95 e4 79
b e7 c8 37 6d 8d d5 4e a9 6c 56 f4 ea 65 7a ae 8
c ba 78 25 2e 1c a6 b4 c6 e8 dd 74 1f 4b bd 8b 8a
d 70 3e b5 66 48 3 f6 e 61 35 57 b9 86 c1 1d 9e
e e1 f8 98 11 69 d9 8e 94 9b 1e 87 e9 ce 55 28 df
f 8c a1 89 d bf e6 42 68 41 99 2d f b0 54 bb 16
0 1 2 3 4 5 6 7 8 9 A B C D E F
0 52 9 6a d5 30 36 a5 38 bf 40 a3 9e 81 f3 d7 fb
1 7c e3 39 82 9b 2f ff 87 34 8e 43 44 c4 de e9 cb
2 54 7b 94 32 a6 c2 23 3d ee 4c 95 b 42 fa c3 4e
3 8 2e a1 66 28 d9 24 b2 76 5b a2 49 6d 8b d1 25
4 72 f8 f6 64 86 68 98 16 d4 a4 5c cc 5d 65 b6 92
5 6c 70 48 50 fd ed b9 da 5e 15 46 57 a7 8d 9d 84
6 90 d8 ab 0 8c bc d3 a f7 e4 58 5 b8 b3 45 6
7 d0 2c 1e 8f ca 3f f 2 c1 af bd 3 1 13 8a 6b
8 3a 91 11 41 4f 67 dc ea 97 f2 cf ce f0 b4 e6 73
9 96 ac 74 22 e7 ad 35 85 e2 f9 37 e8 1c 75 df 6e
a 47 f1 1a 71 1d 29 c5 89 6f b7 62 e aa 18 be 1b
b fc 56 3e 4b c6 d2 79 20 9a db c0 fe 78 cd 5a f4
c 1f dd a8 33 88 7 c7 31 b1 12 10 59 27 80 ec 5f
d 60 51 7f a9 19 b5 4a d 2d e5 7a 9f 93 c9 9c ef
e a0 e0 3b 4d ae 2a f5 b0 c8 eb bb 3c 83 53 99 61
f 17 2b 4 7e ba 77 d6 26 e1 69 14 63 55 21 c 7d
如果發現程序中有 S 盒或者動態生成了 S 盒,那么就可以確定采用了 AES 加密
RC4
RC4 加密算法屬於流加密算法,包括初始化函數和加解密函數,函數代碼具體如下:
/*初始化函數*/
void rc4_init(unsigned char*s,unsigned char*key,unsigned long Len) {
int i=0,j=0;
//char k[256]={0};
unsigned char tmp = 0;
for(i=0;i<256;i++) {
s[i]=i;
k[i]=key[i%Len];
}
for(i=0;i<256;i++) {
j=(j+s[i]+k[i])%256;
tmp=s[i];
s[i]=s[j];//交換s[i]和s[j]
s[j]=tmp;
}
}
/*加解密*/
void rc4_crypt(unsigned char*s,unsigned char*Data,unsigned Long Len) {
int i=0,j=0,t=0;
unsigned long k=0;
unsigned long tmp;
for(k=0;k<Len;k++){
i=(i+1)%256;
j=(j+s[i])%256;
tmp=s[i];
s[i]=s[j];//交換s[i]和s[j]
s[j]=tmp;
t=(s[i]+s[j])%256;
Data[k]^=s[t];
}
}
可以看出,初始化代碼對字符數組 s 進行了初始化賦值,且賦值分別遞增,之后又對 s 進行了 256 次變換操作。通過識別初始化代碼,可以判斷為 RC4 加密
MD5
MD5 消息摘要算法,是一種被廣泛使用的密碼散列函數,可以產生一個 128 位(16字節)的散列值,用於確保信息傳輸的完整性和一致性。MD5 加密的函數大致如下:
MD5_CTX md5c;
MD5Init(&md5c);
MD5UpdaterString(&md5c, plain);
MD5Final(digest,&md5c);
其中,MD5Init 會初始化四個稱作 MD5 鏈接變量的整數參數。因此如果看到這四個常數 0x67452301、0xefcdab89、0x98badcfe、0x10325476,就可以懷疑該函數是否為 MD5 算法了
MD5Init 函數代碼如下:
void MD5Init (MD5_CTX *context)
/*context*/
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants. */
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
匯總
特征值識別
各算法運算過程中使用到的特征常量如下:
但是有時出題人會故意對這些常量進行修改,因此在利用這一手段做出判斷后還需要通過動調等手段來對算法進行驗證
特征運算識別
當特征值不足以識別出算法時,可以通過分析程序是否使用了某些特征運算來鑒別算法,常見算法的特征運算如下:
同理,也許經過動調或復現等手段確認才可下定論