如何用C语言编写暴力破解压缩文件解压密码的程序

如何用C语言编写暴力破解压缩文件解压密码的程序,第1张

由于有一个重要的Rar文件,极需解开,首先试用了ARPC,但是解压的速度极慢,每秒只有30个左右,所以断了穷举破解的念头,却仍不死心,因为我从不崇尚穷举破解的方法,除非每秒可以跑几千万次的,我或许可以一试,所以决定研究一下Winrar 3x密码算法,以期是否可以破解该密码。查看了网络上的资料,包括看雪FAQ里的回答,都声称只能用穷举法破解,起先并不理解,但通过研究,我理解了看雪前辈们在FAQ里所说的原因,不禁让我佩服

Winrar加密思路的成熟。虽然研究的结果没有什么新意,但我还是决定把我的研究结果与大家一起分享,为那些仍然以为winrar密码可以象破解注册码一样的,通过修改winrard出框之类的更改文件流程指向可以达到跳过密码检验的朋友,做一个简要的说明。

一、Rar文件生成的流程。

Winrar加密文件时,总的分两个步骤:

 1:先把源文件压缩,压成一段数据段。

 2:再将压缩完的数据段加密。

对于同一个源文件来说,不进行加密,压缩完,其rar文件中的数据段是一模一样的。但是如果对同一个源文件来说,即使使用同一个密码,加密完rar文件中的数据段是不一样的,这是由于加密的密钥是依赖于一个Salt(8个字节的密钥,用来加密时使用,存放在rar文件头中里)

所以要解密rar加密文件关键在于数据解密这一步,那我们接下来研究一下如何加密的。

二、加密“压缩完的数据段”的流程

1、获取密钥:

将明文的密码与Salt一起,通过HASH算法,生成两个16字节的密钥。(一个是KEY(AES算法的参数),一个是initVector)

2、以Key和initVector来加密压缩数据:

这里,是一个循环加密的结构,每16字节作为一个块,进行加密(这可能正是为什么加密完的文件长度总为16倍数的原因)。加密采用AES算法(RAR采用的是AES的rijndael的标准应用)。这里注意:AES加密前,有一个异或运算,是先将每16字节块与上一个16字节块加密结果进行异或,然后再进行AES算法的。我用一个简单的示意代码看说明:

;===============================================

packblock[0]=packblock[i]^initVector

encryptBlock[0]=AES(packblock[0])  ;(KEY为AES的密钥)

for i=1 to 块数量-1

packblock[i]=packblock[i]^encryptBlock[i-1]

encryptBlock[i]=AES(packblock[i]) ;(KEY为AES的密钥)

next

;packblock[i]表示压缩完的每16字节数据

  ;encryptBlock[i]表示加密完的每16字节数据

;===============================================

三、解密的过程

由于AES算法是对称的,所以解密的过程,是加密过程的逆运算。但解密时AES算法过程与加密所用的不一样(是因为解密过程中由KEY生成的子密钥表不一样)。仍然需要我们将密码输入,与salt一起生成两个16字节密钥,KEY和initVector。

;===============================================

packblock[0]=AES1(encryptBlock[0])  ;(KEY为AES的密钥)

packblock[0]=packblock[i]^initVector

for i=1 to 块数量-1

packblock[i]=AES1(encryptBlock[i])  ;(KEY为AES的密钥)

  packblock[i]=packblock[i]^encryptBlock[i-1]

next

;===============================================

那判断密码是否正确的在什么地方呢?

解密的过程是解密后的数据块进行解压缩,然后解成源文件,对该文件进行CRC校验,存在RAR文件中的源文件CRC校验码比较,相同则密码正确,不相同则密码错误。

四、无法秒破的原因

从上面,我们了解了RAR文件的整体思路。地球人都知道,解密时,肯定有个步骤是来判断密码的正确与否。而且,依据以往的经验,我们也许可以将某些判断的点移动,那样可以缩减破解的流程思路。那RAR的这一步在哪里?它把校验放在了最后的一步。如果要秒破,我们该怎么做泥?至少我认为目前是不可能的。

我们从解密过程逆反过来看看:

1、CRC检验这一块修改跳转?根本毫无意义,因为它已经是最后一步了。你可以修改RAR文件头的CRC值,你可以将它改得和你用任意密码解压出来的文件CRC值一样,但你的文件根本就不是原来的文件了。可能已经完全面目全非了。所以,对这一过程不可行。CRC校验本身是不可逆的

2、那么把判断提前到压缩完的数据?

解压的时候,有没有什么来判断压缩数据是否正确?压缩完的数据,有没有固定的特征,是否可以做为解压的判断,在这一步里,我们也无法找到有效的可用的固定特征。因为这一步涉及到RAR的压缩算法。即使一个源文件,即使你的文件前一部分是完全相同的,只对后面的部分进行改过,那么压缩完,数据也是完全一样的。因为压缩完的数据首先是一个压缩表,后面是编码。文件不一样,扫描完的压缩表也不一样,编码又是依赖于压缩表,所以,这里头找不到压缩完的数据有任何的固定特征可以用来判断的。

