Re 常见加解密算法识别与加解密脚本

2024-05-22

0. findcrypt3

https://github.com/polymorf/findcrypt-yara
好用的ida插件,帮助你快速识别算法。
当然了,有时候这个插件也不一定能帮助你找到这个问题,所以你需要知道一些常见算法的特征

1. 古典加密算法

1.1 caesar: 凯撒密码

凯撒密码的加密、解密可以通过取模的加减法进行计算。首先将字母用数字替代 A = 0,B = 1, …, Z = 25。 当偏移量为n的时候加密方法是

\[c = m + n {\ }mod {\,}26\]

解密方法是:

\[m = c - n {\ } mod {\,}26\]

其加解密脚本为:


key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
shift = 3

def encrypt_caesar(plaintext, shift):
    ciphertext = ''
    for char in plaintext:
        if char in key:
            ciphertext += key[(key.index(char) + shift) % 26]
        else:
            ciphertext += char
    return ciphertext

def decrypt_caesar(ciphertext, shift):
    return encrypt_caesar(ciphertext, -shift)


data = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG"
encrypt = encrypt_caesar(data, shift)
print(encrypt)
print(decrypt_caesar(encrypt,shift))

1.2 vigenere

viginere加密是从caesar引申而来的加密方式:

\[c_i = m_i + k_i {\;} mod {\;} 26\]

其实是把固定的值n 替换成了一组密钥k
解密方式:

\[m_i = c_i - k_i {\;} mod {\;} 26\]

其加解密脚本:


alpha = 'abcdefghijklmnopqrstuvwxyz'
key = 'hhhhh'

def encrypt_vigenere(plain_text, key):
    encrypted_text = ''
    key_length = len(key)
    key_index = 0
    for char in plain_text:
        if char in alpha:
            shift = alpha.index(key[key_index])
            encrypted_text += alpha[(alpha.index(char) + shift) % 26]
            key_index = (key_index + 1) % key_length
        else:
            encrypted_text += char
    return encrypted_text

def decrypt_vigenere(encrypted_text, key):
    decrypted_text = ''
    key_length = len(key)
    key_index = 0
    for char in encrypted_text:
        if char in alpha:
            shift = alpha.index(key[key_index])
            decrypted_text += alpha[(alpha.index(char) - shift) % 26]
            key_index = (key_index + 1) % key_length
        else:
            decrypted_text += char
    return decrypted_text

data = "attackatdawn"
encrypted_data = encrypt_vigenere(data, key)    
print(encrypted_data)
decrypted_data = decrypt_vigenere(encrypted_data, key)
print(decrypted_data)

2. base系列

2.1 base64

如果在程序中出现了base64的索引表,大概率是用了base64,有些人可能会对base64的表进行部分更换,问题也不大。

import base64

origin_charset = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
custom_charset = b"0123456789ABCMtuvwxNOPQRabcdefghijklSTUVWXDEFGHIJKLYZmnopqrsyz+/"
#custom_charset = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
def base64_encode(data):
    return base64.b64encode(data).translate(data.maketrans(origin_charset, custom_charset))

def base64_decode(data):
    return base64.b64decode(data.translate(data.maketrans(custom_charset, origin_charset)))

data = b"attackatdawn"
# print(data.maketrans(origin_charset, custom_charset))
# print(data.maketrans(custom_charset, origin_charset))
encoded_data = base64_encode(data)
print(encoded_data)
decoded_data = base64_decode(encoded_data)
print(decoded_data)

2.2 base32

也是一种加密方式,只不过相比于base64而言,字符更少:

import base64
#输入的数据必须是比特流
s = b'aaaaa'
enc = base64.b32encode(s)
print(enc)
print(base64.b32decode(enc))

3. TEA

关于TEA算法的识别,如果程序中出现了固定常数0x9e377969/0x61c88647,那么很有可能是tea加密或其变种

4. RC4

常见的流加密方式。识别方式为,初始代码中会对大小为256的表进行赋值和交换操作
RC4算法是可逆的,即encrypt和decrypt是一样的。

from Crypto.Cipher import ARC4

key=b"keykeykey"
plain =b"ctf_is_fun"

rc4 = ARC4.new(key)
cipher = rc4.encrypt(plain)
print(cipher)
# 注意,使用RC4时只能加密一次,如果要解密,需要重新初始化RC4对象
rc4 = ARC4.new(key)
dec = rc4.decrypt(cipher)
print(dec)

5. AES

aes的识别首先需要知道AES加密的步骤。
首先是根据key生成轮密钥。

1初始化:即 明文 和 密钥 作异或 前9轮:

一.字节替换(SubBytes): 用s盒对 输入进行字节替换
二.行移位(ShiftRows):输入化成4 * 4矩阵,第i行循环左移i个字节(i=0,1,2,3)
三.列混淆(MixColumns):输入化成4 * 4矩阵,乘以固定的矩阵
四.轮密钥加(AddRoundKey):输入与轮密钥矩阵异或

第10轮: 字节替换、行移位、轮密钥加

因此如果代码中发现了s盒(s盒可以参加仓库的aes的c代码),可以判断是aes加密,具体模式需要自己判断

5.1 AES加解密脚本

AES ECB模式为例

from Crypto.Cipher import AES

key = b'1234567890123456'
aes = AES.new(key, AES.MODE_ECB)

# Encrypt
data = b'Hello, world!!!!'
encrypt=aes.encrypt(data)
print(encrypt)

# decrypt
decrypt=aes.decrypt(encrypt)
print(decrypt)

6. MD5

md5加密的加密步骤通常如下:

md5_ctx sample
md5_init(&sample)
md5_update_string(&sample,plain)
md5_final(digest,&sample)

在md5_init函数中,会出现初始化赋值0x67452301 0xefcdab89 0x98badcfe 0x10325476,即有可能是md5加密