Welcome to Yumao′s Blog.
這章應該算是SqPack的最終拆解記錄了
在之前的幾篇文章中已經說了
如何定位到各種文件塊
並且解析文件頭以獲取文件大小
以下需要做到的僅僅是提取文件而已
按照上一章的内容來説
我們分析到的各個文件都是有一個
0x10長度的文件頭
記錄了文件的大小
那麽我們就從文件頭之後
開始轉儲文件内容 按照解壓前的大小
順帶這裡講一個小段子吧
因爲之前從文件頭分析出文件壓縮過
但是不清楚是否壓縮以及加密
就找了個朋友發了幾段内容給他
在即將發出第二段内容的時候
這個朋友就回我是Zlib壓縮了
說這麽明顯的尾部特徵…
看來我真的是雞丁~
言歸正傳
既然知道只是Zlib加密的話
獲取到文件内容之後
並且知道文件壓縮前後大小
那麽直接調用Zlib解壓就好
順帶説明下
這裡提取的文件塊内容
的的確確是Zlib壓縮產物
不過不帶Zlib的標準頭和AB32尾巴
所以需要自己加上頭尾
然後交給Zlib解壓導出文件即可
老樣子 代碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | private static void outputFile(RandomAccessFile randomAccessFile, long addr) throws Exception{ //進行壓縮前後文件長度獲取 int [] size = getFileLength(randomAccessFile,addr); System.out.println( "文件大小爲:" +Arrays.toString(size)); // TODO之後再寫有問題的處理塊方法 先跳過 if (size[ 0 ]/size[ 1 ]< 250 ){ //將指針偏移到數據開始部分 randomAccessFile.seek(addr+ 0x10 ); //開始讀取到壹個臨時數組 byte [] tmp = new byte [size[ 0 ]]; for ( int i= 0 ;i<( int )size[ 0 ];i++){ tmp[i] = randomAccessFile.readByte(); } //准備好頭和尾 byte header[] = {( byte ) 0x58 ,( byte ) 0x85 }; byte footer[] = HexUtils.HexString2Bytes(Long.toHexString(adler32(tmp,( int )size[ 0 ]))); //組合數組 byte [] hexBytes = new byte [header.length+tmp.length+footer.length]; System.arraycopy(header, 0 , hexBytes, 0 , header.length); System.arraycopy(tmp, 0 , hexBytes, header.length , tmp.length); System.arraycopy(footer, 0 , hexBytes, header.length+tmp.length , footer.length); //解壓 byte [] uncompr=uncompress(hexBytes,( int )size[ 1 ]); //提取解壓之後的文件頭說明 設置爲文件的擴展名 byte [] extension = new byte [ 8 ]; System.arraycopy(uncompr, 0 , extension, 0 , 8 ); //輸出文件 File fileOut = new File( "D:\\sqdat\\" +Long.toHexString(addr)+ ".dat" ); FileOutputStream fos = new FileOutputStream(fileOut); fos.write(uncompr); fos.flush(); fos.close(); } } //Mark工具 private static int adler32( byte [] inB, int size){ final int a32mod= 65521 ; int s1= 1 ,s2= 0 ; for ( int i= 0 ;i<size;i++){ int b = inB[i]; s1 = (s1 + b )%a32mod; s2 = (s2 + s1)%a32mod; } return ( int )((s2<< 16 )+s1); } //Zlib解壓工具 private static byte [] uncompress( byte [] data, int length){ int err; int uncomprLen = length; byte [] uncompr = new byte [uncomprLen]; ZStream d_stream = new ZStream(); err = d_stream.inflateInit(); CHECK_ERR(d_stream, err, "inflateInit" ); d_stream.next_in = data; d_stream.next_in_index = 0 ; d_stream.next_out = uncompr; d_stream.next_out_index = 0 ; while (d_stream.total_out < uncomprLen && d_stream.total_in < uncomprLen) { d_stream.avail_in = d_stream.avail_out = 1 ; err = d_stream.inflate(JZlib.Z_NO_FLUSH); if (err == JZlib.Z_STREAM_END) { break ; } CHECK_ERR(d_stream, err, "inflate" ); } err = d_stream.inflateEnd(); CHECK_ERR(d_stream, err, "inflateEnd" ); byte [] unzipfile = new byte [( int ) d_stream.total_out]; System.arraycopy(uncompr, 0 , unzipfile, 0 , unzipfile.length); return unzipfile; } //Zlib解壓檢錯工具 static void CHECK_ERR(ZStream z, int err, String msg) { if (err!=JZlib.Z_OK){ if (z.msg!= null ) System.out.print(z.msg+ " " ); System.out.println(msg+ " error: " +err); System.exit( 1 ); } } |
至於運行之後的内容
大家去找輸出文件夾吧
順帶說下文本文件是使用UTF-8編碼的喔~
最後給出Zlib的jar包:JZlib
以上 轉載請説明出處喔~
英雄放一下源码到git吧
請問是有什麼不明白的地方嗎
有問題的話可以找我探討喔
好的,我将您的代码重新封装成c++的工程,将一些异常抛出,但是在000000.win32.dat0里面并不能很好的运行,zlib解压的时候会提示Z_DATA_ERROR,我检查了偏移和大小都没发现问题,请帮助我
个人认为这个解包方式还是有点误差的
但是毕竟没有得到真正的解包方案
所以纯粹就是靠个人猜测而已
事实表明拆包也是有一点的成果
欢迎找我一起探讨下深入拆包方案
联系方案在博客footer中有