无法在 Python 中重现工作的 C 位编码函数
Posted
技术标签:
【中文标题】无法在 Python 中重现工作的 C 位编码函数【英文标题】:Can't reproduce working C bitwise encoding function in Python 【发布时间】:2015-08-03 23:53:53 【问题描述】:我正在对专有网络协议进行逆向工程,该协议会在启动时生成(静态)一次性垫,然后使用它来编码/解码它发送/接收的每个数据包。它在一系列复杂的 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()
以强制它们成为按位运算的正确大小,但我一定遗漏了一些东西,因为我不能让 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)
感谢大家的帮助!
【参考方案1】:这行C:
unsigned long entropy = *((unsigned long *)buf + 2);
应该翻译成
entropy = unpack('I', buf[8:12])
因为buf
在向地址添加 2 之前首先转换为 unsigned long,这会将 2 个 unsigned long 的大小添加到它,而不是 2 个字节(假设 unsigned long 的大小为 4 个字节)。
还有:
newBuf[i] = xorPad[(i + baseByteTableIndex) & 2047]
应该是
newBuf[i] ^= xorPad[(i + baseByteTableIndex) & 2047]
匹配 C,否则输出实际上不是基于缓冲区的内容。
【讨论】:
好的,你在这里找到了一些东西。我不敢相信我错过了我为熵值抓取了错误的数据包部分!我什至有一个 010 编辑器模板,它显示了它的位置,但显然忽略了它。问题是它仍然不起作用。这可能是字节序问题,我会在早上尝试解决这个问题。 谢谢,成功了!我想这只是一些简单的编程错误,而不是编码/类型问题。我需要更加小心!我在主帖中贴出了最终的编码函数。【参考方案2】: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
要截断您的数字,您必须在增加变量大小时通过手动与适当的位掩码进行与运算来模拟溢出。
【讨论】:
异或是指与吗?我也尝试过使用位掩码进行“与”运算,但我会再试一次,并确保抓住所有需要掩码的情况。 @k0ss,是的,对不起,我会修复帖子 赞成,因为虽然我已经尝试过了,但对于需要人为限制变量大小的人来说,这是一个很好的建议。以上是关于无法在 Python 中重现工作的 C 位编码函数的主要内容,如果未能解决你的问题,请参考以下文章
在 Julia 中从 R 中重现 `expand.grid` 函数