【问题标题】:How to find byte sequence in file?如何在文件中查找字节序列?
【发布时间】:2018-08-30 10:01:18
【问题描述】:

我有一个 二进制 文件,我需要在其中更改某些位。

该位的字节地址是相对于某个字节序列(某个 ASCII 字符串)的:

content = array('B')
with open(filename, mode="r+b") as file:
    content.fromfile(file, os.fstat(file.fileno()).st_size)
    abc = [ord(letter) for letter in "ABC"]
    i = content.index(abc) // ValueError: array.index(x): x not in list
    content[i + 0x16] |= 1
    content.tofile(file)

但是我必须承认我的耻辱,在谷歌搜索之后,我找不到获取“ABC”字符串索引的方法......

当然,我可以编写一个使用循环执行此操作的函数,但我不敢相信没有单行(好吧,甚至两个...)可以完成它。

怎么做?

【问题讨论】:

  • 您的“尽可能高效”的需求没有得到很好的约束。如果速度是唯一的问题,你为什么还要使用 Python 而不是 C 或汇编?
  • @timgeb,我删除了该约束。这不是这里的主要问题。但是,如果您坚持要一个答案,那么它是一个构建脚本,它必须保持一个脚本,而不是编译代码,并且还有许多其他文件需要更改,同时确保构建不会变得太慢。基本上我只是想避免使用不可变序列,我想就地更改数据。
  • 不用担心。 “尽可能高效”的问题在于,您可能会得到非pythonic 的答案,这会牺牲很多纳秒的可读性。相反,请尝试以更严格的方式描述所需的效率水平。
  • "ABC".encode(hex) 的预期用途是什么?它是一种 Python 2 方法,在 2012 年被称为 not nice ... 无论如何:因为它会将 ABC 转换为 414243,你是否确定文本 414243 应该出现在里面的某个地方你的二进制文件?还是我在这里误解了它的目的?
  • @usr2564301,是的,这就是问题所在,414243 不是作为字符串出现,而是作为字节序列出现,这意味着在文件的某个地方有一个[0x41, 0x42, 0x43] 的序列,我不知道如何:1:从字符串生成该序列,以及 2:如何在文件内容中定位该字节序列。我可以用abc = [ord(letter) for letter in "ABC"] 解决问题#1,但是#2 仍然失败。

标签: python


【解决方案1】:

不确定这是否是最 Pythonic 的方式,但这是可行的。在这个文件中

$ cat so.bin    
���ABC̻�X��w
$ hexdump so.bin
0000000 eeff 41dd 4342 bbcc 58aa 8899 0a77     
000000e

编辑:新的解决方案从这里开始。

import string

char_ints = [ord(c) for c in string.ascii_letters]

with open("so.out.bin", "wb") as fo:
    with open("so.bin", "rb") as fi:

        # Read bytes but only keep letters.
        chars = []
        for b in fi.read():
            if b in char_ints:
                chars.append(chr(b))
            else:
                chars.append(" ")

        # Search for 'ABC' in the read letters.
        pos = "".join(chars).index("ABC")

        # We now know the position of the intersting byte.
        pos_x = pos + len("ABC") + 3 # known offset

        # Now copy all bytes from the input to the output, ...
        fi.seek(0)
        i = 0
        for b in fi.read():
            # ... but replace the intersting byte.
            if i == pos_x:
                fo.write(b"Y")
            else:
                fo.write(bytes([b]))
            i = i + 1

编辑:新的解决方案到此结束。

我想在ABC 之后获得X 四个位置。一点点状态保持定位ABC的位置,跳过偏移量,打印感兴趣的字节。

foundA = False
foundB = False
foundC = False
found = False
offsetAfterC = 3
lengthAfterC = 1

with open("so.bin", "rb") as f:
    pos = 0
    for b in f.read():
        pos = pos + 1
        if not found:
            if b == 0x41:
                foundA = True
            elif foundA and b == 0x42:
                foundB = True
            elif foundA and foundB and b == 0x43:
                foundC = True
            else:
                foundA, foundB, foundC = False, False, False

        if foundA and foundB and foundC:
            found = True
            break

    f.seek(0)
    i = 0
    while i < pos + offsetAfterC:
        b = f.read(1)
        i = i + 1
    while i < pos + offsetAfterC + lengthAfterC:
        b = f.read(1)
        print(hex(int.from_bytes(b, byteorder="big")))
        i = i + 1

输出:

0x58

【讨论】:

  • 谢谢 :-) 但我希望更多的是一种单行代码...我觉得这有点矫枉过正,而且有一个更简单的解决方案。
  • @Tar 我添加了一个新的解决方案。它不是单线,但更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-09
  • 2022-01-02
相关资源
最近更新 更多