Prepare V2

This commit is contained in:
Bjoern Kerler 2023-12-14 14:41:42 +01:00
parent d09ece6366
commit 48f7be990c
1043 changed files with 8329 additions and 521 deletions

View file

@ -9,10 +9,11 @@ Once the mtk script is running, boot into brom mode by powering off device, pres
vol up + power or vol down + power and connect the phone. Once detected by the tool,
release the buttons.
## Unsupported chipsets
- MT678x, MT689x, MT688x, MT698x
- These chipsets use a new protocol called V6 and the bootrom is patched. There is currently NO support for these chipsets (due to the way these loaders are implemented)
- If you want support, consider donating so that I can afford one of these devices in order to start researching them
## MT678x, MT689x, MT688x, MT698x
- These chipsets use a new protocol called V6 and the bootrom is patched, thus you need a valid da via --loader option.
- On some devices, preloader is deactivated, but you still use it by running "adb reboot edl".
- This only works with UNFUSED devices currently.
- For all devices with DAA, SLA and Remote-Auth activated no public solution currently exists (for various reasons).
## Credits
- kamakiri [xyzz]

120
mtk
View file

@ -4,7 +4,7 @@
import argparse
from mtkclient.Library.mtk_main import Main, metamodes
info = "MTK Flash/Exploit Client V1.6.3 (c) B.Kerler 2018-2023"
info = "MTK Flash/Exploit Client Public V2.0.0 Beta (c) B.Kerler 2018-2023"
cmds = {
"printgpt": "Print GPT Table information",
@ -94,49 +94,79 @@ if __name__ == '__main__':
parser_da = subparsers.add_parser("da", help="Run da special commands")
da_cmds = parser_da.add_subparsers(dest='subcmd', help='Commands: peek poke keys unlock memdump seccfg rpmb efuse')
da_efuse = da_cmds.add_parser("efuse", help="Read efuses")
da_efuse.add_argument('--preloader', help='Set the preloader filename for dram config')
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_efuse.add_argument('--loader', type=str, help='Use specific loader, disable autodetection')
da_keys = da_cmds.add_parser("generatekeys", help="Generate keys")
da_keys.add_argument('--preloader', help='Set the preloader filename for dram config')
da_unlock = da_cmds.add_parser("seccfg", help="Unlock device / Configure seccfg")
da_unlock.add_argument('--preloader', help='Set the preloader filename for dram config')
da_rpmb = da_cmds.add_parser("rpmb", help="RPMB Tools")
da_rpmb.add_argument('--preloader', help='Set the preloader filename for dram config')
da_keys.add_argument('--loader', type=str, help='Use specific loader, disable autodetection')
da_meta = da_cmds.add_parser("meta", help="MetaMode Tools")
da_meta.add_argument('--preloader', help='Set the preloader filename for dram config')
da_meta.add_argument("metamode", type=str, help="metamode to use [off,usb,uart]")
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_r.add_argument('--preloader', help='Set the preloader filename for dram config')
da_rpmb_r.add_argument('--loader', type=str, help='Use specific loader, disable autodetection')
da_rpmb_r.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
da_rpmb_r.add_argument('--cert', type=str, help="Use cert file")
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_rpmb_w.add_argument('--preloader', help='Set the preloader filename for dram config')
da_rpmb_w.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
da_rpmb_w.add_argument('--cert', type=str, help="Use cert file")
da_rpmb_w.add_argument('--loader', type=str, help='Use specific loader, disable autodetection')
da_rpmb_e = da_rpmb_cmds.add_parser("e", help="Erase rpmb")
da_rpmb_e.add_argument('--preloader', help='Set the preloader filename for dram config')
da_rpmb_e.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
da_rpmb_e.add_argument('--cert', type=str, help="Use cert file")
da_rpmb_e.add_argument('--loader', type=str, help='Use specific loader, disable autodetection')
da_peek = da_cmds.add_parser("peek", help="Read memory")
da_peek.add_argument('--preloader', help='Set the preloader filename for dram config')
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('--loader', type=str, help='Use specific loader, disable autodetection')
da_peek.add_argument('--filename', type=str, help="Filename to write data into")
da_peek.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
da_peek.add_argument('--cert', type=str, help="Use cert file")
da_dump = da_cmds.add_parser("memdump", help="Dump whole memory areas")
da_dump.add_argument('directory', type=str, help="Directory to dump ram dump files")
da_dump.add_argument('--preloader', help='Set the preloader filename for dram config')
da_dump.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
da_dump.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
da_dump.add_argument('--cert', type=str, help="Use cert file")
da_dumpbrom = da_cmds.add_parser("dumpbrom", help="Dump whole memory areas")
da_dumpbrom.add_argument('--preloader', help='Set the preloader filename for dram config')
da_dumpbrom.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
da_dumpbrom.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
da_dumpbrom.add_argument('--cert', type=str, help="Use cert file")
da_poke = da_cmds.add_parser("poke", help="Write memory")
da_poke.add_argument('--preloader', help='Set the preloader filename for dram config')
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('--loader', type=str, help='Use specific DA loader, disable autodetection')
da_poke.add_argument('--filename', type=str, help="Filename to read data from")
da_poke.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
da_poke.add_argument('--cert', type=str, help="Use cert file")
da_unlock = da_cmds.add_parser("seccfg", help="Unlock device / Configure seccfg")
da_unlock.add_argument('--preloader', help='Set the preloader filename for dram config')
da_unlock.add_argument('flag', type=str, help="Needed flag (unlock,lock)")
da_unlock.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
da_unlock.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
da_unlock.add_argument('--cert', type=str, help="Use cert file")
parser_script.add_argument('script', help='Text script to run')
parser_script.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
@ -161,7 +191,8 @@ if __name__ == '__main__':
parser_script.add_argument('--preloader', help='Set the preloader filename for dram config')
parser_script.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_script.add_argument('--socid', help='Read Soc ID')
parser_script.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_script.add_argument('--cert', type=str, help="Use cert file")
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')
@ -185,6 +216,8 @@ if __name__ == '__main__':
parser_printgpt.add_argument('--preloader', help='Set the preloader filename for dram config')
parser_printgpt.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_printgpt.add_argument('--socid', help='Read Soc ID')
parser_printgpt.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_printgpt.add_argument('--cert', type=str, help="Use cert file")
parser_gpt.add_argument('directory', help='Filename to store gpt files')
parser_gpt.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
@ -212,6 +245,8 @@ if __name__ == '__main__':
'\t\tUFS: [lu0, lu1, lu2, lu0_lu1]')
parser_gpt.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_gpt.add_argument('--socid', help='Read Soc ID')
parser_gpt.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_gpt.add_argument('--cert', type=str, help="Use cert file")
parser_r.add_argument('partitionname', help='Partitions to read (separate by comma for multiple partitions)')
parser_r.add_argument('filename', help='Filename to store files (separate by comma for multiple filenames)')
@ -240,6 +275,8 @@ if __name__ == '__main__':
'\t\tUFS: [lu0, lu1, lu2, lu0_lu1]')
parser_r.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_r.add_argument('--socid', help='Read Soc ID')
parser_r.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_r.add_argument('--cert', type=str, help="Use cert file")
parser_rl.add_argument('directory', help='Directory to write dumped partitions into')
parser_rl.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
@ -268,6 +305,8 @@ if __name__ == '__main__':
parser_rl.add_argument('--filename', help='Optional filename')
parser_rl.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_rl.add_argument('--socid', help='Read Soc ID')
parser_rl.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_rl.add_argument('--cert', type=str, help="Use cert file")
parser_rf.add_argument('filename', help='Filename to store flash file')
parser_rf.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
@ -299,6 +338,8 @@ if __name__ == '__main__':
parser_rf.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_rf.add_argument('--socid', help='Read Soc ID')
parser_rf.add_argument('--iot', help='Use special mode for iot MT6261/2301', action="store_true", default=False)
parser_rf.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_rf.add_argument('--cert', type=str, help="Use cert file")
parser_rs.add_argument('startsector', help='Sector to start reading (int or hex)')
parser_rs.add_argument('sectors', help='Sector count')
@ -331,6 +372,8 @@ if __name__ == '__main__':
parser_rs.add_argument('--filename', help='Optional filename')
parser_rs.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_rs.add_argument('--socid', help='Read Soc ID')
parser_rs.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_rs.add_argument('--cert', type=str, help="Use cert file")
parser_ro.add_argument('offset', help='Offset to start reading (int or hex)')
parser_ro.add_argument('length', help='Length to read (int or hex)')
@ -360,6 +403,8 @@ if __name__ == '__main__':
'\t\tEMMC: [user, boot1, boot2, gp1, gp2, gp3, gp4, rpmb]' +
'\t\tUFS: [lu0, lu1, lu2, lu0_lu1]')
parser_ro.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_ro.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_ro.add_argument('--cert', type=str, help="Use cert file")
parser_w.add_argument('partitionname', help='Partition to write (separate by comma for multiple partitions)')
parser_w.add_argument('filename', help='Filename for writing (separate by comma for multiple filenames)')
@ -391,6 +436,8 @@ if __name__ == '__main__':
parser_w.add_argument('--filename', help='Optional filename')
parser_w.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_w.add_argument('--socid', help='Read Soc ID')
parser_w.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_w.add_argument('--cert', type=str, help="Use cert file")
parser_wf.add_argument('filename', help='Filename to write to flash')
parser_wf.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
@ -419,6 +466,8 @@ if __name__ == '__main__':
'\t\tUFS: [lu0, lu1, lu2, lu0_lu1]')
parser_wf.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_wf.add_argument('--socid', help='Read Soc ID')
parser_wf.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_wf.add_argument('--cert', type=str, help="Use cert file")
parser_wl.add_argument('directory', help='Directory with partition filenames to write to flash')
parser_wl.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
@ -448,6 +497,8 @@ if __name__ == '__main__':
parser_wl.add_argument('--filename', help='Optional filename')
parser_wl.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_wl.add_argument('--socid', help='Read Soc ID')
parser_wl.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_wl.add_argument('--cert', type=str, help="Use cert file")
parser_wo.add_argument('offset', help='Offset to start writing (int or hex)')
parser_wo.add_argument('length', help='Length to write (int or hex)')
@ -479,6 +530,8 @@ if __name__ == '__main__':
parser_wo.add_argument('--filename', help='Optional filename')
parser_wo.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_wo.add_argument('--socid', help='Read Soc ID')
parser_wo.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_wo.add_argument('--cert', type=str, help="Use cert file")
parser_e.add_argument('partitionname', help='Partitionname to erase from flash')
parser_e.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
@ -508,6 +561,8 @@ if __name__ == '__main__':
parser_e.add_argument('--filename', help='Optional filename')
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_e.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_e.add_argument('--cert', type=str, help="Use cert file")
parser_es.add_argument('partitionname', help='Partitionname to erase from flash')
parser_es.add_argument('sectors', help='Sectors to erase')
@ -538,6 +593,8 @@ if __name__ == '__main__':
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_es.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_es.add_argument('--cert', type=str, help="Use cert file")
parser_ess.add_argument('startsector', help='Startsector to erase')
parser_ess.add_argument('sectors', help='Sectors to erase')
@ -568,6 +625,8 @@ if __name__ == '__main__':
parser_ess.add_argument('--filename', help='Optional filename')
parser_ess.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_ess.add_argument('--socid', help='Read Soc ID')
parser_ess.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_ess.add_argument('--cert', type=str, help="Use cert file")
parser_footer.add_argument('filename', help='Filename to store footer')
parser_footer.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
@ -595,6 +654,8 @@ if __name__ == '__main__':
parser_footer.add_argument('--filename', help='Optional filename')
parser_footer.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_footer.add_argument('--socid', help='Read Soc ID')
parser_footer.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_footer.add_argument('--cert', type=str, help="Use cert file")
parser_dumpbrom.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
parser_dumpbrom.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
@ -614,7 +675,8 @@ if __name__ == '__main__':
parser_dumpbrom.add_argument('--filename', help='Optional filename')
parser_dumpbrom.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_dumpbrom.add_argument('--socid', help='Read Soc ID')
parser_dumpbrom.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_dumpbrom.add_argument('--cert', type=str, help="Use cert file")
parser_dumpsram.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
parser_dumpsram.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
@ -634,6 +696,8 @@ if __name__ == '__main__':
parser_dumpsram.add_argument('--filename', help='Optional filename')
parser_dumpsram.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_dumpsram.add_argument('--socid', help='Read Soc ID')
parser_dumpsram.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_dumpsram.add_argument('--cert', type=str, help="Use cert file")
parser_dumppreloader.add_argument('--loader', type=str, help='Use specific DA loader, disable autodetection')
parser_dumppreloader.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
@ -653,6 +717,8 @@ if __name__ == '__main__':
parser_dumppreloader.add_argument('--filename', help='Optional filename')
parser_dumppreloader.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_dumppreloader.add_argument('--socid', help='Read Soc ID')
parser_dumppreloader.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_dumppreloader.add_argument('--cert', type=str, help="Use cert file")
parser_payload.add_argument('--payload', type=str, help='Payload filename (optional)')
parser_payload.add_argument('--metamode', type=str, default=None, help='metamode to use ' + metamodes)
@ -673,11 +739,15 @@ if __name__ == '__main__':
'("amonet","kamakiri","kamakiri2","carbonara" kamakiri2/da used by default)')
parser_payload.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_payload.add_argument('--socid', help='Read Soc ID')
parser_payload.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_payload.add_argument('--cert', type=str, help="Use cert file")
parser_crash.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
parser_crash.add_argument('--pid', type=str, help='Set usb product id used for MTK Preloader')
parser_crash.add_argument('--debugmode', action='store_true', default=False, help='Enable verbose mode')
parser_crash.add_argument('--mode', help='Set a crash mode (0=dasend1,1=dasend2,2=daread)')
parser_crash.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_crash.add_argument('--cert', type=str, help="Use cert file")
parser_brute.add_argument('--loader', type=str, help='Use specific loader, disable autodetection')
parser_brute.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
@ -696,20 +766,29 @@ if __name__ == '__main__':
parser_brute.add_argument('--filename', help='Optional filename')
parser_brute.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_brute.add_argument('--socid', help='Read Soc ID')
parser_brute.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_brute.add_argument('--cert', type=str, help="Use cert file")
parser_logs.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
parser_logs.add_argument('--pid', type=str, help='Set usb product id used for MTK Preloader')
parser_logs.add_argument('--debugmode', action='store_true', default=False, help='Enable verbose mode')
parser_logs.add_argument('--filename', help='Optional filename to write dumped data')
parser_logs.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_logs.add_argument('--cert', type=str, help="Use cert file")
parser_meta.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
parser_meta.add_argument('--pid', type=str, help='Set usb product id used for MTK Preloader')
parser_meta.add_argument('--debugmode', action='store_true', default=False, help='Enable verbose mode')
parser_meta.add_argument('metamode', type=str, default=None, help='metamode to use ' + metamodes)
parser_meta.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_meta.add_argument('--cert', type=str, help="Use cert file")
parser_gettargetconfig.add_argument('--vid', type=str, help='Set usb vendor id used for MTK Preloader')
parser_gettargetconfig.add_argument('--pid', type=str, help='Set usb product id used for MTK Preloader')
parser_gettargetconfig.add_argument('--debugmode', action='store_true', default=False, help='Enable verbose mode')
parser_gettargetconfig.add_argument('--socid', help='Read Soc ID')
parser_gettargetconfig.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_gettargetconfig.add_argument('--cert', type=str, help="Use cert file")
parser_peek.add_argument('address', help='Address to read from memory')
parser_peek.add_argument('length', help='Bytes to read from memory')
@ -731,6 +810,8 @@ if __name__ == '__main__':
parser_peek.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_peek.add_argument('--socid', help='Read Soc ID')
parser_peek.add_argument('--preloader', help='Set the preloader filename for dram config')
parser_peek.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_peek.add_argument('--cert', type=str, help="Use cert file")
parser_stage.add_argument('--payload', type=str, help='Payload filename (optional)')
parser_stage.add_argument('--stage2', help='Set stage2 filename')
@ -753,6 +834,8 @@ if __name__ == '__main__':
parser_stage.add_argument('--filename', help='Optional filename')
parser_stage.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_stage.add_argument('--socid', help='Read Soc ID')
parser_stage.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_stage.add_argument('--cert', type=str, help="Use cert file")
parser_plstage.add_argument('--payload', type=str, help='Payload filename (optional)')
parser_plstage.add_argument('--pl', help='pl stage filename (optional)')
@ -779,6 +862,8 @@ if __name__ == '__main__':
parser_plstage.add_argument('--crash', help='Enforce crash if device is in pl mode to enter brom mode')
parser_plstage.add_argument('--socid', help='Read Soc ID')
parser_plstage.add_argument('--startpartition', help='Option for plstage - Boot to (lk, tee1)')
parser_plstage.add_argument('--auth', type=str, help="Use auth file (auth_sv5.auth)")
parser_plstage.add_argument('--cert', type=str, help="Use cert file")
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')
@ -846,6 +931,15 @@ if __name__ == '__main__':
da_dump.add_argument('--uartloglevel', help='Set uart log level (0=Trace, 2=Normal)')
da_rpmb.add_argument('--uartloglevel', help='Set uart log level (0=Trace, 2=Normal)')
parser_script.add_argument('--appid', help='Use app id (hexstring)')
parser_printgpt.add_argument('--appid', help='Use app id (hexstring)')
parser_rs.add_argument('--appid', help='Use app id (hexstring)')
parser_rf.add_argument('--appid', help='Use app id (hexstring)')
parser_rl.add_argument('--appid', help='Use app id (hexstring)')
parser_gpt.add_argument('--appid', help='Use app id (hexstring)')
parser_r.add_argument('--appid', help='Use app id (hexstring)')
da_keys.add_argument('--appid', help='Use app id (hexstring)')
args = parser.parse_args()
cmd = args.cmd
if cmd not in cmds:

0
mtkclient/Library/DA/__init__.py Normal file → Executable file
View file

View file

@ -153,7 +153,7 @@ class DAconfig(metaclass=LogBase):
loaders = []
for root, dirs, files in os.walk(self.pathconfig.get_loader_path(), topdown=False):
for file in files:
if "MTK_AllInOne_DA" in file:
if "MTK_AllInOne_DA" in file or "MTK_DA" in file:
loaders.append(os.path.join(root, file))
loaders = sorted(loaders)[::-1]
for loader in loaders:
@ -217,14 +217,19 @@ class DAconfig(metaclass=LogBase):
with open(loader, 'rb') as bootldr:
# data = bootldr.read()
# self.debug(hexlify(data).decode('utf-8'))
bootldr.seek(0x68)
hdr = bootldr.read(0x68)
count_da = unpack("<I", bootldr.read(4))[0]
if b"MTK_DA_v6" in hdr:
v6 = True
else:
v6 = False
for i in range(0, count_da):
bootldr.seek(0x6C + (i * 0xDC))
da = DA(bootldr.read(0xDC))
da.setfilename(loader)
if da.hw_code == 0x8127 and "5.1824" not in loader:
continue
da.v6 = v6
#if da.hw_code == 0x8127 and "5.1824" not in loader:
# continue
if da.hw_code not in self.dasetup:
if da.hw_code!=0:
self.dasetup[da.hw_code] = [da]

0
mtkclient/Library/DA/legacy/__init__.py Normal file → Executable file
View file

0
mtkclient/Library/DA/legacy/dalegacy_flash_param.py Normal file → Executable file
View file

View file

View file

@ -72,6 +72,9 @@ class DALegacy(metaclass=LogBase):
self.patch = True
self.lft = legacyext(self.mtk, self, loglevel)
def boot_to(self, addr, data, display=True, timeout=0.5):
pass
def get_fat_info(self, addr: int, dwords: int):
if self.usbwrite(self.Cmd.GET_FAT_INFO_CMD): # 0xF0
self.usbwrite(pack(">I", addr))
@ -209,12 +212,22 @@ class DALegacy(metaclass=LogBase):
return True
return False
def recheck(self): # If Preloader is needed
def sec_usb_recheck(self): # If Preloader is needed
# toDo / sha1 hash
sec_info_len = 0
cmd = self.Cmd.SECURE_USB_RECHECK_CMD + pack(">I", sec_info_len) # B4
status = unpack(">I", self.mtk.port.mtk_cmd(cmd, 1))[0]
if status == 0x1799:
return False # S-USBDL disabled
self.info("S-USBDL disabled")
return True
elif status == 0x179A:
self.info("S-USBDL enabled")
buffer1=bytearray()
buffer2=bytearray()
for i in range(0x100):
buffer1.append(self.rbyte(1))
for i in range(0x5):
buffer2.append(self.rbyte(1))
return True
def set_stage2_config(self, hwcode):
@ -274,6 +287,8 @@ class DALegacy(metaclass=LogBase):
self.error("Didn't receive Stage2 dram info, please check usb cable/hub and retry.")
return False
errorcode = int.from_bytes(buffer,'big')
if errorcode == 0x0:
return True
if errorcode != 0xBC3:
self.error(self.eh.status(errorcode))
return False
@ -303,7 +318,7 @@ class DALegacy(metaclass=LogBase):
if len(returnval)!=4:
self.error("Didn't get a response on dram read")
return False
errorval = errorcode = int.from_bytes(returnval,'big')
errorval = int.from_bytes(returnval,'big')
if errorval != 0xBC4:
self.error(self.eh.status(errorval))
return False
@ -382,8 +397,47 @@ class DALegacy(metaclass=LogBase):
return False
return True
def set_speed_iot(self):
self.usbwrite(b"\x59")
ack = self.usbread(1)
self.usbwrite(b"\xF0")
ret = self.usbread(28)
self.usbwrite(self.Cmd.SPEED_CMD+b"\x01\x01")
ack = self.usbread(1)
if ack != b"\x5A":
return False
self.usbwrite(b"\x5A")
#try:
# self.mtk.port.cdc.setcontrollinestate(RTS=True,DTR=True)
#except:
# pass
try:
self.mtk.port.cdc.setLineCoding(baudrate=921600, parity=0, databits=8, stopbits=1)
except Exception as err:
print(err)
pass
time.sleep(0.1)
for i in range(10):
self.usbwrite(b"\xC0")
ack = self.usbread(1)
if ack == b"\xC0":
break
time.sleep(0.02)
self.usbwrite(b"\x5A")
ack = self.usbread(1)
if ack == b"\x5A":
for i in range(256):
loop_val = pack(">B", i)
self.usbwrite(loop_val)
if self.usbread(1) != loop_val:
return False
else:
return False
return True
def set_speed(self):
self.usbwrite(DALegacy.Cmd.SPEED_CMD)
self.usbwrite(self.Cmd.SPEED_CMD)
self.usbwrite(int.to_bytes(921600, 4, 'big'))
ack = self.usbread(1)
if ack != b"\x5A":
@ -485,7 +539,7 @@ class DALegacy(metaclass=LogBase):
bootldr.seek(da2offset)
da2 = bootldr.read(self.daconfig.da_loader.region[2].m_len)
if self.mtk.config.is_brom or not self.mtk.config.target_config["sbc"]:
hashaddr, hashmode, hashlen = self.mtk.daloader.compute_hash_pos(da1, da2, da2sig_len)
hashaddr, hashmode, hashlen = self.mtk.daloader.compute_hash_pos(da1, da2, da1sig_len, da2sig_len,self.daconfig.da_loader.v6)
if hashaddr is not None:
da2patched = self.lft.patch_da2(da2)
if da2patched != da2:
@ -602,7 +656,6 @@ class DALegacy(metaclass=LogBase):
da3sig_len = self.daconfig.da_loader.region[stage1 + 2].m_sig_len
bootldr.seek(da3offset)
da3 = bootldr.read(da3size)
if self.mtk.preloader.send_da(da1address, da1size, da1sig_len, da1):
if self.mtk.preloader.send_da(da2address, da2size, da2sig_len, da2):
if self.mtk.preloader.jump_da(da1address):
@ -645,7 +698,6 @@ class DALegacy(metaclass=LogBase):
i = 0
while bytestosend > 0:
data = da3[i:i + 0x24]
print(data.hex())
self.usbwrite(data)
i += 0x24
bytestosend -= 0x24
@ -679,6 +731,7 @@ 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
self.set_speed_iot()
return True
return False
@ -1000,7 +1053,7 @@ class DALegacy(metaclass=LogBase):
self.daconfig.readsize = self.daconfig.flashsize // self.daconfig.pagesize * (
self.daconfig.pagesize + self.daconfig.sparesize)
elif self.daconfig.flashtype == "nor":
packetsize = 0x400
packetsize = 0x1000
self.usbwrite(self.Cmd.READ_CMD) # D6
if not self.config.iot:
self.usbwrite(b"\x0C") # Host:Linux, 0x0B=Windows
@ -1026,24 +1079,27 @@ class DALegacy(metaclass=LogBase):
worker = Thread(target=writedata, args=(filename, rq), daemon=True)
worker.start()
bytestoread = length
curpos = 0
while bytestoread > 0:
size = bytestoread
if bytestoread > packetsize:
size = packetsize
rq.put(self.usbread(size))
tmp = self.usbread(size)
rq.put(tmp[:size])
bytestoread -= size
checksum = unpack(">H", self.usbread(1) + self.usbread(1))[0]
curpos+=size
checksum = unpack(">H", self.usbread(2))[0]
self.debug("Checksum: %04X" % checksum)
self.usbwrite(self.Rsp.ACK)
if length > bytestoread:
rpos = length - bytestoread
else:
rpos = 0
self.usbwrite(self.Rsp.ACK)
self.mtk.daloader.progress.show_progress("Read", rpos, length, display)
self.mtk.daloader.progress.show_progress("Read", length, length, display)
rq.put(None)
worker.join(60)
return True
return b""
else:
buffer = bytearray()
bytestoread = length

0
mtkclient/Library/DA/legacy/dalegacy_param.py Normal file → Executable file
View file

0
mtkclient/Library/DA/legacy/extension/__init__.py Normal file → Executable file
View file

33
mtkclient/Library/DA/legacy/extension/legacy.py Normal file → Executable file
View file

