逆向分析中的密码学---AES

本文详细介绍了AES加密算法的原理,包括字节代换、行移位、列混合和轮密钥加等步骤,并展示了AES-128的加密流程。通过逆向分析一个软件,识别出其使用了AES加密和MD5哈希,解析了加密和解密过程。文章还提供了使用OpenSSL实现AES解密的示例代码,强调了RCON数组和S盒在识别魔改AES中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0x01 简介

AES加密,为对称加密算法,分组输入分组输出。3种AES对应的密钥长度、分组长度和轮数如下表。

密钥长度(N个32字节双字)分组长度(N个32位双字)轮数
AES-1284410
AES-1926412
AES-2568414

0x02 算法原理

算法加密流程如下图。主要包含4种轮函数:字节代换(SubByte)、行移位(ShiftRow)、列混合(MixColumn)、轮密钥加(AddRoundKey)。
AES-128加密主要分为下面5步:

  1. 密钥扩展得到每一轮的密钥,将输入复制到状态数组中
  2. 先进行初始密钥加
  3. 再进行9轮的字节代换、行移位、列混合、轮密钥加
  4. 最后一轮进行字节代换、列混合、轮密钥加(没有行移位)
  5. 将最后的结果复制到输出数组中

在这里插入图片描述
字节代换(subBytes)
(不考虑数学原理)字节代换可以当成一个简单的查表操作。AES定义了一个16*16字节的S-box。以状态数组中的每个字节元素的高4位作为行标,低4位作为列标,取出相应的元素作为SubBytes操作。例如,十六进制值(C5),高4位为C,低4位为5,取出S-box中的C行5列的A6替换C5。
在这里插入图片描述
行移位(ShiftRow)
对状态数组进行行移位操作。第一行保存不变,第2行循环左移1字节,第3行循环左移2字节,第4行循环左移3位。
在这里插入图片描述
列混合(MixColumn)

列混合可以看成是一个矩阵乘法的过程
在这里插入图片描述
轮密钥加(AddRoundKey)
将状态中的元素与轮密钥通过异或得到新的状态元素
在这里插入图片描述
密钥扩展(Key Expansion)
密钥扩展算法是Rijndael的密钥编排实现算法,其目的是根据种子密钥(用户密钥)生成多组轮密钥。轮密钥为多组128位密钥,对应不同密钥长度,分别是11,13,15组。11个子密钥存储在W[0]到W[43]中,第0轮为将128位的密钥填入W[0],W[1],W[2],W[3]中。其他的W计算方法如下:

  • W[4i]=W[4(i-1)]+g(W[[4i-1])
  • W[4i+j]=W[4i+j-1]+W[4(i-1)+j]

其中g的计算方法如图的左边部分。

  1. 将4个循环左移
  2. 执行按字节的S盒代换
  3. 轮系数Rcon[i]与最左边的字节相加。Rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 }

在这里插入图片描述

0x03 逆向分析

这里用的例子是加密与解密中的AESKeyGenMe.exe
利用PEiD的插件KANAL识别,可以识别到MD5和AES的S盒、逆S盒
在这里插入图片描述
用ida pro中的Findcrypt同样是识别到了
在这里插入图片描述
找到check函数。先对输入的用户名和序列号长度进行判断,如果用户名长度等于0,或者序列号长度!=32都显示Wrong Serial!
在这里插入图片描述
sub_4012F0函数
根据之前的学习,可以基本判断这是MD5Init函数,初始化了context
在这里插入图片描述sub_401320函数

上面已经识别到MD5Init函数,可以猜测后面的函数为MD5Update和MD5Final。其中sub_401440函数为MD5Transform。所以基本可以确定先对输入的用户名做一个MD5的计算。
在这里插入图片描述
sub_401EC0函数(aes_init)
函数原型为aes_init(aes* a,int mode,int nk,char* key,char* iv),主要是对aes结构体进行初始化。

  • a是AES结构体
  • mode是AES的工作模式,这里采用的是ECB
  • nk是密钥长度,0x10
  • key指向密钥数组,这里可以从v7数组得到{0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c}
  • iv是初始化向量,用于CBC模式,ECB用不到,所以设为NULL

在这里插入图片描述
sub_4023A0函数(aes_encrypt)
aes_init只后调用了aes_encrypt,根据aes结构体中的模式会去调用aes_ecb_encrypt。如下图所示。
在这里插入图片描述

所以这个KeyGenMe.exe的逻辑

  1. 比较输入的用户名和序列号长度是否正常
  2. 将输入的用户名进行MD5得到MD5_username
  3. 将序列号进行aes加密得到AES_serial
  4. 将得到的MD5_username和AES_serial进行比较

keyGen的制作就是将MD5(username)得到的值,用AES解密,即可得到序列号。

keyGenMe
可以利用openssl快速实现keyGenMe.用下面的编译命令来编译keyGen

gcc keyGenMe.c -o keyGenMe -lssl -lcrypto
#include<stdio.h>
#include<openssl/aes.h>
#include<openssl/md5.h>


int main(){
    MD5_CTX md5_ctx;
	unsigned char username[] = "pediy";
	unsigned char md5[16];
    unsigned char serial[16];

	MD5_Init(&md5_ctx);
	MD5_Update(&md5_ctx, username, strlen((char*)username));
	MD5_Final(md5,&md5_ctx);
	printf("字符串%s的MD5码为:",username);
	for (int i = 0; i < 16; i++) printf("%02x", md5[i]);
	printf("\n");

    //AES解密
    unsigned char key[] = {0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c};
    AES_KEY aes;
    AES_set_decrypt_key(key,128,&aes);
    AES_decrypt(md5,serial,&aes);
    printf("AES解密:");
    for (int i = 0; i < 16; i++) printf("%02x", serial[i]);
    printf("\n");
	return 0;
}

在这里插入图片描述
在这里插入图片描述

0x04 总结

现有工具的AES识别主要是集中在S盒和逆S盒。其实RCON数组,或者是其他一些结构体也可以用来对魔改AES进行识别。

《加密与解密第4版》
《深入浅出密码学》
https://github.com/matt-wu/AES

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值