New version. MANY fixes and kewl new stuff. Hopefully more stable now.

This commit is contained in:
Bjoern Kerler 2021-09-28 17:56:15 +02:00
parent 81b6622e2f
commit 65db5b344b
818 changed files with 1719 additions and 770 deletions

130
README.md
View file

@ -1,6 +1,7 @@
# mtkclient
Just some mtk tool for exploitation, reading/writing flash and doing crazy stuff. For linux, a patched kernel is only needed for kamakiri (see Setup folder) (except for read/write flash).
Just some mtk tool for exploitation, reading/writing flash and doing crazy stuff.
For windows, you need to install the stock mtk port and the usbdk driver (see instructions below).
For linux, a patched kernel is only needed when using old kamakiri (see Setup folder) (except for read/write flash).
Once the mtk script is running, boot into brom mode by powering off device, press and hold either
vol up + power or vol down + power and connect the phone. Once detected by the tool,
@ -113,6 +114,80 @@ sudo reboot
## Usage
### Root the phone (Tested with android 9 - 12)
1. Dump boot and vbmeta
```
python mtk r boot,vbmeta boot.img,vbmeta.img
```
2. Reboot the phone
```
python mtk reset
```
3. Download patched magisk for mtk:
Download [here][https://raw.githubusercontent.com/vvb2060/magisk_files/44ca9ed38c29e22fa276698f6c03bc1168df2c10/app-release.apk]
4. Install on target phone
- you need to enable usb-debugging via Settings/About phone/Version, Tap 7x on build number
- Go to Settings/Additional settings/Developer options, enable "OEM unlock" and "USB Debugging"
- Install magisk apk
```
adb install app-release.apk
```
- accept auth rsa request on mobile screen of course to allow adb connection
5. Upload boot to /sdcard/Download
```
adb push boot.img /sdcard/Download
```
6. Start magisk, tap on Install, select boot.img from /sdcard/Download, then:
```
adb pull /sdcard/Download/[displayed magisk patched boot filename here]
mv [displayed magisk patched boot filename here] boot.patched
```
7. Do the steps needed in section "Unlock bootloader below"
8. Flash magisk-patched boot and empty vbmeta
```
python mtk w boot,vbmeta boot.patched,vbmeta.img.empty
```
9. Reboot the phone
```
python mtk reset
```
10. Disconnect usb cable and enjoy your rooted phone :)
### Unlock bootloader
1. Erase metadata and userdata (and md_udt if existing):
```
python mtk e metadata, userdata
```
2. Unlock bootloader:
```
python mtk xflash seccfg unlock
```
for relocking use:
```
python mtk xflash seccfg lock
```
3. Reboot the phone:
```
python mtk reset
```
and disconnect usb cable to let the phone reboot.
### Read flash
Dump boot partition to filename boot.bin via preloader
@ -170,16 +245,47 @@ python mtk wl out
### Erase flash
Erase boot partition (use --preloader for brom)
Erase boot partition
```
python mtk e boot
```
### Leave flash mode and reboot
Erase boot sectors
```
python mtk reset
python mtk es boot [sector count]
```
### XFlash commands (only available via XFlash da, not legacy da for now):
Peek memory
```
python mtk xflash peek [addr in hex] [length in hex] [optional: -filename filename.bin for reading to file]
```
Poke memory
```
python mtk xflash peek [addr in hex] [data as hexstring or -filename for reading from file]
```
Read rpmb
```
python mtk xflash rpmb r [will read to rpmb.bin]
```
Write rpmb [Dangerous and may not work as it's not tested !]
```
python mtk xflash rpmb w filename
```
Generate and display rpmb1-3 key
```
python mtk xflash generatekeys
```
Unlock / Lock bootloader
```
python mtk xflash seccfg [lock or unlock]
```
---------------------------------------------------------------------------------------------------------------
@ -273,8 +379,6 @@ python stage2 preloader
### Read memory as hex data in stage2 mode
``
python stage2 memread [start addr] [length]
python stage2 memread 0x140000 0x10
python stage2 memread 0x140000 16
``
### Read memory to file in stage2 mode
@ -282,17 +386,19 @@ python stage2 memread 0x140000 16
python stage2 memread [start addr] [length] --filename filename.bin
``
### Write data to memory in stage2 mode
### Write hex data to memory in stage2 mode
``
python stage2 memwrite [start addr] [data as hexstring or hex int or filename]
python stage2 memwrite 0x140000 112233445566778899
python stage2 memwrite 0x140000 0x12345678
python stage2 memwrite 0x140000 data.bin
python stage2 memwrite [start addr] --data [data as hexstring]
``
### Write memory from file in stage2 mode
``
python stage2 memwrite [start addr] --filename filename.bin
``
### Extract keys
``
python stage2 keys
python stage2 keys --mode [sej, dxcc]
``
For dxcc, you need to use plstage instead of stage

213
mtk
View file

@ -1,6 +1,7 @@
#!/usr/bin/env python3
# MTK Flash Client (c) B.Kerler 2018-2021.
# Licensed under MIT License
import shutil
import os
import json
import sys
@ -88,6 +89,11 @@ class ArgHandler(metaclass=LogBase):
config.preloader = args.preloader
except AttributeError:
pass
try:
if args.generatekeys is not None:
config.generatekeys = args.generatekeys
except AttributeError:
pass
try:
if args.ptype is not None:
config.ptype = args.ptype
@ -194,7 +200,7 @@ class Mtk(metaclass=LogBase):
def crasher(self, display=True, mode=None):
rmtk = self
plt = PLTools(self, self.__logger.level)
if self.config.enforcecrash or not (self.port.cdc.vid == 0xE8D and self.port.cdc.pid == 0x0003):
if self.config.enforcecrash or self.config.meid is None:
self.info("We're not in bootrom, trying to crash da...")
if mode is None:
for crashmode in range(0, 3):
@ -256,6 +262,7 @@ class Main(metaclass=LogBase):
if idx != -1:
data = data[idx:]
length = unpack("<I", data[0x20:0x24])[0]
time.sleep(0.05)
data = b"".join([pack("<I", val) for val in mtk.preloader.read32(0x200000 + idx, length + 4 // 4)])
preloader = data[:length]
idx = data.find(b"MTK_BLOADER_INFO")
@ -268,7 +275,8 @@ class Main(metaclass=LogBase):
wf.write(preloader)
print(f"Successfully extracted preloader for this device to: {pfilename}")
return preloader
except:
except Exception as err:
self.error(str(err))
return None
def close(self):
@ -426,7 +434,7 @@ class Main(metaclass=LogBase):
return
self.close()
elif cmd == "peek":
addr = getint(self.args.offset)
addr = getint(self.args.address)
length = getint(self.args.length)
if self.args.preloader is not None:
preloader = self.args.preloader
@ -608,7 +616,7 @@ class Main(metaclass=LogBase):
if self.args.ptype is not None:
ptype = self.args.ptype
plt.runpayload(filename=payloadfile)
mtk.port.close()
mtk.port.close(reset=True)
self.close()
elif cmd == "gettargetconfig":
if mtk.preloader.init():
@ -620,10 +628,16 @@ class Main(metaclass=LogBase):
# DA / FLash commands start here
mtk.port.cdc.connected=mtk.port.cdc.connect()
if mtk.port.cdc.connected:
if mtk.port.cdc.connected and os.path.exists(".state"):
info=mtk.daloader.reinit()
else:
preloader = self.args.preloader
if os.path.exists("logs"):
shutil.rmtree("logs", ignore_errors=False, onerror=None)
os.mkdir("logs")
try:
preloader = self.args.preloader
except:
preloader = None
if mtk.preloader.init():
if mtk.config.target_config["daa"]:
mtk = mtk.bypass_security()
@ -636,10 +650,12 @@ class Main(metaclass=LogBase):
else:
self.info("Device is unprotected.")
if mtk.config.is_brom:
#mtk = mtk.bypass_security()
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.")
preloader = self.dump_preloader_ram(mtk)
if preloader is None:
self.error("Failed to dump preloader from ram.")
if not mtk.daloader.upload_da(preloader=preloader):
self.error("Error uploading da")
return False
@ -809,8 +825,8 @@ class Main(metaclass=LogBase):
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,
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,
@ -846,7 +862,7 @@ class Main(metaclass=LogBase):
mtk.daloader.writeflash(addr=0,
length=os.stat(partfilename).st_size,
filename=partfilename,
partitionname=partition, parttype=parttype)
parttype=parttype)
continue
res = mtk.daloader.detect_partition(self.args, partition, parttype)
if res[0]:
@ -854,7 +870,7 @@ class Main(metaclass=LogBase):
if mtk.daloader.writeflash(addr=rpartition.sector * mtk.daloader.daconfig.pagesize,
length=rpartition.sectors * mtk.daloader.daconfig.pagesize,
filename=partfilename,
partitionname=partition, parttype=parttype):
parttype=parttype):
print(
f"Wrote {partfilename} to sector {str(rpartition.sector)} with " +
f"sector count {str(rpartition.sectors)}.")
@ -902,7 +918,7 @@ class Main(metaclass=LogBase):
if mtk.daloader.writeflash(addr=0,
length=os.stat(partfilename).st_size,
filename=partfilename,
partitionname=partition, parttype=parttype):
parttype=parttype):
print(f"Wrote {partition} to sector {str(0)}")
else:
print(f"Failed to write {partition} to sector {str(0)}")
@ -913,7 +929,7 @@ class Main(metaclass=LogBase):
if mtk.daloader.writeflash(addr=rpartition.sector * mtk.daloader.daconfig.pagesize,
length=rpartition.sectors * mtk.daloader.daconfig.pagesize,
filename=partfilename,
partitionname=partition, parttype=parttype):
parttype=parttype):
print(
f"Wrote {partfilename} to sector {str(rpartition.sector)} with " +
f"sector count {str(rpartition.sectors)}.")
@ -968,6 +984,54 @@ class Main(metaclass=LogBase):
self.error(f"Error: Couldn't detect partition: {partition}\nAvailable partitions:")
for rpartition in res[1]:
self.info(rpartition.name)
self.close()
elif cmd == "es":
partitionname = self.args.partitionname
parttype = self.args.parttype
sectors = getint(self.args.sectors)
if self.args.sectors is None:
self.error("Sector count is missing. Usage: es [partname] [sector count]")
self.close()
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]
rsectors=min(sectors*mtk.daloader.daconfig.pagesize,
rpartition.sectors * mtk.daloader.daconfig.pagesize)
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
while sectors:
sectorsize=sectors * mtk.daloader.daconfig.pagesize
wsize=min(sectorsize,0x200000)
if mtk.daloader.writeflash(addr=sector * mtk.daloader.daconfig.pagesize,
length=wsize,
filename=None,
wdata=wipedata[:wsize],
parttype=parttype):
print(
f"Failed to format sector {str(sector)} with " +
f"sector count {str(sectors)}.")
error = True
break
sectors -= (wsize//mtk.daloader.daconfig.pagesize)
sector += (wsize//mtk.daloader.daconfig.pagesize)
if not error:
print(
f"Formatted sector {str(rpartition.sector)} with " +
f"sector count {str(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:
@ -998,9 +1062,49 @@ class Main(metaclass=LogBase):
os.remove(".state")
mtk.daloader.close()
self.close()
print("Reset command was sent. Disconnect usb cable to power off.")
elif cmd == "xflash":
subcmd = args.subcmd
if subcmd is None:
print("Available xflash cmds are: [peek, poke, generatekeys, unlock, rpmb]")
return
if subcmd == "peek":
addr = getint(self.args.address)
length = getint(self.args.length)
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)
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")
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()
else:
if "0x" in self.args.data:
data = pack("<I",int(self.args.data,16))
else:
data = bytes.fromhex(self.args.data)
if mtk.daloader.poke(addr=addr, data=data):
self.info(f"Successfully wrote data to {hex(addr)}, length {hex(len(data))}")
elif subcmd == "generatekeys":
mtk.daloader.keys()
elif subcmd == "seccfg":
mtk.daloader.seccfg(args.flag)
elif subcmd == "rpmb":
rpmb_subcmd = args.rpmb_subcmd
if rpmb_subcmd is None:
print('Available xflash rpmb cmds are: [r w]')
if rpmb_subcmd == "r":
mtk.daloader.read_rpmb(args.filename)
self.close()
info = "MTK Flash/Exploit Client V1.43 (c) B.Kerler 2018-2021"
info = "MTK Flash/Exploit Client V1.50 (c) B.Kerler 2018-2021"
cmds = {
"printgpt": "Print GPT Table information",
@ -1013,6 +1117,7 @@ cmds = {
"wf": "Write flash from filename",
"wl": "Write partitions from directory path to flash",
"e": "Erase partition",
"es": "Erase partition with sector count",
"footer": "Read crypto footer from flash",
"reset": "Send mtk reset command",
"dumpbrom": "Try to dump the bootrom",
@ -1023,7 +1128,8 @@ cmds = {
"gettargetconfig": "Get target config (sbc, daa, etc.)",
"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)"
"plstage": "Run stage2 payload via preloader mode (send_da)",
"xflash" : "Run da xflash special commands"
}
@ -1037,13 +1143,14 @@ def showcommands():
if __name__ == '__main__':
print(info)
print("")
parser = argparse.ArgumentParser(description=info)
subparsers = parser.add_subparsers(dest="cmd",
help='Valid commands are: \n' +
'printgpt, gpt, r, rl, rf, rs, w, wf, wl, e, footer, reset, dumpbrom, \n' +
'dumppreloader, payload, crash, brute, gettargetconfig, peek, \n' +
'stage, plstage \n')
'printgpt, gpt, r, rl, rf, rs, w, wf, wl, e, es, footer, reset, \n' +
'dumpbrom, dumppreloader, payload, crash, brute, gettargetconfig, \n' +
'peek, stage, plstage, da \n')
parser_printgpt = subparsers.add_parser("printgpt", help="Print GPT Table information")
parser_gpt = subparsers.add_parser("gpt", help="Save gpt table to given directory")
@ -1055,6 +1162,7 @@ if __name__ == '__main__':
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_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")
parser_reset = subparsers.add_parser("reset", help="Send mtk reset command")
@ -1070,6 +1178,31 @@ if __name__ == '__main__':
parser_stage = subparsers.add_parser("stage", help="Run stage2 payload via boot rom mode (kamakiri)")
parser_plstage = subparsers.add_parser("plstage", help="Run stage2 payload via preloader mode (send_da)")
parser_xflash = subparsers.add_parser("xflash", help="Run xflash special commands")
da_cmds = parser_xflash.add_subparsers(dest='subcmd', help='Commands: peek poke keys unlock')
da_peek = da_cmds.add_parser("peek", help="Read memory")
da_poke = da_cmds.add_parser("poke", help="Write memory")
da_keys = da_cmds.add_parser("generatekeys", help="Generate keys")
da_unlock = da_cmds.add_parser("seccfg", help="Unlock device / Configure seccfg")
da_rpmb = da_cmds.add_parser("rpmb", help="RPMB Tools")
da_rpmb_cmds = da_rpmb.add_subparsers(dest='rpmb_subcmd', help='Commands: r w')
da_rpmb_r = da_rpmb_cmds.add_parser("r", help="Read rpmb")
da_rpmb_r.add_argument('--filename', type=str, help="Filename to write data into")
da_rpmb_w = da_rpmb_cmds.add_parser("w", help="Write rpmb")
da_rpmb_w.add_argument('--filename', type=str, help="Filename to write from")
da_peek.add_argument('address', type=str, help="Address to read from (hex value)")
da_peek.add_argument('length', type=str, help="Length to read")
da_peek.add_argument('--filename', type=str, help="Filename to write data into")
da_poke.add_argument('address', type=str, help="Address to read from (hex value)")
da_poke.add_argument('data', type=str, help="Data to write")
da_poke.add_argument('--filename', type=str, help="Filename to read data from")
da_unlock.add_argument('flag', type=str, help="Needed flag (unlock,lock)")
parser_printgpt.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
parser_printgpt.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
parser_printgpt.add_argument('--pid', type=str, help='Set usb product id used for MTK Preloader')
@ -1345,6 +1478,35 @@ if __name__ == '__main__':
parser_e.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_e.add_argument('--socid', help='Read Soc ID')
parser_es.add_argument('partitionname', help='Partitionname to erase from flash')
parser_es.add_argument('sectors', help='Sectors to erase')
parser_es.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
parser_es.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
parser_es.add_argument('--pid', type=str, help='Set usb product id used for MTK Preloader')
parser_es.add_argument('--sectorsize', default='0x200', help='Set default sector size')
parser_es.add_argument('--debugmode', action='store_true', default=False, help='Enable verbose mode')
parser_es.add_argument('--gpt-num-part-entries', default='0', help='Set GPT entry count')
parser_es.add_argument('--gpt-part-entry-size', default='0', help='Set GPT entry size')
parser_es.add_argument('--gpt-part-entry-start-lba', default='0', help='Set GPT entry start lba sector')
parser_es.add_argument('--skip', help='Skip reading partition with names "partname1,partname2,etc."')
parser_es.add_argument('--skipwdt', help='Skip wdt init')
parser_es.add_argument('--wdt', help='Set a specific watchdog addr')
parser_es.add_argument('--mode', help='Set a crash mode (0=dasend1,1=dasend2,2=daread)')
parser_es.add_argument('--var1', help='Set kamakiri specific var1 value')
parser_es.add_argument('--uart_addr', help='Set payload uart_addr value')
parser_es.add_argument('--da_addr', help='Set a specific da payload addr')
parser_es.add_argument('--brom_addr', help='Set a specific brom payload addr')
parser_es.add_argument('--ptype',
help='Set the payload type ( "amonet","kamakiri","kamakiri2", kamakiri2/da used by default)')
parser_es.add_argument('--preloader', help='Set the preloader filename for dram config')
parser_es.add_argument('--verifystage2', help='Verify if stage2 data has been written correctly')
parser_es.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_es.add_argument('--filename', help='Optional filename')
parser_es.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_es.add_argument('--socid', help='Read Soc ID')
parser_footer.add_argument('filename', help='Filename to store footer')
parser_footer.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
parser_footer.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
@ -1456,7 +1618,7 @@ if __name__ == '__main__':
parser_gettargetconfig.add_argument('--debugmode', action='store_true', default=False, help='Enable verbose mode')
parser_gettargetconfig.add_argument('--socid', help='Read Soc ID')
parser_peek.add_argument('offset', help='Offset to read from memory')
parser_peek.add_argument('address', help='Address to read from memory')
parser_peek.add_argument('length', help='Bytes to read from memory')
parser_peek.add_argument('--filename', help='Optional filename to write dumped data')
parser_peek.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
@ -1520,6 +1682,19 @@ if __name__ == '__main__':
parser_plstage.add_argument('--socid', help='Read Soc ID')
parser_plstage.add_argument('--startpartition', help='Option for plstage - Boot to (lk, tee1)')
parser_printgpt.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
parser_footer.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
parser_e.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
parser_es.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
parser_wl.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
parser_wf.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
parser_w.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
parser_rs.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
parser_rf.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
parser_rl.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
parser_gpt.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
parser_r.add_argument('--generatekeys', action="store_true", help='Option for deriving hw keys')
args = parser.parse_args()
cmd = args.cmd
if cmd not in cmds:

View file

@ -105,6 +105,7 @@ class Port(metaclass=LogBase):
resp = b""
dlen = len(value)
wr = self.usbwrite(value)
time.sleep(0.05)
if wr:
if nocmd:
cmdrsp = self.usbread(bytestoread)

View file

@ -6,6 +6,7 @@ import os
from struct import unpack
from mtkclient.Library.utils import LogBase, read_object, logsetup
from mtkclient.config.payloads import pathconfig
from mtkclient.config.brom_config import damodes
class Storage:
MTK_DA_HW_STORAGE_NOR = 0
@ -108,9 +109,10 @@ class DAconfig(metaclass=LogBase):
self.readsize = 0
self.pagesize = 512
self.da = None
self.da2 = None
self.dasetup = {}
self.loader = loader
self.extract_emi(preloader, self.mtk.config.chipconfig.damode)
self.extract_emi(preloader)
if loader is None:
loaders = []
@ -126,10 +128,36 @@ class DAconfig(metaclass=LogBase):
else:
self.parse_da_loader(loader)
def extract_emi(self, preloader=None, legacy=False) -> bytearray:
def m_extract_emi(self, data):
idx = data.find(b"\x4D\x4D\x4D\x01\x38\x00\x00\x00")
siglen = 0
if idx != -1:
data = data[idx:]
mlen = unpack("<I", data[0x20:0x20 + 4])[0]
siglen = unpack("<I", data[0x2C:0x2C + 4])[0]
data = data[:mlen]
idx = data.find(b"MTK_BLOADER_INFO")
if idx == -1:
return None
elif idx == 0:
return data
emi = data[idx:-siglen]
rlen = len(emi) - 4
if len(emi) > 4:
val = unpack("<I", emi[-4:])[0]
if val == rlen:
emi = emi[:rlen]
if not self.config.chipconfig.damode==damodes.XFLASH:
if emi.find(b"MTK_BIN")!=-1:
emi=emi[emi.find(b"MTK_BIN")+0xC:]
return emi
return None
def extract_emi(self, preloader=None) -> bytearray:
if preloader is None:
self.emi = None
return
return b""
if isinstance(preloader, bytearray) or isinstance(preloader, bytes):
data = bytearray(preloader)
elif isinstance(preloader, str):
@ -139,25 +167,7 @@ class DAconfig(metaclass=LogBase):
else:
assert "Preloader :"+preloader+" doesn't exist. Aborting."
exit(1)
if legacy:
idx = data.rfind(b"MTK_BIN")
if idx == -1:
self.emi = None
return
dramdata = data[idx:][0xC:][:-0x128]
self.emi = dramdata
return
else:
idx = data.rfind(b"MTK_BLOADER_INFO_v")
if idx != -1:
emi = data[idx:]
count = unpack("<I", emi[0x6C:0x70])[0]
size = (count * 0xB0) + 0x70
emi = emi[:size]
self.emi = emi
return
self.emi = None
return
self.emi = self.m_extract_emi(data)
def parse_da_loader(self, loader):
if not "MTK_AllInOne_DA" in loader:

View file

@ -64,11 +64,13 @@ class hwcrypto(metaclass=LogBase):
return self.gcpu.aes_read_cbc(addr=addr, encrypt=encrypt)
elif btype == "dxcc":
if mode == "fde":
return self.dxcc.generate_fde()
return self.dxcc.generate_rpmb(1)
elif mode == "rpmb2":
return self.dxcc.generate_rpmb(2)
elif mode == "rpmb":
return self.dxcc.generate_rpmb()
elif mode == "itrustee-fde":
return self.dxcc.generate_itrustee_fde()
elif mode == "itrustee":
return self.dxcc.generate_itrustee_fbe()
elif mode == "prov":
return self.dxcc.generate_provision_key()
elif mode == "sha256":

View file

@ -838,13 +838,14 @@ SEP_MAX_CTX_SIZE (max(sizeof(struct sep_ctx_rc4), \
"""
def HW_DESC_INIT():
return [0, 0, 0, 0, 0, 0]
def hw_desc_init():
res = [0, 0, 0, 0, 0, 0]
return res
def BITMASK(mask_size):
def bitmask(mask_size):
if mask_size < 32:
return (1 << (mask_size)) - 1
return (1 << mask_size) - 1
else:
return 0xFFFFFFFF
@ -854,37 +855,37 @@ def tovalue(value, bitsize, shift):
return v << shift
def HW_DESC_SET_CIPHER_MODE(pDesc, cipherMode):
def hw_desc_set_cipher_mode(pDesc, cipherMode):
shift, bitsize = DSCRPTR["DSCRPTR_QUEUE0_WORD4"][1]["CIPHER_MODE"]
pDesc[4] |= tovalue(cipherMode, bitsize, shift)
return pDesc
def HW_DESC_SET_CIPHER_CONFIG0(pDesc, cipherConfig):
def hw_desc_set_cipher_config0(pDesc, cipherConfig):
shift, bitsize = DSCRPTR["DSCRPTR_QUEUE0_WORD4"][1]["CIPHER_CONF0"]
pDesc[4] |= tovalue(cipherConfig, bitsize, shift)
return pDesc
def HW_DESC_SET_CIPHER_CONFIG1(pDesc, cipherConfig):
def hw_desc_set_cipher_config1(pDesc, cipherConfig):
shift, bitsize = DSCRPTR["DSCRPTR_QUEUE0_WORD4"][1]["CIPHER_CONF1"]
pDesc[4] |= tovalue(cipherConfig, bitsize, shift)
return pDesc
def HW_DESC_SET_SETUP_MODE(pDesc, setupMode):
def hw_desc_set_setup_mode(pDesc, setupMode):
shift, bitsize = DSCRPTR["DSCRPTR_QUEUE0_WORD4"][1]["SETUP_OPERATION"]
pDesc[4] |= tovalue(setupMode, bitsize, shift)
return pDesc
def HW_DESC_SET_FLOW_MODE(pDesc, flowMode):
def hw_desc_set_flow_mode(pDesc, flowMode):
shift, bitsize = DSCRPTR["DSCRPTR_QUEUE0_WORD4"][1]["DATA_FLOW_MODE"]
pDesc[4] |= tovalue(flowMode, bitsize, shift)
return pDesc
def HW_DESC_SET_DOUT_SRAM(pDesc, doutAdr, doutSize):
def hw_desc_set_dout_sram(pDesc, doutAdr, doutSize):
v = DSCRPTR["DSCRPTR_QUEUE0_WORD2"]
shift, bitsize = v[1], v[2]
pDesc[2] |= tovalue((doutAdr & 0xFFFFFFFF), bitsize, shift)
@ -895,7 +896,7 @@ def HW_DESC_SET_DOUT_SRAM(pDesc, doutAdr, doutSize):
return pDesc
def HW_DESC_SET_DOUT_DLLI(pDesc, doutAdr, doutSize, axiNs, lastind):
def hw_desc_set_dout_dlli(pDesc, doutAdr, doutSize, axiNs, lastind):
v = DSCRPTR["DSCRPTR_QUEUE0_WORD2"]
shift, bitsize = v[1], v[2]
pDesc[2] |= tovalue((doutAdr & 0xFFFFFFFF), bitsize, shift)
@ -912,13 +913,13 @@ def HW_DESC_SET_DOUT_DLLI(pDesc, doutAdr, doutSize, axiNs, lastind):
return pDesc
def HW_DESC_SET_KEY_SIZE_AES(pDesc, keySize):
def hw_desc_set_key_size_aes(pDesc, keySize):
shift, bitsize = DSCRPTR["DSCRPTR_QUEUE0_WORD4"][1]["KEY_SIZE"]
pDesc[4] |= tovalue(((keySize >> 3) - 2), bitsize, shift)
return pDesc
def HW_DESC_SET_DIN_SRAM(pDesc, dinAdr, dinSize):
def hw_desc_set_din_sram(pDesc, dinAdr, dinSize):
v = DSCRPTR["DSCRPTR_QUEUE0_WORD0"]
shift, bitsize = v[1], v[2]
pDesc[0] |= tovalue(dinAdr & 0xFFFFFFFF, bitsize, shift)
@ -929,7 +930,7 @@ def HW_DESC_SET_DIN_SRAM(pDesc, dinAdr, dinSize):
return pDesc
def HW_DESC_SET_DIN_CONST(pDesc, val, dinSize):
def hw_desc_set_din_const(pDesc, val, dinSize):
v = DSCRPTR["DSCRPTR_QUEUE0_WORD0"]
shift, bitsize = v[1], v[2]
pDesc[0] |= tovalue(val & 0xFFFFFFFF, bitsize, shift)
@ -942,12 +943,13 @@ def HW_DESC_SET_DIN_CONST(pDesc, val, dinSize):
return pDesc
def HW_DESC_SET_CIPHER_DO(pDesc, cipherDo):
def hw_desc_set_cipher_do(pDesc, cipherDo):
shift, bitsize = DSCRPTR["DSCRPTR_QUEUE0_WORD4"][1]["CIPHER_DO"]
pDesc[4] |= tovalue(cipherDo, bitsize, shift)
return pDesc
def HW_DESC_SET_DIN_NODMA(pDesc, dinAdr, dinSize):
def hw_desc_set_din_nodma(pDesc, dinAdr, dinSize):
v = DSCRPTR["DSCRPTR_QUEUE0_WORD0"]
shift, bitsize = v[1], v[2]
pDesc[0] |= tovalue(dinAdr & 0xFFFFFFFF, bitsize, shift)
@ -957,7 +959,8 @@ def HW_DESC_SET_DIN_NODMA(pDesc, dinAdr, dinSize):
pDesc[1] |= tovalue(dinSize, bitsize, shift)
return pDesc
def HW_DESC_SET_DIN_TYPE(pDesc, dmaMode, dinAdr, dinSize, axiId, axiNs):
def hw_desc_set_din_type(pDesc, dmaMode, dinAdr, dinSize, axiId, axiNs):
v = DSCRPTR["DSCRPTR_QUEUE0_WORD0"]
shift, bitsize = v[1], v[2]
pDesc[0] |= tovalue(dinAdr & 0xFFFFFFFF, bitsize, shift)
@ -1009,7 +1012,7 @@ class dxcc(metaclass=LogBase):
DX_DSCRPTR_QUEUE0_WORD4 = 0xE90
DX_DSCRPTR_QUEUE0_WORD5 = 0xE94
DX_DSCRPTR_QUEUE0_CONTENT = 0xE9C
DX_HOST_SEP_HOST_GPR0 = 0xA80 # DX_HOST_SEP_HOST_GPR0_REG_OFFSET
DX_HOST_SEP_HOST_GPR0 = 0xA80 # DX_HOST_SEP_HOST_GPR0_REG_OFFSET
DX_HOST_SEP_HOST_GPR1 = 0xA88
DX_HOST_SEP_HOST_GPR2 = 0xA90
DX_HOST_SEP_HOST_GPR3 = 0xA9C
@ -1023,16 +1026,15 @@ class dxcc(metaclass=LogBase):
value = self.read32(self.dxcc_base + self.DX_HOST_IRR)
if value != 0:
return value
return None
def SaSi_PalDmaUnMap(self, value1):
def sasi_paldmaunmap(self, value1):
return
def SaSi_PalDmaMap(self, value1):
def sasi_paldmamap(self, value1):
# value2=value1
return value1
def SaSi_SB_AddDescSequence(self, data):
def sasi_sb_adddescsequence(self, data):
while True:
if self.read32(self.dxcc_base + self.DX_DSCRPTR_QUEUE0_CONTENT) << 0x1C != 0:
break
@ -1062,34 +1064,33 @@ class dxcc(metaclass=LogBase):
res = self.write32(0x10001088, 0x8000000)
return res
def generate_fde(self):
fde_ikey = b"SQNC!LFZ"
fde_salt = b"TBTJ"
self.tzcc_clk(1)
dstaddr = self.da_payload_addr - 0x300
fdekey = self.SBROM_KeyDerivation(1, fde_ikey, fde_salt, 0x10, dstaddr)
self.tzcc_clk(0)
return fdekey
def generate_itrustee_fde(self, key_sz=32):
def generate_itrustee_fbe(self, key_sz=32):
fdekey = b""
dstaddr = self.da_payload_addr - 0x300
self.tzcc_clk(1)
for ctr in range(0, key_sz // 16):
itrustee = b"TrustedCorekeymaster" + b"\x07" * 0x10
seed = itrustee + pack("<B", ctr)
paddr=self.SBROM_AesCmac(1,0x0,seed,0x0,len(seed),dstaddr)
paddr = self.SBROM_AesCmac(1, 0x0, seed, 0x0, len(seed), dstaddr)
for field in self.read32(paddr + 0x108, 4):
fdekey+=pack("<I", field)
fdekey += pack("<I", field)
self.tzcc_clk(0)
return fdekey
def generate_rpmb(self):
rpmb_ikey = b"RPMB KEY"
rpmb_salt = b"SASI"
def generate_rpmb(self, level=0):
rpmb_ikey = bytearray(b"RPMB KEY")
rpmb_salt = bytearray(b"SASI")
for i in range(len(rpmb_ikey)):
rpmb_ikey[i] = rpmb_ikey[i] + level
for i in range(len(rpmb_salt)):
rpmb_salt[i] = rpmb_salt[i] + level
keylength = 0x20
if level > 0:
keylength = 0x10
self.tzcc_clk(1)
dstaddr = self.da_payload_addr - 0x300
rpmbkey = self.SBROM_KeyDerivation(1, rpmb_ikey, rpmb_salt, 0x20, dstaddr)
rpmbkey = self.SBROM_KeyDerivation(1, rpmb_ikey, rpmb_salt, keylength, dstaddr)
self.tzcc_clk(0)
return rpmbkey
@ -1105,8 +1106,8 @@ class dxcc(metaclass=LogBase):
def generate_sha256(self, data):
dstaddr = self.da_payload_addr - 0x300
self.SBROM_SHA256(buffer=data,destaddr=dstaddr)
result=bytearray()
self.sbrom_sha256(buffer=data, destaddr=dstaddr)
result = bytearray()
for field in self.read32(dstaddr, 8):
result.extend(pack("<I", field))
return result
@ -1167,14 +1168,14 @@ class dxcc(metaclass=LogBase):
def SB_HalWaitDescCompletion(self, destptr):
data = []
self.SB_HalClearInterruptBit()
val = self.SaSi_PalDmaMap(0)
val = self.sasi_paldmamap(0)
data.append(0x0) # 0
data.append(0x8000011) # 1 #DIN_DMA|DOUT_DMA|DIN_CONST
data.append(destptr) # 2
data.append(0x8000012) # 3
data.append(0x100) # 4
data.append((destptr >> 32) << 16) # 5
self.SaSi_SB_AddDescSequence(data)
self.sasi_sb_adddescsequence(data)
while True:
if self.SB_CryptoWait() & 4 != 0:
break
@ -1184,7 +1185,7 @@ class dxcc(metaclass=LogBase):
break
if value == 1:
self.SB_HalClearInterruptBit()
self.SaSi_PalDmaUnMap(val)
self.sasi_paldmaunmap(val)
return 0
else:
return 0xF6000001
@ -1199,50 +1200,52 @@ class dxcc(metaclass=LogBase):
keySizeInBytes = 0x10 # SEP_AES_128_BIT_KEY_SIZE
self.SB_HalInit()
desc = HW_DESC_INIT()
desc = HW_DESC_SET_CIPHER_MODE(desc, sep_cipher_mode.SEP_CIPHER_CMAC)
desc = HW_DESC_SET_CIPHER_CONFIG0(desc, DescDirection.DESC_DIRECTION_ENCRYPT_ENCRYPT)
desc = HW_DESC_SET_KEY_SIZE_AES(desc, keySizeInBytes)
# desc = HW_DESC_SET_DIN_SRAM(desc, ivSramAddr, AES_IV_COUNTER_SIZE_IN_BYTES)
desc = HW_DESC_SET_DIN_CONST(desc, 0, AES_IV_COUNTER_SIZE_IN_BYTES)
desc = HW_DESC_SET_FLOW_MODE(desc, FlowMode.S_DIN_to_AES)
desc = HW_DESC_SET_SETUP_MODE(desc, SetupOp.SETUP_LOAD_STATE0)
self.SaSi_SB_AddDescSequence(desc)
pdesc = hw_desc_init()
pdesc = hw_desc_set_cipher_mode(pdesc, sep_cipher_mode.SEP_CIPHER_CMAC) # desc[4]=0x1C00
pdesc = hw_desc_set_cipher_config0(pdesc, DescDirection.DESC_DIRECTION_ENCRYPT_ENCRYPT)
pdesc = hw_desc_set_key_size_aes(pdesc, keySizeInBytes) # desc[4]=0x801C00
# pdesc = hw_desc_set_din_sram(pdesc, ivSramAddr, AES_IV_COUNTER_SIZE_IN_BYTES)
pdesc = hw_desc_set_din_const(pdesc, 0, AES_IV_COUNTER_SIZE_IN_BYTES) # desc[1]=0x8000041
pdesc = hw_desc_set_flow_mode(pdesc, FlowMode.S_DIN_to_AES) # desc[4]=0x801C20
pdesc = hw_desc_set_setup_mode(pdesc, SetupOp.SETUP_LOAD_STATE0) # desc[4]=0x1801C20
self.sasi_sb_adddescsequence(pdesc)
# Load key
desc = HW_DESC_INIT()
mdesc = hw_desc_init()
if aesKeyType == HwCryptoKey.USER_KEY:
desc = HW_DESC_SET_DIN_SRAM(desc, pInternalKey, AES_Key128Bits_SIZE_IN_BYTES)
desc = HW_DESC_SET_CIPHER_DO(desc, aesKeyType)
desc = HW_DESC_SET_CIPHER_MODE(desc, sep_cipher_mode.SEP_CIPHER_CMAC)
desc = HW_DESC_SET_CIPHER_CONFIG0(desc, DescDirection.DESC_DIRECTION_ENCRYPT_ENCRYPT)
desc = HW_DESC_SET_KEY_SIZE_AES(desc, keySizeInBytes)
desc = HW_DESC_SET_FLOW_MODE(desc, FlowMode.S_DIN_to_AES)
desc = HW_DESC_SET_SETUP_MODE(desc, SetupOp.SETUP_LOAD_KEY0)
self.SaSi_SB_AddDescSequence(desc)
mdesc = hw_desc_set_din_sram(mdesc, pInternalKey, AES_Key128Bits_SIZE_IN_BYTES)
mdesc = hw_desc_set_cipher_do(mdesc, aesKeyType) # desc[4]=0x8000
mdesc = hw_desc_set_cipher_mode(mdesc, sep_cipher_mode.SEP_CIPHER_CMAC) # desc[4]=0x9C00
mdesc = hw_desc_set_cipher_config0(mdesc, DescDirection.DESC_DIRECTION_ENCRYPT_ENCRYPT)
mdesc = hw_desc_set_key_size_aes(mdesc, keySizeInBytes) # desc[4]=0x809C00
mdesc = hw_desc_set_flow_mode(mdesc, FlowMode.S_DIN_to_AES) # desc[4]=0x809C20
mdesc = hw_desc_set_setup_mode(mdesc, SetupOp.SETUP_LOAD_KEY0) # desc[4]=0x4809C20
self.sasi_sb_adddescsequence(mdesc)
# Process input data
desc = HW_DESC_INIT()
rdesc = hw_desc_init()
if dmaMode == DmaMode.DMA_SRAM:
desc = HW_DESC_SET_DIN_SRAM(desc, pDataIn, blockSize)
rdesc = hw_desc_set_din_sram(rdesc, pDataIn, blockSize)
else:
desc = HW_DESC_SET_DIN_TYPE(desc, DmaMode.DMA_DLLI, pDataIn, blockSize, SB_AXI_ID, AXI_SECURE)
desc = HW_DESC_SET_FLOW_MODE(desc, FlowMode.DIN_AES_DOUT)
self.SaSi_SB_AddDescSequence(desc)
rdesc = hw_desc_set_din_type(rdesc, DmaMode.DMA_DLLI, pDataIn, blockSize, SB_AXI_ID,
AXI_SECURE) # desc[1]=0x3E, desc[0]=0x200E18
rdesc = hw_desc_set_flow_mode(rdesc, FlowMode.DIN_AES_DOUT) # desc[4]=1
self.sasi_sb_adddescsequence(rdesc)
if aesKeyType != HwCryptoKey.PROVISIONING_KEY:
desc = HW_DESC_INIT()
desc = HW_DESC_SET_CIPHER_MODE(desc, sep_cipher_mode.SEP_CIPHER_CMAC)
desc = HW_DESC_SET_CIPHER_CONFIG0(desc, DescDirection.DESC_DIRECTION_ENCRYPT_ENCRYPT)
desc = HW_DESC_SET_SETUP_MODE(desc, SetupOp.SETUP_WRITE_STATE0)
desc = HW_DESC_SET_FLOW_MODE(desc, FlowMode.S_AES_to_DOUT)
xdesc = hw_desc_init()
xdesc = hw_desc_set_cipher_mode(xdesc, sep_cipher_mode.SEP_CIPHER_CMAC) # desc[4]=0x1C00
xdesc = hw_desc_set_cipher_config0(xdesc, DescDirection.DESC_DIRECTION_ENCRYPT_ENCRYPT)
xdesc = hw_desc_set_setup_mode(xdesc, SetupOp.SETUP_WRITE_STATE0) # desc[4]=0x8001C00
xdesc = hw_desc_set_flow_mode(xdesc, FlowMode.S_AES_to_DOUT) # desc[4]=0x8001C26
if dmaMode == DmaMode.DMA_SRAM:
desc = HW_DESC_SET_DOUT_SRAM(desc, pInternalKey, AES_BLOCK_SIZE_IN_BYTES)
xdesc = hw_desc_set_dout_sram(xdesc, pInternalKey, AES_BLOCK_SIZE_IN_BYTES)
else:
desc = HW_DESC_SET_DOUT_DLLI(desc, pInternalKey, AES_BLOCK_SIZE_IN_BYTES, SB_AXI_ID, 0)
#desc = HW_DESC_SET_DIN_SRAM(desc, 0, 0)
desc = HW_DESC_SET_DIN_NODMA(desc, 0, 0)
self.SaSi_SB_AddDescSequence(desc)
xdesc = hw_desc_set_dout_dlli(xdesc, pInternalKey, AES_BLOCK_SIZE_IN_BYTES, SB_AXI_ID,
0) # desc[2]=0x200E08, desc[3]=0x42
# xdesc = hw_desc_set_din_sram(xdesc, 0, 0)
xdesc = hw_desc_set_din_nodma(xdesc, 0, 0)
self.sasi_sb_adddescsequence(xdesc)
return self.SB_HalWaitDescCompletion(pCMacResult) == 0
def mtee_decrypt(self, data):
@ -1256,69 +1259,69 @@ class dxcc(metaclass=LogBase):
ctr = Counter.new(128, initial_value=bytes_to_long(iv))
return AES.new(key=key, counter=ctr, mode=AES.MODE_CTR).decrypt(data)
def SBROM_SHA256(self, buffer, destaddr): #TZCC_SHA256_Init
dataptr = destaddr+0x40
ivptr = destaddr+0x20
def sbrom_sha256(self, buffer, destaddr): # TZCC_SHA256_Init
dataptr = destaddr + 0x40
ivptr = destaddr + 0x20
outptr = destaddr
self.writemem(0x1000108C, 0x18000000)
iv = bytes.fromhex("19CDE05BABD9831F8C68059B7F520E513AF54FA572F36E3C85AE67BB67E6096A")
self.writemem(ivptr, iv)
self.writemem(dataptr,buffer)
self.SBROM_CryptoInitDriver(aeskeyptr=0,aesivptr=ivptr,cryptodrivermode=0)
self.SBROM_CryptoUpdate(inputptr=dataptr,outputptr=outptr,blockSize=len(buffer), islastblock=1,
cryptodrivermode=0,waitforcrypto=3)
self.SBROM_CryptoFinishDriver(outptr)
self.writemem(dataptr, buffer)
self.sbrom_cryptoinitdriver(aesivptr=ivptr, cryptodrivermode=0)
self.sbrom_cryptoupdate(inputptr=dataptr, outputptr=outptr, blockSize=len(buffer), islastblock=1,
cryptodrivermode=0, waitforcrypto=3)
self.sbrom_cryptofinishdriver(outptr)
self.writemem(0x10001088, 0x8000000)
return 0
def SBROM_CryptoInitDriver(self, aeskeyptr, aesivptr, cryptodrivermode):
if cryptodrivermode&0xFFFFFFFD == 0:
#0=v9
#1=0x820
#2=0
#3=0
#4=0x1000825
#5=v9>>32
desc = HW_DESC_INIT()
desc = HW_DESC_SET_DIN_TYPE(desc, DmaMode.DMA_DLLI, aesivptr, 0x20, SB_AXI_ID, AXI_SECURE)
desc = HW_DESC_SET_FLOW_MODE(desc, FlowMode.S_DIN_to_HASH)
desc = HW_DESC_SET_CIPHER_MODE(desc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
desc = HW_DESC_SET_SETUP_MODE(desc, SetupOp.SETUP_LOAD_STATE0)
self.SaSi_SB_AddDescSequence(desc)
#0=0
#1=0x8000041
#2=0
#3=0
#4=0x4000825
#5=0
desc = HW_DESC_INIT()
desc = HW_DESC_SET_FLOW_MODE(desc, FlowMode.S_DIN_to_HASH)
desc = HW_DESC_SET_CIPHER_MODE(desc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
desc = HW_DESC_SET_SETUP_MODE(desc, SetupOp.SETUP_LOAD_KEY0)
desc = HW_DESC_SET_DIN_CONST(desc, 0, 0x10)
self.SaSi_SB_AddDescSequence(desc)
def sbrom_cryptoinitdriver(self, aesivptr, cryptodrivermode):
if cryptodrivermode & 0xFFFFFFFD == 0:
# 0=v9
# 1=0x820
# 2=0
# 3=0
# 4=0x1000825
# 5=v9>>32
pdesc = hw_desc_init()
pdesc = hw_desc_set_din_type(pdesc, DmaMode.DMA_DLLI, aesivptr, 0x20, SB_AXI_ID, AXI_SECURE)
pdesc = hw_desc_set_flow_mode(pdesc, FlowMode.S_DIN_to_HASH)
pdesc = hw_desc_set_cipher_mode(pdesc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
pdesc = hw_desc_set_setup_mode(pdesc, SetupOp.SETUP_LOAD_STATE0)
self.sasi_sb_adddescsequence(pdesc)
# 0=0
# 1=0x8000041
# 2=0
# 3=0
# 4=0x4000825
# 5=0
tdesc = hw_desc_init()
tdesc = hw_desc_set_flow_mode(tdesc, FlowMode.S_DIN_to_HASH)
tdesc = hw_desc_set_cipher_mode(tdesc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
tdesc = hw_desc_set_setup_mode(tdesc, SetupOp.SETUP_LOAD_KEY0)
tdesc = hw_desc_set_din_const(tdesc, 0, 0x10)
self.sasi_sb_adddescsequence(tdesc)
def SBROM_CryptoUpdate(self, inputptr, outputptr, blockSize, islastblock, cryptodrivermode, waitforcrypto):
def sbrom_cryptoupdate(self, inputptr, outputptr, blockSize, islastblock, cryptodrivermode, waitforcrypto):
if waitforcrypto != 2 or self.SB_HalWaitDescCompletion(self.dxcc_base) == 0:
if islastblock == 1 and (cryptodrivermode & 0xFFFFFFFD) == 0:
#0=0
#1=0
#2=outputptr
#3=0x42
#4=0x908082B
#5=outputptr>>32<<16
desc = HW_DESC_INIT()
desc = HW_DESC_SET_DOUT_DLLI(desc, outputptr, 0x10, SB_AXI_ID, 0)
desc = HW_DESC_SET_FLOW_MODE(desc, FlowMode.S_HASH_to_DOUT)
desc = HW_DESC_SET_CIPHER_MODE(desc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
desc = HW_DESC_SET_CIPHER_CONFIG1(desc, sep_hash_mode.SEP_HASH_SHA256)
desc = HW_DESC_SET_SETUP_MODE(desc, SetupOp.SETUP_WRITE_STATE1)
self.SaSi_SB_AddDescSequence(desc)
desc = HW_DESC_INIT()
desc = HW_DESC_SET_DIN_TYPE(desc, DmaMode.DMA_DLLI, inputptr, blockSize, SB_AXI_ID, AXI_SECURE)
# 0=0
# 1=0
# 2=outputptr
# 3=0x42
# 4=0x908082B
# 5=outputptr>>32<<16
ydesc = hw_desc_init()
ydesc = hw_desc_set_dout_dlli(ydesc, outputptr, 0x10, SB_AXI_ID, 0)
ydesc = hw_desc_set_flow_mode(ydesc, FlowMode.S_HASH_to_DOUT)
ydesc = hw_desc_set_cipher_mode(ydesc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
ydesc = hw_desc_set_cipher_config1(ydesc, sep_hash_mode.SEP_HASH_SHA256)
ydesc = hw_desc_set_setup_mode(ydesc, SetupOp.SETUP_WRITE_STATE1)
self.sasi_sb_adddescsequence(ydesc)
udesc = hw_desc_init()
udesc = hw_desc_set_din_type(udesc, DmaMode.DMA_DLLI, inputptr, blockSize, SB_AXI_ID, AXI_SECURE)
if not cryptodrivermode:
desc = HW_DESC_SET_FLOW_MODE(desc, FlowMode.DIN_HASH)
self.SaSi_SB_AddDescSequence(desc)
udesc = hw_desc_set_flow_mode(udesc, FlowMode.DIN_HASH)
self.sasi_sb_adddescsequence(udesc)
if (waitforcrypto == 2 and not islastblock) or waitforcrypto == 3:
self.SB_HalWaitDescCompletion(self.dxcc_base)
elif waitforcrypto == 0:
@ -1326,34 +1329,35 @@ class dxcc(metaclass=LogBase):
else:
return 0xF2000001
def SBROM_CryptoFinishDriver(self, outputptr):
desc = HW_DESC_INIT()
desc = HW_DESC_SET_DOUT_DLLI(desc, outputptr, 0x10, SB_AXI_ID, 0)
desc = HW_DESC_SET_FLOW_MODE(desc, FlowMode.S_HASH_to_DOUT)
desc = HW_DESC_SET_CIPHER_MODE(desc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
desc = HW_DESC_SET_CIPHER_CONFIG0(desc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
desc = HW_DESC_SET_CIPHER_CONFIG1(desc, sep_hash_mode.SEP_HASH_SHA256)
desc = HW_DESC_SET_SETUP_MODE(desc, SetupOp.SETUP_WRITE_STATE0)
#0 = 0
#1 = 0
#2 = outputptr
#3 = 0x82
#4 = 0x80C082B
#5 = outputptr>>32<<16
self.SaSi_SB_AddDescSequence(desc)
def sbrom_cryptofinishdriver(self, outputptr):
fdesc = hw_desc_init()
fdesc = hw_desc_set_dout_dlli(fdesc, outputptr, 0x10, SB_AXI_ID, 0)
fdesc = hw_desc_set_flow_mode(fdesc, FlowMode.S_HASH_to_DOUT)
fdesc = hw_desc_set_cipher_mode(fdesc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
fdesc = hw_desc_set_cipher_config0(fdesc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
fdesc = hw_desc_set_cipher_config1(fdesc, sep_hash_mode.SEP_HASH_SHA256)
fdesc = hw_desc_set_setup_mode(fdesc, SetupOp.SETUP_WRITE_STATE0)
# 0 = 0
# 1 = 0
# 2 = outputptr
# 3 = 0x82
# 4 = 0x80C082B
# 5 = outputptr>>32<<16
self.sasi_sb_adddescsequence(fdesc)
return self.SB_HalWaitDescCompletion(self.dxcc_base)
if __name__=="__main__":
if __name__ == "__main__":
# 0=0
# 1=0
# 2=outputptr
# 3=0x42
# 4=0x908082B
# 5=outputptr>>32<<16
desc = HW_DESC_INIT()
desc = HW_DESC_SET_DOUT_DLLI(desc, 0, 0x10, SB_AXI_ID, 0)
desc = HW_DESC_SET_FLOW_MODE(desc, FlowMode.S_HASH_to_DOUT)
desc = HW_DESC_SET_CIPHER_MODE(desc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
desc = HW_DESC_SET_CIPHER_CONFIG1(desc, sep_hash_mode.SEP_HASH_SHA256)
desc = HW_DESC_SET_SETUP_MODE(desc, SetupOp.SETUP_WRITE_STATE1)
desc = hw_desc_init()
desc = hw_desc_set_dout_dlli(desc, 0, 0x10, SB_AXI_ID, 0)
desc = hw_desc_set_flow_mode(desc, FlowMode.S_HASH_to_DOUT)
desc = hw_desc_set_cipher_mode(desc, sep_hash_hw_mode.SEP_HASH_HW_SHA256)
desc = hw_desc_set_cipher_config1(desc, sep_hash_mode.SEP_HASH_SHA256)
desc = hw_desc_set_setup_mode(desc, SetupOp.SETUP_WRITE_STATE1)
print(desc)

View file

@ -702,13 +702,14 @@ class DALegacy(metaclass=LogBase):
if pdram[0] in data or pdram[1] in data:
preloader = os.path.join(root, file)
print("Detected preloader: " + preloader)
self.daconfig.extract_emi(preloader,True)
self.daconfig.extract_emi(preloader)
found = True
break
if found:
break
if self.usbread(4) == pack(">I", 0xBC4): # Nand_Status
nand_id_count = unpack(">H", self.usbread(2))[0]
self.info("Reading nand info ...")
nand_ids = []
for i in range(0, nand_id_count):
nand_ids.append(unpack(">H", self.usbread(2))[0])
@ -724,6 +725,7 @@ class DALegacy(metaclass=LogBase):
val = 0x14
self.usbwrite(pack(">I", val))
if self.usbread(1) == self.Rsp.ACK:
self.info("Sending dram info ...")
dramlength = len(self.daconfig.emi)
if val in [0x10, 0x14, 0x15]:
dramlength = unpack(">I", self.usbread(0x4))[0] # 0x000000BC
@ -745,7 +747,7 @@ class DALegacy(metaclass=LogBase):
self.debug(f"M_EXT_RAM_RET : {m_ext_ram_ret}")
if m_ext_ram_ret != 0:
self.error("Preloader error: %d => %s" % (m_ext_ram_ret, error_to_string(m_ext_ram_ret)))
self.mtk.port.close()
self.mtk.port.close(reset=False)
sys.exit(0)
m_ext_ram_type = self.usbread(1)[0] # 0x02 HW_RAM_DRAM
self.debug(f"M_EXT_RAM_TYPE : {m_ext_ram_type}")
@ -755,7 +757,7 @@ class DALegacy(metaclass=LogBase):
self.debug(f"M_EXT_RAM_SIZE : {m_ext_ram_size}")
else:
self.error("Preloader needed due to dram config.")
self.mtk.port.close()
self.mtk.port.close(reset=True)
sys.exit(0)
return buffer
@ -857,14 +859,13 @@ class DALegacy(metaclass=LogBase):
self.daconfig.flashsize = self.sdc["m_sdmmc_ua_size"]
elif self.daconfig.flashtype == "nor":
self.daconfig.flashsize = self.nor["m_nor_flash_size"]
if os.name != "nt":
self.info("Reconnecting to preloader")
self.set_usb_cmd()
self.mtk.port.close()
time.sleep(2)
while not self.mtk.port.cdc.connect():
time.sleep(0.5)
self.info("Connected to preloader")
self.info("Reconnecting to preloader")
self.set_usb_cmd()
self.mtk.port.close(reset=False)
time.sleep(2)
while not self.mtk.port.cdc.connect():
time.sleep(0.5)
self.info("Connected to preloader")
self.check_usb_cmd()
return True
return False
@ -904,7 +905,7 @@ class DALegacy(metaclass=LogBase):
def close(self):
self.finish(0x0) # DISCONNECT_USB_AND_RELEASE_POWERKEY
self.mtk.port.close()
self.mtk.port.close(reset=True)
def brom_send(self, dasetup, da, stage, packetsize=0x1000):
offset = dasetup.da[stage]["m_buf"]
@ -972,7 +973,7 @@ class DALegacy(metaclass=LogBase):
return True
return False
def sdmmc_write_data(self, addr, length, filename, offset=0, parttype=None, display=True):
def sdmmc_write_data(self, addr, length, filename, offset=0, parttype=None, wdata=None, display=True):
if parttype is None or parttype == "user":
length = min(length, self.emmc["m_emmc_ua_size"])
parttype = EMMC_PartitionType.MTK_DA_EMMC_PART_USER
@ -1008,34 +1009,39 @@ class DALegacy(metaclass=LogBase):
else:
storage = DaStorage.MTK_DA_STORAGE_EMMC
if filename != "":
with open(filename, "rb") as rf:
rf.seek(offset)
self.progress.show_progress("Write", 0, 100, display)
self.usbwrite(self.Cmd.SDMMC_WRITE_DATA_CMD)
self.usbwrite(pack(">B", storage))
self.usbwrite(pack(">B", parttype))
self.usbwrite(pack(">Q", addr))
self.usbwrite(pack(">Q", length))
self.usbwrite(pack(">I", 0x100000))
if self.usbread(1) != self.Rsp.ACK:
self.error("Couldn't send sdmmc_write_data header")
return False
offset = 0
while offset < length:
self.usbwrite(self.Rsp.ACK)
count = min(0x100000, length - offset)
data = bytearray(rf.read(count))
self.usbwrite(data)
chksum = sum(data) & 0xFFFF
self.usbwrite(pack(">H", chksum))
if self.usbread(1) != self.Rsp.CONT_CHAR:
self.error("Data ack failed for sdmmc_write_data")
return False
self.progress.show_progress("Write",offset,length,display)
offset += count
self.progress.show_progress("Write", 100, 100, display)
return True
if filename is not None:
fh=open(filename, "rb")
fh.seek(offset)
self.progress.show_progress("Write", 0, 100, display)
self.usbwrite(self.Cmd.SDMMC_WRITE_DATA_CMD)
self.usbwrite(pack(">B", storage))
self.usbwrite(pack(">B", parttype))
self.usbwrite(pack(">Q", addr))
self.usbwrite(pack(">Q", length))
self.usbwrite(pack(">I", 0x100000))
if self.usbread(1) != self.Rsp.ACK:
self.error("Couldn't send sdmmc_write_data header")
return False
offset = 0
while offset < length:
self.usbwrite(self.Rsp.ACK)
count = min(0x100000, length - offset)
if fh:
data = bytearray(fh.read(count))
else:
data = wdata[offset:offset+count]
self.usbwrite(data)
chksum = sum(data) & 0xFFFF
self.usbwrite(pack(">H", chksum))
if self.usbread(1) != self.Rsp.CONT_CHAR:
self.error("Data ack failed for sdmmc_write_data")
return False
self.progress.show_progress("Write",offset,length,display)
offset += count
if fh:
fh.close()
self.progress.show_progress("Write", 100, 100, display)
return True
def sdmmc_write_image(self, addr, length, filename, display=True):
if filename != "":
@ -1080,9 +1086,9 @@ class DALegacy(metaclass=LogBase):
return True
return True
def writeflash(self, addr, length, filename, partitionname, offset=0, parttype=None, display=True):
def writeflash(self, addr, length, filename, offset=0, parttype=None, wdata=None, display=True):
return self.sdmmc_write_data(addr=addr, length=length, filename=filename, offset=offset, parttype=parttype,
display=display)
wdata=wdata, display=display)
def formatflash(self, addr, length, parttype=None, display=True):
if parttype is None or parttype == "user" or parttype == "":
@ -1212,7 +1218,7 @@ class DALegacy(metaclass=LogBase):
size = bytestoread
if bytestoread > packetsize:
size = packetsize
wf.write(self.usbread(size,0x400))
wf.write(self.usbread(size))
bytestoread -= size
checksum = unpack(">H", self.usbread(1)+self.usbread(1))[0]
self.debug("Checksum: %04X" % checksum)
@ -1227,7 +1233,7 @@ class DALegacy(metaclass=LogBase):
size = bytestoread
if bytestoread > packetsize:
size = packetsize
buffer.extend(self.usbread(size,0x400))
buffer.extend(self.usbread(size))
bytestoread -= size
checksum = unpack(">H", self.usbread(2))[0]
self.debug("Checksum: %04X" % checksum)

View file

@ -9,12 +9,14 @@ from mtkclient.Library.error import ErrorHandler
from mtkclient.Library.daconfig import DAconfig
from mtkclient.Library.mtk_dalegacy import DALegacy
from mtkclient.Library.mtk_daxflash import DAXFlash
from mtkclient.config.brom_config import damodes
from mtkclient.Library.xflash_ext import xflashext
class DAloader(metaclass=LogBase):
def __init__(self, mtk, loglevel=logging.INFO):
self.__logger = logsetup(self, self.__logger, loglevel)
self.mtk = mtk
self.config = mtk.config
self.loglevel = loglevel
self.eh = ErrorHandler()
self.config = self.mtk.config
@ -26,14 +28,16 @@ class DAloader(metaclass=LogBase):
self.rword = self.mtk.port.rword
self.daconfig = DAconfig(mtk=self.mtk, loader=self.mtk.config.loader,
preloader=self.mtk.config.preloader, loglevel=loglevel)
self.xft = None
self.da = None
def writestate(self):
config = {}
config["xflash"] = self.xflash
config["xflash"] = self.mtk.config.chipconfig.damode==damodes.XFLASH
config["hwcode"] = self.config.hwcode
config["flashtype"] = self.daconfig.flashtype
config["flashsize"] = self.daconfig.flashsize
if not self.xflash:
if not self.mtk.config.chipconfig.damode==damodes.XFLASH:
config["m_emmc_ua_size"] = self.da.emmc["m_emmc_ua_size"]
config["m_emmc_boot1_size"] = self.da.emmc["m_emmc_boot1_size"]
config["m_emmc_boot2_size"] = self.da.emmc["m_emmc_boot2_size"]
@ -47,12 +51,15 @@ class DAloader(metaclass=LogBase):
def reinit(self):
if os.path.exists(".state"):
config = json.loads(open(".state", "r").read())
xflash = config["xflash"]
if xflash:
self.config.hwcode = config["hwcode"]
self.xflash = config["xflash"]
self.config.init_hwcode(self.config.hwcode)
if self.xflash:
self.da = DAXFlash(self.mtk, self.daconfig, self.loglevel)
self.daconfig.flashtype = config["flashtype"]
self.daconfig.flashsize = config["flashsize"]
self.da.reinit()
self.xft=xflashext(self.mtk, self.da, self.loglevel)
else:
self.da = DALegacy(self.mtk, self.daconfig, self.loglevel)
self.daconfig.flashtype = config["flashtype"]
@ -69,6 +76,7 @@ class DAloader(metaclass=LogBase):
self.da.nand["m_nand_flash_size"] = config["m_nand_flash_size"]
self.da.sdc["m_sdmmc_ua_size"] = config["m_sdmmc_ua_size"]
self.da.nor["m_nor_flash_size"] = config["m_nor_flash_size"]
self.xft = None
return True
return False
@ -83,6 +91,7 @@ class DAloader(metaclass=LogBase):
self.xflash = True
if self.xflash:
self.da = DAXFlash(self.mtk, self.daconfig, self.loglevel)
self.xft = xflashext(self.mtk, self.da, self.loglevel)
else:
self.da = DALegacy(self.mtk, self.daconfig, self.loglevel)
@ -127,16 +136,52 @@ class DAloader(metaclass=LogBase):
def upload_da(self, preloader=None):
self.daconfig.setup()
self.daconfig.extract_emi(preloader, legacy=self.mtk.config.chipconfig.damode == 0)
self.daconfig.extract_emi(preloader)
self.set_da()
return self.da.upload_da()
def writeflash(self, addr, length, filename, partitionname, offset=0, parttype=None, display=True):
def writeflash(self, addr, length, filename, offset=0, parttype=None, wdata=None, display=True):
return self.da.writeflash(addr=addr, length=length, filename=filename, offset=offset,
partitionname=partitionname, parttype=parttype, display=display)
parttype=parttype, wdata=wdata, display=display)
def formatflash(self, addr, length, partitionname, parttype, display=True):
return self.da.formatflash(addr=addr, length=length, parttype=parttype)
def readflash(self, addr, length, filename, parttype, display=True):
return self.da.readflash(addr=addr, length=length, filename=filename, parttype=parttype, display=display)
def peek(self, addr: int, length:int):
if self.xflash:
return self.xft.custom_read(addr=addr, length=length)
self.error("Device is not in xflash mode, cannot run peek cmd.")
return b""
def poke(self, addr: int, data: bytes or bytearray):
if self.xflash:
return self.xft.custom_write(addr=addr, data=data)
self.error("Device is not in xflash mode, cannot run poke cmd.")
return False
def keys(self):
if self.xflash:
return self.xft.generate_keys()
self.error("Device is not in xflash mode, cannot run keys cmd.")
return False
def seccfg(self, lockflag):
if self.xflash:
return self.xft.seccfg(lockflag)
self.error("Device is not in xflash mode, cannot run unlock cmd.")
return False
def read_rpmb(self, filename=None):
if self.xflash:
return self.xft.read_rpmb(filename)
self.error("Device is not in xflash mode, cannot run read rpmb cmd.")
return False
def write_rpmb(self, filename=None):
if self.xflash:
return self.xft.write_rpmb(filename)
self.error("Device is not in xflash mode, cannot run write rpmb cmd.")
return False

File diff suppressed because it is too large Load diff

View file

@ -124,6 +124,8 @@ class Preloader(metaclass=LogBase):
self.sendcmd = self.mtk.port.mtk_cmd
def init(self, maxtries=None, display=True):
if os.path.exists(".state"):
os.remove(".state")
readsocid=self.config.readsocid
skipwdt = self.config.skipwdt
@ -166,6 +168,15 @@ class Preloader(metaclass=LogBase):
self.info("\tCQ_DMA addr:\t\t" + hex(self.config.chipconfig.cqdma_base))
self.info("\tVar1:\t\t\t" + hex(self.config.chipconfig.var1))
if not skipwdt:
if self.display:
self.info("Disabling Watchdog...")
self.setreg_disablewatchdogtimer(self.config.hwcode) # D4
if self.display:
self.info("HW code:\t\t\t" + hex(self.config.hwcode))
with open(os.path.join("logs", "hwcode.txt"), "w") as wf:
wf.write(hex(self.config.hwcode))
self.config.target_config = self.get_target_config(self.display)
res = self.get_hw_sw_ver()
self.config.hwsubcode = 0
self.config.hwver = 0
@ -178,17 +189,6 @@ class Preloader(metaclass=LogBase):
self.info("\tHW subcode:\t\t" + hex(self.config.hwsubcode))
self.info("\tHW Ver:\t\t\t" + hex(self.config.hwver))
self.info("\tSW Ver:\t\t\t" + hex(self.config.swver))
if not skipwdt:
if self.display:
self.info("Disabling Watchdog...")
self.setreg_disablewatchdogtimer(self.config.hwcode) # D4
if self.display:
self.info("HW code:\t\t\t" + hex(self.config.hwcode))
with open(os.path.join("logs", "hwcode.txt"), "w") as wf:
wf.write(hex(self.config.hwcode))
self.config.target_config = self.get_target_config(self.display)
# blver = self.get_blver()
meid = self.get_meid()
if len(meid) >= 16:
with open(os.path.join("logs", "meid.txt"), "wb") as wf:

View file

@ -16,13 +16,13 @@ class Partition(metaclass=LogBase):
def get_gpt(self, gpt_num_part_entries, gpt_part_entry_size, gpt_part_entry_start_lba, parttype="user"):
data = self.readflash(addr=0, length=2 * self.config.pagesize, filename="", parttype=parttype, display=False)
if data[:9] == b"EMMC_BOOT" and self.read_pmt:
if data[:9] == b"EMMC_BOOT" and self.read_pmt is not None:
partdata, partentries = self.read_pmt()
if partdata == b"":
return None, None
else:
return partdata, partentries
elif data[:8] == b"UFS_BOOT" and self.read_pmt:
elif data[:8] == b"UFS_BOOT" and self.read_pmt is not None:
partdata, partentries = self.read_pmt()
if partdata == b"":
return None, None

View file

@ -182,7 +182,7 @@ class PLTools(metaclass=LogBase):
def crasher(self, mtk, enforcecrash):
plt = PLTools(mtk, self.__logger.level)
if enforcecrash or not (mtk.port.cdc.vid == 0xE8D and mtk.port.cdc.pid == 0x0003):
if enforcecrash or self.config.meid is None:
self.info("We're not in bootrom, trying to crash da...")
for crashmode in range(0, 3):
try:

138
mtkclient/Library/usblib.py Normal file → Executable file
View file

@ -9,7 +9,6 @@ import usb.util
import time
import inspect
import traceback
import array
import usb.backend.libusb0
import usb.backend.libusb1
from struct import calcsize
@ -73,7 +72,7 @@ class usb_class(metaclass=LogBase):
def __init__(self, loglevel=logging.INFO, portconfig=None, devclass=-1):
self.load_windows_dll()
self.connected = False
self.timeout = None
self.timeout = 1000
self.vid = None
self.pid = None
self.stopbits = None
@ -94,7 +93,6 @@ class usb_class(metaclass=LogBase):
self.warning = self.__logger.warning
self.debug = self.__logger.debug
self.__logger.setLevel(loglevel)
self.buffer = array.array('B', [0]) * 1048576
if loglevel == logging.DEBUG:
logfilename = os.path.join("logs", "log.txt")
fh = logging.FileHandler(logfilename)
@ -103,7 +101,7 @@ class usb_class(metaclass=LogBase):
if sys.platform.startswith('freebsd') or sys.platform.startswith('linux'):
self.backend = usb.backend.libusb1.get_backend(find_library=lambda x: "libusb-1.0.so")
elif sys.platform.startswith('win32'):
if calcsize("P")*8==64:
if calcsize("P") * 8 == 64:
self.backend = usb.backend.libusb1.get_backend(find_library=lambda x: "libusb-1.0.dll")
else:
self.backend = usb.backend.libusb1.get_backend(find_library=lambda x: "libusb32-1.0.dll")
@ -284,6 +282,9 @@ class usb_class(metaclass=LogBase):
if e.errno == 13:
self.backend = usb.backend.libusb0.get_backend()
self.device = usb.core.find(idVendor=self.vid, idProduct=self.pid, backend=self.backend)
if self.configuration is None:
self.error("Couldn't get device configuration.")
return False
if self.interface == -1:
for interfacenum in range(0, self.configuration.bNumInterfaces):
itf = usb.util.find_descriptor(self.configuration, bInterfaceNumber=interfacenum)
@ -303,9 +304,9 @@ class usb_class(metaclass=LogBase):
if self.interface != -1:
itf = usb.util.find_descriptor(self.configuration, bInterfaceNumber=self.interface)
try:
if self.device.is_kernel_driver_active(self.interface):
if self.device.is_kernel_driver_active(0):
self.debug("Detaching kernel driver")
self.device.detach_kernel_driver(self.interface)
self.device.detach_kernel_driver(0)
except Exception as err:
self.debug("No kernel driver supported: " + str(err))
try:
@ -314,7 +315,13 @@ class usb_class(metaclass=LogBase):
pass
try:
if self.interface!=0:
if self.device.is_kernel_driver_active(self.interface):
self.debug("Detaching kernel driver")
self.device.detach_kernel_driver(self.interface)
except Exception as err:
self.debug("No kernel driver supported: " + str(err))
try:
if self.interface != 0:
usb.util.claim_interface(self.device, self.interface)
except:
pass
@ -346,12 +353,11 @@ class usb_class(metaclass=LogBase):
def close(self, reset=False):
if self.connected:
try:
# self.device.reset()
if reset:
self.device.reset()
if not self.device.is_kernel_driver_active(self.interface):
# self.device.attach_kernel_driver(self.interface) #Do NOT uncomment
self.device.attach_kernel_driver(0)
if reset:
self.device.reset()
except Exception as err:
self.debug(str(err))
pass
@ -371,7 +377,7 @@ class usb_class(metaclass=LogBase):
except usb.core.USBError as err:
error = str(err.strerror)
if "timeout" in error:
time.sleep(0.01)
# time.sleep(0.01)
try:
self.EP_OUT.write(b'')
except Exception as err:
@ -382,12 +388,14 @@ class usb_class(metaclass=LogBase):
i = 0
while pos < len(command):
try:
self.EP_OUT.write(command[pos:pos + pktsize])
ctr = self.EP_OUT.write(command[pos:pos + pktsize])
if ctr <= 0:
self.info(ctr)
pos += pktsize
except Exception as err:
self.debug(str(err))
# print("Error while writing")
time.sleep(0.01)
# time.sleep(0.01)
i += 1
if i == 3:
return False
@ -395,43 +403,38 @@ class usb_class(metaclass=LogBase):
self.verify_data(bytearray(command), "TX:")
return True
def read(self, maxlength=None, timeout=None):
if maxlength is None:
maxlength=self.EP_IN.wMaxPacketSize
if self.loglevel == logging.DEBUG:
self.debug(inspect.currentframe().f_back.f_code.co_name + ":" + hex(maxlength))
rxBuffer = array.array('B')
extend = rxBuffer.extend
if timeout is None:
timeout = self.timeout
buffer = self.buffer[:maxlength]
ep_read = self.EP_IN.read
while len(rxBuffer) == 0:
def usbread(self, resplen):
if resplen <= 0:
self.info("Warning !")
res = bytearray()
timeout = 0
loglevel = self.loglevel
epr = self.EP_IN.read
wMaxPacketSize = self.EP_IN.wMaxPacketSize
extend = res.extend
while len(res) < resplen:
try:
length = ep_read(buffer, timeout)
extend(buffer[:length])
if len(rxBuffer) > 0:
if self.loglevel == logging.DEBUG:
self.verify_data(rxBuffer, "RX:")
return bytearray(rxBuffer)
extend(epr(resplen))
except usb.core.USBError as e:
error = str(e.strerror)
if "timed out" in error:
# if platform.system()=='Windows':
# time.sleep(0.05)
# print("Waiting...")
self.debug("Timed out")
self.debug(rxBuffer)
return bytearray(rxBuffer)
if timeout == 4:
return b""
timeout += 1
pass
elif "Overflow" in error:
self.error("USB Overflow")
sys.exit(0)
elif e.errno is not None:
print(repr(e), type(e), e.errno)
sys.exit(0)
return b""
else:
break
return bytearray(rxBuffer)
self.info(repr(e), type(e), e.errno)
return b""
if loglevel == logging.DEBUG:
self.debug(inspect.currentframe().f_back.f_code.co_name + ":" + hex(resplen))
if self.loglevel == logging.DEBUG:
self.verify_data(res[:resplen], "RX:")
return res[:resplen]
def ctrl_transfer(self, bmRequestType, bRequest, wValue, wIndex, data_or_wLength):
ret = self.device.ctrl_transfer(bmRequestType=bmRequestType, bRequest=bRequest, wValue=wValue, wIndex=wIndex,
@ -454,9 +457,9 @@ class usb_class(metaclass=LogBase):
def usbwrite(self, data, pktsize=None):
if pktsize is None:
pktsize = len(data)
size = self.write(data, pktsize)
res = self.write(data, pktsize)
# port->flush()
return size
return res
def usbreadwrite(self, data, resplen):
self.usbwrite(data) # size
@ -487,25 +490,6 @@ class usb_class(metaclass=LogBase):
def rbyte(self, count=1):
return self.usbread(count)
def usbread(self, resplen, size=None):
if size is None:
size = resplen
res = bytearray()
timeout = 0
while len(res) < resplen:
v=self.read(size)
res.extend(v)
if len(res) == resplen:
break
if len(res) == 0:
time.sleep(0.001)
if timeout == 4:
return res
timeout += 1
elif len(v)==0:
break
return res
class scsi_cmds(Enum):
SC_TEST_UNIT_READY = 0x00,
@ -671,8 +655,9 @@ class scsi:
print("Sent HTC ums adb enable command: %x" % ret)
def send_zte_adbenable(self): # zte blade
common_cmnd = b"\x86zte\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # reserve_cmd + 'zte' + len + flag
common_cmnd2 = b"\x86zte\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # reserve_cmd + 'zte' + len + flag
# reserve_cmd + 'zte' + len + flag
cmnds = [b"\x86zte\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
b"\x86zte\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"]
'''
Flag values:
0: disable adbd ---for 736T
@ -681,23 +666,24 @@ class scsi:
3: enable adbd ---for All except 736T
'''
lun = 0
datasize = common_cmnd[4]
timeout = 5000
ret_tag = self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
ret_tag += self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
ret_tag = self.send_mass_storage_command(lun, common_cmnd2, USB_DIR_IN, datasize)
ret_tag += self.send_mass_storage_command(lun, common_cmnd2, USB_DIR_IN, datasize)
for cmnd in cmnds:
datasize = cmnd[4]
ret_tag = self.send_mass_storage_command(lun, cmnd, USB_DIR_IN, datasize)
ret_tag += self.send_mass_storage_command(lun, cmnd, USB_DIR_IN, datasize)
if datasize > 0:
data = self.usb.read(datasize, timeout)
print("DATA: " + hexlify(data).decode('utf-8'))
print("Send HTC adb enable command")
def send_fih_adbenable(self): # motorola xt560, nokia 3.1, #f_mass_storage.c
def send_fih_adbenable(self):
# motorola xt560, nokia 3.1, #f_mass_storage.c
if self.usb.connect():
print("Sending FIH adb enable command")
datasize = 0x24
common_cmnd = bytes([self.SC_SWITCH_PORT]) + b"FI1" + struct.pack("<H",
datasize) # reserve_cmd + 'FI' + flag + len + none
datasize)
# reserve_cmd + 'FI' + flag + len + none
'''
Flag values:
common_cmnd[3]->1: Enable adb daemon from mass_storage
@ -728,13 +714,15 @@ class scsi:
print("Sent alcatel adb enable command")
self.usb.close()
def send_fih_root(
self): # motorola xt560, nokia 3.1, huawei u8850, huawei Ideos X6, lenovo s2109, triumph M410, viewpad 7, #f_mass_storage.c
def send_fih_root(self):
# motorola xt560, nokia 3.1, huawei u8850, huawei Ideos X6,
# lenovo s2109, triumph M410, viewpad 7, #f_mass_storage.c
if self.usb.connect():
print("Sending FIH root command")
datasize = 0x24
common_cmnd = bytes([self.SC_SWITCH_ROOT]) + b"FIH" + struct.pack("<H",
datasize) # reserve_cmd + 'FIH' + len + flag + none
datasize)
# reserve_cmd + 'FIH' + len + flag + none
lun = 0
# datasize = common_cmnd[4]
timeout = 5000

View file

@ -13,6 +13,7 @@ import colorama
import copy
import time
import io
import datetime as dt
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
@ -28,27 +29,71 @@ except ImportError:
from struct import unpack, pack
def find_binary(data, strf, pos=0):
t = strf.split(b".")
pre = 0
offsets = []
while pre != -1:
pre = data[pos:].find(t[0], pre)
if pre == -1:
if len(offsets) > 0:
for offset in offsets:
error = 0
rt = offset + len(t[0])
for i in range(1, len(t)):
if t[i] == b'':
rt += 1
continue
rt += 1
prep = data[rt:].find(t[i])
if prep != 0:
error = 1
break
rt += len(t[i])
if error == 0:
return offset
else:
return None
else:
offsets.append(pre)
pre += 1
return None
class progress:
def __init__(self, pagesize):
self.progtime = 0
self.prog = 0
self.progpos = 0
self.start = time.time()
self.pagesize = pagesize
def calcProcessTime(self, starttime, cur_iter, max_iter):
telapsed = time.time() - starttime
if telapsed > 0 and cur_iter > 0:
testimated = (telapsed / cur_iter) * (max_iter)
finishtime = starttime + testimated
finishtime = dt.datetime.fromtimestamp(finishtime).strftime("%H:%M:%S") # in time
lefttime = testimated - telapsed # in seconds
return (int(telapsed), int(lefttime), finishtime)
else:
return 0,0,""
def show_progress(self, prefix, pos, total, display=True):
t0 = time.time()
prog = round(float(pos) / float(total) * float(100), 2)
prog = round(float(pos) / float(total) * float(100), 1)
if prog == 0:
self.prog = 0
self.start = time.time()
self.progtime = time.time()
self.progpos = pos
print_progress(prog, 100, prefix='Progress:',
suffix=prefix + ' (Sector %d of %d) %0.2f MB/s' %
print_progress(prog, 100, prefix='Done',
suffix=prefix + ' (Sector 0x%X of 0x%X) %0.2f MB/s' %
(pos // self.pagesize,
total // self.pagesize,
0), bar_length=50)
if prog > self.prog:
if display:
t0 = time.time()
tdiff = t0 - self.progtime
datasize = (pos - self.progpos) / 1024 / 1024
if datasize != 0 and tdiff != 0:
@ -58,8 +103,24 @@ class progress:
throughput = 0
else:
throughput = 0
telapsed, lefttime, finishtime = self.calcProcessTime(self.start, prog, 100)
hinfo = ""
if lefttime > 0:
sec = lefttime
if sec > 60:
min = sec // 60
sec = sec % 60
if min > 60:
h = min // 24
min = min % 24
hinfo = "%02dh:%02dm:%02ds left" % (h, min, sec)
else:
hinfo = "%02dm:%02ds left" % (min, sec)
else:
hinfo = "%02ds left" % sec
print_progress(prog, 100, prefix='Progress:',
suffix=prefix + ' (Sector %d of %d) %0.2f MB/s' %
suffix=prefix + f' (Sector 0x%X of 0x%X, {hinfo}) %0.2f MB/s' %
(pos // self.pagesize,
total // self.pagesize,
throughput), bar_length=50)

View file

@ -0,0 +1,510 @@
import os
from struct import unpack, pack
from mtkclient.config.payloads import pathconfig
from mtkclient.Library.error import ErrorHandler
from mtkclient.Library.hwcrypto import crypto_setup, hwcrypto
from mtkclient.Library.utils import LogBase, progress, logsetup, find_binary
from binascii import hexlify
import hashlib
class XCmd:
CUSTOM_ACK = 0x0F0000
CUSTOM_READ = 0x0F0001
CUSTOM_WRITE = 0x0F0002
CUSTOM_WRITEREGISTER = 0x0F0003
CUSTOM_INIT_RPMB = 0x0F0004
CUSTOM_READ_RPMB = 0x0F0005
CUSTOM_WRITE_RPMB = 0x0F0006
CUSTOM_INIT_UFS_RPMB = 0x0F0007
CUSTOM_READ_UFS_RPMB = 0x0F0008
CUSTOM_WRITE_UFS_RPMB = 0x0F0009
class seccfg:
def __init__(self, hwc):
self.hwc = hwc
self.magic = 0x4D4D4D4D
self.seccfg_ver = None
self.seccfg_size = None
self.lock_state = None
self.critical_lock_state = None
self.sboot_runtime = None
self.endflag = 0x45454545
self.hash = b""
def parse(self, data):
seccfg_data = unpack("<IIIIIII", data[:7 * 4])
self.magic, self.seccfg_ver, self.seccfg_size, self.lock_state, self.critical_lock_state, \
self.sboot_runtime, self.endflag = seccfg_data
self.hash = data[7 * 4:(7 * 4) + 32]
if self.magic != 0x4D4D4D4D or self.endflag != 0x45454545:
self.error("Unknown seccfg structure !")
return False
return True
"""
LKS_DEFAULT = 0x01
LKS_MP_DEFAULT = 0x02
LKS_UNLOCK = 0x03
LKS_LOCK = 0x04
LKS_VERIFIED = 0x05
LKS_CUSTOM = 0x06
LKCS_UNLOCK = 0x01
LKCS_LOCK = 0x02
SBOOT_RUNTIME_OFF = 0
SBOOT_RUNTIME_ON = 1
"""
def create(self, lockflag: str, locktype: str):
if lockflag == "unlock":
self.lock_state = 3
self.critical_lock_state = 1
elif lockflag == "lock":
self.lock_state = 1
self.critical_lock_state = 0
self.seccfg_ver = 4
self.seccfg_size = 0x3C
self.sboot_runtime = 0
seccfg_data = pack("<IIIIIII", self.magic, self.seccfg_ver, self.seccfg_size, self.lock_state,
self.critical_lock_state, self.sboot_runtime, 0x45454545)
dec_hash = hashlib.sha256(seccfg_data).digest()
if locktype == "sw":
enc_hash = self.hwc.sej.sej_sec_cfg_sw(dec_hash, True)
else:
enc_hash = self.hwc.sej.sej_sec_cfg_hw(dec_hash, True)
self.hash = enc_hash
data = seccfg_data + enc_hash
data += b"\x00" * (0x200 - len(data))
return bytearray(data)
class xflashext(metaclass=LogBase):
def __init__(self, mtk, xflash, loglevel):
self.pathconfig = pathconfig()
self.__logger = logsetup(self, self.__logger, loglevel)
self.info = self.__logger.info
self.debug = self.__logger.debug
self.error = self.__logger.error
self.warning = self.__logger.warning
self.mtk = mtk
self.loglevel = loglevel
self.__logger = self.__logger
self.eh = ErrorHandler()
self.config = self.mtk.config
self.usbwrite = self.mtk.port.usbwrite
self.usbread = self.mtk.port.usbread
self.echo = self.mtk.port.echo
self.rbyte = self.mtk.port.rbyte
self.rdword = self.mtk.port.rdword
self.rword = self.mtk.port.rword
self.xflash = xflash
self.xsend = self.xflash.xsend
self.send_devctrl = self.xflash.send_devctrl
self.xread = self.xflash.xread
self.status = self.xflash.status
self.da2 = None
self.da2address = None
def patch(self):
self.da2 = self.xflash.daconfig.da2
self.da2address = self.xflash.daconfig.da[3]["m_start_addr"] # at_address
daextensions = os.path.join(self.pathconfig.get_payloads_path(), "da_x.bin")
if os.path.exists(daextensions):
daextdata = bytearray(open(daextensions, "rb").read())
# open("out" + hex(self.da2address) + ".da", "wb").write(da2)
register_cmd = find_binary(self.da2, b"\x38\xB5\x05\x46\x0C\x20")
# sec_enc_seccfg = find_binary(self.da2, b"\x0E\x4B\x70\xB5\x06\x46")
mmc_get_card = find_binary(self.da2, b"\x4B\x4F\xF4\x3C\x72")
if mmc_get_card is not None:
mmc_get_card -= 1
else:
mmc_get_card = find_binary(self.da2, b"\xA3\xEB\x00\x13\x18\x1A\x02\xEB\x00\x10")
if mmc_get_card is not None:
mmc_get_card -= 10
mmc_set_part_config = find_binary(self.da2, b"\xC3\x69\x0A\x46\x10\xB5")
if mmc_set_part_config is None:
mmc_set_part_config = find_binary(self.da2, b"\xC3\x69\x13\xF0\x01\x03")
mmc_rpmb_send_command = find_binary(self.da2, b"\xF8\xB5\x06\x46\x9D\xF8\x18\x50")
if mmc_rpmb_send_command is None:
mmc_rpmb_send_command = find_binary(self.da2, b"\x2D\xE9\xF0\x41\x4F\xF6\xFD\x74")
register_ptr = daextdata.find(b"\x11\x11\x11\x11")
mmc_get_card_ptr = daextdata.find(b"\x22\x22\x22\x22")
mmc_set_part_config_ptr = daextdata.find(b"\x33\x33\x33\x33")
mmc_rpmb_send_command_ptr = daextdata.find(b"\x44\x44\x44\x44")
ufshcd_queuecommand_ptr = daextdata.find(b"\x55\x55\x55\x55")
ufshcd_get_free_tag_ptr = daextdata.find(b"\x66\x66\x66\x66")
ptr_g_ufs_hba_ptr = daextdata.find(b"\x77\x77\x77\x77")
g_ufs_hba = None
ptr_g_ufs_hba = find_binary(self.da2,b"\x20\x46\x0B\xB0\xBD\xE8\xF0\x83\x00\xBF")
if ptr_g_ufs_hba is None:
ptr_g_ufs_hba = find_binary(self.da2, b"\x21\x46\x02\xF0\x02\xFB\x1B\xE6\x00\xBF")
if ptr_g_ufs_hba is not None:
g_ufs_hba = int.from_bytes(self.da2[ptr_g_ufs_hba + 10+0x8:ptr_g_ufs_hba + 10+0x8 + 4], 'little')
else:
g_ufs_hba = int.from_bytes(self.da2[ptr_g_ufs_hba + 10:ptr_g_ufs_hba + 10 + 4], 'little')
#open("da2_"+hex(self.da2address)+".bin","wb").write(self.da2)
if ptr_g_ufs_hba is not None:
ufshcd_get_free_tag = find_binary(self.da2,b"\xB5.\xB1\x90\xF8")
ufshcd_queuecommand = find_binary(self.da2,b"\x2D\xE9\xF8\x43\x01\x27")
else:
g_ufs_hba = None
ufshcd_get_free_tag = None
ufshcd_queuecommand = None
if register_ptr != -1 and mmc_get_card_ptr != -1:
if register_cmd:
register_cmd = register_cmd + self.da2address | 1
else:
register_cmd = 0
if mmc_get_card:
mmc_get_card = mmc_get_card + self.da2address | 1
else:
mmc_get_card = 0
if mmc_set_part_config:
mmc_set_part_config = mmc_set_part_config + self.da2address | 1
else:
mmc_set_part_config = 0
if mmc_rpmb_send_command:
mmc_rpmb_send_command = mmc_rpmb_send_command + self.da2address | 1
else:
mmc_rpmb_send_command = 0
if ufshcd_get_free_tag:
ufshcd_get_free_tag = ufshcd_get_free_tag + (self.da2address - 1) | 1
else:
ufshcd_get_free_tag = 0
if ufshcd_queuecommand:
ufshcd_queuecommand = ufshcd_queuecommand + self.da2address | 1
else:
ufshcd_queuecommand = 0
if g_ufs_hba is None:
g_ufs_hba = 0
# Patch the addr
daextdata[register_ptr:register_ptr + 4] = pack("<I", register_cmd)
daextdata[mmc_get_card_ptr:mmc_get_card_ptr + 4] = pack("<I", mmc_get_card)
daextdata[mmc_set_part_config_ptr:mmc_set_part_config_ptr+4] = pack("<I",mmc_set_part_config)
daextdata[mmc_rpmb_send_command_ptr:mmc_rpmb_send_command_ptr+4] = pack("<I",mmc_rpmb_send_command)
daextdata[ufshcd_get_free_tag_ptr:ufshcd_get_free_tag_ptr + 4] = pack("<I", ufshcd_get_free_tag)
daextdata[ufshcd_queuecommand_ptr:ufshcd_queuecommand_ptr + 4] = pack("<I", ufshcd_queuecommand)
daextdata[ptr_g_ufs_hba_ptr:ptr_g_ufs_hba_ptr + 4] = pack("<I", g_ufs_hba)
# print(hexlify(daextdata).decode('utf-8'))
#open("daext.bin","wb").write(daextdata)
return daextdata
return None
def patch_da2(self, da2):
da2patched = bytearray(da2)
# Patch security
is_security_enabled = find_binary(da2, b"\x01\x23\x03\x60\x00\x20\x70\x47")
if is_security_enabled != -1:
da2patched[is_security_enabled:is_security_enabled + 2] = b"\x00\x23"
# Patch hash check
authaddr = find_binary(da2, b"\x04\x00\x07\xC0")
if authaddr:
da2patched[authaddr:authaddr + 4] = b"\x00\x00\x00\x00"
elif authaddr is None:
authaddr = find_binary(da2, b"\x4F\xF0\x04\x09\xCC\xF2\x07\x09")
if authaddr:
da2patched[authaddr:authaddr + 8] = b"\x4F\xF0\x00\x09\x4F\xF0\x00\x09"
# Patch write not allowed
open("da2.bin","wb").write(da2patched)
idx = 0
while idx != -1:
idx = da2patched.find(b"\x37\xB5\x00\x23\x04\x46\x02\xA8")
if idx != -1:
da2patched[idx:idx + 8] = b"\x37\xB5\x00\x20\x03\xB0\x30\xBD"
return da2patched
def fix_hash(self, da1, da2, hashpos, hashmode):
da1 = bytearray(da1)
dahash = None
if hashmode == 1:
dahash = hashlib.sha1(da2).digest()
elif hashmode == 2:
dahash = hashlib.sha256(da2).digest()
da1[hashpos:hashpos + len(dahash)] = dahash
return da1
def cmd(self, cmd):
if self.xsend(self.xflash.Cmd.DEVICE_CTRL):
status = self.status()
if status == 0x0:
if self.xsend(cmd):
status = self.status()
if status == 0x0:
return True
return False
def custom_read(self, addr, length):
if self.cmd(XCmd.CUSTOM_READ):
self.xsend(addr)
self.xsend(length)
data = self.xread()
status = self.status()
if status == 0:
return data
return b""
def custom_write(self, addr, data):
if self.cmd(XCmd.CUSTOM_WRITE):
self.xsend(addr)
self.xsend(len(data))
self.xsend(data)
status = self.status()
if status == 0:
return True
return False
def custom_writeregister(self, addr, data):
if self.cmd(XCmd.CUSTOM_WRITEREGISTER):
self.xsend(addr)
self.xsend(data)
status = self.status()
if status == 0:
return True
return False
def readmem(self, addr, dwords=1):
res = []
for pos in range(dwords):
val = self.custom_read(addr + pos * 4, 4)
if val == b"":
return False
data = unpack("<I", val)[0]
if dwords == 1:
return data
res.append(data)
return res
def writeregister(self, addr, dwords):
if isinstance(dwords, int):
dwords = [dwords]
pos = 0
for val in dwords:
if not self.custom_writeregister(addr + pos, val):
return False
pos += 4
return True
def writemem(self, addr, data):
for i in range(0, len(data), 4):
value = data[i:i + 4]
while len(value) < 4:
value += b"\x00"
self.writeregister(addr + i, unpack("<I", value))
return True
def custom_rpmb_read(self, sector, ufs=False):
cmd=XCmd.CUSTOM_READ_RPMB
if ufs:
cmd=XCmd.CUSTOM_READ_UFS_RPMB
if self.cmd(cmd):
self.xsend(sector)
status = unpack("<H", self.xread())[0]
if status == 0x0:
data = self.xread()
status = self.status()
if status == 0:
return data
return b''
def custom_rpmb_write(self, sector, data: bytes, ufs=False):
if len(data) != 0x100:
self.error("Incorrect rpmb frame length. Aborting")
return False
cmd=XCmd.CUSTOM_WRITE_RPMB
if ufs:
cmd=XCmd.CUSTOM_WRITE_UFS_RPMB
if self.cmd(cmd):
self.xsend(sector)
self.xsend(data[:0x100])
resp = unpack("<H", self.xread())[0]
status = self.status()
if status == 0:
return resp
return False
def custom_rpmb_init(self, ufs=False):
cmd=XCmd.CUSTOM_INIT_RPMB
if ufs:
cmd=XCmd.CUSTOM_INIT_UFS_RPMB
if self.cmd(cmd):
status = self.status()
if status == 0:
return True
return False
def read_rpmb(self, filename=None, display=True):
progressbar = progress(1)
sectors = 0
ufs = False
if self.xflash.emmc.rpmb_size != 0:
sectors = self.xflash.emmc.rpmb_size // 0x100
ufs = False
elif self.xflash.ufs.block_size != 0:
sectors = (512 * 256)
ufs = True
if filename is None:
filename = "rpmb.bin"
if sectors > 0:
with open(filename, "wb") as wf:
for sector in range(sectors):
if display:
progressbar.show_progress("RPMB", sector, sectors, display)
data = self.custom_rpmb_read(sector=sector,ufs=ufs)
if data == b"":
self.error("Couldn't read rpmb.")
return False
wf.write(data)
self.info("Done reading rpmb to " + filename)
return True
return False
def write_rpmb(self, filename=None, display=True):
progressbar = progress(1)
if filename is None:
self.error("Filename has to be given for writing to rpmb")
return False
if not os.path.exists(filename):
self.error(f"Couldn't find {filename} for writing to rpmb.")
return False
ufs = False
sectors = 0
if self.xflash.emmc.rpmb_size != 0:
sectors = self.xflash.emmc.rpmb_size // 0x100
ufs = False
elif self.xflash.ufs.block_size != 0:
sectors = (512 * 256)
ufs = True
if self.custom_rpmb_init():
if sectors > 0:
with open(filename, "rb") as rf:
for sector in range(sectors):
if display:
progressbar.show_progress("RPMB", sector, sectors, display)
if not self.custom_rpmb_write(sector=sector, data=rf.read(0x100), ufs=ufs):
self.error(f"Couldn't write rpmb at sector {sector}.")
return False
self.info(f"Done reading writing {filename} to rpmb")
return True
return False
def cryptosetup(self):
setup = crypto_setup()
setup.blacklist = self.config.chipconfig.blacklist
setup.gcpu_base = self.config.chipconfig.gcpu_base
setup.dxcc_base = self.config.chipconfig.dxcc_base
setup.da_payload_addr = self.config.chipconfig.da_payload_addr
setup.sej_base = self.config.chipconfig.sej_base
setup.read32 = self.readmem
setup.write32 = self.writeregister
setup.writemem = self.writemem
return hwcrypto(setup, self.loglevel)
def seccfg(self, lockflag):
if lockflag not in ["unlock", "lock"]:
print("Valid flags are: unlock, lock")
return False
hwc = self.cryptosetup()
sc_org = seccfg(hwc)
data, guid_gpt = self.xflash.partition.get_gpt(0, 0, 0, "user")
seccfg_data = None
partition = None
for rpartition in guid_gpt.partentries:
if rpartition.name == "seccfg":
partition = rpartition
seccfg_data = self.xflash.readflash(
addr=partition.sector * self.mtk.daloader.daconfig.pagesize,
length=partition.sectors * self.mtk.daloader.daconfig.pagesize,
filename="", parttype="user", display=False)
break
if seccfg_data is None:
self.error("Couldn't detect existing seccfg partition. Aborting unlock.")
return False
if seccfg_data[:4] != pack("<I", 0x4D4D4D4D):
self.error("Unknown seccfg partition header. Aborting unlock.")
return False
if not sc_org.parse(seccfg_data):
return False
sc_new = seccfg(hwc)
if lockflag == "unlock":
prelock = "lock"
else:
prelock = "unlock"
hwtype = "hw"
sc_new.create(prelock, hwtype)
if sc_org.hash != sc_new.hash:
hwtype = "sw"
sc_new.create(prelock, hwtype)
if sc_org.hash != sc_new.hash:
self.error("Device has is either already unlocked or algo is unknown. Aborting.")
return False
writedata = sc_new.create(lockflag, hwtype)
if self.xflash.writeflash(addr=partition.sector * self.mtk.daloader.daconfig.pagesize,
length=len(writedata),
filename=None, wdata=writedata, parttype="user", display=True):
self.info("Successfully wrote seccfg.")
return True
self.error("Error on writing seccfg config to flash.")
return False
def generate_keys(self):
hwc = self.cryptosetup()
meid = b""
if os.path.exists(os.path.join("logs", "meid.txt")):
meid = bytes.fromhex(open(os.path.join("logs", "meid.txt"), "r").read())
self.info("MEID : " + hexlify(meid).decode('utf-8'))
if os.path.exists(os.path.join("logs", "socid.txt")):
socid = bytes.fromhex(open(os.path.join("logs", "socid.txt"), "r").read())
self.info("SOCID : " + hexlify(socid).decode('utf-8'))
if self.config.chipconfig.dxcc_base is not None:
self.info("Generating dxcc rpmbkey...")
rpmbkey = hwc.aes_hwcrypt(btype="dxcc", mode="rpmb")
self.info("Generating dxcc fdekey...")
fdekey = hwc.aes_hwcrypt(btype="dxcc", mode="fde")
self.info("Generating dxcc rpmbkey2...")
rpmb2key = hwc.aes_hwcrypt(btype="dxcc", mode="rpmb2")
self.info("Generating dxcc itrustee key...")
ikey = hwc.aes_hwcrypt(btype="dxcc", mode="itrustee")
if rpmbkey is not None:
self.info("RPMB : " + hexlify(rpmbkey).decode('utf-8'))
open(os.path.join("logs", "rpmbkey.txt"), "wb").write(hexlify(rpmbkey))
if rpmb2key is not None:
self.info("RPMB2 : " + hexlify(rpmb2key).decode('utf-8'))
open(os.path.join("logs", "rpmb2key.txt"), "wb").write(hexlify(rpmb2key))
if fdekey is not None:
self.info("FDE : " + hexlify(fdekey).decode('utf-8'))
open(os.path.join("logs", "fdekey.txt"), "wb").write(hexlify(fdekey))
if ikey is not None:
self.info("iTrustee : " + hexlify(ikey).decode('utf-8'))
open(os.path.join("logs", "itrustee_fbe.txt"), "wb").write(hexlify(ikey))
"""
hrid = self.xflash.get_hrid()
if hrid is not None:
self.info("HRID : " + hexlify(hrid).decode('utf-8'))
open(os.path.join("logs", "hrid.txt"), "wb").write(hexlify(hrid))
"""
elif self.config.chipconfig.sej_base is not None:
if meid != b"":
self.info("Generating sej rpmbkey...")
otp = None
if self.mtk.config.preloader is not None:
idx = self.mtk.config.preloader.find(b"\x4D\x4D\x4D\x01\x30")
if idx != -1:
otp = self.mtk.config.preloader[idx + 0xC:idx + 0xC + 32]
if otp is None:
otp = 32 * b"\x00"
rpmbkey = hwc.aes_hwcrypt(mode="rpmb", data=meid, otp=otp, btype="sej")
self.info("RPMB : " + hexlify(rpmbkey).decode('utf-8'))
open(os.path.join("logs", "rpmbkey.txt"), "wb").write(hexlify(rpmbkey))
return True

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more