在密码学中,RC4 是一种流加密算法,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法。RC4 是有线等效加密(WEP)中采用的加密算法,也曾经是 TLS 可采用的算法之一。
流密码也属于对称密码,但与分组加密算法不同的是,流密码不对明文数据进行分组,而是用密钥生成与明文一样长短的密码流对明文进行加密,加解密使用相同的密钥。也就是说,RC4不是对明文进行分组处理,而是字节流的方式依次加密明文中的每一个字节。
RC4 由伪随机数生成器和异或运算组成(由于异或运算的对合性,RC4 加密解密使用同一套算法)。RC4 的密钥长度可变,范围是1~255。给定一个密钥,伪随机数生成器接受密钥并产生一个 S 盒。S 盒用来加密数据,而且在加密过程中 S 盒会变化。
先初始化状态向量S(256 个字节,用来作为密钥生成的种子)按照升序,给每个字节赋值。
初始密钥(由用户输入),长度任意,如果输入长度小于 256 个字节,则进行轮转,直到填满。例如填入密钥的是1 2 3 4 5 ,那么填入的是1,2,3,4,5,1,3,4,5,1,2,3,4,5 由上述轮转过程得到 256 个字节的向量T(用来作为密钥流生成的种子)
最后是根据向量S和T生成T生成密钥流与明文进行加密
几个基本变量:
初始化长度为 256 的S盒。第一个for循环将 0 到 255 的互不重复的元素装入S盒。第二个for循环根据密钥打乱S盒,i确保S-box的每个元素都得到处理,j保证S-box的搅乱是随机的。
每收到一个字节,就进行循环。通过一定的算法定位S-box中的一个元素,并与输入字节异或,得到k。循环中还改变了S-box。如果输入的是明文,输出的就是密文;如果输入的是密文,输出的就是明文。
RC4 算法主要通过加密算法特征来进行识别。
RC4 常见的魔改方法:
魔改初始化算法,可以将S盒初始化值并不设置成 0-255,也可以设置成其它的,也可以在S的初始置换过程中添加可逆运算。
由于最后加密 flag 是利用密钥流来单字节加密的,也有人会在这个地方添加一些可逆运算来进行魔改。
例:

总之算法需要遵循对称加密性质:
2024Moectf RC4
题目存在花指令,我们先进行去除。去除后我们分析代码。
根据题目中的RC4字样我们就可以判断程序为 RC4 算法。
ida 反编译程序直接看到了一串包含RC4字样疑似密钥的字符,可以猜测这段字符就是密钥。
然后我们找密文尝试解密,上面的三个字符串都是一样的,我们可以尝试一下它们是不是密文。

假定程序是一个标准 RC4,编写解密脚本,然后成功解密。
写加密脚本最好还是用 python,一个是快,另一个是可以避免类型错误。
2024极客大挑战 让我康康你的调试
分析代码,程序第输入进行了异或加密,然后将加密后的输入内容作为参数传入了sub_14A6,接下来我们跟进分析。

很明显就可以看出来这是一个 rc4 加密算法,我们这里通过动态调试的方法来解这道题。

首先我们将程序动态调试起来,然后输入一段符号输入要求长度的测试数据。
本题代码中输入要求为 33 字节,我们构造一个 33 字节的字符串,将程序动态调试起来然后输入。
输入完成后,我们让程序运行到执行完加密逻辑后的代码部分。

然后我们提取加密后的密文,即v5[9]。

这里我们可以通过插件 Lazyida 快速提取。

然后我们再次动态调试程序将 33 个a输入程序来占位,然后我们在加密逻辑之前下断点让运行到这里停下。
之后使用我们的 Lazyida 插件的 Paste data 功能将提取出的密文粘贴到占位的a中,直接选中头字符即可。

我们让程序走过加密逻辑后再次查看密文,可以看到已经变成了我们最初输入的明文a。这里我们已经可以判断程序的加解密是对称的,也就意味着我们只要把程序的密文输入到程序中经过加密逻辑解密就会被解密成明文。

我们可以猜测这这个被数据初始化的数组就是我们的密文。

我们动态调试运行然后通过 lazyida 提取初始化后的密文数据。

然后我们和上面的逻辑一样将程序输入足够的字符占位,然后再把密文复制进去之后再运行程序解密。
运行之后可以看到我们已经成功解出了 flag。

YLCTF xorplus
ida 反编译,从函数名称就可以判断为 rc4 加密,接下来我们寻找密钥。

在主函数中找到密钥,然后分析 rc4 算法是否是标准 rc4。

分析发现在 rc4 初始化部分存在魔改,即v8 = (v8 + *(k + a1) + v9[k] + 1300) % 256;。
接下来分析一下加密部分。

算法加密部分同样存在魔改,*(a2 + i) = (*(v8 + a1) ^ *(a2 + i)) + 20;。

最后我们获取平台给的密文,然后根据魔改后的加密代码逻辑编写解密代码。
RC4加密算法与逆向方法分析
CTF 从0到1
for(int i=0;i<255;i++){
S[i]=i;
T[i]=K[i%keylen]
}
j=0;
for(int i=0;i<255;i++){
j=(j+S[i]+T[i])%256;
swap(S[i],S[j]);
}
i,j=0;
for(int r=0;r<len;r++){
i=(i+1)%256;
j=(j+S[i])%256;
swap(S[i],S[j]);
t=(S[i]+S[j])%256;
k[r]=S[t];
data[r]^=k[r];
}
for(int i=0;i<255;i++){
S[i]=i;
T[i]=K[i%keylen]
}
j=0;
for(int i=0;i<255;i++){
j=(j+S[i]+T[i])%256;
swap(S[i],S[j]);
}
i,j=0;
for(int r=0;r<len;r++){
i=(i+1)%256;
j=(j+S[i])%256;
swap(S[i],S[j]);
t=(S[i]+S[j])%256;
k[r]=S[t];
data[r]^=k[r];
}
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[j]=tmp;
}
}
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[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[j]=tmp;
t=(s[i]+s[j])%256;
data[k]^=s[t];
}
}
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];
[培训]传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!