FFxivARR SqPack 拆包记录 4 (Final)
这章应该算是SqPack的最终拆解记录了 在之前的几篇文章中已经说了 如何定位到各种文件块 并且解析文件头以获取文件大小 以下需要做到的仅仅是提取文件而已 按照上一章的内容来说 我们分析到的各个文件都是有一个 0x10长度的文件头 记录了文件的大小 那么我们就从文…
这章应该算是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包: [媒体不可用]
以上 转载请说明出处喔~