1. Improve dram handling

2. Import error reports
3. Add missing sony usb vid/pid
4. Some xflash improvements
This commit is contained in:
Bjoern Kerler 2022-02-15 21:18:07 +01:00
parent b30d65c706
commit c7752f2003
10 changed files with 141 additions and 35 deletions

3
mtk
View file

@ -90,6 +90,7 @@ if __name__ == '__main__':
da_cmds = parser_da.add_subparsers(dest='subcmd', help='Commands: peek poke keys unlock')
da_peek = da_cmds.add_parser("peek", help="Read memory")
da_peek.add_argument('--preloader', help='Set the preloader filename for dram config')
da_dump = da_cmds.add_parser("memdump", help="Dump whole memory areas")
da_poke = da_cmds.add_parser("poke", help="Write memory")
da_poke.add_argument('--preloader', help='Set the preloader filename for dram config')
da_keys = da_cmds.add_parser("generatekeys", help="Generate keys")
@ -116,6 +117,8 @@ if __name__ == '__main__':
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_dump.add_argument('directory', type=str, help="Directory to dump ram dump files")
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")

View file

@ -157,8 +157,9 @@ class DAconfig(metaclass=LogBase):
data = data[idx:]
mlen = unpack("<I", data[0x20:0x20 + 4])[0]
siglen = unpack("<I", data[0x2C:0x2C + 4])[0]
data = data[:mlen]
data = data[:mlen-siglen]
dramsize = unpack("<I",data[-4:])[0]
data = data[-dramsize-4:-4]
bldrstring = b"MTK_BLOADER_INFO_v"
len_bldrstring = len(bldrstring)
idx = data.find(bldrstring)
@ -168,7 +169,7 @@ class DAconfig(metaclass=LogBase):
ver = int(data[idx + len_bldrstring:idx + len_bldrstring + 2].rstrip(b"\x00"))
return ver, data
ver = int(data[idx + len_bldrstring:idx + len_bldrstring + 2].rstrip(b"\x00"))
emi = data[idx:-siglen]
emi = data[idx:]
rlen = len(emi) - 4
if len(emi) > 4:
val = unpack("<I", emi[-4:])[0]

View file

