-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathrcx_correct
executable file
·65 lines (47 loc) · 1.65 KB
/
rcx_correct
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
#!/usr/bin/env python
# Correct the checksums in EPSON IPL blocks in an .rcx firmware file.
# James Wah 2020
# This file is in the public domain.
import sys
import hashlib
import struct
import rcx
if len(sys.argv) != 3:
print("usage: %s infile.rcx outfile.rcx" % sys.argv[0])
with open(sys.argv[1], 'rb') as fp:
data = fp.read()
fp = open(sys.argv[2], 'w+b')
fp.write(data)
def correct_ipl(offset):
fp.seek(offset, 0)
ipl_header = fp.read(0x100)
assert ipl_header[:9] == b'EPSON IPL'
header_hash = hashlib.sha1(ipl_header[:0xe])
hitem_bytes, = struct.unpack('<H', ipl_header[0xe:0x10])
hitems = hitem_bytes // 0x24
assert hitems == 3
for idx, body_base in enumerate([0x1000, 0x3000]):
hdr_base = 0x10 + 0x24*idx
hi_data = ipl_header[hdr_base:hdr_base+0x10]
f0, f2, f4, _, f8, _, length = struct.unpack('<HHHHHHL', hi_data)
fp.seek(offset + body_base, 0)
checksum = sum(bytearray(fp.read(length)))
fp.seek(offset + hdr_base + 2)
fp.write(struct.pack('<H', checksum & 0xffff))
if idx > 0:
fp.seek(offset + body_base, 0)
body_hash = hashlib.sha1(fp.read(length))
body_hash.update(header_hash.digest())
fp.seek(offset + hdr_base + 0x10)
fp.write(body_hash.digest())
header_end, cfg = rcx.parse_rcx(data)
correct_ipl(header_end)
pointer = header_end
for name, section in cfg.items():
if name.startswith('Z_'):
length = int(section['5'])
pointer += length
if pointer >= len(data):
break
if data[pointer:pointer+9] == b'EPSON IPL':
correct_ipl(pointer)