KTX到PNG的Python转换:处理iOS快照
iOS上的应用快照以KTX文件格式存储,这得益于Geraldine Blay(@i_am_the_gia)和Alex Brignoni(@AlexisBrignoni)的研究已经广为人知。他们甚至提出了一种收集并将其转换为PNG格式的方法。然而,该解决方案仅适用于macOS,因此有了这项研究。
KTX格式
KTX是一种用于存储纹理的文件格式,通常被OpenGL程序使用。KTX文件格式的详细信息可在此处获取。由于它主要用于游戏而非读取/分发独立纹理,因此没有太多独立的实用程序可以处理KTX文件。也没有现成的Python库可以读取它!创建该格式的Khronos组发布了libktx,但它仅支持C++。即便如此,它也无法读取iOS创建的ktx文件(原因如下所述)。我找到的少数Windows应用程序(如PicoPixel)无法将Apple创建的KTX文件识别为有效文件。
那么这里有什么不同?在十六进制编辑器中快速浏览文件显示,纹理数据以LZFSE压缩形式存储,目前只有macOS/iOS可以读取。
现在使用pyliblzfse,我可以解压缩数据,并使用原始纹理数据重新创建新的KTX文件。即便如此,除了macOS的Finder/Quickview和Preview之外,其他KTX查看器也无法渲染。因此我尝试了几种不同的方法来获取数据。
尝试1 - 渲染和导出
纹理与2D图像不同,因此从纹理到图像格式没有直接转换。根据现有研究,似乎最简单的方法是使用OpenGL渲染从KTX文件中提取的纹理数据,然后使用OpenGL保存渲染图像的2D图像。互联网上也有一些示例代码,但为了使其工作,需要了解如何使用OpenGL渲染纹理,这对我来说学习曲线太陡峭了。
在花了几个小时尝试在Python中实现后,我最终放弃了,因为Python不是主要的OpenGL开发平台,因此支持很少甚至没有,而且库依赖于平台。我勉强在Linux中正确安装了一个库,但每一步都遇到了比我想调试的更多的错误,最终我放弃了。
尝试2 - 将纹理数据转换为原始图像数据
读取KTX文件头,所有iOS生成的KTX文件头中的glInternalFormat值字段为0x93B0(如上图所示)。该值是COMPRESSED_RGBA_ASTC_4x4的枚举。所以现在我们知道了格式是ASTC,即自适应可扩展纹理压缩,一种用于存储纹理数据的有损压缩格式,并使用4x4像素的块大小。这简化了我们的任务,现在需要找到一种将ASTC数据转换为原始图像数据的方法。一番搜索后,我找到了python库astc_decomp,它正是做这个的。所以我需要将各部分组合如下:
- 读取KTX文件并解析格式以获取LZFSE压缩数据,以及宽度和高度参数
- 解压缩LZFSE以获取ASTC数据
- 将ASTC转换为原始图像流
- 使用PIL库将原始图像保存为PNG
将这些组合在一起,我们能够创建一个可以将KTX文件转换为PNG文件的Python脚本。在此获取: https://github.com/ydkhatri/MacForensics/tree/master/IOS_KTX_TO_PNG
如果你需要在没有Python的Windows上执行此操作,那里还有一个Windows编译的可执行文件。Alex Brignoni有帮助地向我发送了多个图像的KTX文件样本。该代码也适用于并非真正KTX的文件,即它们有.ktx扩展名但头是’AAPL’。然而格式类似,我的代码也会解析它们。如果你遇到无法工作的文件,请发送给我,我可以查看。
需要注意的是,并非所有KTX文件都使用COMPRESSED_RGBA_ASTC_4x4格式,只有iOS创建的才使用。因此你可能会遇到许多部署或随应用分发的KTX文件无法用此工具解析,因为它仅处理ASTC 4x4格式。
享受吧!