This repository has been archived on 2026-08-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
mtreader/mtreader.py
T

115 lines
4.1 KiB
Python
Raw Normal View History

2020-07-28 20:47:20 +03:00
#!/usr/bin/env python3
import os, sys, struct, time
from serial import Serial
class MTreader:
2020-07-29 18:26:20 +03:00
def __init__(self, devfile):
2020-07-28 20:47:20 +03:00
while True:
try:
self.s = Serial(devfile, 115200)
sys.stdout.write("\n")
break
except OSError as e:
sys.stdout.write(".")
sys.stdout.flush()
time.sleep(0.1)
def send(self, data, sz = 0):
2020-07-29 18:26:20 +03:00
r = ''
2020-07-28 20:47:20 +03:00
if len(data):
self.s.write(data)
if sz > 0:
r = self.s.read(sz)
return r
def cmd(self, cmd, sz = 0):
2020-07-29 18:26:20 +03:00
r = ''
2020-07-28 20:47:20 +03:00
cmdlen = len(cmd)
if cmdlen > 0:
assert(self.send(cmd, cmdlen) == cmd)
if sz > 0:
r = self.s.read(sz)
return r
2020-07-29 18:26:20 +03:00
def read16(self, addr, sz=1, endianness='>'):
r = self.cmd(b'\xA2' + struct.pack('>II', addr, sz), sz*2)
return struct.unpack(endianness + sz * 'H', r)
2020-07-28 20:47:20 +03:00
2020-07-29 18:26:20 +03:00
def write16(self, addr, val):
2020-07-28 20:47:20 +03:00
r = self.cmd(b'\xD2' + struct.pack(">II", addr, 1), 2)
assert(r == b"\0\1")
r = self.cmd(struct.pack(">H", val), 2)
assert(r == b"\0\1")
2020-07-29 18:26:20 +03:00
def read32(self, addr, sz=1, endianness=">"):
r = self.cmd(b'\xD1' + struct.pack(">II", addr, sz), (sz*4)+4)
return struct.unpack(endianness + "H" + (sz*'I')+"H", r)
def write32(self, addr, val):
2020-07-28 20:47:20 +03:00
r = self.cmd(b'\xD4' + struct.pack(">II", addr, 1), 2)
assert(r == b"\0\1")
r = self.cmd(struct.pack(">I", val), 2)
assert(r == b"\0\1")
def connect(self, timeout = 9.0):
2020-07-29 18:26:20 +03:00
self.s.timeout = 0.1
2020-07-28 20:47:20 +03:00
while True:
2020-07-29 18:26:20 +03:00
self.s.write(b'\xA0')
r = self.s.read(1)
if r == b'\x5F':
2020-07-28 20:47:20 +03:00
break
2020-07-29 18:26:20 +03:00
self.s.write(b'\x0A\x50\x05')
r = self.s.read(3)
assert(r == b'\xF5\xAF\xFA')
self.chip = self.read16(0x80000008)[0]
self.write16(0xa0030000, 0x2200) # disable system watchdog
self.write16(0xa0710074, 0x0001) # enable transfers from core to RTC
self.write16(0xa0700a28, 0x8000) # enable USB download mode
self.write16(0xa0700a24, 2) # disable battery watchdog
self.write32(0xa0510000, 3) # enter memory map mode 3
# now all flash is mapped as little-endian 32-bit chunks at 0x10000000
2020-07-28 20:47:20 +03:00
2020-07-29 18:26:20 +03:00
def read_flash(self, outfile, start, size, blk_size=1024):
2020-07-28 20:47:20 +03:00
outf = open(outfile, "wb")
2020-07-29 18:26:20 +03:00
offset = 0
addr = 0x10000000 + start
2020-07-28 20:47:20 +03:00
while size > 0:
2020-07-29 18:26:20 +03:00
rsize = min(size, blk_size)
chunk = self.read32(addr, rsize>>2, '<')
outchunk = struct.pack('>' + (len(chunk) - 2)*'L', *chunk[1:-1])
size -= rsize
addr += rsize
outf.write(outchunk)
2020-07-28 20:47:20 +03:00
sys.stdout.write(".")
sys.stdout.flush()
2020-07-29 18:26:20 +03:00
outf.close()
2020-07-28 20:47:20 +03:00
def da_reset(self):
r = self.send(b'\xB9', 1)
r = self.send(b'\xC9\x00', 1)
r = self.send(b'\xDB\x01\x40\x00\x00\x00\x00', 1)
if __name__ == "__main__": # main app start
from argparse import ArgumentParser
2020-07-29 18:39:00 +03:00
parser = ArgumentParser(description="MTreader: a simple, no-nonsense MediaTek MT6261 phone ROM reader", epilog="(c) Luxferre 2020 --- No rights reserved <https://unlicense.org>")
2020-07-28 20:47:20 +03:00
parser.add_argument('port', help='Serial port to connect to (/dev/ttyUSB0, /dev/tty.usbmodem14100 etc.)')
parser.add_argument('file', help='File to write the dump into')
parser.add_argument('start', type=int, help='start position (in the phone flash memory)')
parser.add_argument('length', type=int, help='data length')
parser.add_argument('-bs','--block-size', type=int, default=1024, help='Readback block size (in bytes), defaults to 1024')
args = parser.parse_args()
if(args.length < 1):
2020-07-28 20:57:09 +03:00
print('Zero length of data, exiting')
2020-07-28 20:47:20 +03:00
exit(1)
print("Turn the phone off, hold the boot key and connect the cable")
2020-07-29 18:26:20 +03:00
m = MTreader(args.port)
print("Sending BROM handshake...")
2020-07-28 20:47:20 +03:00
m.connect()
2020-07-29 18:26:20 +03:00
print("Connected, chip ID: %04x" % m.chip)
2020-07-28 20:47:20 +03:00
print("Dumping, don't disconnect...")
2020-07-29 18:26:20 +03:00
m.read_flash(args.file, args.start, args.length, args.block_size)
2020-07-28 20:47:20 +03:00
print("\nROM dumped, disconnect the cable")
m.da_reset()