Zj_W1nd's BLOG

常见的加密编码算法逆向识别

2025/03/12

参考自 https://www.cnblogs.com/Moomin/p/15004170.html#aes

Base64

识别

一个索引串ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

IO

可能做魔改调整, 6位索引一个ascii码的索引换掉,此时我们用bytes.maketrans方法定义一个转换函数即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import base64
encoded_data = base64.b64encode(data.encode('utf-8'))
decoded_data = base64.b64decode(encoded_data).decode('utf-8')

# 魔改:
custom_alphabet = "ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/"

custom_b64encode_table = bytes.maketrans(
b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
custom_alphabet.encode('utf-8')
)
custom_b64decode_table = bytes.maketrans(
custom_alphabet.encode('utf-8'),
b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
)

def custom_b64encode(data):
encoded = base64.b64encode(data)
return encoded.translate(custom_b64encode_table)

def custom_b64decode(data):
translated = data.translate(custom_b64decode_table)
return base64.b64decode(translated)

# 使用自定义索引表进行编码
encoded_data = custom_b64encode(data.encode('utf-8'))
decoded_data = custom_b64decode(encoded_data).decode('utf-8')

RC4

识别

对称,流加密,2个核心,初始化S盒,加密和解密是对称的。识别方式主要是看一个256次的for循环,尤其是s盒初始化函数,其对256字节的数组按照下标从0开始赋值,这一特征比较明显。

其他特征可以参考下面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*初始化函数*/
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];
}
}

IO

需求crypto模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from Crypto.Cipher import ARC4
from Crypto.Random import get_random_bytes

# 生成一个随机密钥
key = get_random_bytes(16)

# 初始化RC4加密器
cipher = ARC4.new(key)

# 加密数据
data = "Hello, World!"
encrypted_data = cipher.encrypt(data.encode('utf-8'))
print(f"Encrypted: {encrypted_data}")

# 初始化RC4解密器
cipher = ARC4.new(key)

# 解密数据
decrypted_data = cipher.decrypt(encrypted_data).decode('utf-8')
print(f"Decrypted: {decrypted_data}")

注意的是,rc4是一个流加密算法,每次初始化只能获得一个固定的加密器,即new一次之后,后续调用encrypt时会一直“继续”当前的加密,即假设几次需要加密的明文是连续的。如果题目中的rc4每次调用都走了一遍初始化流程,则io也需要对应的每次都new一个新的加密器——即使密钥没有发生变化。

另外,rc4作为对称加密,加解密算法是一样的。

AES

识别

老生常谈,标准AES的识别就是其独有的S盒内容。其S盒和逆S盒数据如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   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

前4个字节就够了,search一下发现了基本100%是AES。相关函数全跳过就行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
graph TD
A[明文] -->|分组| B[初始轮密钥加]
B --> C[轮函数]
C -->|重复Nr-1次| D[最终轮]
D --> E[密文]

subgraph 轮函数
C1[字节代换] --> C2[行移位]
C2 --> C3[列混淆]
C3 --> C4[轮密钥加]
end

subgraph 最终轮
D1[字节代换] --> D2[行移位]
D2 --> D3[轮密钥加]
end

可能有魔改,如果识别算法的话重点在以下:

  • 初始化16*11大小的扩展密钥(其中第一个16字节包含原始秘钥,每4字节颠倒,即abcdabcd->dcbadcba)

  • 行移位和列混合算法的特征

IO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad

# 生成一个随机密钥
key = get_random_bytes(16) # AES-128
iv = get_random_bytes(16) # 初始化向量

# 初始化AES加密器
cipher = AES.new(key, AES.MODE_CBC, iv)

# 加密数据
data = "Hello, World!"
padded_data = pad(data.encode('utf-8'), AES.block_size)
encrypted_data = cipher.encrypt(padded_data)
print(f"Encrypted: {encrypted_data}")

# 初始化AES解密器
cipher = AES.new(key, AES.MODE_CBC, iv)

# 解密数据
decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size).decode('utf-8')
print(f"Decrypted: {decrypted_data}")

TEA

目前没遇见过,只能抄了

tea也是一个简单的对称加密算法,初始化一个128位密钥,按64位分组处理明文。其中有一个magic_number DELTA:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<stdio.h>
#include<stdint.h>
#define DELTA 0x9981abcd

