使用已知明文从 pkware zip 部分正确解码字符串

逆向工程 视窗 解密 解压
2021-06-28 02:50:02

我有一个受密码保护的 zip 文件,其中每个文件的路径和文件名都使用 PKWARE 加密进行加密。

密码是已知且正确的,加密算法也是如此。

我还有示例明文和一个可以正确解密文件的应用程序(32 位闭源、优化、无调试符号)。

下面是部分解密文件名的示例,以及一些完全解密的文件名。 部分正确解密的文件名

以下是由闭源程序生成的完全解密文件的示例。

完全正确解密的文件

如您所见,对于大多数文件,文件名都可以正确解密。然而,对于一小部分,我得到了部分解码的文件名,其余的都是 mojibake。

所以我的问题是,为什么会发生这种情况,我应该怎么做才能纠正它?我很困惑,因为如果我的解密实现是错误的,我期待 100% 的垃圾。部分正确的输出并不是我所期望的。

注意每个文件名都是独立解密的,也就是说下一个文件的解密不依赖于前一个文件的解密。

解密实现或多或少与此处描述的相同

static uint32_t keys[3];

// CRC32_table is from zlib
uint32_t compute_crc32(uint32_t crc, char c) {
    return CRC32_table[(crc ^ c) & 0xff] ^ (crc >> 8);
}

void init_keys(const std::string& password) {
    keys = { 0x12345678, 0x23456789, 0x34567890 };
    for (size_t i = 0; i < password.size(); ++i)
        key_update(keys, password[i]);
}

void update_keys(char c) {
    keys[0] = compute_crc32(keys[0], c);
    keys[1] = keys[1] + (keys[0] & 0xff);
    keys[1] = (keys[1] * 0x8088405) + 1;
    keys[2] = compute_crc32(keys[2], keys[1] >> 24);
}

char decrypt_byte() {
    uint16_t temp = (keys[2] & 0xffff) | 2;
    return char(((temp * (temp ^ 1))>> 8) & 0xff);
}

std::string decrypt(const std::string& password,
                    const std::string& input) {
    init_keys(password);
    auto ret = std::string(input.size(), '\0');
    for (int i = 0; i < input.size(); ++i) {
        char c = input[i] ^ decrypt_byte();
        update_keys(c);
        ret[i] = c;
    }
    return ret;
}

请注意,文件仍能正确解密和解压缩,只是文件名被打乱了。

1个回答

据我所知标准的ZIP格式确实加密文件名,但只有文件的内容。因此,该软件似乎实现了自定义 ZIP 扩展名,用于基于相同算法加密文件名。看起来你已经很接近了,所以现在你只需要逐步执行原始二进制文件中的代码,你的算法处理相同的数据,看看哪里出现了差异。