diff --git a/fw.py b/fw.py new file mode 100755 index 0000000..6e6936e --- /dev/null +++ b/fw.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 + +from uvk5 import argv, eprint, Firmware + +def main(path): + fw = Firmware.load(path) + print('Version:', fw.version) + +if __name__ == '__main__': + main(argv[1]) diff --git a/uvk5.py b/uvk5.py index 8def551..a8b3352 100755 --- a/uvk5.py +++ b/uvk5.py @@ -2,6 +2,7 @@ from binascii import crc_hqx from itertools import cycle +import os from sys import stderr, argv from pathlib import Path from time import time @@ -60,6 +61,20 @@ def crc16(data): return i2b16(crc_hqx(data, 0)) +def is_decrypted(data): + return data[:4] == b'\x88\x13\x00\x20' or data[:4] == b'\x88\x11\x00\x20' + + +def search_for_version(data): + pre = bytes.fromhex('2135D5401303E980') + plen = len(pre) + for i in range(len(data)-plen): + if data[i:i+plen] == pre: + return data[i+plen:i+plen+16].decode(errors='ignore').rstrip('\x00').split('_')[1] + return 'unknown' + + + def decrypt(data): decrypted = xor_fw(data) version = decrypted[V_START:V_END].decode().rstrip('\x00') @@ -73,6 +88,42 @@ def encrypt(data, version='2.01.26'): return encrypted + checksum +class Firmware(bytearray): + @classmethod + def load(cls, path): + data = Path(path).read_bytes() + if is_decrypted(data): + version = search_for_version(data) + else: + data, version = decrypt(data) + + return globals().get(f'Firmware_{version.replace(".", "_")}', cls)(data, version) + + def __init__(self, data, version) -> None: + super().__init__(data) + self.version = version + + + def patch_single(self, addr, new_value, size=4): + old_bytes = self.decrypted[addr:addr+size] + old_value = int.from_bytes(old_bytes, 'little') + new_bytes = int(new_value).to_bytes(size, 'little') + self.decrypted = self.decrypted[:addr] + new_bytes + self.decrypted[addr+size:] + + + def write(self, path=None): + encrypted = encrypt(self.decrypted, self.version) + + if path: + pass + else: + os.write(1, encrypted) + + +class Firmware_2_01_26(Firmware): + pass + + class UVK5(Serial): BLOCK_SIZE = 0x80