galgame解包(封包)記錄Ⅱ
前言
前兩天閑來無事,想找個引擎摸摸。本來想摸bgi的,結(jié)果一看封包,瞪眼法全看出來。遂換了個目標,找了個沒什么人引擎來摸。
研究的游戲叫《あおぞらストライプ》,p口水的早期作品

出品會社叫アストロノーツ?コメット。這個社還出過《付喪女?あおゑ》等作品,這里安利一下《付喪女?あおゑ》的op《AIRI 愛離》,非常好聽。p口水另外還有部叫《えれくと!》的作品,是其一個姐妹社アストロノーツ?スピカ開發(fā)的(應(yīng)該吧)?!钉ⅳ兢楗攻去楗ぅ住泛汀钉à欷?!》使用的都是同一款引擎,可以互相套用。
正文
游戲除了exe,就只有幾個后綴為gxp的文件,毫無疑問這就是游戲的封包。
010Editor打開文件看一下

選觀察對象的時候盡量選可以猜到文件數(shù)的(當然如果封包名和gbi那種一樣就算了),這樣可以比較方便分析。
很明顯數(shù)據(jù)從0x30開始變得雜亂。所以我們先看看前0x30個字節(jié)。

最像文件數(shù)的毫無疑問是0x18,當然我們并沒有辦法保證。
多對比幾個封包,會發(fā)現(xiàn)幾個封包的前6個DWORD是一樣的。說明他并沒有描述封包數(shù)據(jù)。我們暫時不關(guān)心。
如果你足夠仔細的話,可以發(fā)現(xiàn)0x20開始,兩個QWORD的和就是這個封包的size。而0x28處的QWORD都是0x1C處的值+0x30。
這基本是我們現(xiàn)在能從封包獲得的全部信息。剩下的就是

直接斷CreateFile,值得一提的是這引擎用的是W系的API,可以說是領(lǐng)先業(yè)界了。
斷點命中后往回跟幾層??梢园l(fā)現(xiàn)函數(shù)明顯長得像fopen。
最后我們可以看到

此時可以得出該封包封包頭的大致結(jié)構(gòu)
struct GxpArchiveHeader
{
char mgaicNumber[4] = { 0x47,0x58,0x50,0x0 }; //封包文件頭
DWORD engineInfo[5] ; //未知,可能是引擎的版本信息之類的東西吧
DWORD?entryCount ; //封包文件數(shù),或者說是目錄項數(shù)
DWORD?contentsSize; //封包目錄的大小,目錄項的大小不是固定的
QWORD dataSectionSize; //數(shù)據(jù)區(qū)域大小
QWORD?infoSectionSize; //封包頭+封包目錄大小
};
0x30的封包頭過頭就是封包的目錄部分。值得一提的目錄項的大小是不固定。
目錄部分和目錄部分都是有加密的(一個比較簡單的異或),但是解密會用到一個17字節(jié)的表,引擎版本不同這個表可能會不同吧

對于每個目錄項,程序會先解密它的前4個字節(jié),該DWORD記錄了整個項的大小。隨后再解密剩余部分。
數(shù)據(jù)就更簡單了,用同樣的方法解密一次就可以了
目錄項的結(jié)構(gòu)大概為
struct GxpContentsEntry
{
DWORD entrySize;
QWORD?dataSize;
DWORD fileNameLength;
QWORD?unknow;
QWORD offsetInDataSection;
WCHAR fileName[];
};
以system.gxp為例



目錄項里有個被我標注成了unknown的成員,不知道那是個什么東西。看著不像哈希之類的玩意,程序好像也沒有用。
如果嘗試直接塞0然后封包的話,游戲也能正常運行。所以就不管它了吧

總結(jié)
總的來說這個引擎的封包結(jié)構(gòu)還是非常簡單的,只不過數(shù)據(jù)套了層加密而已。
游戲的文本在bincode.gxp里,之后有時間可能會研究。
之前看到一個叫《星降る夜のファルネーゼ》的游戲,那個游戲的封包看起來比較炫酷,有時間可能會看看
