找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4885|回复: 5
收起左侧

编程练习作品 -> ZR智能下载(开源)

[复制链接]
ID:71922 发表于 2015-1-10 23:01 | 显示全部楼层 |阅读模式
    ZR智能下载是一款可以提取网络上压缩文件中指定文件内容的程序。如一个ZIP下载地址为:http:\\www.xxx.com\Setus.rar   这个压缩包 大小是 2G ,你可以通过这款小工具分析这个rar压缩包里面的文件,找到自己需要的文件就可以直接下载那个文件而不需要下载整个2G大的文件。如果你想要下载的文件只有2M 那么就只需要下载那个2M的文件即可。这样既节省下载时间又节省流量。
该程序暂只支持 ZIP、RAR格式。
    如图:
        



双击指定文件即可下载指定文件。下载的文件以原压缩格式保存。




原ZIP文件:




下载的以原来的压缩格式保存,下载下来直接用 WinRAR就能解压。之所以这样是因为在分析压缩文件格式的时候花费的时间很长,以前也从没有接触过这些文件格式,如果再分析解压缩算法,那么花的时间就更长了。

由于最近我把精力放在单片机上,设计这个是因为这个设计思路非常不错,吸引我去设计,是一个好友提出来的,但后来发现难度并想想的要大一些,花费的时间超过预期,所以把基本的功能实现后就放着,这个程序还有很大的提升空间。现在把原理以及实现源码都公布出来,让有心人去完善吧。。。基本的原理以及RAR文件结构以及心得都会在下面给出,让你们少走一些弯路,这样也能快点入手。。。好好感谢【Hades  315102821】吧,那么好的思路是他提出来,设计这个程序的时候也是他提供了资料以及一些建议。设计这个程序的时候我感觉自己C程序方面的进步挺大的,分析这些数据的时候,采用结构来分析方便N倍,我居然现在才体会到。

