FFxivARR SqPack 拆包记录 3
续上一个拆包记录 获得文件块地址之后 我们就可以从对应的dat0文档中 找到对应的文件块了 这章就著重讲下文件块头的解析 我们还是以前面例子的0a0000.win32.dat0文档做例子 从前文写的代码中有帮我们找出三个地址 那么我们就从第一个地址 53 B1 80 …
续上一个拆包记录
获得文件块地址之后
我们就可以从对应的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