void tea_encrypt(unsigned int* v, unsigned int* key) {
unsigned int l = v[0], r = v[1], sum = 0;
for (size_t i = 0; i < 32; i++) { //进行32次迭代加密,Tea算法作者的建议迭代次数
l += (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
sum += DELTA; //累加Delta的值
r += (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]); //利用多次双位移和异或将明文与密钥扩散混乱,并将两个明文互相加密
}
v[0] = l;
v[1] = r;
}

void tea_decrypt(unsigned int* v, unsigned int* key) {
unsigned int l = v[0], r = v[1], sum = 0;
sum = DELTA * 32; //32次迭代累加后delta的值
for (size_t i = 0; i < 32; i++) {
r -= (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]);
sum -= DELTA;
l -= (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
}
v[0] = l;
v[1] = r;
}


int main(int argc, char const *argv[])
{
unsigned int key1[4]={0xa3eeb7be,0x50e7de9a,0x6dbcc2bc,0x78591fad};//key1
unsigned int key2[4]={0x78591fad,0x6dbcc2bc,0xa3eeb7be,0x50e7de9a};//key2
unsigned int v1[2] = {0x556E2853,0x4393DF16};
unsigned int v2[2] = {0x1989FB2B,0x83F5A243};

//encrypt(v1,key1);
//printf("tea_encrypt:%x %x\n",v1[0],v1[1]);
//encrypt(v2,key2);
//printf("tea_encrypt:%x %x\n",v2[0],v2[1]);
tea_decrypt(v1,key1);
printf("tea_decrypt:%x %x\n",v1[0],v1[1]);
tea_decrypt(v2,key2);
printf("tea_decrypt:%x %x\n",v2[0],v2[1]);
return 0;
}

//tea_decrypt:c0cacd59 38bb7623
//tea_decrypt:8757d16 a520cece

其中默认的DELTA一般为 0x9e3779b9 或者 0x61c88647(分别是加和减,其实影响是等价的)

魔改算法一般会修改这个DELTA值,不过识别也很容易,这个值太孤立了。

IO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
DELTA = 0x9981abcd  # 自定义 DELTA 值

def tea_encrypt(v, key):
l, r = v[0], v[1]
sum = 0
for _ in range(32): # 进行32次迭代加密
l += (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3])
sum += DELTA
r += (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3])
return [l, r]

def tea_decrypt(v, key):
l, r = v[0], v[1]
sum = DELTA * 32 # 32次迭代累加后delta的值
for _ in range(32):
r -= (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3])
sum -= DELTA
l -= (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3])
return [l, r]

# 示例数据
key1 = [0xa3eeb7be, 0x50e7de9a, 0x6dbcc2bc, 0x78591fad]
key2 = [0x78591fad, 0x6dbcc2bc, 0xa3eeb7be, 0x50e7de9a]
v1 = [0x556E2853, 0x4393DF16]
v2 = [0x1989FB2B, 0x83F5A243]

# 加密
encrypted_v1 = tea_encrypt(v1, key1)
encrypted_v2 = tea_encrypt(v2, key2)
print(f"Encrypted v1: {encrypted_v1}")
print(f"Encrypted v2: {encrypted_v2}")

# 解密
decrypted_v1 = tea_decrypt(encrypted_v1, key1)
decrypted_v2 = tea_decrypt(encrypted_v2, key2)
print(f"Decrypted v1: {decrypted_v1}")
print(f"Decrypted v2: {decrypted_v2}")

MD5

识别

128位散列值,需要一个context结构体,分三步,init,updatestring和final

其中init过程会将context初始化为4个固定的magic_number:

1
2
3
4
5
6
7
8
9
10
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;
}

IO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import hashlib

# 要计算哈希值的字符串
data = "Hello, World!"

# 创建一个 MD5 哈希对象
md5_hash = hashlib.md5()

# 更新哈希对象
md5_hash.update(data.encode('utf-8'))

# 获取十六进制的哈希值
hash_value = md5_hash.hexdigest()

print(f"MD5 Hash: {hash_value}")
CATALOG
  1. 1. Base64
    1. 1.1. 识别
    2. 1.2. IO
  2. 2. RC4
    1. 2.1. 识别
    2. 2.2. IO
  3. 3. AES
    1. 3.1. 识别
    2. 3.2. IO
  4. 4. TEA
    1. 4.1. IO
  5. 5. MD5
    1. 5.1. 识别
    2. 5.2. IO