修復損壞的gzip壓縮檔案之原理篇
修復一個損壞的gzip檔案的關鍵環節在於找到下一個正常壓縮包的起始點。根據結構圖中的資訊可知,每個壓縮包的開始結構中有是否到達尾部標誌、使用的哈夫曼樹型別、以及3個哈夫曼樹的樹元素個數等。如果某個gzip檔案中間有一個壞扇區,要找到壞扇區後的一個正常起點,僅需按位右移,一直移位到可以正常解壓的某個位,就可能找到了正確的壓縮包起始。而根據gzip檔案的壓縮作業視窗為32KB大小推算,這個遍歷不會超過64KB即可找到。在記憶體中快速迴圈可以很快找到,但需要有明確的判斷錯誤的方法。
首先可以明確的是結尾標誌,應該為0(我們是從損壞的點向後查)。而哈夫曼樹型別也大致應該是動態哈夫曼(0x02),cl1的元素個數應該取值為257到286之間(包含邊界),cl2的元素個數應小於等於30,ccl的元素個數取值可為1-15(包含邊界)。
其實,還可以參考的東西有,解開的哈夫曼樹是否異常,或者透過規律性原則找到最後一個取值為256的值,但這些演算法應該是較為麻煩的,有上面的演算法連續校驗幾個壓縮塊就足夠了。
具體方法是對gzip的原始碼做修改,進行遍歷。因時間關係,未做成通用工程,僅快速修改了部分程式碼。大致的修改點為:
這一行前,獲取當前解碼位元組位置即可。
為:
2、inflate.c檔案中,在int inflate_block(e)函式中
在如下程式碼前
加入程式碼:
3、inflate.c檔案中,在int inflate_block(e)函式尾部
把if (t == 0) 與if (t == 1)的情況都直接返回錯誤值2。
4、inflate.c檔案中,函式int inflate()中,改
為:
此4步完成後,試著除錯這個錯誤的.gz檔案,當然,也可以在程式碼中解釋完頭部結構後加一個seek,直接seek到損壞位置。
通常情況下,輸出printf(“get by !”)這行程式碼時,已經找到了正確的起始位。
找到起始位後,也可以構造或複製一個正常的gzip檔案頭,再拼接好找到的位流,即可解壓了。(如果位流不是位元組對齊的,可能要全部做位移)。拼接後很多壓縮檔案就可以開啟甚至於解壓了,不過,有可能會報錯,主要是尾部的校驗和大小錯,其實可以忽略。
如果拼接好了linux下,不能直接用“gzip –d”解壓,因其crc有錯誤,會導致解壓到99%後報錯,然後把檔案刪除,換成管道命令即可:
首先可以明確的是結尾標誌,應該為0(我們是從損壞的點向後查)。而哈夫曼樹型別也大致應該是動態哈夫曼(0x02),cl1的元素個數應該取值為257到286之間(包含邊界),cl2的元素個數應小於等於30,ccl的元素個數取值可為1-15(包含邊界)。
其實,還可以參考的東西有,解開的哈夫曼樹是否異常,或者透過規律性原則找到最後一個取值為256的值,但這些演算法應該是較為麻煩的,有上面的演算法連續校驗幾個壓縮塊就足夠了。
具體方法是對gzip的原始碼做修改,進行遍歷。因時間關係,未做成通用工程,僅快速修改了部分程式碼。大致的修改點為:
一,找到損壞點:
在unzip.c中,點選(此處)摺疊或開啟
- error("invalid compressed data--format violated")
二、遍歷找到損壞點:
1、inflate.c檔案中,改點選(此處)摺疊或開啟
-
if (nl > 286 || nd > 30)
-
#endif
- return 1
點選(此處)摺疊或開啟
-
if (nl > 286 || nd > 30||nl <257 || nd <1)
-
#endif
- return 1
在如下程式碼前
點選(此處)摺疊或開啟
-
bb = b;
- bk = k
點選(此處)摺疊或開啟
-
if ((t != 2) || (*e != 0))
- return 2
把if (t == 0) 與if (t == 1)的情況都直接返回錯誤值2。
4、inflate.c檔案中,函式int inflate()中,改
點選(此處)摺疊或開啟
-
if ((r = inflate_block(&e)) != 0)
-
return r;
- end
點選(此處)摺疊或開啟
-
unsigned t; /* block type */
-
register ulg b; /* bit buffer */
-
register unsigned k; /* number of bits in bit buffer */
-
while (inptr <= insize)
-
{
-
unsigned int tptr = inptr;
-
unsigned int tbk = bk;
-
unsigned long tbb = bb;
-
unsigned int twp = wp;
-
long long tstart = *(long long*)(inbuf + tptr);
-
if ((r = inflate_block(&e)) != 0)
-
{
-
inptr = tptr;
-
bb = tbb;
-
bk = tbk;
-
wp = twp;
-
b = bb;
-
k = bk;
-
NEEDBITS(1)
-
DUMPBITS(1)
-
}
-
else
-
{
-
printf("get by !"); //也可輸出tstart,bb,bk 值,
-
}
- }
通常情況下,輸出printf(“get by !”)這行程式碼時,已經找到了正確的起始位。
找到起始位後,也可以構造或複製一個正常的gzip檔案頭,再拼接好找到的位流,即可解壓了。(如果位流不是位元組對齊的,可能要全部做位移)。拼接後很多壓縮檔案就可以開啟甚至於解壓了,不過,有可能會報錯,主要是尾部的校驗和大小錯,其實可以忽略。
如果拼接好了linux下,不能直接用“gzip –d”解壓,因其crc有錯誤,會導致解壓到99%後報錯,然後把檔案刪除,換成管道命令即可:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31380569/viewspace-2155428/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 圖解gzip壓縮檔案底層結構及檔案損壞的修復方法圖解
- 修復損壞的gz或tar.gz壓縮檔案之方法篇
- 使用gzip壓縮檔案
- pg 檔案塊損壞的修復措施。
- SQL Anywhere db檔案損壞修復 DB檔案修復 DB資料庫修復SQL資料庫
- system資料檔案頭損壞修復
- Vue開啟gzip壓縮檔案Vue
- InterBase資料庫檔案損壞的修復方法資料庫
- linux檔案系統損壞如何修復Linux
- 選定進行壓縮的卷可能已損壞。請使用chkdsk來修復損壞問題,然後嘗試再次壓縮該卷
- 恢復之單個控制檔案損壞
- 過濾器實現檔案的gzip壓縮過濾器
- 妙用安裝盤修復損壞的系統檔案(轉)
- 損壞控制檔案的恢復方法
- 分析核心對gzip壓縮檔案進行解壓的方法(轉)
- 某個表空間的資料檔案損壞的修復思路
- 修復損壞的資料塊
- 備份&恢復之十三:損壞全部控制檔案
- Java實現檔案壓縮與解壓[zip格式,gzip格式]Java
- Win10系統損壞的cbs.log檔案如何修復Win10
- 單個控制檔案損壞的恢復
- MongoDB 資料檔案損壞修復救命repair與致命危險MongoDBAI
- LINUX 檔案系統損壞後遠端修復方案薦Linux
- ORACLE 10g中使用BBED修復損壞資料檔案Oracle 10g
- SQL Server ldf 檔案損壞恢復SQLServer
- 備份&恢復之十二:損壞單個控制檔案
- Linux檔案系統損壞後的修復技巧詳細介紹Linux
- HTTP 之 檔案壓縮HTTP
- 【BBED】 SYSTEM檔案頭損壞的恢復(4)
- 資料檔案丟失損壞的恢復--
- 某個控制檔案損壞的恢復案例
- REDO檔案丟失或者損壞的恢復
- UNDO 表空間檔案損壞的恢復
- 一次控制檔案損壞的恢復
- linux下修復磁碟損壞Linux
- 修復檔案終結者病毒破壞的檔案
- Android總結之Gzip/Zip壓縮Android
- 關於Java的GZIP壓縮與.net C#的GZIP壓縮的差異JavaC#