【问题标题】:Trying to unpack/decode proprietary data file in Python尝试在 Python 中解压/解码专有数据文件
【发布时间】:2014-10-22 19:09:30
【问题描述】:

tl;dr - 在尝试对专有数据库文件进行逆向工程时,我发现写字板能够自动将一些数据解码为清晰的格式。我正在尝试在 python 中实现该解码。现在,即使是写字板巫毒也无法重复。


准备好脑筋急转弯了吗?

我正在尝试解决一个奇怪的问题。我有一个数据文件,它是科学仪器(Mettler DSC / STARe 软件)程序的数据库,我正在尝试从实验中获取样本信息。根据我在文件中的挖掘,它似乎包含有关运行实验的纯文本、未加密信息以及数据。这是一个 .t00 文件,大小超过 40 mb(它基本上存储了运行的所有数据),而且我对编码知之甚少(除了它看起来很随意。它不应该是一个文本文件)。我可以在写字板中打开这个文件,可以看到我正在寻找的信息(样品名称、时间戳、实验参数),周围是实验运行数据(正如预期的那样,这看起来像很多 gobbledygook,例如¶+ú@”‹ ø@ðßö@¨...)。看起来我基本上很幸运能够理解内容,我正在尝试复制它。

我可以使用基本文件处理程序将文件读​​入 python 并使用正则表达式来获取我想要的一些信息。 'r' vs 'rb' 似乎没有帮助。

def textOpenLines(filename,mode='rb'):
    with open(filename, mode) as content_file:
        return [line for line in content_file]

我可以获取该列表并在其中搜索相关字符串并从中获取示例名称。但是通过查看写字板中的文件,我发现样本名称被列出了两次,第二次它后面有日期戳(例如“二苯甲酰过氧化物 120 C 03.05.1994 14:24:30”)。在 python 中,我找不到这个字符串。我什至找不到时间戳本身。当我查看它应该发生的行时,我得到一堆随机字节。在记事本中打开看起来像 python 输出。

我怀疑这是编码问题。我已经尝试以 Unicode 格式读取文件,我尝试使用 sn-ps 行并将其读取,但我无法破解它。我难住了。

关于如何读入它以便正确解码的任何想法?写字板做对了(尽管现在尝试打开它,它看起来像记事本输出)。

谢谢!!

编辑:

  • 我不知道是谁更改了标题,但当然它“看起来像 Python/记事本中的随机字节”。主要是数据。
  • 它不是一个文本文件。我有点幸运地打开了写字板
  • 它没有损坏。 DSC 仪器程序可以很好地读取它。它只是专有的,所以我不知道它是如何滴答作响的。
  • 我尝试过使用“r”、“rb”和“U”标志。
  • 我尝试使用 utf8、16 和 32 的 codecs.open,但它给出了 UnicodeDecodeError: 'utf8' codec can't decode byte 0xdf in position 49: invalid continuation byte。我不认为它有 BOM,因为我不认为它是为了人类可读的。
  • 前 32 个字节 (f.read(32)) 读取

    '\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x04\x10\x00\x00'

    我对 BOM 了解不多,但通过阅读 Wiki 页面,它看起来不像任何有效的 UTF 标记。

