【问题标题】:Read and write binary file in Python在 Python 中读写二进制文件
【发布时间】:2012-07-12 19:56:24
【问题描述】:

以下代码似乎无法正确读取/写入二进制形式。它应该读取一个二进制文件,按位异或数据并将其写回文件。没有任何语法错误,但数据没有验证,我已经通过另一个工具测试了源数据以确认 xor 键。

更新:根据 cmets 中的反馈,这很可能是由于我正在测试的系统的字节序。

xortools.py:

def four_byte_xor(buf, key):
    out = ''
    for i in range(0,len(buf)/4):
        c = struct.unpack("=I", buf[(i*4):(i*4)+4])[0]
        c ^= key
        out += struct.pack("=I", c)
    return out

调用 xortools.py:

from xortools import four_byte_xor
in_buf = open('infile.bin','rb').read()
out_buf = open('outfile.bin','wb')
out_buf.write(four_byte_xor(in_buf, 0x01010101))
out_buf.close()

看来我需要读取每个 answer 的字节数。当上面的函数操作多个字节时,上面的函数如何合并到下面的函数中?还是没关系?我需要使用struct吗?

with open("myfile", "rb") as f:
    byte = f.read(1)
    while byte:
        # Do stuff with byte.
        byte = f.read(1)

例如,以下文件有 4 个重复字节,01020304:

数据与密钥 01020304 进行异或运算,将原始字节归零:

这是对原始函数的尝试,在这种情况下,05010501 是不正确的结果:

【问题讨论】:

  • 表示没有任何语法错误。问题已更新。
  • 问题是four_byte_xor() 函数不会异或缓冲区的一部分,如果有的话,那不是四个字节的倍数(因此得名)。对于缓冲区中的任何模 4 字节,您想对 key 做什么,它显然希望它也正好是 4 个字节长?

标签: python


【解决方案1】:

这是一个相对简单的解决方案(经过测试):

import sys
from xortools import four_byte_xor
in_buf = open('infile.bin','rb').read()
orig_len = len(in_buf)
new_len = ((orig_len+3)//4)*4
if new_len > orig_len:
    in_buf += ''.join(['x\00']*(new_len-orig_len))
key = 0x01020304
if sys.byteorder == "little":  # adjust for endianess of processor
    key = struct.unpack(">I", struct.pack("<I", key))[0]
out_buf = four_byte_xor(in_buf, key)
f = open('outfile.bin','wb')
f.write(out_buf[:orig_len]) # only write bytes that were part of orig
f.close()

它所做的是将数据的长度填充到 4 字节的整数倍,与 4 字节的密钥进行异或,但随后只写出原始长度的数据。

这个问题有点棘手,因为 4 字节密钥的数据字节顺序取决于您的处理器,但总是先写入高字节,但字符串或字节数组的字节顺序总是写入低字节-byte first 如您的十六进制转储中所示。为了允许将密钥指定为十六进制整数,有必要添加代码以有条件地补偿不同的表示形式——即允许密钥的字节可以按照与十六进制转储中出现的字节相同的顺序指定。

【讨论】:

  • 我收到了几个试图运行此代码的语法错误。
  • @Astron:我不会感到惊讶,但怀疑它们都是微不足道的。稍后有机会我会修复它们。
  • @Astron:语法错误现在已修复,但我要等到以后才有机会测试它。
  • 一些额外的反馈:NameError: name 'out_buf' is not defined
  • @Astron:啊,我刚刚能够重现您使用 01020304 重复数据和 01020304 密钥获得的 05010501 输出。问题与字节序有关。将 inbuf.bin 的前 4 个字节视为 4 字节整数将在大端处理器上产生 0x04030201 的值,这将需要该值的整数键才能在 xor'ing 后生成 00000000 您期望的 -否则你会在 outfile.bin 中得到 05010105s。
【解决方案2】:

试试这个功能:

def four_byte_xor(buf, key):
    outl = []
    for i in range(0, len(buf), 4):
        chunk = buf[i:i+4]
        v = struct.unpack(b"=I", chunk)[0]
        v ^= key
        outl.append(struct.pack(b"=I", v))
    return b"".join(outl)

我不确定您实际上是否将输入占用了 4 个字节,但我没有尝试破译它。这假设您的输入可以被 4 整除。

编辑,基于新输入的新功能:

def four_byte_xor(buf, key):
    key = struct.pack(b">I", key)
    buf = bytearray(buf)
    for offset in range(0, len(buf), 4):
        for i, byte in enumerate(key):
            buf[offset + i] = chr(buf[offset + i] ^ ord(byte))
    return str(buf)

这可能会有所改进,但它确实提供了正确的输出。

【讨论】:

  • 用你的替换了 def 并尝试了原来的功能,但似乎我得到了类似的结果。
  • 您能否编辑您的问题以更准确地指定您的目标?也许是一些示例数据、输入和输出?
  • bytearray(buf) 是否可以接受二进制数据?我已经基于这个函数询问了一个新的question,并且我正在尝试为每次迭代提供新数据。也就是说,我删除了struc.pack() 部分以尝试提供二进制数据。在第一次迭代中工作,然后为额外的数据而死。
  • str 和 bytearray 都适用于二进制数据。它们是二进制数据字符串。 bytearray 是可变的,并且允许就地修改。它们是字节流。你的掩码是一个二进制数(超过8位),所以它必须转换成一个字节序列才能正确对齐异或操作。
猜你喜欢
  • 2012-01-26
  • 2018-07-26
  • 2016-06-14
  • 2021-06-03
  • 1970-01-01
  • 2014-01-07
  • 1970-01-01
  • 2019-04-20
相关资源
最近更新 更多