Welcome, guest | Sign In | My Account | Store | Cart

This recipe will display a hex dump of the disk specified on the command line. As the last two arguments, the program takes the first sector and last sector that should be displayed by this utility. The size of the sectors is stored in a variable created right after the imports executed by this script. The main feature of this recipe is its cross OS capabilities as demonstrated in get_data.

Python, 96 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import os
import sys

SECTOR_SIZE = 512

def main():
    try:
        if len(sys.argv) != 4:
            raise Exception('Not Enough Arguments')
        else:
            program(sys.argv[1], int(sys.argv[2]), int(sys.argv[3]))
    except Exception, error:
        print os.path.basename(sys.argv[0]), '<drive> <first> <last>'
        print 'Note:', error

def program(drive, first, last):
    if first > last:
        first, last = last, first
    data = get_data(drive, first, last)
    sectors = partition(data, SECTOR_SIZE)
    show_hex(first, last, sectors)

def get_data(drive, first, last):
    if os.name == 'posix':
        drive = file('/dev/' + drive)
    elif os.name == 'nt':
        drive = file(r'\\.\%s:' % drive)
    else:
        raise Exception('Do Not Know How To Access Drives')
    return read_all(drive, first, last - first + 1)

def read_all(drive, start_sector, sectors_to_read):
    start = start_sector * SECTOR_SIZE
    end = sectors_to_read * SECTOR_SIZE
    all_data = ''
    while start > 0:
        temp = drive.read(start)
        if not temp:
            temp = drive.read(start)
            if not temp:
                raise Exception('Cannot Read First Sector')
        start -= len(temp)
    assert start == 0
    while end > 0:
        temp = drive.read(end)
        if not temp:
            temp = drive.read(end)
            if not temp:
                if not all_data:
                    raise Exception('Cannot Find Requested Data')
                return all_data
        all_data += temp
        end -= len(temp)
    assert end == 0
    return all_data

def partition(string, size):
    if len(string) % size:
        parts = len(string) / size + 1
    else:
        parts = len(string) / size
    return [string[index*size:index*size+size] for index in range(parts)]

def show_hex(first, last, sectors):
    print '=' * 77
    for index in range(len(sectors)):
        print 'SECTOR', index + first
        print '=' * 77
        engine(sectors[index], index + first)
        print '=' * 77

def engine(string, sector):
    parts = partition(string, 16)
    rule = printable()
    for index in range(len(parts)):
        print ' | '.join([hex(index + sector * 32)[2:].upper().zfill(7)[-7:] + '0', \
                          pad_right(convert_hex(parts[index]), 47), \
                          convert_print(parts[index], rule)])

def printable():
    return ''.join([chr(byte) for byte in range(256) \
                    if len(repr(chr(byte))) == 3 or byte == ord('\\')])

def pad_right(string, length, padding=' '):
        return string + padding[0] * (length - len(string))

def convert_hex(string):
    return ' '.join([hex(ord(character))[2:].upper().zfill(2) \
                     for character in string])

def convert_print(string, rule):
    return ''.join([character in rule and character \
                    or '.' for character in string])

if __name__ == '__main__':
    main()

If you are wondering what is on a disk, then this recipe can be very helpful in getting you an answer.

4 comments

Josiah Carlson 15 years, 8 months ago  # | flag

While I likely won't be using your recipe specifically, knowing how to open the raw disk on Windows is terribly convenient.

Mike McClafferty 14 years, 5 months ago  # | flag

I had had an interest in looking at boot sectors, and this was a great place to start. I did have to change the file open mode to 'rb' to get things to work properly. And I later discovered how to open the physical drive (windows) using a filename such as:

r"\.\PhysicalDrive0"

in addition to example's r"\.\C:" form for opening a logical drive.

Emory Mullis 8 years, 7 months ago  # | flag

I am trying to get this code to work but it keeps giving me errors. I have python 2.7 and up installed but I do not know what version of python was used.

Can some one please let me know what version of python was used and or show me what to fix to get it to work in version 3.0 and up?

Thanks

Mara 8 years, 6 months ago  # | flag

From what I've seen, when running the drive.read(start), it seems almost easier if you're using it AS hex to put it as str(drive.read(start)).

there's occasions where a direct read will show up with "INTEGER" and such like that showing up in the output. As well, how would this accommodate for large size? as when end = 488397168 * 512 seems to throw errors. Or are you using something other than the total sectors on the drive to account for the end count?

Just having random issues trying this with python 2.7 which seemed to be mentioned in a prior update. At present I'm awaiting for the attempt at just the 488397168 as the end amount to complete. lol. This will take a while but once it finishes perhaps I can go back to getting more specifics on this for ya hahaha. Please note, I am running certain portions of this manually to try to play with the ways it functions (in this case, basically looking into the read_all function). So for me it's more like:

>>> drive = file("/dev/sda")
>>> end = 488397168
>>> temp = drive.read(end)

However it will error out with a C long error from using 488397168 * 512 :(

On a funnier note, just using the base total sectors (without the *512):

>>> end -= len(temp)
>>> end
249570952848L
>>> 488397168 * 512
250059350016L

lmao