-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathgui2.py
More file actions
106 lines (85 loc) · 4.03 KB
/
gui2.py
File metadata and controls
106 lines (85 loc) · 4.03 KB
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
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import os
import struct
from PyQt5.QtWidgets import QApplication, QFileDialog, QMainWindow, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget
class DiskPatcher(QMainWindow):
def __init__(self):
super().__init__()
# set up default values
self.img_path = ""
self.verbose = ""
# set up main window
self.setWindowTitle("Disk Patcher")
self.setGeometry(100, 100, 400, 400)
# create widgets
self.select_button = QPushButton("Select Image")
self.select_button.clicked.connect(self.select_image)
self.verbose_box = QPlainTextEdit()
self.verbose_box.setReadOnly(True)
# set up layout
main_layout = QVBoxLayout()
main_layout.addWidget(self.select_button)
main_layout.addWidget(self.verbose_box)
central_widget = QWidget()
central_widget.setLayout(main_layout)
self.setCentralWidget(central_widget)
def select_image(self):
# get image path
self.img_path, _ = QFileDialog.getOpenFileName(self, "Select image", filter="Disk image (*.img)")
if self.img_path:
self.patch_image()
def patch_image(self):
# create "Patched" directory if it doesn't exist
if not os.path.exists('Patched'):
os.mkdir('Patched')
with open(self.img_path, 'r+b') as f:
# loop over all occurrences of the USBC sector in the file
while True:
# find the next occurrence of the USBC sector
usbc_offset = f.read().find(b'USBC')
if usbc_offset == -1:
# USBC sector not found, exit loop
break
# decode the USBC sector and determine the number of sectors it was intended to write
f.seek(usbc_offset)
data = bytearray(f.read(512))
cmd_len = struct.unpack('>H', data[22:24])[0]
# delete the USBC sector
f.seek(usbc_offset)
f.write(b'\x00' * 512)
# shift all sectors in the block up by one LBA
for i in range(2, cmd_len+1):
sector_offset = usbc_offset + i*512
f.seek(sector_offset)
sector_data = bytearray(f.read(512))
f.seek(sector_offset - 512)
f.write(sector_data)
# insert a zero-filled sector at the end of the block
end_offset = usbc_offset + cmd_len * 512
f.seek(end_offset)
f.write(b'\x00' * 512)
# update the verbose box
self.verbose += f"USBC sector at offset {usbc_offset} patched\n"
self.verbose_box.setPlainText(self.verbose)
# save the patched disk image to the "Patched" directory
f.seek(0)
patched_img_path = os.path.join('Patched', os.path.basename(self.img_path))
with open(patched_img_path, 'wb') as patched_f:
patched_f.write(f.read())
# update the verbose box
self.verbose += f"\nPatching complete. Image saved to {patched_img_path}\n"
self.verbose_box.setPlainText(self.verbose)
if __name__ == '__main__':
app = QApplication([])
patcher = DiskPatcher()
patcher.show()
app.exec_()