ActiveState Code

Recipe 475157: Disk Dumper


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

Discussion

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

Comments

  1. 1. At 7:58 p.m. on 22 mar 2006, Josiah Carlson said:

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

  2. 2. At 8:53 p.m. on 5 jul 2007, Mike McClafferty said:

    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.

Sign in to comment