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)
2015-1-10 23:01 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
程序完整源代碼:
ZR 智能下載(源碼).rar
(336.36 KB, 下載次數: 4)
2015-1-10 23:01 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|