参考文章(多数都是搬这个老登的): https://www.cnblogs.com/gaoyucan/p/17087521.html
流密码
常见的有 RC4、Salsa20 以及 ChaCha20.之前一直是识别加密算法,虽然只会识别一个rc4,遇到其他还是傻眼,一直没想到流密码的密文是仅由明文与密钥流异或得到的,以此识别出流密码后,动调获取密钥流或者将密文patch进去拿输出即可.(明明就在高神的流密码第一段,这么久了才发现)
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 char tmp;
for (k = 0; k < Len; k++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j]; // 交换s[x]和s[y]
s[j] = tmp;
t = (s[i] + s[j]) % 256;
Data[k] ^= s[t];
}
}
Salsa20
遇到的话,有时间就补
ChaCha20
同上,暂时记一下例题[RCTF2022 checkserver],顺便附一个识别图,感觉好像见过
分组加密
Tea
#include
void encrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0, i; /* set up */
uint32_t delta=0x9e3779b9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i < 32; i++) { /* basic cycle start */
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
} /* end cycle */
v[0]=v0; v[1]=v1;
}
void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i; /* set up */
uint32_t delta=0x9e3779b9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i<32; i++) { /* basic cycle start */
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
} /* end cycle */
v[0]=v0; v[1]=v1;
}
Tea类加密很好识别,delta=_0x9e3779b9会被魔改
XTea
#include
/* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */
void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
for (i=0; i < num_rounds; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
}
v[0]=v0; v[1]=v1;
}
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
for (i=0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0]=v0; v[1]=v1;
}
与tea区别sum+=delta位置,key[(sum>>11) & 3]与key[sum & 3],其中detal会被魔改,移位数可能被魔改
XXTea
#define DELTA 0x9e3779b9
#define MX ((z>>5^y<<2) + (y>>3^z<<4) ^ (sum^y) + (k[p&3^e]^z))
long btea(long* v, long n, long* k) {
unsigned long z=v[n-1], y=v[0], sum=0, e;
long p, q ;
if (n > 1) { /* Coding Part */
q = 6 + 52/n;
while (q-- > 0) {
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++) y = v[p+1], z = v[p] += MX;
y = v[0];
z = v[n-1] += MX;
}
return 0 ;
} else if (n < -1) { /* Decoding Part */
n = -n;
q = 6 + 52/n;
sum = q*DELTA ;
while (sum != 0) {
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--) z = v[p-1], y = v[p] -= MX;
z = v[n-1];
y = v[0] -= MX;
sum -= DELTA;
}
return 0;
}
return 1;
}
一般来说,识别可以通过,delta 以及round = 6 + 52/n
、(sum >> 2) & 3
这种特殊的运算来判断。
这里v指密文或者明文:n指round【len(flag)/4】正是加密,负是解密:k指密钥
魔改点:(1)(sum>> 2) & 3改为(sum >> 2)& 5 (2)delta值
DES
DES的密钥位64bit,但每个字节的第八位(最后一位)是奇偶校验位,所以有效密钥为56bit
主要通过 S盒 以及各个置乱表来识别,可以使用插件来自动化识别这些特征。
AES
AES(Advanced Encryption Standard,高级加密标准),分组大小为128位,根据密钥长度和轮数可以分为 AES-128、AES-192、AES-256,具体区别如下表:
AES-128 | AES-192 | AES-256 | |
---|---|---|---|
密钥长度 | 128 | 192 | 256 |
轮数 | 10 | 12 | 14 |
对于如何识别是哪一种,可能看密钥大小不好观察,可以选择看循环的次数
整体流程
整体来说AES加密有如下几步
- 密钥拓展,使用密钥拓展算法通过初始密钥获取轮密钥
- AES使用一个密钥扩展算法将原始密钥生成多个轮密钥(Round Keys),这些轮密钥在后续的加密轮次中使用。对于128位密钥,会生成10轮密钥
- 初始轮密钥加
- 将明文数据(明文)与第一个轮密钥进行异或(XOR)运算,得到初始状态。
- 主加密轮
- S盒替换(SubBytes)
- 行移位(ShiftRows)
- 列混合(MixColumns)
- 轮密钥加(AddRoundKey)
- 最后一轮(与主加密轮类似,但省略列混合)
- S盒替换(SubBytes)
- 行移位(ShiftRows)
- 轮密钥加(AddRoundKey)
魔改
- 在某一步实现的函数里面加一个可逆的运算(一般是异或).
- 将行移位与列混合的顺序调换一下.
- S盒代换中将S盒修改一下
- 密钥拓展被修改,不进行分析哪里修改,直接动调将生成的轮密钥dump下来,之后对着源码,将密钥拓展函数(static void KeyExpansion())过程注释,将dump下来的轮密钥直接赋值给RoundKey
基础知识
IV
- 作用
- 防止相同的明文产生相同的密文
- 增强安全性: IV能有效防止重放攻击(patch密文)和某些模式下的分析攻击,特别是在某些分组加密模式(如CBC模式)中,IV的引入可以避免加密块之间存在的相似性,从而进一步提升加密强度。
- 本质:
- IV是加密算法中用来引入随机性或不可预测性的一个输入值,其本身并不需要保密,但它必须是唯一且随机生成的,至少对每次加密来说不能重复使用。IV本质上与密钥不同,密钥是保持加密解密过程的机密性,而IV只是引入随机性的手段。(但是对于真正做逆向的时候会是什么情况,下次遇到仔细分析)
分组大小
- 分组大小指的是加密算法处理的固定数据块的大小(例如AES分组大小为128bit)
- 在每次加密/解密时,AES会将输入的数据分成若干个128bit的数据块
- 如果输入的数据长度超过128位,AES会将数据分块处理.如果数据不足128位,通常会进行填充(padding)以凑满128位。
- 例如
- 如果明文数据为64字节(512bit),AES将这64字节的数据分为四个128位的分组,逐一进行加解密
- 如果明文数据不是128位的整数倍(比如输入是150位的明文),就会使用填充算法来凑齐到128位的倍数。
注意
- 在遇到移位操作时,ida识为什么类型int or uint,再解密时便使用什么类型,如果int型密文报错便(int)强转一下