mirror of
https://github.com/bkerler/mtkclient.git
synced 2024-11-14 19:25:05 -05:00
Add ro and wo tools
This commit is contained in:
parent
2d8df2b69d
commit
aaf192ca1d
2 changed files with 159 additions and 52 deletions
181
mtk
181
mtk
|
@ -21,12 +21,14 @@ from mtkclient.config.brom_config import Mtk_Config
|
|||
from mtkclient.Library.utils import print_progress
|
||||
from mtkclient.Library.error import ErrorHandler
|
||||
|
||||
|
||||
def split_by_n(seq, unit_count):
|
||||
"""A generator to divide a sequence into chunks of n units."""
|
||||
while seq:
|
||||
yield seq[:unit_count]
|
||||
seq = seq[unit_count:]
|
||||
|
||||
|
||||
class ArgHandler(metaclass=LogBase):
|
||||
def __init__(self, args, config):
|
||||
try:
|
||||
|
@ -46,7 +48,7 @@ class ArgHandler(metaclass=LogBase):
|
|||
pass
|
||||
try:
|
||||
if args.loader is not None:
|
||||
config.loader=args.loader
|
||||
config.loader = args.loader
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
|
@ -128,12 +130,12 @@ class Mtk(metaclass=LogBase):
|
|||
patched = False
|
||||
data = bytearray(data)
|
||||
patches = [
|
||||
("A3687BB12846","0123A3602846"), #oppo security
|
||||
("B3F5807F01D1", "B3F5807F01D14FF000004FF000007047"), #confirmed : mt6739 c30, mt6833
|
||||
("A3687BB12846", "0123A3602846"), # oppo security
|
||||
("B3F5807F01D1", "B3F5807F01D14FF000004FF000007047"), # confirmed : mt6739 c30, mt6833
|
||||
("B3F5807F04BF4FF4807305F011B84FF0FF307047", "B3F5807F04BF4FF480734FF000004FF000007047"),
|
||||
]
|
||||
|
||||
i=0
|
||||
i = 0
|
||||
for patchval in patches:
|
||||
pattern = bytes.fromhex(patchval[0])
|
||||
idx = data.find(pattern)
|
||||
|
@ -141,8 +143,8 @@ class Mtk(metaclass=LogBase):
|
|||
patch = bytes.fromhex(patchval[1])
|
||||
data[idx:idx + len(patch)] = patch
|
||||
patched = True
|
||||
#break
|
||||
i+=1
|
||||
# break
|
||||
i += 1
|
||||
if patched:
|
||||
# with open(sys.argv[1]+".patched","wb") as wf:
|
||||
# wf.write(data)
|
||||
|
@ -156,10 +158,10 @@ class Mtk(metaclass=LogBase):
|
|||
if isinstance(preloader, str):
|
||||
if os.path.exists(preloader):
|
||||
with open(preloader, "rb") as rf:
|
||||
data=rf.read()
|
||||
data = rf.read()
|
||||
else:
|
||||
data=preloader
|
||||
data=bytearray(data)
|
||||
data = preloader
|
||||
data = bytearray(data)
|
||||
magic = unpack("<I", data[:4])[0]
|
||||
if magic == 0x014D4D4D:
|
||||
self.info(f"Valid preloader detected.")
|
||||
|
@ -229,9 +231,11 @@ class Mtk(metaclass=LogBase):
|
|||
plt = PLTools(mtk, self.__logger.level)
|
||||
if self.config.payloadfile is None:
|
||||
if self.config.chipconfig.loader is None:
|
||||
self.config.payloadfile = os.path.join(self.pathconfig.get_payloads_path(), "generic_patcher_payload.bin")
|
||||
self.config.payloadfile = os.path.join(self.pathconfig.get_payloads_path(),
|
||||
"generic_patcher_payload.bin")
|
||||
else:
|
||||
self.config.payloadfile = os.path.join(self.pathconfig.get_payloads_path(), self.config.chipconfig.loader)
|
||||
self.config.payloadfile = os.path.join(self.pathconfig.get_payloads_path(),
|
||||
self.config.chipconfig.loader)
|
||||
if plt.runpayload(filename=self.config.payloadfile):
|
||||
mtk.port.run_handshake()
|
||||
# mtk.port.close()
|
||||
|
@ -285,13 +289,13 @@ class Main(metaclass=LogBase):
|
|||
def run(self):
|
||||
try:
|
||||
if self.args.debugmode:
|
||||
loglevel=logging.DEBUG
|
||||
loglevel = logging.DEBUG
|
||||
self.__logger.setLevel(logging.DEBUG)
|
||||
else:
|
||||
loglevel=logging.INFO
|
||||
loglevel = logging.INFO
|
||||
self.__logger.setLevel(logging.INFO)
|
||||
except:
|
||||
loglevel=logging.INFO
|
||||
loglevel = logging.INFO
|
||||
self.__logger.setLevel(logging.INFO)
|
||||
pass
|
||||
config = Mtk_Config(loglevel=loglevel)
|
||||
|
@ -382,7 +386,7 @@ class Main(metaclass=LogBase):
|
|||
else:
|
||||
self.error("Couldn't connect to device, aborting.")
|
||||
if mtk.config.preloader is not None:
|
||||
filename=mtk.config.preloader
|
||||
filename = mtk.config.preloader
|
||||
if mtk.config.is_brom and mtk.config.preloader is None:
|
||||
self.warning("PL stage needs preloader, please use --preloader option. " +
|
||||
"Trying to dump preloader from ram.")
|
||||
|
@ -390,7 +394,7 @@ class Main(metaclass=LogBase):
|
|||
dadata, filename = plt.run_dump_preloader(self.args.ptype)
|
||||
mtk.config.preloader = mtk.patch_preloader_security(dadata)
|
||||
if mtk.config.preloader is not None:
|
||||
self.info("Using custom preloader : "+filename)
|
||||
self.info("Using custom preloader : " + filename)
|
||||
daaddr, dadata = mtk.parse_preloader(mtk.config.preloader)
|
||||
mtk.config.preloader = mtk.patch_preloader_security(dadata)
|
||||
if mtk.preloader.send_da(daaddr, len(dadata), 0x100, dadata):
|
||||
|
@ -414,11 +418,11 @@ class Main(metaclass=LogBase):
|
|||
# data=0x200*b"\x00"+data
|
||||
mtk.preloader.send_partition_data(partition, pldata)
|
||||
status = mtk.preloader.jump_to_partition(partition) # Do not remove !
|
||||
res=mtk.preloader.read32(0x10C180,10)
|
||||
res = mtk.preloader.read32(0x10C180, 10)
|
||||
for val in res:
|
||||
print(hex(val))
|
||||
if status!=0x0:
|
||||
self.error("Error on jumping to partition: "+self.eh.status(status))
|
||||
if status != 0x0:
|
||||
self.error("Error on jumping to partition: " + self.eh.status(status))
|
||||
else:
|
||||
self.info("Jumping to partition ....")
|
||||
return
|
||||
|
@ -632,9 +636,9 @@ class Main(metaclass=LogBase):
|
|||
else:
|
||||
# DA / FLash commands start here
|
||||
|
||||
mtk.port.cdc.connected=mtk.port.cdc.connect()
|
||||
mtk.port.cdc.connected = mtk.port.cdc.connect()
|
||||
if mtk.port.cdc.connected and os.path.exists(".state"):
|
||||
info=mtk.daloader.reinit()
|
||||
info = mtk.daloader.reinit()
|
||||
else:
|
||||
try:
|
||||
preloader = self.args.preloader
|
||||
|
@ -654,7 +658,8 @@ class Main(metaclass=LogBase):
|
|||
if mtk.config.is_brom:
|
||||
mtk = mtk.bypass_security() # Needed for dumping preloader
|
||||
if preloader is None:
|
||||
self.warning("Device is in BROM mode. No preloader given, trying to dump preloader from ram.")
|
||||
self.warning(
|
||||
"Device is in BROM mode. No preloader given, trying to dump preloader from ram.")
|
||||
preloader = self.dump_preloader_ram(mtk)
|
||||
if preloader is None:
|
||||
self.error("Failed to dump preloader from ram.")
|
||||
|
@ -835,6 +840,18 @@ class Main(metaclass=LogBase):
|
|||
else:
|
||||
print(f"Failed to dump sector {str(start)} with sector count {str(sectors)} as {filename}.")
|
||||
self.close()
|
||||
elif cmd == "ro":
|
||||
start = getint(self.args.offset)
|
||||
length = getint(self.args.length)
|
||||
filename = self.args.filename
|
||||
parttype = self.args.parttype
|
||||
if mtk.daloader.readflash(addr=start,
|
||||
length=length,
|
||||
filename=filename, parttype=parttype):
|
||||
print(f"Dumped offset {hex(start)} with length {hex(length)} as {filename}.")
|
||||
else:
|
||||
print(f"Failed to dump offset {hex(start)} with length {hex(length)} as {filename}.")
|
||||
self.close()
|
||||
elif cmd == "footer":
|
||||
filename = self.args.filename
|
||||
data, guid_gpt = mtk.daloader.get_gpt(self.args)
|
||||
|
@ -982,6 +999,30 @@ class Main(metaclass=LogBase):
|
|||
psize += 0x200
|
||||
pos += psize
|
||||
self.close()
|
||||
elif cmd == "wo":
|
||||
start = self.args.offset
|
||||
length = self.args.length
|
||||
filename = self.args.filename
|
||||
parttype = self.args.parttype
|
||||
if filename is None:
|
||||
self.error("No filename given to write to flash")
|
||||
self.close()
|
||||
return
|
||||
if not os.path.exists(filename):
|
||||
self.error(f"Filename {filename} to write doesn't exist")
|
||||
self.close()
|
||||
return
|
||||
self.info(f"Writing offset {hex(start)} with length {hex(length)}")
|
||||
if mtk.daloader.writeflash(addr=start,
|
||||
length=length,
|
||||
filename=filename,
|
||||
parttype=parttype):
|
||||
print(f"Wrote {filename} to offset {hex(start)} with " + \
|
||||
f"length {hex(length)}.")
|
||||
else:
|
||||
print(f"Failed to write {filename} to offset {hex(start)} with " + \
|
||||
f"length {hex(length)}.")
|
||||
self.close()
|
||||
elif cmd == "e":
|
||||
partitionname = self.args.partitionname
|
||||
parttype = self.args.parttype
|
||||
|
@ -1030,18 +1071,18 @@ class Main(metaclass=LogBase):
|
|||
res = mtk.daloader.detect_partition(self.args, partition, parttype)
|
||||
if res[0]:
|
||||
rpartition = res[1]
|
||||
rsectors=min(sectors*mtk.daloader.daconfig.pagesize,
|
||||
rsectors = min(sectors * mtk.daloader.daconfig.pagesize,
|
||||
rpartition.sectors * mtk.daloader.daconfig.pagesize)
|
||||
if sectors>rsectors:
|
||||
if sectors > rsectors:
|
||||
self.error(f"Partition {partition} only has {rsectors}, you were using {sectors}. " +
|
||||
f"Aborting")
|
||||
continue
|
||||
wipedata = b"\x00" * 0x200000
|
||||
error=False
|
||||
sector=rpartition.sector
|
||||
error = False
|
||||
sector = rpartition.sector
|
||||
while sectors:
|
||||
sectorsize=sectors * mtk.daloader.daconfig.pagesize
|
||||
wsize=min(sectorsize,0x200000)
|
||||
sectorsize = sectors * mtk.daloader.daconfig.pagesize
|
||||
wsize = min(sectorsize, 0x200000)
|
||||
if mtk.daloader.writeflash(addr=sector * mtk.daloader.daconfig.pagesize,
|
||||
length=wsize,
|
||||
filename=None,
|
||||
|
@ -1052,8 +1093,8 @@ class Main(metaclass=LogBase):
|
|||
f"sector count {str(sectors)}.")
|
||||
error = True
|
||||
break
|
||||
sectors -= (wsize//mtk.daloader.daconfig.pagesize)
|
||||
sector += (wsize//mtk.daloader.daconfig.pagesize)
|
||||
sectors -= (wsize // mtk.daloader.daconfig.pagesize)
|
||||
sector += (wsize // mtk.daloader.daconfig.pagesize)
|
||||
if not error:
|
||||
print(
|
||||
f"Formatted sector {str(rpartition.sector)} with " +
|
||||
|
@ -1101,22 +1142,23 @@ class Main(metaclass=LogBase):
|
|||
if subcmd == "peek":
|
||||
addr = getint(self.args.address)
|
||||
length = getint(self.args.length)
|
||||
data=mtk.daloader.peek(addr=addr,length=length)
|
||||
if data!=b"":
|
||||
data = mtk.daloader.peek(addr=addr, length=length)
|
||||
if data != b"":
|
||||
if self.args.filename is not None:
|
||||
filename = self.args.filename
|
||||
open(filename,"wb").write(data)
|
||||
open(filename, "wb").write(data)
|
||||
self.info(f"Successfully wrote data from {hex(addr)}, length {hex(length)} to {filename}")
|
||||
else:
|
||||
self.info(f"Data read from {hex(addr)}, length: {hex(length)}:\n{hexlify(data).decode('utf-8')}\n")
|
||||
self.info(
|
||||
f"Data read from {hex(addr)}, length: {hex(length)}:\n{hexlify(data).decode('utf-8')}\n")
|
||||
elif subcmd == "poke":
|
||||
addr = getint(self.args.address)
|
||||
if self.args.filename is not None:
|
||||
if os.path.exists(self.args.filename):
|
||||
data=open(self.args.filename,"rb").read()
|
||||
data = open(self.args.filename, "rb").read()
|
||||
else:
|
||||
if "0x" in self.args.data:
|
||||
data = pack("<I",int(self.args.data,16))
|
||||
data = pack("<I", int(self.args.data, 16))
|
||||
else:
|
||||
data = bytes.fromhex(self.args.data)
|
||||
if mtk.daloader.poke(addr=addr, data=data):
|
||||
|
@ -1145,9 +1187,11 @@ cmds = {
|
|||
"rl": "Read all partitions from flash to a directory",
|
||||
"rf": "Read whole flash to file",
|
||||
"rs": "Read sectors starting at start_sector to filename",
|
||||
"ro": "Read flash starting at offset to filename",
|
||||
"w": "Write partition from filename",
|
||||
"wf": "Write flash from filename",
|
||||
"wl": "Write partitions from directory path to flash",
|
||||
"wo": "Write flash starting at offset from filename",
|
||||
"e": "Erase partition",
|
||||
"es": "Erase partition with sector count",
|
||||
"footer": "Read crypto footer from flash",
|
||||
|
@ -1161,7 +1205,7 @@ cmds = {
|
|||
"peek": "Read memory in patched preloader mode",
|
||||
"stage": "Run stage2 payload via boot rom mode (kamakiri)",
|
||||
"plstage": "Run stage2 payload via preloader mode (send_da)",
|
||||
"xflash" : "Run da xflash special commands"
|
||||
"xflash": "Run da xflash special commands"
|
||||
}
|
||||
|
||||
|
||||
|
@ -1190,9 +1234,11 @@ if __name__ == '__main__':
|
|||
parser_rl = subparsers.add_parser("rl", help="Read all partitions from flash to a directory")
|
||||
parser_rf = subparsers.add_parser("rf", help="Read whole flash to file")
|
||||
parser_rs = subparsers.add_parser("rs", help="Read sectors starting at start_sector to filename")
|
||||
parser_ro = subparsers.add_parser("ro", help="Read flash starting at offset to filename")
|
||||
parser_w = subparsers.add_parser("w", help="Write partition from filename")
|
||||
parser_wf = subparsers.add_parser("wf", help="Write flash from filename")
|
||||
parser_wl = subparsers.add_parser("wl", help="Write partitions from directory path to flash")
|
||||
parser_wo = subparsers.add_parser("wo", help="Write flash starting at offset from filename")
|
||||
parser_e = subparsers.add_parser("e", help="Erase partition")
|
||||
parser_es = subparsers.add_parser("es", help="Erase partition with sector count")
|
||||
parser_footer = subparsers.add_parser("footer", help="Read crypto footer from flash")
|
||||
|
@ -1397,6 +1443,37 @@ if __name__ == '__main__':
|
|||
parser_rs.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
|
||||
parser_rs.add_argument('--socid', help='Read Soc ID')
|
||||
|
||||
parser_ro.add_argument('offset', help='Offset to start reading (int or hex)')
|
||||
parser_ro.add_argument('length', help='Length to read (int or hex)')
|
||||
parser_ro.add_argument('filename', help='Filename to store sectors')
|
||||
parser_ro.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
|
||||
parser_ro.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
|
||||
parser_ro.add_argument('--pid', type=str, help='Set usb product id used for MTK Preloader')
|
||||
parser_ro.add_argument('--sectorsize', default='0x200', help='Set default sector size')
|
||||
parser_ro.add_argument('--debugmode', action='store_true', default=False, help='Enable verbose mode')
|
||||
parser_ro.add_argument('--gpt-num-part-entries', default='0', help='Set GPT entry count')
|
||||
parser_ro.add_argument('--gpt-part-entry-size', default='0', help='Set GPT entry size')
|
||||
parser_ro.add_argument('--gpt-part-entry-start-lba', default='0', help='Set GPT entry start lba sector')
|
||||
parser_ro.add_argument('--skip', help='Skip reading partition with names "partname1,partname2,etc."')
|
||||
parser_ro.add_argument('--skipwdt', help='Skip wdt init')
|
||||
parser_ro.add_argument('--wdt', help='Set a specific watchdog addr')
|
||||
parser_ro.add_argument('--mode', help='Set a crash mode (0=dasend1,1=dasend2,2=daread)')
|
||||
parser_ro.add_argument('--var1', help='Set kamakiri specific var1 value')
|
||||
parser_ro.add_argument('--uart_addr', help='Set payload uart_addr value')
|
||||
parser_ro.add_argument('--da_addr', help='Set a specific da payload addr')
|
||||
parser_ro.add_argument('--brom_addr', help='Set a specific brom payload addr')
|
||||
parser_ro.add_argument('--ptype',
|
||||
help='Set the payload type ( "amonet","kamakiri","kamakiri2", kamakiri2/da used by default)')
|
||||
parser_ro.add_argument('--preloader', help='Set the preloader filename for dram config')
|
||||
parser_ro.add_argument('--verifystage2', help='Verify if stage2 data has been written correctly')
|
||||
parser_ro.add_argument('--parttype', help='Partition type\n' +
|
||||
'\t\tEMMC: [user, boot1, boot2, gp1, gp2, gp3, gp4, rpmb]' +
|
||||
'\t\tUFS: [lu0, lu1, lu2, lu0_lu1]')
|
||||
|
||||
parser_ro.add_argument('--filename', help='Optional filename')
|
||||
parser_ro.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
|
||||
parser_ro.add_argument('--socid', help='Read Soc ID')
|
||||
|
||||
parser_w.add_argument('partitionname', help='Partition to write (separate by comma for multiple partitions)')
|
||||
parser_w.add_argument('filename', help='Filename for writing (separate by comma for multiple filenames)')
|
||||
parser_w.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
|
||||
|
@ -1482,6 +1559,36 @@ if __name__ == '__main__':
|
|||
parser_wl.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
|
||||
parser_wl.add_argument('--socid', help='Read Soc ID')
|
||||
|
||||
parser_wo.add_argument('offset', help='Offset to start writing (int or hex)')
|
||||
parser_wo.add_argument('length', help='Length to write (int or hex)')
|
||||
parser_wo.add_argument('filename', help='Filename to write to flash')
|
||||
parser_wo.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
|
||||
parser_wo.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
|
||||
parser_wo.add_argument('--pid', type=str, help='Set usb product id used for MTK Preloader')
|
||||
parser_wo.add_argument('--sectorsize', default='0x200', help='Set default sector size')
|
||||
parser_wo.add_argument('--debugmode', action='store_true', default=False, help='Enable verbose mode')
|
||||
parser_wo.add_argument('--gpt-num-part-entries', default='0', help='Set GPT entry count')
|
||||
parser_wo.add_argument('--gpt-part-entry-size', default='0', help='Set GPT entry size')
|
||||
parser_wo.add_argument('--gpt-part-entry-start-lba', default='0', help='Set GPT entry start lba sector')
|
||||
parser_wo.add_argument('--skip', help='Skip reading partition with names "partname1,partname2,etc."')
|
||||
parser_wo.add_argument('--skipwdt', help='Skip wdt init')
|
||||
parser_wo.add_argument('--wdt', help='Set a specific watchdog addr')
|
||||
parser_wo.add_argument('--mode', help='Set a crash mode (0=dasend1,1=dasend2,2=daread)')
|
||||
parser_wo.add_argument('--var1', help='Set kamakiri specific var1 value')
|
||||
parser_wo.add_argument('--uart_addr', help='Set payload uart_addr value')
|
||||
parser_wo.add_argument('--da_addr', help='Set a specific da payload addr')
|
||||
parser_wo.add_argument('--brom_addr', help='Set a specific brom payload addr')
|
||||
parser_wo.add_argument('--ptype',
|
||||
help='Set the payload type ( "amonet","kamakiri","kamakiri2", kamakiri2/da used by default)')
|
||||
parser_wo.add_argument('--preloader', help='Set the preloader filename for dram config')
|
||||
parser_wo.add_argument('--verifystage2', help='Verify if stage2 data has been written correctly')
|
||||
parser_wo.add_argument('--parttype', help='Partition type\n' +
|
||||
'\t\tEMMC: [user, boot1, boot2, gp1, gp2, gp3, gp4, rpmb]' +
|
||||
'\t\tUFS: [lu0, lu1, lu2, lu0_lu1]')
|
||||
parser_wo.add_argument('--filename', help='Optional filename')
|
||||
parser_wo.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
|
||||
parser_wo.add_argument('--socid', help='Read Soc ID')
|
||||
|
||||
parser_e.add_argument('partitionname', help='Partitionname to erase from flash')
|
||||
parser_e.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
|
||||
parser_e.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
|
||||
|
|
|
@ -1020,7 +1020,7 @@ hwconfig = {
|
|||
blacklist_count=0x0000000A,
|
||||
send_ptr=(0x10288c, 0xea78),
|
||||
ctrl_buffer=0x00102AA0,
|
||||
cmd_handler=0x0000F7AD,
|
||||
cmd_handler=0x0000F7FD,
|
||||
brom_register_access=(0xee80, 0xef38),
|
||||
meid_addr=0x102B78,
|
||||
socid_addr=0x102B88,
|
||||
|
|
Loading…
Reference in a new issue