文件的开头,当第一次在写字板中自动解码时,如下所示: 121 22二苯甲酰过氧化物 120 C 03.05.1994 14:24:30 1 0 4096 ESTimeAI–@£®@nôÂ@49Õ@kÉå@FÞò@`sþ@N5A2A®"A"A—¥A¿ÝA¡zA"ÓAÿãAÐÅA䤜AÑÌAŸäA ÆAE–AFNATöAÐ|AõAº^A(ÄAèAýqA¹AÖûAº8A¬uAK«AgÜAüAÞAo4A>N AfAB

文件的开头在记事本、Python 和现在的写字板中打开时,如下所示: (空字节 x00...)](x00...)eß(x00...)NvN(x00)... 等

【问题讨论】:

  • 在尝试解码未知文件时,我做的第一件事是hexdump...嗯,实际上是在运行file 之后的第二个。你试过吗?也许它是一种众所周知的“隐藏”格式?
  • 您确定该文件实际上是一个文本文件吗?如果它是来自某个程序的数据库,它可能不会被读取为纯文本。
  • 快速谷歌搜索表明应该有一个人类可读的.h01文件(我想是csv),而.t00文件是某种专有格式。
  • 如果它不是文本文件,您可能应该使用 'rb' 标志打开
  • 您的文件似乎以某种方式损坏。我希望你有一个备份。

标签: python text file-io io


【解决方案1】:

它是 FutureMe。

您可能对写字板很幸运。我不确定,因为该数据早已不复存在,但我猜写字板做出了勇敢的努力来尝试将文件解码为 UTF-8(或者可能是 UTF-16 或 CP1252)。 似乎起作用的原因是,在大多数二进制协议中,字符串可能被编码为 UTF-8,因此对于 ASCII 字符集,它们在转储中看起来是一样的。但是,其他所有内容都将进行二进制编码。

您对 open(fn, 'rb') 的想法是正确的,但您应该只阅读整个 blob,而不是 readlines,后者试图拆分 \n。由于 db 文件不是 \n 分隔的,因此它不起作用。

更好的方法是字节直方图,并尝试推断字段/行分隔符是什么,如果甚至存在的话。寻找TLV (type-length-value) encoded fields。由于您知道样本名称列表,因此您可以获取起始字符串列表,使用它来查找 blob 中的切片点,并确定字段大小的规则程度。

另外,购买比特币。

【讨论】:

    【解决方案2】:

    您的文件不是由 ascii 字符组成,而是被打开它的应用程序解释为 ascii 字符。如果您在写字板中打开 .jpg 图像,也会发生同样的事情 - 您会得到一堆二进制和一些可打印且人眼可识别的 ascii 字符。

    例如,这就是您无法对时间戳进行纯文本搜索的原因。

    这是一个演示问题的代码示例。在您的二进制文件中,您有以下字节:

    \x44\x69\x62\x65\x6e\x7a\x6f\x79\x6c\x70\x65\x72\x6f\x78\x69\x64\x20\x31\
    x32\x30\x20\x43\x20\x30\x33\x2e\x30\x35\x2e\x31\x39\x39\x34\x20\x31\x34\x3a\x32\
    x34\x3a\x33\x30
    

    如果您要在写字板等文本编辑器中打开它,它会呈现以下内容:

    Dibenzoylperoxid 120 C 03.05.1994 14:24:30
    

    这是 Python 中的一段代码 sn-p:

    >>> c='\x44\x69\x62\x65\x6e\x7a\x6f\x79\x6c\x70\x65\x72\x6f\x78\x69\x64\x20\x31\
    x32\x30\x20\x43\x20\x30\x33\x2e\x30\x35\x2e\x31\x39\x39\x34\x20\x31\x34\x3a\x32\
    x34\x3a\x33\x30'
    >>> print c
    Dibenzoylperoxid 120 C 03.05.1994 14:24:30
    

    这些字节是十六进制格式,这就是为什么你不能用纯文本搜索它的原因。

    这是因为二进制文件遵循一个非常特殊的结构(协议、规范),因此读取它的程序可以正确解析它。如果以 jpeg 图像为例,您会发现图像的第一个字节和最后一个字节总是相同的(取决于使用的格式)-FF D8 将是 jpeg 的前两个字节,@987654327 @ 将是 jpeg 的最后两个字节来识别它。图像编辑程序现在将知道开始将此二进制数据解析为 jpeg,并且它将“遍历”文件内的结构以渲染图像。 Here 是一个资源链接,可帮助您根据“签名”或“标题”识别文件 - 文件的前两个字节 10 00 不会出现在该数据库中,因此您可能正在处理专有格式所以你将无法很容易地在网上找到规格。这就是逆向工程派上用场的地方。

    我建议您在十六进制编辑器中打开您的文件 - 它会为您提供十六进制输出以及 ascii 输出,以便您可以开始分析文件格式。我个人使用 here 找到的 Hackman Hexeditor(它是免费的,并且有很多功能)。

    但现在 - 为您提供一些有用的信息,用于在文件中搜索您感兴趣的数据,这是一种在开始搜索之前将搜索查询转换为二进制的快速方法。

    import struct
    
    #binary_data = open("your_binary_file.bin","rb").read()
    
    #your binary data would show up as a big string like this one when you .read()
    binary_data = '\x44\x69\x62\x65\x6e\x7a\x6f\x79\x6c\x70\x65\x72\x6f\x78\x69\x64\x20\x31\
    x32\x30\x20\x43\x20\x30\x33\x2e\x30\x35\x2e\x31\x39\x39\x34\x20\x31\x34\x3a\x32\
    x34\x3a\x33\x30'
    
    def search(text):
    
        #convert the text to binary first
        s = ""
    
        for c in text:
            s+=struct.pack("b", ord(c))
    
        results = binary_data.find(s)
        if results == -1:
            print "no results found"
        else:
            print "the string [%s] is found at position %s in the binary data"%(text, results)
    
    search("Dibenzoylperoxid")
    
    search("03.05.1994")
    

    上面脚本的结果是:

    the string [Dibenzoylperoxid] is found at position 0 in the binary data
    the string [03.05.1994] is found at position 25 in the binary data 
    

    这应该可以帮助您入门。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-29
      • 1970-01-01
      • 2011-06-22
      • 2011-03-27
      • 2019-06-10
      • 1970-01-01
      • 1970-01-01
      • 2014-07-19
      相关资源
      最近更新 更多