forked from acabey/flash-dump-tool
-
Notifications
You must be signed in to change notification settings - Fork 0
/
patcher.py
94 lines (63 loc) · 2.93 KB
/
patcher.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
#!/usr/bin/env python3
from common import *
# Apply KXAM patches to a target
def patch(originaldata, patchset):
# Patch format
# 4 byte offet
# 4 byte count
# 4 byte * count patch payload
# Get the patch offset
# Get the patch size
patcheddata = originaldata
currentoffset = 0
patchoffsetbytes = bytes(patchset[currentoffset:currentoffset+4]
while(patchoffsetbytes != b'\xFF\xFF\xFF\xFF'):
patchoffsetbytes = bytes(patchset[currentoffset:currentoffset+4]
patchoffset = struct.unpack('>I', patchoffsetbytes)[0]
dbgprint('patch offset: ' + str(hex(patchoffset)))
currentoffset += 4
patchcountbytes = bytes(patchset[currentoffset:currentoffset+4]
patchcount = struct.unpack('>I', patchcountbytes)[0]
dbgprint('patch count : ' + str(hex(patchcount)))
dbgprint('payload size: ' + str(hex(patchcount*4)))
currentoffset += 4
patchpayloadbytes = bytes(patchset[currentoffset:currentoffset + 4*patchcount]
dbgprint('payload : ' + str(patchpayloadbytes))
patcheddata[patchoffset:patchoffset+patchcount] = [patchpayloadbytes]
currentoffset += 4*patchcount
return bytes(patcheddata)
"""
There are two implementations of the actual patching algorithm here because writing directly to files is much lighter on MemoryStream
There is no reason to completely load the files into RAM before modifying when they can be modified InitializeComponent
"""
def main(argv):
target = argv[1] if len(argv) > 0 else None
patch = argv[2] if len(argv) > 1 else None
if not (target and patch):
print('Usage: applypatch.py target.bin patches.kxam')
# Patch format
# 4 byte offet
# 4 byte count
# 4 byte * count patch payload
with open(patch, 'rb') as patchfile:
with open(target, 'r+b') as targetfile:
while(patchfile.readable()):
patchoffsetbytes = patchfile.read(4)
if patchoffsetbytes == b'\xFF\xFF\xFF\xFF':
break
patchoffset = struct.unpack('>I', patchoffsetbytes)[0]
print('patchoffset: ' + str(hex(patchoffset)))
patchcountbytes = patchfile.read(4)
patchcount = struct.unpack('>I', patchcountbytes)[0]
print('patchcount: ' + str(hex(patchcount)))
print('expected payload size: ' + str(hex(patchcount*4)))
patchpayloadbytes = patchfile.read(4*patchcount)
print('payload length: ' + str(hex(len(patchpayloadbytes))))
print('payload: ' + str(patchpayloadbytes))
print('Writing patch of length ' + str(hex(patchcount)) + ' to offset ' + str(hex(patchoffset)))
targetfile.seek(patchoffset,0)
targetfile.write(patchpayloadbytes)
print('Successfully wrote patches')
if __name__ == '__main__':
import sys, struct
main(sys.argv)