@ -1,4 +1,5 @@
import os
import sys
from struct import unpack, pack
from mtkclient.Library.settings import hwparam
@ -219,6 +220,31 @@ class legacyext(metaclass=LogBase):
return None
def generate_keys(self):
if self.config.hwcode in [0x2601,0x6572]:
base = 0x11141000
elif self.config.hwcode==0x6261:
base = 0x70000000
elif self.config.hwcode in [0x8172,0x8176]:
base = 0x122000
else:
base = 0x100000
data = b"".join([pack("<I", val) for val in self.readmem(0x111418EC, 0x20000 // 4)])
print(data.hex())
sys.stdout.flush()
if self.config.meid is None:
try:
data = b"".join([pack("<I", val) for val in self.readmem(base+0x8EC, 0x16 // 4)])
self.config.meid = data
self.config.set_meid(data)
except:
return
if self.config.socid is None:
try:
data = b"".join([pack("<I", val) for val in self.readmem(base+0x934, 0x20 // 4)])
self.config.socid = data
self.config.set_socid(data)
except:
return
hwc = self.cryptosetup()
retval = {}
retval["hwcode"] = hex(self.config.hwcode)
@ -233,8 +259,6 @@ class legacyext(metaclass=LogBase):
if meid is not None:
self.info("MEID : " + hexlify(meid).decode('utf-8'))
retval["meid"] = hexlify(meid).decode('utf-8')
if self.config.hwparam is None:
self.config.hwparam = hwparam(meid, self.config.hwparam_path)
self.config.hwparam.writesetting("meid", hexlify(meid).decode('utf-8'))
if socid is not None:
self.info("SOCID : " + hexlify(socid).decode('utf-8'))
@ -252,7 +276,7 @@ class legacyext(metaclass=LogBase):
self.info("Generating dxcc rpmbkey2...")
rpmb2key = hwc.aes_hwcrypt(btype="dxcc", mode="rpmb2")
self.info("Generating dxcc km key...")
ikey = hwc.aes_hwcrypt(btype="dxcc", mode="itrustee")
ikey = hwc.aes_hwcrypt(btype="dxcc", mode="itrustee", data=self.config.hwparam.appid)
# self.info("Generating dxcc platkey + provkey key...")
# platkey, provkey = hwc.aes_hwcrypt(btype="dxcc", mode="prov")
# self.info("Provkey : " + hexlify(provkey).decode('utf-8'))
@ -335,3 +359,6 @@ class legacyext(metaclass=LogBase):
retval["mtee2"] = hexlify(mtee2).decode('utf-8')
self.config.hwparam.writesetting("hwcode", retval["hwcode"])
return retval
def custom_read_reg(self, addr:int, length:int) -> bytes:
return self.custom_read(addr,length)

95
mtkclient/Library/DA/mtk_da_handler.py Normal file → Executable file
View file

@ -33,7 +33,7 @@ class DA_handler(metaclass=LogBase):
def dump_preloader_ram(self):
try:
data = b"".join([pack("<I", val) for val in self.mtk.preloader.read32(0x200000, 0x10000 // 4)])
data=(b"".join([pack("<I", val) for val in self.mtk.preloader.read32(0x200000, 0x10000//4)]))
idx = data.find(b"\x4D\x4D\x4D\x01\x38\x00\x00\x00")
if idx != -1:
data = data[idx:]
@ -78,13 +78,15 @@ class DA_handler(metaclass=LogBase):
if mtk.port.cdc.connected is None or not mtk.port.cdc.connected or mtk.serialportname is not None:
mtk.preloader.init()
else:
if mtk.serialportname is not None:
mtk.preloader.init()
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"]:
if mtk.config.target_config["daa"] and mtk.config.is_brom:
mtk = mtk.bypass_security()
self.mtk = mtk
self.info("Device is protected.")
@ -95,8 +97,12 @@ class DA_handler(metaclass=LogBase):
preloader = self.dump_preloader_ram()
else:
self.info("Device is unprotected.")
# if not mtk.config.is_brom:
# self.mtk.preloader.reset_to_brom()
try:
if not mtk.config.loader:
if not mtk.config.is_brom:
self.mtk.preloader.reset_to_brom()
except:
pass
if mtk.config.is_brom and not mtk.config.iot:
self.info("Device is in BROM-Mode. Bypassing security.")
mtk = mtk.bypass_security() # Needed for dumping preloader
@ -108,10 +114,15 @@ class DA_handler(metaclass=LogBase):
preloader = self.dump_preloader_ram()
if preloader is None:
self.error("Failed to dump preloader from ram.")
mtk.daloader.patch = False
else:
mtk.daloader.patch = True
elif not mtk.config.is_brom:
self.info("Device is in Preloader-Mode :(")
self.info("Device is in Preloader-Mode.")
mtk.daloader.patch = False
else:
self.info("Device is in BROM-Mode. Iot Mode :)")
self.info("Device is in BROM-Mode - Iot Mode.")
mtk.daloader.patch = False
if preloader is not None and mtk.config.preloader is None:
mtk.config.preloader = preloader
@ -168,8 +179,8 @@ class DA_handler(metaclass=LogBase):
break
if rpartition is not None:
self.info(f"Dumping partition \"{rpartition.name}\"")
if self.mtk.daloader.readflash(addr=rpartition.sector * self.mtk.daloader.daconfig.pagesize,
length=rpartition.sectors * self.mtk.daloader.daconfig.pagesize,
if self.mtk.daloader.readflash(addr=rpartition.sector * self.config.pagesize,
length=rpartition.sectors * self.config.pagesize,
filename=partfilename, parttype=parttype):
self.info(f"Dumped sector {str(rpartition.sector)} with sector count " +
f"{str(rpartition.sectors)} as {partfilename}.")
@ -201,6 +212,9 @@ class DA_handler(metaclass=LogBase):
if not os.path.exists(directory):
os.mkdir(directory)
data, guid_gpt = self.mtk.daloader.get_gpt(parttype=parttype)
if not data:
self.error("Couldn't set gpt :(")
return
if guid_gpt is None:
self.error("Error reading gpt")
else:
@ -213,7 +227,7 @@ class DA_handler(metaclass=LogBase):
sfilename = os.path.join(storedir, f"gpt_backup.bin")
with open(sfilename, "wb") as wf:
wf.write(data[self.mtk.daloader.daconfig.pagesize * 2:])
wf.write(data[self.config.pagesize * 2:])
countGPT = 0
for partition in guid_gpt.partentries:
@ -225,8 +239,8 @@ class DA_handler(metaclass=LogBase):
f"Dumping partition {str(partition.name)} with sector count {str(partition.sectors)} " +
f"as {filename}.")
if self.mtk.daloader.readflash(addr=partition.sector * self.mtk.daloader.daconfig.pagesize,
length=partition.sectors * self.mtk.daloader.daconfig.pagesize,
if self.mtk.daloader.readflash(addr=partition.sector * self.config.pagesize,
length=partition.sectors * self.config.pagesize,
filename=filename,
parttype=parttype):
@ -256,14 +270,14 @@ class DA_handler(metaclass=LogBase):
length = self.mtk.daloader.daconfig.flashsize
print(f"Dumping sector 0 with flash size {hex(length)} as {filename}.")
sys.stdout.flush()
if self.mtk.daloader.readflash(addr=0, length=length, filename=filename, parttype=parttype):
if self.mtk.daloader.readflash(addr=0, length=length, filename=filename, parttype=parttype)==b"ACK":
print(f"Dumped sector 0 with flash size {hex(length)} as {filename}.")
else:
print(f"Failed to dump sector 0 with flash size {hex(length)} as {filename}.")
def da_rs(self, start: int, sectors: int, filename: str, parttype: str):
return self.mtk.daloader.readflash(addr=start * self.mtk.daloader.daconfig.pagesize,
length=sectors * self.mtk.daloader.daconfig.pagesize,
return self.mtk.daloader.readflash(addr=start * self.config.pagesize,
length=sectors * self.config.pagesize,
filename=filename, parttype=parttype)
def da_ro(self, start: int, length: int, filename: str, parttype: str):
@ -283,10 +297,10 @@ class DA_handler(metaclass=LogBase):
print(f"Detected partition: {partition.name}")
if partition.name in ["userdata2", "userdata"]:
data = self.mtk.daloader.readflash(
addr=(partition.sector + partition.sectors) * self.mtk.daloader.daconfig.pagesize - 0x4000,
addr=(partition.sector + partition.sectors) * self.config.pagesize - 0x4000,
length=0x4000, filename="", parttype="user", display=False)
else:
data = self.mtk.daloader.readflash(addr=partition.sector * self.mtk.daloader.daconfig.pagesize,
data = self.mtk.daloader.readflash(addr=partition.sector * self.config.pagesize,
length=0x4000, filename="", parttype="user",
display=False)
if data == b"":
@ -318,8 +332,8 @@ class DA_handler(metaclass=LogBase):
res = self.mtk.daloader.detect_partition(partition, parttype)
if res[0]:
rpartition = res[1]
if self.mtk.daloader.writeflash(addr=rpartition.sector * self.mtk.daloader.daconfig.pagesize,
length=rpartition.sectors * self.mtk.daloader.daconfig.pagesize,
if self.mtk.daloader.writeflash(addr=rpartition.sector * self.config.pagesize,
length=rpartition.sectors * self.config.pagesize,
filename=partfilename,
parttype=parttype):
print(
@ -374,8 +388,8 @@ class DA_handler(metaclass=LogBase):
res = self.mtk.daloader.detect_partition(partition, parttype)
if res[0]:
rpartition = res[1]
if self.mtk.daloader.writeflash(addr=rpartition.sector * self.mtk.daloader.daconfig.pagesize,
length=rpartition.sectors * self.mtk.daloader.daconfig.pagesize,
if self.mtk.daloader.writeflash(addr=rpartition.sector * self.config.pagesize,
length=rpartition.sectors * self.config.pagesize,
filename=partfilename,
parttype=parttype):
print(
@ -422,8 +436,8 @@ class DA_handler(metaclass=LogBase):
res = self.mtk.daloader.detect_partition(partition, parttype)
if res[0]:
rpartition = res[1]
if self.mtk.daloader.formatflash(addr=rpartition.sector * self.mtk.daloader.daconfig.pagesize,
length=rpartition.sectors * self.mtk.daloader.daconfig.pagesize,
if self.mtk.daloader.formatflash(addr=rpartition.sector * self.config.pagesize,
length=rpartition.sectors * self.config.pagesize,
partitionname=partition, parttype=parttype):
print(
f"Formatted sector {str(rpartition.sector)} with " +
@ -448,9 +462,9 @@ class DA_handler(metaclass=LogBase):
wipedata = b"\x00" * 0x200000
error = False
while sectors:
sectorsize = sectors * self.mtk.daloader.daconfig.pagesize
sectorsize = sectors * self.config.pagesize
wsize = min(sectorsize, 0x200000)
if self.mtk.daloader.writeflash(addr=sector * self.mtk.daloader.daconfig.pagesize,
if self.mtk.daloader.writeflash(addr=sector * self.config.pagesize,
length=wsize,
filename=None,
wdata=wipedata[:wsize],
@ -460,15 +474,15 @@ class DA_handler(metaclass=LogBase):
f"sector count {str(sectors)}.")
error = True
break
sectors -= (wsize // self.mtk.daloader.daconfig.pagesize)
sector += (wsize // self.mtk.daloader.daconfig.pagesize)
sectors -= (wsize // self.config.pagesize)
sector += (wsize // self.config.pagesize)
if not error:
print(
f"Formatted sector {str(sector)} with sector count {str(sectors)}.")
else:
pos = 0
self.mtk.daloader.formatflash(addr=sector * self.mtk.daloader.daconfig.pagesize,
length=min(sectors * self.mtk.daloader.daconfig.pagesize, 0xF000000),
self.mtk.daloader.formatflash(addr=sector * self.config.pagesize,
length=min(sectors * self.config.pagesize, 0xF000000),
partitionname=None,
parttype=parttype,
display=True)
@ -482,8 +496,8 @@ class DA_handler(metaclass=LogBase):
res = self.mtk.daloader.detect_partition(partition, parttype)
if res[0]:
rpartition = res[1]
rsectors = min(sectors * self.mtk.daloader.daconfig.pagesize,
rpartition.sectors * self.mtk.daloader.daconfig.pagesize)
rsectors = min(sectors * self.config.pagesize,
rpartition.sectors * self.config.pagesize)
if sectors > rsectors:
self.error(f"Partition {partition} only has {rsectors}, you were using {sectors}. " +
f"Aborting")
@ -494,7 +508,7 @@ class DA_handler(metaclass=LogBase):
while sectors:
sectorsize = sectors * self.mtk.daloader.daconfig.pagesize
wsize = min(sectorsize, 0x200000)
if self.mtk.daloader.writeflash(addr=sector * self.mtk.daloader.daconfig.pagesize,
if self.mtk.daloader.writeflash(addr=sector * self.config.pagesize,
length=wsize,
filename=None,
wdata=wipedata[:wsize],
@ -504,8 +518,8 @@ class DA_handler(metaclass=LogBase):
f"sector count {str(sectors)}.")
error = True
break
sectors -= (wsize // self.mtk.daloader.daconfig.pagesize)
sector += (wsize // self.mtk.daloader.daconfig.pagesize)
sectors -= (wsize // self.config.pagesize)
sector += (wsize // self.config.pagesize)
if not error:
print(
f"Formatted sector {str(rpartition.sector)} with " +
@ -518,7 +532,7 @@ class DA_handler(metaclass=LogBase):
pos = 0
for partitionname in partitions:
self.mtk.daloader.formatflash(addr=pos,
length=min(sectors * self.mtk.daloader.daconfig.pagesize, 0xF000000),
length=min(sectors * self.config.pagesize, 0xF000000),
partitionname=partitionname,
parttype=parttype,
display=True)
@ -545,9 +559,15 @@ class DA_handler(metaclass=LogBase):
efuseconfig = efuse(base, hwcode)
for idx in range(len(efuseconfig.efuses)):
addr = efuseconfig.efuses[idx]
data = bytearray(self.mtk.daloader.peek(addr=addr, length=4))
if addr < 0x1000:
data = int.to_bytes(addr, 4, 'little')
else:
data = bytearray(self.mtk.daloader.peek(addr=addr, length=4))
self.info(f"EFuse Idx {hex(idx)}: {data.hex()}")
def da_brom(self, filename:str):
return self.mtk.daloader.dump_brom(filename)
def da_peek(self, addr: int, length: int, filename: str):
bytestoread = length
pos = 0
@ -716,7 +736,7 @@ 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, memdump, efuse]")
print("Available da cmds are: [peek, poke, generatekeys, seccfg, rpmb, meta, memdump, efuse, dumpbrom]")
return
if subcmd == "peek":
addr = getint(args.address)
@ -760,6 +780,9 @@ class DA_handler(metaclass=LogBase):
self.da_poke(addr=addr, data=data, filename=filename)
elif subcmd == "generatekeys":
mtk.daloader.keys()
elif subcmd == "dumpbrom":
filename = f"brom_{hex(mtk.daloader.config.hwcode)[2:]}.bin"
mtk.daloader.dump_brom(filename=filename)
elif subcmd == "efuse":
self.da_efuse()
elif subcmd == "seccfg":

View file

@ -17,11 +17,13 @@ from mtkclient.Library.DA.xflash.xflash_lib import DAXFlash
from mtkclient.config.brom_config import damodes
from mtkclient.Library.DA.xflash.extension.xflash import xflashext
from mtkclient.Library.DA.legacy.extension.legacy import legacyext
from mtkclient.Library.DA.xml.extension.v6 import xmlflashext
from mtkclient.Library.settings import hwparam
class DAloader(metaclass=LogBase):
def __init__(self, mtk, loglevel=logging.INFO):
self.patch = False
self.__logger = logsetup(self, self.__logger, loglevel, mtk.config.gui)
self.mtk = mtk
self.config = mtk.config
@ -36,7 +38,6 @@ 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.hwparam = hwparam(mtk.config.meid)
self.progress = progress(self.daconfig.pagesize, self.mtk.config.guiprogress)
self.xft = None
self.lft = None
@ -58,7 +59,7 @@ class DAloader(metaclass=LogBase):
config["socid"] = hexlify(self.config.socid).decode('utf-8')
config["flashtype"] = self.daconfig.flashtype
config["flashsize"] = self.daconfig.flashsize
if not self.mtk.config.chipconfig.damode == damodes.XFLASH:
if not self.mtk.config.chipconfig.damode == damodes.XFLASH and not self.mtk.config.chipconfig.damode == damodes.XML:
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
@ -70,19 +71,45 @@ class DAloader(metaclass=LogBase):
open(".state", "w").write(json.dumps(config))
def compute_hash_pos(self, da1, da2, da2sig_len):
def compute_hash_pos(self, da1, da2, da1sig_len, da2sig_len, v6):
hashlen = len(da2) - da2sig_len
hashmode, idx = self.calc_da_hash(da1, da2[:hashlen])
if idx == -1:
hashlen = len(da2)
hashmode, idx = self.calc_da_hash(da1, da2[:hashlen])
if idx == -1:
self.error("Hash computation failed.")
return None, None, None
if idx == -1 and not v6:
hashlen = len(da2) - da2sig_len
idx, hashmode = self.find_da_hash_V5(da1)
elif idx == -1 and v6:
hashlen = len(da2) - da2sig_len
idx, hashmode = self.find_da_hash_V6(da1, da1sig_len)
if idx == -1:
self.error("Hash computation failed.")
return None, None, None
return idx, hashmode, hashlen
return idx, hashmode, hashlen
def find_da_hash_V6(self, da1, siglen):
pos = len(da1)-siglen-0x30
hash = da1[pos:pos+0x30]
if hash[-4:] == b"\x00\x00\x00\x00":
return pos, 2
return -1, -1
def find_da_hash_V5(self, da1):
idx1 = da1.find(b"MMU MAP: VA")
if idx1 != -1:
hashed = da1[idx1 - 0x30:idx1]
if hashed[-4:] == b"\x00\x00\x00\x00":
self.debug(f"SHA256({hashed[:0x20].hex()})")
return idx1-0x30, 2
else:
self.debug(f"SHA1({hashed[-0x14:].hex()})")
return idx1-0x14, 1
else:
self.debug(f"Error: No hash found")
return -1, -1
def calc_da_hash(self, da1, da2):
hashdigest = hashlib.sha1(da2).digest()
hashdigest256 = hashlib.sha256(da2).digest()
@ -100,7 +127,7 @@ class DAloader(metaclass=LogBase):
dahash = hashlib.sha1(da2[:hashlen]).digest()
elif hashmode == 2:
dahash = hashlib.sha256(da2[:hashlen]).digest()
orighash=da1[hashpos:hashpos + len(dahash)]
orighash = da1[hashpos:hashpos + len(dahash)]
da1[hashpos:hashpos + len(dahash)] = dahash
return da1
@ -121,14 +148,15 @@ class DAloader(metaclass=LogBase):
elif config["flashmode"] == "XML":
self.mtk.config.chipconfig.damode = damodes.XML
self.flashmode = damodes.XML
self.config.init_hwcode(self.config.hwcode)
if self.config.meid is not None:
self.config.hwparam = hwparam(self.config.meid.hex(), self.mtk.config.hwparam_path)
if self.flashmode == damodes.XML:
self.da = DAXML(self.mtk, self.daconfig, self.loglevel)
self.daconfig.flashtype = config["flashtype"]
self.daconfig.flashsize = config["flashsize"]
self.da.reinit()
self.xmlft = None
self.xmlft = xmlflashext(self.mtk, self.da, self.loglevel)
self.xft = None
self.lft = None
if self.flashmode == damodes.XFLASH:
@ -161,6 +189,15 @@ class DAloader(metaclass=LogBase):
return True
return False
def patch_da2(self, da2):
if self.flashmode == damodes.XFLASH:
return self.xft.patch_da2(da2)
elif self.flashmode == damodes.LEGACY:
return self.lft.patch_da2(da2)
elif self.flashmode == damodes.XML:
return self.xmlft.patch_da2(da2)
return False
def set_da(self):
self.flashmode = damodes.LEGACY
if self.mtk.config.plcap is not None:
@ -174,13 +211,16 @@ class DAloader(metaclass=LogBase):
self.flashmode = damodes.XML
if self.flashmode == damodes.XFLASH:
self.da = DAXFlash(self.mtk, self.daconfig, self.loglevel)
self.da.patch = self.patch
self.xft = xflashext(self.mtk, self.da, self.loglevel)
elif self.flashmode == damodes.LEGACY:
self.da = DALegacy(self.mtk, self.daconfig, self.loglevel)
self.da.patch = self.patch
self.lft = legacyext(self.mtk, self.da, self.loglevel)
elif self.flashmode == damodes.XML:
self.da = DAXML(self.mtk,self.daconfig,self.loglevel)
self.xmlft = None
self.da = DAXML(self.mtk, self.daconfig, self.loglevel)
self.da.patch = self.patch
self.xmlft = xmlflashext(self.mtk, self.da, self.loglevel)
def setmetamode(self, porttype: str):
if self.mtk.config.chipconfig.damode == damodes.XFLASH:
@ -196,31 +236,44 @@ class DAloader(metaclass=LogBase):
return False
def detect_partition(self, partitionname, parttype=None):
fpartitions = []
data, guid_gpt = self.da.partition.get_gpt(self.mtk.config.gpt_settings, parttype)
if guid_gpt is None:
if self.partition_table_category() == "GPT":
fpartitions = []
data, guid_gpt = self.da.partition.get_gpt(self.mtk.config.gpt_settings, parttype)
if guid_gpt is None:
return [False, fpartitions]
else:
for partition in guid_gpt.partentries:
fpartitions.append(partition)
if partition.name.lower() == partitionname.lower():
return [True, partition]
return [False, fpartitions]
else:
for partition in guid_gpt.partentries:
fpartitions.append(partition)
if partition.name.lower() == partitionname.lower():
return [True, partition]
return [False, fpartitions]
data, partitions = self.da.partition.read_pmt()
return [True, partitions]
def get_partition_data(self, parttype=None):
fpartitions = []
data, guid_gpt = self.da.partition.get_gpt(self.mtk.config.gpt_settings, parttype)
if guid_gpt is None:
return [False, fpartitions]
if self.partition_table_category() == "GPT":
fpartitions = []
data, guid_gpt = self.da.partition.get_gpt(self.mtk.config.gpt_settings, parttype)
if guid_gpt is None:
return [False, fpartitions]
else:
return guid_gpt.partentries
else:
return guid_gpt.partentries
data, partitions = self.da.partition.read_pmt()
return [True, partitions]
def get_gpt(self, parttype=None) -> tuple:
fpartitions = []
data, guid_gpt = self.da.partition.get_gpt(self.mtk.config.gpt_settings, parttype)
if guid_gpt is None:
return False, fpartitions
return data, guid_gpt
if self.partition_table_category() == "GPT":
fpartitions = []
data, guid_gpt = self.da.partition.get_gpt(self.mtk.config.gpt_settings, parttype)
if guid_gpt is None:
return False, fpartitions
return data, guid_gpt
else:
data, partitions = self.da.partition.read_pmt()
return data, partitions
def upload(self):
return self.da.upload_da1()
@ -239,6 +292,11 @@ class DAloader(metaclass=LogBase):
self.set_da()
return self.da.upload_da()
def boot_to(self, addr, data, display=True, timeout=0.5):
if self.da.boot_to(addr, data):
return True
return False
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,
parttype=parttype, wdata=wdata, display=display)
@ -259,26 +317,68 @@ class DAloader(metaclass=LogBase):
def peek(self, addr: int, length: int):
if self.flashmode == damodes.XFLASH:
return self.xft.custom_read(addr=addr, length=length)
if self.flashmode == damodes.LEGACY:
elif self.flashmode == damodes.LEGACY:
return self.lft.custom_read(addr=addr, length=length)
elif self.flashmode == damodes.XML:
return self.xmlft.custom_read(addr=addr, length=length)
def peek_reg(self, addr: int, length: int):
if self.flashmode == damodes.XFLASH:
return self.xft.custom_read_reg(addr=addr, length=length)
elif self.flashmode == damodes.LEGACY:
return self.lft.custom_read_reg(addr=addr, length=length)
elif self.flashmode == damodes.XML:
return self.xmlft.custom_read_reg(addr=addr, length=length)
def dump_brom(self, filename):
rm = None
if self.flashmode == damodes.XFLASH:
rm = self.xft.readmem
elif self.flashmode == damodes.LEGACY:
rm = self.lft.readmem
elif self.flashmode == damodes.XML:
rm = self.xmlft.readmem
pg = progress(4)
with open(filename, "wb") as wf:
length = 0x200000
bytesread = 0
for addr in range(0x0, length, 0x40):
tmp = rm(addr, 0x10)
bytesread += 0x40
pg.show_progress("Dump:", bytesread, length)
dtmp = b"".join([int.to_bytes(val, 4, 'little') for val in tmp])
wf.write(dtmp)
pg.show_progress("Dump:", length, length)
def partition_table_category(self):
#if self.flashmode == damodes.XFLASH:
# return self.xft.get_partition_table_category()
return "GPT"
def poke(self, addr: int, data: bytes or bytearray):
if self.flashmode == damodes.XFLASH:
return self.xft.custom_write(addr=addr, data=data)
elif self.flashmode == damodes.LEGACY:
return self.lft.custom_write(addr=addr, data=data)
elif self.flashmode == damodes.XML:
return self.xmlft.custom_write(addr=addr, data=data)
def keys(self):
if self.flashmode == damodes.XFLASH:
return self.xft.generate_keys()
elif self.flashmode == damodes.LEGACY:
return self.lft.generate_keys()
elif self.flashmode == damodes.XML:
return self.xmlft.generate_keys()
def readfuses(self):
if self.flashmode == damodes.XFLASH:
return self.xft.readfuses()
pass
elif self.flashmode == damodes.LEGACY:
return self.lft.readfuses()
pass
elif self.flashmode == damodes.XML:
return self.xmlft.readfuses()
def is_patched(self):
return self.da.patch
@ -288,21 +388,29 @@ class DAloader(metaclass=LogBase):
return self.xft.seccfg(lockflag)
elif self.flashmode == damodes.LEGACY:
return self.lft.seccfg(lockflag)
elif self.flashmode == damodes.XML:
return self.xmlft.seccfg(lockflag)
def read_rpmb(self, filename=None):
if self.flashmode == damodes.XFLASH:
return self.xft.read_rpmb(filename)
self.error("Device is not in xflash mode, cannot run read rpmb cmd.")
elif self.flashmode == damodes.XML:
return self.xmlft.read_rpmb(filename)
self.error("Device is not in xflash/xml mode, cannot run read rpmb cmd.")
return False
def write_rpmb(self, filename=None):
if self.flashmode == damodes.XFLASH:
return self.xft.write_rpmb(filename)
self.error("Device is not in xflash mode, cannot run write rpmb cmd.")
elif self.flashmode == damodes.XML:
return self.xmlft.write_rpmb(filename)
self.error("Device is not in xflash/xml mode, cannot run write rpmb cmd.")
return False
def erase_rpmb(self):
if self.flashmode == damodes.XFLASH:
return self.xft.erase_rpmb()
self.error("Device is not in xflash mode, cannot run erase rpmb cmd.")
if self.flashmode == damodes.XML:
return self.xmlft.erase_rpmb()
self.error("Device is not in xflash/xml mode, cannot run erase rpmb cmd.")
return False

0
mtkclient/Library/DA/xflash/__init__.py Normal file → Executable file
View file

0
mtkclient/Library/DA/xflash/extension/__init__.py Normal file → Executable file
View file

115
mtkclient/Library/DA/xflash/extension/xflash.py Normal file → Executable file
View file

@ -1,4 +1,5 @@
import os
import sys
from struct import unpack, pack
from mtkclient.config.payloads import pathconfig
@ -67,9 +68,10 @@ class xflashext(metaclass=LogBase):
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")
register_devctrl = find_binary(self.da2, b"\x38\xB5\x05\x46\x0C\x20")
####################### EMMC ##########################################
mmc_get_card = find_binary(self.da2, b"\x4B\x4F\xF4\x3C\x72")
if mmc_get_card is not None:
mmc_get_card -= 1
@ -92,24 +94,24 @@ class xflashext(metaclass=LogBase):
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")
####################### UFS ##########################################
# ptr is right after ufshcd_probe_hba and at the beginning
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:
if ptr_g_ufs_hba is not None:
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)
else:
# 6833 -> ufshcd_probe_hba
ptr_g_ufs_hba = find_binary(self.da2, b"\x20\x46\x0D\xB0\xBD\xE8\xF0\x83")
if ptr_g_ufs_hba is not None:
g_ufs_hba = int.from_bytes(self.da2[ptr_g_ufs_hba + 8:ptr_g_ufs_hba + 8 + 4], 'little')
else:
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')
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")
@ -118,11 +120,19 @@ class xflashext(metaclass=LogBase):
ufshcd_get_free_tag = None
ufshcd_queuecommand = None
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")
if register_ptr != -1 and mmc_get_card_ptr != -1:
if register_cmd:
register_cmd = register_cmd + self.da2address | 1
if register_devctrl:
register_devctrl = register_devctrl + self.da2address | 1
else:
register_cmd = 0
register_devctrl = 0
if mmc_get_card:
mmc_get_card = mmc_get_card + self.da2address | 1
else:
@ -150,7 +160,7 @@ class xflashext(metaclass=LogBase):
g_ufs_hba = 0
# Patch the addr
daextdata[register_ptr:register_ptr + 4] = pack("<I", register_cmd)
daextdata[register_ptr:register_ptr + 4] = pack("<I", register_devctrl)
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)
@ -187,6 +197,14 @@ class xflashext(metaclass=LogBase):
self.info("Patching da2 ...")
# open("da2.bin","wb").write(da2)
da2patched = bytearray(da2)
# Patch oppo security
oppo = 0
pos = 0
while oppo is not None:
oppo = find_binary(da2, b"\x01\x3B\x01\x2B\x08\xD9", pos)
if oppo is not None:
da2patched[oppo:oppo + 4] = b"\x01\x20\x08\xBD"
pos = oppo + 1
# Patch security
is_security_enabled = find_binary(da2, b"\x01\x23\x03\x60\x00\x20\x70\x47")
if is_security_enabled != -1:
@ -194,9 +212,9 @@ class xflashext(metaclass=LogBase):
else:
self.warning("Security check not patched.")
# Patch hash check
authaddr = find_binary(da2, b"\x04\x00\x07\xC0")
authaddr = find_binary(da2, int.to_bytes(0xC0070004,4, 'little'))
if authaddr:
da2patched[authaddr:authaddr + 4] = b"\x00\x00\x00\x00"
da2patched[authaddr:authaddr + 4] = int.to_bytes(0,4,'little')
elif authaddr is None:
authaddr = find_binary(da2, b"\x4F\xF0\x04\x09\xCC\xF2\x07\x09")
if authaddr:
@ -207,6 +225,11 @@ class xflashext(metaclass=LogBase):
da2patched[authaddr:authaddr + 14] = b"\x4F\xF0\x00\x09\x32\x46\x01\x98\x03\x99\x4F\xF0\x00\x09"
else:
self.warning("Hash check not patched.")
# Disable da anti rollback version check
antirollback = find_binary(da2, int.to_bytes(0xC0020053,4,'little'))
if antirollback:
da2patched[antirollback:antirollback + 4] = int.to_bytes(0, 4, 'little')
self.info("DA version anti-rollback patched")
# Patch write not allowed
# open("da2.bin","wb").write(da2patched)
idx = 0
@ -555,6 +578,8 @@ class xflashext(metaclass=LogBase):
hwcode = self.mtk.config.hwcode
efuseconfig = efuse(base, hwcode)
addr = efuseconfig.efuses[idx]
if addr < 0x1000:
return int.to_bytes(addr,4,'little')
data = bytearray(self.mtk.daloader.peek(addr=addr, length=4))
return data
return None
@ -575,10 +600,44 @@ class xflashext(metaclass=LogBase):
data = []
for idx in range(len(efuseconfig.efuses)):
addr = efuseconfig.efuses[idx]
data.append(bytearray(self.mtk.daloader.peek(addr=addr, length=4)))
if addr < 0x1000:
data.append(int.to_bytes(addr, 4, 'little'))
else:
data.append(bytearray(self.mtk.daloader.peek(addr=addr, length=4)))
return data
def custom_read_reg(self, addr:int, length:int) -> bytes:
data=bytearray()
for pos in range(addr,addr+length,4):
tmp=self.custom_readregister(pos)
if tmp==b"":
break
data.extend(tmp.to_bytes(4,'little'))
return data
def generate_keys(self):
if self.config.hwcode in [0x2601,0x6572]:
base = 0x11141000
elif self.config.hwcode==0x6261:
base = 0x70000000
elif self.config.hwcode in [0x8172,0x8176]:
base = 0x122000
else:
base = 0x100000
if self.config.meid is None:
try:
data = b"".join([pack("<I", val) for val in self.readmem(base+0x8EC, 0x16 // 4)])
self.config.meid = data
self.config.set_meid(data)
except:
return
if self.config.socid is None:
try:
data = b"".join([pack("<I", val) for val in self.readmem(base+0x934, 0x20 // 4)])
self.config.socid = data
self.config.set_socid(data)
except:
return
hwc = self.cryptosetup()
meid = self.config.get_meid()
socid = self.config.get_socid()
@ -592,8 +651,8 @@ class xflashext(metaclass=LogBase):
pubk=self.read_pubk()
if pubk is not None:
retval["pubkey"]=pubk.hex()
self.info("PUBK : " + pubk.hex())
self.config.hwparam.writesetting("pubkey", pubk.hex())
self.info("PUBK : " + pubk.hex())
self.config.hwparam.writesetting("pubkey", pubk.hex())
if meid is not None:
self.info("MEID : " + meid.hex())
retval["meid"] = meid.hex()
@ -619,7 +678,7 @@ class xflashext(metaclass=LogBase):
self.info("Generating dxcc rpmbkey2...")
rpmb2key = hwc.aes_hwcrypt(btype="dxcc", mode="rpmb2")
self.info("Generating dxcc km key...")
ikey = hwc.aes_hwcrypt(btype="dxcc", mode="itrustee")
ikey = hwc.aes_hwcrypt(btype="dxcc", mode="itrustee", data=self.config.hwparam.appid)
# self.info("Generating dxcc platkey + provkey key...")
# platkey, provkey = hwc.aes_hwcrypt(btype="dxcc", mode="prov")
# self.info("Provkey : " + provkey.hex())

0
mtkclient/Library/DA/xflash/xflash_flash_param.py Normal file → Executable file
View file

View file

@ -1,12 +1,16 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# (c) B.Kerler 2018-2023 GPLv3 License
import array
import logging
import sys
import time
import os
from binascii import hexlify
from struct import pack, unpack
import usb
from mtkclient.Library.DA.xflash.xflash_flash_param import NandExtension
from mtkclient.Library.DA.xflash.xflash_param import Cmd, ChecksumAlgorithm, FtSystemOSE, DataType
from mtkclient.Library.utils import LogBase, logsetup
@ -56,6 +60,19 @@ class DAXFlash(metaclass=LogBase):
self.patch = True
self.xft = xflashext(self.mtk, self, loglevel)
try:
from mtkclient.Library.Exploit.kamakiri_pl import Kamakiri_Pl
self.kamakiri_pl = Kamakiri_Pl(self.mtk, loglevel)
#self.kamakiri_pl = None
except:
self.kamakiri_pl = None
try:
from mtkclient.Library.Exploit.carbonara import Carbonara
self.carbonara = Carbonara(self.mtk, loglevel)
except:
self.carbonara = None
def usleep(self, usec):
time.sleep(usec / 100000)
@ -131,7 +148,7 @@ class DAXFlash(metaclass=LogBase):
return status
def read_pmt(self) -> tuple:
return b"", []
return self.partition.get_pmt()
def send_param(self, params):
if isinstance(params, bytes):
@ -247,22 +264,22 @@ class DAXFlash(metaclass=LogBase):
if self.usbwrite(data[pos:pos + 64]):
pos += 64
bytestowrite -= 64
status = self.status()
status = self.status() # 0xC0070004
if status == 0x0:
return True
else:
self.error(f"Error on sending data: {self.eh.status(status)}")
return False
def boot_to(self, at_address, da, display=True, timeout=0.5): # =0x40000000
def boot_to(self, addr, da, display=True, timeout=0.5): # =0x40000000
if self.xsend(self.Cmd.BOOT_TO):
if self.status() == 0:
param = pack("<QQ", at_address, len(da))
param = pack("<QQ", addr, len(da))
pkt1 = pack("<III", self.Cmd.MAGIC, self.DataType.DT_PROTOCOL_FLOW, len(param))
if self.usbwrite(pkt1):
if self.usbwrite(param):
if self.send_data(da):
if at_address == 0x68000000:
if addr == 0x68000000:
self.info(f"Extensions were accepted. Jumping to extensions...")
else:
self.info(f"Upload data was accepted. Jumping to stage 2...")
@ -676,6 +693,17 @@ class DAXFlash(metaclass=LogBase):
else:
return 0
def get_partition_table_category(self):
res = self.send_devctrl(self.Cmd.GET_PARTITION_TBL_CATA)
if res != b"":
value = unpack("<I", res)[0]
if value == 0x64:
return "GPT"
elif value == 0x65:
return "PMT"
else:
return 0
def get_packet_length(self):
resp = self.send_devctrl(self.Cmd.GET_PACKET_LENGTH)
if resp != b"":
@ -795,10 +823,10 @@ class DAXFlash(metaclass=LogBase):
self.mtk.daloader.progress.show_progress("Read", total, total, display)
rq.put(None)
worker.join(60)
return True
return b""
rq.put(None)
worker.join(60)
return False
return b"ACK"
else:
buffer = bytearray()
while length > 0:
@ -973,17 +1001,20 @@ class DAXFlash(metaclass=LogBase):
da2sig_len = self.daconfig.da_loader.region[2].m_sig_len
bootldr.seek(da2offset)
da2 = bootldr.read(self.daconfig.da_loader.region[2].m_len)
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
self.daconfig.da2 = da2[:hashlen]
if self.patch:
hashaddr, hashmode, hashlen = self.mtk.daloader.compute_hash_pos(da1, da2, da1sig_len, da2sig_len,self.daconfig.da_loader.v6)
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
self.daconfig.da2 = da2[:hashlen]
else:
self.patch = False
self.daconfig.da2 = da2[:-da2sig_len]
else:
self.patch = False
self.daconfig.da2 = da2[:-da2sig_len]
if self.mtk.preloader.send_da(da1address, da1size, da1sig_len, da1):
self.info("Successfully uploaded stage 1, jumping ..")
if self.mtk.preloader.jump_da(da1address):
@ -993,6 +1024,8 @@ class DAXFlash(metaclass=LogBase):
return False
else:
self.sync()
#if self.kamakiri_pl is not None:
# self.kamakiri_pl.bypass2ndDA()
self.setup_env()
self.setup_hw_init()
res = self.xread()
@ -1008,7 +1041,6 @@ class DAXFlash(metaclass=LogBase):
return False
def reinit(self, display=False):
self.config.hwparam = hwparam(self.config.meid, self.config.hwparam_path)
self.config.sram, self.config.dram = self.get_ram_info()
self.emmc = self.get_emmc_info(display)
self.nand = self.get_nand_info(display)
@ -1055,6 +1087,9 @@ class DAXFlash(metaclass=LogBase):
self.config.set_gui_status(self.config.tr("Connected to stage2 with higher speed"))
def upload_da(self):
if not self.mtk.daloader.patch:
if self.kamakiri_pl is not None:
self.kamakiri_pl.initbrom()
if self.upload_da1():
self.get_expire_date()
self.set_reset_key(0x68)
@ -1109,21 +1144,24 @@ class DAXFlash(metaclass=LogBase):
self.info("Uploading stage 2...")
with open(self.daconfig.loader, 'rb') as bootldr:
stage = stage + 1
loaded = self.boot_to(self.daconfig.da_loader.region[stage].m_start_addr, self.daconfig.da2)
if not self.mtk.daloader.patch:
loaded = self.boot_to(self.daconfig.da_loader.region[stage].m_start_addr, self.daconfig.da2)
else:
loaded = self.boot_to(self.daconfig.da_loader.region[stage].m_start_addr, self.daconfig.da2)
if loaded:
self.info("Successfully uploaded stage 2")
self.reinit(True)
self.config.hwparam.writesetting("hwcode", hex(self.config.hwcode))
daextdata = self.xft.patch()
if daextdata is not None:
self.daext = False
if self.boot_to(at_address=0x68000000, da=daextdata):
if self.boot_to(addr=0x68000000, da=daextdata):
ret = self.send_devctrl(XCmd.CUSTOM_ACK)
status = self.status()
if status == 0x0 and unpack("<I", ret)[0] == 0xA1A2A3A4:
self.info("DA Extensions successfully added")
self.daext = True
self.config.hwparam = hwparam(self.mtk.config.meid,self.mtk.config.hwparam_path)
self.config.hwparam.writesetting("hwcode", hex(self.config.hwcode))
if not self.daext:
self.warning("DA Extensions failed to enable")

0
mtkclient/Library/DA/xflash/xflash_param.py Normal file → Executable file
View file

0
mtkclient/Library/DA/xml/__init__.py Normal file → Executable file
View file

View file

View file

@ -0,0 +1,832 @@
import os
import sys
from struct import unpack, pack
# from keystone import *
from mtkclient.config.payloads import pathconfig
from mtkclient.config.brom_config import efuse
from mtkclient.Library.error import ErrorHandler, ErrorCodes_XFlash
from mtkclient.Library.Hardware.hwcrypto import crypto_setup, hwcrypto
from mtkclient.Library.utils import LogBase, progress, logsetup, find_binary
from mtkclient.Library.Hardware.seccfg import seccfgV3, seccfgV4
from mtkclient.Library.utils import mtktee
import json
rpmb_error = [
"",
"General failure",
"Authentication failure",
"Counter failure",
"Address failure",
"Write failure",
"Read failure",
"Authentication key not yet programmed"
]
class xmlflashext(metaclass=LogBase):
def __init__(self, mtk, xmlflash, loglevel):
self.pathconfig = pathconfig()
self.__logger = logsetup(self, self.__logger, loglevel, mtk.config.gui)
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 = xmlflash
self.xsend = self.xflash.xsend
self.xread = self.xflash.xread
self.da2 = None
self.da2address = None
def patch_command(self, da2):
self.da2address = self.xflash.daconfig.da_loader.region[2].m_start_addr # at_address
data = bytearray(da2)
idx = data.find(b"\x00CMD:SET-HOST-INFO\x00")
base = self.da2address
if idx != -1:
first_op, second_op = offset_to_op_mov(idx + 1, 0, base)
first_op = int.to_bytes(first_op, 4, 'little')
second_op = int.to_bytes(second_op, 4, 'little')
midx = data.find(first_op)
midx2 = data.find(second_op, midx)
if midx + 8 == midx2:
instr1 = int.from_bytes(data[midx + 4:midx + 8], 'little')
instr2 = int.from_bytes(data[midx2 + 4:midx2 + 8], 'little')
addr = op_mov_to_offset(instr1, instr2, 2) - base
# rw_primitive = bytes.fromhex("FF412DE90040A0E30460A0E30C708DE20050A0E10710A0E1003090E508008DE200408DE506808DE004408DE508408DE50C608DE533FF2FE108309DE50710A0E10D00A0E10C608DE5040053E1003095E50A00001A33FF2FE100309DE50610A0E10C608DE50800A0E1003093E504308DE5043095E533FF2FE110D08DE2F081BDE833FF2FE1003095E50710A0E10800A0E10C608DE533FF2FE100309DE50400A0E104209DE5002083E5F2FFFFEA")
# ks = Ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_LITTLE_ENDIAN)
content = """
PUSH {R4-R6,R10,R11,LR}
ADD R11, SP, #0x10
MOV R8, R0
MOVW R0, #0xF000
MOVT R0, #0x6800
MOV R1, #4
LDR R2, [R8]
BLX R2
MOVW R0, #0xF000
MOVT R0, #0x6800
MOV R1, [R0]
MOVW R0, #0x0000
MOVT R0, #0x6800
LDR R2, [R8]
BLX R2
MOVW R0, #0x0000
MOVT R0, #0x6800
BLX R0
POP {R4-R6,R10,R11,PC}
"""
# encoding, length = ks.asm(content, addr=addr)
# newdata = b"".join(int.to_bytes(val, 1, 'little') for val in encoding)
newdata = bytes.fromhex(
"704c2de910b08de20080a0e100000fe3000846e30410a0e3002098e532ff2fe100000fe3000846e3000000e3000846e3002098e532ff2fe1000000e3000846e330ff2fe1708cbde8")
sys.stdout.flush()
data[addr:addr + len(newdata)] = newdata
newcmd = b"CMD:CUSTOM\x00"
data[idx + 1:idx + 1 + len(newcmd)] = newcmd
return data
return da2
def ack(self):
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMACK")
if self.xsend(xmlcmd):
result = self.xflash.get_response()
# DATA
data = self.xflash.get_response(raw=True)
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
if data == b"\xA4\xA3\xA2\xA1":
return True
return False
def patch(self):
self.da2 = self.xflash.daconfig.da2
self.da2address = self.xflash.daconfig.da_loader.region[2].m_start_addr # at_address
daextensions = os.path.join(self.pathconfig.get_payloads_path(), "da_xml.bin")
if os.path.exists(daextensions):
daextdata = bytearray(open(daextensions, "rb").read())
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")
# register_xml_cmd("CMD:GET-SYS-PROPERTY", & a1, cmd_get_sys_property);
# open("out" + hex(self.da2address) + ".da", "wb").write(da2)
register_xml_cmd = find_binary(self.da2,
b"\x70\x4C\x2D\xE9\x10\xB0\x8D\xE2\x00\x50\xA0\xE1\x14\x00\xA0\xE3")
################# UFS ##################
idx = self.da2.find(b"\x00\x00\x94\xE5\x34\x10\x90\xE5\x01\x00\x11\xE3\x03\x00\x00\x0A")
g_ufs_hba = 0
ufshcd_queuecommand = 0
ufshcd_get_free_tag = 0
if idx != -1:
instr1 = int.from_bytes(self.da2[idx - 0x8:idx - 0x4], 'little')
instr2 = int.from_bytes(self.da2[idx - 0x4:idx], 'little')
g_ufs_hba = op_mov_to_offset(instr1, instr2, 4)
ufshcd_queuecommand = find_binary(self.da2,
b"\xF0\x4D\x2D\xE9\x18\xB0\x8D\xE2\x08\xD0\x4D\xE2\x48\x40\x90\xE5")
if ufshcd_queuecommand is None:
ufshcd_queuecommand = 0
else:
ufshcd_queuecommand = ufshcd_queuecommand + self.da2address
ufshcd_get_free_tag = find_binary(self.da2,
b"\x10\x4C\x2D\xE9\x08\xB0\x8D\xE2\x00\x40\xA0\xE3\x00\x00\x51\xE3")
if ufshcd_get_free_tag is None:
ufshcd_get_free_tag = 0
else:
ufshcd_get_free_tag = ufshcd_get_free_tag + self.da2address
############### EMMC ##########################
mmc_get_card = find_binary(self.da2, b"\x90\x12\x20\xE0\x1E\xFF\x2F\xE1")
if mmc_get_card is not None:
mmc_get_card -= 0xC
else:
mmc_get_card = 0
mmc_set_part_config = find_binary(self.da2,b"\xF0\x4B\x2D\xE9\x18\xB0\x8D\xE2\x23\xDE\x4D\xE2")
if mmc_set_part_config is None:
mmc_set_part_config = 0
mmc_rpmb_send_command = find_binary(self.da2, b"\xF0\x48\x2D\xE9\x10\xB0\x8D\xE2\x08\x70\x9B\xE5")
if mmc_rpmb_send_command is None:
mmc_rpmb_send_command = 0
#########################################
if register_ptr != -1:
if register_xml_cmd:
register_xml_cmd = register_xml_cmd + self.da2address
else:
register_xml_cmd = 0
# Patch the addr
daextdata[register_ptr:register_ptr + 4] = pack("<I", register_xml_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_da1(self, da1):
pass
def patch_da2(self, da2):
self.info("Patching da2 ...")
da2patched = bytearray(da2)
pos = 0
idx = 0
while idx is not None:
idx = find_binary(da2, b"\x00\x00\xA0\xE3\x04\x10\xA0\xE1\x00\x20\xA0\xE3..\x00\xEB\x01\x40\x00\xE3", pos)
if idx is not None:
offset = int.from_bytes(da2patched[idx + 0xC:idx + 0xE], 'little') - 1
da2patched[
idx:idx + 0x14] = b"\x00\x00\xA0\xE3\x04\x10\xA0\xE1\x2C\x22\x0E\xE3\x00\x20\x44\xE3" + offset.to_bytes(
2, 'little') + b"\x00\xEB"
patched = True
pos += idx
pos += 0x14
if patched:
self.info("Patched read_register / write_register")
da2patched = self.patch_command(da2)
idx = find_binary(da2patched,
b"\x00\xA0\xE3\x1E\xFF\x2F\xE1.\x00\xA0\xE3\x1E\xFF\x2F\xE1.\x00\xA0\xE3\x1E\xFF\x2F\xE1\x70\x4C")
if idx is not None:
da2patched[idx - 1:idx - 1 + (
3 * 8)] = b"\x01\x00\xA0\xE3\x1E\xFF\x2F\xE1\x01\x00\xA0\xE3\x1E\xFF\x2F\xE1\x01\x00\xA0\xE3\x1E\xFF\x2F\xE1"
patched = True
self.info("Patched write partitions / allow_read / allow_write")
if not patched:
self.warning("Write not allowed not patched.")
return da2patched
def custom_rpmb_read(self, sector, ufs=False):
data = b''
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMRPMBR")
if ufs:
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMURPMBR")
if self.xsend(xmlcmd):
result = self.xflash.get_response()
if result == "OK":
self.xsend(sector)
resp = unpack("<H", self.xflash.get_response(raw=True))[0]
if resp == 0x0:
data = self.xflash.get_response(raw=True)
else:
self.error(rpmb_error[resp])
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
return data
def custom_rpmb_write(self, sector, data: bytes, ufs=False):
if len(data) != 0x100:
self.error("Incorrect rpmb frame length. Aborting")
return False
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMRPMBW")
if ufs:
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMURPMBW")
if self.xsend(xmlcmd):
result = self.xflash.get_response()
if result == "OK":
self.xsend(sector)
self.xsend(data[:0x100])
resp = unpack("<H", self.xflash.get_response(raw=True))[0]
if resp != 0:
self.error(rpmb_error[resp])
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
return False
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
return True
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
return False
def custom_rpmb_init(self):
hwc = self.cryptosetup()
if self.config.chipconfig.meid_addr:
meid = self.config.get_meid()
otp = self.config.get_otp()
if meid != b"\x00" * 16:
# self.config.set_meid(meid)
self.info("Generating sej rpmbkey...")
rpmbkey = hwc.aes_hwcrypt(mode="rpmb", data=meid, btype="sej", otp=otp)
if rpmbkey is not None:
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMRPMBKEY")
if self.xsend(xmlcmd):
result = self.xflash.get_response()
if result == "OK":
self.xsend(rpmbkey)
read_key = self.xflash.get_response(raw=True)
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
if rpmbkey == read_key:
self.info("Setting rpmbkey: ok")
ufs = False
if self.xflash.emmc.rpmb_size != 0:
ufs = False
elif self.xflash.ufs.block_size != 0:
ufs = True
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMMMCINIT")
if ufs:
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMUFSINIT")
if self.xsend(xmlcmd):
result = self.xflash.get_response()
if result == "OK":
derivedrpmb = self.xflash.get_response(raw=True)
if int.from_bytes(derivedrpmb[:4], 'little') != 0xff:
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
self.info("Derived rpmb key:" + derivedrpmb.hex())
return True
self.error("Failed to derive a valid rpmb key.")
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
return False
def setotp(self, hwc):
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"
hwc.sej.sej_set_otp(otp)
def read_rpmb(self, filename=None, display=True):
progressbar = progress(1, self.mtk.config.guiprogress)
sectors = 0
#val = self.custom_rpmb_init()
ufs = False
if self.xflash.emmc is not None:
sectors = self.xflash.emmc.rpmb_size // 0x100
ufs = False
elif self.xflash.ufs.lu1_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 read", sector * 0x100, sectors * 0x100, 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, self.mtk.config.guiprogress)
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
elif self.xflash.ufs.block_size != 0:
sectors = (512 * 256)
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 written", sector * 0x100, sectors * 0x100, 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 erase_rpmb(self, display=True):
progressbar = progress(1, self.mtk.config.guiprogress)
ufs = False
sectors = 0
if self.xflash.emmc.rpmb_size != 0:
sectors = self.xflash.emmc.rpmb_size // 0x100
elif self.xflash.ufs.block_size != 0:
sectors = (512 * 256)
if self.custom_rpmb_init():
if sectors > 0:
for sector in range(sectors):
if display:
progressbar.show_progress("RPMB erased", sector * 0x100, sectors * 0x100, display)
if not self.custom_rpmb_write(sector=sector, data=b"\x00" * 0x100, ufs=ufs):
self.error(f"Couldn't erase rpmb at sector {sector}.")
return False
self.info(f"Done erasing rpmb")
return True
return False
def custom_read(self, addr, length) -> bytes:
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMMEMR")
if self.xsend(xmlcmd):
result = self.xflash.get_response()
if result == "OK":
# DATA
self.xsend(data=addr, is64bit=True)
self.xsend(length)
data = self.xflash.get_response(raw=True)
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
return data
return b""
def custom_read_reg(self, addr: int, length: int) -> bytes:
data = bytearray()
for pos in range(addr, addr + length, 4):
tmp = self.custom_readregister(pos)
if tmp == b"":
break
data.extend(tmp.to_bytes(4, 'little'))
return data
def custom_readregister(self, addr) -> (int, None):
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMREGR")
if self.xsend(xmlcmd):
result = self.xflash.get_response()
if result == "OK":
# DATA
self.xsend(data=addr)
data = self.xflash.get_response(raw=True)
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
return int.from_bytes(data, 'little')
return None
def custom_write(self, addr, data) -> bool:
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMMEMR")
if self.xsend(xmlcmd):
result = self.xflash.get_response()
if result == "OK":
# DATA
self.xsend(data=addr, is64bit=True)
self.xsend(len(data))
self.xsend(data)
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
return True
return False
def custom_writeregister(self, addr: int, data: int):
xmlcmd = self.xflash.Cmd.create_cmd("CUSTOMREGW")
if self.xsend(xmlcmd):
result = self.xflash.get_response()
if result == "OK":
# DATA
self.xsend(addr)
self.xsend(data)
# CMD:END
result = self.xflash.get_response()
self.xflash.ack()
# CMD:START
result = self.xflash.get_response()
self.xflash.ack()
return True
return False
def readmem(self, addr, dwords=1):
res = []
if dwords < 0x20:
for pos in range(dwords):
val = self.custom_readregister(addr + pos * 4)
if val == b"":
return False
if dwords == 1:
self.debug(f"RX: {hex(addr + (pos * 4))} -> " + hex(val))
return val
res.append(val)
else:
res = self.custom_read(addr, dwords * 4)
res = [unpack("<I", res[i:i + 4])[0] for i in range(0, len(res), 4)]
self.debug(f"RX: {hex(addr)} -> " + bytearray(b"".join(pack("<I", val) for val in res)).hex())
return res
def writeregister(self, addr, dwords):
if isinstance(dwords, int):
dwords = [dwords]
pos = 0
if len(dwords) < 0x20:
for val in dwords:
self.debug(f"TX: {hex(addr + pos)} -> " + hex(val))
if not self.custom_writeregister(addr + pos, val):
return False
pos += 4
else:
dat = b"".join([pack("<I", val) for val in dwords])
self.custom_write(addr, dat)
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 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.efuse_base = self.config.chipconfig.efuse_addr
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
setup.hwcode = self.config.hwcode
return hwcrypto(setup, self.loglevel, self.config.gui)
def seccfg(self, lockflag):
if lockflag not in ["unlock", "lock"]:
return False, "Valid flags are: unlock, lock"
data, guid_gpt = self.xflash.partition.get_gpt(self.mtk.config.gpt_settings, "user")
seccfg_data = None
partition = None
if guid_gpt is None:
return False, "Error getting the partition table."
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:
return False, "Couldn't detect existing seccfg partition. Aborting unlock."
if seccfg_data[:4] != pack("<I", 0x4D4D4D4D):
return False, "Unknown seccfg partition header. Aborting unlock."
hwc = self.cryptosetup()
if seccfg_data[:0xC] == b"AND_SECCFG_v":
self.info("Detected V3 Lockstate")
sc_org = seccfgV3(hwc, self.mtk)
elif seccfg_data[:4] == b"\x4D\x4D\x4D\x4D":
self.info("Detected V4 Lockstate")
sc_org = seccfgV4(hwc, self.mtk)
else:
return False, "Unknown lockstate or no lockstate"
if not sc_org.parse(seccfg_data):
return False, "Device has is either already unlocked or algo is unknown. Aborting."
ret, writedata = sc_org.create(lockflag=lockflag)
if ret is False:
return False, writedata
if self.xflash.writeflash(addr=partition.sector * self.mtk.daloader.daconfig.pagesize,
length=len(writedata),
filename=None, wdata=writedata, parttype="user", display=True):
return True, "Successfully wrote seccfg."
return False, "Error on writing seccfg config to flash."
def decrypt_tee(self, filename="tee1.bin", aeskey1: bytes = None, aeskey2: bytes = None):
hwc = self.cryptosetup()
with open(filename, "rb") as rf:
data = rf.read()
idx = 0
while idx != -1:
idx = data.find(b"EET KTM ", idx + 1)
if idx != -1:
mt = mtktee()
mt.parse(data[idx:])
rdata = hwc.mtee(data=mt.data, keyseed=mt.keyseed, ivseed=mt.ivseed,
aeskey1=aeskey1, aeskey2=aeskey2)
open("tee_" + hex(idx) + ".dec", "wb").write(rdata)
def read_fuse(self, idx):
if self.mtk.config.chipconfig.efuse_addr is not None:
base = self.mtk.config.chipconfig.efuse_addr
hwcode = self.mtk.config.hwcode
efuseconfig = efuse(base, hwcode)
addr = efuseconfig.efuses[idx]
if addr < 0x1000:
return int.to_bytes(addr, 4, 'little')
data = bytearray(self.mtk.daloader.peek_reg(addr=addr, length=4))
return data
return None
def read_pubk(self):
if self.mtk.config.chipconfig.efuse_addr is not None:
base = self.mtk.config.chipconfig.efuse_addr
addr = base + 0x90
data = bytearray(self.mtk.daloader.peek_reg(addr=addr, length=0x20))
return data
return None
def readfuses(self):
if self.mtk.config.chipconfig.efuse_addr is not None:
base = self.mtk.config.chipconfig.efuse_addr
hwcode = self.mtk.config.hwcode
efuseconfig = efuse(base, hwcode)
data = []
for idx in range(len(efuseconfig.efuses)):
addr = efuseconfig.efuses[idx]
if addr < 0x1000:
return data.append(int.to_bytes(addr, 4, 'little'))
else:
data.append(bytearray(self.mtk.daloader.peek(addr=addr, length=4)))
return data
def generate_keys(self):
if self.config.hwcode in [0x2601, 0x6572]:
base = 0x11141000
elif self.config.hwcode == 0x6261:
base = 0x70000000
elif self.config.hwcode in [0x8172, 0x8176]:
base = 0x122000
else:
base = 0x100000
if self.config.meid is None:
try:
data = b"".join([pack("<I", val) for val in self.readmem(base + 0x8EC, 0x16 // 4)])
self.config.meid = data
self.config.set_meid(data)
except:
return
if self.config.socid is None:
try:
data = b"".join([pack("<I", val) for val in self.readmem(base + 0x934, 0x20 // 4)])
self.config.socid = data
self.config.set_socid(data)
except:
return
hwc = self.cryptosetup()
meid = self.config.get_meid()
socid = self.config.get_socid()
hwcode = self.config.get_hwcode()
cid = self.config.get_cid()
otp = self.config.get_otp()
retval = {}
# data=hwc.aes_hwcrypt(data=bytes.fromhex("A9 E9 DC 38 BF 6B BD 12 CC 2E F9 E6 F5 65 E8 C6 88 F7 14 11 80 2E 4D 91 8C 2B 48 A5 BB 03 C3 E5"), mode="sst", btype="sej",
# encrypt=False)
# self.info(data.hex())
pubk = self.read_pubk()
if pubk is not None:
retval["pubkey"] = pubk.hex()
self.info("PUBK : " + pubk.hex())
self.config.hwparam.writesetting("pubkey", pubk.hex())
if meid is not None:
self.info("MEID : " + meid.hex())
retval["meid"] = meid.hex()
self.config.hwparam.writesetting("meid", meid.hex())
if socid is not None:
self.info("SOCID : " + socid.hex())
retval["socid"] = socid.hex()
self.config.hwparam.writesetting("socid", socid.hex())
if hwcode is not None:
self.info("HWCODE : " + hex(hwcode))
retval["hwcode"] = hex(hwcode)
self.config.hwparam.writesetting("hwcode", hex(hwcode))
if cid is not None:
self.info("CID : " + cid)
retval["cid"] = cid
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 mirpmbkey...")
mirpmbkey = hwc.aes_hwcrypt(btype="dxcc", mode="mirpmb")
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 km key...")
ikey = hwc.aes_hwcrypt(btype="dxcc", mode="itrustee", data=self.config.hwparam.appid)
# self.info("Generating dxcc platkey + provkey key...")
# platkey, provkey = hwc.aes_hwcrypt(btype="dxcc", mode="prov")
# self.info("Provkey : " + provkey.hex())
# self.info("Platkey : " + platkey.hex())
if mirpmbkey is not None:
self.info("MIRPMB : " + mirpmbkey.hex())
self.config.hwparam.writesetting("mirpmbkey", mirpmbkey.hex())
retval["mirpmbkey"] = mirpmbkey.hex()
if rpmbkey is not None:
self.info("RPMB : " + rpmbkey.hex())
self.config.hwparam.writesetting("rpmbkey", rpmbkey.hex())
retval["rpmbkey"] = rpmbkey.hex()
if rpmb2key is not None:
self.info("RPMB2 : " + rpmb2key.hex())
self.config.hwparam.writesetting("rpmb2key", rpmb2key.hex())
retval["rpmb2key"] = rpmb2key.hex()
if fdekey is not None:
self.info("FDE : " + fdekey.hex())
self.config.hwparam.writesetting("fdekey", fdekey.hex())
retval["fdekey"] = fdekey.hex()
if ikey is not None:
self.info("iTrustee : " + ikey.hex())
self.config.hwparam.writesetting("kmkey", ikey.hex())
retval["kmkey"] = ikey.hex()
if self.config.chipconfig.prov_addr:
provkey = self.custom_read(self.config.chipconfig.prov_addr, 16)
self.info("PROV : " + provkey.hex())
self.config.hwparam.writesetting("provkey", provkey.hex())
retval["provkey"] = provkey.hex()
val = self.read_fuse(0xC)
if val is not None:
val += self.read_fuse(0xD)
val += self.read_fuse(0xE)
val += self.read_fuse(0xF)
self.info("HRID : " + val.hex())
self.config.hwparam.writesetting("hrid", val.hex())
retval["hrid"] = val.hex()
if hwcode == 0x699 and self.config.chipconfig.sej_base is not None:
mtee3 = hwc.aes_hwcrypt(mode="mtee3", btype="sej")
if mtee3:
self.config.hwparam.writesetting("mtee3", mtee3.hex())
self.info("MTEE3 : " + mtee3.hex())
retval["mtee3"] = mtee3.hex()
return retval
elif self.config.chipconfig.sej_base is not None:
if os.path.exists("tee.json"):
val = json.loads(open("tee.json", "r").read())
self.decrypt_tee(val["filename"], bytes.fromhex(val["data"]), bytes.fromhex(val["data2"]))
if meid == b"":
meid = self.custom_read(0x1008ec, 16)
if meid != b"":
# self.config.set_meid(meid)
self.info("Generating sej rpmbkey...")
self.setotp(hwc)
rpmbkey = hwc.aes_hwcrypt(mode="rpmb", data=meid, btype="sej", otp=otp)
if rpmbkey:
self.info("RPMB : " + rpmbkey.hex())
self.config.hwparam.writesetting("rpmbkey", rpmbkey.hex())
retval["rpmbkey"] = rpmbkey.hex()
self.info("Generating sej mtee...")
mtee = hwc.aes_hwcrypt(mode="mtee", btype="sej", otp=otp)
if mtee:
self.config.hwparam.writesetting("mtee", mtee.hex())
self.info("MTEE : " + mtee.hex())
retval["mtee"] = mtee.hex()
mtee3 = hwc.aes_hwcrypt(mode="mtee3", btype="sej", otp=otp)
if mtee3:
self.config.hwparam.writesetting("mtee3", mtee3.hex())
self.info("MTEE3 : " + mtee3.hex())
retval["mtee3"] = mtee3.hex()
else:
self.info("SEJ Mode: No meid found. Are you in brom mode ?")
if self.config.chipconfig.gcpu_base is not None:
if self.config.hwcode in [0x335, 0x8167, 0x8163, 0x8176]:
self.info("Generating gcpu mtee2 key...")
mtee2 = hwc.aes_hwcrypt(btype="gcpu", mode="mtee")
if mtee2 is not None:
self.info("MTEE2 : " + mtee2.hex())
self.config.hwparam.writesetting("mtee2", mtee2.hex())
retval["mtee2"] = mtee2.hex()
return retval
def offset_to_op_mov(addr, register, base):
offset = addr + base
low = (((offset & 0xFFFF) >> 12) & 0xF) << 16 | (register << 14) | offset & 0xFFF
offset = (offset >> 16)
shift = 4
high = (((offset & 0xFFFF) >> 12) & 0xF) << 16 | (register << 14) | offset & 0xFFF | (shift << 20)
first_op = (0xE3 << 24) + low
second_op = (0xE3 << 24) + high
return first_op, second_op
def op_mov_to_offset(first_op, second_op, register):
reglo = (first_op & 0xF000) >> 12
reghi = (second_op & 0xF000) >> 12
shiftlo = (first_op & 0xF00000) >> 20
shifthi = (second_op & 0xF00000) >> 20
hi = ((second_op & 0xF0000) >> 4 | second_op & 0xFFF) << shifthi * 4
lo = ((first_op & 0xF0000) >> 4 | first_op & 0xFFF) << shiftlo * 4
if reglo == reghi == register:
return hi | lo
return None
if __name__ == "__main__":
with open("/home/bjk/Projects/mtkclient_github/Research/new_loaders/MT6789_oppo_realme_10/normal/da2_40000000.bin",
"rb") as rf:
data = bytearray(rf.read())
idx = data.find(b"\x00\x00\x94\xE5\x34\x10\x90\xE5\x01\x00\x11\xE3\x03\x00\x00\x0A")
base = 0x40000000
if idx != -1:
instr1 = int.from_bytes(data[idx - 0x8:idx - 0x4], 'little')
instr2 = int.from_bytes(data[idx - 0x4:idx], 'little')
g_ufs_ptr = op_mov_to_offset(instr1, instr2, 4)

407
mtkclient/Library/DA/xml/xml_cmd.py Normal file → Executable file
View file

@ -1,22 +1,30 @@
import datetime
import sys
from mtkclient.Library.utils import LogBase
class BootModes:
fastboot = "FASTBOOT"
meta = "META"
testmode = "ANDROID-TEST-MODE"
class XMLCmd(metaclass=LogBase):
def __init__(self, mtk):
self.mtk = mtk
self.MAGIC = 0xFEEEEEEF
def create_cmd(self, cmd: str, arg: str = "", adv: str = ""):
args = f"""<arg>{arg}</arg>"""
cmd = f"""<?xml version="1.0" encoding="utf-8"?>
<da>
<version>1.0</version>
<command>CMD:{cmd}</command>
{args}
{adv}
</da>"""
def create_cmd(self, cmd: str, content:dict=None, version="1.0"):
cmd = f"<?xml version=\"1.0\" encoding=\"utf-8\"?><da><version>{version}</version><command>CMD:{cmd}</command>"
if content is not None:
for item in content:
cmd+=f"<{item}>"
for subitem in content[item]:
cmd+=f"{subitem}"
cmd+=f"</{item}>"
cmd +="</da>"
return cmd
################ DA1 ######################
@ -33,10 +41,14 @@ class XMLCmd(metaclass=LogBase):
"""
<?xml version="1.0" encoding="utf-8"?><da><version>1.0</version><command>CMD:BOOT-TO</command><arg><at_address>0x40000000</at_address><jmp_address>0x40000000</jmp_address> <source_file>MEM://0x7fe83c09a04c:0x50c78</source_file></arg></da>
"""
arg = f"""<at_address>{hex(at_addr)}</at_address>
<jmp_address>{hex(jmp_addr)}</jmp_address>
<source_file>MEM://{hex(host_offset)}:{hex(length)}</source_file>"""
cmd = self.create_cmd("BOOT-TO", arg)
content = {
"arg": [
f"<at_address>{hex(at_addr)}</at_address>",
f"<jmp_address>{hex(jmp_addr)}</jmp_address>",
f"<source_file>MEM://{hex(host_offset)}:{hex(length)}</source_file>"
]
}
cmd = self.create_cmd("BOOT-TO", content)
return cmd
"""
@ -47,40 +59,41 @@ class XMLCmd(metaclass=LogBase):
def cmd_set_runtime_parameter(self, checksum_level: str = "NONE", battery_exist: str = "AUTO-DETECT",
da_log_level: str = "INFO", log_channel: str = "UART", system_os: str = "LINUX",
version: str = "1.1", initialize_dram: bool = True):
b"""
<?xml version="1.0" encoding="utf-8"?>
<da>
<version>1.1</version>
<command>CMD:SET-RUNTIME-PARAMETER</command>
<arg>
<checksum_level>NONE</checksum_level>
<battery_exist>AUTO-DETECT</battery_exist>
<da_log_level>INFO</da_log_level>
<log_channel>UART</log_channel>
<system_os>LINUX</system_os>
</arg>
<adv>
<initialize_dram>YES</initialize_dram>
</adv>
</da>\x00
"""
arg = f"""<checksum_level>{checksum_level}</checksum_level>
<da_log_level>{da_log_level}</da_log_level>
<log_channel>{log_channel}</da_log_channel>
<battery_exist>{battery_exist}</battery_exist>
<system_os>{system_os}</system_os>"""
if version is not None:
arg += f"""<version>{version}</version>"""
cmd=f"""<?xml version="1.0" encoding="utf-8"?>
<da>
<version>1.1</version>
<command>CMD:SET-RUNTIME-PARAMETER</command>
<arg>
<checksum_level>{checksum_level}</checksum_level>
<battery_exist>{battery_exist}</battery_exist>
<da_log_level>{da_log_level}</da_log_level>
<log_channel>{log_channel}</log_channel>
<system_os>{system_os}</system_os>
</arg>
<adv>
<initialize_dram>{"YES" if initialize_dram else "NO"}</initialize_dram>
</adv>
</da>\x00"""
if initialize_dram is not None:
dram = "YES" if initialize_dram else "NO"
else:
dram = "YES"
content = {
"arg":[
f"<checksum_level>{checksum_level}</checksum_level>",
f"<battery_exist>{battery_exist}</battery_exist>",
f"<da_log_level>{da_log_level}</da_log_level>",
f"<log_channel>{log_channel}</log_channel>",
f"<system_os>{system_os}</system_os>"],
"adv":[
f"<initialize_dram>{dram}</initialize_dram>"
]
}
# checksum_level (NONE,USB,STORAGE,USB-STORAGE)
# da_log_level (TRACE,DEBUG,INFO,WARN,ERROR)
# log_channel (USB/UART)
# battery_exist (YES,NO,AUTO-DETECT)
adv = ""
if initialize_dram is not None:
adv = f"""<adv><initialize_dram>YES</initialize_dram></adv>"""
else:
adv = f"""<adv><initialize_dram>NO</initialize_dram></adv>"""
cmd = self.create_cmd("SET-RUNTIME-PARAMETER", arg, adv)
cmd = self.create_cmd("SET-RUNTIME-PARAMETER", content, version)
return cmd
def cmd_host_supported_commands(self,
@ -88,21 +101,33 @@ class XMLCmd(metaclass=LogBase):
"""
<?xml version="1.0" encoding="utf-8"?><da><version>1.0</version><command>CMD:HOST-SUPPORTED-COMMANDS</command><arg><host_capability>CMD:DOWNLOAD-FILE^1@CMD:FILE-SYS-OPERATION^1@CMD:PROGRESS-REPORT^1@CMD:UPLOAD-FILE^1@</host_capability></arg></da>\x00
"""
arg = f"""<host_capability>{host_capability}</host_capability>"""
cmd = self.create_cmd("HOST-SUPPORTED-COMMANDS", arg)
content = {
"arg": [
f"<host_capability>{host_capability}</host_capability>"
]
}
cmd = self.create_cmd("HOST-SUPPORTED-COMMANDS", content)
return cmd
def cmd_ram_test(self, function: str = "FLIP", start_address: int = 0x4000000, length: int = 0x100000,
repeat: int = 0xA):
if function == "FLIP":
arg = f"""<function>FLIP</function>
<start_address>{hex(start_address)}</start_address>
<length>{hex(length)}</length>
<repeat>{hex(repeat)}</repeat>"""
content = {
"arg": [
f"<function>FLIP</function>",
f"<start_address>{hex(start_address)}</start_address>",
f"<length>{hex(length)}</length>",
f"<repeat>{hex(repeat)}</repeat>"
]
}
else:
arg = f"""<function>CALIBRATION</function>
<target_file>ms-appdata:///local/calib.bin</target_file>"""
cmd = self.create_cmd("RAM-TEST", arg)
content = {
"arg": [
f"<function>CALIBRATION</function>",
f"<target_file>ms-appdata:///local/calib.bin</target_file>"
]
}
cmd = self.create_cmd("RAM-TEST", content)
resp = """
<?xml version=\"1.0\" encoding=\"utf-8\"?><host><version>1.0</version><command>CMD:UPLOAD-FILE</command><arg><checksum>CHK_NO</checksum><info>WriteLocalFile</info><target_file>%s</target_file><packet_length>0x%x</packet_length></arg></host>
<?xml version=\"1.0\" encoding=\"utf-8\"?><host><version>1.0</version><command>CMD:PROGRESS-REPORT</command><arg><message>RAM test.</message></arg></host>
@ -112,9 +137,13 @@ class XMLCmd(metaclass=LogBase):
return cmd
def cmd_dram_repair(self, mem_offset: int = 0x10000, mem_length: int = 0x1000):
arg = f"""<param_file>D:/dram.info</param_file>
<target_file>MEM://{mem_offset}:{mem_length}</target_file>"""
cmd = self.create_cmd("DRAM-REPAIR", arg)
content = {
"arg": [
f"<param_file>D:/dram.info</param_file>",
f"<target_file>MEM://{mem_offset}:{mem_length}</target_file>"
]
}
cmd = self.create_cmd("DRAM-REPAIR", content)
# INFO Result: SUCCEEDED, NO-NEED, FAILED
return cmd
@ -130,8 +159,13 @@ class XMLCmd(metaclass=LogBase):
</arg>
</da>
"""
arg = f"""<target_file>MEM://{hex(host_mem_offset)}:{hex(length)}</target_file>"""
cmd = self.create_cmd("READ-PARTITION-TABLE", arg)
content = {
"arg": [
f"<target_file>MEM://{hex(host_mem_offset)}:{hex(length)}</target_file>"
]
}
cmd = self.create_cmd("READ-PARTITION-TABLE", content)
resp = """
<?xml version="1.0" encoding="utf-8"?>
<partition_table version="1.0">
@ -164,20 +198,33 @@ class XMLCmd(metaclass=LogBase):
"""
<?xml version="1.0" encoding="utf-8"?><da><version>1.0</version><command>CMD:CAN-HIGHER-USB-SPEED</command><arg><target_file>MEM://0x7fe8463ed240:0x40</target_file></arg></da>
"""
arg = f"<target_file>MEM://{hex(host_mem_offset)}:{hex(length)}</target_file>"
cmd = self.create_cmd("CAN-HIGHER-USB-SPEED", arg)
content = {
"arg": [
f"<target_file>MEM://{hex(host_mem_offset)}:{hex(length)}</target_file>"
]
}
cmd = self.create_cmd("CAN-HIGHER-USB-SPEED", content)
return cmd
def cmd_write_efuse(self):
arg = f"""<source_file>ms-appdata:///local/efuse.xml</source_file>"""
cmd = self.create_cmd("WRITE-EFUSE", arg)
content = {
"arg": [
f"<source_file>ms-appdata:///local/efuse.xml</source_file>"
]
}
cmd = self.create_cmd("WRITE-EFUSE", content)
resp = """
<?xml version=\"1.0\" encoding=\"utf-8\"?><host><version>1.0</version><command>CMD:DOWNLOAD-FILE</command><a"rg><checksum>%s</checksum><info>%s</info><source_file>%s</source_file><packet_length>0x%x</packet_length></arg></host>
"""
return cmd
def cmd_read_efuse(self):
arg = f"""<target_file>ms-appdata:///local/efuse.xml</target_file>"""
cmd = self.create_cmd("READ-EFUSE", arg)
content = {
"arg": [
f"<target_file>ms-appdata:///local/efuse.xml</target_file>"
]
}
cmd = self.create_cmd("READ-EFUSE", content)
resp = """
<?xml version=\"1.0\" encoding=\"utf-8\"?><host><version>1.0</version><command>CMD:UPLOAD-FILE</command><arg><"checksum>CHK_NO</checksum><info>%s</info><target_file>%s</target_file><packet_length>0x%x</packet_length></arg></host>
OK@0x%x (length)
@ -195,8 +242,12 @@ class XMLCmd(metaclass=LogBase):
</arg>
</da>
"""
arg = f"""<target_file>MEM://{hex(host_mem_offset)}:{hex(length)}</target_file>"""
cmd = self.create_cmd("GET-HW-INFO", arg)
content = {
"arg": [
f"<target_file>MEM://{hex(host_mem_offset)}:{hex(length)}</target_file>"
]
}
cmd = self.create_cmd("GET-HW-INFO", content)
resp = """ #EMMC
<?xml version=\"1.0\" encoding=\"utf-8\"?><da_hw_info><version>1.2</version><ram_size>0x%llx</ram_size><battery_voltage>%d</battery_voltage><random_id>%s</random_id><storage>%s</storage><emmc><block_size>0x%x</block_size><boot1_size>0x%llx</boot1_size><boot2_size>0x%llx</boot2_size><rpmb_size>0x%llx</rpmb_size><user_size>0x%llx</user_size><gp1_size>0</gp1_size><gp2_size>0</gp2_size><gp3_size>0</gp3_size><gp4_size>0</gp4_size><id>%s</id></emmc><product_id>%s</product_id></da_hw_info>
or #UFS
@ -208,24 +259,43 @@ class XMLCmd(metaclass=LogBase):
"""
return cmd
def cmd_set_boot_mode(self, mode:BootModes=BootModes.testmode, adb:bool=True, mobilelog:bool=True, connectuart:bool=False):
connect_type="UART" if connectuart else "USB"
mobilelog="ON" if mobilelog else "OFF"
adb="ON" if adb else "OFF"
content = {
"arg": [
f"<mode>{mode}</mode>",
f"<connect_type>{connect_type}</connect_type>",
f"<mobile_log>{mobilelog}</mobile_log>",
f"<adb>{adb}</adb>"
]
}
cmd = self.create_cmd("SET-BOOT-MODE", content)
def cmd_read_reg(self, bit_width: int = 32, base_address: int = 0x1000, mem_offset: int = 0x8000000,
mem_length: int = 0x4):
arg = f"""<bit_width>{bit_width}</bit_width>
<base_address>{hex(base_address)}</base_address>
<target_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</target_file>"""
cmd = self.create_cmd("READ-REGISTER", arg)
resp = """
<?xml version=\"1.0\" encoding=\"utf-8\"?><host><version>1.0</version><command>CMD:UPLOAD-FILE</command><arg><"checksum>CHK_NO</checksum><info>%s</info><target_file>%s</target_file><packet_length>0x%x</packet_length></arg></host>
OK@0x%x (length)
"""
content = {
"arg": [
f"<bit_width>{bit_width}</bit_width>",
f"<base_address>{hex(base_address)}</base_address>",
f"<target_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</target_file>"
]
}
cmd = self.create_cmd("READ-REGISTER", content)
return cmd
def cmd_write_reg(self, bit_width: int = 32, base_address: int = 0x1000, mem_offset: int = 0x8000000,
mem_length: int = 0x4):
arg = f"""<bit_width>{bit_width}</bit_width>
<base_address>{hex(base_address)}</base_address>
<source_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</source_file>"""
cmd = self.create_cmd("WRITE-REGISTER", arg)
content = {
"arg": [
f"<bit_width>{bit_width}</bit_width>",
f"<base_address>{hex(base_address)}</base_address>",
f"<source_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</source_file>"
]
}
cmd = self.create_cmd("WRITE-REGISTER", content)
return cmd
def cmd_read_partition_name(self):
@ -248,9 +318,13 @@ class XMLCmd(metaclass=LogBase):
</arg>
</da>
"""
arg = f"""<function>{function}</function>
<target_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</target_file>"""
cmd = self.create_cmd("EMMC-CONTROL", arg)
content = {
"arg": [
f"<function>{function}</function>",
f"<target_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</target_file>"
]
}
cmd = self.create_cmd("EMMC-CONTROL", content)
return cmd
def cmd_reboot(self, disconnect: bool = False):
@ -258,100 +332,139 @@ class XMLCmd(metaclass=LogBase):
action = "DISCONNECT"
else:
action = "IMMEDIATE"
arg = f"""<action>{action}</action>"""
cmd = self.create_cmd("REBOOT", arg)
content = {
"arg": [
f"<action>{action}</action>",
]
}
cmd = self.create_cmd("REBOOT", content)
return cmd
def cmd_write_partition(self, partition: str = "system", mem_offset: int = 0x8000000, mem_length: int = 0x100000):
arg = f"""<partition>{partition}</partition>
<source_file>MEM://{hex(mem_offset)}:{hex(mem_length)}"""
cmd = self.create_cmd("WRITE-FLASH", arg)
content = {
"arg": [
f"<partition>{partition}</partition>",
f"<source_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</source_file>"
]
}
cmd = self.create_cmd("WRITE-FLASH", content)
return cmd
def cmd_write_flash(self, partition: str = "EMMC-USER", offset: int = 0, mem_offset: int = 0x8000000,
mem_length: int = 0x100000):
arg = f"""<partition>{partition}</partition>
<offset>{hex(offset)}</offset>
<source_file>MEM://{hex(mem_offset)}:{hex(mem_length)}"""
cmd = self.create_cmd("WRITE-FLASH", arg)
content = {
"arg": [
f"<partition>{partition}</partition>",
f"<offset>{hex(offset)}</offset>",
f"<source_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</source_file>"
]
}
cmd = self.create_cmd("WRITE-FLASH", content)
return cmd
def cmd_read_partition(self, partition: str = "system"):
arg = f"""<partition>{partition}</partition>
<target_file>"C:/file.bin"</target_file>"""
cmd = self.create_cmd("READ-PARTITION", arg)
content = {
"arg": [
f"<partition>{partition}</partition>",
f"<target_file>\"C:/file.bin\"</target_file>"
]
}
cmd = self.create_cmd("READ-PARTITION", content)
return cmd
def cmd_read_flash(self, partition: str = "EMMC-USER", offset: int = 0, length: int = 0x100000):
arg = f"""<partition>{partition}</partition>
<offset>{hex(offset)}</offset>
<length>{hex(length)}</length>"""
cmd = self.create_cmd("READ-FLASH", arg)
content = {
"arg": [
f"<partition>{partition}</partition>",
f"<offset>{hex(offset)}</offset>",
f"<length>{hex(length)}</length>",
f"<target_file>ROM_0</target_file>"
]
}
cmd = self.create_cmd("READ-FLASH", content)
return cmd
def cmd_flash_all(self):
arg = f"""<path_separator>/</path_separator>
<source_file>D:/scatter.xml</source_file>"""
cmd = self.create_cmd("FLASH-ALL", arg)
content = {
"arg": [
f"<path_separator>/</path_separator>",
f"<source_file>D:/scatter.xml</source_file>"
]
}
cmd = self.create_cmd("FLASH-ALL", content)
return cmd
def cmd_erase_partition(self, partition: str = "system"):
arg = f"""<partition>{partition}</partition>"""
cmd = self.create_cmd("ERASE-PARTITION", arg)
content = {
"arg": [
f"<partition>{partition}</partition>"
]
}
cmd = self.create_cmd("ERASE-PARTITION", content)
return cmd
def cmd_erase_flash(self, partition: str = "EMMC-USER", offset: int = 0, length: int = 0x100000):
arg = f"""<partition>{partition}</partition>
<offset>{hex(offset)}</offset>
<length>{hex(length)}</length>"""
cmd = self.create_cmd("ERASE-FLASH", arg)
content = {
"arg": [
f"<partition>{partition}</partition>",
f"<offset>{hex(offset)}</offset>",
f"<length>{hex(length)}</length>"
]
}
cmd = self.create_cmd("ERASE-FLASH", content)
return cmd
def cmd_flash_update(self):
arg = f"""<path_separator>/</path_separator>
<source_file>D:/scatter.xml</source_file>
<backup_folder>D:/backup</backup_folder>"""
cmd = self.create_cmd("FLASH-UPDATE", arg)
content = {
"arg": [
f"<path_separator>/</path_separator>",
f"<source_file>D:/scatter.xml</source_file>",
f"<backup_folder>D:/backup</backup_folder>"
]
}
cmd = self.create_cmd("FLASH-UPDATE", content)
return cmd
def cmd_write_partitions(self, partitions):
flashlist = ""
for partition in partitions:
flashlist += f"<pt name={partition}>{partition}.img</pt>\n"
arg = f"""<source_file>D:/scatter.xml</source_file>
<flash_list>{flashlist}</flash_list>"""
cmd = self.create_cmd("WRITE-PARTITIONS", arg)
return cmd
def cmd_set_boot_mode(self, boot_mode):
if boot_mode == "META":
arg = f"""<mode>META</mode>
<connect_type>WIFI</connect_type>
<mobile_log>ON</mobile_log>
<adb>ON</adb>"""
# ADB = (ON,UART,USB)
elif boot_mode == "FASTBOOT":
arg = f"""<mode>META</mode>"""
elif boot_mode == "ANDROID-TEST-MODE":
arg = f"""<mode>ANDROID-TEST-MODE</mode>"""
cmd = self.create_cmd("SET-BOOT-MODE", arg)
flashlist += f" <pt name={partition}>{partition}.img</pt>\n"
content = {
"arg": [
f"<source_file>D:/scatter.xml</source_file>",
f"<flash_list>{flashlist}</flash_list>"
]
}
cmd = self.create_cmd("WRITE-PARTITIONS", content)
return cmd
def cmd_set_rsc(self, key: str = "k6885v1_64[op01]"):
# runtime_switchable_config
arg = f"""<key>{key}</key>
<source_file>ms-appdata:///local/RSC.bin</source_file>"""
cmd = self.create_cmd("SET-RSC", arg)
content = {
"arg": [
f"<key>{key}</key>",
f"<source_file>ms-appdata:///local/RSC.bin</source_file>"
]
}
cmd = self.create_cmd("SET-RSC", content)
return cmd
def cmd_write_private_cert(self):
arg = f"""<source_file>ms-appdata:///local/cert.bin</source_file>"""
cmd = self.create_cmd("WRITE-PRIVATE-CERT", arg)
content = {
"arg": [
f"<source_file>ms-appdata:///local/cert.bin</source_file>"
]
}
cmd = self.create_cmd("WRITE-PRIVATE-CERT", content)
return cmd
def cmd_get_da_info(self, mem_offset: int = 0x2000000, mem_length: int = 0x20000):
arg = f"""<target_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</target_file>"""
cmd = self.create_cmd("GET-DA-INFO", arg)
content = {
"arg": [
f"<target_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</target_file>"
]
}
cmd = self.create_cmd("GET-DA-INFO", content)
resp = """
<?xml version=\"1.0\" encoding=\"utf-8\"?><host><version>1.0</version><command>CMD:UPLOAD-FILE</command><arg><checksum>CHK_NO</checksum><info>WriteLocalFile</info><target_file>%s</target_file><packet_length>0x%x</packet_length></arg></host>
<?xml version=\"1.0\" encoding=\"utf-8\"?><da_info><version>1.0</version><da_version>2021</da_version><build>May 24 2022:19:03:56</build></da_info>"
@ -372,9 +485,13 @@ class XMLCmd(metaclass=LogBase):
</arg>
</da>
"""
arg = f"""<key>{key}</key>
<target_file>MEM://{hex(host_mem_offset)}:{hex(length)}</target_file>"""
cmd = self.create_cmd("GET-SYS-PROPERTY", arg)
content = {
"arg": [
f"<key>{key}</key>",
f"<target_file>MEM://{hex(host_mem_offset)}:{hex(length)}</target_file>"
]
}
cmd = self.create_cmd("GET-SYS-PROPERTY", content)
return cmd
def cmd_set_host_info(self, hostinfo: str = ""):
@ -384,11 +501,19 @@ class XMLCmd(metaclass=LogBase):
if hostinfo == "":
currentDateAndTime = datetime.datetime.now()
hostinfo = currentDateAndTime.strftime("%Y%m%dT%H%M%S")
arg = f"""<info>{hostinfo}</info>"""
cmd = self.create_cmd("SET-HOST-INFO", arg)
content = {
"arg": [
f"<info>{hostinfo}</info>",
]
}
cmd = self.create_cmd("SET-HOST-INFO", content)
return cmd
def cmd_get_downloaded_image_feedback(self, mem_offset: int = 0x2000000, mem_length: int = 0x20000):
arg = f"""<target_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</target_file>"""
cmd = self.create_cmd("GET-DOWNLOADED-IMAGE-FEEDBACK", arg)
content = {
"arg": [
f"<target_file>MEM://{hex(mem_offset)}:{hex(mem_length)}</target_file>",
]
}
cmd = self.create_cmd("GET-DOWNLOADED-IMAGE-FEEDBACK", content)
return cmd

679
mtkclient/Library/DA/xml/xml_lib.py Normal file → Executable file
View file

@ -16,11 +16,41 @@ from mtkclient.config.payloads import pathconfig
from mtkclient.Library.settings import hwparam
from mtkclient.Library.thread_handling import writedata, Queue, Thread
from mtkclient.Library.DA.xml.xml_cmd import *
from mtkclient.Library.DA.xml.extension.v6 import xmlflashext
rq = Queue()
class ShutDownModes:
TEST = 3
META = 4
NORMAL = 0
HOME_SCREEN = 1
FASTBOOT = 2
def get_field(data, fieldname):
if type(data)==bytes or type(data)==bytearray:
data = data.decode('utf-8')
start = data.find(f"<{fieldname}>")
if start != -1:
end = data.find(f"</{fieldname}>", start + len(fieldname) + 2)
if start != -1 and end != -1:
return data[start + len(fieldname) + 2:end]
return ""
class file_sys_op:
key = None
file_path = None
def __init__(self, key, file_path):
self.key = key
self.file_path = file_path
class upfile:
checksum = None
info = None
source_file = None
packet_length = None
def __init__(self, checksum, info, target_file, packet_length):
self.checksum = checksum
self.info = info
@ -29,7 +59,12 @@ class upfile:
class dwnfile:
def __init__(self, checksum, info, source_file, packet_length):
checksum = None
info = None
source_file = None
packet_length = None
def __init__(self, checksum:str, info:str, source_file:str, packet_length:int):
self.checksum = checksum
self.info = info
self.source_file = source_file
@ -60,12 +95,32 @@ class DAXML(metaclass=LogBase):
self.rdword = self.mtk.port.rdword
self.rword = self.mtk.port.rword
self.daconfig = daconfig
self.partition = Partition(self.mtk, self.readflash, self.read_pmt, loglevel)
self.partition = Partition(self.mtk, self.readflash, self.read_partition_table, loglevel)
self.pathconfig = pathconfig()
self.patch = False
self.generatekeys = self.mtk.config.generatekeys
if self.generatekeys:
self.patch = True
try:
from mtkclient.Library.Exploit.carbonara import Carbonara
self.carbonara = Carbonara(self.mtk, loglevel)
except:
self.carbonara = None
self.xmlft = xmlflashext(self.mtk, self, loglevel)
def xread(self):
try:
hdr = self.usbread(4 + 4 + 4)
magic, datatype, length = unpack("<III", hdr)
except Exception as err:
self.error("xread error: " + str(err))
return -1
if magic != 0xFEEEEEEF:
self.error("xread error: Wrong magic")
return -1
resp = self.usbread(length)
return resp
def xsend(self, data, datatype=DataType.DT_PROTOCOL_FLOW, is64bit: bool = False):
if isinstance(data, int):
@ -94,6 +149,9 @@ class DAXML(metaclass=LogBase):
def ack_value(self, length):
return self.xsend(f"OK@{hex(length)}")
def ack_text(self, text):
return self.xsend(f"OK@{text}")
def setup_env(self):
da_log_level = int(self.daconfig.uartloglevel)
loglevel = "INFO"
@ -118,11 +176,15 @@ class DAXML(metaclass=LogBase):
if noack:
return True
cmd, result = self.get_command_result()
if cmd == "CMD:END" and result == "OK":
if cmd == "CMD:END":
self.ack()
scmd, sresult = self.get_command_result()
if scmd == "CMD:START":
return True
if result == "OK":
return True
else:
self.error(result)
return False
else:
return result
elif result == "ERR!UNSUPPORTED":
@ -135,32 +197,32 @@ class DAXML(metaclass=LogBase):
return result
return False
def get_field(self, data, fieldname):
start = data.find(f"<{fieldname}>")
if start!=-1:
end = data.find(f"</{fieldname}>",start+len(fieldname)+2)
if start!=-1 and end!=-1:
return data[start+len(fieldname)+2:end]
return ""
def get_response(self) -> str:
def get_response(self, raw:bool=False) -> str:
sync = self.usbread(4 * 3)
if len(sync) == 4 * 3:
if int.to_bytes(sync[:4], 'little') == 0xfeeeeeef:
if int.to_bytes(sync[4:8], 'little') == 0x1:
length = int.to_bytes(sync[8:12])
if int.from_bytes(sync[:4], 'little') == 0xfeeeeeef:
if int.from_bytes(sync[4:8], 'little') == 0x1:
length = int.from_bytes(sync[8:12],'little')
data = self.usbread(length)
if len(data) == length:
return bytes.decode(data.rstrip(b"\x00"), 'utf-8')
if raw:
return data
return data.rstrip(b"\x00").decode('utf-8')
return ""
def get_response_data(self) -> bytes:
sync = self.usbread(4 * 3)
if len(sync) == 4 * 3:
if int.to_bytes(sync[:4], 'little') == 0xfeeeeeef:
if int.to_bytes(sync[4:8], 'little') == 0x1:
length = int.to_bytes(sync[8:12])
data = self.usbread(length)
if int.from_bytes(sync[:4], 'little') == 0xfeeeeeef:
if int.from_bytes(sync[4:8], 'little') == 0x1:
length = int.from_bytes(sync[8:12],'little')
usbepsz = self.mtk.port.cdc.get_read_packetsize()
data=bytearray()
bytestoread = length
while bytestoread>0:
sz = min(usbepsz, bytestoread)
data.extend(self.usbread(sz))
bytestoread-=sz
if len(data) == length:
return data
return b""
@ -229,10 +291,79 @@ class DAXML(metaclass=LogBase):
res = self.send_command(self.Cmd.cmd_set_host_info(hostinfo))
return res
def write_register(self,addr, data):
result = self.send_command(self.Cmd.cmd_write_reg(bit_width=32,base_address=addr))
if type(result) == dwnfile:
if self.upload(result, data):
self.info("Successfully wrote data.")
return True
return False
def read_efuse(self):
tmp = self.Cmd.cmd_read_efuse()
self.send_command(tmp)
cmd, result = self.get_command_result()
# CMD:END
scmd, sresult = self.get_command_result()
self.ack()
if sresult == "OK":
tcmd, tresult = self.get_command_result()
if tresult=="START":
return result
return None
def read_register(self,addr):
tmp = self.Cmd.cmd_read_reg(base_address=addr)
if self.send_command(tmp):
cmd, data = self.get_command_result()
if cmd!='':
return False
# CMD:END
scmd, sresult = self.get_command_result()
self.ack()
if sresult == "OK":
tcmd, tresult = self.get_command_result()
if tresult=="START":
return data
return None
def get_command_result(self):
data = self.get_response()
cmd = self.get_field(data,"command")
cmd = get_field(data,"command")
result = ""
if cmd == '' and "OK@" in data:
tmp = data.split("@")[1]
length = int(tmp[2:], 16)
self.ack()
sresp = self.get_response()
if "OK" in sresp:
self.ack()
data = bytearray()
bytesread = 0
bytestoread = length
worker = None
while bytestoread > 0:
tmp = self.get_response_data()
bytestoread -= len(tmp)
bytesread += len(tmp)
data.extend(tmp)
self.ack()
return cmd, data
if cmd=="CMD:PROGRESS-REPORT":
"""
<?xml version="1.0" encoding="utf-8"?><host><version>1.0</version>
<command>CMD:PROGRESS-REPORT</command>
<arg>
<message>init-hw</message>
</arg></host>
"""
self.ack()
data = ""
while data != "OK!EOT":
data = self.get_response()
self.ack()
data = self.get_response()
cmd = get_field(data, "command")
if cmd == "CMD:START":
self.ack()
return cmd, "START"
@ -247,86 +378,126 @@ class DAXML(metaclass=LogBase):
<packet_length>0x1000</packet_length>
</arg></host>
"""
checksum = self.get_field(data,"checksum")
info = self.get_field(data,"info")
source_file = self.get_field(data, "source_file")
packet_length = self.get_field(data, "packet_length")
checksum = get_field(data,"checksum")
info = get_field(data,"info")
source_file = get_field(data, "source_file")
packet_length = int(get_field(data, "packet_length"),16)
self.ack()
return cmd, dwnfile(checksum,info,source_file,packet_length)
elif cmd=="CMD:PROGRESS-REPORT":
"""
<?xml version="1.0" encoding="utf-8"?><host><version>1.0</version>
<command>CMD:PROGRESS-REPORT</command>
<arg>
<message>init-hw</message>
</arg></host>
"""
self.ack()
data = ""
while data != "OK!EOT":
data = self.get_response()
self.ack()
data = self.get_response()
cmd = self.get_field(data, "command")
elif cmd=="CMD:UPLOAD-FILE":
checksum = self.get_field(data, "checksum")
info = self.get_field(data, "info")
target_file = self.get_field(data, "target_file")
packet_length = self.get_field(data, "packet_length")
checksum = get_field(data, "checksum")
info = get_field(data, "info")
target_file = get_field(data, "target_file")
packet_length = get_field(data, "packet_length")
self.ack()
return cmd, upfile(checksum,info,target_file,packet_length)
elif cmd=="CMD:FILE-SYS-OPERATION":
"""
'<?xml version="1.0" encoding="utf-8"?><host><version>1.0</version><command>CMD:FILE-SYS-OPERATION</command><arg><key>FILE-SIZE</key><file_path>MEM://0x8000000:0x4000000</file_path></arg></host>'
"""
key = get_field(data, "key")
file_path = get_field(data, "file_path")
self.ack()
return cmd, file_sys_op(key, file_path)
if cmd=="CMD:END":
result = self.get_field(data,"result")
result = get_field(data,"result")
if "message" in data and result !="OK":
message = self.get_field(data,"message")
message = get_field(data,"message")
return cmd, message
return cmd, result
def upload(self, result, data):
def upload(self, result:dwnfile, data, display=True, raw=False):
if type(result)==dwnfile:
checksum, info, source_file, packet_length = result
checksum=result.checksum
info=result.info
source_file=result.source_file
packet_length = result.packet_length
tmp = source_file.split(":")[2]
length = int(tmp[2:], 16)
self.ack_value(length)
if display:
self.mtk.daloader.progress.clear()
resp = self.get_response()
byteswritten=0
if resp == "OK":
for pos in range(0, length, packet_length):
self.ack_value(0)
self.xsend(data=data[pos:pos + packet_length])
resp = self.get_response()
if resp != "OK":
if not "OK" in resp:
msg = get_field(resp, "message")
self.error(f"Error on writing stage2 ACK0 at pos {hex(pos)}")
self.error(msg)
return False
tmp=data[pos:pos+packet_length]
tmplen=len(tmp)
self.xsend(data=tmp)
resp = self.get_response()
if not "OK" in resp:
self.error(f"Error on writing stage2 at pos {hex(pos)}")
return False
cmd, result = self.get_command_result()
byteswritten+=tmplen
if display:
self.mtk.daloader.progress.show_progress("Written", byteswritten, length, display)
if raw:
self.ack()
if cmd == "CMD:END" and result=="OK":
cmd, result = self.get_command_result()
if cmd=="CMD:START":
self.ack()
return True
return True
cmd, result = self.get_command_result()
self.ack()
if cmd == "CMD:END" and result=="OK":
cmd, result = self.get_command_result()
if cmd=="CMD:START":
return True
else:
cmd, result = self.get_command_result()
self.error(result)
return False
else:
self.error("No upload data received. Aborting.")
return False
def download(self, result):
def download_raw(self, result, filename:str="", display:bool=False):
global rq
if display:
self.mtk.daloader.progress.clear()
if type(result)==upfile:
checksum, info, target_file, packet_length = result
checksum = result.checksum
info = result.info
target_file = result.target_file
packet_length = int(result.packet_length,16)
resp = self.get_response()
if "OK@" in resp:
tmp = resp.split("@")[1]
length = int(tmp[2:], 16)
self.ack()
sresp = self.get_response()
if sresp == "OK":
if "OK" in sresp:
self.ack()
data=bytearray()
while length>0:
bytesread = 0
bytestoread = length
worker = None
if filename != "":
worker = Thread(target=writedata, args=(filename, rq), daemon=True)
worker.start()
while bytestoread>0:
tmp = self.get_response_data()
length-=len(tmp)
data.extend(tmp)
bytestoread-=len(tmp)
bytesread+=len(tmp)
if filename != "":
rq.put(tmp)
else:
data.extend(tmp)
if display:
self.mtk.daloader.progress.show_progress("Read", bytesread, length, display)
self.ack()
sresp = self.get_response()
if "OK" not in sresp:
break
else:
self.ack()
if filename != "":
rq.put(None)
worker.join(60)
return True
return data
self.error("Error on downloading data:"+resp)
return False
@ -334,12 +505,44 @@ class DAXML(metaclass=LogBase):
self.error("No download data received. Aborting.")
return False
def boot_to(self, da2, da2offset):
result = self.send_command(self.Cmd.cmd_boot_to(at_addr=da2offset, jmp_addr=da2offset, length=len(da2)))
if type(result) == dict:
def download(self, result):
if type(result)==upfile:
checksum = result.checksum
info = result.info
target_file = result.target_file
packet_length = int(result.packet_length,16)
resp = self.get_response()
if "OK@" in resp:
tmp = resp.split("@")[1]
length = int(tmp[2:], 16)
self.ack()
sresp = self.get_response()
if "OK" in sresp:
self.ack()
data=bytearray()
bytesread = 0
bytestoread = length
worker = None
while bytestoread>0:
tmp = self.get_response_data()
bytestoread-=len(tmp)
bytesread+=len(tmp)
data.extend(tmp)
self.ack()
return data
self.error("Error on downloading data:"+resp)
return False
else:
self.error("No download data received. Aborting.")
return False
def boot_to(self, addr, data, display=True, timeout=0.5):
result = self.send_command(self.Cmd.cmd_boot_to(at_addr=addr, jmp_addr=addr, length=len(data)))
if type(result) == dwnfile:
self.info("Uploading stage 2...")
if self.upload(result,da2):
if self.upload(result, data):
self.info("Successfully uploaded stage 2.")
return True
else:
self.error("Wrong boot_to response :(")
return False
@ -349,8 +552,15 @@ class DAXML(metaclass=LogBase):
if self.upload_da1():
self.info("Stage 1 successfully loaded.")
da2 = self.daconfig.da2
da2offset = self.daconfig.da_loader.region[2].m_buf
if self.boot_to(da2,da2offset):
da2offset = self.daconfig.da_loader.region[2].m_start_addr
if not self.mtk.daloader.patch:
loaded = self.boot_to(da2offset, da2)
self.daext = False
else:
loaded = self.boot_to(da2offset, da2)
self.daext = False
if loaded:
self.info("Successfully uploaded stage 2")
self.setup_hw_init()
self.change_usb_speed()
@ -362,7 +572,6 @@ class DAXML(metaclass=LogBase):
self.info("SLA is enabled")
else:
self.error(res)
self.daext = False
self.storage = self.get_hw_info()
self.reinit(True)
self.check_lifecycle()
@ -374,6 +583,8 @@ class DAXML(metaclass=LogBase):
def get_hw_info(self):
self.send_command(self.Cmd.cmd_get_hw_info(),noack=True)
cmd, result = self.get_command_result()
if type(result)!=upfile:
return False
data = self.download(result)
"""
<?xml version="1.0" encoding="utf-8"?>
@ -399,45 +610,68 @@ class DAXML(metaclass=LogBase):
if sresult == "OK":
tcmd, tresult = self.get_command_result()
if tresult=="START":
storage = self.get_field(data, "storage")
storage = get_field(data, "storage")
class storage_info:
def __init__(self, storagetype, data):
self.storagetype = storagetype
if self.storagetype == "UFS":
self.block_size = self.get_field(data,"block_size")
self.lua0_size = self.get_field(data,"lua0_size")
self.lua1_size = self.get_field(data,"lua1_size")
self.lua2_size = self.get_field(data,"lua2_size")
self.lua3_size = self.get_field(data,"lua3_size")
self.cid = self.get_field(data,"id")
self.block_size = int(get_field(data,"block_size"),16)
self.lua0_size = int(get_field(data,"lua0_size"),16)
self.lua1_size = int(get_field(data,"lua1_size"),16)
self.lua2_size = int(get_field(data,"lua2_size"),16)
self.lua3_size = int(get_field(data,"lua3_size"),16)
self.cid = get_field(data,"id")
elif self.storagetype == "EMMC":
self.block_size = self.get_field(data, "block_size")
self.boot1_size = self.get_field(data, "boot1_size")
self.boot2_size = self.get_field(data, "boot2_size")
self.rpmb_size = self.get_field(data, "rpmb_size")
self.user_size = self.get_field(data, "user_size")
self.gp1_size = self.get_field(data, "gp1_size")
self.gp2_size = self.get_field(data, "gp2_size")
self.gp3_size = self.get_field(data, "gp3_size")
self.gp4_size = self.get_field(data, "gp4_size")
self.cid = self.get_field(data, "id")
self.block_size = int(get_field(data, "block_size"),16)
self.boot1_size = int(get_field(data, "boot1_size"),16)
self.boot2_size = int(get_field(data, "boot2_size"),16)
self.rpmb_size = int(get_field(data, "rpmb_size"),16)
self.user_size = int(get_field(data, "user_size"),16)
self.gp1_size = int(get_field(data, "gp1_size"),16)
self.gp2_size = int(get_field(data, "gp2_size"),16)
self.gp3_size = int(get_field(data, "gp3_size"),16)
self.gp4_size = int(get_field(data, "gp4_size"),16)
self.cid = get_field(data, "id")
elif self.storagetype == "NAND":
self.block_size = self.get_field(data, "block_size")
self.page_size = self.get_field(data, "page_size")
self.spare_size = self.get_field(data, "spare_size")
self.total_size = self.get_field(data, "total_size")
self.cid = self.get_field(data, "id")
self.page_parity_size = self.get_field(data, "page_parity_size")
self.sub_type = self.get_field(data, "sub_type")
self.block_size = int(get_field(data, "block_size"),16)
self.page_size = int(get_field(data, "page_size"),16)
self.spare_size = int(get_field(data, "spare_size"),16)
self.total_size = int(get_field(data, "total_size"),16)
self.cid = get_field(data, "id")
self.page_parity_size = int(get_field(data, "page_parity_size"),16)
self.sub_type = get_field(data, "sub_type")
else:
self.error(f"Unknown storage type: {storage}")
return storage_info(storagetype=storage,data=data)
def check_sla(self):
"""
;private_key_d="009a3c3d4da0650cef38ed96ef833904c9c13835199367c7b9cb03a55e7aa482016a820dfe597cd54dd1f81fd879cf070ec0c25899ac5a49822db09675a92acf6a01e0f8f538bbe66de48ca9bdca313b616470d9ec2914356d03c95f7d9236549e5a21457e4dd5fcaf09046c47ca7436f06cd7b82cb6d2a936fca88b707f6ce28f33110fea1ec363e8482419db901cb0d38e574fe0c02ad117166b40ec78f59aaa7f3eafa425010a95614e046651273a6cb1371380c4e6ce81bdb892db6ff4892cc4d8c613a8fb3fec1e72c279052896872fc23da07fba63783374f3be8e16a15e0a04a139108dd6ac239f191135f4a895e27c670de065d2248e3f9c7e920fd001"
;public_key_e = "00010001"
;public_key_n = "008C8BF38EB2FC7FC06D567DBF70E9C34BE4281C4239ED9C58A6B598C3AE7821815D94D0B463463EEBBD69FF6AF990AE0499B6C3B3CADCD91D54499CD66E5314DB610FC0C6CAEEB1F16B6F2D451E3F2B2D515008917FCEC50ADA4CE0699BCF247D5AE2A1DDD34C48624A657CCB11CE5F8C6CE92CAB6038EFC2A89E42E029488C02C3CF21947C86D51BBA8EF540A2A7CE85356F431891261D860B518E89DD73B2D240461ACB66BCC213403145DE83F6963147E65274EA1E45DB2D231E0774ECC86E4F2328F8A90835C4FDEF1088DDBA1D8F7CA0CA732A64BDA6816162C0F88F02CF97634D85530968CBF8B7CE6A8B67D53BBFB4910843EA413135D56FB5074445"
ROWAN / 0_2048_key.pem / CHIP_TEST_KEY.ini
e_brom = 010001
n_brom = D16403466C530EF9BB53C1E8A96A61A4E332E17DC0F55BB46D207AC305BAE9354EAAC2CB3077B33740D275036B822DB268200DE17DA3DB7266B27686B8970B85737050F084F8D576904E74CD6C53B31F0BB0CD60686BF67C60DA0EC20F563EEA715CEBDBF76D1C5C10E982AB2955D833DE553C9CDAFD7EA2388C02823CFE7DD9AC83FA2A8EB0685ABDAB56A92DF1A7805E8AC0BD10C0F3DCB1770A9E6BBC3418C5F84A48B7CB2316B2C8F64972F391B116A58C9395A9CE9E743569A367086D7771D39FEC8EBBBA3DD2B519785A76A9F589D36D637AF884543FD65BAC75BE823C0C50AA16D58187B97223625C54C66B5A5E4DBAEAB7BE89A4E340A2E241B09B2F
d_brom = 09976537029b4362591c5b13873f223de5525d55df52dde283e52afa67f6c9dbf1408d2fb586a624efc93426f5f3be981f80e861ddd975a1e5e662db84f5164804a3ae717605d7f15866df9ed1497c38fdd6197243163ef22f958d7b822c57317203e9a1e7d18dad01f15054facdbddb9261a1272638da661fe4f9f0714ecf00e6541cc435afb1fd75a27d34b17ad400e9474ba850dafce266799caff32a058ff71e4c2daacaf8ba709e9ca4dc87584a7ffe8aa9a0a160ed069c3970b7dae3987ded71bd0bc824356987bd74363d46682c71913c3edbdb2a911f701f23aee3f8dd98180b5a138fd5ad74743682d2d2d1bb3d92786710248f316dd8391178ea81
SetRsaKey in libsla_challenge.so :
e_brom = 010001
n_brom = C43469A95B143CDC63CE318FE32BAD35B9554A136244FA74D13947425A32949EE6DC808CDEBF4121687A570B83C51E657303C925EC280B420C757E5A63AD3EC6980AAD5B6CA6D1BBDC50DB793D2FDDC0D0361C06163CFF9757C07F96559A2186322F7ABF1FFC7765F396673A48A4E8E3296427BC5510D0F97F54E5CA1BD7A93ADE3F6A625056426BDFE77B3B502C68A18F08B470DA23B0A2FAE13B8D4DB3746255371F43306582C74794D1491E97FDE504F0B1ECAC9DDEF282D674B817B7FFA8522672CF6281790910378FEBFA7DC6C2B0AF9DA03A58509D60AA1AD6F9BFDC84537CD0959B8735FE0BB9B471104B458A38DF846366926993097222F90628528F
d_brom = 8E02CDB389BBC52D5383EBB5949C895B0850E633CF7DD3B5F7B5B8911B0DDF2A80387B46FAF67D22BC2748978A0183B5B420BA579B6D847082EA0BD14AB21B6CCCA175C66586FCE93756C2F426C85D7DF07629A47236265D1963B8354CB229AFA2E560B7B3641DDB8A0A839ED8F39BA8C7CDB94104650E8C7790305E2FF6D18206F49B7290B1ADB7B4C523E10EBF53630D438EF49C877402EA3C1BD6DD903892FD662FBDF1DFF5D7B095712E58E728BD7F6A8B5621175F4C08EBD6143CDACD65D9284DFFECAB64F70FD63182E4981551522727A2EE9873D0DB78180C26553AD0EE1CAAA21BCEBC5A8C0B331FE7FD8710F905A7456AF675A04AF1118CE71E36C9
d_da = 707C8892D0DE8CE0CA116914C8BD277B821E784D298D00D3473EDE236399435F8541009525C2786CB3ED3D7530D47C9163692B0D588209E7E0E8D06F4A69725498B979599DC576303B5D8D96F874687A310D32E8C86E965B844BC2ACE51DC5E06859EA087BD536C39DCB8E1262FDEAF6DA20035F14D3592AB2C1B58734C5C62AC86FE44F98C602BABAB60A6C8D09A199D2170E373D9B9A5D9B6DE852E859DEB1BDF33034DCD91EC4EEBFDDBECA88E29724391BB928F40EFD945299DFFC4595BB8D45F426AC15EC8B1C68A19EB51BEB2CC6611072AE5637DF0ABA89ED1E9CB8C9AC1EB05B1F01734DB303C23BE1869C9013561B9F6EA65BD2516DE950F08B2E81
n_da = A243F6694336D527C5B3ED569DDD0386D309C6592841E4C033DCB461EEA7B6F8535FC4939E403060646A970DD81DE367CF003848146F19D259F50A385015AF6309EAA71BFED6B098C7A24D4871B4B82AAD7DC6E2856C301BE7CDB46DC10795C0D30A68DD8432B5EE5DA42BA22124796512FCA21D811D50B34C2F672E25BCC2594D9C012B34D473EE222D1E56B90E7D697CEA97E8DD4CCC6BED5FDAECE1A43F96495335F322CCE32612DAB462B024281841F553FF7FF33E0103A7904037F8FE5D9BE293ACD7485CDB50957DB11CA6DB28AF6393C3E78D9FBCD4567DEBCA2601622F0F2EB19DA9192372F9EA3B28B1079409C0A09E3D51D64A4C4CE026FAD24CD7
e_da = 010001
int RSA_private_encrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding);
0x10, , 1
"""
data=self.get_sys_property(key="DA.SLA", length=0x200000)
data = data.decode('utf-8')
if "item key=" in data:
tmp=data[data.find("item key=")+8]
tmp=data[data.find("item key=")+8:]
res=tmp[tmp.find(">")+1:tmp.find("<")]
if res=="DISABLED":
return False
@ -451,6 +685,8 @@ class DAXML(metaclass=LogBase):
def get_sys_property(self, key:int="DA.SLA", length:int=0x200000):
self.send_command(self.Cmd.cmd_get_sys_property(key=key,length=length),noack=True)
cmd, result = self.get_command_result()
if type(result)!=upfile:
return False
data = self.download(result)
# CMD:END
scmd, sresult = self.get_command_result()
@ -466,36 +702,183 @@ class DAXML(metaclass=LogBase):
if "Unsupported" in resp:
return False
def read_partition_table(self):
def read_partition_table(self) -> tuple:
self.send_command(self.Cmd.cmd_read_partition_table(),noack=True)
cmd, result = self.get_command_result()
if "Unsupported" in result:
return False
if type(result)!=upfile:
return b"", None
data = self.download(result)
# CMD:END
scmd, sresult = self.get_command_result()
self.ack()
self.ack()
if sresult == "OK":
tcmd, tresult = self.get_command_result()
class partitiontable:
def __init__(self,name,start,size):
self.name=name
self.start=int(start,16)
self.size=int(size,16)
self.start=start
self.size=size
if tresult=="START":
parttbl=[]
data = data.decode('utf-8')
for item in data.split("<pt>"):
name=self.get_field(item,"name")
start = self.get_field(item, "start")
size = self.get_field(item, "size")
parttbl.append(partitiontable(name,start,size))
return parttbl
return None
name=get_field(item,"name")
if name!='':
start = get_field(item, "start")
size = get_field(item, "size")
if size=="":
continue
size = int(size,16)
start = int(start,16)
parttbl.append(partitiontable(name,start//self.config.pagesize,size//self.config.pagesize))
return data, parttbl
return b"", None
def partitiontype_and_size(self, storage=None, parttype=None, length=0):
if length<0x20000:
length = 0x20000
if storage == DaStorage.MTK_DA_STORAGE_EMMC or storage == DaStorage.MTK_DA_STORAGE_SDMMC:
storage = 1
if parttype is None or parttype == "user":
parttype = "EMMC-USER"
elif parttype == "boot1":
parttype = "EMMC-BOOT1"
if self.daconfig.flashtype == "emmc":
length = min(length, self.emmc.boot1_size)
elif parttype == "boot2":
parttype = "EMMC-BOOT2"
if self.daconfig.flashtype == "emmc":
length = min(length, self.emmc.boot2_size)
elif parttype == "gp1":
parttype = "EMMC-GP1"
if self.daconfig.flashtype == "emmc":
length = min(length, self.emmc.gp1_size)
else:
self.error("Unknown parttype. Known parttypes are \"boot1\",\"boot2\",\"gp1\"," +
"\"gp2\",\"gp3\",\"gp4\",\"rpmb\"")
return []
elif storage == DaStorage.MTK_DA_STORAGE_UFS:
if parttype is None or parttype == "lu3" or parttype == "user": # USER
parttype = "UFS-LUA2"
length = min(length, self.ufs.lu3_size)
elif parttype in ["lu1", "boot1"]: # BOOT1
parttype = "UFS-LUA0"
length = min(length, self.ufs.lu1_size)
elif parttype in ["lu2", "boot2"]: # BOOT2
parttype = "UFS-LUA1"
length = min(length, self.ufs.lu2_size)
elif parttype in ["lu4", "rpmb"]: # RPMB
parttype = "UFS-LUA3"
length = min(length, self.ufs.lu4_size)
else:
self.error("Unknown parttype. Known parttypes are \"lu1\",\"lu2\",\"lu3\",\"lu4\"")
return []
elif storage in [DaStorage.MTK_DA_STORAGE_NAND, DaStorage.MTK_DA_STORAGE_NAND_MLC,
DaStorage.MTK_DA_STORAGE_NAND_SLC, DaStorage.MTK_DA_STORAGE_NAND_TLC,
DaStorage.MTK_DA_STORAGE_NAND_SPI, DaStorage.MTK_DA_STORAGE_NAND_AMLC]:
parttype = "NAND-WHOLE" # NAND-AREA0
length = min(length, self.nand.total_size)
elif storage in [DaStorage.MTK_DA_STORAGE_NOR, DaStorage.MTK_DA_STORAGE_NOR_PARALLEL,
DaStorage.MTK_DA_STORAGE_NOR_SERIAL]:
parttype = "NOR-WHOLE" # NOR-AREA0
length = min(length, self.nor.available_size)
return [storage, parttype, length]
def getstorage(self, parttype, length):
if self.daconfig.flashtype == "nor":
storage = DaStorage.MTK_DA_STORAGE_NOR
elif self.daconfig.flashtype == "nand":
storage = DaStorage.MTK_DA_STORAGE_NAND
elif self.daconfig.flashtype == "ufs":
storage = DaStorage.MTK_DA_STORAGE_UFS
if parttype == EMMC_PartitionType.MTK_DA_EMMC_PART_USER:
parttype = UFS_PartitionType.UFS_LU3
elif self.daconfig.flashtype == "sdc":
storage = DaStorage.MTK_DA_STORAGE_SDMMC
else:
storage = DaStorage.MTK_DA_STORAGE_EMMC
part_info = self.partitiontype_and_size(storage, parttype, length)
return part_info
def readflash(self, addr, length, filename, parttype=None, display=True) -> (bytes,bool):
global rq
if parttype is None:
if self.daconfig.flashtype=="emmc":
parttype = "user"
elif self.daconfig.flashtype=="ufs":
parttype = "lu3"
partinfo = self.getstorage(parttype, length)
if not partinfo:
return b""
self.mtk.daloader.progress.clear()
storage, parttype, length = partinfo
self.send_command(self.Cmd.cmd_read_flash(parttype,addr,length),noack=True)
cmd, result = self.get_command_result()
if type(result)!=upfile:
return b""
data = self.download_raw(result=result,filename=filename,display=display)
scmd, sresult = self.get_command_result()
if sresult == "START":
if not filename:
return data
else:
return True
if not filename:
return b""
return False
def writeflash(self, addr, length, filename, offset=0, parttype=None, wdata=None, display=True):
self.mtk.daloader.progress.clear()
fh = None
fill = 0
if filename is not None:
if os.path.exists(filename):
fsize = os.stat(filename).st_size
length = min(fsize, length)
if length % 512 != 0:
fill = 512 - (length % 512)
length += fill
fh = open(filename, "rb")
fh.seek(offset)
else:
self.error(f"Filename doesn't exists: {filename}, aborting flash write.")
return False
if parttype is None:
if self.daconfig.flashtype=="emmc":
parttype = "user"
elif self.daconfig.flashtype=="ufs":
parttype = "lu3"
partinfo = self.getstorage(parttype, length)
if not partinfo:
return False
storage, parttype, rlength = partinfo
self.send_command(self.Cmd.cmd_write_flash(partition=parttype,offset=addr,mem_length=length),noack=True)
cmd, fileopresult = self.get_command_result()
if type(fileopresult)==file_sys_op:
if fileopresult.key != "FILE-SIZE":
return False
self.ack_value(length)
cmd, result = self.get_command_result()
if type(result)==dwnfile:
data = fh.read(length)
if not self.upload(result, data,raw=True):
self.error("Error on writing flash at 0x%08X" % addr)
return False
if fh:
fh.close()
return True
if fh:
fh.close()
return False
def check_lifecycle(self):
self.send_command(self.Cmd.cmd_emmc_control(function="LIFE-CYCLE-STATUS"),noack=True)
cmd, result = self.get_command_result()
if "Unsupported" in result:
if type(result)!=upfile:
return False
data = self.download(result)
scmd, sresult = self.get_command_result()
@ -503,14 +886,13 @@ class DAXML(metaclass=LogBase):
if sresult == "OK":
tcmd, tresult = self.get_command_result()
if tresult == "START":
if data==b"OK":
if data==b"OK\x00":
return True
else:
return False
return False
def reinit(self, display=False):
self.config.hwparam = hwparam(self.config.meid, self.config.hwparam_path)
"""
self.config.sram, self.config.dram = self.get_ram_info()
self.emmc = self.get_emmc_info(display)
@ -524,6 +906,29 @@ class DAXML(metaclass=LogBase):
self.daconfig.rpmbsize = self.storage.rpmb_size
self.daconfig.boot1size = self.storage.boot1_size
self.daconfig.boot2size = self.storage.boot2_size
class EmmcInfo:
type = 1 # emmc or sdmmc or none
block_size = 0x200
boot1_size = 0
boot2_size = 0
rpmb_size = 0
gp1_size = 0
gp2_size = 0
gp3_size = 0
gp4_size = 0
user_size = 0
cid = b""
fwver = 0
unknown = b""
self.emmc = EmmcInfo()
self.emmc.gp1_size = self.storage.gp1_size
self.emmc.gp2_size = self.storage.gp2_size
self.emmc.gp3_size = self.storage.gp3_size
self.emmc.gp4_size = self.storage.gp4_size
self.emmc.rpmb_size = self.storage.rpmb_size
self.emmc.boot1_size = self.storage.boot1_size
self.emmc.boot2_size = self.storage.boot2_size
elif self.storage.storagetype == "NAND":
self.daconfig.flashtype = "nand"
self.daconfig.flashsize = self.storage.total_size
@ -536,6 +941,22 @@ class DAXML(metaclass=LogBase):
self.daconfig.rpmbsize = self.storage.lua1_size
self.daconfig.boot1size = self.storage.lua1_size
self.daconfig.boot2size = self.storage.lua2_size
self.config.pagesize = 4096
class UfsInfo:
type = 1 # nor, none
block_size = 0
lu1_size = 0
lu2_size = 0
lu3_size = 0
lu4_size = 0
cid = b""
fwver = b""
serial = b""
self.ufs = UfsInfo()
self.ufs.lu1_size = self.storage.lua0_size
self.ufs.lu2_size = self.storage.lua1_size
self.ufs.lu3_size = self.storage.lua2_size
self.ufs.lu4_size = self.storage.lua3_size
"""
self.chipid = self.get_chip_id()
self.daversion = self.get_da_version()
@ -553,3 +974,37 @@ class DAXML(metaclass=LogBase):
self.mtk.port.cdc.set_fast_mode(True)
self.config.set_gui_status(self.config.tr("Connected to stage2 with higher speed"))
"""
def formatflash(self, addr, length, storage=None,
parttype=None, display=False):
self.mtk.daloader.progress.clear()
part_info = self.getstorage(parttype, length)
if not part_info:
return False
storage, parttype, length = part_info
self.info(f"Formatting addr {hex(addr)} with length {hex(length)}, please standby....")
self.mtk.daloader.progress.show_progress("Erasing", 0, length, True)
self.send_command(self.Cmd.cmd_erase_flash(partition=parttype,offset=addr,length=length))
result=self.get_response()
if result=="OK":
self.info(f"Successsfully formatted addr {hex(addr)} with length {length}.")
return True
self.error(f"Error on format.")
return False
def shutdown(self, async_mode: int = 0, dl_bit: int = 0, bootmode: ShutDownModes = ShutDownModes.NORMAL):
if bootmode == ShutDownModes.FASTBOOT:
self.send_command(self.Cmd.cmd_set_boot_mode(mode=BootModes.fastboot))
elif bootmode == ShutDownModes.TEST:
self.send_command(self.Cmd.cmd_set_boot_mode(mode=BootModes.testmode))
elif bootmode == ShutDownModes.META:
self.send_command(self.Cmd.cmd_set_boot_mode(mode=BootModes.meta))
if self.send_command(self.Cmd.cmd_reboot(disconnect=False)):
self.mtk.port.close(reset=True)
return True
else:
self.error(f"Error on sending reboot")
self.mtk.port.close(reset=True)
return False

0
mtkclient/Library/DA/xml/xml_param.py Normal file → Executable file
View file

0
mtkclient/Library/Exploit/__init__.py Normal file → Executable file
View file

0
mtkclient/Library/Exploit/amonet.py Normal file → Executable file
View file

0
mtkclient/Library/Exploit/hashimoto.py Normal file → Executable file
View file

4
mtkclient/Library/Exploit/kamakiri2.py Normal file → Executable file
View file

@ -19,7 +19,9 @@ class Kamakiri2(Exploitation, metaclass=LogBase):
def kamakiri2(self, addr):
self.udev = self.mtk.port.cdc.device
try:
# self.linecode = array('B', [0x80, 0x25, 0, 0, 0, 0, 8, 0])
if self.linecode is None:
#self.linecode = array('B', [0x80, 0x25, 0, 0, 0, 0, 8, 0])
self.linecode = self.mtk.port.cdc.device.ctrl_transfer(0xA1, 0x25, 0, 0, 8) + array.array('B', [0])
# array('B', [128, 37, 0, 0, 0, 0, 8, 0, addr, addr, addr, addr])
self.udev.ctrl_transfer(0x21, 0x20, 0, 0, self.linecode + array.array('B', pack("<I", addr)))
self.udev.ctrl_transfer(0x80, 0x6, 0x02FF, 0, 9)

View file

@ -0,0 +1,97 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# (c) B.Kerler 2018-2023 GPLv3 License
import logging
import array
from binascii import hexlify
from struct import pack, unpack
from mtkclient.Library.exploit_handler import Exploitation
from mtkclient.Library.utils import LogBase, print_progress
from mtkclient.Library.Connection.usblib import usb
class Kamakiri_Pl(Exploitation, metaclass=LogBase):
def __init__(self, mtk, loglevel=logging.INFO):
super().__init__(mtk, loglevel)
self.linecode = None
def initbrom(self):
# bypass1stda
for i in range(5):
getVal = self.mtk.port.cdc.device.ctrl_transfer(bmRequestType=0xa1,
bRequest=0x21,
wValue=0,
wIndex=0,
data_or_wLength=7)
data = pack("<Q", 0x800000001C200)
self.mtk.port.cdc.device.ctrl_transfer(bmRequestType=0x21,
bRequest=0x20,
wValue=0,
wIndex=0,
data_or_wLength=array.array('B',data))
for i in range(2):
self.mtk.port.cdc.device.ctrl_transfer(bmRequestType=0x21,
bRequest=0x22,
wValue=0x3,
wIndex=0,
data_or_wLength=0)
getVal = self.mtk.port.cdc.device.ctrl_transfer(bmRequestType=0xa1,
bRequest=0x21,
wValue=0,
wIndex=0,
data_or_wLength=7)
self.mtk.port.cdc.device.ctrl_transfer(bmRequestType=0x21,
bRequest=0x20,
wValue=0,
wIndex=0,
data_or_wLength=getVal)
self.mtk.port.cdc.device.ctrl_transfer(bmRequestType=0x21,
bRequest=0x23,
wValue=0,
wIndex=0,
data_or_wLength=0)
for i in range(2):
self.mtk.port.cdc.device.ctrl_transfer(bmRequestType=0x21,
bRequest=0x22,
wValue=0x3,
wIndex=0,
data_or_wLength=0)
def bypass2ndDA(self):
usb.util.claim_interface(self.mtk.port.cdc.device, 0)
try:
ret = self.mtk.port.cdc.device.ctrl_transfer(bmRequestType=0x80,
bRequest=0x6,
wValue=0x02FF,
wIndex=0xFFFF,
data_or_wLength=9)
except:
pass
try:
value = self.mtk.port.cdc.device.ctrl_transfer(0xA1, 0x21, 0, 0, 7) + array.array('B', [0])
except:
pass
data = pack("<QI", 0x800000001C200, 0x22C3B0)
try:
self.mtk.port.cdc.device.ctrl_transfer(bmRequestType=0x21,
bRequest=0x20,
wValue=0,
wIndex=0,
data_or_wLength=array.array('B',data))
except:
pass
try:
ret = self.mtk.port.cdc.device.ctrl_transfer(bmRequestType=0x80,
bRequest=0x6,
wValue=0x02FF,
wIndex=0xFFFF,
data_or_wLength=9)
except:
pass

0
mtkclient/Library/Hardware/__init__.py Normal file → Executable file
View file

View file

@ -102,7 +102,7 @@ class hwcrypto(metaclass=LogBase):
elif mode == "mirpmb":
return self.dxcc.generate_rpmb_mitee()
elif mode == "itrustee":
return self.dxcc.generate_itrustee_fbe()
return self.dxcc.generate_itrustee_fbe(appid=data)
elif mode == "prov":
return self.dxcc.generate_provision_key()
elif mode == "sha256":

View file

@ -1085,12 +1085,12 @@ class dxcc(metaclass=LogBase):
res = self.write32(0x10001088, 0x8000000)
return res
def generate_itrustee_fbe(self, key_sz=32):
def generate_itrustee_fbe(self, key_sz=32, appid:bytes=b""):
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
itrustee = b"TrustedCorekeymaster" + b"\x07" * 0x10 + appid
seed = itrustee + pack("<B", ctr)
paddr = self.SBROM_AesCmac(1, 0x0, seed, 0x0, len(seed), dstaddr)
for field in self.read32(paddr, 4):

View file

@ -777,6 +777,17 @@ class sej(metaclass=LogBase):
return dec
def generate_hw_meta(self, otp=None, encrypt=False, data=b""):
"""
WR8 mt65
LR9 CRC RC4 AES128-CBC SBC=OFF
LR11 CRC RC4 AES128-CBC SBC=ON
LR12 CRC AES128-ECB AES128-CBC mt6750/6797
LR12A MD5 AES128-ECB AES128-CBC mt6761/6765/6771/6777/6778/6779
LR13 MD5 AES128-ECB AES128-CBC mt6781/mt6785
NR15 MD5 AES128-ECB AES128-CBC mt6877/6889/6833
NR16 MD5/HMAC-SHA256 AES128-CBC/AES256-CBC AES128-CBC/AES256-CBC mt6895
NR17 MD5/HMAC-SHA256 AES128-CBC/AES256-CBC AES128-CBC/AES256-CBC
"""
if otp is not None:
self.sej_set_otp(otp)
seed = (CustomSeed[2] << 16) | (CustomSeed[1] << 8) | CustomSeed[0] | (CustomSeed[3] << 24)

0
mtkclient/Library/Hardware/seccfg.py Normal file → Executable file
View file

View file

@ -47,6 +47,82 @@ class Port(metaclass=LogBase):
else:
self.__logger.setLevel(logging.INFO)
def run_serial_handshake(self):
EP_OUT = None
try: # Support for serial port where EP_OUT is unknown
if hasattr(self.cdc, 'EP_OUT'):
EP_OUT = self.cdc.EP_OUT.write
maxinsize = self.cdc.EP_IN.wMaxPacketSize
else:
EP_OUT = self.cdc.write
except:
EP_OUT = self.cdc.write
try:
if hasattr(self.cdc, 'EP_IN'):
EP_IN = self.cdc.EP_IN.read
else:
EP_IN = self.cdc.read
except:
EP_IN = self.cdc.read
i = 0
startcmd = b"\xa0\x0a\x50\x05"
length = len(startcmd)
try:
while i < length:
if EP_OUT(int.to_bytes(startcmd[i], 1, 'little')):
v = EP_IN(1, timeout=20) # Do not wait 1 sec, bootloader is only active for 0.3 sec.
if len(v) == 1 and v[0] == ~(startcmd[i]) & 0xFF:
i += 1
else:
i = 0
self.info("Device detected :)")
return True
except Exception as serr:
self.debug(str(serr))
time.sleep(0.005)
return False
def serial_handshake(self, maxtries=None, loop=0):
counter = 0
if not self.cdc.connected:
self.cdc.connected = self.cdc.connect()
while 1: # Workaround for serial port
try:
if maxtries is not None and counter == maxtries:
break
counter += 1
#self.cdc.connected = self.cdc.connect()
if self.cdc.connected and self.run_serial_handshake():
self.info("Handshake successful.")
return True
else:
if loop == 5:
sys.stdout.write('\n')
self.info("Hint:\n\nPower off the phone before connecting.\n" + \
"For brom mode, press and hold vol up, vol dwn, or all hw buttons and " + \
"connect usb.\n" +
"For preloader mode, don't press any hw button and connect usb.\n"
"If it is already connected and on, hold power for 10 seconds to reset.\n")
sys.stdout.write('\n')
if loop >= 10:
sys.stdout.write('.')
if loop >= 20:
sys.stdout.write('\n')
loop = 0
loop += 1
time.sleep(0.1)
sys.stdout.flush()
except Exception as serr:
print("Handshake: " + str(serr))
if "access denied" in str(serr):
self.warning(str(serr))
self.debug(str(serr))
pass
return False
def run_handshake(self):
EP_OUT = self.cdc.EP_OUT.write
EP_IN = self.cdc.EP_IN.read

0
mtkclient/Library/__init__.py Normal file → Executable file
View file

View file

@ -439,7 +439,7 @@ ErrorCodes = {
0x1D00: "ADDRESS_TOO_HIGH_80000000",
0x1D01: "ADDRESS_TOO_HIGH_40000000",
0x1D02: "INVALID_ADDRESS",
0x1D0C: "",
0x1D0C: "NO_AUTH_NEEDED",
0x1D0D: "SLA_ERROR",
0x1D0E: "DA_OVERLAP",
0x1D0F: "DA_INVALID_JUMP_ADDR",
@ -488,6 +488,10 @@ ErrorCodes = {
0x5004: "IMG_LOCK_MAGIC_ERROR",
0x6000: "SBC_KEY_NOT_FOUND",
0x6001: "BR_SEC_CFG_NOT_FOUND",
0x6002: "ERR_PUBK_NOT_INITIALIZED",
0x6003: "SHA256_OP_FAIL",
0x6004: "ERR_PSS_CHK_FAIL",
0x6005: "ERR_SIG_CHK_FAIL",
0x7000: "REGION_INVALID_INCLUDE",
0x7001: "REGION_INVALID_OVERLAP",
0x7002: "REGION_INVALID_OVERFLOW",

0
mtkclient/Library/exploit_handler.py Normal file → Executable file
View file

6
mtkclient/Library/meta.py Normal file → Executable file
View file

@ -60,6 +60,12 @@ class META(metaclass=LogBase):
while resp==b"READY":
resp = bytearray(EP_IN(maxinsize))
if resp in [b"ATEMEVDX",b"TOOBTSAF",b"ATEMATEM",b"TCAFTCAF",b"MYROTCAF"]:
if resp == b"ATEMATEM":
EP_OUT(b"\x04\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\xC0")
EP_OUT(b"\x04\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\xC0")
EP_OUT(b"\x06\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\xC0\x00\x80\x00\x00")
info = EP_IN(13) #!READYATEM
EP_OUT(b"DISCONNECT")
return True
self.warning(resp)
else:

31
mtkclient/Library/mtk_class.py Normal file → Executable file
View file

@ -10,7 +10,7 @@ from mtkclient.Library.pltools import PLTools
from mtkclient.Library.mtk_preloader import Preloader
from mtkclient.Library.DA.mtk_daloader import DAloader
from mtkclient.Library.Port import Port
from mtkclient.Library.utils import LogBase, logsetup
from mtkclient.Library.utils import LogBase, logsetup, find_binary
from mtkclient.Library.error import ErrorHandler
@ -47,18 +47,29 @@ class Mtk(metaclass=LogBase):
("5072656C6F61646572205374617274","50617463686564204C205374617274", "Patched loader msg"),
("F0B58BB002AE20250C460746","002070470000000000205374617274", "sec_img_auth"),
("FFC0F3400008BD","FF4FF0000008BD","get_vfy_policy"),
("040007C0","00000000","hash_check")
("040007C0","00000000","hash_check"),
("CCF20709", "4FF00009", "hash_check2"),
(b"\x14\x2C\xF6.\xFE\xE7",b"\x00\x00\x00\x00\x00\x00","hash_check3")
]
i = 0
for patchval in patches:
pattern = bytes.fromhex(patchval[0])
idx = data.find(pattern)
if idx != -1:
patch = bytes.fromhex(patchval[1])
data[idx:idx + len(patch)] = patch
self.info(f"Patched \"{patchval[2]}\" in preloader")
patched = True
# break
if type(patchval[0])==bytes:
idx = find_binary(data,patchval[0])
if idx is None:
idx = -1
else:
data[idx:idx + len(patch)] = patch
self.info(f"Patched \"{patchval[2]}\" in preloader")
patched = True
else:
pattern = bytes.fromhex(patchval[0])
idx = data.find(pattern)
if idx != -1:
patch = bytes.fromhex(patchval[1])
data[idx:idx + len(patch)] = patch
self.info(f"Patched \"{patchval[2]}\" in preloader")
patched = True
# break
i += 1
if not patched:
self.warning(f"Failed to patch preloader security")

17
mtkclient/Library/mtk_main.py Normal file → Executable file
View file

@ -57,6 +57,11 @@ class ArgHandler(metaclass=LogBase):
config.payloadfile = args.payload
except:
pass
try:
if args.appid is not None:
config.appid = bytes.fromhex(args.appid)
except:
pass
try:
if args.loader is not None:
config.loader = args.loader
@ -354,6 +359,16 @@ class Main(metaclass=LogBase):
config.iot = iot
except:
pass
try:
auth = self.args.auth
config.auth = auth
except:
pass
try:
cert = self.args.cert
config.cert = cert
except:
pass
mtk = Mtk(config=config, loglevel=loglevel, serialportname=serialport)
config.set_peek(mtk.daloader.peek)
if mtk.config.debugmode:
@ -415,6 +430,8 @@ class Main(metaclass=LogBase):
self.warning("We couldn't enter preloader.")
plt = PLTools(rmtk, self.__logger.level)
data, filename = plt.run_dump_preloader(self.args.ptype)
if filename is None:
filename = "preloader.bin"
if data is not None:
if filename == "":
if self.args.filename is not None:

View file

@ -3,9 +3,14 @@
# (c) B.Kerler 2018-2023 GPLv3 License
import os
import logging
import time
from enum import Enum
from struct import unpack, pack
from binascii import hexlify
from Cryptodome.Util.number import bytes_to_long, long_to_bytes, ceil_div, size
from Cryptodome.PublicKey import RSA
from mtkclient.Library.utils import LogBase, logsetup
from mtkclient.Library.error import ErrorHandler
@ -17,6 +22,27 @@ USBDL_MAGIC = 0x444C0000 # Brom will check this magic number
MISC_LOCK_KEY_MAGIC = 0xAD98
def customizedSign(n, e, msg):
modBits = size(n)
k = ceil_div(modBits, 8)
ps = b'\xFF' * (k - len(msg) - 3)
em = b'\x00\x01' + ps + b'\x00' + msg
em_int = bytes_to_long(em)
m_int = pow(em_int, e, n)
signature = long_to_bytes(m_int, k)
return signature
def generate_rsa_challenge(n,e,data):
for i in range(0,len(data),2):
data[i],data[i+1]=data[i+1],data[i]
msg=bytearray(customizedSign(n,e,data))
for i in range(0,len(msg),2):
msg[i],msg[i+1]=msg[i+1],msg[i]
return msg
def calc_xflash_checksum(data):
checksum = 0
pos = 0
@ -78,7 +104,7 @@ class Preloader(metaclass=LogBase):
PWR_DEINIT = b"\xC5"
PWR_READ16 = b"\xC6"
PWR_WRITE16 = b"\xC7"
CMD_C8 = b"\xC8" # RE
CMD_C8 = b"\xC8" # Cache control
READ16 = b"\xD0"
READ32 = b"\xD1"
@ -97,17 +123,18 @@ class Preloader(metaclass=LogBase):
JUMP_DA64 = b"\xDE", # RE
GET_BROM_LOG_NEW = b"\xDF", # RE
SEND_CERT = b"\xE0",
SEND_CERT = b"\xE0", # DA_CHK_PC_SEC_INFO_CMD
GET_ME_ID = b"\xE1"
SEND_AUTH = b"\xE2"
SLA = b"\xE3"
CMD_E4 = b"\xE4"
CMD_E5 = b"\xE5"
CMD_E6 = b"\xE6"
CMD_E4 = b"\xE4" # returns 0x703A
CMD_E5 = b"\xE5" # echo cmd, dword = dword, then returns 0x7054 as status
CMD_E6 = b"\xE6" # returns 0x7054
GET_SOC_ID = b"\xE7"
CMD_E8 = b"\xE8" # return 0x100A00 cert content and check similar to SLA
ZEROIZATION = b"\xF0"
GET_PL_CAP = b"\xFB"
CMD_FA = b"\xFA"
GET_HW_SW_VER = b"\xFC"
GET_HW_CODE = b"\xFD"
GET_BL_VER = b"\xFE"
@ -141,23 +168,23 @@ class Preloader(metaclass=LogBase):
readsocid = self.config.readsocid
skipwdt = self.config.skipwdt
if not display:
self.info("Status: Waiting for PreLoader VCOM, please reconnect mobile to brom mode")
self.config.set_gui_status(self.config.tr("Status: Waiting for connection"))
else:
self.info("Status: Waiting for PreLoader VCOM, please connect mobile")
self.config.set_gui_status(self.config.tr("Status: Waiting for connection"))
self.info("Status: Waiting for PreLoader VCOM, please reconnect mobile to brom mode")
self.config.set_gui_status(self.config.tr("Status: Waiting for connection"))
res = False
maxtries = 100
tries = 0
while not res and tries < 10:
res = self.mtk.port.handshake(maxtries=maxtries)
while not res and tries < 1000:
if self.mtk.serialportname:
res = self.mtk.port.serial_handshake(maxtries=maxtries)
else:
res = self.mtk.port.handshake(maxtries=maxtries)
if not res:
if display:
self.error("Status: Handshake failed, retrying...")
self.config.set_gui_status(self.config.tr("Status: Handshake failed, retrying..."))
self.mtk.port.close()
tries += 1
if tries == 10:
if tries == 1000:
return False
if self.config.iot:
@ -194,7 +221,7 @@ class Preloader(metaclass=LogBase):
if not skipwdt:
if self.display:
self.info("Disabling Watchdog...")
self.setreg_disablewatchdogtimer(self.config.hwcode) # D4
self.setreg_disablewatchdogtimer(self.config.hwcode, self.config.hwver) # D4
if self.display:
self.info("HW code:\t\t\t" + hex(self.config.hwcode))
self.config.target_config = self.get_target_config(self.display)
@ -226,6 +253,20 @@ class Preloader(metaclass=LogBase):
if self.display:
if socid != b"":
self.info("SOC_ID:\t\t\t" + hexlify(socid).decode('utf-8').upper())
if self.config.auth is not None and self.config.is_brom and self.config.target_config["daa"]:
if os.path.exists(self.config.auth):
authdata = open(self.config.auth,"rb").read()
self.send_auth(authdata)
else:
self.error(f"Couldn't find auth file {self.config.auth}")
if self.config.cert is not None and self.config.is_brom and self.config.target_config["daa"]:
if os.path.exists(self.config.cert):
certdata = open(self.config.cert,"rb").read()
self.send_root_cert(certdata)
else:
self.error(f"Couldn't find cert file {self.config.cert}")
if self.config.target_config["sla"]:
self.handle_sla(func=None,isbrom=self.config.is_brom)
return True
def read_a2(self, addr, dwords=1) -> list:
@ -377,51 +418,74 @@ class Preloader(metaclass=LogBase):
# self.usbwrite(data)
self.usbwrite(pack(">I", checksum))
def setreg_disablewatchdogtimer(self, hwcode):
def setreg_disablewatchdogtimer(self, hwcode, hwver):
"""
SetReg_DisableWatchDogTimer; BRom_WriteCmd32(): Reg 0x10007000[1]={ Value 0x22000000 }.
"""
addr, value = self.config.get_watchdog_addr()
if hwcode == 0x6261:
# SetLongPressPWKEY
self.read32(0xA01C0108)
self.write16(0xA0700F00, 0x41)
self.write16(0xA0700F00, 0x51)
self.write16(0xA0700F00, 0x41)
# SetReg_DisableChargeControl()
self.write16(0xA0700A28, self.read16(0xA0700A28) | 0x4000)
self.write16(0xA0700A00, self.read16(0xA0700A00, 1) | 0x10)
self.write16(0xA0030000, 0x2200)
# SetReg_LockPowerKey
self.read16(0xA0710000, 1)
# PowerKeysMatched
self.read16(0xA0710050, 1)
self.read16(0xA0710054, 1)
self.write16(0xA0710010, 0)
self.write16(0xA0710008, 0)
self.write16(0xA071000C, 0)
# Disable watchdog timer
# MT2503
if hwver == 0xca02:
# PMU
#self.write16(0xA0700F00, 0x41)
#self.write16(0xA0700F00, 0x51)
#self.write16(0xA0700F00, 0x41)
# Unlock
self.write16(0xA0710074, 1)
val2 = self.read16(0xA0710000, 1)
self.write16(0xA0710050, 0xA357)
self.write16(0xA0710054, 0x67D2)
self.read16(0xA0710074, 1)
val2 = self.read16(0xA0710000, 1)
self.write16(0xA0710068, 0x586A)
self.write16(0xA0710074, 1)
self.read16(0xA0710000, 1)
self.write16(0xA0710068, 0x9136)
self.write16(0xA0710074, 1)
self.read16(0xA0710000, 1)
self.write16(0xA0710074, 1)
self.read16(0xA0710000, 1)
# Get Target Config : D8
# GPIO
#self.write32(0xA0020318,0x2000) # GPIO_DOUT1_SET, GPIO45
#self.write32(0xA0020014, 0x2000) # GPIO_DIR1_SET, GPIO45
#self.write32(0xA0020C58, 0x700000) # GPIO_MODE5_CLR, GPIO45 TESTMODE_D
# SetRemap:
self.write32(0xA0510000, self.read32(0xA0510000, 1) | 2)
self.write32(0xA0510000, self.read32(0xA0510000, 1) | 2)
# PMU
# SetReg_MinuteLevelChargerWDT
#self.write16(0xA0700A24, 0x15)
# SetReg_DisableBAT_ON_Protection
#self.write16(0xA0700A14, 0x6001)
# SetReg_OV_Level
#self.write16(0xA0700A14, 0x6041)
# SetReg_USBDL_ChargerCurrent
#self.write16(0xA0700A08, 0x10B)
# SetReg_EnableChargeControlToNormalMode
#self.write16(0xA0700A00, 0xF27A)
# SetReg_HWAutoFChargeModeToNormalMode
#self.write16(0xA0700A28, 0x8010)
# Disable watchdog
self.write16(0xA0030000, 0x2200)
# SetLSRSTB
#self.write16(0xA0020318, 0x2000)
#self.write16(0xA0020014, 0x2000)
#self.write32(0xA0020C58, 0x700000)
# SetupRTC32K
#self.write16(0xA071004C, 0x1A57)
#self.write16(0xA071004C, 0x2B68)
#self.write16(0xA071004C, 0x407)
#self.write16(0xA0710010, 0x0)
#self.write16(0xA0710008, 0x0)
#self.write16(0xA071000C, 0x0)
#self.write16(0xA0710074, 0x1)
# RTC Unlock
#self.write16(0xA0710068, 0x586A)
#self.write16(0xA0710074, 1)
#self.write16(0xA0710068, 0x9136)
#self.write16(0xA0710074, 1)
#self.write16(0xA0710000, 0x430E)
#self.write16(0xA0710074, 0x1)
# SetRemap:
# BootEngine
# set external boot , remap control change to Bus
# Set MB0 to Bank0 and MB1 to Bank1
self.write32(0xA0510000, self.read32(0xA0510000, 1) | 2)
else:
self.write16(0xA0030000, 0x2200)
res = True
elif hwcode in [0x6575, 0x6577]:
@ -510,20 +574,15 @@ class Preloader(metaclass=LogBase):
try:
status = self.rword()
except Exception as e:
self.error(f"Jump_DA Resp2 {str(e)} ," + hexlify(data).decode('utf-8'))
self.error(f"Jump_DA No data available {str(e)} ," + hexlify(data).decode('utf-8'))
self.config.set_gui_status(self.config.tr("DA Error"))
return False
if status == 0:
self.info(f"Jumping to {hex(addr)}: ok.")
self.config.set_gui_status(self.config.tr(f"Jumping to {hex(addr)}: ok."))
return True
else:
self.error(f"Jump_DA status error:{self.eh.status(status)}")
self.config.set_gui_status(self.config.tr("DA Error"))
else:
self.error(f"Jump_DA status error:{self.eh.status(addr)}")
self.config.set_gui_status(self.config.tr("DA Error"))
self.error(f"Jump_DA status error:{self.eh.status(status)}")
self.config.set_gui_status(self.config.tr("DA Error"))
return False
def jump_da64(self, addr: int):
@ -580,18 +639,344 @@ class Preloader(metaclass=LogBase):
return False
def send_auth(self, auth):
gen_chksum, data = self.prepare_data(auth)
if self.echo(self.Cmd.SEND_AUTH):
self.usbwrite(len(data))
gen_chksum, data = self.prepare_data(data=auth,sigdata=b"",maxsize=len(auth))
if self.echo(self.Cmd.SEND_AUTH.value):
length = len(data)
self.usbwrite(int.to_bytes(length,4,'big'))
rlen = self.rdword()
if rlen != length:
return False
self.config.set_gui_status(self.config.tr(f"Uploading data."))
status = self.rword()
if 0x0 <= status <= 0xFF:
if not self.upload_data(data, gen_chksum):
self.error("Error on uploading auth.")
return False
return True
self.error(f"Send auth error:{self.eh.status(status)}")
if status < 0xFF:
bytestowrite = len(data)
pos = 0
while bytestowrite > 0:
size = min(bytestowrite, 64)
self.usbwrite(data[pos:pos + size])
bytestowrite -= size
pos += size
self.usbwrite(b"")
time.sleep(0.035)
status = self.rword()
if 0x0 <= status <= 0xFF:
return True
if status==0x1D0C:
self.info("No auth needed.")
else:
self.error(f"Send auth error:{self.eh.status(status)}")
return False
def handle_sla(self, func=None, isbrom:bool=True):
rsakeys = [
# libsla_challenge.so, secure_chip_tools/keys/toolauth/sla_prvk.pem V5
(bytes_to_long(bytes.fromhex("010001")),
bytes_to_long(bytes.fromhex(
"C43469A95B143CDC63CE318FE32BAD35B9554A136244FA74D13947425A32949EE6DC808CDEBF4121687A570B83C51E657303C925EC280B420C757E5A63AD3EC6980AAD5B6CA6D1BBDC50DB793D2FDDC0D0361C06163CFF9757C07F96559A2186322F7ABF1FFC7765F396673A48A4E8E3296427BC5510D0F97F54E5CA1BD7A93ADE3F6A625056426BDFE77B3B502C68A18F08B470DA23B0A2FAE13B8D4DB3746255371F43306582C74794D1491E97FDE504F0B1ECAC9DDEF282D674B817B7FFA8522672CF6281790910378FEBFA7DC6C2B0AF9DA03A58509D60AA1AD6F9BFDC84537CD0959B8735FE0BB9B471104B458A38DF846366926993097222F90628528F")),
bytes_to_long(bytes.fromhex(
"8E02CDB389BBC52D5383EBB5949C895B0850E633CF7DD3B5F7B5B8911B0DDF2A80387B46FAF67D22BC2748978A0183B5B420BA579B6D847082EA0BD14AB21B6CCCA175C66586FCE93756C2F426C85D7DF07629A47236265D1963B8354CB229AFA2E560B7B3641DDB8A0A839ED8F39BA8C7CDB94104650E8C7790305E2FF6D18206F49B7290B1ADB7B4C523E10EBF53630D438EF49C877402EA3C1BD6DD903892FD662FBDF1DFF5D7B095712E58E728BD7F6A8B5621175F4C08EBD6143CDACD65D9284DFFECAB64F70FD63182E4981551522727A2EE9873D0DB78180C26553AD0EE1CAAA21BCEBC5A8C0B331FE7FD8710F905A7456AF675A04AF1118CE71E36C9"))),
# bootloader/preloader/platform/mt6781/flash/custom/oemkey.h V6
(bytes_to_long(bytes.fromhex("010001")),
bytes_to_long(bytes.fromhex(
"B243F6694336D527C5B3ED569DDD0386D309C6592841E4C033DCB461EEA7B6F8535FC4939E403060646A970DD81DE367CF003848146F19D259F50A385015AF6309EAA71BFED6B098C7A24D4871B4B82AAD7DC6E2856C301BE7CDB46DC10795C0D30A68DD8432B5EE5DA42BA22124796512FCA21D811D50B34C2F672E25BCC2594D9C012B34D473EE222D1E56B90E7D697CEA97E8DD4CCC6BED5FDAECE1A43F96495335F322CCE32612DAB462B024281841F553FF7FF33E0103A7904037F8FE5D9BE293ACD7485CDB50957DB11CA6DB28AF6393C3E78D9FBCD4567DEBCA2601622F0F2EB19DA9192372F9EA3B28B1079409C0A09E3D51D64A4C4CE026FAD24CD7")),
bytes_to_long(bytes.fromhex(
"607C8892D0DE8CE0CA116914C8BD277B821E784D298D00D3473EDE236399435F8541009525C2786CB3ED3D7530D47C9163692B0D588209E7E0E8D06F4A69725498B979599DC576303B5D8D96F874687A310D32E8C86E965B844BC2ACE51DC5E06859EA087BD536C39DCB8E1262FDEAF6DA20035F14D3592AB2C1B58734C5C62AC86FE44F98C602BABAB60A6C8D09A199D2170E373D9B9A5D9B6DE852E859DEB1BDF33034DCD91EC4EEBFDDBECA88E29724391BB928F40EFD945299DFFC4595BB8D45F426AC15EC8B1C68A19EB51BEB2CC6611072AE5637DF0ABA89ED1E9CB8C9AC1EB05B1F01734DB303C23BE1869C9013561B9F6EA65BD2516DE950F08B2E81"))),
# lk/files/pbp/keys/toolauth/sla_prvk.pem, rowan
(bytes_to_long(bytes.fromhex("010001")),
bytes_to_long(bytes.fromhex(
"D16403466C530EF9BB53C1E8A96A61A4E332E17DC0F55BB46D207AC305BAE9354EAAC2CB3077B33740D275036B822DB268200DE17DA3DB7266B27686B8970B85737050F084F8D576904E74CD6C53B31F0BB0CD60686BF67C60DA0EC20F563EEA715CEBDBF76D1C5C10E982AB2955D833DE553C9CDAFD7EA2388C02823CFE7DD9AC83FA2A8EB0685ABDAB56A92DF1A7805E8AC0BD10C0F3DCB1770A9E6BBC3418C5F84A48B7CB2316B2C8F64972F391B116A58C9395A9CE9E743569A367086D7771D39FEC8EBBBA3DD2B519785A76A9F589D36D637AF884543FD65BAC75BE823C0C50AA16D58187B97223625C54C66B5A5E4DBAEAB7BE89A4E340A2E241B09B2F")),
bytes_to_long(bytes.fromhex(
"09976537029b4362591c5b13873f223de5525d55df52dde283e52afa67f6c9dbf1408d2fb586a624efc93426f5f3be981f80e861ddd975a1e5e662db84f5164804a3ae717605d7f15866df9ed1497c38fdd6197243163ef22f958d7b822c57317203e9a1e7d18dad01f15054facdbddb9261a1272638da661fe4f9f0714ecf00e6541cc435afb1fd75a27d34b17ad400e9474ba850dafce266799caff32a058ff71e4c2daacaf8ba709e9ca4dc87584a7ffe8aa9a0a160ed069c3970b7dae3987ded71bd0bc824356987bd74363d46682c71913c3edbdb2a911f701f23aee3f8dd98180b5a138fd5ad74743682d2d2d1bb3d92786710248f316dd8391178ea81"))),
# Alcatel/TCL MTK_U91
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"9a97c44b0768424b6bbb0b6aa987a2d373448c6fee1f61fb81f8cf53d70856f0f77e76c06a6901de90ed3b4d9ad4b9e04eaed42e5657bf2fccf390fe9f5abe1abe8575f07916da69acef95d38874223ec51cb501148a1feea2be2b8ccda08672aa423a4099203c6aa4777fed7353c57696b8e0d4020bd6930b828b9846a454cd")),
bytes_to_long(bytes.fromhex(
"8553e31d7a73f6c9294e961815c23f31f2b5ea1116e3c613ae12b26cf285e4c5ca0e2dc8e17d52f96b30cef6ad544e43205933f20ad17eb8712097aaa23116c68eb6328980b8ba26706105656fa65315688b8232758607b8936d0abc27dbc97d94e95b4f1957fd1965082e5849c4185ebba8afc7d558d4f5f001ac5363423ac1"))
),
# Alcatel/TCL MTK_OTMINI
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"bc7b5107bcf46c2cd7758f4bd4d4e9f06b731d9cff383dffe48156d1ad91ff74a7925fa3027669766b3d4c6e28c1c9310194c34a59e672c8ced38588e998d7b162889dcf06668345f93e4efca34b5fee5bb57dfc38d7623a48f31b382de2db656ec1f3b5267a9a8f5e441c61448a283e4717ace6983d01b163e34f959c9972cd")),
bytes_to_long(bytes.fromhex(
"6bc0e84b4f38415bc575dd0d5248c2d182ec55e2ba7a11dfe86815155c709a25bbe34fafa6a9c19344adcfb32eb3d2eca465c2dc0fd7528a00cc268c6657cdff0b0da1b2ac6a95b94865facb7e1494cedf44358e29ec7e8f091172e4ef29856d1f45032aa644efc273f141c10cb8281a12cebe202b65f176e1a145c326d75841"))
),
# Alcatel/TCL ST513
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"df836c16bc8e129dac8e6efcd3f41636981687c29c465b481cbe874ffb14d592de024b70f4fa20ad96c96e4e3eded3625f314dedb4d8635782f6d668d04ab1167982229e03ede17a7857a22cbf72444a6bee2bba54f32099e0eabe654c3da4933926db4d97dcaeb68236df4b3e51bd3c4bfa8b2d47c2534405e4f1c1d43e1069")),
bytes_to_long(bytes.fromhex(
"9ea0f7256bcca9099e5db80757a5f3ddeb3292475c01d2e6eaff8da905d9537a5875e874d26872a8c04b552dd310f194ef5a5ea445a50d5c1e6670e5126ef01e5fb1af24a67d07b5a9f72197bc66d5743faab54759fbedcf1fd8ac1aabede2c6fb29601b4734334db92a92fc25f7ed8700d307b74a2c435c9ce5b5caba4b3801"))
),
# Alcatel/TCL MPK_U7
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"db0b6e89fabdc24e6e7379d25b0c402686537ab6375d8b2407beaf44cbbef27e04e90b556801bbce5eee2a7ec636ac825667dae3578eb7bbb66701bc62ee86f28fc14d57e8637a2ddcee00cc3ab87dff4155250c2dbde9ae62f3d7a9d5e4a265fb0a8b23c082be263d7788e44d59780b47a31b25dc588f81902be419f917933b")),
bytes_to_long(bytes.fromhex(
"c5829b5bc34253f090db831f5085cd5a6f88da7f6f90e3a3cb6fff6e53218c5a616719971b3f64ef02de526719a7b709978bf1ed48c821981b32ea77c9e536bbda206fad74946d02a20d17120f89419b0daee2d8a47275768930ad53c876afebffb6805483c1ddcf6c19f3566f0de494838afb51b18080beff66364de5294581"))
),
# Alcatel/TCL MTK_U8
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"9bc517a0dfa87a7e240000c5f42cf31905ab93d4bcb95694dee85282867d5c83270aea0b0948d66eb39d8500aa6c8b1069b8ee784f75948958f7bbf627d6ed5f286fd3bd4df60a6c9490cb319448b22765aba9329820eec50f62f1ca0b6b3322aa27747b26855a1f1719cf0c4060c9f5a6a3a60ec60fe6e04e7b044e5da994e9")),
bytes_to_long(bytes.fromhex(
"76ca90a16bcf7552db2b716b8531fe5617bfe86635627647e3d27291fdf47e67ba8f953ac362dbbce2977f05a9f24aff4250f8f3a14d3ef09b7b99c9384aad0c53104f87b47d7daea3ca725beb233d127ec342ce0619b16bd3d5e44371cffce9f23178ff48dd42fc4450ccdb3e2d63437ef9dfc0296b12840ae85d472cf0135d"))
),
# Alcatel/TCL MPK_U91
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"9a97c44b0768424b6bbb0b6aa987a2d373448c6fee1f61fb81f8cf53d70856f0f77e76c06a6901de90ed3b4d9ad4b9e04eaed42e5657bf2fccf390fe9f5abe1abe8575f07916da69acef95d38874223ec51cb501148a1feea2be2b8ccda08672aa423a4099203c6aa4777fed7353c57696b8e0d4020bd6930b828b9846a454cd")),
bytes_to_long(bytes.fromhex(
"8553e31d7a73f6c9294e961815c23f31f2b5ea1116e3c613ae12b26cf285e4c5ca0e2dc8e17d52f96b30cef6ad544e43205933f20ad17eb8712097aaa23116c68eb6328980b8ba26706105656fa65315688b8232758607b8936d0abc27dbc97d94e95b4f1957fd1965082e5849c4185ebba8afc7d558d4f5f001ac5363423ac1"))
),
# Alcatel/TCL MTK_6577_HUIZHOU
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"ac2a2c19bf4beef4272df8899cb648f90453e53faa1dd8143327978620ec74e6068a8fd051fac856a59ff0a2f3051b7512f55fcd6eea57262a5a24e141b2a9c105509b79976b952a4cfa0367535aa1db83290f18f62e2f604bfd5fee3fb6fa863ca5546e359e0348937e5b62e47f645e9552ebd2e7e516c13a192a6075c55351192dd545dd90c34fa28c695d6643a2449c0c7acc9d003b9bb4f9d249bc19beb8ffdc2d6115260499156461eea896361aac9a24ace3bf6c81db3e8c32fd6d74d876882382618c7ae920ce63b0c33a3ed6a59642acdcdccd68f2e84f6b1dfe8e4dd33fd78208c750f877a8eddbf32b7f6cd28bc7f62a79e1281cad49b29ea1aeeb")),
bytes_to_long(bytes.fromhex(
"3d6ff33ae0ec1d029db4a6fb9ca3e41890f5cb5a53bfc0ab3cb2053d85243c7715a07ebfad719bea67c252a223ad0fe65074a5d26ea14ba63ff8d92e553e879b6ce51e065f05b23e5d27deed116ec751c9556ea0cec11e80f3bd206da9e9072fbe1695b19a8a9fcb576f00f7a268df8d6d262127ab3f3246941004f25534ac8d2f418815d15f4a5a663a2f1383115cb3e8bd263ebcd92c5bd1b92644497e15a1b41e77e648cac179182d83c496728fb52b9a1c600954ad0c3eac5d4633d519c88daf775fe090c2f2568c7c91a8938a2859245f100fce764033147d84d79075a81331ecdd170d2541832ab9161dc473cadc1dfbc17df2be89fa6d6c13d9db3611"))
),
# Alcatel/TCL MTK_S_2019
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"e4607e6cf78f5e4857bdaea441f8ddd35a7576f552b4ad2c8b4ee7f578c0590d747b049bb5014e06f8350dc6b78d5e0ddff1b4bb8af695e4a338a154596555738cccbe6b58eb43ae221df9babfe9dda6ca770c25ab42ff986f946756b46ec553daf7616f2843dcd6a48f48d9011c050e7ed11c99f61624f057695d622088f868bf6a3966f25bd8ad58db81623fd63f2b91f3ded1a5be0efb69a64bb40d8bbfc251d9c32fbf0a1bad516751e9e04439392c59ba6f856b5c0bebe0dcc67d7d4f25da5342aba94680583ed76d94823c6f62e5e7484f7e2d2a467d167ad3f5647f958dbba3eb66f756c851a55138d1ce465333592969470fa8652df2e38bc380ff4f")),
bytes_to_long(bytes.fromhex(
"68d01875ee507057075dd8cf2e3007aebeaf767f350c130684911c483eb918a5e235ab71c2eaec62aa7bbeecdac518cb8962272e83a2943cb0e486b66da8e244fbf3e3d8e4a065198032fdb045f011784127cdfd63d285f7f20dcc37b0ebbdc8b49020b9a16333f196e8e3e8246835b1e76615985ba6e221241d096cc5bdd7336d8b22704dc1576ae0ac252fea8dab129756a609f347d60e25d8d085cf0c8775631d3c0e54e50fc67dff2c55148b4e78cf36987febb23e14ffc1da9cb0adfc139d509826aa98f6fe0e25ec6ab6442e5a7cebbe6454ff06b897467512cdd8f0460201125d0bc9cc2bae259840722ae56d16b06f9e0515a2d128a23b5b0a1896e1"))
),
# Alcatel/TCL MTK_6577_SHENZHEN
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"a29274e3085c260de63f571646cd2c69737ba5a0bf604ad31cf6a86d6a9e08dc931ecdddb7404f4c9255c72b5debdb69114146bdd7edf6b38505b19c4d18eb0e71516d4faa871cbe1d2e24e15c1877b33587a8bdd1e7dfe1b17235d1ac431c27cae07804014c287fbf2479e6b4b80665898f7cbaa7edcf23daa8dd95f63039fe7eb641ad7c05e221d29adc62cf84893ffc6acfd44a9d2cd60d5e0f94d1c29d317bbddb3f5a324648069c72857cfc708fc9bd8a3f7a98051fa9835af1f9c71d80236334ea51cbd52e57e5a7950beb394d9c97bcc32591d9700106b0abfe1dd2db9617fb7dd2eaa3885630c3ce1dfcf087c814b480f30c411f3071f12aedee4077")),
bytes_to_long(bytes.fromhex(
"6d209285b39ee78c7cfa17a34473855463c8a42d7b494ff0d6885c16d672aed0219193ef388b5aafb3ab10bef394d6fb7831b122ce47564abb084f68f3f7be113bcfc4e8ad3774fbc8eaa8a6fe030e96a56022cd0891f59eb2564ffa2700056e50a8cce72357d3f7ac7ef7b4fdaa69e0ceae1ab3d0f5b90e00414a3cd7bd17afc3b6463ef43bfd22788b68fcfcc2964421b1b622907d8c75e8d83193a579e50c26b0beb93e53e2888cfddafefa03c368c68e6d357087f1bf0800e1bb4f0fc97c092a7e7098cb60cad71e292b506c0cd1f428aff3192da6818351a780aa1b4cce0dccd15adad815b610f445a6571d3c65d2c44da9057b5c8970cded0dfc3072c1"))
),
# Alcatel/TCL MTK_S_2022
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"af823063550d6e5adcca01a1ae1fe357f73d7e5c60cfa25e4beac24304b70623654fd13547de869899be532f45f3c5ff26b50292dccd112dda1478721c05304445058499bd00f6b104e16fcf2d0af55781be147787227eff54a25dca42b9d6f1fc8f4b821c099f483c402addd178330167aa9b1021dae121bb2bdcb0127ac47ae866a1579f2399c70e69293ddd3b0bacec2df9dc518aa0c58c2d7561c5783ac32e57b91d16d6c57764755894963733b85f19f9a3bcbf624199cdd1b31cbecc5448b132c3799e2d0e569f0ba61245796db5876820ef125f4a230039c5cd16b2414855bf3a3b565f81787a4e9b264c9bc855b4fe7ac17caca1bc5f070594a9c175")),
bytes_to_long(bytes.fromhex(
"3be4c4d89124e53d12cdc922c0c6571224e8925fba160186068855c5032de6655be49233899432008faef8ba5037f1a0b237e169f6f9f05be2694bf53d04b44507fceb1480007d2f49c8191ced7528e6b4fb06070851c85f2025ccb60271631def9f831822b351ed17ca9a165aae97516a6c3940971d17e927f3befb43432c1b689cc660a896237f090d7b311d9e39aa1eee5a4e3af00843c965c30ca9aa5dd7767809d27d4f66777661779d2a1fb90b014329a1973e67b8989de924e8ac98673667e4f734382f87f0dd0300d360142afa772d5beca2ef248e90a7bd32240c4a5b5f41aed3f4b63f90642f138186fe17afd713a3242eea7b2dd0f32b06b67681"))
),
# Alcatel/TCL MTK_B3G
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"cf8243d13128ed39fadad9ca97c15585d634f4d9b38dd59e4eec4b0b93e4eb2fd2d96c425855e69706d5c11021a8c2e08bff87b424bed2dc3efa9360bf1bcf80c96cd4ba9c39eb79bfa2bf9d4efc5a56798ccd9c6599ede595aea644086605fbe55b2f7719fccbafe0c95956fcffb0ce77a9637c9ed66e067165cbe901eb041b")),
bytes_to_long(bytes.fromhex(
"12ff6a160cda225ddc898cc6ef7dd3c69d05dc24d23b7a0334568dc85191f3b63d278ab1c8449507dea8533496e04c77225a12a27b7abcf34d10c3cd67b1b41d7c19c44114e344a74396541d998d7b76ca06d0322bf3333684652528df22021c190bc38acdac2a3be6e2d0bce7f1e3c77a71750ff17895cff9c6225275a3ce81"))
),
# Alcatel/TCL MTK_E8
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"bdef438901dfa726cfc2cca59d12f009108b8e1fd7dd9b91a5cc71fa7b1e36c8783f9de5850050e6505fc715c50bddd59a3064b05214c4365360cb98d080cc38658a94695184b564e8e8dcc28f70eb0122a4bb7662e3a1f34c057ea523819ed02ed46bae0cd9530b0536cbe7a1ba3f33a45feb2f92ff5104dc32ebe94f249eed")),
bytes_to_long(bytes.fromhex(
"95b32d61a10e6c2a54fa4e5e020d590f6bf0f295fa87fa03b3d00dcdc4982dc997ad5c7ff872255141ec1b77f714c14587ffb87c985531c937b245062ee03514aa796ad79698c40c49a8b3c54ec66fc20deb874a8bbce87239c414f541367a350d525fa6bdea77e4cd3078cf7ddf22a8aefb0c595a6c76285d837008c0a77e29"))
),
# Alcatel/TCL MTK_C3G
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"c04e6a1be49c5a57accaebc837099b40890180fc046c3dca58745749d0979cadb63b8b4573fafc129c2f89ebb64c4ec81339e862f5638ae145e2c8bc291097e6b90434ff3f3a1e620fa77dcb6d963f53b79abaf4eefb8a5d4378cdf4ab3060a9901909fd455cf850ae5adbdf035cb3cbcf572ac4dce4bc1321562273a461ddf1")),
bytes_to_long(bytes.fromhex(
"4375be875664fad432cb6476f1c7aeecaea3166a51eadeaa32e96d0d79dd159b6287f4cd42685330fc15391eb4ee83dc6fd22a913c5fd5023d8fd6b71af8b530209b5355acf1cc6e6397aa6e5d2dc92b7d37635d391cd22a3aa337d8fc0a274cdd7d6630395d13517e32c91daab2f5378ed7a1be86c81c2e775c249201f2c221"))
),
# Alcatel/TCL MTK_K6
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"a7e3089840bb7a9a7a972e8c88d7c464fe40dc4771a2df0da981079cc800f5d3cd45ed9eb34efac6bf7d2aa6dbc1266285f50d7e86e6e0e5dc6d062bc8fe871672139904e5ffe64c6ffb4ff00817ffc0ad4c18787a253ba5f7f7bd8412e5f46e2c264cedf174ed5163943331a658b434c59ec9e11b269e829ab638c80c4ebe51")),
bytes_to_long(bytes.fromhex(
"4f65cda0c3ac66753c58d748db46bfb8cb8dbd1f849c7444afcf37dc6bb218904c5a2fe08808680d2a6e7587681256a6ed9751046fa42ce44874bf2061f40dca4953c345c2f156e8ee7e2f497ebc59b3ddccda98584dfc999d213d6782f2b0faff59a9671cee801defeb5a51178a7b95c487aa735b463e8b1321b6ebe58c7401"))
),
# Alcatel/TCL OPK_VLE5
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"cb676a5de86e2c7d75a17f10fb2e3f81a473e5d2d088833d8c1928ce78caf1000aaa607c83f55b57dc07fac7a9ecad1600df5d033986c02c003884620661a9674042a835b99cf8a024c27a10410eb379ac69e72d6f5a9cf72c185262331c98879cbc225de835d864983d2bd085f1df99341d3cbb0ba3b0a50491c8ee98d691b5")),
bytes_to_long(bytes.fromhex(
"4befe0eb0c424d83cd2dacb59740cddec599ab3c8833dee354717425993d12ba5441056297153bb3d2667c3e9c76caabc349a07cfab60efa9e5e7b35e971fe7eedac090a1a5a7d8a2cd59de84762f09cacffecb65bf70ed504243721fd0e094c3f216fbb85778ad82829658232a2f472919e992060394e79f2aada9e8a42ce21"))
),
# Alcatel/TCL OPK_U7_1
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"de15dc10818e30c363bd0a87d5f8d89b832329fa25b8388709d94e9b0ee4efdd3e24eed3d931f01ea1b0e2b76265d7dc270ea8012545bb7245c286761210bf46c6dd1fadefc257fabebba29bbbd86e8336460e5d21888a319156e8ba529e4b6a200136ae4aba447fb37a357028142d8b16d79a421d513ecd9b9ec0d908ba8217")),
bytes_to_long(bytes.fromhex(
"18e2fa361f4e7fc86574d9a93f2113a4d99d272710f303e29e07ebf71444335ce789dbf9816d472b27935ad49202379e44023071706bd0058e2bae45ace0938e75610579240ec87086d27fc0844ba25bba09214ae43037cb902801a58915ce58c6f805fb3ad6cf7996f25e0cf0a94c13e04eb4370ed6b93c39ba2136f8cfd101"))
),
# Alcatel/TCL MPK_U7_1
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"b6a33b825b0cf6abd3c9d39d1c8bdce50a41f9bd5ca2de52c4c447afa9943f5c1365d2e9cb7961ffd877fd38696b4479a8bb7eb8da15bd8d59a1cd7e5ee517d1a20f29bc66974f87796a11f7537529f8f46ac57861484808bfce9ee6cd6527f7fe3bfd57b4a7fd46f8dc047d6c8370de6507620c2b9a3bf864e8ee4c4d2abda1")),
bytes_to_long(bytes.fromhex(
"88a4477997b57337cb144d0656bd2d5f0ef59d6b574b631a79ac8015a4c20d454e1df85682ad25eccc7fb92be373259fffe58741b5a85e50caa68b9fe84f6e295d2176b96c20ff819e8bb889702c474effe1a77710ff3b93e896fa488f1717c75e46a1b0f5898fcacfa35943f1abf80ebb665ba7fde59c4baa61dd2f6c5ec001"))
),
# Alcatel/TCL MTK_S_AT_META
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"d1eee63f19d148c904076c507aa8d4f6c7e931a65476fe5231c06036fea2ecbcb8c811882c4f70e6e3523be73f5c7a83570f3a40bd894399a5ee9f903e8e745ec4e4e034495175b167192535843f06241d6477e3ce1ad5270e590db9cb905404c01aa407433fa2c2ca1f8366c1623fa45bd5ee68e3145a57f9af3e6e68fce41b8c682c0e07f3c48f4b377951b23b467fea0d4ee0e67c0235d0e83ae27e40ad1c060063ceb966835a0ac1eb68066f8b55775ceb7b444ffaeec19548a42247ebe687f881a0c8e5277beec22241e2ddae1c21cec8046eb005302812b7ef42ac153cab317bbeaad73f7ccaced38c433530b7e0ad464150026025a9a3ff5d45e025db")),
bytes_to_long(bytes.fromhex(
"8294e45929b8f95a380c59fe715da5225fd518920a85fdc9a8b2ade6675b7680293c21539fa4466907cb3601b072d8adebb0481ecf069baaee00d0f5cb4396f4ffea11dfd41f3c62fdeb312ee9b4be2026bc40aacd9ff928130fa7af0305228dd5e47c551c2a701653dd6841b9566099de99e2731194ae617ca8d9df99a47c49d9f514620ea1e3742da8dc7dec6756403631a274dc226c6121863e4a571a120b63c38d134853df5b986fac1565e1f3bd8a02d239462967e9c71cedd9ae0c0eec330018ca553cc7cc2fbc73d6ba37be2fe360644ff69ab7c734264675c057417857df4ca206dfdac9a5621f9d8e45dd2e58dc8b4198667de3efd1d5bd7ce007a1"))
),
# Alcatel/TCL MTK_B7
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"e3e3166f47177de4915e915a9d555d980afad96be22cbb8a02516ac8fe69657bd10bc6d072046dcd33e4476e24f128cb7ac613df140cefe71abf080a74d27c114635d3954c55299f6f81c2a0aa14c4c678307f4b3bbf0c64f0006051ea7573b5b0cc290201c76c4d272c981b1bb19bd0a0a0ac046e6e63b0f4cf88d2c98a5c91")),
bytes_to_long(bytes.fromhex(
"776b1deb8c3e943b3dae67cf2b597ba55c439dc1fa10e4e9ea530df96bd0815cc3ec3ef0267f89a699c5cb64bdb91e5e9ae4c7af03cbcfbfb4755cda55e3a31d510f96a102b5aed90731788a426e371f8ae24f660403377cc0836a06b2a8e159bd177f4cf68e36d447e4b52ca63611cd8416c1efcac52143106c272f7474387d"))
),
# Alcatel/TCL MTK_BACHATA
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"94cc529bb1af0ab8043f09e3ca612d787cc19485d3769546e750f6edb844979ba8f1f9afb8b93b521330b74713831a78a584f7b24780f92dd00e5d56ce8defa3cd39d01752e514a4c2ba7499f334729622049491b1aecee6c9e1c867e996c294b10f5d62ea4504e333424b280162087296c300c01fdf75f47d874df40dbdb94f")),
bytes_to_long(bytes.fromhex(
"09fe029a23ff7e37c749386fcc9a640450546b95e5127489d364d380393c99f5c10da6d7cf0ed955f4a5f3d8d90d97cc7c49069d394206f9b59c11568ffe66163eae377447abb103cd5d4256885cf7984b28cff8a096dc479b9196d66cd534cbdfece7a61de04110bb14a3ba5e0f20ae0bb4d82e18fbff0335904dc09b829e91"))
),
# Alcatel/TCL MPK_VLE5
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"a62bf756a70657b6b560588e85e662e181b6a61ae466ac3d0d2e971f160e88216792cedfb1979b3d6b665068eee8a8699888cd74ec9482c61ae7eae3571e50beccdcb336477c26040d09b46dbd93efc0fece4adde2e00c1cbedafd6ad7c43bd621675a6a46425c5cf6182fc5602be443a372fb4ead4531e64285ce29be913285")),
bytes_to_long(bytes.fromhex(
"7005d1bf5be81db7b17c9b16b1d407b308b42e3490e75a93e9d00fd6c812d1d8db2f1041a342964808a037f315a448ecaf0502a5215c58f0de709c5bd87e3a65e0291a1a23547c76cf437ef1d9b434b70dbb417049a31de9ee7becf218a5bb63b05fb84ff49d1e6aaa4b9b4376f47417435ecd85ccda63be9070e7892ecd4a41"))
),
# Alcatel/TCL MTK_C7
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"c1d6c392828f4620e455c138840ab448cfcd4aca821663335dba9c51dec9b8198301ca6b069adefcd1887f1cec31c15674ab264daeeb82398b419f08b4236904203c48a7db8724f1773d04a6b8c88cb38907a00bc53e86cdb2bbf479a68b8241382bdc5ac6105270efc2da4cb91a36459ccf6a2a87dd56ec4c331dd419ba5931")),
bytes_to_long(bytes.fromhex(
"31d28ed040a8ace0d56fc94b4a7d29dbb135d62c7905621818d657499fd6ff6fe7417592cececdd3f3d37ec0a361228da34d3e7a2724b7832ced00008fb4ae500357fc3d285c64fbf7efd4bd1ee48ed40190296171acc3c2d0c69e89da5a8fde7e0ba7048aec6bef1bb19646f883fe9d77d8d263545e7c00e8604be38210d065"))
),
# Alcatel/TCL MTK_MARTELL
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"a800d061e4a42e4c3453a17cc8daa974e23bfaa403b4a60fad6d3516d8ec035c1ebabdcd60009d9b8c639954e616c6cb6cf821e31e58772ffc366e6ffb7314657567b12279a34dd69e46b8a4a628dc2dfabc68fa1d89388d2058a97d2e31520b4fb04bc2f963e110e8541eefd22d90a03eca806b3c6a20c6bd1a7468e61ea1ab283ed1bc462dfae189eb5fb451f802fb868cda9a7409aa52e42b18882e79f4f1c2377829fafd9760468bd1db823bd9080378cf46ef405d91636cafc03acad9fada6b0446dbaf51e9d533887e4a3a8f62114063e0b8920684c28bfbe256aab26e98751166358c201347ba6c3b36d49aab6302fc248eea3c254e15a08429fd2149")),
bytes_to_long(bytes.fromhex(
"985e549fd42c0b4955d3db8c3ee601f65e10a3db08f957fab4016dbad0f60c7e09e8b7a782404cb0fc7c805dfd67fed814765ed58b7a146ed2c1d31b80e3f845a45b6ccda5a0344247be404c23debf027c7b5082373372b49bf78d9058caa66c57d3be829088c3610034faf1ea9f24a21110bbb3865182747ca1779e83c6983c189b3f19f3df49e5f9cdfa57f4f69dfae53e19ee0b1ec30986d59ad11f52bdc022a9499dfa89f8546d266f6026aa307501ca5a619f5413a45ef38f139c3ea8b52f02fbc8983aa878052d9108668ecfc8605057a298355d2f680c34630e224c57dd4c4f2dc0d51766ef7070daddfa3c885a3f94d76c943c6c1054d338e2323b99"))
),
# Alcatel/TCL OPK_U7
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"9f94e8f1171fed4b427629c928e807b2220f109ac70a3d5b1b8cbd295bc3fa3226d3903298cd81319b9b08a6f8e77efad0b04139b686ee0d1586175913ad6f65d6cf21bbc7f769885381ba6d840414b26fe7b9b3e393acacb3453e3a0cb79ca21cb38a42685a03462244fdb2a5f1d8b9e20745fb3206e799655c47146310911b")),
bytes_to_long(bytes.fromhex(
"61ed86791440c26491b763730f483c18c32fcd77bdb6f9e9e3e11cdfb9716d22c392c68556219e2b6c1ada57649ce2de559c239a9ff8f33252480421e4a2649df8e3ee0095c9bec361f25a5ec67d0b4d96c73404ff8a115fecf1173a6568845480fd4423b5dba2e5111335655f3bc2f3fec65510648571992e010ba0aaf243e1"))
),
# Alcatel/TCL MTK_S_2020
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"e4cc4967bec817bb348468024c3084b15fd4f7810c8a9d078a4f51cf9974d2e3bae8d5a19a85c0a73befd0675100e642a3f425e3192dfb1de56928c37f45fc142adaa65798ada863b84d4b5f22c3f79b95cc201ac7c292c99475453a62b7b7e06e84833dfca7a0df931084932a80129e543c6d24a13c5f2cba6ef5ffed9efd4dbc20496f5194f0d1aad9d789f32577f8846df9a14778504ccb5dd7507114c148c1937fb99da15f9596d4fa052cdaf1f66d7e5e0c0793628752bf9af3c4ac67e21c21d170ad448160761bddf586a4900fbb7dcc44467f1550d15db774d7cacfe3105b465321a5f95fec22c2011d616a5c0e22f0535dd1f969202be56ec015f891")),
bytes_to_long(bytes.fromhex(
"b86887499d157d3b1feb1041b9d2e94065732b41d22feebce317676321d66d1babcc7a53544e35a714c207811e62d134291d616417295e5b0c4aa3d65e40b41a352822263c22cbb4041a1883c76b97a8c925cb428a7b2300622ddaec62209d8dc0c60159f6c7ccfc26768bc469deec22bcd62f49f4c2ca1b2cf0be49d6e5ec563279cdee79c92800c6c965200d316c79285551a54359b37ec4173eadf4c0506d857ddca4831ade7ea8f13097b4e2b630a2d3eb9c57abcc65f84d693c55e361763d8d37bb40cd6e2520684ae05edc62a36cda6747509600f4605b7ed924ee1ad49e66eca1176a20794600173dbb42fced2f1fa0cccc0af3b56d58453bee420099"))
),
# Alcatel/TCL MTK_U82
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"ed2055a7b95db86f7e3101196ae6218015d70d03df6fd5787de150e82927443097a90485757743447e2f4641afcf510acf585f73e79c45b2908d5de8835221a76d93e48ca465ffbe0dd76cdaa98550ab2e7b84a6470d48595742fb54a204442ce67bab989c69adf86457e313eb24c87d80aa7d635449fab0d97b6b08c5f7c86f")),
bytes_to_long(bytes.fromhex(
"3f5d99a61561d70c6c335a30d9a11fa8a3ad70fbecf46c9e233d57aa827cccbb137c060a47e693e234ba1b532851053e17446d5582b9fee205c0d12c7613378c8b8c8c0184cdba90d56a308014aac0458c5572699d599a15ba36146b6f2e230034708cf67d31ab837b7bd8e5967fd9a7bf413b7d9314302b18e48962d01cf6f1"))
),
# Alcatel/TCL MTK_JADE
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"e8490dcbd3488278442f78ec5634ccdb8befee081ed0d19071480a10c299416ab8d0e9eb19e8975cac260606463c51bb62875ab24690d07905b9c48fe60086da12899bce3dbed91e0157cff76f27a1c09b37e837e7acb71da3c0e30564223ae20216fbcb3de5e93c2d7f98827d61441b988e57497c1ddacb87cec1e73139bf67")),
bytes_to_long(bytes.fromhex(
"69fd6b9e25ba604e204ec90e8e0769b28417e6b52dda7ac53deb712c549f398a48ea8ad20bf065a093ac85f336f92f1221d3413f3793bc8c7c6057a091828c04f6fb695f43747d0d22de100bccce70ac7a8f9d092afaa7d44fcda99b12454f8c887e383c69e7e21ad15203eaae51d803cf35da09c8d536139c658bebfddccf01"))
),
# Alcatel/TCL MTK_B82
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"b6a33b825b0cf6abd3c9d39d1c8bdce50a41f9bd5ca2de52c4c447afa9943f5c1365d2e9cb7961ffd877fd38696b4479a8bb7eb8da15bd8d59a1cd7e5ee517d1a20f29bc66974f87796a11f7537529f8f46ac57861484808bfce9ee6cd6527f7fe3bfd57b4a7fd46f8dc047d6c8370de6507620c2b9a3bf864e8ee4c4d2abda1")),
bytes_to_long(bytes.fromhex(
"88a4477997b57337cb144d0656bd2d5f0ef59d6b574b631a79ac8015a4c20d454e1df85682ad25eccc7fb92be373259fffe58741b5a85e50caa68b9fe84f6e295d2176b96c20ff819e8bb889702c474effe1a77710ff3b93e896fa488f1717c75e46a1b0f5898fcacfa35943f1abf80ebb665ba7fde59c4baa61dd2f6c5ec001"))
),
# Alcatel/TCL MTK_S_2021
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"df85f4c4ae8c98e78142d403d002276a5bf9edd17870caa848fc45720e8b4be94f6f9a47181417840a5b7d4fc36575129afd6a848a0de3f62fac5b5f687a2219cab8cdf2e7527d6af3c6be84eb99bf519b0b210960fc8f5223c9bc38e8f20d0267642153cf370312b955143e10490c6a207868ac7ac314bbe10f6063a1ba606e28d248a1ee3e7000d12e9c4ebd47ae483b625156b82026fcfdc36118198cac1463aeb56bdfe260efa38ac1d4123c13fe59e0fb0f2f895609c117f7a39fb9f27c356d4748cf7af41e15ea68c6c7c64c4d0a1acb4632965e0260d9b08de9fd81b82050c9929b79ee865f89272483b6fed8a409d6a1af2429d24fd358a4b4da4e77")),
bytes_to_long(bytes.fromhex(
"cf553c03ac3cf21fdb4097d4a97f35fc6c305a2e30dfbebb7667ba2adfdec99d3277bccd314281c592ade680b42849fde6122659a68cd7e525b764520d612c7c6c141bc4b2594bc88732d4ca0a97e464d7c1ecf4fc2788f1920cb030c1b2b3ea84e8d6191d5e53d56c5fc495051a1d0fdbea947d58a9d773a68152d157d4bf57f2b4fba8182f96ea4c9b798018361054f95b251089c786be542c7881c49b077ad52af25a359bb26257170706217f66533cf4b8379a1fb7a30c955c8ed4c1c6dca905ce6e7e5e92ec7e1bda1db44cd187a9e5137fe44a37cfdbee173a49654994926cb2fdd7857dfc8978d9de73e899e18f5dfe33a64e6414fc5d93738f8c5591"))
),
# Alcatel/TCL MTK_MINIQ2
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"ba1d10a245e60471e8d3138611615170f213cae5b895c8af35eb720e2671915f07dd6ccb5384d7580200d18f430c89405dcb0be6a5e91cff0fda970e292d5f0704720473bc61e19590539b1bb08ce2b306755db1f70cf1193933802ca44281fe01699f75e56fb7660fce0342ccc284d497a17ad7d3d15eaa20ad4c67bd92de61")),
bytes_to_long(bytes.fromhex(
"a475ba952a9f2f9e58d6ec91b41a03158354ea1e451656d83d15691c07eca3410e7a2401283462f66a0ebf1f91682a80ae61168b2260f4368f93e197a9db65f4139523ef5449a6fa77568a9ffe90e0a34a37f99b7c1ec6ed1683a574d9045993679ef73299991cd43b96fdba6673ae4318f2f635a816f8559d325f9ebe428a01"))
),
# Alcatel/TCL MTK_HIGHWAY
(
bytes_to_long(bytes.fromhex("00010001")),
bytes_to_long(bytes.fromhex(
"beca753fd31ef104bbb01b0a7c560c7bc040d30ea18f216b64b7de416b695af2b3350ecc02fa5224b412793f876a7bdbd8cbe7fecd754aa8214a27bfe7ececd8caa16959df83bdaeed524880a820f8dfe601dc70f164ff1921baaa06efd8c584c22269a109d16287356fd30e7eb02a1365ca93fcb8088278f119a2c7298306a9")),
bytes_to_long(bytes.fromhex(
"5407571c851f5b877a2255c6887c5d832369698b481c81db8ac07062dfabc7229d4b00f95956665743f7deeedbf54a17c9a404c97433f46d983bd0c5f49fa4b013b9d86e5f1377f563d8299675c0ea2b81f51c33ad74a265184df9389eefb8e72d2f0585e4a41826b8846b0ee6da5ef8cce471536109fe4c658735247ebbc301"))
),
]
if isbrom:
# e, n, d
for key in rsakeys:
if self.echo(self.Cmd.SLA.value):
status = self.rword()
if status > 0xFF:
self.error(f"Send auth error:{self.eh.status(status)}")
return False
e = key[0]
n = key[1]
d = key[2]
challenge_length = self.rdword()
challenge = self.rbyte(challenge_length)
response = generate_rsa_challenge(n, d, challenge)
resplen = len(response) # 0x80, 0x100, 0x180
self.usbwrite(int.to_bytes(resplen,4,'little'))
rlen = self.rdword()
if resplen == rlen:
status = self.rword()
if status > 0xFF:
self.error(f"Send sla challenge response len error:{self.eh.status(status)}")
return False
self.usbwrite(response[:resplen])
status = self.rdword()
if status < 0xFF:
return True
else:
self.error(f"Send auth error:{self.eh.status(status)}")
continue
return False
else: # not brom / da
"""
# N=B243F669.....
for key in rsakeys:
rsakey = RSA.construct((n, e, d))
encryptor = PKCS1_OAEP.new(rsakey)
encrypted = encryptor.encrypt(data)
print(encrypted.hex())
"""
return True
def get_brom_log(self):
if self.echo(self.Cmd.BROM_DEBUGLOG.value): # 0xDD
length = self.rdword()
@ -677,7 +1062,17 @@ class Preloader(metaclass=LogBase):
return self.mtk.config.meid
else:
self.error("Error on get_meid: " + self.eh.status(status))
else:
elif int.from_bytes(res,'little')>2:
self.usbwrite(self.Cmd.GET_ME_ID.value)
if self.usbread(1) == self.Cmd.GET_ME_ID.value:
length = unpack(">I", self.usbread(4))[0]
self.mtk.config.meid = self.usbread(length)
status = unpack("<H", self.usbread(2))[0]
self.config.is_brom = False
if status == 0:
return self.mtk.config.meid
else:
self.error("Error on get_meid: " + self.eh.status(status))
self.config.is_brom = False
return None
@ -694,6 +1089,18 @@ class Preloader(metaclass=LogBase):
return self.mtk.config.socid
else:
self.error("Error on get_socid: " + self.eh.status(status))
elif int.from_bytes(res,'little')>2:
self.usbwrite(self.Cmd.GET_SOC_ID.value)
if self.usbread(1) == self.Cmd.GET_SOC_ID.value:
length = unpack(">I", self.usbread(4))[0]
self.mtk.config.socid = self.usbread(length)
status = unpack("<H", self.usbread(2))[0]
self.config.is_brom = False
if status == 0:
return self.mtk.config.socid
else:
self.error("Error on get_socid: " + self.eh.status(status))
self.config.is_brom = False
return b""
def prepare_data(self, data, sigdata=b"", maxsize=0):
@ -716,7 +1123,8 @@ class Preloader(metaclass=LogBase):
self.usbwrite(data[pos:pos + size])
bytestowrite -= size
pos += size
# self.usbwrite(b"")
self.usbwrite(b"")
time.sleep(0.035)
try:
res = self.rword(2)
if isinstance(res, list):
@ -757,6 +1165,12 @@ class Preloader(metaclass=LogBase):
return False
status = self.rword()
if status == 0x1D0D:
self.info("SLA required ...")
if not self.handle_sla(func=None,isbrom=self.config.is_brom):
self.info("Bad sla challenge :(")
return False
status = 0
if 0 <= status <= 0xFF:
if not self.upload_data(data, gen_chksum):
self.error("Error on uploading da data")
@ -766,3 +1180,33 @@ class Preloader(metaclass=LogBase):
self.error(f"DA_Send status error:{self.eh.status(status)}")
self.config.set_gui_status(self.config.tr("Error on DA_Send"))
return False
if __name__ == "__main__":
"""
e = bytes_to_long(bytes.fromhex("010001"))
n = bytes_to_long(bytes.fromhex(
"C43469A95B143CDC63CE318FE32BAD35B9554A136244FA74D13947425A32949EE6DC808CDEBF4121687A570B83C51E657303C925EC280B420C757E5A63AD3EC6980AAD5B6CA6D1BBDC50DB793D2FDDC0D0361C06163CFF9757C07F96559A2186322F7ABF1FFC7765F396673A48A4E8E3296427BC5510D0F97F54E5CA1BD7A93ADE3F6A625056426BDFE77B3B502C68A18F08B470DA23B0A2FAE13B8D4DB3746255371F43306582C74794D1491E97FDE504F0B1ECAC9DDEF282D674B817B7FFA8522672CF6281790910378FEBFA7DC6C2B0AF9DA03A58509D60AA1AD6F9BFDC84537CD0959B8735FE0BB9B471104B458A38DF846366926993097222F90628528F"))
d = bytes_to_long(bytes.fromhex(
"8E02CDB389BBC52D5383EBB5949C895B0850E633CF7DD3B5F7B5B8911B0DDF2A80387B46FAF67D22BC2748978A0183B5B420BA579B6D847082EA0BD14AB21B6CCCA175C66586FCE93756C2F426C85D7DF07629A47236265D1963B8354CB229AFA2E560B7B3641DDB8A0A839ED8F39BA8C7CDB94104650E8C7790305E2FF6D18206F49B7290B1ADB7B4C523E10EBF53630D438EF49C877402EA3C1BD6DD903892FD662FBDF1DFF5D7B095712E58E728BD7F6A8B5621175F4C08EBD6143CDACD65D9284DFFECAB64F70FD63182E4981551522727A2EE9873D0DB78180C26553AD0EE1CAAA21BCEBC5A8C0B331FE7FD8710F905A7456AF675A04AF1118CE71E36C9"))
data=bytearray([0xA,0xB,0xC,0xD,0xE,0xF,0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9])
msg = generate_rsa_challenge(n,d,data)
print(msg.hex())
"""
data = bytearray([0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9])
from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_OAEP
#E_DA=bytes_to_long(bytes.fromhex("010001"))
#N_DA= bytes_to_long(bytes.fromhex("A243F6694336D527C5B3ED569DDD0386D309C6592841E4C033DCB461EEA7B6F8535FC4939E403060646A970DD81DE367CF003848146F19D259F50A385015AF6309EAA71BFED6B098C7A24D4871B4B82AAD7DC6E2856C301BE7CDB46DC10795C0D30A68DD8432B5EE5DA42BA22124796512FCA21D811D50B34C2F672E25BCC2594D9C012B34D473EE222D1E56B90E7D697CEA97E8DD4CCC6BED5FDAECE1A43F96495335F322CCE32612DAB462B024281841F553FF7FF33E0103A7904037F8FE5D9BE293ACD7485CDB50957DB11CA6DB28AF6393C3E78D9FBCD4567DEBCA2601622F0F2EB19DA9192372F9EA3B28B1079409C0A09E3D51D64A4C4CE026FAD24CD7"))
#D_DA= bytes_to_long(bytes.fromhex("707C8892D0DE8CE0CA116914C8BD277B821E784D298D00D3473EDE236399435F8541009525C2786CB3ED3D7530D47C9163692B0D588209E7E0E8D06F4A69725498B979599DC576303B5D8D96F874687A310D32E8C86E965B844BC2ACE51DC5E06859EA087BD536C39DCB8E1262FDEAF6DA20035F14D3592AB2C1B58734C5C62AC86FE44F98C602BABAB60A6C8D09A199D2170E373D9B9A5D9B6DE852E859DEB1BDF33034DCD91EC4EEBFDDBECA88E29724391BB928F40EFD945299DFFC4595BB8D45F426AC15EC8B1C68A19EB51BEB2CC6611072AE5637DF0ABA89ED1E9CB8C9AC1EB05B1F01734DB303C23BE1869C9013561B9F6EA65BD2516DE950F08B2E81"))
e = bytes_to_long(bytes.fromhex("010001"))
n = bytes_to_long(bytes.fromhex(
"C43469A95B143CDC63CE318FE32BAD35B9554A136244FA74D13947425A32949EE6DC808CDEBF4121687A570B83C51E657303C925EC280B420C757E5A63AD3EC6980AAD5B6CA6D1BBDC50DB793D2FDDC0D0361C06163CFF9757C07F96559A2186322F7ABF1FFC7765F396673A48A4E8E3296427BC5510D0F97F54E5CA1BD7A93ADE3F6A625056426BDFE77B3B502C68A18F08B470DA23B0A2FAE13B8D4DB3746255371F43306582C74794D1491E97FDE504F0B1ECAC9DDEF282D674B817B7FFA8522672CF6281790910378FEBFA7DC6C2B0AF9DA03A58509D60AA1AD6F9BFDC84537CD0959B8735FE0BB9B471104B458A38DF846366926993097222F90628528F"))
d = bytes_to_long(bytes.fromhex(
"8E02CDB389BBC52D5383EBB5949C895B0850E633CF7DD3B5F7B5B8911B0DDF2A80387B46FAF67D22BC2748978A0183B5B420BA579B6D847082EA0BD14AB21B6CCCA175C66586FCE93756C2F426C85D7DF07629A47236265D1963B8354CB229AFA2E560B7B3641DDB8A0A839ED8F39BA8C7CDB94104650E8C7790305E2FF6D18206F49B7290B1ADB7B4C523E10EBF53630D438EF49C877402EA3C1BD6DD903892FD662FBDF1DFF5D7B095712E58E728BD7F6A8B5621175F4C08EBD6143CDACD65D9284DFFECAB64F70FD63182E4981551522727A2EE9873D0DB78180C26553AD0EE1CAAA21BCEBC5A8C0B331FE7FD8710F905A7456AF675A04AF1118CE71E36C9"))
rsakey = RSA.construct((n,e,d))
encryptor = PKCS1_OAEP.new(rsakey)
encrypted = encryptor.encrypt(data)
decrypted = encryptor.decrypt(encrypted)
print(encrypted.hex())
print(decrypted.hex())

View file

@ -5,6 +5,7 @@ import logging
from mtkclient.Library.utils import LogBase, logsetup
from mtkclient.Library.gpt import gpt
from mtkclient.Library.pmt import pmt
class Partition(metaclass=LogBase):
@ -27,7 +28,43 @@ class Partition(metaclass=LogBase):
return data
return b""
def get_gpt(self, gpt_settings, parttype="user") -> tuple:
def get_pmt(self, backup: bool = False, parttype: str = "user") -> tuple:
pt = pmt()
blocksize = self.mtk.daloader.daconfig.pagesize
if not backup:
addr = self.mtk.daloader.daconfig.flashsize - (2 * blocksize)
else:
addr = self.mtk.daloader.daconfig.flashsize - (2 * blocksize) + blocksize
data = self.readflash(addr=addr, length=2 * self.config.pagesize, filename="", parttype=parttype, display=False)
magic = int.from_bytes(data[:4],'little')
if magic in [b"PTv3", b"MPT3"]:
partdata = data[8:]
partitions = []
for partpos in range(128):
partinfo = pt.pt_resident(partdata[partpos * 96:(partpos * 96) + 96])
if partinfo[:4] == b"\x00\x00\x00\x00":
break
class partf:
unique = b""
first_lba = 0
last_lba = 0
flags = 0
sector = 0
sectors = 0
type = b""
name = ""
pm = partf()
pm.name = partinfo.name.rstrip(b"\x00").decode('utf-8')
pm.sector = partinfo.offset // self.config.pagesize
pm.sectors = partinfo.size // self.config.pagesize
pm.type = 1
pm.flags = partinfo.mask_flags
partitions.add(pm)
return data, partitions
return b"", None
def get_gpt(self, gpt_settings, parttype: str = "user") -> tuple:
data = self.readflash(addr=0, length=2 * self.config.pagesize, filename="", parttype=parttype, display=False)
if data[:4] == b"BPI\x00":
guid_gpt = gpt(
@ -77,7 +114,8 @@ class Partition(metaclass=LogBase):
guid_gpt.parse(data, self.config.pagesize)
return data, guid_gpt
def get_backup_gpt(self, lun, gpt_num_part_entries, gpt_part_entry_size, gpt_part_entry_start_lba, parttype="user") -> bytearray:
def get_backup_gpt(self, lun, gpt_num_part_entries, gpt_part_entry_size, gpt_part_entry_start_lba,
parttype="user") -> bytearray:
data = self.readflash(addr=0, length=2 * self.config.pagesize, filename="", parttype=parttype, display=False)
if data == b"":
return data

55
mtkclient/Library/pmt.py Normal file
View file

@ -0,0 +1,55 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# (c) B.Kerler 2018-2023
import argparse
import os
import sys
import logging
from io import BytesIO
from enum import Enum
from struct import unpack
from binascii import hexlify
try:
from mtkclient.Library.utils import LogBase, structhelper
except:
from utils import LogBase, structhelper
class pmt(metaclass=LogBase):
class pt_resident:
def __init__(self, data):
sh = structhelper(data)
self.name = sh.bytes(64)
self.size = sh.qword()
self.part_id = sh.qword()
self.offset = sh.qword()
self.mask_flags = sh.qword()
class pt_info:
def __init__(self, data):
sh = structhelper(data)
self.sequencenumber = sh.bytes(1)
self.tool_or_sd_update = sh.bytes(1)
tmp = sh.bytes(1)
self.mirror_pt_dl = (tmp>>4)&0xF
self.mirror_pt_has_space = tmp&0xF
tmp = sh.bytes(1)
self.pt_changed = (tmp >> 4) & 0xF
self.pt_has_space = tmp & 0xF
class pmt_header:
def __init__(self, data):
sh = structhelper(data)
self.signature = sh.bytes(8)
self.revision = sh.dword()
self.header_size = sh.dword()
self.crc32 = sh.dword()
self.reserved = sh.dword()
self.current_lba = sh.qword()
self.backup_lba = sh.qword()
self.first_usable_lba = sh.qword()
self.last_usable_lba = sh.qword()
self.disk_guid = sh.bytes(16)
self.part_entry_start_lba = sh.qword()
self.num_part_entries = sh.dword()
self.part_entry_size = sh.dword()

2
mtkclient/Library/settings.py Normal file → Executable file
View file

@ -5,10 +5,12 @@ from binascii import hexlify
class hwparam:
paramsetting = None
hwcode = None
appid = b""
def __init__(self, meid:str, path:str="logs"):
self.paramfile = "hwparam.json"
self.hwparampath = path
self.appid = b""
if isinstance(meid,bytearray) or isinstance(meid,bytes):
meid=hexlify(meid).decode('utf-8')
if meid is None:

0
mtkclient/Library/thread_handling.py Normal file → Executable file
View file

View file

@ -124,7 +124,7 @@ def find_binary(data, strf, pos=0):
rt += 1
continue
rt += 1
prep = data[rt:].find(t[i])
prep = data[pos+rt:].find(t[i])
if prep != 0:
error = 1
break

Binary file not shown.

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