学破解第118天,《C++之RC4算法加密解密》学习
[ 本帖最后由 小菜鸟一枚 于 2020-7-17 21:07 编辑 ]\n\n## 学破解第118天,《C++之RC4算法加密解密》学习从小学到大专(计算机网络技术专业),玩过去的,所以学习成绩惨不忍睹,什么证书也没考,直到找不到工作才后悔,不知道怎么办才好。
2017年12月16日,通过19元注册码注册论坛账号,开始做伸手党,潜水一年多,上来就是找软件。(拿论坛高大上的软件出去装X)
2018年8月某一天,报名了华中科技大学网络教育本科(计算机科学与技术专业)2018级秋季。(开始提升学历)
2019年6月17日,不愿再做小菜鸟一枚,开始零基础学习破解。(感谢小糊涂虫大哥在我刚开始学习脱壳时,录制视频解答我的问题)
2020年7月7日,感谢H大对我的鼓励,拥有了第一篇获得优秀的文章。(接下来希望学习逆向,逆天改命)
坛友们,年轻就是资本,和我一起逆天改命吧,我的学习过程全部记录及学习资源:(https://www.52pojie.cn/thread-1208234-1-1.html)
立帖为证!--------记录学习的点点滴滴
**本文对应视频教程地址:(https://www.52pojie.cn/thread-1221530-1-1.html)**
### 0x1RC4算法的基本介绍
1.密钥流:RC4算法的关键是依据明文和密钥生成相应的密钥流,密钥流的长度和明文的长度是相应的。也就是说明文的长度是500字节,那么密钥流也是500字节。当然,加密生成的密文也是500字节。由密文第i字节=明文第i字节^密钥流第i字节;
2.状态向量S:长度为256。S,S.....S。每一个单元都是一个字节。算法执行的不论什么时候。S都包含0-255的8比特数的排列组合,仅仅只是值的位置发生了变换;
3.暂时向量T:长度也为256,每一个单元也是一个字节。
假设密钥的长度是256字节。就直接把密钥的值赋给T,否则,轮转地将密钥的每一个字节赋给T。
4.密钥K:长度为1-256字节。注意密钥的长度keylen与明文长度、密钥流的长度没有必定关系。通常密钥的长度趣味16字节(128比特)。
### 0x2RC4算法的实现原理
1.初始化S和T,这个时候的S显然是均匀分布的,呈线性增长,然后用密钥K对对T表进行打乱,此时T表中的数据就能用K表中的数据表示。
for i=0 to 255 do
S=i;
T=K[ i mod keylen ];
2.初始排列S,用j+S+T的值对256取余,然后把值再给j,接下来用S中的值交换S中的值
j=0;
for i=0 to 255 do
j= ( j+S+T)mod256;
swap(S,S);
3.产生密钥流
i,j=0;
for r=0 to len do//r为明文长度,r字节
i=(i+1) mod 256;
j=(j+S)mod 256;
swap(S,S);
t=(S+S)mod 256;
k=S;
### 0x3RC4算法的C++实现
1.按照上述过程,首先我要初始化S盒,作为子密钥(密钥流),然后进行加解密,解密的时候也需要它的。
```
/*
初始化函数
参数1是一个256长度的char型数组,定义为: unsigned char sBox;
参数2是密钥,其内容可以随便定义:char key;
参数3是密钥的长度,Len = strlen(key);
返回值:0表示成功
*/
int rc4_init(unsigned char*s, unsigned char*key, unsigned long Len)
{
int i = 0, j = 0;
//这里要定义为无符号char类型,防止出现负数,负数作为数组下标......
unsigned char k = { 0 };
unsigned char tmp = 0;
for (i = 0; i < 256; i++) {
s = i;
k = key;
}
for (i = 0; i < 256; i++) {
j = (j + s + k) % 256;
tmp = s;//打乱S盒的值
s = s;//交换s和s
s = tmp;
}
//这里还应该添加代码保存子密钥,稍后会提到
return 0;
}
```
2.接下来就应该是加解密函数了,使用密钥流对明文进行异或加解密。(这里说加解密是因为两次异或后,值会还原,也就是解密了)
```
/*
加解密函数
参数1是上边rc4_init函数中,被搅乱的S盒
参数2是明文data
参数3是data的长度
返回值:0表示成功
*/
int rc4_crypt(unsigned char*s, unsigned char*data, unsigned long Len)
{
int i = 0, j = 0, t = 0;
unsigned char tmp;
for (int k = 0; k < Len; k++)
{
i = (i + 1) % 256;
j = (j + s) % 256;
tmp = s;
s = s;//交换s和s
s = tmp;
t = (s + s) % 256;
data ^= s;//将明文与密钥流(打乱的s盒)进行异或加解密
}
return 0;
}
```
3.现在是不是就可以进行使用RC4加密了呢?再看看,我们S和初始化后在加密函数中会再次打乱进行异或,而我们解密的时候还需要初始化时候的密钥流进行解密。所以我们应该在定义一个全局变量T盒,用来保存子密钥(密钥流),然后在初始化函数中添加代码。
```
unsigned char T = {0};
//这里还应该添加代码保存子密钥,稍后会提到
for (int i = 0; i < 256; i++)
{
T = s;//字符串拷贝到全局变量T表中
}
```
4.现在我们就能使用RC4对字符串进行RC4加解密了。(同样,这也可以用于对文本文件加密)
```
#include "main.h"
using namespace std;
unsigned char T = { 0 };//T盒
/*
初始化函数
参数1是一个256长度的char型数组,定义为: unsigned char sBox;
参数2是密钥,其内容可以随便定义:char key;
参数3是密钥的长度,Len = strlen(key);
返回值:0表示成功
*/
int rc4_init(unsigned char*s, unsigned char*key, unsigned long Len)
{
int i = 0, j = 0;
//这里要定义为无符号char类型,防止出现负数
unsigned char t = { 0 };
unsigned char tmp = 0;
for (i = 0; i < 256; i++) {
s = i;//下标为几,s就对应几
t = key;//将密钥逐个字节赋值给T盒
}
for (i = 0; i < 256; i++) {
j = (j + s + t) % 256;
tmp = s;//打乱S盒的值
s = s;//交换s和s
s = tmp;
}
//用T盒保留S盒初始化后的值
for (int i = 0; i < 256; i++)
{
T = s;
cout << "0x" << hex << (int) T << ',';
}
cout << endl;
return 0;
}
/*
加解密函数
参数1是上边rc4_init函数中,被搅乱的S盒
参数2是明文data
参数3是data的长度
返回值:0表示成功
*/
int rc4_crypt(unsigned char*s, unsigned char*data, unsigned long Len)
{
int i = 0, j = 0, t = 0;
unsigned char tmp;
for (int k = 0; k < Len; k++)
{
i = (i + 1) % 256;
j = (j + s) % 256;
tmp = s;
s = s;//交换s和s
s = tmp;
t = (s + s) % 256;
data ^= s;//将明文与密钥流(打乱的s盒)进行异或加解密
}
return 0;
}
unsigned int main()
{
char key[] = "reverse";//密钥
char data[] = "小菜鸟一枚";//明文
unsigned char s;//定义S盒
rc4_init(s, (unsigned char *)key, strlen(key));//初始化
cout << "加密前的明文:" << data << endl;
cout << "key:" << key << endl;
cout << "==========RC4加解密==========" << endl;
rc4_crypt(s, (unsigned char *)data, strlen(data));//加密
cout << "加密后的密文:" << data << endl;
rc4_crypt(T, (unsigned char *)data, strlen(data));//解密
cout << "解密后的明文:" << data << endl;
system("pause");
return 0;
}
```
5.最后再来看看生成的子密钥能不能配合我们的密钥将密文解密,还是声明一个长度为256的数组,然后把子密钥的十六进制形式放进去,是不是能不能解密密文。
```
unsigned char TT = {
0x41,0x36,0x50,0x1e,0x55,0xa6,0x11,0x80,0x2c,0x63,0xe5,0x62,0xfa,0x1a,0xd3,0x6b,
0x4,0x27,0xb0,0x42,0x12,0x3f,0xba,0x88,0xc0,0x20,0x5a,0x5f,0xed,0x6f,0x39,0x87,0x83,
0xad,0x10,0xc9,0x19,0x1c,0x78,0x38,0xac,0x3a,0x1f,0x66,0xa5,0x9a,0x6a,0xef,
0x9b,0xea,0x81,0xd6,0xf8,0x58,0x32,0x9d,0x8d,0x98,0x24,0xfc,0xe4,0x29,0x40,0x71,
0x65,0x72,0x7a,0xb2,0xe6,0xb4,0x48,0xff,0xcf,0xf3,0x18,0xc1,0xc8,0xf5,0xa8,0x6c,
0x7f,0x70,0x6e,0xe9,0x5,0x60,0xf7,0x2b,0xa2,0xf6,0xdf,0xa,0xc,0x79,0xa0,0xb5,0x91
,0xe8,0xd4,0x9c,0x9,0x1b,0xc6,0xb7,0x84,0x23,0xcd,0x3d,0x4b,0xa1,0x2,0x3c,0x4f,
0xb9,0x25,0xaf,0xab,0x93,0x54,0xa4,0xca,0x9e,0x4a,0x68,0x8b,0xd5,0x21,0xa9,0xc2,
0x4c,0x33,0x52,0x0,0x57,0x95,0xb6,0x15,0xbc,0x8c,0xd0,0x4d,0xe7,0xc4,0xe3,0x5e,
0xae,0xfb,0xe2,0xdb,0xf0,0x51,0x94,0x3b,0x7b,0x1,0x2d,0x3,0x14,0x97,0xf9,0xbf,0xd2
,0x8f,0x77,0x6,0x56,0x92,0x8a,0xc3,0x74,0xd,0x47,0x31,0x73,0xec,0x2f,0x4e,0x69,
0xc5,0xb8,0x90,0x22,0x82,0xe0,0xcc,0x28,0xdc,0xcb,0xbb,0xb,0x1d,0x7c,0xc7,0xd1,0x9f,
0x17,0xde,0x85,0xfd,0x89,0xd8,0xbe,0x49,0xb1,0x16,0x5c,0xa7,0x99,0x3e,0x7e,0xda,
0x45,0x76,0xce,0xf2,0x8,0xf,0x59,0x26,0xee,0xbd,0x61,0xeb,0x53,0x8e,0x64,0xdd
,0x7,0xd9,0xe,0xb3,0x13,0xf4,0x67,0xa3,0xf1,0x46,0x2e,0x37,0x43,0xd7,0x6d,0x44,0x96,
0x35,0xfe,0x5b,0x5d,0x86,0x7d,0xe1,0x34,0x2a,0x30,0xaa,0x75
};
rc4_crypt(TT, (unsigned char *)data, strlen(data));//解密
cout << "解密后的明文:" << data << endl;
```
成功输出:小菜鸟一枚,说明我这次的学习是成功的,加解密都没问题了。
6.补充一下,我这里为了尝试能不能直接用密钥流加解密,是使用密钥流直接进行解密的,如果有密钥,那么我们按照与加密同样的步骤,将原始密钥初始化,然后执行加解密函数进行解密,看上去很简单的算法,原理看上去还是有些迷糊,主要还是在模余和交换值的地方不知道为什么那么做。
### 0x4使用OD分析RC4加密的程序
1.将随书文件RC4Sample.exe载入OD,程序运行起来,发现如图所示(禁用了编辑器代码,图在最后面)!
2.当message(信息)改变后,对应的cipherTEXT(密文)也一起改变,先试试GetDlgItemTextA,不敢怎么样他也得获取文本框的内容才能运算吧,然后运行程序,对话框还没显示出来就被断下来了,不用慌,Alt+F9多来几次,返回到用户代码
```
004012BD|.C64424 1C 01mov byte ptr ss:,0x1 ; |
004012C2|.C64424 1D 23mov byte ptr ss:,0x23 ; |
004012C7|.C64424 1E 45mov byte ptr ss:,0x45 ; |
004012CC|.C64424 1F 67mov byte ptr ss:,0x67 ; |
004012D1|.C64424 20 89mov byte ptr ss:,0x89 ; |
004012D6|.C64424 21 ABmov byte ptr ss:,0xAB ; |
004012DB|.C64424 22 CDmov byte ptr ss:,0xCD ; |
004012E0|.C64424 23 EFmov byte ptr ss:,0xEF ; |
004012E5|.FF15 B0604000 call dword ptr ds:[<&USER32.GetDlgItemTe>; \GetDlgItemTextA
004012EB|.8BE8 mov ebp,eax
004012ED|.85ED test ebp,ebp
004012EF|.75 1A jnz short RC4Sampl.0040130B
004012F1|.68 40704000 push RC4Sampl.00407040 ; /Text = "please input name"
004012F6|.6A 6F push 0x6F ; |ControlID = 6F (111.)
004012F8|.56 push esi ; |hWnd = 003A0352 ('RC4 Sample',class='#32770')
004012F9|.FF15 B4604000 call dword ptr ds:[<&USER32.SetDlgItemTe>; \SetDlgItemTextA
```
不用回去跑,看寄存器窗口,因为ebp(pediy的长度)不为0,所以下面jnz会跳走
EAX:00000005
ESP:0012F4D4
而ESP+4*EAX的地址对应的字符串就是message(信息)的文本pediy
3.继续向下走,就看到加密函数了
```
00401319|.6A 08 push 0x8
0040131B|.F3:AB rep stos dword ptr es:
0040131D|.8D4C24 10 lea ecx,dword ptr ss:
00401321|.8D9424 180200>lea edx,dword ptr ss:
00401328|.51 push ecx ;0012F4E0:pediy
00401329|.52 push edx ;0012F6E8
0040132A|.E8 D1FCFFFF call RC4Sampl.00401000 ;初始化S盒,注意常数0x100,也就是256
0040132F|.8D4424 20 lea eax,dword ptr ss: ;取出pediy给eax
00401333|.55 push ebp ;pediy的长度入栈
00401334|.8D8C24 240200>lea ecx,dword ptr ss: ;0012F6E8这个地址给ecx
0040133B|.50 push eax ;待加密数据pediy
0040133C|.51 push ecx ;S盒
0040133D|.E8 2EFDFFFF call RC4Sampl.00401070 ;加密函数
00401342|.83C4 18 add esp,0x18 ;销毁局部变量
00401345|.33F6 xor esi,esi
00401347|.85ED test ebp,ebp ;判断pediy长度是否为0
00401349|.7E 24 jle short RC4Sampl.0040136F ;小于等于0跳走
0040134B|.8DBC24 140100>lea edi,dword ptr ss:
00401352|>33D2 /xor edx,edx
00401354|.8A5434 14 |mov dl,byte ptr ss:
00401358|.52 |push edx
00401359|.68 38704000 |push RC4Sampl.00407038 ;ASCII "%02X"
0040135E|.57 |push edi
0040135F|.E8 3C000000 |call RC4Sampl.004013A0 ;将加密后的文本变成2位16进制表示
```
4.接下来就是把密文设置到cipherTEXT文本框中,补充一下加密函数里面几个这样的指令,要把它当成数组(或者是一连串存储空间来看)来看。
```
004010A3|.8B4CB8 08 |mov ecx,dword ptr ds: ;0012F6E8
004010BB|.8B4C88 08 |mov ecx,dword ptr ds: ;0012F6E8
```
### 0x5总结
1.RC4算法采用的是异或运算,因此加密函数也就是解密函数。
2.使用key,初始化S盒,形成密钥流,然后执行加密函数加密,每次加密都会改变S盒中的内容。
3.破解RC4算法时,可以想办法取得加密时密钥流,初始化后的S盒,然后在执行一次加密函数,密文就自己解密了。
4.RC4作为对称加密算法,加密前和加密后的文本长度不变,但是要想找到key还是很难的。
### 0x6参考资料:
(https://baike.baidu.com/item/RC4/3454548?fr=aladdin)
(https://www.cnblogs.com/gambler/p/9075415.html)
《加密解密第四版》P231-P233
**PS:善于总结,善于发现,找到分析问题的思路和解决问题的办法。虽然我现在还是零基础的小菜鸟一枚,也许逆天改命我会失败,但也有着成功的可能,只要还有希望,就决不放弃!** aikoz88 发表于 2020-7-18 10:08
4.RC4作为对称加密算法,加密前和加密后的文本长度不变,但是要想找到key还是很难的。
对称/非对称加密算 ...
以我的学识,确实是这样理解的。
如果我的认知有误,这位朋友能否说的详细一些,谈一谈你的见解,让我学习一下!
PS:关于这个算法和破解,请留下你的高见,欢迎交流,共获提升。:handshake 4.RC4作为对称加密算法,加密前和加密后的文本长度不变,但是要想找到key还是很难的。
对称/非对称加密算法和加解密前后的数据长度是否相同一点关系都没有!你肯定是以为对称加密的所谓对称就是加解/解密的两段数据是一样长的吧?至于破解,呵呵!你懂的! 细水流长 发表于 2020-7-17 19:44
同是18级学生,为何你如此优秀
因为你读的是一流大学,我读的是个大专,毕业后你赚大钱,我这大专毕业好多年,还在下面打杂,累死累活挣点小钱,这就是区别,你是科班,我是野鸡大学:lol,所以,只要你想学,很定很快就能超过我了。:handshake 加油鸭,(ง •̀_•́)ง ................ 118天还在玩这个? 乐灿峰 发表于 2020-7-17 21:04
................ 118天还在玩这个?
所以没看到我最后一句话说了,我还是小菜鸟一枚呀:lol 厉害了看不懂 努力总会有回报!楼主,加油{:301_993:}
页:
[1]
2