做题前,我们先了解Rc4算法的相关知识
加密过程:密钥^明文=密文 解密过程:密文^密钥=明文 (此处两密钥一致)
关键变量:
1,密钥K,长度1-256字节,密钥的长度与明文长度密钥流长度没必然关系,通常16字节
2,密钥流:明文和密钥生成相应的密钥流,密钥流的长度和明文,密文的长度是相等的,密文第i字节=明文第i字节^密钥流第i字节(密钥流由明文和密钥生成)
3,状态向量S,长度为256,S[0],S[1],每个单元都是一个字节,任何时候,S都包括取值范围在0-255的8bit数的排列组合,其中数的位置会发生变化,
4,临时向量T,长度256,由密钥给他赋值,如果密钥长度为256,直接copy给他,如果密钥长度不是256,那么则会轮转的将密钥的每个字节赋值给T
原理一般分为3步:
1,用户输入密钥,一般为一个字符串,对密钥进行了初始化
2,对S数组进行初始化,由0-255依次赋值
3,打乱S数组,对其进行排序
4,产生密钥流(由明文和密钥生成)
如何区分是否是Rc4算法
首先看初始化状态向量,形如:
for(int i=0;i<256;i++){
S[i]=i;
}
再看初始密钥,有没有字符串之类的进行赋值
最后再看,有没有对某一数组的每一位进行了处理,打乱S数组,生成密钥流等等,形如:
int temp=0,j=0;
for(int i=0;i<256;i++){
j=(j+S[i]+T[i])%256;
temp=S[i];
S[i]=S[j];
S[j]=temp; 这边辨别出来的关键点是,看是不是挨个字节进行打乱,每一位都在变化
}
好,那么好,Rc4算法简单介绍完了,那么开始做题
首先,查壳
发现是没壳的,64bit的,那就丢进ida64中进行反编译,左侧函数栏中,单击任意函数,然后ctrl+f搜索main函数,然后tap,转换为c代码简单分析,打上注释,str猜测为密钥,点进函数sub_140001120和函数sub_140001240看看这个大概率是对状态向量S进行赋初值,并且也对该数组每一位进行了处理,再看另一个这个也是对数组的每一位进行了操作,可能是打乱数组S,或者是生成密钥流什么的,也不清楚,但到这里,我们就可以大胆的猜测这个是Rc4算法了,然后去找关键变量,脚本解密即可,这边我们已知关键变量密钥(主函数str数组存的字符串),密文(主函数if条件中,右侧数组byte_14013B000[i]^0x22之后的结果),有这两个关键变量已经ok了,接下来是Rc4的解密脚本,
#include<stdio.h>
#include<string.h>
typedef unsigned longULONG;
//初始化函数
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];
}
}
int main()
{
unsigned char s[256] = { 0 }, s2[256] = { 0 }; // S-box
char key[256] = { "12345678abcdefghijklmnopqrspxyz" };
char pData[] = { 0xbc,0xc5,0x12,0x7d,0x85,0x23,0x84,0x71,0x7b,0x39,0x28,0x2,0xd3,0x51,0xf3,0x2c,0x89,0x2b,0xa6,0x2c,0xaf,0x9,};
unsigned long len = strlen(pData);
int i;
printf("pData=%s\n", pData);
printf("key=%s,length=%d\n\n", key, strlen(key));
rc4_init(s, (unsigned char*)key, strlen(key)); // 已经完成了初始化
printf("\n\n");
for (i = 0; i < 256; i++) // 用s2[i]暂时保留经过初始化的s[i],很重要的!!!
{
s2[i] = s[i];
}
//可以看到,加解密函数都是相同的
printf("已经加密,现在解密:\n\n");
rc4_crypt(s2, (unsigned char*)pData, len); // 解密
printf("pData=%s\n\n", pData);
return 0;
}
解密脚本也是网上我找别人抄来的(^_^),key代表密钥,pData代表明文或者密文,当然,直接复制到vs2022中运行应该会出点问题,如果输出的结果是乱码,或者显示栈溢出什么的,如下操作点击上方的项目,然后点击属性,最后再按图中操作,即可得到flag{nice_to_meet_you}
忙活了两天才搞出这道题目来,有没有大佬带带啊,让我少走点弯路(~^~)