[color=#110df2,strength=3)"]基本实现思路:
        充分利用断点续传原理,以及压缩文件结构的特点,来实现随意提取网络上压缩包内所需要的文件。断点续传可以让我们随意获取网络文件中的任意指定数据范围的数据块,而压缩文件结构一般都是一个文件一个数据块,而不会几个文件数据混合在一起,所以可以根据压缩文件的结构来确定我们所需要的数据块的位置、大小,这样可以从源头就能跳过我们不需要的数据块,只下载我们想要的是数据块,这个数据块可以是一个被压缩后的文件也可以是一段注释,任意选取。so 这个实现思路不单单可以用在压缩文件上,还可以用于其他的方面。不要被我们的惯性思想局限了。当然,只利用我的程序代码里面还可以实现快速分离压缩文件中的指定文件,如果有一个很大的RAR文件,里面包含的很多文件,那么可以利用下面RAR文件结构,实现快速分析RAR文件名以及快速提取里面的文件,当然提取出来的还是RAR压缩文件格式。你可以试试,我这种分析方法比WinRAR分析的快很多很多。


实现基本原理(例RAR):
以下所有的解释以这个RAR文件为例子。



【第一部分:分析RAR格式】
由于我们只需要得到指定文件的数据块所以不需要对rar文件格式分析的多深入,RAR文件格式是数据块做单位的,一般有标记块,压缩文件头块,文件头块,注释头,用户身份信息,子块和恢复记录块等。
每一块的前七个字节最重要,这七个字节包含:
HEAD_CRC  2 字节    所有块或块部分的 CRC
HEAD_TYPE  1 字节    块类型
HEAD_FLAGS  2 字节    块标记
HEAD_SIZE  2 字节    块大小
    如果块标记的第一位被置1的话,还存在:
ADD_SIZE   4 字节    可选结构 - 增加块大小
所以文件大小的计算分两种情况,当块标记HEAD_FLAGS首位未置1,则总块大小就是HEAD_SIZE,当块标记HEAD_FLAGS首位置1,可选结构存在,则总块大小为HEAD_SIZE+ ADD_SIZE[8]。

[标记块]:这个块只有七个字节一般都是固定的十六进制:526172211A0700 可由此判断该文件是否为rar文件。此块只有一块。
[压缩文件头块]:这个块是描述整个压缩文件的属性,如这个RAR文件是否被加密,使用什么压缩方式如固实压缩等。此块只有一块。
[文件头块]:这个块就是RAR压缩包里面文件被压缩的数据块了,压缩了多少个文件就有多少个文件头数据块。这正好是我们需要的。
[结尾块]:这个是位于文件最后七个字节,一般都是固定的十六进制:C43D7B00400700

我们要提取指定的数据块只需要知道这四个块的数据即可。标记块用于判断该文件是不是RAR文件,压缩文件头块则用来判断该文件是否别加密,文件头块则是要获取的文件名以及记录压缩后的数据块位置,结尾块则是判断RAR压缩文件是否结束。

其余就可根据以后程序的扩展使用,如可以通过读取注释块得到该文件的注释信息并显示出来。

标记块的七个字节含义:



HEAD_CRC  2字节  CRC总是0x6152
HEAD_TYPE  1字节  块类型 0x72
HEAD_FLAGS  2字节  位标记总是 0x1a21
HEAD_SIZE  2字节  块大小 = 0x0007,即7个字节


压缩文件头块:



HEAD_CRC  2字节  HEAD_TYPE 到 RESERVED2 的 CRC 结构
HEAD_TYPE  1字节  头类型:0x73
HEAD_FLAGS  2字节  位标记:
              0x0001  - 卷属性(压缩文件卷)
              0x0002  - 压缩文件注释存在
                       RAR 3.x 使用分开的注释块,不设置这个标记。
                0x0004  - 压缩文件锁定属性
                0x0008  - 固实属性 (固实压缩文件)
                0x0010  - 新的卷命名法则 ('volname.partN.rar')
                0x0020  - 用户信息存在
                          RAR 3.x 不设置这个标记。
                0x0040  - 恢复记录存在
                0x0080  - 块头被加密
                0x0100  - 第一卷(只有 RAR 3.0 及以后版本设置)
                其中的其它位为内部使用保留
HEAD_SIZE  2字节  压缩文件头总大小(包括压缩文件注释)
RESERVED1  2字节  保留
RESERVED2  4字节  保留
        对于压缩文件头里的位标记,如果它的第九位被置1,块头被加密,也就是通常所说的加密文件名,打开这样加密的rar文件时,需要先输入密码才能看到压缩包内的文件列表。
看上图:
0x90CF :是整个压缩文件块的CRC校验值。
0x73      :是代表这个块是压缩文件块类型。
0x0000  :是位标记 所有块都有这个位标记,这个位标记指示了该块的一些特殊属性。这里为0x0000未有位被置1。
                 如果块头被加密则位标记应为0x8000。
0x000D  :是这个块的大小 转换十进制 就是13个字节保留字节用0x00填充。 也就是说下面选中的字节都是属于压缩块。





文件头块:



HEAD_CRC  2 字节  从 HEAD_TYPE 到 FILEATTR 的 CRC 结构和文件名
HEAD_TYPE  1 字节  头类型: 0x74
HEAD_FLAGS  2 字节  位标记:
             0x01 - 文件在前一卷中继续
             0x02 - 文件在后一卷中继续
             0x04 - 文件使用密码加密
             0x08 - 文件注释存在
                       RAR 3.x 使用分开的注释块,不设置这个标记。
             0x10 - 前一文件信息被使用(固实标记)
                       (对于 RAR 2.0 和以后版本)
                     7 6 5 位(对于 RAR 2.0 和以后版本)
                     0 0 0    - 字典大小   64 KB
                     0 0 1    - 字典大小  128 KB
                     0 1 0    - 字典大小  256 KB
                     0 1 1    - 字典大小  512 KB
                     1 0 0    - 字典大小 1024 KB
                     1 0 1    - 字典大小 2048 KB
                     1 1 0    - 字典大小 4096 KB
                     1 1 1    - 文件作为字典
           0x100 - HIGH_PACK_SIZE 和 HIGH_UNP_SIZE 结构存在。这些结构仅
用在非常大(大于 2GB)的文档,对于小文件这些结构不存在。[9]
           0x200 - FILE_NAME 包含用 0隔开的普通的和 Unicode 编码的文件名。
                  所以 NAME_SIZE 结构长度等于普通文件名的长度加 Unicode
                  编码文件名的长度再加1。
                  如果此标记存在,单 FILE_NAME 不包含 0 字节,它意味文件
                  使用 UTF-8 编码。[10]
           0x400 - 头在文件名后包含附加的8位,它对于增加加密的安全性是必需
                  的。(所谓的'Salt')。
           0x800 - 版本标记。他是老文件版本,版本号作为';n'附加到文件名后。
           0x1000 - 扩展时间区域存在。
           0x8000 -此位总被设置,所以完整的块的大小是HEAD_SIZE+ PACK_SIZE
                   (如果 0x100 位被设置,再加上 HIGH_PACK_SIZE)
HEAD_SIZE  2字节  文件头的全部大小(包含文件名和注释)

0x817E:是这个文件块的CRC校验值。
0x74    :表示这个文件块是文件块头
0x8220:位标记。
0x0053:整个文件头块的大小转换成十进制就是83个字节,也就是说下面就是整个文件块的数据。




文件块头之后紧接着文件压缩后、文件压缩前、保存文件的操作系统、文件CRC、文件创建日期、解压最低版本、存储压缩方式、文件名长度、文件属性、文件名,各个字节所占字节数及含义如下。

HIGH_PACK_SIZE  4字节  已压缩文件大小
UNP_SIZE   4字节  未压缩文件大小
HOST_OS   1字节  保存压缩文件使用的操作系统
              0 - MS DOS
                1 - OS/2
                 2 - Win32
                 3 - Unix
                 4 - Mac OS
                 5 - BeOS
FILE_CRC  4字节  文件 CRC
FTIME   4字节  MS DOS 标准格式的日期和时间
UNP_VER  1字节  解压文件所需要最低 RAR 版本
                版本编码方法 10 * 主版本 + 副版本。
METHOD  1字节  压缩方式
                0x30 - 存储
                0x31 - 最快压缩
                0x32 - 快速压缩
                0x33 - 标准压缩
                0x34 - 较好压缩
                0x35 - 最好压缩
NAME_SIZE  2字节  文件名大小
ATTR    4字节  文件属性
HIGH_PACK_SIZE   4字节
压缩文件大小 64 位值的高4字节。可选值,只有 HEAD_FLAGS 中的0x100 位被设置才存在。[11]
HIGH_UNP_SIZE  4字节
未压缩文件大小64位值的高4字节。可选值,只有 HEAD_FLAGS 中的0x100 位被设置才存在。
FILE_NAME  文件名 - NAME_SIZE 字节大小字符串
SALT[12]   8字节  如果 (HEAD_FLAGS & 0x400) != 0 则存在
EXT_TIME   可变大小 如果 (HEAD_FLAGS & 0x1000) != 0 则存在




上面那张图可能看的有些乱,




0x00002338:文件压缩后大小 转换十进制就是9016字节。
0x00007800:文件压缩前大小 转换十进制就是30720字节。







0x02:保存该压缩文件的操作系统 02表示Win32。
0xF05B0A99:文件压缩后数据的CRC校验值。
0x40247E18:文件创建的日期 MS DOS标准格式。
0x1D:解压文件所需要的最低WinRar版本。
0x33:文件压缩方式。
0x0033:文件名的长度,转换十进制就是51个字节。




0x00000020:文件属性
剩余就是文件名了。

文件名后9016个字节就是 存储单位换算器 V1.2.exe 这个文件被压缩后的数据内容了。



这时候如果这个rar压缩包还有第二个文件,那么接下来就是第二个文件的文件块头了,结构也和上面一样。
如果没有第二个文件,那么接下来就是结尾块的7个字节了。



和文件标记块一样,这个结尾块一般是固定的:C43D7B00400700
0xD743:结尾块的CRC校验值
0x7B:表示这是个结尾块
0x4000:位标记
0x0007:这个块的长度

好了,RAR文件格式分析到此就可以了,上面就是提取工具所需要的所必备的RAR文件结构知识。
我们总结一下:
提取工具所需要的基本功能:
第一,要知道文件名,列出来,这样可以让用户决定需要提取哪个文件。
第二,要能保存与文件名所对应的被压缩的文件数据内容的偏移以及长度,这样才能提取。
第三,要能显示出该文件的压缩前后大小,让用户决定是否提取。
第四,要能提供下载功能,把用户指定的文件下载下来,而不是下载整个RAR文件,这样就失去了意义。
第五,要能支持所有的下载链接,如迅雷、快车、QQ旋风等。。。
第六,分析的速度要尽量的快,因为是跳过文件压缩的数据内容所以速度方面肯定会快很多。
第七,进行人性化的设计。

利用上面的知识,我们很容易可以得到文件名、文件压缩前后大小、文件压缩后内容的偏移以及长度等数据。


【第三部分:获取指定数据块】
利用断点续传的方式可以得到指定的文件数据块。
例如:
GET /downfiles/RunStartup.rar HTTP/1.1                                // 请求的文件
Host:www.mndsoft.com                                                            // 请求的主机
Range: bytes=0-6                                                                    // 要求该文件的数据块范围



服务器就会返回数据包:
HTTP/1.1 206 Partial Content
Server: nginx/1.3.9
Date: Tue, 28 May 2013 08:13:22 GMT
Content-Type: application/octet-stream
Content-Length: 7
Connection: keep-alive
Content-Location: http://www.mndsoft.com/downfiles/RunStartup.rar
Content-Range: bytes 0-6/6147
Last-Modified: Sat, 29 Dec 2007 07:44:44 GMT
Accept-Ranges: bytes
ETag: "44f7dcadee49c81:15ce4"
X-Powered-By: WAF/2.0

Rar! .                                                                                 // 这里就是服务器返回的数据块



通过分析RAR的文件格式,来定位文件名、文件属性、被压缩的文件数据。 程序只关注文件压缩前大小、压缩后大小、文件名、文件是否加密,只需要得到这些即可,跳过其他数据。就能实现不需要下载整个文件就能得到文件的相关信息。
当用户想要其中一个文件时,只需要根据自己计算得到的数据块范围 构造一个HTTP给服务器即可得到该数据块的数据,加上RAR的头尾标记即可构成一个完整的rar文件。


程序设计大概思路:
  首先发送请求数据包,请求0-6 七个字节,存入结构:
// 块标记结构
struct HEAD_STRUCT
{
short HEAD_CRC;   // 2字节 头CRC校验值
char HEAD_TYPE;   // 1字节 头类型:
short HEAD_FLAGS;   // 2字节 位标记
short HEAD_SIZE;   // 2字节 头总大小  
};

然后判断:
if(Head.HEAD_CRC != 0x6152 || Head.HEAD_TYPE != 0x72 || Head.HEAD_FLAGS != 0x1A21 || Head.HEAD_SIZE != 0x0007)
{
            // 不是RAR文件的处理方式

再继续读取7-14,不出意外这次肯定就是压缩块头了。
为了方便区分这些不同的块头,我采用如下的结构

  while (1)
{

  // 读取前七个字节
         switch (RarStruct->Head.HEAD_TYPE)
          {
               case 0x73:       // 压缩文件头
   
                    break;
   
               case 0x74:       // 文件头

                    break;
   
               case 0x75:       // 旧风格的注释头
   
                    break;
   
                case 0x76:       // 旧风格的用户身份信息头
   
                    break;
   
                case 0x77:       // 旧风格的子块头
   
                    break;
   
                case 0x78:       // 旧风格的恢复记录头
   
                    break;
   
                 case 0x79:       // 用户身份信息头
   
                    break;
   
                   case 0x7A:       // 注释头
   
                        break;
   
                   case 0x7B:       // 结尾头
                         goto Exit;
                    break;
          }
   }

Exit:
{
  Ting = TRUE;
}

根据不同的头块做不同的处理。我们只需要处理标记块头和压缩块头以及文件块头还有结尾块头即可,其余可全部跳过,这样可以加快分析速度。

    大概的实现原理就是上面那些,ZIP的结构在网上有公开,你们可以感兴趣的话可以去分析一下。当然,ZIP你也可以找【Hades  315102821】,因为是他负责ZIP部分,他比我更加清楚,我这里就不提了。

下面给出程序的下载地址以及完整的源码工程下载地址。
该源码存在的问题,URL处理模块、数据包请求部分以及文件下载模块不完善。
由于一开始采用WinInet编程的方式,导致有时候出现假死状态,实际是由于 HttpSendRequest 这个API阻塞引起的。不知道是什么原因,就把分析部分改用SOCKET的方式,文件下载部分没有修改,所以最好也采用SOCKET的方式下载文件,不然采用WinInet方式有时候会无法下载文件。

源码写的有些乱,不好意思哈。。。

程序下载地址: ZR 智能下载.rar (150.71 KB, 下载次数: 6)
程序完整源代码: ZR 智能下载(源码).rar (336.36 KB, 下载次数: 4)
回复

使用道具 举报

ID:76230 发表于 2015-4-6 11:17 | 显示全部楼层
谢谢楼主
回复

使用道具 举报

ID:85925 发表于 2015-7-17 15:21 | 显示全部楼层
很好不错
回复

使用道具 举报

ID:85925 发表于 2015-7-17 15:21 | 显示全部楼层
很好不错
回复

使用道具 举报

ID:85925 发表于 2015-7-17 15:22 | 显示全部楼层
很好不错
回复

使用道具 举报

ID:85925 发表于 2015-7-17 15:22 | 显示全部楼层
很好不错
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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