从CTF和勒索样本中学习AES加密算法逆向识别
字数 1602 2025-08-22 12:23:36

AES加密算法逆向识别与实战分析

1. AES加密算法概述

AES(Advanced Encryption Standard)又称Rijndael加密法,是用于取代DES的对称加密算法,具有以下特点:

  • 分组大小为128位的分组密码
  • 支持三种密钥长度:128位、192位和256位
  • 软硬件实现高效
  • 加密轮数:128位10轮、192位12轮、256位14轮
  • 明文长度必须是16的倍数,不足时需要填充

1.1 填充模式

常见填充模式包括:

  • NONE
  • PKCS7
  • ZERO
  • ANSI923
  • IOS7816_4
  • IOS10126

2. AES加密流程详解

2.1 加密过程概述

完整加密流程分为三个阶段:

  1. 初始轮(1)

    • AddRoundKey:明文矩阵与第一轮密钥异或
  2. 中间轮(2~9/11/13)

    • SubBytes:字节替换
    • ShiftRows:行移位
    • MixColumns:列混淆
    • AddRoundKey:轮密钥加
  3. 最终轮(10/12/14)

    • SubBytes
    • ShiftRows
    • AddRoundKey

2.2 核心组件

2.2.1 State(状态矩阵)

  • 将明文数据分成多个4×4的数据块
  • 第一个字节位于第一列第一行,第二个字节位于第一列第二行,以此类推

2.2.2 S盒(S-Box)

  • 用于SubBytes操作的替换表
  • 加密使用S-Box,解密使用逆S-Box
  • 标准AES提供固定的S-Box表

2.2.3 密钥扩展(Key Expansion)

将原始密钥扩展为轮密钥数组:

# Round Constants (AES-128)
RCON = [None, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36]

def subword(self, word):
    """AES SubWord方法"""
    bs = struct.pack('>I', word)
    nw = []
    for b in bs:
        nw.append(self.s_box[b])
    nw = struct.unpack('>I', bytes(nw))[0]
    return nw

def rotword(self, word):
    """AES RotateWord方法"""
    bs = list(struct.pack('>I', word))
    bs.append(bs.pop(0))
    nw = struct.unpack('>I', bytes(bs))[0]
    return nw

