galwiki吧 关注:153贴子:2,102
  • 14回复贴,共1

ai6win引擎的arc封包和akb图片

取消只看楼主收藏回复

先挖坑。本贴试图通过garbro对ai6win arc和akb的拆包反向推理其封包方式。


IP属地:北京1楼2025-01-09 09:10回复
    首先介绍一般的旮旯封包的结构:
    文件头--文件目录--原始文件内容。
    文件头记录被封包的文件夹的基本信息。
    文件目录一般是文件名--偏移量--文件大小的形式。
    这个听起来比较抽象不好懂,所以我们结合ai6win的arc封包具体分析。


    IP属地:北京4楼2025-01-10 08:25
    回复
      首先我们要在garbro源码里找到ai6win引擎部分代码。直接搜索ai6win,注意搜索选项选整个解决方案
      于是我们找到arcai6win.cs,在当前的GARbro1.544版本下,它应该位于GARbro-1.5.44\ArcFormats\Silky下。源码的网盘链接:
      通过网盘分享的文件:ArcAi6Win.7z
      链接: https://pan.baidu.com/s/1uLcMorX3LYUaovW-_mHlOg?pwd=m5iu 提取码: m5iu
      这就是ai6win引擎的拆包源码。


      IP属地:北京5楼2025-01-10 09:32
      回复
        (注意这张图右上角的搜索选项)
        其中的TryOpen函数为解包函数。如果不信可以在这里下断点,你会发现用garbro解包的时候,只命中这个函数。
        由这个解包过程,得arc封包结构:
        开头4byte,存储一个32位整数(count),是封包里的总文件数目。—最开始说的文件头
        文件目录头紧跟其后。每个目录头占272bytes,前260bytes文件名,字符串。261-264byte为文件大小,32位整数。265-268byte解密后大小,32位整数。269-272byte为文件偏移量,32位整数。
        4+272*count byte后为文件内容。
        因此我们封包的思路也很简单,读入文件然后分别把需要的信息写进目录头和内容。这个unpacked size我不太明白,如果你在vs下断点观察到这俩一样,封包也写成和size相等即可。


        IP属地:北京6楼2025-01-10 10:10
        回复
          为了更好理解,我们以十六进制编辑器打开一个arc文件。这里的示例是
          姬騎士オリヴィア~へ、変態、この変態男! 少しは恥を知りなさい!的layer.arc。
          芝士文件头,封包里有0x0D89 = 3465个文件。为什么不是890D? 这是小端序,高位字节在后而每一个字节中高位在前。

          拆一下,确实有3465个文件。

          芝士文件名。使用了简单的加密让你一眼看不出来原名。

          加密的原理是:
          byte - 文件名长度 - 1 + byte所在位数。(0起)
          l - 9 - 1 + 0 = b (b cdefghijkl)
          u - 9 - 1 + 1 = l
          ....
          最后得出的文件名应该是black,akb,一共九个字。
          芝士文件大小。

          看一下也确实是0x20 = 32bytes。为什么是20?这里又用的是大端序了。

          芝士文件偏移。我们可以在封包的这个位置,0xE6194,找到文件原始内容。

          从这里开始的32位和解包为akb得到的32位完全一样。


          实际上,这种通过偏移寻找文件内容的做法在计算机领域是极为常见的。
          arc包就是这样了,很简单吧


          IP属地:北京7楼2025-01-10 10:49
          回复
            接着我们来说akb格式。
            同样的,我们搜索ai6win找到源码,然后设断点找到解密函数。
            在GARbro1.5.44版本,它应该位于GARbro-1.5.44\ArcFormats\Silky下。
            通过网盘分享的文件:ImageAKB.zip
            链接: https://pan.baidu.com/s/1Bdsa7NXCDdfpIOV-ELAJow?pwd=b9wc 提取码: b9wc

            涉及到图片解密的有多个函数,首先是ReadMetaData,读文件头;
            然后是Read,读文件内容。而其中的Unpack函数是解密akb的核心。


            IP属地:北京8楼2025-01-10 11:00
            回复
              从ReadMetaData我们可得.akb文件前32位为文件头,结构如下:

              前四byte是一个标志,大抵是标记这张图是不是差分,不太确定,先不管;
              5-6byte为图片宽度;
              7-8byte为图片高度;
              9-12byte也是一个标志。其中,第12byte的第七位为1,色深(BPP)为32位;否则为24位。
              32位色深就是一个像素用32位表示,r(红),g(绿),b(蓝),a(透明度)各占八位,24位就没有a。
              13-16byte不知道。
              17-20byte为图片X方向偏移。
              21-24byte为图片Y方向偏移。
              25-28byte 减去X方向偏移,为图片实际宽度。
              29-32byte 减去Y方向偏移,为图片实际高度。
              不知道的其实无所谓,可以照抄原图的属性。


              IP属地:北京9楼2025-01-10 11:27
              收起回复
                然后来用之前的black.akb认识文件头:
                这是原始图片,可以看到它宽800,高600,色深24位:

                这是文件签名:

                宽度,0x320 = 800(虽然事到如今了,但是我还是要说x不是乘号,x代表后面的数是十六进制)

                高度,0x258 = 600

                flag,第12byte0xC0 = 1100 0000(二进制),由低位向高位数第七位为1,故为24位色深。

                其余的几个属性,Xoffset,Yoffset,innerWidth,innerHeight




                至于为什么这张全黑只有一个文件头,我的猜想是底下的文件内容假如像素数量,小于 宽*高 个,就会以(0,0,0)也就是纯黑填充。所以它不需要写,节省空间。


                IP属地:北京10楼2025-01-10 17:08
                回复
                  文件解压的算法是unpack。源码应当位于GARbro-1.5.44\ArcFormats\LzssStream.cs
                  简单语言描述一下
                  (提示:通过右键>转到定义可以迅速转到函数原型,通过步进也可以追溯)
                  文件内容由若干操作组组成。每一个操作组的第一byte是操作数,每个操作组占
                  1 (操作数)+ 16 - 操作数变为二进制后1的个数(例如,0xFC = 11111100,6个)byte。
                  解压前初始化字典,由某位置(不一定是0)开始写入。写满词典后,再次从起始位置开始写入。
                  由操作数最低位开始,若该位为1,则从操作组读入1byte,写入输出流,并写入字典。
                  若该位为0,则从操作组读入2bytes;
                  偏移量为 (第二byte & 0xf0) << 4 | 第一byte,即第二byte高位 在12 - 9 位,第一byte在8-1位合成偏移量
                  向输出流写入由字典偏移量开始,长度为(第二byte低位 + 3 )的byte序列,每写入1byte后也向字典写入。

                  大概就是这么个过程。说真的看源码比我这个说的清楚多了


                  IP属地:北京11楼2025-01-10 17:27
                  回复
                    复原akb文件的思路,最简单的是不压缩。
                    也就是将所有操作组的操作数全部设为0xFF,而后跟8byte原始数据。
                    虽然这样会得到120%的惊人压缩率(
                    但是一定可以保证ai6win引擎能读取我们封回的akb。


                    IP属地:北京12楼2025-01-10 17:30
                    回复
                      但是,事实上在转化成akb时,被压缩的并不是图片的原始rgb。
                      这一点我们可以参照源码的RestoreDelta函数,它位于GARbro-1.5.44\ArcFormats\Silky\ImageAKB.cs
                      由此可以得出,解压后GARbro恢复了所得像素点的差分。

                      那么压缩前,我们就该对像素点进行差分编码。(压缩和解压的所有步骤先后顺序完全颠倒)
                      具体而言,ai6win引擎是这么做的:
                      (tips:bmp图片的像素存储也是“小端序”的。也就是最左边一列的height*bpp/8个像素,存储在bmp最后的height*bpp/8个byte)
                      将所有像素从上到下,从左到右,行遍历,每个像素的三个byte以bgr排列,排成一串。
                      对于第height * bpp + 1 至第 width * height *bpp byte,从最后一个byte开始,减去它前方height * bpp 位置的byte 的值。
                      然后,对于第bpp + 1 至 第height * bpp byte,从第height * bpp byte开始,减去它前方 bpp 位置的byte 的值。
                      第1 至 第 bpp byte 不变。
                      注意这几步是有先后顺序的。


                      IP属地:北京13楼2025-01-10 17:58
                      回复
                        然后对差分后的编码做---额,不压缩封回akb。
                        但在数据不能整除8的时候,会导致错误。(操作数指示还有几byte,而文件已经结束了)
                        那么,我们退而求其次,只压缩一次。
                        已知akb的压缩算法实际上就是把长序列变为两位索引,实现压缩。那么对一个长度为n的序列做压缩,可以压缩掉n-2byte。设数据总量为s,%为取余,
                        则压缩一个长度为s % 8 + 2的序列,我们的数据的byte数就被8整除了。
                        而只压缩一次确实没什么难度...反正我目前用这种方法实现了替换ai6win 引擎游戏的图片。


                        IP属地:北京14楼2025-01-10 21:42
                        收起回复
                          但是,要完全复原压缩算法,就有很多细节了。目前我大概推出这么三点:
                          1.将写入一byte差分编码前,在字典中寻找其开头的最长序列,用字典中序列的起始位置代替序列,以实现最高压缩率;
                          2.写入n个连0时,如果字典开头位置前有足够的0,且字典中没有以连0开头的更长序列,则字典中位置为 (开头位置-n);
                          3.字典是首尾相接的。
                          不过我还是没能完全复原。有更多发现我在这接着写吧。


                          IP属地:北京来自Android客户端15楼2025-01-11 12:25
                          回复
                            那么关于ai6win暂时先写到这里,没想到这个就写了那么久ai翻译那个估计得过两三天了,因为我想搜集一下线上和线下模型,还有不同文字提取软件的使用素材,还是有丶多。
                            最后的话教程应该会给出一个最简单的流程,而在文后给出别的选择,尽可能兼顾易懂和全面。总之,大家敬请期待喵~


                            IP属地:北京来自Android客户端16楼2025-01-11 12:29
                            回复
                              如果您需要解封包这个引擎的素材,我可以尽量帮忙。不过我想我还是不公开自己的源码了
                              另外github上面毛子的那个ai6arc真不靠谱,别用


                              IP属地:北京来自Android客户端17楼2025-01-11 12:33
                              回复