不管压缩数据是什么样的,Winrar都一如既往地进行解压,没有进行压缩数据是否有效的判断。

3、那假如我们破解了AES了泥?

由于AES只依赖于KEY,如果AES算法被破解了,我们知道了KEY,我们可以解出压缩完的数据,但是这里有一个问题,还有一个initVector密钥,用来第一个16字节块的异或,你没有initVector参数,你第一个16字节块的数据便无法解得出来。

4、那就只能从第一步Hash的算法入手

即使你能破解hash,但hash后的结果泥?没有结果,你怎么返推密码。

所以综上,我发现rar的加密是由hash和AES两种算法互相牵制,而两种算法当前都无法破解,至少目前还没有办法秒破,也理解了看雪高手讲的道理。

五、对穷举提高算法效率的一些设想。

我用汇编写完了RAR穷举解密的算法模块,但是如何提高效率,优化穷举的速度泥?我有如下的想法:

1、从压缩数据里找寻特征,省掉解压缩、CRC检验代码和生成initVector生成代码。目前,通过多次实验,我找到的一个特征(不知道这个是否正确),即解密完的最后一个16字节块的最后一个字节必须为0。因为经过多次的试验,我发现有加密的数据段长度都会比未加密前的数据长,那么,最后一个

16个字节的数据块解密完,多出的部分就都为0,但多出几个字节泥?多次实验,长度不一,我试想着从加密数据段最后一个16个字节块着手,只解这一块,看是否一个字节为0,这样,只解密16个字节的数据,来大大提高效率?如果能进行到这一步了,再通过解全部数据,进行CRC校验的判断。

2、如果第一个特征不成立的话,针对特定格式的压缩文件,比如doc、jpg等,部分数据固定,压缩完的数据是否存在相互牵制的数据?从而把判断提前,这一步,我不知道如何找到压缩完的数据是否存在相互牵制的数据。

#include <stdioh>

void stringZip(const char

pInputStr, long lInputLen, char pOutputStr)

{ int n=1;

char c,p1=pInputStr,p2=pOutputStr;

while(p1)

{

 c=(p1++);

 while(p1==c){n++;p1++;}

 if(n>1)

 {

  if(n>999){(p2++)=48+n/1000; n/=10;}

  if(n>99){(p2++)=48+n/100; n/=10;}

  if(n>9){(p2++)=48+n/10; n/=10;}

  (p2++)=48+n;

 }

 (p2++)=c;

 n=1;

}

p2='\0';

}

void main()

{ char s1[200],s2[200];

gets(s1);

stringZip(s1,strlen(s1),s2);

puts(s2);

}

首先选择一个压缩算法

然后按照算法实现压缩代码,调用接口就可以

常见的

可以使用哈夫曼编码压缩,或者使用开源的压缩代码,比如lzo,

gzip,

lzma等等。

byte[] buf = new byte[40962];

//建立字节数组输入流

ByteArrayInputStream i = new ByteArrayInputStream(buffer);

//建立gzip解压输入流

GZIPInputStream gzin = new GZIPInputStream(i);

int size = gzinread(buf);

iclose();

gzinclose();

byte b[] = new byte[size];

Systemarraycopy(buf,0,b,0,size);

return b;

//由于字数限制,下述代码有删节,如需完整代码,请直接访//问gdgzzchblog163com

//霍夫曼树,又称哈夫曼数,huffman树

//-----------------------------------------------------------------------------

//huffmantreemaincpp

//主界面

#include "huffmantreeh"

#include <fstreamh>

#include <conioh>

#include "compress1h"

#include "Ceshih"

void menu()

{

cout<<endl;

cout<<"\t\t *** 作菜单 \n\n";

cout<<"\t\t\t 1 压缩文件\n";

cout<<"\t\t\t 2 解压文件\n";

cout<<"\t\t\t 3 测试\n";

cout<<"\t\t\t 0 退出\n\n\n\n";

return;

}

int main()

{

char meiyong;

cout<<"\n\n\n\n\n\n\n\n\n"

<<"\t & 压缩软件 &\n"

<<"\t \n"

<<"\t \n"

<<"\t \n\n\n"

<<"\t 运行本软件之前,请务必仔细阅读使用指南 "

<<"\n\n\n\n\n\n\n\n\n\n";

cinunsetf(ios::skipws);

cin>>meiyong;

cinsetf(ios::skipws);

ifstream fin("使用说明txt",ios::binary);

finunsetf(ios::skipws);

while(fin>>meiyong)

{

cout<<meiyong;

}

cout<<endl;

getch();

finsetf(ios::skipws);

finclose();

cout<<"\n\n\n\n\n\n";

cout<<"\n";

cout<<"\t\t-------------------------------------------\n";

cout<<"\t\t 实验六: 霍夫曼树的应用 \n";

cout<<"\t \n";

cout<<"\t\t 作者: gdgzzch 学号: 15201314 \n";

cout<<"\t\t-------------------------------------------\n\n";

cout<<"\t\t 20051116\n\n";

menu();

int choice;

cout<<"请选择 *** 作: ";

cin>>choice;

while(1)

{

switch(choice)

{

case 1:

Compress();

break;

case 2:

Decompress();

break;

case 3:

Ceshi();

break;

case 0:

cout<<"\n\n\t\t 谢谢您使用本软件,再见! \n\n\n\n";

return 1;

default:

cout<<"无此 *** 作!\n\n";

}

cout<<endl<<"请选择 *** 作: ";

cin>>choice;

}

return 1;

}

//----------------------------------------------------------

//compress1h

//压缩

#ifndef COMPRESS

#define COMPRESS

#include "huffmantreeh"

#include <fstreamh>

#include <iostreamh>

#include <conioh>

#include <stringh>

//压缩函数

void Compress()

{

unsigned char ch;

int i,j,k;

int Charnum[256];//

unsigned char Chars[256]; //与下面共同使用 ,记录字符

int Charnums[256]; //记录对应字符的个数

int CharKinds; //字符种数

char filenameorg[21]; //文件名不超过20个字符 源文件名

char filenameaim[21]; //目标文件名

int fileorgsize; //源文件大小

int fileaimsize; //压缩文件大小

HuffmanTree<unsigned char> ht;

CharNameNode NameNode[256]; //存储字符对应的霍夫曼编码

BinTreeNode<unsigned char> btn=NULL;

Code first=NULL;

Code last=NULL;

ifstream filein;

ofstream fileout;

cout<<"请输入你要压缩的文件的名字:";

cin>>filenameorg;

fileinopen(filenameorg,ios::nocreate|ios::binary); //open:filenameorg

if(!filein)

{

cout<<filenameorg<<" 不存在!\n";

fileinclear();

return;

}

cout<<"请输入你的压缩文件的名字(HFM):"; //以后再用

cin>>filenameaim;

char filetype[5];

int len;

len=strlen(filenameaim);

if(len<=4)

{

cout<<filenameaim<<"文件的扩展名必须为HFM\n";

return ;

}

for(i=len-1,j=3;i>=len-4;i--,j--)

filetype[j]=filenameaim[i];

filetype[4]='\0';

if(strcmp(filetype,"HFM")!=0)

{

cout<<filenameaim<<"文件的扩展名必须为HFM\n";

return ;

}

//

for(i=0;i<256;i++)

{

Charnum[i]=0; //记录每一个字符的个数

Charnums[i]=0; //记录字符Char[i]的个数

}

fileinunsetf(ios::skipws);

fileorgsize=0; //计算源文件大小

while(filein>>ch)

{

Charnum[unsigned int(ch)]++; //统计每种字符的频数

fileorgsize++;

}

fileinsetf(ios::skipws);

fileinclose(); //close:filenameorg

//

j=0;

for(i=0;i<256;i++)

{

if(Charnum[i])

{

Chars[j]=unsigned char(i); //统计源文件中存在的字符的

Charnums[j]=Charnum[i];

j++;

}

}

CharKinds=j;

//

fileaimsize=0; //计算压缩文件大小

fileoutopen(filenameaim,ios::binary);

fileout<<'0'<<' '; //非法位数(之后修改)

fileout<<filenameorg<<' ';

fileout<<CharKinds<<' '; //存入字符种类

fileaimsize+=7;

for(i=0;i<CharKinds;i++)

{

fileout<<Chars[i]<<' '<<Charnums[i]<<' ';//将字符信息存入临时文件

fileaimsize+=10;

}

htBuild(Charnums,Chars,CharKinds,ht); //建立霍夫曼树

i=0;

htPath(htGetRoot(),first,last,NameNode,i); //搜索霍夫曼树求得字符对应的霍夫曼编码

//

fileinopen(filenameorg,ios::nocreate|ios::binary);

fileinunsetf(ios::skipws);

k=0;

j=0;

while(filein>>ch)

{

i=0;

while(ch!=NameNode[i]charname) //找到ch

i++;

Code p=NameNode[i]link;

while(p!=NULL)

{

j<<=1;

j+=p->code;

k++;

if(k==8)

{

fileout<<unsigned char(j);

fileaimsize++; //计算压缩文件大小

k=0;

j=0;

}

p=p->link;

}

}

fileinsetf(ios::skipws);

fileinclose();

if(k<8)

{

j<<=(8-k);

fileout<<unsigned char(j);

fileaimsize++; //计算压缩文件大小

}

fileoutseekp(0,ios::beg);

fileout<<8-k; //修改非法代码的位数

fileoutclose();

for(i=0;i<CharKinds;i++)

{

Code q=NameNode[i]link;

Code s=NULL;

while(q!=NULL)

{

s=q;

q=q->link;

delete s;

}

NameNode[i]link=NULL; //清除链表信息

}

htDestroy();

cout<<"文件压缩成功!压缩率为:"<<(fileaimsize100)/fileorgsize<<'%'<<endl;

return;

}

