游戏:仏蘭西少女
厂家:PIL

这个封包没有经过压缩、加密处理,而且主程序也没作任何反调试的处理,逆起来相当轻松。。。

封包的相关结构如下,2 和 3 的 entry 即对应 DDP2 和 DDP3 的封包,DDP3 中的索引使用了二级结构。

struct Header
{
    enum {
        MAGIC_2 = 0x32504444,	// DDP2
        MAGIC_3 = 0x33504444,	// DDP3
    };
    uint32_t Magic;
    uint32_t EntryCount;   // DDP3 中指 Entry3_L1 的数量
    uint32_t DataOffset;   // 起始数据的偏移
    uint8_t  Revsered[20];
};

struct Entry2
{
    uint32_t Offset;
    uint32_t PlainSize;    // 实际大小
    uint32_t PackedSize;   // 压缩后大小
    uint32_t Revsered;
};

struct Entry3_L1
{
    uint32_t BlockSize;    // 块大小
    uint32_t BlockOffset;  // 块偏移
};

#pragma pack(push, 1)
struct Entry3_L2_Header
{
    uint8_t  Size;         // 索引大小
    uint32_t Offset;
    uint32_t PlainSize;
    uint32_t PackedSize;
    uint8_t  Revsered[4];
    // followed by char* NameWithoutSuffix;
};
#pragma pack(pop)

就这个游戏来看,DDP2 封包的内容都是经过压缩的,两个字段的大小不一致;而 DDP3 中不是所有文件都经过压缩,未压缩文件的 PackedSize 字段为 0。另外 DDP3 的索引中带有 C 风格字符串的文件名,DDP2 中则没有。封包橙色部分即为索引部分,按照大小是 16 字节一个索引。

压缩似乎是采用了自有的压缩算法(弱渣,认不出来什么算法_(:з」∠)_),总之用 ida 整个抽出来了,把没有的代码删掉,重建一下入口就能用了www

脚本文件还多了一步加密的操作,就是生成一个 key 简单异或一下。还原后的脚本:脚本

这样一来各种资源就全部拆出来了w

封包解析代码