mirror of
https://github.com/bkerler/mtkclient.git
synced 2024-11-14 19:25:05 -05:00
Prepare V2
This commit is contained in:
parent
d09ece6366
commit
48f7be990c
1043 changed files with 8329 additions and 521 deletions
|
@ -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
120
mtk
|
@ -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
0
mtkclient/Library/DA/__init__.py
Normal file → Executable 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
0
mtkclient/Library/DA/legacy/__init__.py
Normal file → Executable file
0
mtkclient/Library/DA/legacy/dalegacy_flash_param.py
Normal file → Executable file
0
mtkclient/Library/DA/legacy/dalegacy_flash_param.py
Normal file → Executable file
0
mtkclient/Library/DA/legacy/dalegacy_iot_flash_param.py
Normal file → Executable file
0
mtkclient/Library/DA/legacy/dalegacy_iot_flash_param.py
Normal file → Executable 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
0
mtkclient/Library/DA/legacy/dalegacy_param.py
Normal file → Executable file
0
mtkclient/Library/DA/legacy/extension/__init__.py
Normal file → Executable file
0
mtkclient/Library/DA/legacy/extension/__init__.py
Normal file → Executable file
33
mtkclient/Library/DA/legacy/extension/legacy.py
Normal file → Executable file
33
mtkclient/Library/DA/legacy/extension/legacy.py
Normal file → Executable 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
95
mtkclient/Library/DA/mtk_da_handler.py
Normal file → Executable 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":
|
||||
|
|
|
@ -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
0
mtkclient/Library/DA/xflash/__init__.py
Normal file → Executable file
0
mtkclient/Library/DA/xflash/extension/__init__.py
Normal file → Executable file
0
mtkclient/Library/DA/xflash/extension/__init__.py
Normal file → Executable file
115
mtkclient/Library/DA/xflash/extension/xflash.py
Normal file → Executable file
115
mtkclient/Library/DA/xflash/extension/xflash.py
Normal file → Executable 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
0
mtkclient/Library/DA/xflash/xflash_flash_param.py
Normal file → Executable 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
0
mtkclient/Library/DA/xflash/xflash_param.py
Normal file → Executable file
0
mtkclient/Library/DA/xml/__init__.py
Normal file → Executable file
0
mtkclient/Library/DA/xml/__init__.py
Normal file → Executable file
0
mtkclient/Library/DA/xml/extension/__init__.py
Executable file
0
mtkclient/Library/DA/xml/extension/__init__.py
Executable file
832
mtkclient/Library/DA/xml/extension/v6.py
Executable file
832
mtkclient/Library/DA/xml/extension/v6.py
Executable 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
407
mtkclient/Library/DA/xml/xml_cmd.py
Normal file → Executable 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
679
mtkclient/Library/DA/xml/xml_lib.py
Normal file → Executable 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
0
mtkclient/Library/DA/xml/xml_param.py
Normal file → Executable file
0
mtkclient/Library/Exploit/__init__.py
Normal file → Executable file
0
mtkclient/Library/Exploit/__init__.py
Normal file → Executable file
0
mtkclient/Library/Exploit/amonet.py
Normal file → Executable file
0
mtkclient/Library/Exploit/amonet.py
Normal file → Executable file
0
mtkclient/Library/Exploit/hashimoto.py
Normal file → Executable file
0
mtkclient/Library/Exploit/hashimoto.py
Normal file → Executable file
4
mtkclient/Library/Exploit/kamakiri2.py
Normal file → Executable file
4
mtkclient/Library/Exploit/kamakiri2.py
Normal file → Executable 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)
|
||||
|
|
97
mtkclient/Library/Exploit/kamakiri_pl.py
Executable file
97
mtkclient/Library/Exploit/kamakiri_pl.py
Executable 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
0
mtkclient/Library/Hardware/__init__.py
Normal file → Executable 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":
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
0
mtkclient/Library/Hardware/seccfg.py
Normal file → Executable 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
0
mtkclient/Library/__init__.py
Normal file → Executable 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
0
mtkclient/Library/exploit_handler.py
Normal file → Executable file
6
mtkclient/Library/meta.py
Normal file → Executable file
6
mtkclient/Library/meta.py
Normal file → Executable 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
31
mtkclient/Library/mtk_class.py
Normal file → Executable 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
17
mtkclient/Library/mtk_main.py
Normal file → Executable 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:
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
55
mtkclient/Library/pmt.py
Normal 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
2
mtkclient/Library/settings.py
Normal file → Executable 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
0
mtkclient/Library/thread_handling.py
Normal file → Executable 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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
mtkclient/Loader/MTK_DA_V6.bin
Normal file
BIN
mtkclient/Loader/MTK_DA_V6.bin
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue