Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to unpack/decode proprietary data file in Python

tl;dr - While trying to reverse engineer a proprietary database file, I found that Wordpad was able to automagically decode some of the data into a legible format. I'm trying to implement that decoding in python. Now, even the Wordpad voodoo is not repeatable.


Ready for a brain teaser?

I'm trying to crack a bit of a strange problem. I have a data file, it is the database of a program for a scientific instrument (Mettler DSC / STARe software), and I'm trying to grab sample information from experiments. From my digging around in the file, it appears to consist of plaintext, unencrypted information about the experiments run, along with data. It's a .t00 file, over 40 mb in size (it stores essentially all the data of the runs), and I know very little about the encoding (other than it's seemingly arbitrary. It's not meant to be a text file). I can open this file in Wordpad and can see the information I'm looking for (sample names, timestamp, experiment parameters), surrounded by experimental run data (as expected, this looks like lots of gobbledygook, e.g. ¶+ú@”‹ø@ðßö@¨...). It seems like I basically got lucky with it being able to make some sense of the contents, and I'm trying to replicate that.

I can read the file into python with a basic file handler and use regex to get some of the pieces of info I want. 'r' vs 'rb' doesn't seem to help.

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

I'm able to take that list and search it for relevant strings and get the sample name from it. BUT from looking at the file in Wordpad, I found that the sample name is listed twice, the second time it has the datestamp following it (e.g. 'Dibenzoylperoxid 120 C 03.05.1994 14:24:30'). In python, I can't find this string. I can't find even the timestamp by itself. When I look at the line where it is supposed to occur, I get a bunch of random bytes. Opening in Notepad looks like the python output.

I suspect it's an encoding issue. I've tried reading the file in as Unicode, I've tried taking snippets of lines and reading those in, but I can't crack it. I'm stumped.

Any thoughts on how to read this in so that it decodes right? Wordpad got it right (though now subsequently trying to open it, it looks like the Notepad output).

Thanks!!

Edit:

  • I don't know who changed the title, but of course it 'looks like random bytes in Python/Notepad'. It's mostly data.
  • It's not meant to be a text file. I sorta got lucky with the Wordpad opening
  • It's not corrupted. The DSC instrument program reads it just fine. It's just proprietary so I have no idea how it ticks.
  • I've tried using 'r', 'rb', and 'U' flags.
  • I've tried codecs.open using utf8, 16 and 32, but it gives UnicodeDecodeError: 'utf8' codec can't decode byte 0xdf in position 49: invalid continuation byte. I don't think it has a BOM, because I don't think it's meant to be human readable.
  • First 32 bytes (f.read(32)) reads

    '\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'

    I don't know much about BOMs, but from reading the Wiki page, that doesn't look like any of the valid UTF markings.

The start of the file, when first automagically decoded in Wordpad, looks like this: 121 22Dibenzoylperoxid 120 C 03.05.1994 14:24:30 1 0 4096 ESTimeAI–@£®@nôÂ@49Õ@kÉå@FÞò@`sþ@N5A2­A®"A"A—¥A¿ÝA¡zA"ÓAÿãAÐÅAäHA‚œAÑÌAŸäA¤ÆAE–AFNATöAÐ|AõAº^A(ÄAèAýqA¹AÖûAº8A¬uAK«AgÜAüAÞAo4A>N AfAB

The start of the file, when opened in Notepad, Python, and now Wordpad, looks like this: (empty bytes x00...)](x00...)eß(x00...)NvN(x00)... etc

like image 355
DeusXMachina Avatar asked Jul 19 '26 14:07

DeusXMachina


1 Answers

Your file is not comprised of ascii characters but is being interpreted as such by applications that open it. The same thing would happen if you opened up a .jpg image in wordpad - you would get a bunch of binary and some ascii characters that are printable and recognizible to the human eye.

This is the reason why you can't do a plain-text search for your timestamp, for example.

Here is an example in code to demonstrate the issue. In your binary file you have the following bytes:

\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

If you were to open this inside of a text editor like wordpad it would render the following:

Dibenzoylperoxid 120 C 03.05.1994 14:24:30

Here is a code snippet in Python:

>>> 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

These bytes are in hexadecimal format which is why you can't search it with plaintext.

The reason for this is because the binary file is following a very particular structure (protocol, specification) so that the program that reads it can parse it correctly. If you take a jpeg image as an example you will find that the first bytes and the last bytes of the image are always the same (depending on the format used) - FF D8 will be the first two bytes of a jpeg and FF D9 will be the last two bytes of a jpeg to identify it as such. An image editing program will now know to start parsing this binary data as a jpeg and it will "walk" the structures inside the file to render the image. Here is a link to a resource that helps you identify files based on "signatures" or "headers" - the first two bytes of your file 10 00 do not show up in that database so you are likely dealing with a proprietary format so you won't be able to find the specs online very easily. This is where reverse engineering comes in handy.

I would recommend you open your file up in a hexeditor - it will give you both the hexadecimal output as well as the ascii output so that you can start to analyze the file format. I personally use the Hackman Hexeditor found here (it's free and has a lot of features).

But for now - to give you something useful to use in searching the file for data that you are interested in here is a quick method to covert your search queries to binary before the start the search.

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 results of the above script are:

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 

This should get you started.

like image 189
Max Worg Avatar answered Jul 22 '26 04:07

Max Worg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!