forked from Synacktiv-contrib/stuffz
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dump_pocketbook_update.py
137 lines (106 loc) · 3.94 KB
/
dump_pocketbook_update.py
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
"""
PocketBook SWUPDATE.BIN parser script
Copyright 2018 Synacktiv
Usage: compile the KSY file with kaitai-struct-compiler and then use
this script to parse / dump the pocketbook firmware update file
Licensed under the "THE BEER-WARE LICENSE" (Revision 42):
yourname wrote this file. As long as you retain this notice you
can do whatever you want with this stuff. If we meet some day, and you think
this stuff is worth it, you can buy me a beer or coffee in return
"""
import argparse
import binascii
from hashlib import md5, sha256
import swupdate
PREFIX = "./"
def show_info(fname):
"""
Dump the informations contained in the structure
"""
mupdate = swupdate.Swupdate.from_file(fname)
print("Update magic: %s" % mupdate.header.magic)
print("Update Model: %s" % mupdate.header.model)
print("Update revision: %s" % mupdate.header.revision)
print("Update md5 hash: %s" % binascii.hexlify(mupdate.header.md5_sum))
print("Update signature: %s" % binascii.hexlify(mupdate.header.signature))
print("Partition table:")
for part in mupdate.header.fw_partitions:
print("\toffset 0x%x size 0x%x type %s " % (
part.offset,
part.size,
part.part_type,
))
print("Checking hashes")
check_md5(mupdate, fname)
def check_md5(update, fname):
"""
Compute the checksum of the updates
It creates a MD5 hash of the MD5 hashes of the partitions
"""
mfile = open(fname, "rb")
hashes = []
for part in update.header.fw_partitions:
mfile.seek(1024 + part.offset)
data = mfile.read(part.size)
hashes.append(md5(data).digest())
mfile.close()
final_hash = md5()
for tmp in hashes[:-1]:
final_hash.update(tmp)
print("Header hash: %s" % (binascii.hexlify(update.header.md5_sum)))
print("Calc hash: %s" % (final_hash.hexdigest()))
def get_extension_from_type(part_type):
"""
Outputs a sensible file extension given a partition type
"""
extensions = {
swupdate.Swupdate.PartTypeEnum.ebrmain_img: ".ebrmain",
swupdate.Swupdate.PartTypeEnum.a_img: ".aimg",
swupdate.Swupdate.PartTypeEnum.bmp_image: ".bmp",
swupdate.Swupdate.PartTypeEnum.dragon_tar: "_dragon.tar",
swupdate.Swupdate.PartTypeEnum.elf_megadog_img: "_megadog.elf",
swupdate.Swupdate.PartTypeEnum.rootfs_img: ".rootfs",
swupdate.Swupdate.PartTypeEnum.swupdate_tar_gz: "_swupdate.tar.gz",
swupdate.Swupdate.PartTypeEnum.updatefs_cramfs: ".cramfs",
swupdate.Swupdate.PartTypeEnum.uboot_loader: ".uboot",
swupdate.Swupdate.PartTypeEnum.kernel_img: ".kernel",
}
try:
return extensions[part_type]
except KeyError:
return ".bin"
def dump(fname):
"""
Dump the sections
"""
mupdate = swupdate.Swupdate.from_file(fname)
mfile = open(fname, "rb")
for part in mupdate.header.fw_partitions:
if part.part_type != swupdate.Swupdate.PartTypeEnum.empty:
print("Dumping section of type %s size 0x%x offset %x" % (
part.part_type,
part.size,
part.offset))
mfile.seek(0)
mfile.seek(part.offset + 1024)
data = mfile.read(part.size + 8192)
mhash = sha256(data).hexdigest()
out = PREFIX + mhash
out += get_extension_from_type(part.part_type)
with open(out, "wb") as out_file:
out_file.write(data)
def main():
"""
Argument parsing and dispatching
"""
actions = {
"dump": dump,
"info": show_info
}
parser = argparse.ArgumentParser("Test script for swupdate format parsing")
parser.add_argument("action", choices=actions.keys())
parser.add_argument("update", help="the update file")
args = parser.parse_args()
actions[args.action](args.update)
if __name__ == "__main__":
main()