吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5760|回复: 18
收起左侧

[原创] 学破解第118天,《C++之RC4算法加密解密》学习

[复制链接]
小菜鸟一枚 发表于 2020-7-17 19:39
[ 本帖最后由 小菜鸟一枚 于 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[0],S[1].....S[255]。每一个单元都是一个字节。算法执行的不论什么时候。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]=i;

T[i]=K[ i mod keylen ];

  2.初始排列S,用j+S[i]+T[i]的值对256取余,然后把值再给j,接下来用S[i]中的值交换S[j]中的值

j=0;

for i=0 to 255 do

j= ( j+S[i]+T[i])mod256;

swap(S[i],S[j]);

  3.产生密钥流

i,j=0;

for r=0 to len do  //r为明文长度,r字节

i=(i+1) mod 256;

j=(j+S[i])mod 256;

swap(S[i],S[j]);

t=(S[i]+S[j])mod 256;

k[r]=S[t];

0x3RC4算法的C++实现

  1.按照上述过程,首先我要初始化S盒,作为子密钥(密钥流),然后进行加解密,解密的时候也需要它的。

/*
初始化函数

参数1是一个256长度的char型数组,定义为: unsigned char sBox[256];
参数2是密钥,其内容可以随便定义:char key[256];
参数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[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盒的值
                s[i] = s[j];//交换s[i]和s[j]
                s[j] = 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[i]) % 256;
                tmp = s[i];
                s[i] = s[j];//交换s[i]和s[j]
                s[j] = tmp;
                t = (s[i] + s[j]) % 256;
                data[k] ^= s[t];//将明文与密钥流(打乱的s盒)进行异或加解密
        }
        return 0;
}

  3.现在是不是就可以进行使用RC4加密了呢?再看看,我们S和初始化后在加密函数中会再次打乱进行异或,而我们解密的时候还需要初始化时候的密钥流进行解密。所以我们应该在定义一个全局变量T盒,用来保存子密钥(密钥流),然后在初始化函数中添加代码。

unsigned char T[256] = {0};

//这里还应该添加代码保存子密钥,稍后会提到
        for (int i = 0; i < 256; i++)
        {
                T[i] = s[i];//字符串拷贝到全局变量T表中
        }

  4.现在我们就能使用RC4对字符串进行RC4加解密了。(同样,这也可以用于对文本文件加密)

#include "main.h"

using namespace std;

unsigned char T[256] = { 0 };//T盒

/*
初始化函数

参数1是一个256长度的char型数组,定义为: unsigned char sBox[256];
参数2是密钥,其内容可以随便定义:char key[256];
参数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[256] = { 0 };
        unsigned char tmp = 0;
        for (i = 0; i < 256; i++) {
                s[i] = i;//下标为几,s[i]就对应几
                t[i] = key[i%Len];//将密钥逐个字节赋值给T盒
        }

        for (i = 0; i < 256; i++) {
                j = (j + s[i] + t[i]) % 256;
                tmp = s[i];//打乱S盒的值
                s[i] = s[j];//交换s[i]和s[j]
                s[j] = tmp;
        }
        //用T盒保留S盒初始化后的值
        for (int i = 0; i < 256; i++)
        {
                T[i] = s[i];
                cout << "0x" << hex << (int) T[i] << ',';
        }
        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[i]) % 256;
                tmp = s[i];
                s[i] = s[j];//交换s[i]和s[j]
                s[j] = tmp;
                t = (s[i] + s[j]) % 256;
                data[k] ^= s[t];//将明文与密钥流(打乱的s盒)进行异或加解密
        }
        return 0;
}

unsigned int main()
{
        char key[] = "reverse";//密钥

        char data[] = "小菜鸟一枚";//明文

        unsigned char s[256];//定义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[256] = {
        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,程序运行起来,发现如图所示(禁用了编辑器代码,图在最后面)!
1.png

  2.当message(信息)改变后,对应的cipherTEXT(密文)也一起改变,先试试GetDlgItemTextA,不敢怎么样他也得获取文本框的内容才能运算吧,然后运行程序,对话框还没显示出来就被断下来了,不用慌,Alt+F9多来几次,返回到用户代码

004012BD  |.  C64424 1C 01  mov byte ptr ss:[esp+0x1C],0x1           ; |
004012C2  |.  C64424 1D 23  mov byte ptr ss:[esp+0x1D],0x23          ; |
004012C7  |.  C64424 1E 45  mov byte ptr ss:[esp+0x1E],0x45          ; |
004012CC  |.  C64424 1F 67  mov byte ptr ss:[esp+0x1F],0x67          ; |
004012D1  |.  C64424 20 89  mov byte ptr ss:[esp+0x20],0x89          ; |
004012D6  |.  C64424 21 AB  mov byte ptr ss:[esp+0x21],0xAB          ; |
004012DB  |.  C64424 22 CD  mov byte ptr ss:[esp+0x22],0xCD          ; |
004012E0  |.  C64424 23 EF  mov byte ptr ss:[esp+0x23],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:[edi]
0040131D  |.  8D4C24 10     lea ecx,dword ptr ss:[esp+0x10]
00401321  |.  8D9424 180200>lea edx,dword ptr ss:[esp+0x218]
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:[esp+0x20]          ;  取出pediy给eax
00401333  |.  55            push ebp                                 ;  pediy的长度入栈
00401334  |.  8D8C24 240200>lea ecx,dword ptr ss:[esp+0x224]         ;  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:[esp+0x114]
00401352  |>  33D2          /xor edx,edx
00401354  |.  8A5434 14     |mov dl,byte ptr ss:[esp+esi+0x14]
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:[eax+edi*4+0x8]    ;  0012F6E8[edi]

004010BB  |.  8B4C88 08     |mov ecx,dword ptr ds:[eax+ecx*4+0x8]    ;  0012F6E8[ecx]

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:善于总结,善于发现,找到分析问题的思路和解决问题的办法。虽然我现在还是零基础的小菜鸟一枚,也许逆天改命我会失败,但也有着成功的可能,只要还有希望,就决不放弃!

免费评分

参与人数 9威望 +1 吾爱币 +26 热心值 +7 收起 理由
lucky2020lucky + 1 我很赞同!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
万里绿枫叶 + 1 + 1 用心讨论,共获提升!
夕阳下的背影 + 1 鼓励转贴优秀软件安全工具和文档!
loo1221ool + 1 + 1 我很赞同!
易请惜 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
烟雨成林 + 1 热心回复!
wakenJ + 1 用心讨论,共获提升!
白云点缀的蓝 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 小菜鸟一枚 发表于 2020-7-18 10:21
aikoz88 发表于 2020-7-18 10:08
4.RC4作为对称加密算法,加密前和加密后的文本长度不变,但是要想找到key还是很难的。
对称/非对称加密算 ...

以我的学识,确实是这样理解的。
如果我的认知有误,这位朋友能否说的详细一些,谈一谈你的见解,让我学习一下!

PS:关于这个算法和破解,请留下你的高见,欢迎交流,共获提升。
aikoz88 发表于 2020-7-18 10:08
4.RC4作为对称加密算法,加密前和加密后的文本长度不变,但是要想找到key还是很难的。
对称/非对称加密算法和加解密前后的数据长度是否相同一点关系都没有!你肯定是以为对称加密的所谓对称就是加解/解密的两段数据是一样长的吧?至于破解,呵呵!你懂的!
头像被屏蔽
细水流长 发表于 2020-7-17 19:44
 楼主| 小菜鸟一枚 发表于 2020-7-17 19:47
细水流长 发表于 2020-7-17 19:44
同是18级学生,为何你如此优秀

因为你读的是一流大学,我读的是个大专,毕业后你赚大钱,我这大专毕业好多年,还在下面打杂,累死累活挣点小钱,这就是区别,你是科班,我是野鸡大学,所以,只要你想学,很定很快就能超过我了。

免费评分

参与人数 1吾爱币 +2 热心值 +1 收起 理由
细水流长 + 2 + 1 没有没有,就算一流大学的学生,也不一定能达到您的水平

查看全部评分

零下灼冰 发表于 2020-7-17 20:34
加油鸭,(&#3591; &#8226;&#768;_&#8226;&#769;)&#3591;
乐灿峰 发表于 2020-7-17 21:04
................   118天还在玩这个?
 楼主| 小菜鸟一枚 发表于 2020-7-17 21:11
乐灿峰 发表于 2020-7-17 21:04
................   118天还在玩这个?

所以没看到我最后一句话说了,我还是小菜鸟一枚呀
835228 发表于 2020-7-17 23:14
厉害了看不懂
icbcxcxxcx 发表于 2020-7-18 08:21
努力总会有回报!楼主,加油
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-24 03:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表