Welcome to Yumao′s Blog.

這章應該算是SqPack的最終拆解記錄了
在之前的幾篇文章中已經說了
如何定位到各種文件塊
並且解析文件頭以獲取文件大小
以下需要做到的僅僅是提取文件而已

按照上一章的内容來説
我們分析到的各個文件都是有一個
0x10長度的文件頭
記錄了文件的大小
那麽我們就從文件頭之後
開始轉儲文件内容 按照解壓前的大小

順帶這裡講一個小段子吧
因爲之前從文件頭分析出文件壓縮過
但是不清楚是否壓縮以及加密
就找了個朋友發了幾段内容給他
在即將發出第二段内容的時候
這個朋友就回我是Zlib壓縮了
說這麽明顯的尾部特徵…
看來我真的是雞丁~

言歸正傳
既然知道只是Zlib加密的話
獲取到文件内容之後
並且知道文件壓縮前後大小
那麽直接調用Zlib解壓就好

順帶説明下
這裡提取的文件塊内容
的的確確是Zlib壓縮產物
不過不帶Zlib的標準頭和AB32尾巴
所以需要自己加上頭尾
然後交給Zlib解壓導出文件即可

老樣子 代碼如下:

    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
以上 轉載請説明出處喔~

关键字:, , , , ,

      • 好的,我将您的代码重新封装成c++的工程,将一些异常抛出,但是在000000.win32.dat0里面并不能很好的运行,zlib解压的时候会提示Z_DATA_ERROR,我检查了偏移和大小都没发现问题,请帮助我

        • 个人认为这个解包方式还是有点误差的
          但是毕竟没有得到真正的解包方案
          所以纯粹就是靠个人猜测而已
          事实表明拆包也是有一点的成果
          欢迎找我一起探讨下深入拆包方案
          联系方案在博客footer中有