攻防世界crypt做法(附Rc4原理和解密脚本)

做题前,我们先了解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}

忙活了两天才搞出这道题目来,有没有大佬带带啊,让我少走点弯路(~^~)

  • 31
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值