mirror of
https://github.com/bkerler/mtkclient.git
synced 2024-11-14 19:25:05 -05:00
1. Improve dram handling
2. Import error reports 3. Add missing sony usb vid/pid 4. Some xflash improvements
This commit is contained in:
parent
b30d65c706
commit
c7752f2003
10 changed files with 141 additions and 35 deletions
3
mtk
3
mtk
|
@ -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")
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue