由于有一个重要的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语言实现数据压缩等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)