void Decompress()

{

unsigned char ch;

int i,j,k;

unsigned char Chars[256]; //与下面共同使用 ,记录字符

int Charnums[256]; //记录对应字符的个数

int CharKinds; //字符种数

unsigned int total; //记录字符转化后的数

int fpend; //暂存文件指针的最后位置

char filenameorg[21]; //文件名不超过20个字符 源文件名

char filenameaim[21]; //目标文件名

HuffmanTree<unsigned char> ht;

CharNameNode NameNode[256]; //存储字符对应的霍夫曼编码

BinTreeNode<unsigned char> btn=NULL;

Code first=NULL;

Code last=NULL;

ifstream filein;

ofstream fileout;

char filetype[5];

int len;

cout<<"请输入你要解压的文件的名字:";

cin>>filenameorg;

len=strlen(filenameorg);

if(len<=4)

{

cout<<filenameorg<<"不是霍夫曼编码的程序,不能解压!\n";

return ;

}

for(i=len-1,j=3;i>=len-4;i--,j--)

filetype[j]=filenameorg[i];

filetype[4]='\0';

if(strcmp(filetype,"HFM")!=0)

{

cout<<filenameorg<<"不是霍夫曼编码的程序,不能解压!\n";

return ;

}

fileinopen(filenameorg,ios::nocreate|ios::binary);

if(!filein)

{

cout<<filenameorg<<" 不存在!\n";

fileinclear();

return;

}

fileinclose();

/ cout<<"请输入你解压后的文件的名字:";

cin>>filenameaim;/

fileinopen(filenameorg,ios::nocreate|ios::binary);

if(!filein)

{

cout<<"解压失败,请重试!\n";

fileinclear();

return;

}

fileinseekg(0,ios::end);

fpend=fileintellg(); //记录文件尾的位置

fileinseekg(0,ios::beg); //恢复

fileinunsetf(ios::skipws);

filein>>k>>ch; //最后一个字符不合法的位数

filein>>filenameaim>>ch;

filein>>CharKinds>>ch;

for(i=0;i<CharKinds;i++)

filein>>Chars[i]>>ch>>Charnums[i]>>ch; //载入字符信息

htBuild(Charnums,Chars,CharKinds,ht); //建立霍夫曼树

btn=htGetRoot();

fileoutopen(filenameaim,ios::binary); //以文本文件打开

if(!fileout)

{

cout<<"目标文件创建失败,请重试!\n";

fileoutclear();

return;

}

while(filein>>ch)

{

total=(unsigned int)(ch); //这里都是正确的

j=0;

if(fileintellg()==fpend) //到了文件尾

j=k; //留k位不输出

for(i=7;i>=j;i--)

{

if(total&(1<<i)) //这一位是1向右子树走

btn=btn->GetRight();

else

btn=btn->GetLeft();

// if(btn->GetData()!=0)

if(btn->GetLeft()==NULL&&btn->GetRight()==NULL)

{

fileout<<btn->GetData();

btn=htGetRoot();

}

}

}

fileoutclose();

fileinsetf(ios::skipws);

fileinclose();

htDestroy();

cout<<"解压成功!\n";

cout<<"保存在\""<<filenameaim<<"\"中"<<endl;

return;

}

#endif

1、首先,右键单击压缩器图标并选择“打开属性”。

2、然后单击打开d出窗口中的“打开文件位置”。

3、然后在d出窗口中,找到winrarexe并将其放入文件夹中。

4、然后打开文本文档并输入代码:对于在(arar,brar,Crar)do“C:\ program files\WinRAR\rarexe”(WinRARexe所在的目录)中的%I

5、然后点击文件中的另存为。

6、然后选择winrarexe所在的文件夹,输入后缀名“bat”,回车确定。

7、最后转到保存的目录并双击bat程序。

以上就是关于如何用C语言编写暴力破解压缩文件解压密码的程序全部的内容,包括:如何用C语言编写暴力破解压缩文件解压密码的程序、C语言求助:请编写一个字符串压缩程序,将字符串中连续出席的重复字母进行压缩,并输出压缩后的字符串。、如何用C语言实现数据压缩等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9331361.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-27
下一篇 2023-04-27

发表评论

登录后才能评论

评论列表(0条)

保存