mtkclient/stage2.py

732 lines
30 KiB
Python
Raw Normal View History

2021-08-01 16:25:44 -04:00
#!/usr/bin/env python3
# MTK Stage2 Client (c) B.Kerler 2018-2024.
2021-11-27 08:25:53 -05:00
# Licensed under GPLv3 License
2021-08-01 16:25:44 -04:00
import os
import sys
2021-08-01 16:25:44 -04:00
import logging
import time
import argparse
import hashlib
from binascii import hexlify
from struct import pack, unpack
from mtkclient.Library.Connection.usblib import UsbClass
2021-08-01 16:25:44 -04:00
from mtkclient.Library.utils import LogBase
from mtkclient.Library.utils import Progress
from mtkclient.Library.Hardware.hwcrypto import CryptoSetup, HwCrypto
from mtkclient.config.mtk_config import MtkConfig
2021-08-31 16:34:17 -04:00
from mtkclient.config.usb_ids import default_ids
2021-08-01 16:25:44 -04:00
2021-08-01 16:25:44 -04:00
class Stage2(metaclass=LogBase):
2021-08-02 07:08:51 -04:00
def __init__(self, args, loglevel=logging.INFO):
self.hwcrypto = None
self.config = None
2021-08-02 07:08:51 -04:00
self.__logger = self.__logger
self.args = args
self.loglevel = loglevel
self.info = self.__logger.info
self.error = self.__logger.error
self.warning = self.__logger.warning
self.emmc_inited = False
# Setup HW Crypto chip variables
self.setup = CryptoSetup()
2021-08-02 07:08:51 -04:00
if loglevel == logging.DEBUG:
logfilename = os.path.join("logs", "log.txt")
if os.path.exists(logfilename):
os.remove(logfilename)
fh = logging.FileHandler(logfilename, encoding='utf-8')
2021-08-02 07:08:51 -04:00
self.__logger.addHandler(fh)
self.__logger.setLevel(logging.DEBUG)
else:
self.__logger.setLevel(logging.INFO)
self.cdc = UsbClass(portconfig=default_ids, loglevel=loglevel, devclass=10)
self.usbread = self.cdc.usbread
self.usbwrite = self.cdc.usbwrite
2021-08-02 07:08:51 -04:00
def preinit(self):
try:
hwcode = self.read32(0x8000000)
except:
print("Error reading hwcode...aborting.")
return False
self.config = MtkConfig(self.loglevel)
2021-08-02 07:08:51 -04:00
self.config.init_hwcode(hwcode)
self.setup.blacklist = self.config.chipconfig.blacklist
self.setup.gcpu_base = self.config.chipconfig.gcpu_base
self.setup.dxcc_base = self.config.chipconfig.dxcc_base
self.setup.da_payload_addr = self.config.chipconfig.da_payload_addr
self.setup.sej_base = self.config.chipconfig.sej_base
self.setup.read32 = self.read32
self.setup.write32 = self.write32
self.setup.writemem = self.memwrite
self.setup.meid_addr = self.config.chipconfig.meid_addr
2021-08-22 12:03:22 -04:00
self.setup.socid_addr = self.config.chipconfig.socid_addr
self.hwcrypto = HwCrypto(self.setup, self.loglevel, self.config.gui)
2021-08-02 07:08:51 -04:00
return True
2021-08-01 16:25:44 -04:00
def init_emmc(self):
2021-09-01 05:47:56 -04:00
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x6001))
if unpack("<I", self.usbread(4))[0] != 0x1:
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x6000))
2021-08-01 16:25:44 -04:00
time.sleep(2)
2021-09-01 05:47:56 -04:00
if unpack("<I", self.usbread(4))[0] == 0xD1D1D1D1:
2021-08-01 16:25:44 -04:00
return True
self.emmc_inited = True
return False
def jump(self, addr):
2021-09-01 05:47:56 -04:00
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x4001))
self.usbwrite(pack(">I", addr))
2021-08-01 16:25:44 -04:00
time.sleep(5)
2021-09-01 05:47:56 -04:00
if unpack("<I", self.usbread(4))[0] == 0xD0D0D0D0:
2021-08-01 16:25:44 -04:00
return True
return False
def read32(self, addr, dwords=1):
result = []
for pos in range(dwords):
2021-09-01 05:47:56 -04:00
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x4002))
self.usbwrite(pack(">I", addr + (pos * 4)))
self.usbwrite(pack(">I", 4))
result.append(unpack("<I", self.usbread(4))[0])
2021-08-01 16:25:44 -04:00
if len(result) == 1:
return result[0]
return result
def cmd_C8(self, val) -> bool:
2024-05-04 05:39:20 -04:00
"""Clear cache func"""
2021-09-01 05:47:56 -04:00
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x5000))
2024-05-04 08:31:02 -04:00
if self.usbread(4) == b"\xD0\xD0\xD0\xD0":
2021-08-01 16:25:44 -04:00
return True
return False
def write32(self, addr, dwords) -> bool:
if isinstance(dwords, int):
dwords = [dwords]
for pos in range(0, len(dwords)):
2021-09-01 05:47:56 -04:00
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x4000))
self.usbwrite(pack(">I", addr + (pos * 4)))
self.usbwrite(pack(">I", 4))
self.usbwrite(pack("<I", dwords[pos]))
2024-05-04 08:31:02 -04:00
if self.usbread(4) == b"\xD0\xD0\xD0\xD0":
2021-08-01 16:25:44 -04:00
continue
else:
return False
return True
def connect(self):
self.cdc.connected = self.cdc.connect()
return self.cdc.connected
def close(self):
if self.cdc.connected:
self.cdc.close()
2024-05-04 05:15:43 -04:00
def readflash(self, type_: int, start, length, display=False, filename: str = None):
2021-08-01 16:25:44 -04:00
if not self.emmc_inited:
self.init_emmc()
wf = None
pg = Progress(pagesize=0x200)
2021-08-01 16:25:44 -04:00
buffer = bytearray()
if filename is not None:
wf = open(filename, "wb")
sectors = (length // 0x200)
sectors += (1 if length % 0x200 else 0)
startsector = (start // 0x200)
# emmc_switch(1)
2021-09-01 05:47:56 -04:00
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x1002))
2024-05-04 05:15:43 -04:00
self.usbwrite(pack(">I", type_))
2021-08-01 16:25:44 -04:00
# kick-wdt
2021-09-01 05:47:56 -04:00
# self.usbwrite(pack(">I", 0xf00dd00d))
# self.usbwrite(pack(">I", 0x3001))
2021-08-01 16:25:44 -04:00
bytestoread = length
bytesread = 0
old = 0
# emmc_read(0)
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x1000))
self.usbwrite(pack(">I", startsector))
self.usbwrite(pack(">I", sectors))
if display:
pg.show_progress(prefix="Progress:", pos=0, total=sectors)
for sector in range(sectors):
2021-09-01 05:47:56 -04:00
tmp = self.usbread(0x200)
2021-09-01 03:46:35 -04:00
if not tmp or len(tmp) != 0x200:
2021-08-01 16:25:44 -04:00
self.error("Error on getting data")
return
if display:
pg.show_progress(prefix="Progress:", pos=sector, total=sectors)
2021-08-01 16:25:44 -04:00
bytesread += len(tmp)
size = min(bytestoread, len(tmp))
if wf is not None:
wf.write(tmp[:size])
else:
buffer.extend(tmp)
bytestoread -= size
if display:
pg.show_progress(prefix="Progress:", pos=sectors, total=sectors)
2021-08-01 16:25:44 -04:00
if wf is not None:
wf.close()
else:
return buffer[start % 0x200:(start % 0x200) + length]
def userdata(self, start=0, length=32 * 0x200, filename="data.bin"):
sectors = 0
if length != 0:
sectors = (length // 0x200) + (1 if length % 0x200 else 0)
self.info("Reading user data...")
if self.cdc.connected:
2024-05-04 05:15:43 -04:00
self.readflash(type_=0, start=start, length=length, display=True, filename=filename)
2021-08-01 16:25:44 -04:00
def preloader(self, start, length, filename):
sectors = 0
if start != 0:
start = (start // 0x200)
if length != 0:
sectors = (length // 0x200) + (1 if length % 0x200 else 0)
self.info("Reading preloader...")
if self.cdc.connected:
if sectors == 0:
2024-05-04 05:15:43 -04:00
buffer = self.readflash(type_=1, start=0, length=0x4000, display=False)
2021-08-01 16:25:44 -04:00
if len(buffer) != 0x4000:
print("Error on reading boot1 area.")
return
if buffer[:9] == b'EMMC_BOOT':
startbrlyt = unpack("<I", buffer[0x10:0x14])[0]
if buffer[startbrlyt:startbrlyt + 5] == b"BRLYT":
start = unpack("<I", buffer[startbrlyt + 0xC:startbrlyt + 0xC + 4])[0]
st = buffer[start:start + 4]
if st == b"MMM\x01":
length = unpack("<I", buffer[start + 0x20:start + 0x24])[0]
2024-05-04 05:15:43 -04:00
data = self.readflash(type_=1, start=0, length=start + length, display=True)
2021-08-01 16:25:44 -04:00
if len(data) != start + length:
print("Warning, please rerun command, length doesn't match.")
idx = data.find(b"MTK_BLOADER_INFO")
if idx != -1:
filename = data[idx + 0x1B:idx + 0x3D].rstrip(b"\x00").decode('utf-8')
with open(os.path.join("logs", filename), "wb") as wf:
wf.write(data[start:start + length])
2024-05-04 08:42:05 -04:00
print(f"Done writing to {os.path.join('logs', filename)}")
2021-08-01 16:25:44 -04:00
with open(os.path.join("logs", "hdr_" + filename), "wb") as wf:
wf.write(data[:start])
2024-05-04 08:42:05 -04:00
print(f"Done writing to {os.path.join('logs', 'hdr_' + filename)}")
2021-08-01 16:25:44 -04:00
return
else:
length = 0x40000
2024-05-04 05:15:43 -04:00
self.readflash(type_=1, start=0, length=length, display=True, filename=filename)
2021-08-01 16:25:44 -04:00
print("Done")
print("Error on getting preloader info, aborting.")
else:
2024-05-04 05:15:43 -04:00
self.readflash(type_=1, start=start, length=length, display=True, filename=filename)
2021-08-01 16:25:44 -04:00
print("Done")
def boot2(self, start, length, filename):
sectors = 0
if start != 0:
start = (start // 0x200)
if length != 0:
sectors = (length // 0x200) + (1 if length % 0x200 else 0)
self.info("Reading boot2...")
if self.cdc.connected:
if sectors == 0:
2024-05-04 05:15:43 -04:00
self.readflash(type_=2, start=0, length=0x40000, display=True, filename=filename)
2021-08-01 16:25:44 -04:00
print("Done")
else:
2024-05-04 05:15:43 -04:00
self.readflash(type_=1, start=start, length=length, display=True, filename=filename)
2021-08-01 16:25:44 -04:00
print("Done")
def memread(self, start, length, filename=None):
bytestoread = length
addr = start
data = b""
pos = 0
wf = None
2021-08-01 16:25:44 -04:00
if filename is not None:
wf = open(filename, "wb")
while bytestoread > 0:
size = min(bytestoread, 0x100)
2021-09-01 05:47:56 -04:00
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x4002))
self.usbwrite(pack(">I", addr + pos))
self.usbwrite(pack(">I", size))
2021-08-01 16:25:44 -04:00
if filename is None:
2021-09-01 05:47:56 -04:00
data += self.usbread(size)
2021-08-01 16:25:44 -04:00
else:
2021-09-01 05:47:56 -04:00
wf.write(self.usbread(size))
2021-08-01 16:25:44 -04:00
bytestoread -= size
pos += size
2024-05-04 08:42:05 -04:00
self.info(f"{hex(start)}: {hexlify(data).decode('utf-8')}")
2021-08-01 16:25:44 -04:00
if filename is not None:
wf.close()
return data
def memwrite(self, start, data, filename=None):
rf = None
2021-08-01 16:25:44 -04:00
if filename is not None:
rf = open(filename, "rb")
bytestowrite = os.stat(filename).st_size
else:
if isinstance(data, str):
data = bytes.fromhex(data)
elif isinstance(data, int):
data = pack("<I", data)
bytestowrite = len(data)
addr = start
pos = 0
while bytestowrite > 0:
size = min(bytestowrite, 0x100)
2021-09-01 05:47:56 -04:00
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x4000))
self.usbwrite(pack(">I", addr + pos))
self.usbwrite(pack(">I", size))
2021-08-01 16:25:44 -04:00
if filename is None:
wdata = data[pos:pos + size]
else:
wdata = rf.read(size)
bytestowrite -= size
pos += size
while len(wdata) % 4 != 0:
wdata += b"\x00"
2021-09-01 05:47:56 -04:00
self.usbwrite(wdata)
2021-08-01 16:25:44 -04:00
if filename is not None:
rf.close()
2021-09-01 05:47:56 -04:00
ack = self.usbread(4)
2024-05-31 19:52:55 -04:00
return ack == b"\xD0\xD0\xD0\xD0"
2021-08-01 16:25:44 -04:00
def rpmb(self, start, length, filename, reverse=False):
pg = Progress(pagesize=0x100)
2021-08-01 16:25:44 -04:00
if not self.emmc_inited:
self.init_emmc()
if start == 0:
start = 0
else:
start = (start // 0x100)
if start > 0xFFFF:
start = 0xFFFF
2021-08-01 16:25:44 -04:00
if length == 0:
sectors = 16 * 1024 * 1024 // 0x100
2021-08-01 16:25:44 -04:00
else:
sectors = (length // 0x100) + (1 if length % 0x100 else 0)
self.info("Reading rpmb...")
2021-09-01 05:47:56 -04:00
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x1002))
self.usbwrite(pack(">I", 0x1))
2021-08-01 16:25:44 -04:00
# kick-wdt
2021-09-01 05:47:56 -04:00
# self.usbwrite(pack(">I", 0xf00dd00d))
# self.usbwrite(pack(">I", 0x3001))
2021-08-01 16:25:44 -04:00
bytesread = 0
old = 0
bytestoread = sectors * 0x100
count = sectors
pg = Progress(pagesize=0x200)
if sectors > 0xFFFF:
count = 0xFFFF
2021-08-01 16:25:44 -04:00
with open(filename, "wb") as wf:
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x2000))
self.usbwrite(pack(">H", start))
self.usbwrite(pack(">H", count))
for sector in range(count):
2021-09-01 05:47:56 -04:00
tmp = self.usbread(0x100)
2021-08-01 16:25:44 -04:00
if reverse:
tmp = tmp[::-1]
if len(tmp) != 0x100:
self.error("Error on getting data")
return
pg.show_progress(prefix="Progress:", pos=sector, total=sectors)
2021-08-01 16:25:44 -04:00
bytesread += 0x100
size = min(bytestoread, len(tmp))
wf.write(tmp[:size])
bytestoread -= size
while bytestoread > 0:
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x2000))
self.usbwrite(pack(">H", sector + 1))
self.usbwrite(pack(">H", 1))
tmp = self.usbread(0x100)
size = min(bytestoread, len(tmp))
wf.write(tmp[:size])
bytestoread -= size
pg.show_progress(prefix="Progress:", pos=sector, total=sectors)
sector += 1
pg.show_progress(prefix="Progress:", pos=sectors, total=sectors)
print("Done")
2021-08-01 16:25:44 -04:00
def keys(self, data=b"", otp=None, mode="dxcc"):
2021-08-01 16:25:44 -04:00
# self.hwcrypto.disable_range_blacklist("cqdma",self.cmd_C8)
keyinfo = ""
2022-01-11 05:52:22 -05:00
retval = {}
meid = self.config.get_meid()
socid = self.config.get_socid()
if meid is not None:
2024-05-04 08:42:05 -04:00
self.info(f"MEID : {hexlify(meid).decode('utf-8')}")
2022-01-11 05:52:22 -05:00
else:
try:
if self.config.chipconfig.meid_addr is not None:
meid = self.memread(self.config.chipconfig.meid_addr, 16)
self.config.set_meid(meid)
2024-05-04 08:42:05 -04:00
self.info(f"MEID : {hexlify(meid).decode('utf-8')}")
2022-01-11 05:52:22 -05:00
retval["meid"] = hexlify(meid).decode('utf-8')
except Exception as err:
pass
if socid is not None:
2024-05-04 08:42:05 -04:00
self.info(f"SOCID : {hexlify(socid).decode('utf-8')}")
2022-01-11 05:52:22 -05:00
retval["socid"] = socid
else:
try:
if self.config.chipconfig.socid_addr is not None:
socid = self.memread(self.config.chipconfig.socid_addr, 32)
self.config.set_socid(socid)
2024-05-04 08:42:05 -04:00
self.info(f"SOCID : {hexlify(socid).decode('utf-8')}")
2022-01-11 05:52:22 -05:00
retval["socid"] = hexlify(socid).decode('utf-8')
except Exception as err:
pass
if self.setup.dxcc_base is not None and mode not in ["sej_aes_decrypt", "sej_aes_encrypt", "sej_sst_decrypt",
"sej_sst_encrypt", "dxcc_sha256"]:
rpmbkey = self.hwcrypto.aes_hwcrypt(btype="dxcc", mode="rpmb")
rpmb2key = self.hwcrypto.aes_hwcrypt(btype="dxcc", mode="rpmb2")
fdekey = self.hwcrypto.aes_hwcrypt(btype="dxcc", mode="fde")
ikey = self.hwcrypto.aes_hwcrypt(btype="dxcc", mode="itrustee")
platkey, provkey = self.hwcrypto.aes_hwcrypt(btype="dxcc", mode="prov")
keyinfo += "\nKeys :\n-----------------------------------------\n"
2024-05-04 08:42:05 -04:00
keyinfo += f"RPMB: {hexlify(rpmbkey).decode('utf-8')}\n"
keyinfo += f"RPMB2: {hexlify(rpmb2key).decode('utf-8')}\n"
keyinfo += f"FDE : {hexlify(fdekey).decode('utf-8')}\n"
keyinfo += f"iTrustee: {hexlify(ikey).decode('utf-8')}\n"
keyinfo += f"Platform: {hexlify(platkey).decode('utf-8')}\n"
keyinfo += f"Provisioning: {hexlify(provkey).decode('utf-8')}\n"
keyinfo += "\n"
2022-01-11 05:52:22 -05:00
if rpmbkey is not None:
2024-05-04 08:42:05 -04:00
self.info(f"RPMB : {hexlify(rpmbkey).decode('utf-8')}")
self.config.hwparam.writesetting("rpmbkey", hexlify(rpmbkey).decode('utf-8'))
2022-01-11 05:52:22 -05:00
retval["rpmbkey"] = hexlify(rpmbkey).decode('utf-8')
if rpmb2key is not None:
2024-05-04 08:42:05 -04:00
self.info(f"RPMB2 : {hexlify(rpmb2key).decode('utf-8')}")
self.config.hwparam.writesetting("rpmb2key", hexlify(rpmb2key).decode('utf-8'))
2022-01-11 05:52:22 -05:00
retval["rpmb2key"] = hexlify(rpmb2key).decode('utf-8')
if fdekey is not None:
2024-05-04 08:42:05 -04:00
self.info(f"FDE : {hexlify(fdekey).decode('utf-8')}")
self.config.hwparam.writesetting("fdekey", hexlify(fdekey).decode('utf-8'))
2022-01-11 05:52:22 -05:00
retval["fdekey"] = hexlify(fdekey).decode('utf-8')
if ikey is not None:
2024-05-04 08:42:05 -04:00
self.info(f"iTrustee : {hexlify(ikey).decode('utf-8')}")
2022-01-11 05:52:22 -05:00
self.config.hwparam.writesetting("kmkey", hexlify(ikey).decode('utf-8'))
retval["kmkey"] = hexlify(ikey).decode('utf-8')
if self.config.chipconfig.prov_addr:
provkey = self.memread(self.config.chipconfig.prov_addr, 16)
2024-05-04 08:42:05 -04:00
self.info(f"PROV : {hexlify(provkey).decode('utf-8')}")
2022-01-11 05:52:22 -05:00
self.config.hwparam.writesetting("provkey", hexlify(provkey).decode('utf-8'))
retval["provkey"] = hexlify(provkey).decode('utf-8')
return retval, keyinfo
elif self.setup.sej_base is not None and mode not in ["sej_aes_decrypt", "sej_aes_encrypt", "sej_sst_decrypt",
"sej_sst_encrypt", "dxcc_sha256"]:
retval = {}
2022-01-11 05:52:22 -05:00
rpmbkey = self.hwcrypto.aes_hwcrypt(mode="rpmb", data=meid, otp=otp, btype="sej")
if rpmbkey:
2024-05-04 08:42:05 -04:00
self.info(f"RPMB : {hexlify(rpmbkey).decode('utf-8')}")
2022-01-11 05:52:22 -05:00
self.config.hwparam.writesetting("rpmbkey", hexlify(rpmbkey).decode('utf-8'))
retval["rpmbkey"] = hexlify(rpmbkey).decode('utf-8')
self.info("Generating sej mtee...")
mtee = self.hwcrypto.aes_hwcrypt(mode="mtee", otp=otp, btype="sej")
if mtee:
2024-05-04 08:42:05 -04:00
self.info(f"MTEE : {hexlify(mtee).decode('utf-8')}")
2022-01-11 05:52:22 -05:00
self.config.hwparam.writesetting("mtee", hexlify(mtee).decode('utf-8'))
retval["mtee"] = hexlify(mtee).decode('utf-8')
2022-11-08 14:02:58 -05:00
mtee3 = self.hwcrypto.aes_hwcrypt(mode="mtee3", otp=otp, btype="sej")
if mtee3:
2024-05-04 08:42:05 -04:00
self.info(f"MTEE3 : {hexlify(mtee3).decode('utf-8')}")
2022-11-08 14:02:58 -05:00
self.config.hwparam.writesetting("mtee3", hexlify(mtee3).decode('utf-8'))
retval["mtee3"] = hexlify(mtee3).decode('utf-8')
keyinfo += "\nKeys :\n-----------------------------------------\n"
2024-05-04 08:42:05 -04:00
keyinfo += f"RPMB: {hexlify(rpmbkey).decode('utf-8')}\n"
keyinfo += f"MTEE: {hexlify(mtee).decode('utf-8')}\n"
2022-01-11 05:52:22 -05:00
retval["rpmbkey"] = hexlify(rpmbkey).decode('utf-8')
return retval, keyinfo
if mode == "sej_aes_decrypt":
2023-06-12 12:56:52 -04:00
dec_data = self.hwcrypto.aes_hwcrypt(mode="cbc", data=data, btype="sej", encrypt=False, otp=otp)
2024-05-04 08:42:05 -04:00
keyinfo += f"\nData: {hexlify(dec_data).decode('utf-8')}\n"
2021-09-01 06:54:33 -04:00
return dec_data, keyinfo
2021-08-01 16:25:44 -04:00
elif mode == "sej_aes_encrypt":
2023-06-12 12:56:52 -04:00
enc_data = self.hwcrypto.aes_hwcrypt(mode="cbc", data=data, btype="sej", encrypt=True, otp=otp)
2024-05-04 08:42:05 -04:00
keyinfo += f"\nData: {hexlify(enc_data).decode('utf-8')}\n"
2021-09-01 06:54:33 -04:00
return enc_data, keyinfo
2022-12-14 07:19:10 -05:00
elif mode == "sej_sst_decrypt":
2023-06-12 12:56:52 -04:00
dec_data = self.hwcrypto.aes_hwcrypt(mode="sst", data=data, btype="sej", encrypt=False, otp=otp)
2024-05-04 08:42:05 -04:00
keyinfo += f"\nData: {hexlify(dec_data).decode('utf-8')}\n"
2022-12-14 07:19:10 -05:00
return dec_data, keyinfo
elif mode == "sej_sst_encrypt":
2023-06-12 12:56:52 -04:00
enc_data = self.hwcrypto.aes_hwcrypt(mode="sst", data=data, btype="sej", encrypt=True, otp=otp)
2024-05-04 08:42:05 -04:00
keyinfo += f"\nData: {hexlify(enc_data).decode('utf-8')}\n"
2022-12-14 07:19:10 -05:00
return enc_data, keyinfo
2021-08-01 16:25:44 -04:00
elif mode == "dxcc_sha256":
sha256val = self.hwcrypto.aes_hwcrypt(mode="sha256", data=data, btype="dxcc")
2024-05-04 08:42:05 -04:00
keyinfo += f"\nSHA256: {hexlify(sha256val).decode('utf-8')}\n"
2021-09-01 06:54:33 -04:00
return sha256val, keyinfo
return None, ""
2021-08-01 16:25:44 -04:00
def reboot(self):
2021-08-02 06:46:18 -04:00
print("Rebooting..")
2021-09-01 05:47:56 -04:00
self.usbwrite(pack(">I", 0xf00dd00d))
self.usbwrite(pack(">I", 0x3000))
2021-08-01 16:25:44 -04:00
def getint(valuestr):
if valuestr == '':
return None
try:
return int(valuestr)
except Exception as err:
err = err
try:
return int(valuestr, 16)
except Exception as err:
err = err
pass
return 0
cmds = {
"rpmb": 'Dump rpmb',
"preloader": 'Dump preloader',
"data": 'Dump mmc data',
2021-08-01 16:25:44 -04:00
"boot2": 'Dump boot2',
"reboot": 'Reboot phone',
"memread": "Read memory [Example: memread 0 0x10]",
"memwrite": "Write memory [Example: memwrite 0x200000 1122334455667788, memwrite 0x0 0x12345678, " +
"memwrite 0x0 data.bin]",
2021-08-22 12:03:22 -04:00
"keys": "Extract rpmb and fde key",
"seccfg": "Generate unlock config"
2021-08-01 16:25:44 -04:00
}
info = "MTK Stage2 client (c) B.Kerler 2021"
def main():
parser = argparse.ArgumentParser(description=info)
subparsers = parser.add_subparsers(dest="cmd",
help='Valid commands are: rpmb, preloader, data, boot2, memread, memwrite, keys')
2021-08-02 06:46:18 -04:00
parser_rpmb = subparsers.add_parser("rpmb", help="Dump the rpmb")
parser_rpmb.add_argument('--start', dest='start', type=str,
help='Start offset to dump')
2021-08-02 06:46:18 -04:00
parser_rpmb.add_argument('--length', dest='length', type=str,
help='Max length to dump')
2021-08-02 06:46:18 -04:00
parser_rpmb.add_argument('--reverse', dest='reverse', action="store_true",
help='Reverse byte order (example: rpmb command)')
2021-08-02 06:46:18 -04:00
parser_rpmb.add_argument('--filename', dest='filename', type=str,
help='Read from / save to filename')
2021-08-02 06:46:18 -04:00
parser_preloader = subparsers.add_parser("preloader", help="Dump the preloader")
parser_preloader.add_argument('--start', dest='start', type=str,
help='Start offset to dump')
2021-08-02 06:46:18 -04:00
parser_preloader.add_argument('--length', dest='length', type=str,
help='Max length to dump')
2021-08-02 06:46:18 -04:00
parser_preloader.add_argument('--filename', dest='filename', type=str,
help='Read from / save to filename')
2021-08-02 06:46:18 -04:00
parser_data = subparsers.add_parser("data", help="Read the mmc")
parser_data.add_argument('--start', dest='start', type=str,
help='Start offset to dump')
parser_data.add_argument('--length', dest='length', type=str,
help='Max length to dump')
parser_data.add_argument('--filename', dest='filename', type=str,
help='Read from / save to filename')
2021-08-02 06:46:18 -04:00
parser_boot2 = subparsers.add_parser("boot2", help="Dump boot2")
parser_boot2.add_argument('--start', dest='start', type=str,
help='Start offset to dump')
2021-08-02 06:46:18 -04:00
parser_boot2.add_argument('--length', dest='length', type=str,
help='Max length to dump')
2021-08-02 06:46:18 -04:00
parser_boot2.add_argument('--filename', dest='filename', type=str,
help='Read from / save to filename')
2021-08-02 06:46:18 -04:00
parser_memread = subparsers.add_parser("memread", help="Read memory")
parser_memread.add_argument(dest='start', type=str,
help='Start offset to dump')
2021-08-02 06:46:18 -04:00
parser_memread.add_argument(dest='length', type=str,
help='Max length to dump')
2021-08-02 06:46:18 -04:00
parser_memread.add_argument('--filename', dest='filename', type=str,
help='Save to filename')
2021-08-02 06:46:18 -04:00
2021-08-02 07:08:51 -04:00
parser_memwrite = subparsers.add_parser("memwrite", help="Write memory")
2021-08-02 06:46:18 -04:00
parser_memwrite.add_argument(dest='start', type=str,
help='Start offset to dump')
parser_memwrite.add_argument('data', type=str,
help='Data to write [hexstring, dword or filename]')
2021-08-02 06:46:18 -04:00
parser_reboot = subparsers.add_parser("reboot", help="Reboot device")
2021-09-02 04:47:33 -04:00
parser_seccfg = subparsers.add_parser("seccfg", help="Generate seccfg")
parser_seccfg.add_argument('flag', type=str,
help='Option for generating: unlock or lock')
parser_seccfg.add_argument('--sw', dest='sw', action="store_true",
help='Option for generating: sw or hw')
2021-09-02 04:47:33 -04:00
2021-08-02 06:46:18 -04:00
parser_keys = subparsers.add_parser("keys", help="Write memory")
parser_keys.add_argument('--otp', dest='otp', type=str,
help='OTP for keys (dxcc,sej,gcpu)')
2021-08-31 16:34:17 -04:00
parser_keys.add_argument('--mode', dest='mode', default=None, type=str,
help='keymode (dxcc,sej,gcpu,sej_aes_decrypt,sej_aes_decrypt,' +
'sej_sst_decrypt,sej_sst_encrypt')
2022-12-14 07:19:10 -05:00
parser_keys.add_argument('--data', dest='data', default=None, type=str,
help='data')
2021-08-01 16:25:44 -04:00
args = parser.parse_args()
cmd = args.cmd
if cmd not in cmds:
parser.print_help()
2021-08-01 16:25:44 -04:00
exit(0)
if not os.path.exists("logs"):
os.mkdir("logs")
st2 = Stage2(args)
if st2.connect():
2021-08-02 07:08:51 -04:00
if not st2.preinit():
exit(1)
2021-08-01 16:25:44 -04:00
if cmd == "rpmb":
if args.filename is None:
filename = os.path.join("logs", "rpmb")
else:
filename = args.filename
2021-08-02 06:46:18 -04:00
start = getint(args.start)
length = getint(args.length)
2022-06-28 09:43:55 -04:00
st2.rpmb(start, length, filename, not args.reverse)
2021-08-01 16:25:44 -04:00
elif cmd == "preloader":
if args.filename is None:
filename = os.path.join("logs", "preloader")
else:
filename = args.filename
2021-08-02 06:46:18 -04:00
start = getint(args.start)
length = getint(args.length)
2021-08-01 16:25:44 -04:00
st2.preloader(start, length, filename=filename)
elif cmd == "data":
if args.filename is None:
filename = os.path.join("logs", "data")
else:
filename = args.filename
start = getint(args.start)
length = getint(args.length)
st2.userdata(start, length, filename=filename)
2021-08-01 16:25:44 -04:00
elif cmd == "boot2":
if args.filename is None:
filename = os.path.join("logs", "boot2")
else:
filename = args.filename
2021-08-02 06:46:18 -04:00
start = getint(args.start)
length = getint(args.length)
2021-08-01 16:25:44 -04:00
st2.boot2(start, length, filename=filename)
elif cmd == "memread":
if args.start is None:
print("Option --start is needed")
exit(0)
if args.length is None:
print("Option --length is needed")
exit(0)
2021-08-02 06:46:18 -04:00
start = getint(args.start)
length = getint(args.length)
2021-08-01 16:25:44 -04:00
st2.memread(start, length, args.filename)
elif cmd == "memwrite":
if args.start is None:
print("Option --start is needed")
exit(0)
if args.data is None:
print("Option --data is needed")
2021-08-01 16:25:44 -04:00
exit(0)
2021-08-02 06:46:18 -04:00
start = getint(args.start)
if os.path.exists(args.data):
filename = args.data
data = None
else:
if "0x" in args.data:
data = getint(args.data)
else:
data = args.data
filename = None
if st2.memwrite(start, data, filename):
2021-08-01 16:25:44 -04:00
print(f"Successfully wrote data to {hex(start)}.")
else:
print(f"Failed to write data to {hex(start)}.")
elif cmd == "keys":
keyinfo = ""
data = b""
if args.mode in ["sej_aes_decrypt", "sej_aes_encrypt", "sej_sst_decrypt", "sej_sst_encrypt"]:
2021-08-01 16:25:44 -04:00
if not args.data:
print("Option --data is needed")
exit(0)
data = bytes.fromhex(args.data)
# otp_hisense=bytes.fromhex("486973656E736500000000000000000000000000000000000000000000000000")
# st2.jump(0x223449)
keys, keyinfo = st2.keys(data=data, mode=args.mode, otp=args.otp)
2021-08-22 12:03:22 -04:00
print(keyinfo)
2022-01-11 05:52:22 -05:00
print("Wrote keys to logs/hwparam.json")
2021-08-01 16:25:44 -04:00
elif cmd == "reboot":
st2.reboot()
2021-08-22 12:03:22 -04:00
elif cmd == "seccfg":
critical_lock_state = 0
if args.flag not in ["unlock", "lock"]:
print("Valid flags are: unlock, lock")
2021-08-22 12:03:22 -04:00
"""
LKS_DEFAULT = 0x01
LKS_MP_DEFAULT = 0x02
LKS_UNLOCK = 0x03
LKS_LOCK = 0x04
LKS_VERIFIED = 0x05
LKS_CUSTOM = 0x06
"""
2021-08-22 12:03:22 -04:00
"""
LKCS_UNLOCK = 0x01
LKCS_LOCK = 0x02
"""
"""
SBOOT_RUNTIME_OFF = 0
SBOOT_RUNTIME_ON = 1
"""
sys.exit(1)
if args.flag == "unlock":
lock_state = 3
critical_lock_state = 1
elif args.flag == "lock":
lock_state = 1
critical_lock_state = 0
with open("seccfg.bin", "wb") as wf:
seccfg_ver = 4
seccfg_size = 0x3C
sboot_runtime = 0
2021-08-22 12:03:22 -04:00
seccfg_data = pack("<IIIIIII", 0x4D4D4D4D, seccfg_ver, seccfg_size, lock_state,
critical_lock_state, sboot_runtime, 0x45454545)
dec_hash = hashlib.sha256(seccfg_data).digest()
if args.sw:
enc_hash = st2.hwcrypto.sej.sej_sec_cfg_sw(dec_hash, True)
else:
enc_hash = st2.hwcrypto.sej.sej_sec_cfg_hw(dec_hash, True)
2021-08-22 12:03:22 -04:00
data = seccfg_data + enc_hash
data += b"\x00" * (0x200 - len(data))
wf.write(data)
print("Successfully wrote seccfg to seccfg.bin. You need to write seccfg.bin to partition seccfg.")
2021-08-22 12:03:22 -04:00
st2.close()
2021-08-01 16:25:44 -04:00
if __name__ == "__main__":
main()