|
ZR智能下載是一款可以提取網(wǎng)絡(luò)上壓縮文件中指定文件內(nèi)容的程序。如一個(gè)ZIP下載地址為:http:\\www.xxx.com\Setus.rar 這個(gè)壓縮包 大小是 2G ,你可以通過這款小工具分析這個(gè)rar壓縮包里面的文件,找到自己需要的文件就可以直接下載那個(gè)文件而不需要下載整個(gè)2G大的文件。如果你想要下載的文件只有2M 那么就只需要下載那個(gè)2M的文件即可。這樣既節(jié)省下載時(shí)間又節(jié)省流量。
該程序暫只支持 ZIP、RAR格式。
如圖:
雙擊指定文件即可下載指定文件。下載的文件以原壓縮格式保存。
原ZIP文件:
下載的以原來的壓縮格式保存,下載下來直接用 WinRAR就能解壓。之所以這樣是因?yàn)樵诜治鰤嚎s文件格式的時(shí)候花費(fèi)的時(shí)間很長,以前也從沒有接觸過這些文件格式,如果再分析解壓縮算法,那么花的時(shí)間就更長了。
由于最近我把精力放在單片機(jī)上,設(shè)計(jì)這個(gè)是因?yàn)檫@個(gè)設(shè)計(jì)思路非常不錯(cuò),吸引我去設(shè)計(jì),是一個(gè)好友提出來的,但后來發(fā)現(xiàn)難度并想想的要大一些,花費(fèi)的時(shí)間超過預(yù)期,所以把基本的功能實(shí)現(xiàn)后就放著,這個(gè)程序還有很大的提升空間。現(xiàn)在把原理以及實(shí)現(xiàn)源碼都公布出來,讓有心人去完善吧。。。基本的原理以及RAR文件結(jié)構(gòu)以及心得都會(huì)在下面給出,讓你們少走一些彎路,這樣也能快點(diǎn)入手。。。好好感謝【Hades 315102821】吧,那么好的思路是他提出來,設(shè)計(jì)這個(gè)程序的時(shí)候也是他提供了資料以及一些建議。設(shè)計(jì)這個(gè)程序的時(shí)候我感覺自己C程序方面的進(jìn)步挺大的,分析這些數(shù)據(jù)的時(shí)候,采用結(jié)構(gòu)來分析方便N倍,我居然現(xiàn)在才體會(huì)到。
[color=#110df2,strength=3)"]基本實(shí)現(xiàn)思路:
充分利用斷點(diǎn)續(xù)傳原理,以及壓縮文件結(jié)構(gòu)的特點(diǎn),來實(shí)現(xiàn)隨意提取網(wǎng)絡(luò)上壓縮包內(nèi)所需要的文件。斷點(diǎn)續(xù)傳可以讓我們隨意獲取網(wǎng)絡(luò)文件中的任意指定數(shù)據(jù)范圍的數(shù)據(jù)塊,而壓縮文件結(jié)構(gòu)一般都是一個(gè)文件一個(gè)數(shù)據(jù)塊,而不會(huì)幾個(gè)文件數(shù)據(jù)混合在一起,所以可以根據(jù)壓縮文件的結(jié)構(gòu)來確定我們所需要的數(shù)據(jù)塊的位置、大小,這樣可以從源頭就能跳過我們不需要的數(shù)據(jù)塊,只下載我們想要的是數(shù)據(jù)塊,這個(gè)數(shù)據(jù)塊可以是一個(gè)被壓縮后的文件也可以是一段注釋,任意選取。so 這個(gè)實(shí)現(xiàn)思路不單單可以用在壓縮文件上,還可以用于其他的方面。不要被我們的慣性思想局限了。當(dāng)然,只利用我的程序代碼里面還可以實(shí)現(xiàn)快速分離壓縮文件中的指定文件,如果有一個(gè)很大的RAR文件,里面包含的很多文件,那么可以利用下面RAR文件結(jié)構(gòu),實(shí)現(xiàn)快速分析RAR文件名以及快速提取里面的文件,當(dāng)然提取出來的還是RAR壓縮文件格式。你可以試試,我這種分析方法比WinRAR分析的快很多很多。
實(shí)現(xiàn)基本原理(例RAR):
以下所有的解釋以這個(gè)RAR文件為例子。
【第一部分:分析RAR格式】
由于我們只需要得到指定文件的數(shù)據(jù)塊所以不需要對rar文件格式分析的多深入,RAR文件格式是數(shù)據(jù)塊做單位的,一般有標(biāo)記塊,壓縮文件頭塊,文件頭塊,注釋頭,用戶身份信息,子塊和恢復(fù)記錄塊等。
每一塊的前七個(gè)字節(jié)最重要,這七個(gè)字節(jié)包含:
HEAD_CRC 2 字節(jié) 所有塊或塊部分的 CRC
HEAD_TYPE 1 字節(jié) 塊類型
HEAD_FLAGS 2 字節(jié) 塊標(biāo)記
HEAD_SIZE 2 字節(jié) 塊大小
如果塊標(biāo)記的第一位被置1的話,還存在:
ADD_SIZE 4 字節(jié) 可選結(jié)構(gòu) - 增加塊大小
所以文件大小的計(jì)算分兩種情況,當(dāng)塊標(biāo)記HEAD_FLAGS首位未置1,則總塊大小就是HEAD_SIZE,當(dāng)塊標(biāo)記HEAD_FLAGS首位置1,可選結(jié)構(gòu)存在,則總塊大小為HEAD_SIZE+ ADD_SIZE[8]。
[標(biāo)記塊]:這個(gè)塊只有七個(gè)字節(jié)一般都是固定的十六進(jìn)制:526172211A0700 可由此判斷該文件是否為rar文件。此塊只有一塊。
[壓縮文件頭塊]:這個(gè)塊是描述整個(gè)壓縮文件的屬性,如這個(gè)RAR文件是否被加密,使用什么壓縮方式如固實(shí)壓縮等。此塊只有一塊。
[文件頭塊]:這個(gè)塊就是RAR壓縮包里面文件被壓縮的數(shù)據(jù)塊了,壓縮了多少個(gè)文件就有多少個(gè)文件頭數(shù)據(jù)塊。這正好是我們需要的。
[結(jié)尾塊]:這個(gè)是位于文件最后七個(gè)字節(jié),一般都是固定的十六進(jìn)制:C43D7B00400700
我們要提取指定的數(shù)據(jù)塊只需要知道這四個(gè)塊的數(shù)據(jù)即可。標(biāo)記塊用于判斷該文件是不是RAR文件,壓縮文件頭塊則用來判斷該文件是否別加密,文件頭塊則是要獲取的文件名以及記錄壓縮后的數(shù)據(jù)塊位置,結(jié)尾塊則是判斷RAR壓縮文件是否結(jié)束。
其余就可根據(jù)以后程序的擴(kuò)展使用,如可以通過讀取注釋塊得到該文件的注釋信息并顯示出來。
標(biāo)記塊的七個(gè)字節(jié)含義:
HEAD_CRC 2字節(jié) CRC總是0x6152
HEAD_TYPE 1字節(jié) 塊類型 0x72
HEAD_FLAGS 2字節(jié) 位標(biāo)記總是 0x1a21
HEAD_SIZE 2字節(jié) 塊大小 = 0x0007,即7個(gè)字節(jié)
壓縮文件頭塊:
HEAD_CRC 2字節(jié) HEAD_TYPE 到 RESERVED2 的 CRC 結(jié)構(gòu)
HEAD_TYPE 1字節(jié) 頭類型:0x73
HEAD_FLAGS 2字節(jié) 位標(biāo)記:
0x0001 - 卷屬性(壓縮文件卷)
0x0002 - 壓縮文件注釋存在
RAR 3.x 使用分開的注釋塊,不設(shè)置這個(gè)標(biāo)記。
0x0004 - 壓縮文件鎖定屬性
0x0008 - 固實(shí)屬性 (固實(shí)壓縮文件)
0x0010 - 新的卷命名法則 ('volname.partN.rar')
0x0020 - 用戶信息存在
RAR 3.x 不設(shè)置這個(gè)標(biāo)記。
0x0040 - 恢復(fù)記錄存在
0x0080 - 塊頭被加密
0x0100 - 第一卷(只有 RAR 3.0 及以后版本設(shè)置)
其中的其它位為內(nèi)部使用保留
HEAD_SIZE 2字節(jié) 壓縮文件頭總大小(包括壓縮文件注釋)
RESERVED1 2字節(jié) 保留
RESERVED2 4字節(jié) 保留
對于壓縮文件頭里的位標(biāo)記,如果它的第九位被置1,塊頭被加密,也就是通常所說的加密文件名,打開這樣加密的rar文件時(shí),需要先輸入密碼才能看到壓縮包內(nèi)的文件列表。
看上圖:
0x90CF :是整個(gè)壓縮文件塊的CRC校驗(yàn)值。
0x73 :是代表這個(gè)塊是壓縮文件塊類型。
0x0000 :是位標(biāo)記 所有塊都有這個(gè)位標(biāo)記,這個(gè)位標(biāo)記指示了該塊的一些特殊屬性。這里為0x0000未有位被置1。
如果塊頭被加密則位標(biāo)記應(yīng)為0x8000。
0x000D :是這個(gè)塊的大小 轉(zhuǎn)換十進(jìn)制 就是13個(gè)字節(jié)保留字節(jié)用0x00填充。 也就是說下面選中的字節(jié)都是屬于壓縮塊。
文件頭塊:
HEAD_CRC 2 字節(jié) 從 HEAD_TYPE 到 FILEATTR 的 CRC 結(jié)構(gòu)和文件名
HEAD_TYPE 1 字節(jié) 頭類型: 0x74
HEAD_FLAGS 2 字節(jié) 位標(biāo)記:
0x01 - 文件在前一卷中繼續(xù)
0x02 - 文件在后一卷中繼續(xù)
0x04 - 文件使用密碼加密
0x08 - 文件注釋存在
RAR 3.x 使用分開的注釋塊,不設(shè)置這個(gè)標(biāo)記。
0x10 - 前一文件信息被使用(固實(shí)標(biāo)記)
(對于 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 結(jié)構(gòu)存在。這些結(jié)構(gòu)僅
用在非常大(大于 2GB)的文檔,對于小文件這些結(jié)構(gòu)不存在。[9]
0x200 - FILE_NAME 包含用 0隔開的普通的和 Unicode 編碼的文件名。
所以 NAME_SIZE 結(jié)構(gòu)長度等于普通文件名的長度加 Unicode
編碼文件名的長度再加1。
如果此標(biāo)記存在,單 FILE_NAME 不包含 0 字節(jié),它意味文件
使用 UTF-8 編碼。[10]
0x400 - 頭在文件名后包含附加的8位,它對于增加加密的安全性是必需
的。(所謂的'Salt')。
0x800 - 版本標(biāo)記。他是老文件版本,版本號作為';n'附加到文件名后。
0x1000 - 擴(kuò)展時(shí)間區(qū)域存在。
0x8000 -此位總被設(shè)置,所以完整的塊的大小是HEAD_SIZE+ PACK_SIZE
(如果 0x100 位被設(shè)置,再加上 HIGH_PACK_SIZE)
HEAD_SIZE 2字節(jié) 文件頭的全部大小(包含文件名和注釋)
0x817E:是這個(gè)文件塊的CRC校驗(yàn)值。
0x74 :表示這個(gè)文件塊是文件塊頭
0x8220:位標(biāo)記。
0x0053:整個(gè)文件頭塊的大小轉(zhuǎn)換成十進(jìn)制就是83個(gè)字節(jié),也就是說下面就是整個(gè)文件塊的數(shù)據(jù)。
文件塊頭之后緊接著文件壓縮后、文件壓縮前、保存文件的操作系統(tǒng)、文件CRC、文件創(chuàng)建日期、解壓最低版本、存儲壓縮方式、文件名長度、文件屬性、文件名,各個(gè)字節(jié)所占字節(jié)數(shù)及含義如下。
HIGH_PACK_SIZE 4字節(jié) 已壓縮文件大小
UNP_SIZE 4字節(jié) 未壓縮文件大小
HOST_OS 1字節(jié) 保存壓縮文件使用的操作系統(tǒng)
0 - MS DOS
1 - OS/2
2 - Win32
3 - Unix
4 - Mac OS
5 - BeOS
FILE_CRC 4字節(jié) 文件 CRC
FTIME 4字節(jié) MS DOS 標(biāo)準(zhǔn)格式的日期和時(shí)間
UNP_VER 1字節(jié) 解壓文件所需要最低 RAR 版本
版本編碼方法 10 * 主版本 + 副版本。
METHOD 1字節(jié) 壓縮方式
0x30 - 存儲
0x31 - 最快壓縮
0x32 - 快速壓縮
0x33 - 標(biāo)準(zhǔn)壓縮
0x34 - 較好壓縮
0x35 - 最好壓縮
NAME_SIZE 2字節(jié) 文件名大小
ATTR 4字節(jié) 文件屬性
HIGH_PACK_SIZE 4字節(jié)
壓縮文件大小 64 位值的高4字節(jié)。可選值,只有 HEAD_FLAGS 中的0x100 位被設(shè)置才存在。[11]
HIGH_UNP_SIZE 4字節(jié)
未壓縮文件大小64位值的高4字節(jié)。可選值,只有 HEAD_FLAGS 中的0x100 位被設(shè)置才存在。
FILE_NAME 文件名 - NAME_SIZE 字節(jié)大小字符串
SALT[12] 8字節(jié) 如果 (HEAD_FLAGS & 0x400) != 0 則存在
EXT_TIME 可變大小 如果 (HEAD_FLAGS & 0x1000) != 0 則存在
上面那張圖可能看的有些亂,
0x00002338:文件壓縮后大小 轉(zhuǎn)換十進(jìn)制就是9016字節(jié)。
0x00007800:文件壓縮前大小 轉(zhuǎn)換十進(jìn)制就是30720字節(jié)。
0x02:保存該壓縮文件的操作系統(tǒng) 02表示W(wǎng)in32。
0xF05B0A99:文件壓縮后數(shù)據(jù)的CRC校驗(yàn)值。
0x40247E18:文件創(chuàng)建的日期 MS DOS標(biāo)準(zhǔn)格式。
0x1D:解壓文件所需要的最低WinRar版本。
0x33:文件壓縮方式。
0x0033:文件名的長度,轉(zhuǎn)換十進(jìn)制就是51個(gè)字節(jié)。
0x00000020:文件屬性
剩余就是文件名了。
文件名后9016個(gè)字節(jié)就是 存儲單位換算器 V1.2.exe 這個(gè)文件被壓縮后的數(shù)據(jù)內(nèi)容了。
這時(shí)候如果這個(gè)rar壓縮包還有第二個(gè)文件,那么接下來就是第二個(gè)文件的文件塊頭了,結(jié)構(gòu)也和上面一樣。
如果沒有第二個(gè)文件,那么接下來就是結(jié)尾塊的7個(gè)字節(jié)了。
和文件標(biāo)記塊一樣,這個(gè)結(jié)尾塊一般是固定的:C43D7B00400700
0xD743:結(jié)尾塊的CRC校驗(yàn)值
0x7B:表示這是個(gè)結(jié)尾塊
0x4000:位標(biāo)記
0x0007:這個(gè)塊的長度
好了,RAR文件格式分析到此就可以了,上面就是提取工具所需要的所必備的RAR文件結(jié)構(gòu)知識。
我們總結(jié)一下:
提取工具所需要的基本功能:
第一,要知道文件名,列出來,這樣可以讓用戶決定需要提取哪個(gè)文件。
第二,要能保存與文件名所對應(yīng)的被壓縮的文件數(shù)據(jù)內(nèi)容的偏移以及長度,這樣才能提取。
第三,要能顯示出該文件的壓縮前后大小,讓用戶決定是否提取。
第四,要能提供下載功能,把用戶指定的文件下載下來,而不是下載整個(gè)RAR文件,這樣就失去了意義。
第五,要能支持所有的下載鏈接,如迅雷、快車、QQ旋風(fēng)等。。。
第六,分析的速度要盡量的快,因?yàn)槭翘^文件壓縮的數(shù)據(jù)內(nèi)容所以速度方面肯定會(huì)快很多。
第七,進(jìn)行人性化的設(shè)計(jì)。
利用上面的知識,我們很容易可以得到文件名、文件壓縮前后大小、文件壓縮后內(nèi)容的偏移以及長度等數(shù)據(jù)。
【第三部分:獲取指定數(shù)據(jù)塊】
利用斷點(diǎn)續(xù)傳的方式可以得到指定的文件數(shù)據(jù)塊。
例如:
GET /downfiles/RunStartup.rar HTTP/1.1 // 請求的文件
Host:www.mndsoft.com // 請求的主機(jī)
Range: bytes=0-6 // 要求該文件的數(shù)據(jù)塊范圍
服務(wù)器就會(huì)返回?cái)?shù)據(jù)包:
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! . // 這里就是服務(wù)器返回的數(shù)據(jù)塊
通過分析RAR的文件格式,來定位文件名、文件屬性、被壓縮的文件數(shù)據(jù)。 程序只關(guān)注文件壓縮前大小、壓縮后大小、文件名、文件是否加密,只需要得到這些即可,跳過其他數(shù)據(jù)。就能實(shí)現(xiàn)不需要下載整個(gè)文件就能得到文件的相關(guān)信息。
當(dāng)用戶想要其中一個(gè)文件時(shí),只需要根據(jù)自己計(jì)算得到的數(shù)據(jù)塊范圍 構(gòu)造一個(gè)HTTP給服務(wù)器即可得到該數(shù)據(jù)塊的數(shù)據(jù),加上RAR的頭尾標(biāo)記即可構(gòu)成一個(gè)完整的rar文件。
程序設(shè)計(jì)大概思路:
首先發(fā)送請求數(shù)據(jù)包,請求0-6 七個(gè)字節(jié),存入結(jié)構(gòu):
// 塊標(biāo)記結(jié)構(gòu)
struct HEAD_STRUCT
{
short HEAD_CRC; // 2字節(jié) 頭CRC校驗(yàn)值
char HEAD_TYPE; // 1字節(jié) 頭類型:
short HEAD_FLAGS; // 2字節(jié) 位標(biāo)記
short HEAD_SIZE; // 2字節(jié) 頭總大小
};
然后判斷:
if(Head.HEAD_CRC != 0x6152 || Head.HEAD_TYPE != 0x72 || Head.HEAD_FLAGS != 0x1A21 || Head.HEAD_SIZE != 0x0007)
{
// 不是RAR文件的處理方式
}
再繼續(xù)讀取7-14,不出意外這次肯定就是壓縮塊頭了。
為了方便區(qū)分這些不同的塊頭,我采用如下的結(jié)構(gòu)
while (1)
{
// 讀取前七個(gè)字節(jié)
switch (RarStruct->Head.HEAD_TYPE)
{
case 0x73: // 壓縮文件頭
break;
case 0x74: // 文件頭
break;
case 0x75: // 舊風(fēng)格的注釋頭
break;
case 0x76: // 舊風(fēng)格的用戶身份信息頭
break;
case 0x77: // 舊風(fēng)格的子塊頭
break;
case 0x78: // 舊風(fēng)格的恢復(fù)記錄頭
break;
case 0x79: // 用戶身份信息頭
break;
case 0x7A: // 注釋頭
break;
case 0x7B: // 結(jié)尾頭
goto Exit;
break;
}
}
Exit:
{
Ting = TRUE;
}
根據(jù)不同的頭塊做不同的處理。我們只需要處理標(biāo)記塊頭和壓縮塊頭以及文件塊頭還有結(jié)尾塊頭即可,其余可全部跳過,這樣可以加快分析速度。
大概的實(shí)現(xiàn)原理就是上面那些,ZIP的結(jié)構(gòu)在網(wǎng)上有公開,你們可以感興趣的話可以去分析一下。當(dāng)然,ZIP你也可以找【Hades 315102821】,因?yàn)槭撬?fù)責(zé)ZIP部分,他比我更加清楚,我這里就不提了。
下面給出程序的下載地址以及完整的源碼工程下載地址。
該源碼存在的問題,URL處理模塊、數(shù)據(jù)包請求部分以及文件下載模塊不完善。
由于一開始采用WinInet編程的方式,導(dǎo)致有時(shí)候出現(xiàn)假死狀態(tài),實(shí)際是由于 HttpSendRequest 這個(gè)API阻塞引起的。不知道是什么原因,就把分析部分改用SOCKET的方式,文件下載部分沒有修改,所以最好也采用SOCKET的方式下載文件,不然采用WinInet方式有時(shí)候會(huì)無法下載文件。
源碼寫的有些亂,不好意思哈。。。
程序下載地址:
ZR 智能下載.rar
(150.71 KB, 下載次數(shù): 6)
2015-1-10 23:01 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
程序完整源代碼:
ZR 智能下載(源碼).rar
(336.36 KB, 下載次數(shù): 4)
2015-1-10 23:01 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|
|