我希望用Python和scapy解析一些数据。因此,我必须分析单个位。但是目前我有一些包含一些有效载荷的UDP数据包,例如:
bytes = b'\x18\x00\x03\x61\xFF\xFF\x00\x05\x42\xFF\xFF\xFF\xFF'
有没有一种优雅的方式将字节转换,以便我可以像这样访问单个位:
bytes_as_bits = convert(bytes)
bit_at_index_42 = bytes_as_bits[42]
我希望用Python和scapy解析一些数据。因此,我必须分析单个位。但是目前我有一些包含一些有效载荷的UDP数据包,例如:
bytes = b'\x18\x00\x03\x61\xFF\xFF\x00\x05\x42\xFF\xFF\xFF\xFF'
有没有一种优雅的方式将字节转换,以便我可以像这样访问单个位:
bytes_as_bits = convert(bytes)
bit_at_index_42 = bytes_as_bits[42]
那会起作用:
def access_bit(data, num):
base = int(num // 8)
shift = int(num % 8)
return (data[base] >> shift) & 0x1
如果你想创建一个二进制数组,可以像这样使用:
[access_bit(data,i) for i in range(len(data)*8)]
bytes = '\xf0\x0f'
bytes_as_bits = ''.join(format(ord(byte), '08b') for byte in bytes)
这应该输出:'1111000000001111'
如果你想要最低有效位(LSB)在前,你可以翻转format()的输出,所以:
bytes = '\xf0\x0f'
bytes_as_bits = ''.join(format(ord(byte), '08b')[::-1] for byte in bytes)
这应该输出:'0000111111110000'
现在你想使用 b'\xf0\x0f'
而不是 '\xf0\x0f'
。对于 Python2,代码的工作方式相同,但对于 Python3,您必须摆脱 ord(),因此:
bytes = b'\xf0\x0f'
bytes_as_bits = ''.join(format(byte, '08b') for byte in bytes)
反转字符串同样是一个问题。
bits
类型,但你可以这样做>>> bin(int.from_bytes(b"hello world", byteorder="big")).lstrip('0b')
'110100001100101011011000110110001101111001000000111011101101111011100100110110001100100'
.lstrip('0b')
方法可以移除bin()
函数输出中的任何前导'0b'
字符。>>> n=17
>>> [(n & (1<<x))>>x for x in [7,6,5,4,3,2,1,0]]
[0, 0, 0, 1, 0, 0, 0, 1]
>>> bytes = b'\x18\x00\x03\x61\xFF\xFF\x00\x05\x42\xFF\xFF\xFF\xFF'
>>> convert = lambda x: f"{int.from_bytes(x, 'big'):b}"
>>> bytes_as_bits = convert(bytes)
>>> bytes_as_bits[42]
'1'
>>> _
'big'
是要使用的字节顺序。Python官方文档描述如下:
byteorder参数确定用于表示整数的字节顺序。 如果byteorder为“big”,则最高有效字节位于字节数组的开头。如果byteorder为“little”,则最高有效字节位于字节数组的末尾。要请求主机系统的本机字节顺序,请使用sys.byteorder作为字节顺序值。
byteorder
,默认为“big”。
注意,我不是指字节内的位打包。
def access_bit(b: bytearray, n: int, byteorder: str = "big") -> int:
"""
Returns the boolean value of the nth bit (n) from the byte array (b).
The byteorder argument accepts the literal strings ['little', 'big'] and
refers to the byte order endianness
"""
base = int(n // 8)
shift = int(n % 8)
if byteorder == "big":
return (b[-base - 1] >> shift) & 0x1
elif byteorder == "little":
return (b[base] >> shift) & 0x1
else:
raise KeyError("byteorder only recognises 'big' or 'little'")
access_bit(b, 0)
返回假设为 大端序 的 最低有效位 所在的 最低有效字节
access_bit(b, 7)
返回假设为 大端序 的 最高有效位 所在的 最低有效字节
access_bit(b, 0, 'little')
返回指定为 小端序 的 最低有效位 所在的 最低有效字节
access_bit(b, 7)
返回假设为 小端序 的 最高有效位 所在的 最低有效字节
如果指定的索引 n
超出了 bytearray 的范围,则会导致错误(例如,access_bit(b'\x05\x01', 16)
将导致错误,因为 bytearray 的最大索引为 15)
8
会是什么呢?第二个字节的最高有效位?还是最低有效位? - Eugene Sh.''.join(f'{byte:b}' for byte in bytes)
这样的东西吗? - vaultah