#!/usr/bin/env python3 # MTK Flash Client (c) B.Kerler 2018-2021. # Licensed under MIT License """ Usage: mtk.py -h | --help mtk.py [--vid=vid] [--pid=pid] mtk.py [--loader=filename] mtk.py [--debugmode] mtk.py [--gpt-num-part-entries=number] [--gpt-part-entry-size=number] [--gpt-part-entry-start-lba=number] mtk.py [--sectorsize=bytes] mtk.py printgpt [--memory=memtype] [--lun=lun] [--preloader=filename] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] mtk.py gpt [--memory=memtype] [--lun=lun] [--preloader=filename] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] mtk.py r [--parttype=parttype] [--memory=memtype] [--lun=lun] [--preloader=filename] [--payload=filename] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--var1=var1] [--ptype=ptype] mtk.py rl [--memory=memtype] [--parttype=parttype] [--lun=lun] [--skip=partnames] [--preloader=filename] [--payload=filename] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--var1=var1] [--ptype=ptype] mtk.py rf [--memory=memtype] [--parttype=parttype] [--lun=lun] [--preloader=filename] [--loader=filename] [--payload=filename] [--debugmode] [--vid=vid] [--pid=pid] [--var1=var1] [--ptype=ptype] mtk.py rs [--parttype=parttype] [--lun=lun] [--preloader=filename] [--loader=filename] [--payload=filename] [--debugmode] [--vid=vid] [--pid=pid] [--var1=var1] [--ptype=ptype] mtk.py w [--parttype=parttype] [--memory=memtype] [--lun=lun] [--preloader=filename] [--loader=filename] [--payload=filename] [--debugmode] [--vid=vid] [--pid=pid] [--var1=var1] [--ptype=ptype] mtk.py wf [--parttype=parttype] [--memory=memtype] [--lun=lun] [--preloader=filename] [--loader=filename] [--payload=filename] [--debugmode] [--vid=vid] [--pid=pid] [--var1=var1] [--ptype=ptype] mtk.py wl [--memory=memtype] [--parttype=parttype] [--lun=lun] [--skip=partnames] [--preloader=filename] [--payload=filename] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--var1=var1] [--ptype=ptype] mtk.py e [--parttype=parttype] [--memory=memtype] [--lun=lun] [--preloader=filename] [--loader=filename] [--payload=filename] [--debugmode] [--vid=vid] [--pid=pid] [--var1=var1] [--ptype=ptype] mtk.py footer [--memory=memtype] [--lun=lun] [--preloader=filename] [--loader=filename] [--payload=filename] [--debugmode] [--vid=vid] [--pid=pid] [--var1=var1] mtk.py reset [--debugmode] [--vid=vid] [--pid=pid] mtk.py dumpbrom [--filename=filename] [--ptype=ptype] [--crash] [--skipwdt] [--wdt=wdt] [--var1=var1] [--da_addr=addr] [--brom_addr=addr] [--uartaddr=addr] [--debugmode] [--vid=vid] [--pid=pid] [--interface=interface] [--socid] mtk.py dumppreloader [--filename=filename] [--ptype=ptype] [--crash] [--skipwdt] [--wdt=wdt] [--var1=var1] [--da_addr=addr] [--brom_addr=addr] [--uartaddr=addr] [--debugmode] [--vid=vid] [--pid=pid] [--interface=interface] [--socid] mtk.py payload [--payload=filename] [--ptype=ptype] [--crash] [--var1=var1] [--skipwdt] [--wdt=wdt] [--uartaddr=addr] [--da_addr=addr] [--brom_addr=addr] [--debugmode] [--vid=vid] [--pid=pid] [--interface=interface] [--socid] mtk.py crash [--mode=mode] [--debugmode] [--skipwdt] [--vid=vid] [--pid=pid] [--socid] mtk.py brute [--var1=var1] [--ptype=ptype] [--socid] mtk.py gettargetconfig [--debugmode] [--vid=vid] [--pid=pid] [--socid] mtk.py peek [--filename=filename] [--preloader=preloader] mtk.py stage [--stage2=filename] [--stage2addr=addr] [--stage1=filename] [--ptype=ptype] [--verifystage2] [--crash] [--socid] [--debugmode] mtk.py plstage [--filename=filename] [--preloader=preloader] [--startpartition=startpartition] [--ptype=ptype] [--socid] [--debugmode] Description: printgpt # Print GPT Table information gpt # Save gpt table to given directory r # Read flash to filename rl # Read all partitions from flash to a directory rf # Read whole flash to file rs # Read sectors starting at start_sector to filename w # Write flash to filename wl # Write partitions from directory path to flash footer # Read crypto footer from flash reset # Send mtk reset command brute # Bruteforce the kamakiri var1 dumpbrom # Try to dump the bootrom dumppreloader # Try to dump the preloader crash # Try to crash the preloader gettargetconfig # Get target config (sbc, daa, etc.) payload # Run a specific kamakiri / da payload, if no filename is given, generic patcher is used stage # Run stage2 payload via boot rom mode (kamakiri) plstage # Run stage2 payload via preloader mode (send_da) Options: --loader=filename Use specific DA loader, disable autodetection --vid=vid Set usb vendor id used for MTK Preloader --pid=pid Set usb product id used for MTK Preloader --sectorsize=bytes Set default sector size [default: 0x200] --debugmode Enable verbose mode --gpt-num-part-entries=number Set GPT entry count [default: 0] --gpt-part-entry-size=number Set GPT entry size [default: 0] --gpt-part-entry-start-lba=number Set GPT entry start lba sector [default: 0] --skip=partnames Skip reading partition with names "partname1,partname2,etc." --wdt=wdt Set a specific watchdog addr --mode=mode Set a crash mode (0=dasend1,1=dasend2,2=daread) --var1=var1 Set kamakiri specific var1 value --uart_addr=addr Set payload uart_addr value --da_addr=addr Set a specific da payload addr --brom_addr=addr Set a specific brom payload addr --ptype=ptype Set the payload type ("amonet","kamakiri","kamakiri2", kamakiri2/da used by default) --uartaddr=addr Set the payload uart addr --preloader=filename Set the preloader filename for dram config --skipwdt Skip wdt init --verifystage2 Verify if stage2 data has been written correctly --parttype=parttype Partition type EMMC: [user,boot1,boot2,gp1,gp2,gp3,gp4,rpmb] UFS: [lu0,lu1,lu2,lu0_lu1] --filename=filename Optional filename --crash Enforce crash if device is in pl mode to enter brom mode --socid Read Soc ID --startpartition=startpartition Option for plstage - Boot to (lk, tee1) """ import os import sys import logging import time from binascii import hexlify from struct import unpack, pack from docopt import docopt from mtkclient.config.usb_ids import default_ids from mtkclient.config.payloads import pathconfig from mtkclient.Library.pltools import PLTools from mtkclient.Library.mtk_preloader import Preloader from mtkclient.Library.mtk_daloader import DAloader from mtkclient.Library.Port import Port from mtkclient.Library.utils import LogBase, logsetup, getint from mtkclient.config.brom_config import Mtk_Config from mtkclient.Library.utils import print_progress 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 Mtk(metaclass=LogBase): def __init__(self, args, loader, loglevel=logging.INFO, vid=-1, pid=-1, interface=0, preinit=True): self.config = Mtk_Config(loglevel=loglevel) self.args = args self.loader = loader self.vid = vid self.pid = pid self.interface = interface self.pathconfig = pathconfig() self.__logger = logsetup(self, self.__logger, loglevel) da_address = self.args["--da_addr"] if da_address is not None: self.config.chipconfig.da_payload_addr = getint(da_address) brom_address = self.args["--brom_addr"] if brom_address is not None: self.config.chipconfig.brom_payload_addr = getint(brom_address) watchdog_address = self.args["--wdt"] if watchdog_address is not None: self.config.chipconfig.watchdog = getint(watchdog_address) uart_address = self.args["--uartaddr"] if uart_address is not None: self.config.chipconfig.uart = getint(uart_address) var1 = self.args["--var1"] if var1 is not None: self.config.chipconfig.var1 = getint(var1) if preinit: self.init() def init(self, vid=None, pid=None, interface=None, loader=None): if loader is None: loader = self.loader if vid is None: vid = self.vid if pid is None: pid = self.pid if interface is None: interface = self.interface preloader = self.args["--preloader"] if vid != -1 and pid != -1: if interface == -1: for dev in default_ids: if dev[0] == vid and dev[1] == pid: interface = dev[2] break portconfig = [[vid, pid, interface]] else: portconfig = default_ids self.port = Port(self, portconfig, self.__logger.level) self.preloader = Preloader(self, self.__logger.level) self.daloader = DAloader(self, loader, preloader, None, self.__logger.level) def crasher(self, args, enforcecrash, readsocid=False, display=True, mode=None): rmtk = self plt = PLTools(self, self.__logger.level) if enforcecrash or not (self.port.cdc.vid == 0xE8D and self.port.cdc.pid == 0x0003): self.info("We're not in bootrom, trying to crash da...") if mode is None: for crashmode in range(0, 3): try: plt.crash(crashmode) except: pass rmtk = Mtk(loader=args["--loader"], loglevel=self.__logger.level, vid=0xE8D, pid=0x0003, args=args, interface=1) rmtk.preloader.display = display if rmtk.preloader.init(args=args, readsocid=readsocid, maxtries=20): break else: try: plt.crash(mode) except Exception as err: self.__logger.debug(str(err)) pass rmtk = Mtk(loader=self.args["--loader"], loglevel=self.__logger.level, vid=0xE8D, pid=0x0003, interface=1, args=self.args) rmtk.preloader.display = display if rmtk.preloader.init(args=self.args, readsocid=readsocid, maxtries=20): return rmtk return rmtk def bypass_security(self, args, vid: int, pid: int, interface: int, readsocid=False, enforcecrash=False): mtk = self.crasher(args=args, readsocid=readsocid, enforcecrash=enforcecrash) plt = PLTools(mtk, self.__logger.level) payloadfile = args["--payload"] if payloadfile is None: if self.config.chipconfig.loader is None: payloadfile = os.path.join(self.pathconfig.get_payloads_path(), "generic_patcher_payload.bin") else: payloadfile = os.path.join(self.pathconfig.get_payloads_path(), self.config.chipconfig.loader) ptype = "kamakiri2" if self.args["--ptype"] is not None: ptype = self.args["--ptype"] if plt.runpayload(filename=payloadfile, ptype=ptype): mtk.port.run_handshake() #mtk.port.close() #mtk = Mtk(loader=args["--loader"], loglevel=self.__logger.level, vid=vid, pid=pid, # interface=interface, args=args) #mtk.preloader.init(args=args, readsocid=readsocid) return mtk else: self.error("Error on running kamakiri payload") return self def parse_preloader(mtk, preloader): with open(preloader, "rb") as rf: magic = unpack("I", mtk.port.usbread(4))[0] if ack == 0xB1B2B3B4: self.info("Successfully loaded stage2") return else: self.error("Error on jumping to pl") return else: print("Preloader path doesn't exist :(") return else: if os.path.exists(filename): with open(filename, "rb") as rf: rf.seek(0) dadata = rf.read() if mtk.preloader.init(args=self.args, readsocid=readsocid): if mtk.config.chipconfig.pl_payload_addr is not None: daaddr = mtk.config.chipconfig.pl_payload_addr else: daaddr = 0x40200000 # 0x40001000 if mtk.preloader.send_da(daaddr, len(dadata), 0x100, dadata): self.info(f"Sent da to {hex(daaddr)}, length {hex(len(dadata))}") if mtk.preloader.jump_da(daaddr): self.info(f"Jumped to {hex(daaddr)}.") ack = unpack(">I", mtk.port.usbread(4))[0] if ack == 0xB1B2B3B4: self.info("Successfully loaded stage2") else: self.error("Error on jumping to pl") return else: self.error("Error on sending pl") return self.close() elif self.args["peek"]: addr = getint(self.args[""]) length = getint(self.args[""]) if self.args["--preloader"] is None: preloader = "umidigi_power_preloader_patched" else: preloader = self.args["--preloader"] if self.args["--filename"] is None: filename = "" else: filename = self.args["--filename"] if os.path.exists(preloader): daaddr, dadata = parse_preloader(mtk, preloader) if mtk.preloader.init(args=self.args, readsocid=readsocid): if mtk.config.target_config["daa"]: mtk = mtk.bypass_security(args=self.args, vid=vid, pid=pid, interface=interface, readsocid=readsocid, enforcecrash=enforcecrash) if mtk is not None: if mtk.preloader.send_da(daaddr, len(dadata), 0x100, dadata): self.info(f"Sent preloader to {hex(daaddr)}, length {hex(len(dadata))}") if mtk.preloader.jump_da(daaddr): self.info(f"Jumped to pl {hex(daaddr)}.") time.sleep(2) mtk = Mtk(loader=self.args["--loader"], loglevel=self.__logger.level, vid=vid, pid=pid, interface=interface, args=self.args) res = mtk.preloader.init(args=self.args, readsocid=readsocid) if not res: self.error("Error on loading preloader") return else: self.info("Successfully connected to pl.") # mtk.preloader.get_hw_sw_ver() # status=mtk.preloader.jump_to_partition(b"") # Do not remove ! else: self.error("Error on jumping to pl") return self.info("Starting to read ...") dwords = length // 4 if length % 4: dwords += 1 if filename != "": wf = open(filename, "wb") sdata = b"" print_progress(0, 100, prefix='Progress:', suffix='Starting, addr 0x%08X' % addr, bar_length=50) length = dwords * 4 old = 0 pos = 0 while dwords: size = min(512 // 4, dwords) data = b"".join(int.to_bytes(val, 4, 'little') for val in mtk.preloader.read32(addr + pos, size)) sdata += data if filename != "": wf.write(data) pos += len(data) prog = pos / length * 100 if round(prog, 1) > old: print_progress(prog, 100, prefix='Progress:', suffix='Complete, addr 0x%08X' % (addr + pos), bar_length=50) old = round(prog, 1) dwords = (length - pos) // 4 print_progress(100, 100, prefix='Progress:', suffix='Finished', bar_length=50) if filename == "": print(hexlify(sdata).decode('utf-8')) else: wf.close() self.info(f"Data from {hex(addr)} with size of {hex(length)} was written to " + filename) self.close() elif self.args["stage"]: if self.args["--filename"] is None: pc = pathconfig() stage1file = os.path.join(pc.get_payloads_path(), "generic_stage1_payload.bin") else: stage1file = self.args["--filename"] if not os.path.exists(stage1file): self.error(f"Error: {stage1file} doesn't exist !") return False if self.args["--stage2addr"] is None: stage2addr = None else: stage2addr = getint(self.args["--stage2addr"]) if self.args["--stage2"] is None: stage2file = os.path.join(mtk.pathconfig.get_payloads_path(), "stage2.bin") else: stage2file = self.args["--stage2"] if not os.path.exists(stage2file): self.error(f"Error: {stage2file} doesn't exist !") return False verifystage2 = self.args["--verifystage2"] if mtk.preloader.init(args=self.args, readsocid=readsocid): if self.args["--crash"] is not None: mtk = mtk.crasher(args=self.args, readsocid=readsocid, enforcecrash=enforcecrash) if mtk.port.cdc.pid == 0x0003: plt = PLTools(mtk, self.__logger.level) self.info("Uploading stage 1") ptype = "kamakiri2" if self.args["--ptype"] is not None: ptype = self.args["--ptype"] if plt.runpayload(filename=stage1file, ptype=ptype): self.info("Successfully uploaded stage 1, sending stage 2") with open(stage2file, "rb") as rr: stage2data = rr.read() while len(stage2data) % 0x200: stage2data += b"\x00" if stage2addr is None: stage2addr = mtk.config.chipconfig.da_payload_addr if stage2addr is None: stage2addr = 0x201000 # ###### Send stage2 # magic mtk.port.usbwrite(pack(">I", 0xf00dd00d)) # cmd write mtk.port.usbwrite(pack(">I", 0x4000)) # address mtk.port.usbwrite(pack(">I", stage2addr)) # length mtk.port.usbwrite(pack(">I", len(stage2data))) bytestowrite = len(stage2data) pos = 0 while bytestowrite > 0: size = min(bytestowrite, 1) if mtk.port.usbwrite(stage2data[pos:pos + size]): bytestowrite -= size pos += size # mtk.port.usbwrite(b"") time.sleep(0.1) flag = mtk.port.rdword() if flag != 0xD0D0D0D0: self.error(f"Error on sending stage2, size {hex(len(stage2data))}.") self.info(f"Done sending stage2, size {hex(len(stage2data))}.") if verifystage2: self.info("Verifying stage2 data") rdata = b"" mtk.port.usbwrite(pack(">I", 0xf00dd00d)) mtk.port.usbwrite(pack(">I", 0x4002)) mtk.port.usbwrite(pack(">I", stage2addr)) mtk.port.usbwrite(pack(">I", len(stage2data))) bytestoread = len(stage2data) while bytestoread > 0: size = min(bytestoread, 1) rdata += mtk.port.usbread(size) bytestoread -= size flag = mtk.port.rdword() if flag != 0xD0D0D0D0: self.error("Error on reading stage2 data") if rdata != stage2data: self.error("Stage2 data doesn't match") with open("rdata", "wb") as wf: wf.write(rdata) else: self.info("Stage2 verification passed.") # ####### Kick Watchdog # magic # mtk.port.usbwrite(pack("I", 0xf00dd00d)) # cmd jump mtk.port.usbwrite(pack(">I", 0x4001)) # address mtk.port.usbwrite(pack(">I", stage2addr)) self.info("Done jumping stage2 at %08X" % stage2addr) ack = unpack(">I", mtk.port.usbread(4))[0] if ack == 0xB1B2B3B4: self.info("Successfully loaded stage2") self.close() else: mtk.port.close() return False elif self.args["payload"]: if mtk.preloader.init(args=self.args, readsocid=readsocid): mtk = mtk.crasher(args=self.args, readsocid=readsocid, enforcecrash=enforcecrash) plt = PLTools(mtk, self.__logger.level) payloadfile = self.args["--payload"] if payloadfile is None: if mtk.config.chipconfig.loader is None: payloadfile = os.path.join(mtk.pathconfig.get_payloads_path(), "generic_patcher_payload.bin") else: payloadfile = os.path.join(mtk.pathconfig.get_payloads_path(), mtk.config.chipconfig.loader) ptype = "" if self.args["--ptype"] is not None: ptype = self.args["--ptype"] plt.runpayload(filename=payloadfile, ptype=ptype) mtk.port.close() self.close() elif self.args["gettargetconfig"]: if mtk.preloader.init(args=self.args, readsocid=readsocid): self.info("Getting target info...") mtk.preloader.get_target_config() mtk.port.close() self.close() else: preloader = self.args["--preloader"] if mtk.preloader.init(args=self.args, readsocid=readsocid): if mtk.config.target_config["daa"]: mtk = mtk.bypass_security(args=self.args, vid=vid, pid=pid, interface=interface, readsocid=readsocid, enforcecrash=enforcecrash) self.info("Device is protected.") if mtk is not None: meid = mtk.preloader.get_meid() if meid: self.info("Device is in BROM mode. Trying to dump preloader.") if preloader is None: preloader=self.dump_preloader_ram(mtk) else: self.info("Device is unprotected.") meid = mtk.preloader.get_meid() if meid: self.info("Device is in BROM mode. Trying to dump preloader.") mtk = mtk.bypass_security(args=self.args, vid=vid, pid=pid, interface=interface, readsocid=readsocid, enforcecrash=enforcecrash) preloader = self.dump_preloader_ram(mtk) if not mtk.daloader.upload_da(preloader=preloader): self.error("Error uploading da") return False else: return False if self.args["gpt"]: directory = self.args[""] if directory is None: directory = "" sfilename = os.path.join(directory, f"gpt_main.bin") data, guid_gpt = mtk.daloader.get_gpt(self.args) if guid_gpt is None: self.error("Error reading gpt") mtk.daloader.close() exit(1) else: with open(sfilename, "wb") as wf: wf.write(data) print(f"Dumped GPT from to {sfilename}") sfilename = os.path.join(directory, f"gpt_backup.bin") with open(sfilename, "wb") as wf: wf.write(data[mtk.daloader.daconfig.pagesize:]) print(f"Dumped Backup GPT to {sfilename}") mtk.daloader.close() self.close() elif self.args["printgpt"]: data, guid_gpt = mtk.daloader.get_gpt(self.args) if guid_gpt is None: self.error("Error reading gpt") else: guid_gpt.print() mtk.daloader.close() self.close() elif self.args["r"]: partitionname = self.args[""] parttype = self.args["--parttype"] filename = self.args[""] filenames = filename.split(",") partitions = partitionname.split(",") if len(partitions) != len(filenames): self.error("You need to gives as many filenames as given partitions.") mtk.daloader.close() exit(1) if parttype == "user" or parttype is None: i = 0 self.info("Requesting available partitions ....") gpttable = mtk.daloader.get_partition_data(self.args, parttype=parttype) for partition in partitions: partfilename = filenames[i] i += 1 if partition == "gpt": mtk.daloader.readflash(addr=0, length=0x16000, filename=partfilename, parttype=parttype) continue else: rpartition = None for gptentry in gpttable: if gptentry.name.lower()==partition.lower(): rpartition=gptentry break if rpartition is not None: self.info(f"Dumping partition {rpartition.name}") if mtk.daloader.readflash(addr=rpartition.sector * mtk.daloader.daconfig.pagesize, length=rpartition.sectors * mtk.daloader.daconfig.pagesize, filename=partfilename, parttype=parttype): self.info(f"Dumped sector {str(rpartition.sector)} with sector count " + f"{str(rpartition.sectors)} as {partfilename}.") else: self.info(f"Failed to dump sector {str(rpartition.sector)} with sector count " + f"{str(rpartition.sectors)} as {partfilename}.") else: self.error(f"Error: Couldn't detect partition: {partition}\nAvailable partitions:") for rpartition in gpttable: self.info(rpartition.name) else: i = 0 for partfilename in filenames: pos = 0 if mtk.daloader.readflash(addr=pos, length=0xFFFFFFFF, filename=partfilename, parttype=parttype): print(f"Dumped partition {str(partitionname)} as {partfilename}.") else: print(f"Failed to dump partition {str(partitionname)} as {partfilename}.") i += 1 mtk.daloader.close() self.close() elif self.args["rl"]: directory = self.args[""] parttype = self.args["--parttype"] if self.args["--skip"]: skip = self.args["--skip"].split(",") else: skip = [] if not os.path.exists(directory): os.mkdir(directory) data, guid_gpt = mtk.daloader.get_gpt(self.args, parttype=parttype) if guid_gpt is None: self.error("Error reading gpt") else: storedir = directory if not os.path.exists(storedir): os.mkdir(storedir) sfilename = os.path.join(storedir, f"gpt_main.bin") with open(sfilename, "wb") as wf: wf.write(data) sfilename = os.path.join(storedir, f"gpt_backup.bin") with open(sfilename, "wb") as wf: wf.write(data[mtk.daloader.daconfig.pagesize * 2:]) for partition in guid_gpt.partentries: partitionname = partition.name if partition.name in skip: continue filename = os.path.join(storedir, partitionname + ".bin") self.info(f"Dumping partition {str(partition.name)} with sector count {str(partition.sectors)} " + f"as {filename}.") mtk.daloader.readflash(addr=partition.sector * mtk.daloader.daconfig.pagesize, length=partition.sectors * mtk.daloader.daconfig.pagesize, filename=filename, parttype=parttype) mtk.daloader.close() self.close() elif self.args["rf"]: filename = self.args[""] parttype = self.args["--parttype"] if mtk.daloader.daconfig.flashtype == "ufs": if parttype == "lu0": length = mtk.daloader.daconfig.flashsize[0] elif parttype == "lu1": length = mtk.daloader.daconfig.flashsize[1] elif parttype == "lu2": length = mtk.daloader.daconfig.flashsize[2] else: length = mtk.daloader.daconfig.flashsize[0] else: length = mtk.daloader.daconfig.flashsize print(f"Dumping sector 0 with flash size {hex(length)} as {filename}.") if mtk.daloader.readflash(addr=0, length=length, filename=filename, parttype=parttype): print(f"Dumped sector 0 with flash size {hex(length)} as {filename}.") else: print(f"Failed to dump sector 0 with flash size {hex(length)} as {filename}.") mtk.daloader.close() self.close() elif self.args["rs"]: start = getint(self.args[""]) sectors = getint(self.args[""]) filename = self.args[""] parttype = self.args["--parttype"] if mtk.daloader.readflash(addr=start * mtk.daloader.daconfig.pagesize, length=sectors * mtk.daloader.daconfig.pagesize, filename=filename, parttype=parttype): print(f"Dumped sector {str(start)} with sector count {str(sectors)} as {filename}.") else: print(f"Failed to dump sector {str(start)} with sector count {str(sectors)} as {filename}.") mtk.daloader.close() self.close() elif self.args["footer"]: filename = self.args[""] data, guid_gpt = mtk.daloader.get_gpt(self.args) if guid_gpt is None: self.error("Error reading gpt") mtk.daloader.close() exit(1) else: pnames = ["userdata2", "metadata", "userdata", "reserved1", "reserved2", "reserved3"] for partition in guid_gpt.partentries: if partition.name in pnames: print(f"Detected partition: {partition.name}") if partition.name in ["userdata2", "userdata"]: data = mtk.daloader.readflash( addr=(partition.sector + partition.sectors) * mtk.daloader.daconfig.pagesize - 0x4000, length=0x4000, filename="", parttype="user", display=False) else: data = mtk.daloader.readflash(addr=partition.sector * mtk.daloader.daconfig.pagesize, length=0x4000, filename="", parttype="user", display=False) if data == b"": continue val = unpack(""] filename = self.args[""] parttype = self.args["--parttype"] filenames = filename.split(",") partitions = partitionname.split(",") if len(partitions) != len(filenames): self.error("You need to gives as many filenames as given partitions.") mtk.daloader.close() exit(0) if parttype == "user" or parttype is None: i = 0 for partition in partitions: partfilename = filenames[i] i += 1 if partition == "gpt": mtk.daloader.writeflash(addr=0, length=os.stat(partfilename).st_size, filename=partfilename, partitionname=partition, parttype=parttype) continue res = mtk.daloader.detect_partition(self.args, partition, parttype) if res[0]: rpartition = res[1] if mtk.daloader.writeflash(addr=rpartition.sector * mtk.daloader.daconfig.pagesize, length=rpartition.sectors * mtk.daloader.daconfig.pagesize, filename=partfilename, partitionname=partition, parttype=parttype): print( f"Wrote {partfilename} to sector {str(rpartition.sector)} with " + f"sector count {str(rpartition.sectors)}.") else: print( f"Failed to write {partfilename} to sector {str(rpartition.sector)} with " + f"sector count {str(rpartition.sectors)}.") else: self.error(f"Error: Couldn't detect partition: {partition}\nAvailable partitions:") for rpartition in res[1]: self.info(rpartition.name) else: pos = 0 for partfilename in filenames: size = os.stat(partfilename).st_size if mtk.daloader.writeflash(addr=pos, length=size, filename=partfilename, partitionname=partitionname, parttype=parttype): print(f"Wrote {partfilename} to sector {str(pos // 0x200)} with " + f"sector count {str(size)}.") else: print(f"Failed to write {partfilename} to sector {str(pos // 0x200)} with " + f"sector count {str(size)}.") psize = size // 0x200 * 0x200 if size % 0x200 != 0: psize += 0x200 pos += psize mtk.daloader.close() self.close() elif self.args["wl"]: directory = self.args[""] parttype = self.args["--parttype"] filenames = [] for dirName, subdirList, fileList in os.walk(directory): for fname in fileList: filenames.append(os.path.join(dirName, fname)) if parttype == "user" or parttype is None: i = 0 for partfilename in filenames: partition = os.path.basename(partfilename) partition = os.path.splitext(partition)[0] i += 1 if partition == "gpt": self.info(f"Writing partition {partition}") if mtk.daloader.writeflash(addr=0, length=os.stat(partfilename).st_size, filename=partfilename, partitionname=partition, parttype=parttype): print(f"Wrote {partition} to sector {str(0)}") else: print(f"Failed to write {partition} to sector {str(0)}") continue res = mtk.daloader.detect_partition(self.args, partition, parttype) if res[0]: rpartition = res[1] if mtk.daloader.writeflash(addr=rpartition.sector * mtk.daloader.daconfig.pagesize, length=rpartition.sectors * mtk.daloader.daconfig.pagesize, filename=partfilename, partitionname=partition, parttype=parttype): print( f"Wrote {partfilename} to sector {str(rpartition.sector)} with " + f"sector count {str(rpartition.sectors)}.") else: print( f"Failed to write {partfilename} to sector {str(rpartition.sector)} with " + f"sector count {str(rpartition.sectors)}.") else: self.error(f"Error: Couldn't detect partition: {partition}\n, skipping") else: pos = 0 for partfilename in filenames: size = os.stat(partfilename).st_size partition = os.path.basename(partfilename) partition = os.path.splitext(partition)[0] self.info(f"Writing filename {partfilename}") if mtk.daloader.writeflash(addr=pos, length=size, filename=partfilename, partitionname=partition, parttype=parttype): print(f"Wrote {partfilename} to sector {str(pos // 0x200)} with " + f"sector count {str(size)}.") else: print(f"Failed to write {partfilename} to sector {str(pos // 0x200)} with " + f"sector count {str(size)}.") psize = size // 0x200 * 0x200 if size % 0x200 != 0: psize += 0x200 pos += psize mtk.daloader.close() self.close() elif self.args["e"]: partitionname = self.args[""] parttype = self.args["--parttype"] partitions = partitionname.split(",") if parttype == "user" or parttype is None: i = 0 for partition in partitions: i += 1 res = mtk.daloader.detect_partition(self.args, partition, parttype) if res[0]: rpartition = res[1] if mtk.daloader.formatflash(addr=rpartition.sector * mtk.daloader.daconfig.pagesize, length=rpartition.sectors * mtk.daloader.daconfig.pagesize, partitionname=partition, parttype=parttype): print( f"Formatted sector {str(rpartition.sector)} with " + f"sector count {str(rpartition.sectors)}.") else: print( f"Failed to format sector {str(rpartition.sector)} with " + f"sector count {str(rpartition.sectors)}.") else: self.error(f"Error: Couldn't detect partition: {partition}\nAvailable partitions:") for rpartition in res[1]: self.info(rpartition.name) else: pos = 0 for partitionname in partitions: mtk.daloader.formatflash(addr=pos, length=0xF000000, partitionname=partitionname, parttype=parttype, display=True) print(f"Formatted sector {str(pos // 0x200)}") mtk.daloader.close() self.close() elif self.args["wf"]: filename = self.args[""] parttype = self.args["--parttype"] filenames = filename.split(",") pos = 0 for partfilename in filenames: size = os.stat(partfilename).st_size // 0x200 * 0x200 if mtk.daloader.writeflash(addr=pos, length=size, filename=partfilename, partitionname=None, parttype=parttype): print(f"Wrote {partfilename} to sector {str(pos // 0x200)} with " + f"sector count {str(size // 0x200)}.") else: print(f"Failed to write {partfilename} to sector {str(pos // 0x200)} with " + f"sector count {str(size // 0x200)}.") mtk.daloader.close() self.close() elif self.args["reset"]: mtk.daloader.close() self.close() if __name__ == '__main__': print("MTK Flash/Exploit Client V1.41 (c) B.Kerler 2018-2021") mtk = Main().run()