Welcome to Yumao′s Blog.
FFxivARR SqPack 拆包記錄 3
, 2014年04月19日 , Java Language , 评论 在〈FFxivARR SqPack 拆包記錄 3〉中留言功能已關閉 ,

續上一個拆包記錄
獲得文件塊地址之後
我們就可以從對應的dat0文檔中
找到對應的文件塊了
這章就著重講下文件塊頭的解析

我們還是以前面例子的0a0000.win32.dat0文檔做例子
從前文寫的代碼中有幫我們找出三個地址
那麽我們就從第一個地址 53 B1 80 開始
附近的塊内容如下:

53b170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
53b180: 80 00 00 00 02 00 00 00 8c 1a 00 00 16 00 00 00 
53b190: 13 00 00 00 01 00 00 00 00 00 00 00 80 09 8c 1a 
53b1a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

接著還是給出個人對此段代碼的理解吧

0x53b180-0x53b183 文件頭的長度
0x53b184-0x53b187 未知
0x53b188-0x53b18b 解壓后的文件長度
0x53b80c-0x53b80f 未知
0x53b190-0x53b193 未知
0x53b194-0x53b197 文件塊中文件個數
之後的每八字節為一組
内容為塊内各個文件的説明
例如:本代碼塊只包含一個文件 
所以有數據的部分只有0x53b198-0x53b19f
0x53b198-0x53b19b 文件起始相對第一個文件的偏移值 因爲是單文件所以這裡值為0
0x53b19c-0x53b19d 未知
0x53b19e-0x53b19f 單文件解壓后的大小

然後我們按照文件頭的長度偏移到文件開始部分
每個文件開始都會有長度為0x10也就是十六字節的文件頭
下面是此文件頭的例子:

53b200: 10 00 00 00 00 00 00 00 2d 09 00 00 8c 1a 00 00 

依然是羽毛的解析時間
從多條案例來看是這樣的理解:

0x53b200-0x53b203 此條文件頭的長度 固定為0x10
0x53b204-0x53b207 全空
0x53b208-0x53b20b 文件壓縮前的長度
0x53b20e-0x53b20f 文件解壓后的長度

老樣子給出代碼
代碼實現的的功能暫時為
尋址到文件内容
獲取文件内容以及壓縮前後的大小
解密的話..下節講喔

private static void getFileContent(long addr, String filePatch2) throws Exception {
    //解析同文件夾內的dat0文件地址
    String dat0Path = filePath.substring(0,filePath.indexOf(".index"))+".dat0";
    //開始讀取
    RandomAccessFile randomAccessFile = new RandomAccessFile(dat0Path, "r");
    randomAccessFile.seek(addr);
    //進行標准數據頭格式判斷
    if(addr<randomAccessFile.length()&&randomAccessFile.readByte()==(byte)0x80){
        //數據頭長度獲取
        long headerLength = getHeaderLength(randomAccessFile,addr);
        //數據段內文件個數獲取
        int fileCount = getFileCount(randomAccessFile,addr);
        System.out.print("\r該數據塊內文件個數爲:" + fileCount + " ");
         
        //多文件讀取 先將指針偏移到說明頭 獲取文件長度
        randomAccessFile.seek(addr+headerLength);
        //循環幹的事情
        for(int i=0;i<fileCount;i++){
            int count = i+1;
            System.out.print("正在處理第 " + count + "個文件 ");
            while(randomAccessFile.readByte()!=(byte)0x10){
                //什麽都不做 就是偏移指針 直到跳到下壹段數據的開始
            }
            //獲取指針 然後處理文件輸出
            long nowAddr = randomAccessFile.getFilePointer()-1;
            //搞定文件即可
            System.out.print("地址爲:"+Long.toHexString(nowAddr)+" ");
            outputFile(randomAccessFile,nowAddr);
        }
    }else{
        System.out.println();
    }
    randomAccessFile.close();
}
    private static int getHeaderLength(RandomAccessFile randomAccessFile,long addr) throws Exception{
        //按照分析前面四位應該是文件頭的長度 2^7對齊
        randomAccessFile.seek(addr);
        byte[] tmp = new byte[4];
        for(int i=3;i>0;i--){
            tmp[i] = randomAccessFile.readByte();
        }
        return Integer.parseInt(HexUtils.Bytes2HexString(tmp).replace(" ", ""),16);
    }

輸出結果參考:

文件塊地址爲: 53 B1 80 
該數據塊內文件個數爲:1 正在處理第 1個文件 地址爲:53b200 文件大小爲:[2349, 6796]
文件塊地址爲: 18 
文件塊地址爲: 64 00 
关键字:, , , , ,

评论已关闭