无法在Python

时间:2015-05-22 04:48:19

标签: python security python-2.7 encoding reverse-engineering

我反向设计一种专有网络协议,该协议在启动时生成(静态)一次性缓冲区,然后使用它来编码/解码它发送/接收的每个数据包。它在一系列复杂的XOR,移位和乘法中使用一次性焊盘。

在使用IDA遍历程序中的解码功能后,我生成了以下C代码。此功能可以完美地对数据进行编码/解码:

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修正来进行编码/解码,因此我需要将此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(),以强制它们成为按位操作的正确大小,但我必须是遗漏了一些东西,因为我无法像C代码一样使用Python代码。有谁知道我错过了什么?

如果它可以帮助你在本地尝试这个,这里是一次性垫生成功能:

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)

感谢大家的帮助!

2 个答案:

答案 0 :(得分:2)

这一行C:

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

应转换为

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

因为buf在向地址添加2之前首先强制转换为无符号长整数,这会向其添加2个无符号长整数,而不是2个字节(假设无符号长整数为4个字节)。 / p>

此外:

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

应该是

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

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

答案 1 :(得分:1)

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

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

使用array和/或unpack似乎没有任何区别(正如您所发现的那样)

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

要截断您的数字,只要您增加变量的大小,就必须使用适当的位掩码手动进行AND运算来模拟溢出。