def key_expansion(self, key):
    """AES密钥扩展算法"""
    ek = []
    i = 0
    
    # 保存原始密钥
    while i < 4:  # AES-128为4个字
        b = bytes(key[i*4:(i*4)+4])
        w = struct.unpack('>I', b)[0]
        ek.append(w)
        i += 1
    
    # 生成扩展密钥
    while i < 44:  # AES-128生成44个字
        tmp = ek[i-1]
        if i % 4 == 0:
            rcon_val = struct.unpack('>I', bytes([self.RCON[i//4], 0, 0, 0]))[0]
            tmp = self.subword(self.rotword(tmp)) ^ rcon_val
        nw = tmp ^ ek[i-4]
        ek.append(nw)
        i += 1
    return ek

2.3 加密操作详解

2.3.1 AddRoundKey(轮密钥加)

将数据矩阵与密钥矩阵进行逐字节异或:

def add_round_key(s, k):
    for i in range(4):
        for j in range(4):
            s[i][j] ^= k[i][j]

2.3.2 SubBytes(字节替换)

使用S-Box进行字节替换:

def sub_bytes(s):
    for i in range(4):
        for j in range(4):
            s[i][j] = s_box[s[i][j]]

2.3.3 ShiftRows(行移位)

  • 第一行不变
  • 第二行左移1字节
  • 第三行左移2字节
  • 第四行左移3字节
def shift_rows(grid, inv=False):
    for i in range(4):
        if inv:  # 解密
            grid[i::4] = grid[i::4][-i:] + grid[i::4][:-i]
        else:    # 加密
            grid[i::4] = grid[i::4][i:] + grid[i::4][:i]

2.3.4 MixColumns(列混淆)

在GF(2^8)有限域做矩阵乘法:

def mix_columns(grid):
    def mul_by_2(n):
        s = (n << 1) & 0xff
        if n & 128:
            s ^= 0x1b
        return s
    
    def mul_by_3(n):
        return n ^ mul_by_2(n)
    
    def mix_column(c):
        return [
            mul_by_2(c[0]) ^ mul_by_3(c[1]) ^ c[2] ^ c[3],
            c[0] ^ mul_by_2(c[1]) ^ mul_by_3(c[2]) ^ c[3],
            c[0] ^ c[1] ^ mul_by_2(c[2]) ^ mul_by_3(c[3]),
            mul_by_3(c[0]) ^ c[1] ^ c[2] ^ mul_by_2(c[3])
        ]
    
    for i in range(0, 16, 4):
        grid[i:i+4] = mix_column(grid[i:i+4])

3. AES优化实现:T表(T-Table)方法

为提高效率,将MixColumns、ShiftRows和SubBytes合并为查找表操作。

3.1 T表生成

def gmul(a, b):
    """AES专用乘法函数"""
    p = 0
    for c in range(8):
        if b & 1:
            p ^= a
        a <<= 1
        if a & 0x100:
            a ^= 0x11b
        b >>= 1
    return p

def generate_t_tables(self):
    """生成AES查找表方法使用的T表"""
    self.t1 = []
    self.t2 = []
    self.t3 = []
    self.t4 = []
    self.t5 = []
    
    for i in range(len(self.s_box)):
        word1 = [gmul(self.s_box[i], 2), self.s_box[i], self.s_box[i], gmul(self.s_box[i], 3)]
        word2 = [gmul(self.s_box[i], 3), gmul(self.s_box[i], 2), self.s_box[i], self.s_box[i]]
        word3 = [self.s_box[i], gmul(self.s_box[i], 3), gmul(self.s_box[i], 2), self.s_box[i]]
        word4 = [self.s_box[i], self.s_box[i], gmul(self.s_box[i], 3), gmul(self.s_box[i], 2)]
        word5 = [self.s_box[i]] * 4
        
        self.t1.append(struct.unpack('>I', bytes(word1))[0])
        self.t2.append(struct.unpack('>I', bytes(word2))[0])
        self.t3.append(struct.unpack('>I', bytes(word3))[0])
        self.t4.append(struct.unpack('>I', bytes(word4))[0])
        self.t5.append(struct.unpack('>I', bytes(word5))[0])

3.2 基于T表的加密实现

def cipher_t_table(self, pt):
    """查找表实现的AES加密"""
    ct = []
    around_key = [0, 0, 0, 0]
    tmp = [0, 0, 0, 0]
    
    # 初始化轮密钥
    around_key[0] = struct.unpack('>I', pt[0:4])[0] ^ self.ek[0]
    around_key[1] = struct.unpack('>I', pt[4:8])[0] ^ self.ek[1]
    around_key[2] = struct.unpack('>I', pt[8:12])[0] ^ self.ek[2]
    around_key[3] = struct.unpack('>I', pt[12:16])[0] ^ self.ek[3]
    
    # 前9轮加密
    for round in range(1, 10):
        for i in range(4):
            tmp[i] = (self.t1[(around_key[i] >> 24) & 0xff] ^ 
                      self.t2[(around_key[(i+1)%4] >> 16) & 0xff] ^ 
                      self.t3[(around_key[(i+2)%4] >> 8) & 0xff] ^ 
                      self.t4[(around_key[(i+3)%4]) & 0xff] ^ 
                      self.ek[(round*4)+i])
        around_key = tmp.copy()
    
    # 最后一轮加密
    for i in range(4):
        ct.append(self.s_box[(around_key[i] >> 24) & 0xff] ^ ((self.ek[-4+i] >> 24) & 0xff))
        ct.append(self.s_box[(around_key[(i+1)%4] >> 16) & 0xff] ^ ((self.ek[-4+i] >> 16) & 0xff))
        ct.append(self.s_box[(around_key[(i+2)%4] >> 8) & 0xff] ^ ((self.ek[-4+i] >> 8) & 0xff))
        ct.append(self.s_box[(around_key[(i+3)%4]) & 0xff] ^ ((self.ek[-4+i]) & 0xff))
    
    return bytes(ct)

4. AES逆向识别实战

4.1 强网拟态2024 babyre题目分析

  1. 识别加密函数

    • 主函数调用sub_401550进行解密
    • sub_401bce被调用3次,疑似AddRoundKey操作
  2. 识别S-Box

    • 作者将S-Box写成4字节间隔,增加识别难度
    • 可通过标准S-Box交叉验证
  3. 识别密钥扩展

    • 查找轮常量(RCON)特征
    • 识别密钥扩展函数中的S-Box替换和轮常量异或操作

4.2 Sodinokibi勒索软件分析

  1. 识别T表

    • 计算T表前4字节:0xc66363a5, 0xa5c66363, 0x63a5c663, 0x6363a5c6
    • 在IDA中搜索这些特征值定位T表
  2. 识别加密流程

    • 跟踪T表的使用位置
    • 识别轮密钥加操作
    • 根据轮数判断AES版本(128/192/256)

5. 逆向识别技巧总结

  1. 识别S-Box

    • 查找256字节的固定表
    • 标准S-Box以0x63开头
  2. 识别轮常量(RCON)

    • 查找0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36序列
  3. 识别T表

    • 查找4个256项的查找表
    • 计算前几项验证是否为T表
  4. 判断AES版本

    • 根据轮数:10轮(AES-128), 12轮(AES-192), 14轮(AES-256)
    • 根据密钥扩展后的轮密钥数量
  5. 识别加密模式

    • ECB模式:相同的明文块产生相同的密文块
    • CBC模式:需要初始向量(IV),状态矩阵作为下一轮输入

6. 参考资源

  1. AES标准文档
  2. OpenSSL AES实现
  3. AES可视化工具
AES加密算法逆向识别与实战分析 1. AES加密算法概述 AES(Advanced Encryption Standard)又称Rijndael加密法,是用于取代DES的对称加密算法,具有以下特点: 分组大小为128位的分组密码 支持三种密钥长度:128位、192位和256位 软硬件实现高效 加密轮数:128位10轮、192位12轮、256位14轮 明文长度必须是16的倍数,不足时需要填充 1.1 填充模式 常见填充模式包括: NONE PKCS7 ZERO ANSI923 IOS7816_ 4 IOS10126 2. AES加密流程详解 2.1 加密过程概述 完整加密流程分为三个阶段: 初始轮(1) : AddRoundKey:明文矩阵与第一轮密钥异或 中间轮(2~9/11/13) : SubBytes:字节替换 ShiftRows:行移位 MixColumns:列混淆 AddRoundKey:轮密钥加 最终轮(10/12/14) : SubBytes ShiftRows AddRoundKey 2.2 核心组件 2.2.1 State(状态矩阵) 将明文数据分成多个4×4的数据块 第一个字节位于第一列第一行,第二个字节位于第一列第二行,以此类推 2.2.2 S盒(S-Box) 用于SubBytes操作的替换表 加密使用S-Box,解密使用逆S-Box 标准AES提供固定的S-Box表 2.2.3 密钥扩展(Key Expansion) 将原始密钥扩展为轮密钥数组: 2.3 加密操作详解 2.3.1 AddRoundKey(轮密钥加) 将数据矩阵与密钥矩阵进行逐字节异或: 2.3.2 SubBytes(字节替换) 使用S-Box进行字节替换: 2.3.3 ShiftRows(行移位) 第一行不变 第二行左移1字节 第三行左移2字节 第四行左移3字节 2.3.4 MixColumns(列混淆) 在GF(2^8)有限域做矩阵乘法: 3. AES优化实现:T表(T-Table)方法 为提高效率,将MixColumns、ShiftRows和SubBytes合并为查找表操作。 3.1 T表生成 3.2 基于T表的加密实现 4. AES逆向识别实战 4.1 强网拟态2024 babyre题目分析 识别加密函数 : 主函数调用sub_ 401550进行解密 sub_ 401bce被调用3次,疑似AddRoundKey操作 识别S-Box : 作者将S-Box写成4字节间隔,增加识别难度 可通过标准S-Box交叉验证 识别密钥扩展 : 查找轮常量(RCON)特征 识别密钥扩展函数中的S-Box替换和轮常量异或操作 4.2 Sodinokibi勒索软件分析 识别T表 : 计算T表前4字节:0xc66363a5, 0xa5c66363, 0x63a5c663, 0x6363a5c6 在IDA中搜索这些特征值定位T表 识别加密流程 : 跟踪T表的使用位置 识别轮密钥加操作 根据轮数判断AES版本(128/192/256) 5. 逆向识别技巧总结 识别S-Box : 查找256字节的固定表 标准S-Box以0x63开头 识别轮常量(RCON) : 查找0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36序列 识别T表 : 查找4个256项的查找表 计算前几项验证是否为T表 判断AES版本 : 根据轮数:10轮(AES-128), 12轮(AES-192), 14轮(AES-256) 根据密钥扩展后的轮密钥数量 识别加密模式 : ECB模式:相同的明文块产生相同的密文块 CBC模式:需要初始向量(IV),状态矩阵作为下一轮输入 6. 参考资源 AES标准文档 OpenSSL AES实现 AES可视化工具