@ -617,6 +617,28 @@ ErrorCodes_XFlash = {
0xc0020036: "GFH sec cfg not found",
0xc0020037: "Unsupported source type",
0xc0020038: "Cust name mismatch",
0xc0020039: "Invalid address",
0xc0020040: "Certificate version not synced",
0xc0020041: "Signature not synced",
0xc0020042: "Ext AllInOne Signature rejected",
0xc0020043: "Ext AllInOne Signature missing",
0xc0020044: "Comm Key is not set",
0xc0020045: "DevInfo Check failed",
0xc0020046: "Bootimg count overflow",
0xc0020047: "Signature not found",
0xc0020048: "Bootimg special handle",
0xc0020049: "Remote Seucrity policy disabled",
0xc002004A: "RSA OAEP fail",
0xc002004B: "Insufficient buffer",
0xc002004C: "DA Anti-Rollback error",
0xc002004D: "Get OTP value fail",
0xc002004E: "Invalid unit size",
0xc002004F: "Invalid group idx",
0xc0020050: "Img version overflow",
0xc0020051: "Otp table not initialized",
0xc0020052: "Invalid Partition name",
0xc0020053: "DA version Anti-Rollback error",
0xc0020054: "Invalid msg size",
0xc0030001: "Scatter file invalid",
0xc0030002: "DA file invalid",
0xc0030003: "DA selection error",

View file

@ -309,8 +309,12 @@ class GCpu(metaclass=LogBase):
for i in range(1, 48):
self.write32(self.gcpu_base + regval["GCPU_REG_MEM_CMD"] + (i * 4), args[i])
# Clear/Enable GCPU Interrupt
self.reg.GCPU_REG_INT_CLR = CLR_EN
self.reg.GCPU_REG_INT_EN = GCPU_INT_MASK
if cmd == 0x79:
self.reg.GCPU_REG_INT_CLR = 1
self.reg.GCPU_REG_INT_EN = 0
else:
self.reg.GCPU_REG_INT_CLR = CLR_EN
self.reg.GCPU_REG_INT_EN = GCPU_INT_MASK
# GCPU Decryption Mode
self.reg.GCPU_REG_MEM_CMD = cmd
# GCPU PC
@ -433,7 +437,7 @@ class GCpu(metaclass=LogBase):
return rdata
def aes_read_ecb(self, data, encrypt=False, src=0x12, dst=0x1a, keyslot=0x30):
if self.load_hw_key(0x30):
if self.load_hw_key(0x30): #0x58
self.memptr_set(src, data)
if encrypt:
if not self.aes_encrypt_ecb(keyslot, src, dst):
@ -534,6 +538,18 @@ class GCpu(metaclass=LogBase):
data += pack("<I", word)
return data
def mtk_gcpu_mtee_8167(self, data=None, encrypt=True, src=0x12, dst=0x1a, keyslot=0x58):
if self.load_hw_key(keyslot):
if data is None:
data = bytearray(bytes.fromhex("735f23c962e7a10ab201d9a6426064b1"))
self.memptr_set(src, data)
if encrypt:
if not self.aes_encrypt_ecb(keyslot, src, dst):
return self.memptr_get(dst, 16)
else:
if not self.aes_decrypt_ecb(keyslot, src, dst):
return self.memptr_get(dst, 16)
def aes_decrypt_ecb(self, key_offset, data_offset, out_offset):
self.reg.GCPU_REG_MEM_P0 = 1
self.reg.GCPU_REG_MEM_P1 = key_offset
@ -547,10 +563,10 @@ class GCpu(metaclass=LogBase):
self.reg.GCPU_REG_MEM_P1 = key_offset
self.reg.GCPU_REG_MEM_P2 = data_offset
self.reg.GCPU_REG_MEM_P3 = out_offset
if self.set_mode_cmd(encrypt=False, mode="ecb", encryptedkey=False) != 0:
if self.set_mode_cmd(encrypt=True, mode="ecb", encryptedkey=False) != 0:
raise Exception("failed to call the function!")
def load_hw_key(self, offset):
def load_hw_key(self, offset): # vGcpuMEMExeNoIntr
self.reg.GCPU_REG_MEM_P0 = 0x58 # SrcStartAddr
self.reg.GCPU_REG_MEM_P1 = offset # DstStartAddr
self.reg.GCPU_REG_MEM_P2 = 4 # Length/16 for ECB

View file

@ -78,6 +78,9 @@ class DA_handler(metaclass=LogBase):
if mtk.port.cdc.connected and os.path.exists(".state"):
info = mtk.daloader.reinit()
return mtk
if mtk.config.target_config is None:
self.info("Please disconnect, start mtkclient and reconnect.")
return None
if mtk.config.target_config["daa"]:
mtk = mtk.bypass_security()
self.mtk = mtk
@ -105,7 +108,6 @@ class DA_handler(metaclass=LogBase):
else:
self.info("Device is in Preloader-Mode :(")
if not mtk.daloader.upload_da(preloader=preloader):
self.error("Error uploading da")
return None
else:
mtk.daloader.writestate()
@ -498,7 +500,7 @@ class DA_handler(metaclass=LogBase):
pos = 0
pagesize = 0x200
if self.mtk.daloader.xflash:
pagesize = 1*1024*1024
pagesize = self.mtk.daloader.get_packet_length()
pg = progress(pagesize)
bytesread=0
wf = None
@ -507,15 +509,19 @@ class DA_handler(metaclass=LogBase):
retval = bytearray()
while bytestoread > 0:
msize = min(bytestoread,pagesize)
data = self.mtk.daloader.peek(addr=addr+pos, length=msize)
if wf is not None:
wf.write(data)
else:
retval.extend(data)
pg.show_progress("Dump:",bytesread//pagesize,length//pagesize)
pos+=len(data)
bytesread+=len(data)
bytestoread-=len(data)
try:
data = self.mtk.daloader.peek(addr=addr+pos, length=msize)
if wf is not None:
wf.write(data)
else:
retval.extend(data)
pg.show_progress("Dump:",bytesread//pagesize,length//pagesize)
pos+=len(data)
bytesread+=len(data)
bytestoread-=len(data)
except:
pass
pg.show_progress("Dump:", 100, 100)
if filename is not None:
wf.close()
self.info(f"Successfully wrote data from {hex(addr)}, length {hex(length)} to {filename}")
@ -660,13 +666,21 @@ class DA_handler(metaclass=LogBase):
elif cmd == "da":
subcmd = args.subcmd
if subcmd is None:
print("Available da cmds are: [peek, poke, generatekeys, seccfg, rpmb, meta]")
print("Available da cmds are: [peek, poke, generatekeys, seccfg, rpmb, meta, memdump]")
return
if subcmd == "peek":
addr = getint(args.address)
length = getint(args.length)
filename = args.filename
self.da_peek(addr=addr, length=length, filename=filename)
elif subcmd == "memdump":
directory = args.directory
if not os.path.exists(directory):
os.mkdir(directory)
self.da_peek(addr=0, length=0x11200000,
filename=os.path.join(directory, "dump_brom.bin"))
self.da_peek(addr=0x20000000, length=0xE0000000,
filename=os.path.join(directory, "dump_ram.bin"))
elif subcmd == "poke":
addr = getint(args.address)
filename = args.filename
@ -675,7 +689,7 @@ class DA_handler(metaclass=LogBase):
elif subcmd == "generatekeys":
mtk.daloader.keys()
elif subcmd == "seccfg":
v=mtk.daloader.seccfg(args.flag)
v = mtk.daloader.seccfg(args.flag)
if v[0]:
self.info(v[1])
else:

View file

@ -202,6 +202,13 @@ class DAloader(metaclass=LogBase):
def readflash(self, addr, length, filename, parttype, display=True):
return self.da.readflash(addr=addr, length=length, filename=filename, parttype=parttype, display=display)
def get_packet_length(self):
if self.xflash:
pt=self.da.get_packet_length()
return pt.read_packet_length
else:
return 512
def peek(self, addr: int, length:int):
if self.xflash:
return self.xft.custom_read(addr=addr, length=length)

View file

@ -79,7 +79,7 @@ class DAXFlash(metaclass=LogBase):
GET_NAND_INFO = 0x040002
GET_NOR_INFO = 0x040003
GET_UFS_INFO = 0x040004
GET_VERSION = 0x040005
GET_DA_VERSION = 0x040005
GET_EXPIRE_DATA = 0x040006
GET_PACKET_LENGTH = 0x040007
GET_RANDOM_ID = 0x040008
@ -320,7 +320,9 @@ class DAXFlash(metaclass=LogBase):
if status == 0:
try:
if self.xsend(pack("<I", len(emi))):
return self.send_param([emi])
if self.send_param([emi]):
self.info(f"DRAM setup passed.")
return True
except Exception as err:
self.error(f"Error on sending emi: {str(err)}")
return False
@ -352,9 +354,19 @@ class DAXFlash(metaclass=LogBase):
if self.usbwrite(pkt1):
if self.usbwrite(param):
if self.send_data(da):
self.info(f"Upload data was accepted. Jumping to stage 2...")
if timeout:
time.sleep(timeout)
status = self.status()
status = -1
try:
status = self.status()
except:
if status == -1:
self.error(f"Stage was't executed. Maybe dram issue ?.")
return False
self.error(f"Error on boot to: {self.eh.status(status)}")
return False
if status == 0x434E5953 or status == 0x0:
return True
else:
@ -478,6 +490,16 @@ class DAXFlash(metaclass=LogBase):
self.error(f"Error on format: {self.eh.status(status)}")
return False
def get_da_version(self):
data = self.send_devctrl(self.Cmd.GET_DA_VERSION)
status = self.status()
if status == 0:
self.info(f"DA-VERSION : {data.decode('utf-8')}")
return data
else:
self.error(f"Error on getting chip id: {self.eh.status(status)}")
return None
def get_chip_id(self):
class Chipid:
hw_code = 0
@ -488,10 +510,15 @@ class DAXFlash(metaclass=LogBase):
cid = Chipid
data = self.send_devctrl(self.Cmd.GET_CHIP_ID)
cid.hw_code, cid.hw_sub_code, cid.hw_version, cid.sw_version, cid.chip_evolution = unpack(">HHHHH",
cid.hw_code, cid.hw_sub_code, cid.hw_version, cid.sw_version, cid.chip_evolution = unpack("<HHHHH",
data[:(5 * 2)])
status = self.status()
if status == 0:
self.info("HW-CODE : 0x%X", cid.hw_code)
self.info("HWSUB-CODE : 0x%X", cid.hw_sub_code)
self.info("HW-VERSION : 0x%X", cid.hw_version)
self.info("SW-VERSION : 0x%X", cid.sw_version)
self.info("CHIP-EVOLUTION : 0x%X", cid.chip_evolution)
return cid
else:
self.error(f"Error on getting chip id: {self.eh.status(status)}")
@ -962,7 +989,7 @@ class DAXFlash(metaclass=LogBase):
log_channel = 1
system_os = self.FtSystemOSE.OS_LINUX
ufs_provision = 0x0
param = pack("<IIIII", da_log_level, log_channel, system_os, ufs_provision, 0x0)
param = pack("<IIIII", da_log_level, log_channel, system_os, ufs_provision, 0x1)
if self.send_param(param):
return True
return False
@ -997,6 +1024,7 @@ class DAXFlash(metaclass=LogBase):
hashaddr, hashmode, hashlen = self.mtk.daloader.compute_hash_pos(da1, da2, da2sig_len)
if hashaddr is not None:
da1 = self.xft.patch_da1(da1)
da2 = self.xft.patch_da2(da2)
da1 = self.mtk.daloader.fix_hash(da1, da2, hashaddr, hashmode, hashlen)
self.patch = True
@ -1058,9 +1086,8 @@ class DAXFlash(metaclass=LogBase):
self.daconfig.boot1size = self.ufs.lu1_size
self.daconfig.boot2size = self.ufs.lu2_size
self.chipid = self.get_chip_id()
self.daversion = self.get_da_version()
self.randomid = self.get_random_id()
# if self.get_da_stor_life_check() == 0x0:
# cid = self.get_chip_id()
speed = self.get_usb_speed()
if speed == b"full-speed":
self.info("Reconnecting to preloader")
@ -1133,9 +1160,6 @@ class DAXFlash(metaclass=LogBase):
if loaded:
self.info("Successfully uploaded stage 2")
self.reinit(True)
# if self.get_da_stor_life_check() == 0x0:
cid = self.get_chip_id()
self.info("DA-CODE : 0x%X", (cid.hw_code << 4) + (cid.hw_code >> 4))
self.config.hwparam.writesetting("hwcode", hex(self.config.hwcode))
daextdata = self.xft.patch()
@ -1155,6 +1179,7 @@ class DAXFlash(metaclass=LogBase):
return True
else:
self.error("Error on booting to da (xflash)")
return False
else:
self.error("Didn't get brom connection, got instead: " + hexlify(connagent).decode('utf-8'))
return False

View file

@ -275,7 +275,7 @@ class Main(metaclass=LogBase):
dwords = length // 4
if length % 4:
dwords += 1
if filename != None:
if filename is not None:
wf = open(filename, "wb")
sdata = b""
print_progress(0, 100, prefix='Progress:',
@ -285,9 +285,12 @@ class Main(metaclass=LogBase):
pos = 0
while dwords:
size = min(512 // 4, dwords)
data = b"".join(int.to_bytes(val, 4, 'little') for val in mtk.preloader.read32(addr + pos, size))
if dwords == 1:
data = pack("<I",mtk.preloader.read32(addr + pos, size))
else:
data = b"".join(int.to_bytes(val, 4, 'little') for val in mtk.preloader.read32(addr + pos, size))
sdata += data
if filename != "":
if filename is not None:
wf.write(data)
pos += len(data)
prog = pos / length * 100
@ -298,7 +301,7 @@ class Main(metaclass=LogBase):
dwords = (length - pos) // 4
print_progress(100, 100, prefix='Progress:',
suffix='Finished', bar_length=50)
if filename == "":
if filename is None:
print(hexlify(sdata).decode('utf-8'))
else:
wf.close()
@ -514,6 +517,8 @@ class Main(metaclass=LogBase):
mtk = da_handler.configure_da(mtk, preloader)
if mtk is not None:
da_handler.handle_da_cmds(mtk, cmd, self.args)
else:
self.close()
def cmd_log(self, mtk, filename):

View file

@ -167,7 +167,19 @@ class xflashext(metaclass=LogBase):
return daextdata
return None
def patch_da1(self, da1):
self.info("Patching da1 ...")
da1patched = bytearray(da1)
# Patch security
da_version_check = find_binary(da1, b"\x40\xB1\x01\x23\x4F\xF0")
if da_version_check != -1:
da1patched[da_version_check+0x2] = 0x0
else:
self.info("Error on patching da1 version check...")
return da1patched
def patch_da2(self, da2):
self.info("Patching da2 ...")
# open("da2.bin","wb").write(da2)
da2patched = bytearray(da2)
# Patch security

View file

@ -8,4 +8,5 @@ default_ids = [
[0x22d9, 0x0006, -1], # OPPO Preloader
[0x0FCE, 0xF200, -1], # Sony Brom
[0x0FCE, 0xD1E9, -1], # Sony Brom XA1
[0x0FCE, 0xD1E2, -1], # Sony Brom
]