无法在 Python 中重现有效的 C 按位​​编码函数

Can't reproduce working C bitwise encoding function in Python

我正在对一种专有网络协议进行逆向工程,该协议会在启动时生成一个(静态)一次性密码本,然后将其用于 encode/decode 每个数据包 sends/receives。它在一系列复杂的 XOR、移位和乘法中使用一次一密。

我用 IDA 遍历了程序中的解码函数后生成了以下 C 代码。这个功能encodes/decodes 数据完美:

void encodeData(char *buf)
{
    int i;
    size_t bufLen = *(unsigned short *)buf;
    unsigned long entropy = *((unsigned long *)buf + 2);
    int xorKey = 9 * (entropy ^ ((entropy ^ 0x3D0000) >> 16));
    unsigned short baseByteTableIndex = (60205 * (xorKey ^ (xorKey >> 4)) ^ (668265261 * (xorKey ^ (xorKey >> 4)) >> 15)) & 0x7FFF;

    //Skip first 24 bytes, as that is the header
    for (i = 24; i <= (signed int)bufLen; i++)
        buf[i] ^= byteTable[((unsigned short)i + baseByteTableIndex) & 2047];
}

现在我想尝试为这个协议制作一个 Peach 模糊器。由于在进行模糊测试之前,我需要自定义 Python 修复来执行 encoding/decoding,因此我需要将此 C 代码移植到 Python.

我已经实现了以下 Python 函数,但在解码接收到的数据包时没有任何运气。

def encodeData(buf):
    newBuf = bytearray(buf)
    bufLen = unpack('H', buf[:2])
    entropy = unpack('I', buf[2:6])
    xorKey = 9 * (entropy[0] ^ ((entropy[0] ^ 0x3D0000) >> 16))
    baseByteTableIndex = (60205 * (xorKey ^ (xorKey >> 4)) ^ (668265261 * (xorKey ^ (xorKey >> 4)) >> 15)) & 0x7FFF;
    #Skip first 24 bytes, since that is header data
    for i in range(24,bufLen[0]):
        newBuf[i] = xorPad[(i + baseByteTableIndex) & 2047]
    return str(newBuf)

我尝试过使用和不使用 array()pack()/unpack() 各种变量来强制它们成为按位运算的正确大小,但我必须遗漏了一些东西,因为我无法让 Python 代码像 C 代码那样工作。有谁知道我错过了什么?

如果它能帮助你在本地尝试这个,这里是一次性一密生成函数:

def buildXorPad():
    global xorPad
    xorKey = array('H', [0xACE1])
    for i in range(0, 2048):
        xorKey[0] = -(xorKey[0] & 1) & 0xB400 ^ (xorKey[0] >> 1)
        xorPad = xorPad + pack('B',xorKey[0] & 0xFF)

这是十六进制编码的原始(编码)和解码数据包。

原文:20000108fcf3d71d98590000010000000000000000000000a992e0ee2525a5e5

解码:20000108fcf3d71d98590000010000000000000000000000ae91e1ee25252525

解决方案

原来我的问题与C和Python类型的区别没有太大关系,而是一些简单的编程错误。

def encodeData(buf):
    newBuf = bytearray(buf)
    bufLen = unpack('H', buf[:2])
    entropy = unpack('I', buf[8:12])
    xorKey = 9 * (entropy[0] ^ ((entropy[0] ^ 0x3D0000) >> 16))
    baseByteTableIndex = (60205 * (xorKey ^ (xorKey >> 4)) ^ (668265261 * (xorKey ^ (xorKey >> 4)) >> 15)) & 0x7FFF;
    #Skip first 24 bytes, since that is header data
    for i in range(24,bufLen[0]):
        padIndex = (i + baseByteTableIndex) & 2047
        newBuf[i] ^= unpack('B',xorPad[padIndex])[0]
    return str(newBuf)

感谢大家的帮助!

这一行C:

unsigned long entropy = *((unsigned long *)buf + 2);

应该翻译成

entropy = unpack('I', buf[8:12])

因为 buf 在将 2 添加到地址之前先转换为无符号长整型,这会向其添加 2 个无符号长整型的大小,而不是 2 个字节(假设无符号长整型的大小为 4 个字节) .

还有:

newBuf[i] = xorPad[(i + baseByteTableIndex) & 2047]

应该是

newBuf[i] ^= xorPad[(i + baseByteTableIndex) & 2047]

匹配C,否则输出实际上不是基于缓冲区的内容。

Python 整数不会溢出 - 当它们超过 sys.maxint(或 -sys.maxint-1)时,它们会自动提升到任意精度。

>>> sys.maxint
9223372036854775807
>>> sys.maxint + 1
9223372036854775808L

使用 array and/or unpack 似乎没有什么不同(如您所见)

>>> array('H', [1])[0] + sys.maxint
9223372036854775808L
>>> unpack('H', '\x01\x00')[0] + sys.maxint
9223372036854775808L

要截断您的数字,您必须在每次增加变量大小时通过手动与适当的位掩码进行 ANDing 来模拟溢出。