-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathdell_inspiron_1100_unpacker.py
executable file
·121 lines (115 loc) · 3.29 KB
/
dell_inspiron_1100_unpacker.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
#!/usr/bin/env python3
# Dell/Phoenix ROM BIOS PLUS unpacker
# 2012-09-12 version 0.1
# 2012-10-10 version 0.2 added support for older BIOSes with 16-bit length (Dell Inspiron 1100)
# 3-clause BSD license
import array
import struct
import sys
def memcpy(arr1, off1, arr2, off2, count):
while count:
if off1 < len(arr1):
arr1[off1] = arr2[off2]
elif off1 == len(arr1):
arr1.append(arr2[off2])
else:
raise Exception("Trying to write out of bounds")
off1 += 1
off2 += 1
count -= 1
# looks like some lzss variation
def dell_unpack(indata):
srcoff = 0
dstoff = 0
src = array.array('B', indata)
dst = array.array('B')
inlen = len(indata)
while srcoff < inlen:
b = src[srcoff]
nibl, nibh = b & 0x0F, (b >> 4) & 0x0F
srcoff += 1
if nibl:
if nibl == 0xF:
al = src[srcoff]
ah = src[srcoff+1]
srcoff += 2
cx = nibh | (ah << 4)
count = (cx & 0x3F) + 2
delta = ((ah >> 2) << 8) | al
else:
count = nibl + 1
delta = (nibh << 8) | src[srcoff]
srcoff += 1
memcpy(dst, dstoff, dst, dstoff - delta - 1, count)
dstoff += count
elif nibh == 0x0E:
count = src[srcoff] + 1
srcoff += 1
memcpy(dst, dstoff, dst, dstoff - 1, count)
dstoff += count
else:
if nibh == 0x0F:
count = src[srcoff] + 15
srcoff += 1
else:
count = nibh + 1
memcpy(dst, dstoff, src, srcoff, count)
dstoff += count
srcoff += count
return dst
mod_types = {
0x01: "Main ROM",
0x0C: "Microcode update",
}
print("Dell/Phoenix ROM BIOS PLUS unpacker")
if len(sys.argv) < 2:
print("Usage: dell_unpack.py bios.bin [offset]")
sys.exit(1)
fname = sys.argv[1]
offs = 0
f = open(fname, "rb").read()
if len(sys.argv) > 2:
offs = int(sys.argv[2], 16)
else:
offs = f.find(b"\xF0\x00Copyright 1985-\x02\x04\xF0\x0F8 Phoenix Technologies Ltd.")
if offs == -1:
print("Does not look like a Dell/Phoenix ROM BIOS PLUS")
sys.exit(2)
if f[offs-5] == 0x01:
hlen = 5 # 32-bit length
offs -= 5
fmt = "<BI"
elif f[offs-3] == 0x01:
hlen = 3 # 16-bit length
offs -= 3
fmt = "<BH"
else:
print("Unhandled format!")
sys.exit(1)
print("Found compressed module at %08X" % offs)
if offs > 0:
fn = "EC.bin"
print("%08X EC code, %08X %s" % (0, offs, fn))
open(fn, "wb").write(f[:offs])
while True:
type_id, leng = struct.unpack(fmt, f[offs:offs+hlen])
print("%08X type %02X" % (offs, type_id), end=" ")
offs += hlen
if type_id == 0xFF:
print("<end of chain>")
break
data = f[offs:offs+leng]
offs += leng
if type_id != 0xC:
odata = dell_unpack(data)
else:
odata = data
print(" %08X -> %08X" % (leng, len(odata)), end=" ")
fn = "mod_%02X.bin" % type_id
print(" %s" % fn, end=" ")
if type_id in mod_types:
print("(%s)" % mod_types[type_id])
else:
print("")
open(fn, "wb").write(odata)