mirror of
https://github.com/bkerler/edl.git
synced 2024-11-14 19:14:58 -05:00
Bump to 3.60 pre-release
This commit is contained in:
parent
d5ff2d474a
commit
d81e857379
22 changed files with 1815 additions and 3891 deletions
11
README.md
11
README.md
|
@ -65,6 +65,17 @@ pip3 install -r requirements.txt
|
|||
- Test on device connect using "UsbDkController -n" if you see a device with pid 0x9008
|
||||
- Works fine under Windows 10 and 11 :D
|
||||
|
||||
#### Using serial port instead of usb
|
||||
With Port autodetection
|
||||
```bash
|
||||
edl --serial
|
||||
```
|
||||
|
||||
or Port name
|
||||
```bash
|
||||
edl --portname \\.\COM1
|
||||
```
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
## Get Loaders
|
||||
You should get these automatically if you do a ``` git submodule update --init --recursive ```
|
||||
|
|
290
edl
290
edl
|
@ -4,50 +4,51 @@
|
|||
"""
|
||||
Usage:
|
||||
edl -h | --help
|
||||
edl [--vid=vid] [--pid=pid]
|
||||
edl [--loader=filename] [--memory=memtype]
|
||||
edl [--debugmode]
|
||||
edl [--gpt-num-part-entries=number] [--gpt-part-entry-size=number] [--gpt-part-entry-start-lba=number]
|
||||
edl [--memory=memtype] [--skipstorageinit] [--maxpayload=bytes] [--sectorsize==bytes]
|
||||
edl server [--tcpport=portnumber] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit]
|
||||
edl memorydump [--partitions=partnames] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl printgpt [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl gpt <directory> [--memory=memtype] [--lun=lun] [--genxml] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl r <partitionname> <filename> [--memory=memtype] [--sectorsize==bytes] [--lun=lun] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl rl <directory> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skip=partnames] [--genxml] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl rf <filename> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl rs <start_sector> <sectors> <filename> [--lun=lun] [--sectorsize==bytes] [--memory=memtype] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl w <partitionname> <filename> [--partitionfilename=filename] [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skipwrite] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit]
|
||||
edl wl <directory> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skip=partnames] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit]
|
||||
edl wf <filename> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit]
|
||||
edl ws <start_sector> <filename> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skipwrite] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit]
|
||||
edl e <partitionname> [--memory=memtype] [--skipwrite] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit]
|
||||
edl es <start_sector> <sectors> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skipwrite] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit]
|
||||
edl ep <partitionname> <sectors> [--memory=memtype] [--skipwrite] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit]
|
||||
edl footer <filename> [--memory=memtype] [--lun=lun] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl peek <offset> <length> <filename> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid]
|
||||
edl peekhex <offset> <length> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl peekdword <offset> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl peekqword <offset> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl memtbl <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl poke <offset> <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl pokehex <offset> <data> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl pokedword <offset> <data> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl pokeqword <offset> <data> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl memcpy <offset> <size> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl secureboot [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl pbl <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl qfp <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl getstorageinfo [--loader=filename] [--memory=memtype] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl setbootablestoragedrive <lun> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid]
|
||||
edl send <command> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid]
|
||||
edl xml <xmlfile> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit]
|
||||
edl rawxml <xmlstring> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit]
|
||||
edl reset [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl nop [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit]
|
||||
edl modules <command> <options> [--memory=memtype] [--lun=lun] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value]
|
||||
edl provision <xmlfile> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid]
|
||||
edl qfil <rawprogram> <patch> <imagedir> [--loader=filename] [--memory=memtype] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid]
|
||||
edl [--vid=vid] [--pid=pid] [--portname=portname] [--serial]
|
||||
edl [--loader=filename] [--memory=memtype] [--portname=portname] [--serial]
|
||||
edl [--debugmode] [--portname=portname] [--serial]
|
||||
edl [--gpt-num-part-entries=number] [--gpt-part-entry-size=number] [--gpt-part-entry-start-lba=number] [--portname=portname] [--serial]
|
||||
edl [--memory=memtype] [--skipstorageinit] [--maxpayload=bytes] [--sectorsize==bytes] [--portname=portname] [--serial]
|
||||
edl server [--tcpport=portnumber] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl memorydump [--partitions=partnames] [--debugmode] [--vid=vid] [--pid=pid] [--portname=portname] [--serial]
|
||||
edl printgpt [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl gpt <directory> [--memory=memtype] [--lun=lun] [--genxml] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl r <partitionname> <filename> [--memory=memtype] [--sectorsize==bytes] [--lun=lun] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl rl <directory> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skip=partnames] [--genxml] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl rf <filename> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl rs <start_sector> <sectors> <filename> [--lun=lun] [--sectorsize==bytes] [--memory=memtype] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl w <partitionname> <filename> [--partitionfilename=filename] [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skipwrite] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl wl <directory> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skip=partnames] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl wf <filename> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl ws <start_sector> <filename> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skipwrite] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl e <partitionname> [--memory=memtype] [--skipwrite] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl es <start_sector> <sectors> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skipwrite] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl ep <partitionname> <sectors> [--memory=memtype] [--skipwrite] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl footer <filename> [--memory=memtype] [--lun=lun] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl peek <offset> <length> <filename> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--portname=portname] [--serial]
|
||||
edl peekhex <offset> <length> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--portname=portname] [--serial]
|
||||
edl peekdword <offset> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl peekqword <offset> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl memtbl <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl poke <offset> <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl pokehex <offset> <data> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl pokedword <offset> <data> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl pokeqword <offset> <data> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl memcpy <offset> <size> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--portname=portname] [--serial]
|
||||
edl secureboot [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl pbl <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl qfp <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl getstorageinfo [--loader=filename] [--memory=memtype] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl setbootablestoragedrive <lun> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--portname=portname] [--serial]
|
||||
edl setactiveslot <slot> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--portname=portname] [--serial]
|
||||
edl send <command> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--portname=portname] [--serial]
|
||||
edl xml <xmlfile> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl rawxml <xmlstring> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl reset <resetmode> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--portname=portname] [--serial]
|
||||
edl nop [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--skipstorageinit] [--portname=portname] [--serial]
|
||||
edl modules <command> <options> [--memory=memtype] [--lun=lun] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value] [--portname=portname] [--serial]
|
||||
edl provision <xmlfile> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--portname=portname] [--serial]
|
||||
edl qfil <rawprogram> <patch> <imagedir> [--loader=filename] [--memory=memtype] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--portname=portname] [--serial]
|
||||
|
||||
Description:
|
||||
server # Run tcp/ip server
|
||||
|
@ -83,9 +84,10 @@ Description:
|
|||
send # Send firehose command
|
||||
xml # Send firehose xml file
|
||||
rawxml # Send firehose xml raw string
|
||||
reset # Send firehose reset command
|
||||
reset # Send firehose reset command, reset modes: reset, off, edl
|
||||
nop # Send firehose nop command
|
||||
modules # Enable submodules, for example: "oemunlock enable"
|
||||
setactiveslot # Set partition as active (Slot A/B)
|
||||
provision # UFS provision
|
||||
qfil # Write rawprogram xml files
|
||||
# <rawprogram> : program config xml, such as rawprogram_unsparse.xml or rawprogram*.xml
|
||||
|
@ -113,6 +115,9 @@ Options:
|
|||
--skip=partnames Skip reading partition with names "partname1,partname2,etc."
|
||||
--genxml Generate rawprogram[lun].xml
|
||||
--devicemodel=value Set device model
|
||||
--portname=portname Set serial port name (/dev/ttyUSB0 for Linux/MAC; \\.\COM1 for Windows)
|
||||
--serial Use serial port (port autodetection)
|
||||
--slot Set active slot for setactiveslot [a or b]
|
||||
"""
|
||||
|
||||
import os
|
||||
|
@ -124,25 +129,25 @@ import re
|
|||
from docopt import docopt
|
||||
from edlclient.Config.usb_ids import default_ids
|
||||
from edlclient.Library.utils import LogBase
|
||||
from edlclient.Library.usblib import UsbClass
|
||||
from edlclient.Library.Connection.usblib import usb_class
|
||||
from edlclient.Library.Connection.seriallib import serial_class
|
||||
from edlclient.Library.sahara import sahara
|
||||
from edlclient.Library.streaming_client import streaming_client
|
||||
from edlclient.Library.firehose_client import firehose_client
|
||||
from edlclient.Library.streaming import Streaming
|
||||
from edlclient.Library.sahara_defs import cmd_t, sahara_mode_t
|
||||
from binascii import hexlify
|
||||
|
||||
args = docopt(__doc__, version='3')
|
||||
|
||||
print("Qualcomm Sahara / Firehose Client V3.53 (c) B.Kerler 2018-2021.")
|
||||
print("Qualcomm Sahara / Firehose Client V3.60 (c) B.Kerler 2018-2022.")
|
||||
|
||||
|
||||
def parse_cmd(rargs):
|
||||
cmds = ["server", "printgpt", "gpt", "r", "rl", "rf", "rs", "w", "wl", "wf", "ws", "e", "es", "ep", "footer",
|
||||
"peek", "peekhex",
|
||||
"peekdword", "peekqword", "memtbl", "poke", "pokehex", "pokedword", "pokeqword", "memcpy", "secureboot",
|
||||
"pbl",
|
||||
"qfp", "getstorageinfo", "setbootablestoragedrive", "send", "xml", "rawxml", "reset", "nop", "modules",
|
||||
"memorydump", "provision", "qfil"]
|
||||
"peek", "peekhex", "peekdword", "peekqword", "memtbl", "poke", "pokehex", "pokedword", "pokeqword",
|
||||
"memcpy", "secureboot", "pbl", "qfp", "getstorageinfo", "setbootablestoragedrive", "setactiveslot",
|
||||
"send", "xml", "rawxml", "reset", "nop", "modules", "memorydump", "provision", "qfil"]
|
||||
for cmd in cmds:
|
||||
if rargs[cmd]:
|
||||
return cmd
|
||||
|
@ -177,9 +182,9 @@ class main(metaclass=LogBase):
|
|||
self.cdc = None
|
||||
self.sahara = None
|
||||
|
||||
def doconnect(self, loop, mode, resp):
|
||||
def doconnect(self, loop):
|
||||
while not self.cdc.connected:
|
||||
self.cdc.connected = self.cdc.connect()
|
||||
self.cdc.connected = self.cdc.connect(portname=self.portname)
|
||||
if not self.cdc.connected:
|
||||
sys.stdout.write('.')
|
||||
if loop == 5:
|
||||
|
@ -199,25 +204,40 @@ class main(metaclass=LogBase):
|
|||
else:
|
||||
self.info("Device detected :)")
|
||||
try:
|
||||
mode, resp = self.sahara.connect()
|
||||
resp = self.sahara.connect()
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
self.debug(str(err))
|
||||
if mode == "" or resp == -1:
|
||||
mode, resp = self.sahara.connect()
|
||||
if mode == -1:
|
||||
mode, resp = self.sahara.connect()
|
||||
if mode == "":
|
||||
self.info("Unknown mode. Aborting.")
|
||||
self.exit()
|
||||
self.info(f"Mode detected: {mode}")
|
||||
break
|
||||
|
||||
return mode, resp
|
||||
continue
|
||||
if "mode" in resp:
|
||||
mode = resp["mode"]
|
||||
self.info(f"Mode detected: {mode}")
|
||||
return resp
|
||||
return {"mode":"error"}
|
||||
|
||||
def exit(self):
|
||||
self.cdc.close()
|
||||
sys.exit()
|
||||
|
||||
def handle_streaming(self, mode):
|
||||
self.cdc.timeout = None
|
||||
sahara_info = self.sahara.streaminginfo()
|
||||
if sahara_info:
|
||||
mode, resp = self.sahara.connect()
|
||||
if mode == "sahara":
|
||||
mode = self.sahara.upload_loader()
|
||||
if "enprg" in self.sahara.programmer.lower():
|
||||
mode = "load_enandprg"
|
||||
elif "nprg" in self.sahara.programmer.lower():
|
||||
mode = "load_nandprg"
|
||||
elif mode != "":
|
||||
mode = "load_" + mode
|
||||
if "load_" in mode:
|
||||
time.sleep(0.3)
|
||||
else:
|
||||
print("Error, couldn't find suitable enprg/nprg loader :(")
|
||||
self.exit()
|
||||
return mode
|
||||
|
||||
def run(self):
|
||||
if sys.platform == 'win32' or sys.platform == 'win64' or sys.platform == 'winnt':
|
||||
proper_driver = console_cmd(r'reg query HKLM\HARDWARE\DEVICEMAP\SERIALCOMM')
|
||||
|
@ -243,7 +263,20 @@ class main(metaclass=LogBase):
|
|||
else:
|
||||
self.__logger.setLevel(logging.INFO)
|
||||
|
||||
self.cdc = UsbClass(portconfig=portconfig, loglevel=self.__logger.level)
|
||||
if args["--serial"]:
|
||||
self.serial = True
|
||||
else:
|
||||
self.serial = False
|
||||
if args["--portname"]:
|
||||
self.portname = args["--portname"]
|
||||
self.serial = True
|
||||
else:
|
||||
self.portname = ""
|
||||
if self.serial:
|
||||
self.cdc = serial_class(loglevel=self.__logger.level,portconfig=portconfig)
|
||||
else:
|
||||
self.cdc = usb_class(portconfig=portconfig, loglevel=self.__logger.level)
|
||||
|
||||
self.sahara = sahara(self.cdc, loglevel=self.__logger.level)
|
||||
|
||||
if args["--loader"] == 'None':
|
||||
|
@ -256,25 +289,14 @@ class main(metaclass=LogBase):
|
|||
|
||||
self.info("Waiting for the device")
|
||||
resp = None
|
||||
self.cdc.timeout = 100
|
||||
mode, resp = self.doconnect(loop, mode, resp)
|
||||
if resp == -1:
|
||||
mode, resp = self.doconnect(loop, mode, resp)
|
||||
if resp == -1:
|
||||
self.error("USB desync, please rerun command !")
|
||||
self.exit()
|
||||
# print((mode, resp))
|
||||
self.cdc.timeout = 1500
|
||||
conninfo = self.doconnect(loop)
|
||||
mode = conninfo["mode"]
|
||||
if mode == "sahara":
|
||||
if resp is None:
|
||||
if mode == "sahara":
|
||||
print("Sahara in error state, resetting ...")
|
||||
self.sahara.cmd_reset()
|
||||
data = self.cdc.read(5)
|
||||
self.debug(hexlify(data).decode('utf-8'))
|
||||
self.exit()
|
||||
elif "mode" in resp:
|
||||
mode = resp["mode"]
|
||||
if mode == self.sahara.sahara_mode.SAHARA_MODE_MEMORY_DEBUG:
|
||||
cmd = conninfo["cmd"]
|
||||
data = conninfo["data"]
|
||||
if cmd == cmd_t.SAHARA_END_TRANSFER:
|
||||
if data.status == sahara_mode_t.SAHARA_MODE_MEMORY_DEBUG:
|
||||
if args["memorydump"]:
|
||||
time.sleep(0.5)
|
||||
print("Device is in memory dump mode, dumping memory")
|
||||
|
@ -303,54 +325,41 @@ class main(metaclass=LogBase):
|
|||
print("Error, couldn't find suitable enprg/nprg loader :(")
|
||||
self.exit()
|
||||
else:
|
||||
print("Device is in EDL mode .. continuing.")
|
||||
self.cdc.timeout = None
|
||||
sahara_info = self.sahara.cmd_info()
|
||||
if sahara_info:
|
||||
mode, resp = self.sahara.connect()
|
||||
if mode == "sahara":
|
||||
mode = self.sahara.upload_loader()
|
||||
if mode == "firehose":
|
||||
if "enprg" in self.sahara.programmer.lower():
|
||||
mode = "enandprg"
|
||||
elif "nprg" in self.sahara.programmer.lower():
|
||||
mode = "nandprg"
|
||||
if mode != "":
|
||||
if mode != "firehose":
|
||||
streaming = Streaming(self.cdc, self.sahara, self.__logger.level)
|
||||
if streaming.connect(1):
|
||||
print("Successfully uploaded programmer :)")
|
||||
mode = "nandprg"
|
||||
else:
|
||||
print("Device is in an unknown state")
|
||||
self.exit()
|
||||
else:
|
||||
print("Successfully uploaded programmer :)")
|
||||
else:
|
||||
print("No suitable loader found :(")
|
||||
self.exit()
|
||||
else:
|
||||
print("Device is in an unknown sahara state, resetting")
|
||||
print("resp={0}".format(resp))
|
||||
self.sahara.cmd_reset()
|
||||
self.exit()
|
||||
else:
|
||||
print("Device is in an unknown state")
|
||||
self.exit()
|
||||
else:
|
||||
self.sahara.bit64 = True
|
||||
|
||||
if mode == "firehose":
|
||||
self.cdc.timeout = None
|
||||
cmd = parse_cmd(args)
|
||||
if cmd == 'provision':
|
||||
args["--memory"] = 'ufs'
|
||||
args["--skipstorageinit"] = 1
|
||||
fh = firehose_client(args, self.cdc, self.sahara, self.__logger.level, print)
|
||||
options = parse_option(args)
|
||||
if cmd != "":
|
||||
fh.handle_firehose(cmd, options)
|
||||
elif mode == "nandprg" or mode == "enandprg" or mode == "load_nandprg" or mode == "load_enandprg":
|
||||
self.error("Device is in an unknown sahara state, rebooting...")
|
||||
self.sahara.cmd_reset()
|
||||
data = self.cdc.read(timeout=None)
|
||||
self.debug(hexlify(data).decode('utf-8'))
|
||||
self.exit()
|
||||
elif cmd == cmd_t.SAHARA_HELLO_REQ:
|
||||
sahara_info = self.sahara.cmd_info()
|
||||
if sahara_info is not None:
|
||||
resp = self.sahara.connect()
|
||||
mode = resp["mode"]
|
||||
if "data" in resp:
|
||||
data = resp["data"]
|
||||
if mode == "sahara":
|
||||
mode = self.sahara.upload_loader()
|
||||
else:
|
||||
print("Error on sahara handshake, resetting.")
|
||||
self.sahara.cmd_reset()
|
||||
sys.exit(1)
|
||||
if mode == "error":
|
||||
print("Connection detected, quiting.")
|
||||
sys.exit(1)
|
||||
elif mode == "firehose":
|
||||
if "enprg" in self.sahara.programmer.lower():
|
||||
mode = "enandprg"
|
||||
elif "nprg" in self.sahara.programmer.lower():
|
||||
mode = "nandprg"
|
||||
if mode != "firehose":
|
||||
streaming = Streaming(self.cdc, self.sahara, self.__logger.level)
|
||||
if streaming.connect(1):
|
||||
print("Successfully uploaded programmer :)")
|
||||
mode = "nandprg"
|
||||
else:
|
||||
print("No suitable loader found :(")
|
||||
self.exit()
|
||||
if mode != "firehose":
|
||||
sc = streaming_client(args, self.cdc, self.sahara, self.__logger.level, print)
|
||||
cmd = parse_cmd(args)
|
||||
options = parse_option(args)
|
||||
|
@ -360,10 +369,17 @@ class main(metaclass=LogBase):
|
|||
options["<mode>"] = 0
|
||||
sc.handle_streaming(cmd, options)
|
||||
else:
|
||||
self.error("Sorry, couldn't talk to Sahara, please reboot the device !")
|
||||
|
||||
self.exit()
|
||||
|
||||
self.cdc.timeout = None
|
||||
cmd = parse_cmd(args)
|
||||
if cmd == 'provision':
|
||||
args["--memory"] = 'ufs'
|
||||
args["--skipstorageinit"] = 1
|
||||
fh = firehose_client(args, self.cdc, self.sahara, self.__logger.level, print)
|
||||
options = parse_option(args)
|
||||
if cmd != "":
|
||||
self.info("Trying to connect to firehose loader ...")
|
||||
if fh.connect(sahara):
|
||||
fh.handle_firehose(cmd, options)
|
||||
|
||||
if __name__ == '__main__':
|
||||
base = main()
|
||||
|
|
|
@ -141,10 +141,10 @@ msmids = {
|
|||
0x13F0E1: "bitra_SDM", # soc_vers 0x6012 SDM690
|
||||
0x1410E1: "bitra_SDA",
|
||||
0x1590E1: "cedros", # soc_vers 0x6017
|
||||
0x1360E1: "kamorta", # soc_vers 0x9002 SnapDragon 460 SM4350, bengal
|
||||
0x1370E1: "kamorta_P", # soc_vers 0x9002 SnapDragon 460 SM4350, bengal
|
||||
0x1730E1: "kamorta_IoT_modem", # soc_vers 0x9002 SnapDragon 460 SM4350, bengal
|
||||
0x1740E1: "kamorta_IoT_APQ", # soc_vers 0x9002 SnapDragon 460 SM4350, bengal
|
||||
0x1360E1: "kamorta", # soc_vers 0x9002 SnapDragon 460 SM4350
|
||||
0x1370E1: "kamorta_P", # soc_vers 0x9002 SnapDragon 460 SM4350
|
||||
0x1730E1: "kamorta_IoT_modem", # soc_vers 0x9002 SnapDragon 460 SM4350
|
||||
0x1740E1: "kamorta_IoT_APQ", # soc_vers 0x9002 SnapDragon 460 SM4350
|
||||
0x1350E1: "lahaina", # soc_vers 0x600F sm8350, SDM875
|
||||
0x1420E1: "lahaina_premier",
|
||||
0x14A0E1: "SC8280X", # soc_vers 0x6014, makena
|
||||
|
@ -189,7 +189,7 @@ msmids = {
|
|||
0x0B80E1: "sc8180x", # Snapdragon 8CX, soc_vers 0x6006
|
||||
0x1560E1: "SM8250", # HDK 8250
|
||||
0x1510E1: "SA2150p",
|
||||
0x14D0E1: "SDM662", # sm6115
|
||||
0x14D0E1: "SDM662", # sm6115, bengal
|
||||
0x18A0E1: "fraser", #soc_vers 0x600D
|
||||
0x1920E1: "sm7325", #soc_vers 0x6018
|
||||
0x1930E1: "sc7280", #soc_vers 0x6018
|
||||
|
|
|
@ -23,15 +23,17 @@ except ImportError as e:
|
|||
xiaomi = None
|
||||
pass
|
||||
|
||||
|
||||
class modules(metaclass=LogBase):
|
||||
def __init__(self, fh, serial, supported_functions, loglevel, devicemodel, args):
|
||||
self.fh = fh
|
||||
self.args = args
|
||||
self.serial = serial
|
||||
self.error = self.__logger.error
|
||||
self.info = self.__logger.info
|
||||
self.supported_functions = supported_functions
|
||||
self.__logger.setLevel(loglevel)
|
||||
if loglevel==logging.DEBUG:
|
||||
if loglevel == logging.DEBUG:
|
||||
logfilename = "log.txt"
|
||||
fh = logging.FileHandler(logfilename)
|
||||
self.__logger.addHandler(fh)
|
||||
|
@ -45,10 +47,10 @@ class modules(metaclass=LogBase):
|
|||
self.ops = None
|
||||
try:
|
||||
self.ops = oneplus(fh=self.fh, projid=self.devicemodel, serial=self.serial,
|
||||
supported_functions=self.supported_functions, args=self.args,loglevel=loglevel)
|
||||
supported_functions=self.supported_functions, args=self.args, loglevel=loglevel)
|
||||
except Exception as e:
|
||||
pass
|
||||
self.xiaomi=None
|
||||
self.xiaomi = None
|
||||
try:
|
||||
self.xiaomi = xiaomi(fh=self.fh)
|
||||
except Exception as e:
|
||||
|
@ -84,7 +86,7 @@ class modules(metaclass=LogBase):
|
|||
options[option[0]] = option[1]
|
||||
else:
|
||||
options[args[i]] = True
|
||||
if command=="":
|
||||
if command == "":
|
||||
print("Valid commands are:\noemunlock\n")
|
||||
return False
|
||||
if self.generic is not None and command == "oemunlock":
|
||||
|
@ -96,4 +98,3 @@ class modules(metaclass=LogBase):
|
|||
self.error("Unknown mode given. Available are: enable, disable.")
|
||||
return False
|
||||
return self.generic.oem_unlock(enable)
|
||||
return False
|
||||
|
|
|
@ -143,7 +143,7 @@ class oneplus(metaclass=LogBase):
|
|||
lun = res[1]
|
||||
rpartition = res[2]
|
||||
data = self.fh.cmd_read_buffer(lun, rpartition.sector, 1, False)
|
||||
value = data[24:24 + 5]
|
||||
value = data.data[24:24 + 5]
|
||||
try:
|
||||
test = int(value.decode('utf-8'))
|
||||
self.info("Oneplus protection with prjid %d detected" % test)
|
||||
|
@ -155,7 +155,7 @@ class oneplus(metaclass=LogBase):
|
|||
logfilename = "log.txt"
|
||||
filehandler = logging.FileHandler(logfilename)
|
||||
self.__logger.addHandler(filehandler)
|
||||
self.ops_parm = None
|
||||
self.ops_parm = None
|
||||
self.ops = self.convert_projid(fh, projid, serial)
|
||||
|
||||
def getprodkey(self, projid):
|
||||
|
@ -227,9 +227,6 @@ class oneplus(metaclass=LogBase):
|
|||
if self.ops.demacia():
|
||||
return self.ops.demacia()
|
||||
|
||||
def enable_ops(self, data, enable, projid, serial):
|
||||
return None
|
||||
|
||||
def addpatch(self):
|
||||
if "setprojmodel" in self.supported_functions or "setswprojmodel" in self.supported_functions:
|
||||
pk, token = self.ops.generatetoken(True)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -68,6 +68,8 @@ class firehose_client(metaclass=LogBase):
|
|||
devicemodel=devicemodel, serial=sahara.serial, skipresponse=skipresponse,
|
||||
luns=self.getluns(arguments), args=arguments)
|
||||
self.connected = False
|
||||
|
||||
def connect(self, sahara):
|
||||
self.firehose.connect()
|
||||
if "hwid" in dir(sahara):
|
||||
if sahara.hwid is not None:
|
||||
|
@ -88,18 +90,22 @@ class firehose_client(metaclass=LogBase):
|
|||
elif type == memory_type.ufs:
|
||||
self.cfg.MemoryName = "UFS"
|
||||
self.warning("Based on the chipset, we assume " +
|
||||
self.cfg.MemoryName + " as default memory type..., if it fails, try using " +
|
||||
"--memory\" with \"UFS\",\"NAND\" or \"spinor\" instead !")
|
||||
self.cfg.MemoryName + " as default memory type..., if it fails, try using " +
|
||||
"--memory\" with \"UFS\",\"NAND\" or \"spinor\" instead !")
|
||||
elif socid in sochw:
|
||||
self.target_name = sochw[socid].split(",")[0]
|
||||
|
||||
# We assume ufs is fine (hopefully), set it as default
|
||||
if self.cfg.MemoryName == "":
|
||||
self.warning(
|
||||
"No --memory option set, we assume \"eMMC\" as default ..., if it fails, try using \"--memory\" " +
|
||||
"with \"UFS\",\"NAND\" or \"spinor\" instead !")
|
||||
self.cfg.MemoryName = "eMMC"
|
||||
|
||||
if "ufs" in self.firehose.supported_functions:
|
||||
self.warning(
|
||||
"No --memory option set, we assume \"UFS\" as default ..., if it fails, try using \"--memory\" " +
|
||||
"with \"UFS\",\"NAND\" or \"spinor\" instead !")
|
||||
self.cfg.MemoryName = "UFS"
|
||||
else:
|
||||
self.warning(
|
||||
"No --memory option set, we assume \"eMMC\" as default ..., if it fails, try using \"--memory\" " +
|
||||
"with \"UFS\",\"NAND\" or \"spinor\" instead !")
|
||||
self.cfg.MemoryName = "eMMC"
|
||||
if self.firehose.configure(0):
|
||||
funcs = "Supported functions:\n-----------------\n"
|
||||
for function in self.firehose.supported_functions:
|
||||
|
@ -116,6 +122,7 @@ class firehose_client(metaclass=LogBase):
|
|||
devicemodel=self.firehose.devicemodel, args=self.arguments)
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
self.firehose.modules = None
|
||||
return self.connected
|
||||
|
||||
def check_cmd(self, func):
|
||||
if not self.firehose.supported_functions:
|
||||
|
@ -167,16 +174,15 @@ class firehose_client(metaclass=LogBase):
|
|||
return True
|
||||
|
||||
def get_storage_info(self):
|
||||
if "getstorageinfo" in self.firehose.supported_functions:
|
||||
storageinfo = self.firehose.cmd_getstorageinfo()
|
||||
for info in storageinfo:
|
||||
if "storage_info" in info:
|
||||
rs = info.replace("INFO: ", "")
|
||||
field = json.loads(rs)
|
||||
if "storage_info" in field:
|
||||
info = field["storage_info"]
|
||||
return info
|
||||
return None
|
||||
storageinfo = self.firehose.cmd_getstorageinfo()
|
||||
for info in storageinfo:
|
||||
if "storage_info" in info:
|
||||
rs = info.replace("INFO: ", "")
|
||||
field = json.loads(rs)
|
||||
if "storage_info" in field:
|
||||
info = field["storage_info"]
|
||||
return info
|
||||
return False
|
||||
|
||||
def handle_firehose(self, cmd, options):
|
||||
if cmd == "gpt":
|
||||
|
@ -229,10 +235,10 @@ class firehose_client(metaclass=LogBase):
|
|||
return False
|
||||
i = 0
|
||||
for partition in partitions:
|
||||
if partition=="gpt":
|
||||
if partition == "gpt":
|
||||
luns = self.getluns(options)
|
||||
for lun in luns:
|
||||
partfilename=filenames[i]+".lun%d" % lun
|
||||
partfilename = filenames[i] + ".lun%d" % lun
|
||||
if self.firehose.cmd_read(lun, 0, 32, partfilename):
|
||||
self.printer(
|
||||
f"Dumped sector {str(0)} with sector count {str(32)} " +
|
||||
|
@ -302,10 +308,9 @@ class firehose_client(metaclass=LogBase):
|
|||
for skippart in skip:
|
||||
filtered = fnmatch.filter(guid_gpt.partentries, skippart)
|
||||
skipped.append(filtered)
|
||||
for selpart in guid_gpt.partentries:
|
||||
partition = guid_gpt.partentries[selpart]
|
||||
partitionname = partition.name
|
||||
if partition.name in skipped:
|
||||
for partitionname in guid_gpt.partentries:
|
||||
partition = guid_gpt.partentries[partitionname]
|
||||
if partitionname in skipped:
|
||||
continue
|
||||
filename = os.path.join(storedir, partitionname + ".bin")
|
||||
self.info(
|
||||
|
@ -319,33 +324,34 @@ class firehose_client(metaclass=LogBase):
|
|||
if not self.check_param(["<filename>"]):
|
||||
return False
|
||||
filename = options["<filename>"]
|
||||
storageinfo = self.get_storage_info()
|
||||
if storageinfo is not None and self.cfg.MemoryName.lower() in ["spinor" , "nand"]:
|
||||
totalsectors = None
|
||||
if "total_blocks" in storageinfo:
|
||||
totalsectors = storageinfo["total_blocks"]
|
||||
if "num_physical" in storageinfo:
|
||||
num_physical = storageinfo["num_physical"]
|
||||
luns = [0]
|
||||
if num_physical > 0:
|
||||
luns=[]
|
||||
for i in range(num_physical):
|
||||
luns.append(i)
|
||||
#storageinfo = self.firehose.parse_storage()
|
||||
if self.cfg.MemoryName.lower() in ["spinor", "nand"]:
|
||||
luns = [0]
|
||||
totalsectors = (self.cfg.block_size * self.cfg.total_blocks) // self.cfg.SECTOR_SIZE_IN_BYTES
|
||||
if self.cfg.num_physical > 0:
|
||||
luns = []
|
||||
for i in range(self.cfg.num_physical):
|
||||
luns.append(i)
|
||||
elif 99 > self.cfg.maxlun > 0:
|
||||
luns = []
|
||||
for i in range(self.cfg.maxlun):
|
||||
luns.append(i)
|
||||
if totalsectors is not None:
|
||||
for lun in luns:
|
||||
buffer=self.firehose.cmd_read_buffer(physical_partition_number=lun,
|
||||
start_sector=0, num_partition_sectors=1, display=False)
|
||||
storageinfo = self.get_storage_info()
|
||||
if "total_blocks" in storageinfo:
|
||||
totalsectors = storageinfo["total_blocks"]
|
||||
if len(luns) > 1:
|
||||
sfilename = filename + f".lun{str(lun)}"
|
||||
else:
|
||||
sfilename = filename
|
||||
self.printer(f"Dumping sector 0 with sector count {str(totalsectors)} as {filename}.")
|
||||
if self.firehose.cmd_read(lun, 0, totalsectors, sfilename):
|
||||
self.printer(
|
||||
f"Dumped sector 0 with sector count {str(totalsectors)} as {filename}.")
|
||||
buffer = self.firehose.cmd_read_buffer(physical_partition_number=lun,
|
||||
start_sector=0, num_partition_sectors=1, display=False)
|
||||
if self.get_storage_info():
|
||||
totalsectors = (self.cfg.block_size *
|
||||
self.cfg.total_blocks ) // self.cfg.SECTOR_SIZE_IN_BYTES
|
||||
|
||||
if len(luns) > 1:
|
||||
sfilename = filename + f".lun{str(lun)}"
|
||||
else:
|
||||
sfilename = filename
|
||||
self.printer(f"Dumping sector 0 with sector count {str(totalsectors)} as {filename}.")
|
||||
if self.firehose.cmd_read(lun, 0, totalsectors, sfilename):
|
||||
self.printer(
|
||||
f"Dumped sector 0 with sector count {str(totalsectors)} as {filename}.")
|
||||
else:
|
||||
luns = self.getluns(options)
|
||||
for lun in luns:
|
||||
|
@ -356,11 +362,17 @@ class firehose_client(metaclass=LogBase):
|
|||
break
|
||||
if len(luns) > 1:
|
||||
sfilename = filename + f".lun{str(lun)}"
|
||||
self.printer(f"Dumping lun {lun} with sector count {str(guid_gpt.totalsectors)} as {filename}.")
|
||||
else:
|
||||
sfilename = filename
|
||||
self.printer(f"Dumping sector 0 with sector count {str(guid_gpt.totalsectors)} as {filename}.")
|
||||
self.printer(f"Dumping flash with sector count {str(guid_gpt.totalsectors)} as {filename}.")
|
||||
|
||||
if self.firehose.cmd_read(lun, 0, guid_gpt.totalsectors, sfilename):
|
||||
self.printer(f"Dumped sector 0 with sector count {str(guid_gpt.totalsectors)} as {filename}.")
|
||||
if len(luns) > 1:
|
||||
self.printer(f"Dumped lun {lun} with sector count " +
|
||||
f"{str(guid_gpt.totalsectors)} as {filename}.")
|
||||
else:
|
||||
self.printer(f"Dumped flash with sector count {str(guid_gpt.totalsectors)} as {filename}.")
|
||||
return True
|
||||
elif cmd == "pbl":
|
||||
if not self.check_param(["<filename>"]):
|
||||
|
@ -465,8 +477,9 @@ class firehose_client(metaclass=LogBase):
|
|||
break
|
||||
pnames = ["userdata2", "metadata", "userdata", "reserved1", "reserved2", "reserved3"]
|
||||
for pname in pnames:
|
||||
if pname in guid_gpt.partentries:
|
||||
partition = guid_gpt.partentries[pname]
|
||||
for partition in guid_gpt.partentries:
|
||||
if partition.name != pname:
|
||||
continue
|
||||
self.printer(f"Detected partition: {partition.name}")
|
||||
data = self.firehose.cmd_read_buffer(lun,
|
||||
partition.sector +
|
||||
|
@ -602,7 +615,10 @@ class firehose_client(metaclass=LogBase):
|
|||
else:
|
||||
return False
|
||||
elif cmd == "reset":
|
||||
return self.firehose.cmd_reset()
|
||||
mode = "reset"
|
||||
if not self.check_param(["<resetmode>"]):
|
||||
return False
|
||||
return self.firehose.cmd_reset(options["<resetmode>"])
|
||||
elif cmd == "nop":
|
||||
if not self.check_cmd("nop"):
|
||||
self.error("Nop command isn't supported by edl loader")
|
||||
|
@ -617,6 +633,11 @@ class firehose_client(metaclass=LogBase):
|
|||
return False
|
||||
else:
|
||||
return self.firehose.cmd_setbootablestoragedrive(int(options["<lun>"]))
|
||||
elif cmd == "setactiveslot":
|
||||
if not self.check_param(["<slot>"]):
|
||||
return False
|
||||
else:
|
||||
return self.firehose.cmd_setactiveslot(options["<slot>"])
|
||||
elif cmd == "getstorageinfo":
|
||||
if not self.check_cmd("getstorageinfo"):
|
||||
self.error("getstorageinfo command isn't supported by edl loader")
|
||||
|
@ -668,9 +689,9 @@ class firehose_client(metaclass=LogBase):
|
|||
for lun in fpartitions:
|
||||
for partition in fpartitions[lun]:
|
||||
if self.cfg.MemoryName == "emmc":
|
||||
self.error("\t" + partition)
|
||||
self.error("\t" + partition.name)
|
||||
else:
|
||||
self.error(lun + ":\t" + partition)
|
||||
self.error(lun + ":\t" + partition.name)
|
||||
return False
|
||||
elif cmd == "wl":
|
||||
if not self.check_param(["<directory>"]):
|
||||
|
@ -780,7 +801,8 @@ class firehose_client(metaclass=LogBase):
|
|||
f"with sector count {str(partition.sectors)}.")
|
||||
return True
|
||||
else:
|
||||
self.printer(f"Couldn't erase partition {partitionname}. Either wrong memorytype given or no gpt partition.")
|
||||
self.printer(
|
||||
f"Couldn't erase partition {partitionname}. Either wrong memorytype given or no gpt partition.")
|
||||
return False
|
||||
self.error(f"Error: Couldn't detect partition: {partitionname}")
|
||||
return False
|
||||
|
|
|
@ -1,18 +1,192 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) B.Kerler 2018-2021
|
||||
import argparse
|
||||
# (c) B.Kerler 2018-2021 MIT License
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import colorama
|
||||
import copy
|
||||
import logging
|
||||
import logging.config
|
||||
from enum import Enum
|
||||
from struct import unpack, pack
|
||||
from binascii import hexlify
|
||||
from struct import calcsize, unpack, pack
|
||||
from io import BytesIO
|
||||
|
||||
try:
|
||||
from edlclient.Library.utils import LogBase, structhelper
|
||||
except:
|
||||
from utils import LogBase, structhelper
|
||||
class ColorFormatter(logging.Formatter):
|
||||
LOG_COLORS = {
|
||||
logging.ERROR: colorama.Fore.RED,
|
||||
logging.DEBUG: colorama.Fore.LIGHTMAGENTA_EX,
|
||||
logging.WARNING: colorama.Fore.YELLOW,
|
||||
}
|
||||
|
||||
def format(self, record, *args, **kwargs):
|
||||
# if the corresponding logger has children, they may receive modified
|
||||
# record, so we want to keep it intact
|
||||
new_record = copy.copy(record)
|
||||
if new_record.levelno in self.LOG_COLORS:
|
||||
pad = ""
|
||||
if new_record.name != "root":
|
||||
print(new_record.name)
|
||||
pad = "[LIB]: "
|
||||
# we want levelname to be in different color, so let"s modify it
|
||||
new_record.msg = "{pad}{color_begin}{msg}{color_end}".format(
|
||||
pad=pad,
|
||||
msg=new_record.msg,
|
||||
color_begin=self.LOG_COLORS[new_record.levelno],
|
||||
color_end=colorama.Style.RESET_ALL,
|
||||
)
|
||||
# now we can let standart formatting take care of the rest
|
||||
return super(ColorFormatter, self).format(new_record, *args, **kwargs)
|
||||
|
||||
|
||||
class LogBase(type):
|
||||
debuglevel = logging.root.level
|
||||
|
||||
def __init__(cls, *args):
|
||||
super().__init__(*args)
|
||||
logger_attribute_name = "_" + cls.__name__ + "__logger"
|
||||
logger_debuglevel_name = "_" + cls.__name__ + "__debuglevel"
|
||||
logger_name = ".".join([c.__name__ for c in cls.mro()[-2::-1]])
|
||||
log_config = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"root": {
|
||||
"()": ColorFormatter,
|
||||
"format": "%(name)s - %(message)s",
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
"root": {
|
||||
# "level": cls.__logger.level,
|
||||
"formatter": "root",
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": "ext://sys.stdout",
|
||||
}
|
||||
},
|
||||
"loggers": {
|
||||
"": {
|
||||
"handlers": ["root"],
|
||||
# "level": cls.debuglevel,
|
||||
"propagate": False
|
||||
}
|
||||
},
|
||||
}
|
||||
logging.config.dictConfig(log_config)
|
||||
logger = logging.getLogger(logger_name)
|
||||
|
||||
setattr(cls, logger_attribute_name, logger)
|
||||
setattr(cls, logger_debuglevel_name, cls.debuglevel)
|
||||
cls.logsetup = logsetup
|
||||
|
||||
|
||||
def logsetup(self, logger, loglevel):
|
||||
self.info = logger.info
|
||||
self.debug = logger.debug
|
||||
self.error = logger.error
|
||||
self.warning = logger.warning
|
||||
if loglevel == logging.DEBUG:
|
||||
logfilename = os.path.join("logs", "log.txt")
|
||||
if os.path.exists(logfilename):
|
||||
try:
|
||||
os.remove(logfilename)
|
||||
except:
|
||||
pass
|
||||
fh = logging.FileHandler(logfilename, encoding="utf-8")
|
||||
logger.addHandler(fh)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
else:
|
||||
logger.setLevel(logging.INFO)
|
||||
self.loglevel = loglevel
|
||||
return logger
|
||||
|
||||
|
||||
def read_object(data: object, definition: object) -> object:
|
||||
"""
|
||||
Unpacks a structure using the given data and definition.
|
||||
"""
|
||||
obj = {}
|
||||
object_size = 0
|
||||
pos = 0
|
||||
for (name, stype) in definition:
|
||||
object_size += calcsize(stype)
|
||||
obj[name] = unpack(stype, data[pos:pos + calcsize(stype)])[0]
|
||||
pos += calcsize(stype)
|
||||
obj["object_size"] = object_size
|
||||
obj["raw_data"] = data
|
||||
return obj
|
||||
|
||||
|
||||
class structhelper:
|
||||
pos = 0
|
||||
|
||||
def __init__(self, data, pos=0):
|
||||
self.pos = 0
|
||||
self.data = data
|
||||
|
||||
def qword(self, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + "Q", self.data[self.pos:self.pos + 8])[0]
|
||||
self.pos += 8
|
||||
return dat
|
||||
|
||||
def dword(self, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + "I", self.data[self.pos:self.pos + 4])[0]
|
||||
self.pos += 4
|
||||
return dat
|
||||
|
||||
def dwords(self, dwords=1, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + str(dwords) + "I", self.data[self.pos:self.pos + 4 * dwords])
|
||||
self.pos += 4 * dwords
|
||||
return dat
|
||||
|
||||
def qwords(self, qwords=1, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + str(qwords) + "Q", self.data[self.pos:self.pos + 8 * qwords])
|
||||
self.pos += 8 * qwords
|
||||
return dat
|
||||
|
||||
def short(self, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + "H", self.data[self.pos:self.pos + 2])[0]
|
||||
self.pos += 2
|
||||
return dat
|
||||
|
||||
def shorts(self, shorts, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + str(shorts) + "H", self.data[self.pos:self.pos + 2 * shorts])
|
||||
self.pos += 2 * shorts
|
||||
return dat
|
||||
|
||||
def bytes(self, rlen=1):
|
||||
dat = self.data[self.pos:self.pos + rlen]
|
||||
self.pos += rlen
|
||||
if rlen == 1: return dat[0]
|
||||
return dat
|
||||
|
||||
def string(self, rlen=1):
|
||||
dat = self.data[self.pos:self.pos + rlen]
|
||||
self.pos += rlen
|
||||
return dat
|
||||
|
||||
def getpos(self):
|
||||
return self.pos
|
||||
|
||||
def seek(self, pos):
|
||||
self.pos = pos
|
||||
|
||||
|
||||
AB_FLAG_OFFSET = 6
|
||||
AB_PARTITION_ATTR_SLOT_ACTIVE = (0x1 << 2)
|
||||
AB_PARTITION_ATTR_BOOT_SUCCESSFUL = (0x1 << 6)
|
||||
AB_PARTITION_ATTR_UNBOOTABLE = (0x1 << 7)
|
||||
AB_SLOT_ACTIVE_VAL = 0x3F
|
||||
AB_SLOT_INACTIVE_VAL = 0x0
|
||||
AB_SLOT_ACTIVE = 1
|
||||
AB_SLOT_INACTIVE = 0
|
||||
|
||||
|
||||
class gpt(metaclass=LogBase):
|
||||
|
@ -43,6 +217,10 @@ class gpt(metaclass=LogBase):
|
|||
self.flags = sh.qword()
|
||||
self.name = sh.string(72)
|
||||
|
||||
def create(self):
|
||||
val = pack("16s16sQQQ72s", self.type, self.unique, self.first_lba, self.last_lba, self.flags, self.name)
|
||||
return val
|
||||
|
||||
class efi_type(Enum):
|
||||
EFI_UNUSED = 0x00000000
|
||||
EFI_MBR = 0x024DEE41
|
||||
|
@ -139,18 +317,19 @@ class gpt(metaclass=LogBase):
|
|||
self.totalsectors = None
|
||||
self.header = None
|
||||
self.sectorsize = None
|
||||
self.partentries = {}
|
||||
self.partentries = []
|
||||
|
||||
self.error = self.__logger.error
|
||||
self.__logger.setLevel(loglevel)
|
||||
if loglevel == logging.DEBUG:
|
||||
logfilename = "log.txt"
|
||||
fh = logging.FileHandler(logfilename)
|
||||
fh = logging.FileHandler(logfilename, encoding="utf-8")
|
||||
self.__logger.addHandler(fh)
|
||||
|
||||
def parseheader(self, gptdata, sectorsize=512):
|
||||
return self.gpt_header(gptdata[sectorsize:sectorsize + 0x5C])
|
||||
|
||||
|
||||
def parse(self, gptdata, sectorsize=512):
|
||||
self.header = self.gpt_header(gptdata[sectorsize:sectorsize + 0x5C])
|
||||
self.sectorsize = sectorsize
|
||||
|
@ -176,6 +355,7 @@ class gpt(metaclass=LogBase):
|
|||
sectors = 0
|
||||
type = b""
|
||||
name = ""
|
||||
entryoffset = 0
|
||||
|
||||
num_part_entries = self.header.num_part_entries
|
||||
|
||||
|
@ -194,6 +374,7 @@ class gpt(metaclass=LogBase):
|
|||
pa.sector = partentry.first_lba
|
||||
pa.sectors = partentry.last_lba - partentry.first_lba + 1
|
||||
pa.flags = partentry.flags
|
||||
pa.entryoffset = start + (idx * entrysize)
|
||||
type = int(unpack("<I", partentry.type[0:0x4])[0])
|
||||
try:
|
||||
pa.type = self.efi_type(type).name
|
||||
|
@ -211,11 +392,12 @@ class gpt(metaclass=LogBase):
|
|||
|
||||
def tostring(self):
|
||||
mstr = "\nGPT Table:\n-------------\n"
|
||||
for selpart in self.partentries:
|
||||
partition=self.partentries[selpart]
|
||||
mstr += ("{:20} Offset 0x{:016x}, Length 0x{:016x}, Flags 0x{:08x}, UUID {}, Type {}\n".format(
|
||||
for partitionname in self.partentries:
|
||||
partition = self.partentries[partitionname]
|
||||
active = ((partition.flags >> (AB_FLAG_OFFSET*8))&0xFF) & AB_PARTITION_ATTR_SLOT_ACTIVE == AB_PARTITION_ATTR_SLOT_ACTIVE
|
||||
mstr += ("{:20} Offset 0x{:016x}, Length 0x{:016x}, Flags 0x{:016x}, UUID {}, Type {}, Active {}\n".format(
|
||||
partition.name + ":", partition.sector * self.sectorsize, partition.sectors * self.sectorsize,
|
||||
partition.flags, partition.unique, partition.type))
|
||||
partition.flags, partition.unique, partition.type, active))
|
||||
mstr += ("\nTotal disk size:0x{:016x}, sectors:0x{:016x}\n".format(self.totalsectors * self.sectorsize,
|
||||
self.totalsectors))
|
||||
return mstr
|
||||
|
@ -227,8 +409,7 @@ class gpt(metaclass=LogBase):
|
|||
partofsingleimage = "false"
|
||||
readbackverify = "false"
|
||||
sparse = "false"
|
||||
for selpart in self.partentries:
|
||||
partition = self.partentries[selpart]
|
||||
for partition in self.partentries:
|
||||
filename = partition.name + ".bin"
|
||||
mstr += f"\t<program SECTOR_SIZE_IN_BYTES=\"{sectorsize}\" " + \
|
||||
f"file_sector_offset=\"0\" " \
|
||||
|
@ -270,7 +451,7 @@ class gpt(metaclass=LogBase):
|
|||
f"start_byte_hex=\"({sectorsize}*NUM_DISK_SECTORS)-{sectorsize * sectors}.\" " + \
|
||||
f"start_sector=\"NUM_DISK_SECTORS-{sectors}.\"/>\n"
|
||||
mstr += "</data>"
|
||||
wf.write(bytes(mstr, 'utf-8'))
|
||||
wf.write(bytes(mstr, "utf-8"))
|
||||
print(f"Wrote partition xml as {fname}")
|
||||
|
||||
def print_gptfile(self, filename):
|
||||
|
@ -294,23 +475,72 @@ class gpt(metaclass=LogBase):
|
|||
res = self.print_gptfile(os.path.join("TestFiles", "gpt_sm8180x.bin"))
|
||||
assert res, "GPT Partition wasn't decoded properly"
|
||||
|
||||
def patch(self, data:bytes, partitionname="boot", active: bool = True):
|
||||
try:
|
||||
rf = BytesIO(data)
|
||||
for sectorsize in [512, 4096]:
|
||||
result = self.parse(data, sectorsize)
|
||||
if result:
|
||||
for rname in self.partentries:
|
||||
if partitionname.lower() == rname.lower():
|
||||
partition = self.partentries[rname]
|
||||
rf.seek(partition.entryoffset)
|
||||
sdata = rf.read(self.header.part_entry_size)
|
||||
partentry = self.gpt_partition(sdata)
|
||||
flags = partentry.flags
|
||||
if active:
|
||||
flags |= AB_PARTITION_ATTR_SLOT_ACTIVE << (AB_FLAG_OFFSET*8)
|
||||
else:
|
||||
flags |= AB_PARTITION_ATTR_UNBOOTABLE << (AB_FLAG_OFFSET*8)
|
||||
partentry.flags = flags
|
||||
data = partentry.create()
|
||||
return data, partition.entryoffset
|
||||
break
|
||||
return None, None
|
||||
except Exception as e:
|
||||
self.error(str(e))
|
||||
return None, None
|
||||
|
||||
def get_flag(self, filename, imagename):
|
||||
if "." in imagename:
|
||||
imagename = imagename[:imagename.find(".")]
|
||||
try:
|
||||
with open(filename, "rb") as rf:
|
||||
if os.stat(filename).st_size > 0x200000:
|
||||
print("Error: GPT is too big or no GPT at all.")
|
||||
return None
|
||||
data = rf.read()
|
||||
return self.get_flag_data(data, imagename)
|
||||
except FileNotFoundError:
|
||||
print(f"File not found : {filename}")
|
||||
return None, None
|
||||
|
||||
def get_flag_data(self, gpt: bytes, imagename: str):
|
||||
for sectorsize in [512, 4096]:
|
||||
result = self.parse(gpt, sectorsize)
|
||||
if result:
|
||||
for partition in self.partentries:
|
||||
if imagename in partition.name.lower():
|
||||
return partition.sector, sectorsize
|
||||
return None, None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="GPT utils")
|
||||
subparsers = parser.add_subparsers(dest="command", help='sub-command help')
|
||||
parser.add_argument("image", help="The path of the GPT disk image")
|
||||
subparsers = parser.add_subparsers(dest="command", help="sub-command help")
|
||||
|
||||
parser_print = subparsers.add_parser("print", help="Print the gpt table")
|
||||
parser_print.add_argument("image", help="The path of the GPT disk image")
|
||||
|
||||
parser_test = subparsers.add_parser("test", help="Run self-test")
|
||||
|
||||
parser_patch = subparsers.add_parser("patch", help="Set active boot slot")
|
||||
parser_patch.add_argument("partition", help="Extract specific partitions (separated by comma)")
|
||||
parser_patch.add_argument("-active", action="store_true", help="Set bootable")
|
||||
parser_extract = subparsers.add_parser("extract", help="Extract the partitions")
|
||||
parser_extract.add_argument("image", help="The path of the GPT disk image")
|
||||
parser_extract.add_argument("-out", "-o", help="The path to extract the partitions")
|
||||
parser_extract.add_argument("-partition", "-p", help="Extract specific partitions (separated by comma)")
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.command not in ["print", "extract", "test"]:
|
||||
if args.command not in ["print", "extract", "test", "patch"]:
|
||||
parser.error("Command is mandatory")
|
||||
|
||||
gp = gpt()
|
||||
|
@ -321,6 +551,22 @@ if __name__ == "__main__":
|
|||
gp.print_gptfile(args.image)
|
||||
elif args.command == "test":
|
||||
gp.test_gpt()
|
||||
elif args.command == "patch":
|
||||
partitition = args.partition
|
||||
active = args.active
|
||||
filesize = os.stat(args.image).st_size
|
||||
with open(args.image, "rb") as rf:
|
||||
size = min(32 * 4096, filesize)
|
||||
data = bytearray(rf.read(size))
|
||||
pdata, offset = gp.patch(data,partitition, active=active)
|
||||
if data is not None:
|
||||
data[offset:offset + len(pdata)] = pdata
|
||||
wfilename = args.image + ".patched"
|
||||
with open(wfilename,"wb") as wf:
|
||||
wf.write(data)
|
||||
print(f"Successfully wrote patched gpt to {wfilename}")
|
||||
else:
|
||||
print("Error on setting bootable mode")
|
||||
elif args.command == "extract":
|
||||
if not os.path.exists(args.image):
|
||||
print(f"File {args.image} does not exist. Aborting.")
|
||||
|
@ -335,26 +581,33 @@ if __name__ == "__main__":
|
|||
ssize = sectorsize
|
||||
break
|
||||
if ssize is not None:
|
||||
for selpart in gp.partentries:
|
||||
partition = gp.partentries[selpart]
|
||||
if args.partition is not None:
|
||||
if partition != args.partition:
|
||||
continue
|
||||
name = partition.name
|
||||
start = partition.sector * ssize
|
||||
length = partition.sectors * ssize
|
||||
out = args.out
|
||||
if out is None:
|
||||
out = "."
|
||||
if not os.path.exists(out):
|
||||
os.makedirs(out)
|
||||
filename = os.path.join(out, name)
|
||||
rf.seek(start)
|
||||
bytestoread = length
|
||||
with open(filename, "wb", buffering=1024 * 1024) as wf:
|
||||
while bytestoread > 0:
|
||||
size = min(bytestoread, 0x200000)
|
||||
rf.read(size)
|
||||
wf.write(size)
|
||||
bytestoread -= size
|
||||
print(f"Extracting {name} to {filename} at {hex(start)}, length {hex(length)}")
|
||||
if args.partition == "gpt":
|
||||
print(f"Extracting gpt to gpt.bin at {hex(0)}, length {hex(32 * ssize)}")
|
||||
rf.seek(0)
|
||||
data = rf.read(32 * ssize)
|
||||
with open("gpt.bin", "wb") as wf:
|
||||
wf.write(data)
|
||||
else:
|
||||
for partition in gp.partentries:
|
||||
if args.partition is not None:
|
||||
if partition.name.lower() != args.partition:
|
||||
continue
|
||||
name = partition.name
|
||||
start = partition.sector * ssize
|
||||
length = partition.sectors * ssize
|
||||
out = args.out
|
||||
if out is None:
|
||||
out = "."
|
||||
else:
|
||||
if not os.path.exists(out):
|
||||
os.makedirs(out)
|
||||
filename = os.path.join(out, name) + ".bin"
|
||||
print(f"Extracting {name} to {filename} at {hex(start)}, length {hex(length)}")
|
||||
rf.seek(start)
|
||||
bytestoread = length
|
||||
with open(filename, "wb", buffering=1024 * 1024) as wf:
|
||||
while bytestoread > 0:
|
||||
size = min(bytestoread, 0x200000)
|
||||
data = rf.read(size)
|
||||
wf.write(data)
|
||||
bytestoread -= size
|
||||
|
|
|
@ -134,15 +134,15 @@ class hdlc:
|
|||
replybuf = bytearray()
|
||||
if timeout is None:
|
||||
timeout = self.timeout
|
||||
tmp = self.cdc.read(MAX_PACKET_LEN, timeout)
|
||||
tmp = self.cdc.read(timeout=timeout)
|
||||
if tmp == bytearray():
|
||||
return 0
|
||||
return b""
|
||||
if tmp == b"":
|
||||
return 0
|
||||
return b""
|
||||
retry = 0
|
||||
while tmp[-1] != 0x7E:
|
||||
time.sleep(0.01)
|
||||
tmp += self.cdc.read(MAX_PACKET_LEN, timeout)
|
||||
tmp += self.cdc.read(timeout=timeout)
|
||||
retry += 1
|
||||
if retry > 5:
|
||||
break
|
||||
|
@ -150,13 +150,15 @@ class hdlc:
|
|||
data = unescape(replybuf)
|
||||
# print(hexlify(data))
|
||||
if len(data) > 3:
|
||||
if data[0]==0x7E:
|
||||
data=data[1:]
|
||||
crc16val = crc16(0xFFFF, data[:-3])
|
||||
reccrc = int(data[-3]) + (int(data[-2]) << 8)
|
||||
if crc16val != reccrc:
|
||||
return -1
|
||||
else:
|
||||
time.sleep(0.01)
|
||||
data = self.cdc.read(MAX_PACKET_LEN, timeout)
|
||||
data = self.cdc.read(timeout=timeout)
|
||||
if len(data) > 3:
|
||||
crc16val = crc16(0xFFFF, data[:-3])
|
||||
reccrc = int(data[-3]) + (int(data[-2]) << 8)
|
||||
|
@ -169,15 +171,15 @@ class hdlc:
|
|||
replybuf = bytearray()
|
||||
if timeout is None:
|
||||
timeout = self.timeout
|
||||
tmp = self.cdc.read(MAX_PACKET_LEN, timeout)
|
||||
tmp = self.cdc.read(timeout=timeout)
|
||||
if tmp == bytearray():
|
||||
return 0
|
||||
return b""
|
||||
if tmp == b"":
|
||||
return 0
|
||||
return b""
|
||||
retry = 0
|
||||
while tmp[-1] != 0x7E:
|
||||
# time.sleep(0.05)
|
||||
tmp += self.cdc.read(MAX_PACKET_LEN, timeout)
|
||||
tmp += self.cdc.read(timeout=timeout)
|
||||
retry += 1
|
||||
if retry > 5:
|
||||
break
|
||||
|
@ -190,7 +192,7 @@ class hdlc:
|
|||
return data[:-3]
|
||||
else:
|
||||
time.sleep(0.5)
|
||||
data = self.cdc.read(MAX_PACKET_LEN, timeout)
|
||||
data = self.cdc.read(timeout=timeout)
|
||||
if len(data) > 3:
|
||||
# crc16val = self.crc16(0xFFFF, data[:-3])
|
||||
# reccrc = int(data[-3]) + (int(data[-2]) << 8)
|
||||
|
@ -212,6 +214,7 @@ class hdlc:
|
|||
if isinstance(outdata, str):
|
||||
outdata = bytes(outdata, 'utf-8')
|
||||
packet = convert_cmdbuf(bytearray(outdata))
|
||||
self.cdc.flush()
|
||||
if self.send_unframed_buf(packet, prefixflag):
|
||||
if nocrc:
|
||||
return self.receive_reply_nocrc()
|
||||
|
@ -229,12 +232,9 @@ class hdlc:
|
|||
if len(pktbuf) == 0:
|
||||
return
|
||||
logging.error("Error: %s " % descr)
|
||||
|
||||
if pktbuf[1] == 0x0e:
|
||||
pktbuf[-4] = 0
|
||||
# puts(pktbuf+2)
|
||||
ret = self.receive_reply()
|
||||
errorcode = unpack("<I", ret[2:2 + 4])
|
||||
logging.error("Error code = %08x\n\n", errorcode)
|
||||
else:
|
||||
print(hexlify(pktbuf))
|
||||
|
|
|
@ -245,6 +245,8 @@ class SettingsOpt:
|
|||
self.sectorsize = 512
|
||||
self.flash_mfr = ""
|
||||
self.flash_descr = ""
|
||||
self.flash_fid = 0
|
||||
self.flash_pid = 0
|
||||
self.IsWideFlash = 0
|
||||
self.badsector = 0
|
||||
self.badflag = 0
|
||||
|
@ -559,7 +561,8 @@ class NandDevice:
|
|||
|
||||
fid = (nandid >> 8) & 0xff
|
||||
pid = nandid & 0xff
|
||||
|
||||
self.settings.flash_fid = fid
|
||||
self.settings.flash_pid = pid
|
||||
self.settings.flash_mfr = ""
|
||||
for info in nand_manuf_ids:
|
||||
if info[0] == pid:
|
||||
|
|
|
@ -13,279 +13,11 @@ parent_dir = os.path.dirname(current_dir)
|
|||
sys.path.insert(0, parent_dir)
|
||||
from edlclient.Library.utils import read_object, print_progress, rmrf, LogBase
|
||||
from edlclient.Config.qualcomm_config import sochw, msmids, root_cert_hash
|
||||
|
||||
|
||||
|
||||
|
||||
def convertmsmid(msmid):
|
||||
msmiddb = []
|
||||
if int(msmid, 16) & 0xFF == 0xe1 or msmid == '00000000':
|
||||
return [msmid]
|
||||
socid = int(msmid, 16) >> 16
|
||||
if socid in sochw:
|
||||
names = sochw[socid].split(",")
|
||||
for name in names:
|
||||
for ids in msmids:
|
||||
if msmids[ids] == name:
|
||||
rmsmid = hex(ids)[2:].lower()
|
||||
while len(rmsmid) < 8:
|
||||
rmsmid = '0' + rmsmid
|
||||
msmiddb.append(rmsmid)
|
||||
return msmiddb
|
||||
|
||||
from edlclient.Library.loader_db import loader_utils
|
||||
from edlclient.Library.sahara_defs import ErrorDesc, cmd_t, exec_cmd_t, sahara_mode_t, status_t, \
|
||||
CommandHandler, SAHARA_VERSION
|
||||
|
||||
class sahara(metaclass=LogBase):
|
||||
SAHARA_VERSION = 2
|
||||
SAHARA_MIN_VERSION = 1
|
||||
|
||||
class cmd:
|
||||
SAHARA_HELLO_REQ = 0x1
|
||||
SAHARA_HELLO_RSP = 0x2
|
||||
SAHARA_READ_DATA = 0x3
|
||||
SAHARA_END_TRANSFER = 0x4
|
||||
SAHARA_DONE_REQ = 0x5
|
||||
SAHARA_DONE_RSP = 0x6
|
||||
SAHARA_RESET_REQ = 0x7
|
||||
SAHARA_RESET_RSP = 0x8
|
||||
SAHARA_MEMORY_DEBUG = 0x9
|
||||
SAHARA_MEMORY_READ = 0xA
|
||||
SAHARA_CMD_READY = 0xB
|
||||
SAHARA_SWITCH_MODE = 0xC
|
||||
SAHARA_EXECUTE_REQ = 0xD
|
||||
SAHARA_EXECUTE_RSP = 0xE
|
||||
SAHARA_EXECUTE_DATA = 0xF
|
||||
SAHARA_64BIT_MEMORY_DEBUG = 0x10
|
||||
SAHARA_64BIT_MEMORY_READ = 0x11
|
||||
SAHARA_64BIT_MEMORY_READ_DATA = 0x12
|
||||
SAHARA_RESET_STATE_MACHINE_ID = 0x13
|
||||
|
||||
class exec_cmd:
|
||||
SAHARA_EXEC_CMD_NOP = 0x00
|
||||
SAHARA_EXEC_CMD_SERIAL_NUM_READ = 0x01
|
||||
SAHARA_EXEC_CMD_MSM_HW_ID_READ = 0x02
|
||||
SAHARA_EXEC_CMD_OEM_PK_HASH_READ = 0x03
|
||||
SAHARA_EXEC_CMD_SWITCH_TO_DMSS_DLOAD = 0x04
|
||||
SAHARA_EXEC_CMD_SWITCH_TO_STREAM_DLOAD = 0x05
|
||||
SAHARA_EXEC_CMD_READ_DEBUG_DATA = 0x06
|
||||
SAHARA_EXEC_CMD_GET_SOFTWARE_VERSION_SBL = 0x07
|
||||
|
||||
class sahara_mode:
|
||||
SAHARA_MODE_IMAGE_TX_PENDING = 0x0
|
||||
SAHARA_MODE_IMAGE_TX_COMPLETE = 0x1
|
||||
SAHARA_MODE_MEMORY_DEBUG = 0x2
|
||||
SAHARA_MODE_COMMAND = 0x3
|
||||
|
||||
class status:
|
||||
SAHARA_STATUS_SUCCESS = 0x00 # Invalid command received in current state
|
||||
SAHARA_NAK_INVALID_CMD = 0x01 # Protocol mismatch between host and target
|
||||
SAHARA_NAK_PROTOCOL_MISMATCH = 0x02 # Invalid target protocol version
|
||||
SAHARA_NAK_INVALID_TARGET_PROTOCOL = 0x03 # Invalid host protocol version
|
||||
SAHARA_NAK_INVALID_HOST_PROTOCOL = 0x04 # Invalid packet size received
|
||||
SAHARA_NAK_INVALID_PACKET_SIZE = 0x05 # Unexpected image ID received
|
||||
SAHARA_NAK_UNEXPECTED_IMAGE_ID = 0x06 # Invalid image header size received
|
||||
SAHARA_NAK_INVALID_HEADER_SIZE = 0x07 # Invalid image data size received
|
||||
SAHARA_NAK_INVALID_DATA_SIZE = 0x08 # Invalid image type received
|
||||
SAHARA_NAK_INVALID_IMAGE_TYPE = 0x09 # Invalid tranmission length
|
||||
SAHARA_NAK_INVALID_TX_LENGTH = 0x0A # Invalid reception length
|
||||
SAHARA_NAK_INVALID_RX_LENGTH = 0x0B # General transmission or reception error
|
||||
SAHARA_NAK_GENERAL_TX_RX_ERROR = 0x0C # Error while transmitting READ_DATA packet
|
||||
SAHARA_NAK_READ_DATA_ERROR = 0x0D # Cannot receive specified number of program headers
|
||||
SAHARA_NAK_UNSUPPORTED_NUM_PHDRS = 0x0E # Invalid data length received for program headers
|
||||
SAHARA_NAK_INVALID_PDHR_SIZE = 0x0F # Multiple shared segments found in ELF image
|
||||
SAHARA_NAK_MULTIPLE_SHARED_SEG = 0x10 # Uninitialized program header location
|
||||
SAHARA_NAK_UNINIT_PHDR_LOC = 0x11 # Invalid destination address
|
||||
SAHARA_NAK_INVALID_DEST_ADDR = 0x12 # Invalid data size received in image header
|
||||
SAHARA_NAK_INVALID_IMG_HDR_DATA_SIZE = 0x13 # Invalid ELF header received
|
||||
SAHARA_NAK_INVALID_ELF_HDR = 0x14 # Unknown host error received in HELLO_RESP
|
||||
SAHARA_NAK_UNKNOWN_HOST_ERROR = 0x15 # Timeout while receiving data
|
||||
SAHARA_NAK_TIMEOUT_RX = 0x16 # Timeout while transmitting data
|
||||
SAHARA_NAK_TIMEOUT_TX = 0x17 # Invalid mode received from host
|
||||
SAHARA_NAK_INVALID_HOST_MODE = 0x18 # Invalid memory read access
|
||||
SAHARA_NAK_INVALID_MEMORY_READ = 0x19 # Host cannot handle read data size requested
|
||||
SAHARA_NAK_INVALID_DATA_SIZE_REQUEST = 0x1A # Memory debug not supported
|
||||
SAHARA_NAK_MEMORY_DEBUG_NOT_SUPPORTED = 0x1B # Invalid mode switch
|
||||
SAHARA_NAK_INVALID_MODE_SWITCH = 0x1C # Failed to execute command
|
||||
SAHARA_NAK_CMD_EXEC_FAILURE = 0x1D # Invalid parameter passed to command execution
|
||||
SAHARA_NAK_EXEC_CMD_INVALID_PARAM = 0x1E # Unsupported client command received
|
||||
SAHARA_NAK_EXEC_CMD_UNSUPPORTED = 0x1F # Invalid client command received for data response
|
||||
SAHARA_NAK_EXEC_DATA_INVALID_CLIENT_CMD = 0x20 # Failed to authenticate hash table
|
||||
SAHARA_NAK_HASH_TABLE_AUTH_FAILURE = 0x21 # Failed to verify hash for a given segment of ELF image
|
||||
SAHARA_NAK_HASH_VERIFICATION_FAILURE = 0x22 # Failed to find hash table in ELF image
|
||||
SAHARA_NAK_HASH_TABLE_NOT_FOUND = 0x23 # Target failed to initialize
|
||||
SAHARA_NAK_TARGET_INIT_FAILURE = 0x24 # Failed to authenticate generic image
|
||||
SAHARA_NAK_IMAGE_AUTH_FAILURE = 0x25 # Invalid ELF hash table size. Too bit or small.
|
||||
SAHARA_NAK_INVALID_IMG_HASH_TABLE_SIZE = 0x26
|
||||
SAHARA_NAK_MAX_CODE = 0x7FFFFFFF # To ensure 32-bits wide */
|
||||
|
||||
ErrorDesc = {
|
||||
0x00: "Invalid command received in current state",
|
||||
0x01: "Protocol mismatch between host and target",
|
||||
0x02: "Invalid target protocol version",
|
||||
0x03: "Invalid host protocol version",
|
||||
0x04: "Invalid packet size received",
|
||||
0x05: "Unexpected image ID received",
|
||||
0x06: "Invalid image header size received",
|
||||
0x07: "Invalid image data size received",
|
||||
0x08: "Invalid image type received",
|
||||
0x09: "Invalid tranmission length",
|
||||
0x0A: "Invalid reception length",
|
||||
0x0B: "General transmission or reception error",
|
||||
0x0C: "Error while transmitting READ_DATA packet",
|
||||
0x0D: "Cannot receive specified number of program headers",
|
||||
0x0E: "Invalid data length received for program headers",
|
||||
0x0F: "Multiple shared segments found in ELF image",
|
||||
0x10: "Uninitialized program header location",
|
||||
0x11: "Invalid destination address",
|
||||
0x12: "Invalid data size received in image header",
|
||||
0x13: "Invalid ELF header received",
|
||||
0x14: "Unknown host error received in HELLO_RESP",
|
||||
0x15: "Timeout while receiving data",
|
||||
0x16: "Timeout while transmitting data",
|
||||
0x17: "Invalid mode received from host",
|
||||
0x18: "Invalid memory read access",
|
||||
0x19: "Host cannot handle read data size requested",
|
||||
0x1A: "Memory debug not supported",
|
||||
0x1B: "Invalid mode switch",
|
||||
0x1C: "Failed to execute command",
|
||||
0x1D: "Invalid parameter passed to command execution",
|
||||
0x1E: "Unsupported client command received",
|
||||
0x1F: "Invalid client command received for data response",
|
||||
0x20: "Failed to authenticate hash table",
|
||||
0x21: "Failed to verify hash for a given segment of ELF image",
|
||||
0x22: "Failed to find hash table in ELF image",
|
||||
0x23: "Target failed to initialize",
|
||||
0x24: "Failed to authenticate generic image",
|
||||
0x25: "Invalid ELF hash table size. Too bit or small.",
|
||||
0x26: "Invalid IMG Hash Table Size"
|
||||
}
|
||||
|
||||
def init_loader_db(self):
|
||||
loaderdb = {}
|
||||
for (dirpath, dirnames, filenames) in os.walk(os.path.join(parent_dir,"..","Loaders")):
|
||||
for filename in filenames:
|
||||
fn = os.path.join(dirpath, filename)
|
||||
found = False
|
||||
for ext in [".bin", ".mbn", ".elf"]:
|
||||
if ext in filename[-4:]:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
continue
|
||||
try:
|
||||
hwid = filename.split("_")[0].lower()
|
||||
msmid = hwid[:8]
|
||||
devid = hwid[8:]
|
||||
pkhash = filename.split("_")[1].lower()
|
||||
for msmid in convertmsmid(msmid):
|
||||
mhwid = msmid + devid
|
||||
mhwid = mhwid.lower()
|
||||
if mhwid not in loaderdb:
|
||||
loaderdb[mhwid] = {}
|
||||
if pkhash not in loaderdb[mhwid]:
|
||||
loaderdb[mhwid][pkhash] = fn
|
||||
else:
|
||||
loaderdb[mhwid][pkhash].append(fn)
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
self.debug(str(e))
|
||||
continue
|
||||
self.loaderdb = loaderdb
|
||||
return loaderdb
|
||||
|
||||
def get_error_desc(self, status):
|
||||
if status in self.ErrorDesc:
|
||||
return "Error: " + self.ErrorDesc[status]
|
||||
else:
|
||||
return "Unknown error"
|
||||
|
||||
pkt_hello_req = [
|
||||
('cmd', 'I'),
|
||||
('len', 'I'),
|
||||
('version', 'I'),
|
||||
('version_min', 'I'),
|
||||
('max_cmd_len', 'I'),
|
||||
('mode', 'I'),
|
||||
('res1', 'I'),
|
||||
('res2', 'I'),
|
||||
('res3', 'I'),
|
||||
('res4', 'I'),
|
||||
('res5', 'I'),
|
||||
('res6', 'I')]
|
||||
|
||||
pkt_cmd_hdr = [
|
||||
('cmd', 'I'),
|
||||
('len', 'I')
|
||||
]
|
||||
|
||||
pkt_read_data = [
|
||||
('id', 'I'),
|
||||
('data_offset', 'I'),
|
||||
('data_len', 'I')
|
||||
]
|
||||
|
||||
pkt_read_data_64 = [
|
||||
('id', 'Q'),
|
||||
('data_offset', 'Q'),
|
||||
('data_len', 'Q')
|
||||
]
|
||||
|
||||
pkt_memory_debug = [
|
||||
('memory_table_addr', 'I'),
|
||||
('memory_table_length', 'I')
|
||||
]
|
||||
|
||||
pkt_memory_debug_64 = [
|
||||
('memory_table_addr', 'Q'),
|
||||
('memory_table_length', 'Q')
|
||||
]
|
||||
'''
|
||||
execute_cmd=[
|
||||
('cmd', 'I'),
|
||||
('len', 'I'),
|
||||
('client_cmd','I')
|
||||
]
|
||||
'''
|
||||
|
||||
pkt_execute_rsp_cmd = [
|
||||
('cmd', 'I'),
|
||||
('len', 'I'),
|
||||
('client_cmd', 'I'),
|
||||
('data_len', 'I')
|
||||
]
|
||||
|
||||
pkt_image_end = [
|
||||
('id', 'I'),
|
||||
('status', 'I')
|
||||
]
|
||||
|
||||
pkt_done = [
|
||||
('cmd', 'I'),
|
||||
('len', 'I'),
|
||||
('status', 'I')
|
||||
]
|
||||
|
||||
pbl_info = [
|
||||
('serial', 'I'),
|
||||
('msm_id', 'I'),
|
||||
('pk_hash', '32s'),
|
||||
('pbl_sw', 'I')
|
||||
]
|
||||
|
||||
parttbl = [
|
||||
('save_pref', 'I'),
|
||||
('mem_base', 'I'),
|
||||
('length', 'I'),
|
||||
('desc', '20s'),
|
||||
('filename', '20s')
|
||||
]
|
||||
|
||||
parttbl_64bit = [
|
||||
('save_pref', 'Q'),
|
||||
('mem_base', 'Q'),
|
||||
('length', 'Q'),
|
||||
('desc', '20s'),
|
||||
('filename', '20s')
|
||||
]
|
||||
|
||||
def __init__(self, cdc, loglevel):
|
||||
self.cdc = cdc
|
||||
self.__logger = self.__logger
|
||||
|
@ -294,7 +26,6 @@ class sahara(metaclass=LogBase):
|
|||
self.error = self.__logger.error
|
||||
self.warning = self.__logger.warning
|
||||
self.id = None
|
||||
self.loaderdb = None
|
||||
self.version = 2.1
|
||||
self.programmer = None
|
||||
self.mode = ""
|
||||
|
@ -312,8 +43,9 @@ class sahara(metaclass=LogBase):
|
|||
self.msm_str = None
|
||||
self.bit64 = False
|
||||
self.pktsize = None
|
||||
|
||||
self.init_loader_db()
|
||||
self.ch = CommandHandler()
|
||||
self.loader_handler=loader_utils(loglevel=loglevel)
|
||||
self.loaderdb = self.loader_handler.init_loader_db()
|
||||
|
||||
self.__logger.setLevel(loglevel)
|
||||
if loglevel == logging.DEBUG:
|
||||
|
@ -321,50 +53,51 @@ class sahara(metaclass=LogBase):
|
|||
fh = logging.FileHandler(logfilename)
|
||||
self.__logger.addHandler(fh)
|
||||
|
||||
def get_error_desc(self, status):
|
||||
if status in ErrorDesc:
|
||||
return "Error: " + ErrorDesc[status]
|
||||
else:
|
||||
return "Unknown error"
|
||||
|
||||
def get_rsp(self):
|
||||
data = []
|
||||
try:
|
||||
v = self.cdc.read()
|
||||
if v == b'':
|
||||
return [None, None]
|
||||
if b"<?xml" in v:
|
||||
return ["firehose", None]
|
||||
pkt = read_object(v[0:0x2 * 0x4], self.pkt_cmd_hdr)
|
||||
if "cmd" in pkt:
|
||||
cmd = pkt["cmd"]
|
||||
if cmd == self.cmd.SAHARA_HELLO_REQ:
|
||||
data = read_object(v[0x0:0xC * 0x4], self.pkt_hello_req)
|
||||
elif cmd == self.cmd.SAHARA_DONE_RSP:
|
||||
data = read_object(v[0x0:0x3 * 4], self.pkt_done)
|
||||
elif cmd == self.cmd.SAHARA_END_TRANSFER:
|
||||
data = read_object(v[0x8:0x8 + 0x2 * 0x4], self.pkt_image_end)
|
||||
elif cmd == self.cmd.SAHARA_64BIT_MEMORY_READ_DATA:
|
||||
self.bit64 = True
|
||||
data = read_object(v[0x8:0x8 + 0x3 * 0x8], self.pkt_read_data_64)
|
||||
elif cmd == self.cmd.SAHARA_READ_DATA:
|
||||
self.bit64 = False
|
||||
data = read_object(v[0x8:0x8 + 0x3 * 0x4], self.pkt_read_data)
|
||||
elif cmd == self.cmd.SAHARA_64BIT_MEMORY_DEBUG:
|
||||
self.bit64 = True
|
||||
data = read_object(v[0x8:0x8 + 0x2 * 0x8], self.pkt_memory_debug_64)
|
||||
elif cmd == self.cmd.SAHARA_MEMORY_DEBUG:
|
||||
self.bit64 = False
|
||||
data = read_object(v[0x8:0x8 + 0x2 * 0x4], self.pkt_memory_debug)
|
||||
elif cmd == self.cmd.SAHARA_EXECUTE_RSP:
|
||||
data = read_object(v[0:0x4 * 0x4], self.pkt_execute_rsp_cmd)
|
||||
elif cmd == self.cmd.SAHARA_CMD_READY or cmd == self.cmd.SAHARA_RESET_RSP:
|
||||
data = []
|
||||
else:
|
||||
return [None,None]
|
||||
return [pkt, data]
|
||||
data = self.cdc.read()
|
||||
if data == b'':
|
||||
return {}
|
||||
if b"<?xml" in data:
|
||||
return {"firehose":"yes"}
|
||||
pkt = self.ch.pkt_cmd_hdr(data)
|
||||
if pkt.cmd == cmd_t.SAHARA_HELLO_REQ:
|
||||
return {"cmd":pkt.cmd,"data":self.ch.pkt_hello_req(data)}
|
||||
elif pkt.cmd == cmd_t.SAHARA_DONE_RSP:
|
||||
return {"cmd": pkt.cmd, "data":self.ch.pkt_done(data)}
|
||||
elif pkt.cmd == cmd_t.SAHARA_END_TRANSFER:
|
||||
return {"cmd": pkt.cmd, "data": self.ch.pkt_image_end(data)}
|
||||
elif pkt.cmd == cmd_t.SAHARA_64BIT_MEMORY_READ_DATA:
|
||||
self.bit64 = True
|
||||
return {"cmd": pkt.cmd, "data": self.ch.pkt_read_data_64(data)}
|
||||
elif pkt.cmd == cmd_t.SAHARA_READ_DATA:
|
||||
self.bit64 = False
|
||||
return {"cmd": pkt.cmd, "data": self.ch.pkt_read_data(data)}
|
||||
elif pkt.cmd == cmd_t.SAHARA_64BIT_MEMORY_DEBUG:
|
||||
self.bit64 = True
|
||||
return {"cmd": pkt.cmd, "data": self.ch.pkt_memory_debug_64(data)}
|
||||
elif pkt.cmd == cmd_t.SAHARA_MEMORY_DEBUG:
|
||||
self.bit64 = False
|
||||
return {"cmd": pkt.cmd, "data": self.ch.pkt_memory_debug(data)}
|
||||
elif pkt.cmd == cmd_t.SAHARA_EXECUTE_RSP:
|
||||
return {"cmd": pkt.cmd, "data": self.ch.pkt_execute_rsp_cmd(data)}
|
||||
elif pkt.cmd == cmd_t.SAHARA_CMD_READY or pkt.cmd == cmd_t.SAHARA_RESET_RSP:
|
||||
return {"cmd": pkt.cmd, "data": None }
|
||||
return {}
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
self.error(str(e))
|
||||
return [None,None]
|
||||
return {}
|
||||
|
||||
def cmd_hello(self, mode, version_min=1, max_cmd_len=0): # CMD 0x1, RSP 0x2
|
||||
cmd = self.cmd.SAHARA_HELLO_RSP
|
||||
cmd = cmd_t.SAHARA_HELLO_RSP
|
||||
length = 0x30
|
||||
version = self.SAHARA_VERSION
|
||||
version = SAHARA_VERSION
|
||||
responsedata = pack("<IIIIIIIIIIII", cmd, length, version, version_min, max_cmd_len, mode, 0, 0, 0, 0, 0, 0)
|
||||
try:
|
||||
self.cdc.write(responsedata)
|
||||
|
@ -375,82 +108,73 @@ class sahara(metaclass=LogBase):
|
|||
|
||||
def connect(self):
|
||||
try:
|
||||
v = self.cdc.read()
|
||||
v = self.cdc.read(length=0xC * 0x4,timeout=1)
|
||||
if len(v) > 1:
|
||||
if v[0] == 0x01:
|
||||
cmd = read_object(v[0:0x2 * 0x4], self.pkt_cmd_hdr)
|
||||
if cmd['cmd'] == self.cmd.SAHARA_HELLO_REQ:
|
||||
data = read_object(v[0x0:0xC * 0x4], self.pkt_hello_req)
|
||||
self.pktsize = data['max_cmd_len']
|
||||
self.version = float(str(data['version']) + "." + str(data['version_min']))
|
||||
return ["sahara", data]
|
||||
elif v[0] == self.cmd.SAHARA_END_TRANSFER:
|
||||
return ["sahara", None]
|
||||
pkt = self.ch.pkt_cmd_hdr(v)
|
||||
if pkt.cmd == cmd_t.SAHARA_HELLO_REQ:
|
||||
rsp = self.ch.pkt_hello_req(v)
|
||||
self.pktsize = rsp.max_cmd_len
|
||||
self.version = float(str(rsp.version) + "." + str(rsp.version_min))
|
||||
self.info(f"Protocol version: {self.version}")
|
||||
return {"mode":"sahara", "cmd":cmd_t.SAHARA_HELLO_REQ, "data":rsp}
|
||||
elif pkt.cmd == cmd_t.SAHARA_END_TRANSFER:
|
||||
rsp = self.ch.pkt_image_end(v)
|
||||
return {"mode":"sahara", "cmd":cmd_t.SAHARA_END_TRANSFER, "data":rsp}
|
||||
elif b"<?xml" in v:
|
||||
return ["firehose", None]
|
||||
return {"mode":"firehose"}
|
||||
elif v[0] == 0x7E:
|
||||
return ["nandprg", None]
|
||||
return {"mode":"nandprg"}
|
||||
else:
|
||||
data = b"<?xml version=\"1.0\" ?><data><nop /></data>"
|
||||
self.cdc.write(data)
|
||||
res = self.cdc.read()
|
||||
if res == b"":
|
||||
try:
|
||||
data = b"\x7E\x06\x4E\x95\x7E" # Streaming nop
|
||||
self.cdc.write(data)
|
||||
res = self.cdc.read()
|
||||
if b"\x7E\x0D\x16\x00\x00\x00\x00" in res or b"Invalid Command" in res:
|
||||
return ["nandprg", None]
|
||||
else:
|
||||
return ["", None]
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
self.error(str(e))
|
||||
return ["", None]
|
||||
res = self.cdc.read(timeout=1)
|
||||
if b"<?xml" in res:
|
||||
return ["firehose", None]
|
||||
elif len(res) > 0 and res[0] == self.cmd.SAHARA_END_TRANSFER:
|
||||
print("Device is in Sahara error state, please reboot the device.")
|
||||
return ["sahara", None]
|
||||
else:
|
||||
return {"mode": "firehose"}
|
||||
elif len(res)> 0:
|
||||
if res[0] == 0x7E:
|
||||
return {"mode":"nandprg"}
|
||||
elif res[0] == cmd_t.SAHARA_END_TRANSFER:
|
||||
rsp = self.ch.pkt_image_end(res)
|
||||
return {"mode": "sahara", "cmd": cmd_t.SAHARA_END_TRANSFER, "data": rsp}
|
||||
elif res == b"":
|
||||
data = b"\x7E\x11\x00\x12\x00\xA0\xE3\x00\x00\xC1\xE5\x01\x40\xA0\xE3\x1E\xFF\x2F\xE1\x4B\xD9\x7E"
|
||||
self.cdc.write(data)
|
||||
res = self.cdc.read()
|
||||
if len(res) > 0 and res[1] == 0x12:
|
||||
return ["nandprg", None]
|
||||
else:
|
||||
self.cmd_modeswitch(self.sahara_mode.SAHARA_MODE_COMMAND)
|
||||
return ["sahara", None]
|
||||
return {"mode":"nandprg"}
|
||||
elif len(res) == 0:
|
||||
print("Device is in Sahara error state, please reboot the device.")
|
||||
return {"mode": "error"}
|
||||
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
self.error(str(e))
|
||||
|
||||
self.cmd_modeswitch(self.sahara_mode.SAHARA_MODE_MEMORY_DEBUG)
|
||||
cmd, pkt = self.get_rsp()
|
||||
if None in [cmd , pkt]:
|
||||
return ["", None]
|
||||
return ["sahara", pkt]
|
||||
return {"mode": "error"}
|
||||
|
||||
def enter_command_mode(self):
|
||||
if not self.cmd_hello(self.sahara_mode.SAHARA_MODE_COMMAND):
|
||||
return False
|
||||
cmd, pkt = self.get_rsp()
|
||||
if cmd["cmd"] == self.cmd.SAHARA_CMD_READY:
|
||||
return True
|
||||
elif "status" in pkt:
|
||||
self.error(self.get_error_desc(pkt["status"]))
|
||||
if not self.cmd_hello(sahara_mode_t.SAHARA_MODE_COMMAND):
|
||||
return False
|
||||
res = self.get_rsp()
|
||||
if "cmd" in res:
|
||||
if res["cmd"] == cmd_t.SAHARA_END_TRANSFER:
|
||||
if "data" in res:
|
||||
pkt = res["data"]
|
||||
self.error(self.get_error_desc(pkt.status))
|
||||
return False
|
||||
elif res["cmd"] == cmd_t.SAHARA_CMD_READY:
|
||||
return True
|
||||
return False
|
||||
|
||||
def cmdexec_nop(self):
|
||||
res = self.cmd_exec(self.exec_cmd.SAHARA_EXEC_CMD_NOP)
|
||||
res = self.cmd_exec(exec_cmd_t.SAHARA_EXEC_CMD_NOP)
|
||||
return res
|
||||
|
||||
def cmdexec_get_serial_num(self):
|
||||
res = self.cmd_exec(self.exec_cmd.SAHARA_EXEC_CMD_SERIAL_NUM_READ)
|
||||
res = self.cmd_exec(exec_cmd_t.SAHARA_EXEC_CMD_SERIAL_NUM_READ)
|
||||
return unpack("<I", res)[0]
|
||||
|
||||
def cmdexec_get_msm_hwid(self):
|
||||
res = self.cmd_exec(self.exec_cmd.SAHARA_EXEC_CMD_MSM_HW_ID_READ)
|
||||
res = self.cmd_exec(exec_cmd_t.SAHARA_EXEC_CMD_MSM_HW_ID_READ)
|
||||
try:
|
||||
return unpack("<Q", res[0:0x8])[0]
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
|
@ -459,26 +183,26 @@ class sahara(metaclass=LogBase):
|
|||
|
||||
def cmdexec_get_pkhash(self):
|
||||
try:
|
||||
res = self.cmd_exec(self.exec_cmd.SAHARA_EXEC_CMD_OEM_PK_HASH_READ)[0:0x20]
|
||||
res = self.cmd_exec(exec_cmd_t.SAHARA_EXEC_CMD_OEM_PK_HASH_READ)[0:0x20]
|
||||
return binascii.hexlify(res).decode('utf-8')
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
self.error(str(e))
|
||||
return None
|
||||
|
||||
def cmdexec_get_sbl_version(self):
|
||||
res = self.cmd_exec(self.exec_cmd.SAHARA_EXEC_CMD_GET_SOFTWARE_VERSION_SBL)
|
||||
res = self.cmd_exec(exec_cmd_t.SAHARA_EXEC_CMD_GET_SOFTWARE_VERSION_SBL)
|
||||
return unpack("<I", res)[0]
|
||||
|
||||
def cmdexec_switch_to_dmss_dload(self):
|
||||
res = self.cmd_exec(self.exec_cmd.SAHARA_EXEC_CMD_SWITCH_TO_DMSS_DLOAD)
|
||||
res = self.cmd_exec(exec_cmd_t.SAHARA_EXEC_CMD_SWITCH_TO_DMSS_DLOAD)
|
||||
return res
|
||||
|
||||
def cmdexec_switch_to_stream_dload(self):
|
||||
res = self.cmd_exec(self.exec_cmd.SAHARA_EXEC_CMD_SWITCH_TO_STREAM_DLOAD)
|
||||
res = self.cmd_exec(exec_cmd_t.SAHARA_EXEC_CMD_SWITCH_TO_STREAM_DLOAD)
|
||||
return res
|
||||
|
||||
def cmdexec_read_debug_data(self):
|
||||
res = self.cmd_exec(self.exec_cmd.SAHARA_EXEC_CMD_READ_DEBUG_DATA)
|
||||
res = self.cmd_exec(exec_cmd_t.SAHARA_EXEC_CMD_READ_DEBUG_DATA)
|
||||
return res
|
||||
|
||||
def cmd_info(self):
|
||||
|
@ -526,6 +250,7 @@ class sahara(metaclass=LogBase):
|
|||
for rootcert in root_cert_hash:
|
||||
if self.pkhash[0:16] in root_cert_hash[rootcert]:
|
||||
unfused = True
|
||||
break
|
||||
if unfused:
|
||||
self.info("Possibly unfused device detected, so any loader should be fine...")
|
||||
if self.pkhash[0:16] in mt:
|
||||
|
@ -557,7 +282,7 @@ class sahara(metaclass=LogBase):
|
|||
if self.pkhash[0:16] in self.loaderdb[hwidstr]:
|
||||
self.programmer = self.loaderdb[hwidstr][self.pkhash[0:16]]
|
||||
self.info(f"Found loader: {self.programmer}")
|
||||
self.cmd_modeswitch(self.sahara_mode.SAHARA_MODE_COMMAND)
|
||||
self.cmd_modeswitch(sahara_mode_t.SAHARA_MODE_COMMAND)
|
||||
return True
|
||||
else:
|
||||
if self.pkhash[0:16] in self.loaderdb[hwidstr]:
|
||||
|
@ -565,7 +290,7 @@ class sahara(metaclass=LogBase):
|
|||
self.info(f"Found possible loader: {self.programmer}")
|
||||
found = True
|
||||
if found:
|
||||
self.cmd_modeswitch(self.sahara_mode.SAHARA_MODE_COMMAND)
|
||||
self.cmd_modeswitch(sahara_mode_t.SAHARA_MODE_COMMAND)
|
||||
return True
|
||||
else:
|
||||
self.error(
|
||||
|
@ -576,7 +301,7 @@ class sahara(metaclass=LogBase):
|
|||
self.error(f"Couldn't find a suitable loader :(")
|
||||
return False
|
||||
|
||||
self.cmd_modeswitch(self.sahara_mode.SAHARA_MODE_COMMAND)
|
||||
self.cmd_modeswitch(sahara_mode_t.SAHARA_MODE_COMMAND)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -584,35 +309,47 @@ class sahara(metaclass=LogBase):
|
|||
if self.enter_command_mode():
|
||||
self.serial = self.cmdexec_get_serial_num()
|
||||
self.info(f"Device serial : {hex(self.serial)}")
|
||||
self.cmd_modeswitch(self.sahara_mode.SAHARA_MODE_COMMAND)
|
||||
self.cmd_modeswitch(sahara_mode_t.SAHARA_MODE_COMMAND)
|
||||
return True
|
||||
return False
|
||||
|
||||
def cmd_done(self):
|
||||
if self.cdc.write(pack("<II", self.cmd.SAHARA_DONE_REQ, 0x8)):
|
||||
cmd, pkt = self.get_rsp()
|
||||
if self.cdc.write(pack("<II", cmd_t.SAHARA_DONE_REQ, 0x8)):
|
||||
res = self.get_rsp()
|
||||
time.sleep(0.3)
|
||||
if cmd["cmd"] == self.cmd.SAHARA_DONE_RSP:
|
||||
return True
|
||||
elif cmd["cmd"] == self.cmd.SAHARA_END_TRANSFER:
|
||||
if pkt["status"] == self.status.SAHARA_NAK_INVALID_CMD:
|
||||
self.error("Invalid Transfer command received.")
|
||||
return False
|
||||
return True
|
||||
if "cmd" in res:
|
||||
cmd = res["cmd"]
|
||||
if cmd == cmd_t.SAHARA_DONE_RSP:
|
||||
return True
|
||||
elif cmd == cmd_t.SAHARA_END_TRANSFER:
|
||||
if "data" in res:
|
||||
pkt = res["data"]
|
||||
if pkt.status == status_t.SAHARA_NAK_INVALID_CMD:
|
||||
self.error("Invalid Transfer command received.")
|
||||
return False
|
||||
else:
|
||||
self.error(f"Received invalid response {cmd}.")
|
||||
return False
|
||||
|
||||
def cmd_reset_state_machine(self):
|
||||
self.cdc.write(pack("<II", cmd_t.SAHARA_RESET_STATE_MACHINE_ID, 0x8))
|
||||
return True
|
||||
|
||||
|
||||
def cmd_reset(self):
|
||||
self.cdc.write(pack("<II", self.cmd.SAHARA_RESET_REQ, 0x8))
|
||||
self.cdc.write(pack("<II", cmd_t.SAHARA_RESET_REQ, 0x8))
|
||||
try:
|
||||
cmd, pkt = self.get_rsp()
|
||||
res = self.get_rsp()
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
self.debug(str(e))
|
||||
return False
|
||||
if cmd["cmd"] == self.cmd.SAHARA_RESET_RSP:
|
||||
return True
|
||||
elif "status" in pkt:
|
||||
self.error(self.get_error_desc(pkt["status"]))
|
||||
return False
|
||||
if "cmd" in res:
|
||||
if res["cmd"] == cmd_t.SAHARA_RESET_RSP:
|
||||
return True
|
||||
elif res["cmd"] == cmd_t.SAHARA_END_TRANSFER:
|
||||
if "data" in res:
|
||||
pkt=res["data"]
|
||||
self.error(self.get_error_desc(pkt.status))
|
||||
return False
|
||||
|
||||
def read_memory(self, addr, bytestoread, display=False, wf=None):
|
||||
|
@ -634,12 +371,12 @@ class sahara(metaclass=LogBase):
|
|||
self.debug(str(e))
|
||||
pass
|
||||
if self.bit64:
|
||||
if not self.cdc.write(pack("<IIQQ", self.cmd.SAHARA_64BIT_MEMORY_READ, 0x8 + 8 + 8, addr + pos,
|
||||
if not self.cdc.write(pack("<IIQQ", cmd_t.SAHARA_64BIT_MEMORY_READ, 0x8 + 8 + 8, addr + pos,
|
||||
length)):
|
||||
return None
|
||||
else:
|
||||
if not self.cdc.write(
|
||||
pack("<IIII", self.cmd.SAHARA_MEMORY_READ, 0x8 + 4 + 4, addr + pos, length)):
|
||||
pack("<IIII", cmd_t.SAHARA_MEMORY_READ, 0x8 + 4 + 4, addr + pos, length)):
|
||||
return None
|
||||
while length > 0:
|
||||
try:
|
||||
|
@ -689,13 +426,13 @@ class sahara(metaclass=LogBase):
|
|||
return True
|
||||
|
||||
def debug_mode(self, dump_partitions=None):
|
||||
if not self.cmd_hello(self.sahara_mode.SAHARA_MODE_MEMORY_DEBUG):
|
||||
if not self.cmd_hello(sahara_mode_t.SAHARA_MODE_MEMORY_DEBUG):
|
||||
return False
|
||||
if os.path.exists("memory"):
|
||||
rmrf("memory")
|
||||
os.mkdir("memory")
|
||||
cmd, pkt = self.get_rsp()
|
||||
if cmd["cmd"] == self.cmd.SAHARA_MEMORY_DEBUG or cmd["cmd"] == self.cmd.SAHARA_64BIT_MEMORY_DEBUG:
|
||||
if cmd["cmd"] == cmd_t.SAHARA_MEMORY_DEBUG or cmd["cmd"] == cmd_t.SAHARA_64BIT_MEMORY_DEBUG:
|
||||
memory_table_addr = pkt["memory_table_addr"]
|
||||
memory_table_length = pkt["memory_table_length"]
|
||||
if self.bit64:
|
||||
|
@ -709,8 +446,7 @@ class sahara(metaclass=LogBase):
|
|||
num_entries = len(ptbldata) // pktsize
|
||||
partitions = []
|
||||
for id_entry in range(0, num_entries):
|
||||
pd = read_object(ptbldata[id_entry * pktsize:(id_entry * pktsize) + pktsize],
|
||||
self.parttbl_64bit)
|
||||
pd = self.ch.parttbl_64bit(ptbldata[id_entry * pktsize:(id_entry * pktsize) + pktsize])
|
||||
desc = pd["desc"].replace(b"\x00", b"").decode('utf-8')
|
||||
filename = pd["filename"].replace(b"\x00", b"").decode('utf-8')
|
||||
if dump_partitions and filename not in dump_partitions:
|
||||
|
@ -738,7 +474,7 @@ class sahara(metaclass=LogBase):
|
|||
num_entries = len(ptbldata) // pktsize
|
||||
partitions = []
|
||||
for id_entry in range(0, num_entries):
|
||||
pd = read_object(ptbldata[id_entry * pktsize:(id_entry * pktsize) + pktsize], self.parttbl)
|
||||
pd = self.parttbl(ptbldata[id_entry * pktsize:(id_entry * pktsize) + pktsize])
|
||||
desc = pd["desc"].replace(b"\x00", b"").decode('utf-8')
|
||||
filename = pd["filename"].replace(b"\x00", b"").decode('utf-8')
|
||||
if dump_partitions and filename not in dump_partitions:
|
||||
|
@ -769,80 +505,99 @@ class sahara(metaclass=LogBase):
|
|||
self.error(str(e))
|
||||
sys.exit()
|
||||
|
||||
if not self.cmd_hello(self.sahara_mode.SAHARA_MODE_IMAGE_TX_PENDING):
|
||||
if not self.cmd_hello(sahara_mode_t.SAHARA_MODE_IMAGE_TX_PENDING):
|
||||
return ""
|
||||
|
||||
try:
|
||||
datalen = len(programmer)
|
||||
done = False
|
||||
loop = 0
|
||||
while datalen > 0 or done:
|
||||
cmd, pkt = self.get_rsp()
|
||||
if cmd == -1 or pkt == -1:
|
||||
resp = self.get_rsp()
|
||||
if "cmd" in resp:
|
||||
cmd = resp["cmd"]
|
||||
else:
|
||||
cmd = None
|
||||
if cmd == cmd_t.SAHARA_DONE_REQ:
|
||||
if self.cmd_done():
|
||||
return self.mode # Do NOT remove
|
||||
else:
|
||||
self.error("Timeout while uploading loader. Wrong loader ?")
|
||||
return ""
|
||||
if cmd["cmd"] == self.cmd.SAHARA_64BIT_MEMORY_READ_DATA:
|
||||
self.bit64 = True
|
||||
elif cmd["cmd"] == self.cmd.SAHARA_READ_DATA:
|
||||
self.bit64 = False
|
||||
elif cmd["cmd"] == self.cmd.SAHARA_END_TRANSFER:
|
||||
if pkt["status"] == self.status.SAHARA_STATUS_SUCCESS:
|
||||
self.cmd_done()
|
||||
elif cmd in [cmd_t.SAHARA_64BIT_MEMORY_READ_DATA,cmd_t.SAHARA_READ_DATA]:
|
||||
if cmd == cmd_t.SAHARA_64BIT_MEMORY_READ_DATA:
|
||||
self.bit64 = True
|
||||
if loop == 0:
|
||||
self.info("64-Bit mode detected.")
|
||||
elif cmd == cmd_t.SAHARA_READ_DATA:
|
||||
self.bit64 = False
|
||||
if loop == 0:
|
||||
self.info("32-Bit mode detected.")
|
||||
pkt = resp["data"]
|
||||
self.id = pkt.id
|
||||
if self.id == 0x7:
|
||||
self.mode = "nandprg"
|
||||
if loop == 0:
|
||||
self.info("NAND mode detected, uploading...")
|
||||
elif self.id == 0xB:
|
||||
self.mode = "enandprg"
|
||||
if loop == 0:
|
||||
self.info("eNAND mode detected, uploading...")
|
||||
elif self.id >= 0xC:
|
||||
self.mode = "firehose"
|
||||
if loop == 0:
|
||||
self.info("Firehose mode detected, uploading...")
|
||||
else:
|
||||
self.error(f"Unknown sahara id: {self.id}")
|
||||
return "error"
|
||||
loop+=1
|
||||
data_offset = pkt.data_offset
|
||||
data_len = pkt.data_len
|
||||
if data_offset + data_len > len(programmer):
|
||||
while len(programmer) < data_offset + data_len:
|
||||
programmer += b"\xFF"
|
||||
data_to_send = programmer[data_offset:data_offset + data_len]
|
||||
self.cdc.write(data_to_send)
|
||||
datalen -= data_len
|
||||
elif cmd == cmd_t.SAHARA_END_TRANSFER:
|
||||
pkt = resp["data"]
|
||||
if pkt.status == status_t.SAHARA_STATUS_SUCCESS:
|
||||
if self.cmd_done():
|
||||
self.info("Loader successfully uploaded.")
|
||||
else:
|
||||
self.error("Error on uploading Loader.")
|
||||
sys.exit(1)
|
||||
return self.mode
|
||||
else:
|
||||
return ""
|
||||
elif "status" in pkt:
|
||||
self.error(self.get_error_desc(pkt["status"]))
|
||||
return ""
|
||||
self.error(self.get_error_desc(pkt.status))
|
||||
return "error"
|
||||
else:
|
||||
self.error("Unexpected error on uploading")
|
||||
return ""
|
||||
self.id = pkt["id"]
|
||||
if self.id == 0x7:
|
||||
self.mode = "nandprg"
|
||||
elif self.id == 0xB:
|
||||
self.mode = "enandprg"
|
||||
elif self.id >= 0xC:
|
||||
self.mode = "firehose"
|
||||
|
||||
data_offset = pkt["data_offset"]
|
||||
data_len = pkt["data_len"]
|
||||
if data_offset + data_len > len(programmer):
|
||||
while len(programmer) < data_offset + data_len:
|
||||
programmer += b"\xFF"
|
||||
data_to_send = programmer[data_offset:data_offset + data_len]
|
||||
self.cdc.write(data_to_send)
|
||||
datalen -= data_len
|
||||
self.info("Loader uploaded.")
|
||||
cmd, pkt = self.get_rsp()
|
||||
if cmd["cmd"] == self.cmd.SAHARA_END_TRANSFER:
|
||||
if pkt["status"] == self.status.SAHARA_STATUS_SUCCESS:
|
||||
self.cmd_done()
|
||||
return self.mode
|
||||
return ""
|
||||
self.error("Unknown response received on uploading loader.")
|
||||
sys.exit(1)
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
self.error("Unexpected error on uploading, maybe signature of loader wasn't accepted ?\n" + str(e))
|
||||
return ""
|
||||
|
||||
def cmd_modeswitch(self, mode):
|
||||
data = pack("<III", self.cmd.SAHARA_SWITCH_MODE, 0xC, mode)
|
||||
data = pack("<III", cmd_t.SAHARA_SWITCH_MODE, 0xC, mode)
|
||||
self.cdc.write(data)
|
||||
|
||||
def cmd_exec(self, mcmd): # CMD 0xD, RSP 0xE, CMD2 0xF
|
||||
# Send request
|
||||
data = pack("<III", self.cmd.SAHARA_EXECUTE_REQ, 0xC, mcmd)
|
||||
data = pack("<III", cmd_t.SAHARA_EXECUTE_REQ, 0xC, mcmd)
|
||||
self.cdc.write(data)
|
||||
# Get info about request
|
||||
cmd, pkt = self.get_rsp()
|
||||
if cmd["cmd"] == self.cmd.SAHARA_EXECUTE_RSP:
|
||||
# Ack
|
||||
data = pack("<III", self.cmd.SAHARA_EXECUTE_DATA, 0xC, mcmd)
|
||||
self.cdc.write(data)
|
||||
payload = self.cdc.read(pkt["data_len"])
|
||||
return payload
|
||||
elif "status" in pkt:
|
||||
self.error(self.get_error_desc(pkt["status"]))
|
||||
res = self.get_rsp()
|
||||
if "cmd" in res:
|
||||
cmd = res["cmd"]
|
||||
if res["cmd"] == cmd_t.SAHARA_EXECUTE_RSP:
|
||||
pkt = res["data"]
|
||||
data = pack("<III", cmd_t.SAHARA_EXECUTE_DATA, 0xC, mcmd)
|
||||
self.cdc.write(data)
|
||||
payload = self.cdc.usbread(pkt.data_len)
|
||||
return payload
|
||||
elif cmd == cmd_t.SAHARA_END_TRANSFER:
|
||||
pkt = res["data"]
|
||||
self.error(self.get_error_desc(pkt.status))
|
||||
return None
|
||||
return [cmd, pkt]
|
||||
return res
|
||||
|
|
|
@ -6,6 +6,9 @@ from binascii import unhexlify
|
|||
from edlclient.Library.utils import *
|
||||
from edlclient.Library.hdlc import *
|
||||
from edlclient.Library.nand_config import BadFlags, SettingsOpt, nandregs, NandDevice
|
||||
from edlclient.Library.utils import progress
|
||||
|
||||
STREAMING_DLOAD_PARTITION_TABLE_SIZE = 512
|
||||
|
||||
|
||||
class Streaming(metaclass=LogBase):
|
||||
|
@ -27,6 +30,7 @@ class Streaming(metaclass=LogBase):
|
|||
self.error = self.__logger.error
|
||||
self.warning = self.__logger.warning
|
||||
self.modules = None
|
||||
self.hp = None
|
||||
self.Qualcomm = 0
|
||||
self.Patched = 1
|
||||
self.streaming_mode = None
|
||||
|
@ -81,12 +85,12 @@ class Streaming(metaclass=LogBase):
|
|||
self.regs.NAND_ADDR0 = 0
|
||||
self.regs.NAND_ADDR1 = 0
|
||||
self.regs.NAND_DEV0_CFG0 = 0 << self.nanddevice.CW_PER_PAGE | 512 << self.nanddevice.UD_SIZE_BYTES | \
|
||||
5 << self.nanddevice.NUM_ADDR_CYCLES | 0 << self.nanddevice.SPARE_SIZE_BYTES
|
||||
5 << self.nanddevice.NUM_ADDR_CYCLES | 0 << self.nanddevice.SPARE_SIZE_BYTES
|
||||
self.regs.NAND_DEV1_CFG1 = 7 << self.nanddevice.NAND_RECOVERY_CYCLES | 0 << self.nanddevice.CS_ACTIVE_BSY | \
|
||||
17 << self.nanddevice.BAD_BLOCK_BYTE_NUM | \
|
||||
1 << self.nanddevice.BAD_BLOCK_IN_SPARE_AREA | 2 << self.nanddevice.WR_RD_BSY_GAP | \
|
||||
0 << self.nanddevice.WIDE_FLASH | \
|
||||
1 << self.nanddevice.DEV0_CFG1_ECC_DISABLE
|
||||
17 << self.nanddevice.BAD_BLOCK_BYTE_NUM | \
|
||||
1 << self.nanddevice.BAD_BLOCK_IN_SPARE_AREA | 2 << self.nanddevice.WR_RD_BSY_GAP | \
|
||||
0 << self.nanddevice.WIDE_FLASH | \
|
||||
1 << self.nanddevice.DEV0_CFG1_ECC_DISABLE
|
||||
self.regs.NAND_EBI2_ECC_BUF_CFG = 1 << self.nanddevice.ECC_CFG_ECC_DISABLE
|
||||
self.regs.NAND_DEV_CMD_VLD = self.regs.NAND_DEV_CMD_VLD & ~(1 << self.nanddevice.READ_START_VLD)
|
||||
self.regs.NAND_DEV_CMD1 = (self.regs.NAND_DEV_CMD1 & ~(
|
||||
|
@ -144,60 +148,73 @@ class Streaming(metaclass=LogBase):
|
|||
self.mempoke(self.nanddevice.NAND_FLASH_BUFFER + i, 0xffffffff)
|
||||
|
||||
def secure_mode(self):
|
||||
self.send(b"\x17\x01", True)
|
||||
return 0
|
||||
resp = self.send(b"\x17\x01", True) # 0x00 = Untrusted, 0x01 = Trusted
|
||||
if resp[1] == 0x18:
|
||||
return True
|
||||
return False
|
||||
|
||||
def qclose(self, errmode):
|
||||
resp = self.send(b"\x15")
|
||||
if not errmode:
|
||||
if len(resp) > 0 and resp[0] == 0x16:
|
||||
time.sleep(0.5)
|
||||
return True
|
||||
if len(resp) > 2 and resp[1] == 0x16:
|
||||
time.sleep(0.5)
|
||||
return True
|
||||
self.error("Error on closing stream")
|
||||
if errmode:
|
||||
self.error("Error on closing stream")
|
||||
return False
|
||||
|
||||
def send_section_header(self, name):
|
||||
# 0x1b open muliimage, 0xe for user-defined partition
|
||||
resp = self.send(b"\x1b\x0e" + name + b"\x00")
|
||||
if resp[1] == 0x1c:
|
||||
resp = self.send(b"\x1b\x0e" + bytes("0:"+name, 'utf-8') + b"\x00")
|
||||
if resp[0] == 0x1c:
|
||||
return True
|
||||
self.error("Error on sending section header")
|
||||
return False
|
||||
|
||||
def enter_flash_mode(self, ptable=None):
|
||||
self.info("Entering flash mode ...")
|
||||
self.secure_mode()
|
||||
self.qclose(0)
|
||||
if ptable is None:
|
||||
self.send_ptable(ptable, 0) # 1 for fullflash
|
||||
if not self.qclose(0):
|
||||
data = self.cdc.usbread(timeout=0)
|
||||
if ptable is not None:
|
||||
if self.send_ptable(ptable, 0): # 1 for fullflash
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
|
||||
def write_flash(self, partname, filename):
|
||||
def write_flash(self, lba:int=0, partname="", filename="", info=True):
|
||||
wbsize = 1024
|
||||
filesize = os.stat(filename).st_size
|
||||
total = filesize
|
||||
progbar = progress(1)
|
||||
progbar.show_progress(prefix="Write", pos=0, total=total, display=info)
|
||||
with open(filename, 'rb') as rf:
|
||||
if self.send_section_header(partname):
|
||||
adr = 0
|
||||
adr = lba
|
||||
while filesize > 0:
|
||||
subdata = rf.read(wbsize)
|
||||
if len(subdata) < wbsize + 1:
|
||||
subdata += b'\xFF' * ((wbsize + 1) - len(subdata))
|
||||
if len(subdata)<1024:
|
||||
subdata += (1024-len(subdata))*b'\xFF'
|
||||
scmd = b"\x07" + pack("<I", adr) + subdata
|
||||
resp = self.send(scmd)
|
||||
if len(resp) == 0 or resp[1] != 0x8:
|
||||
if len(resp) == 0 or resp[0] != 0x8:
|
||||
self.error("Error on sending data at address %08X" % adr)
|
||||
return False
|
||||
adr += len(subdata)
|
||||
progbar.show_progress(prefix="Write", pos=adr, total=total, display=info)
|
||||
adr += 1024
|
||||
filesize -= len(subdata)
|
||||
if not self.qclose(0):
|
||||
progbar.show_progress(prefix="Write", pos=total, total=total, display=info)
|
||||
if not self.qclose(1):
|
||||
self.error("Error on closing data stream")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def read_sectors(self, sector, sectors, filename, info=False):
|
||||
old = 0
|
||||
sectorsize = self.settings.PAGESIZE // self.settings.sectors_per_page
|
||||
if info:
|
||||
print_progress(0, 100, prefix='Progress:', suffix='Complete', bar_length=50)
|
||||
progbar = progress(sectorsize)
|
||||
progbar.show_progress(prefix="Read", pos=0, total=sectors, display=info)
|
||||
with open(filename, "wb") as write_handle:
|
||||
while sector < sectors:
|
||||
offset = (sector // self.settings.sectors_per_page) * self.settings.PAGESIZE
|
||||
|
@ -214,24 +231,23 @@ class Streaming(metaclass=LogBase):
|
|||
data = data[sectorsize * sector:]
|
||||
write_handle.write(data)
|
||||
sector += sectorstoread
|
||||
if info:
|
||||
prog = round(float(sector) / float(sectors) * float(100), 1)
|
||||
if prog > old:
|
||||
print_progress(prog, 100, prefix='Progress:', suffix='Complete (Sector %d)' % sector,
|
||||
bar_length=50)
|
||||
old = prog
|
||||
progbar.show_progress(prefix="Read", pos=sector, total=sectors, display=info)
|
||||
self.nand_post()
|
||||
if info:
|
||||
print_progress(100, 100, prefix='Progress:', suffix='Complete', bar_length=50)
|
||||
progbar.show_progress(prefix="Read", pos=sectors, total=sectors, display=info)
|
||||
return True
|
||||
|
||||
def send_ptable(self, parttable, mode):
|
||||
def send_ptable(self, parttable, mode=0):
|
||||
cmdbuf = b"\x19" + pack("<B", mode) + parttable
|
||||
# mode 0x01 = override existing table
|
||||
resp = self.send(cmdbuf)
|
||||
if resp[1] != 0x1a:
|
||||
if resp[0] != 0x1a and resp[1] != 0x00:
|
||||
self.error("Error on sending raw partition table")
|
||||
return False
|
||||
elif resp[2] == 0x0:
|
||||
else:
|
||||
# 0x0 – Partition table accepted
|
||||
# 0x1 – Partition table differs, override is accepted
|
||||
# 0x2 – Partition table format not recognized, does not accept override
|
||||
# 0x3 – Erase operation failed
|
||||
return True
|
||||
self.error("Partition tables do not match - you need to fully flash the modem")
|
||||
return False
|
||||
|
@ -635,16 +651,29 @@ class Streaming(metaclass=LogBase):
|
|||
partdata = rf.read()
|
||||
if partdata != -1:
|
||||
data = partdata[0x10:]
|
||||
for i in range(0, len(data) // 0x1C):
|
||||
name, offset, length, attr1, attr2, attr3, which_flash = unpack("16sIIBBBB",
|
||||
data[i * 0x1C:(i * 0x1C) + 0x1C])
|
||||
magic1, magic2, version, partcount = unpack("<IIII", partdata[:0x10])
|
||||
partitions["magic1"] = magic1
|
||||
partitions["magic2"] = magic2
|
||||
partitions["version"] = version
|
||||
partitions["partcount"] = partcount
|
||||
offset = 0
|
||||
for i in range(partcount):
|
||||
if magic1 == 0xAA7D1B9a and magic2 == 0x1F7D48BC:
|
||||
name, length, spare, attr1, attr2, attr3, which_flash = unpack("16sIIBBBB",
|
||||
data[i * 0x1C:(i * 0x1C) + 0x1C])
|
||||
else:
|
||||
name, offset, length, attr1, attr2, attr3, which_flash = unpack("16sIIBBBB",
|
||||
data[i * 0x1C:(i * 0x1C) + 0x1C])
|
||||
spare = 0
|
||||
if name[1] != 0x3A:
|
||||
break
|
||||
partitions[name[2:].rstrip(b"\x00").decode('utf-8').lower()] = dict(offset=offset,
|
||||
length=length & 0xFFFF,
|
||||
partitions[name[2:].rstrip(b"\x00").decode('utf-8')] = dict(offset=offset,
|
||||
length=(length+spare) & 0xFFFF,
|
||||
attr1=attr1, attr2=attr2,
|
||||
attr3=attr3,
|
||||
which_flash=which_flash)
|
||||
if magic1 == 0xAA7D1B9a and magic2 == 0x1F7D48BC:
|
||||
offset += length + spare
|
||||
return partitions
|
||||
return {}
|
||||
|
||||
|
@ -728,6 +757,7 @@ class Streaming(metaclass=LogBase):
|
|||
data = unpack(str(hp.numberOfSectors) + "I", resp[offset + 4:offset + 4 + (4 * hp.numberOfSectors)])
|
||||
hp.sectorSizes = data
|
||||
hp.featureBits = resp[offset + 4 + hp.numberOfSectors * 4:offset + 4 + hp.numberOfSectors * 4 + 1]
|
||||
self.hp = hp
|
||||
"""
|
||||
self.settings.PAGESIZE=512
|
||||
self.settings.UD_SIZE_BYTES=512
|
||||
|
@ -740,7 +770,7 @@ class Streaming(metaclass=LogBase):
|
|||
return False, hp
|
||||
|
||||
def connect(self, mode=1):
|
||||
time.sleep(0.200)
|
||||
# time.sleep(0.200)
|
||||
self.memread = self.patched_memread
|
||||
if mode == 0:
|
||||
cmdbuf = bytearray(
|
||||
|
@ -826,7 +856,10 @@ class Streaming(metaclass=LogBase):
|
|||
self.settings.num_pages_per_blk / 1024 * self.settings.PAGESIZE / 1024))
|
||||
|
||||
val = resp[1].flashId.decode('utf-8') if resp[1].flashId[0] != 0x65 else ""
|
||||
self.info("Flash memory: %s %s, %s" % (self.settings.flash_mfr, val, self.settings.flash_descr))
|
||||
self.info("Flash memory: %s %s, %s (vendor: 0x%02X id: 0x%02X)" % (self.settings.flash_mfr, val,
|
||||
self.settings.flash_descr,
|
||||
self.settings.flash_pid,
|
||||
self.settings.flash_fid))
|
||||
# self.info("Maximum packet size: %i byte",*((unsigned int*)&rbuf[0x24]))
|
||||
self.info(
|
||||
"Page size: %d bytes (%d sectors)" % (self.settings.PAGESIZE, self.settings.sectors_per_page))
|
||||
|
@ -852,8 +885,8 @@ class Streaming(metaclass=LogBase):
|
|||
old = 0
|
||||
pos = 0
|
||||
toread = length
|
||||
if info:
|
||||
print_progress(0, 100, prefix='Progress:', suffix='Complete', bar_length=50)
|
||||
progbar = progress(1)
|
||||
progbar.show_progress(prefix="Read", pos=0, total=length, display=info)
|
||||
with open(filename, "wb") as wf:
|
||||
while toread > 0:
|
||||
size = 0x20000
|
||||
|
@ -868,44 +901,39 @@ class Streaming(metaclass=LogBase):
|
|||
break
|
||||
toread -= size
|
||||
pos += size
|
||||
progbar.show_progress(prefix="Read", pos=pos, total=length, display=info)
|
||||
if info:
|
||||
prog = round(float(pos) / float(length) * float(100), 1)
|
||||
if prog > old:
|
||||
print_progress(prog, 100, prefix='Progress:', suffix='Complete (Offset: %08X)' % (offset + pos),
|
||||
bar_length=50)
|
||||
old = prog
|
||||
if info:
|
||||
print_progress(100, 100, prefix='Progress:', suffix='Complete', bar_length=50)
|
||||
progbar.show_progress(prefix="Read", pos=length, total=length, display=info)
|
||||
return True
|
||||
|
||||
def read_blocks(self, fw, block, length, cwsize, savespare=False, info=True):
|
||||
badblocks = 0
|
||||
old = 0
|
||||
pos = 0
|
||||
progbar = progress(1)
|
||||
totallength = length * self.settings.num_pages_per_blk * self.settings.PAGESIZE
|
||||
if info:
|
||||
print_progress(0, 100, prefix='Progress:', suffix='Complete', bar_length=50)
|
||||
startoffset = block * self.settings.num_pages_per_blk * self.settings.PAGESIZE
|
||||
endoffset = startoffset + totallength
|
||||
progbar.show_progress(prefix="Read", pos=pos, total=totallength, display=info)
|
||||
|
||||
for offset in range(startoffset, endoffset, self.settings.PAGESIZE):
|
||||
pages = int(offset / self.settings.PAGESIZE)
|
||||
curblock = int(pages / self.settings.num_pages_per_blk)
|
||||
curpage = int(pages - curblock * self.settings.num_pages_per_blk)
|
||||
data, spare = self.flash_read(curblock, curpage, self.settings.sectors_per_page, cwsize)
|
||||
if self.bbtbl[curblock] != 1 or (self.settings.bad_processing_flag != BadFlags.BAD_SKIP.value):
|
||||
fw.write(data)
|
||||
if savespare:
|
||||
fw.write(spare)
|
||||
for curblock in range(block,block+length):
|
||||
for curpage in range(self.settings.num_pages_per_blk):
|
||||
data, spare = self.flash_read(curblock, curpage, self.settings.sectors_per_page, cwsize)
|
||||
pos = (curblock * self.settings.num_pages_per_blk + curpage) * self.settings.PAGESIZE
|
||||
progbar.show_progress(prefix="Read", pos=pos, total=totallength, display=info)
|
||||
if self.bbtbl[curblock] != 1 or (self.settings.bad_processing_flag != BadFlags.BAD_SKIP.value):
|
||||
fw.write(data)
|
||||
if savespare:
|
||||
fw.write(spare)
|
||||
else:
|
||||
self.debug("Bad block at block %d" % curblock)
|
||||
badblocks += 1
|
||||
pos += self.settings.PAGESIZE
|
||||
if info:
|
||||
prog = round(float(pos) / float(totallength) * float(100), 1)
|
||||
if prog > old:
|
||||
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
|
||||
old = prog
|
||||
|
||||
progbar.show_progress(prefix="Read", pos=totallength, total=totallength, display=info)
|
||||
return badblocks
|
||||
|
||||
"""
|
||||
|
|
|
@ -50,12 +50,12 @@ class streaming_client(metaclass=LogBase):
|
|||
self.printer("-------------------------------------------------------------")
|
||||
for name in partitions:
|
||||
partition = partitions[name]
|
||||
if not isinstance(partition,dict):
|
||||
continue
|
||||
for i in range(0x10 - len(name)):
|
||||
name += " "
|
||||
offset = partition[
|
||||
"offset"] * self.streaming.settings.num_pages_per_blk * self.streaming.settings.PAGESIZE
|
||||
length = partition[
|
||||
"length"] * self.streaming.settings.num_pages_per_blk * self.streaming.settings.PAGESIZE
|
||||
offset = partition["offset"] * self.streaming.settings.num_pages_per_blk * self.streaming.settings.PAGESIZE
|
||||
length = partition["length"] * self.streaming.settings.num_pages_per_blk * self.streaming.settings.PAGESIZE
|
||||
attr1 = partition["attr1"]
|
||||
attr2 = partition["attr2"]
|
||||
attr3 = partition["attr3"]
|
||||
|
@ -108,7 +108,7 @@ class streaming_client(metaclass=LogBase):
|
|||
i = 0
|
||||
rpartitions = self.streaming.get_partitions()
|
||||
for partition in partitions:
|
||||
if partition.lower() in rpartitions:
|
||||
if partition in rpartitions:
|
||||
spartition = rpartitions[partition]
|
||||
offset = spartition["offset"]
|
||||
length = spartition["length"]
|
||||
|
@ -314,17 +314,45 @@ class streaming_client(metaclass=LogBase):
|
|||
partitionfilename = ""
|
||||
if "--partitionfilename" in options:
|
||||
partitionfilename = options["--partitionfilename"]
|
||||
if not os.path.exists(partitionfilename):
|
||||
self.error(f"Error: Couldn't find partition file: {partitionfilename}")
|
||||
return False
|
||||
if partitionfilename is not None:
|
||||
if not os.path.exists(partitionfilename):
|
||||
self.error(f"Error: Couldn't find partition file: {partitionfilename}")
|
||||
return False
|
||||
else:
|
||||
ptable = open(partitionfilename,"rb").read()
|
||||
else:
|
||||
self.error("Partition file is needed for writing (--partitionfilename)")
|
||||
sys.exit(1)
|
||||
if not os.path.exists(filename):
|
||||
self.error(f"Error: Couldn't find file: {filename}")
|
||||
return False
|
||||
if partitionfilename == "":
|
||||
"""
|
||||
if partitionfilename is None:
|
||||
ptable = None
|
||||
rpartitions = self.streaming.get_partitions()
|
||||
if partitionname in rpartitions:
|
||||
spartition = rpartitions[partitionname]
|
||||
offset = spartition["offset"]
|
||||
length = spartition["length"]
|
||||
attr1 = spartition["attr1"]
|
||||
attr2 = spartition["attr2"]
|
||||
attr3 = spartition["attr3"]
|
||||
which_flash = spartition["which_flash"]
|
||||
numparts = 1
|
||||
pname = bytes("0:"+partitionname,'utf-8')
|
||||
pname += (16-len(pname))*b"\x00"
|
||||
ptable = pack("<IIII",0xAA7D1B9A,0x1F7D48BC,rpartitions["version"],numparts)
|
||||
ptable += pname
|
||||
ptable += pack("<IIBBBB",offset,length,attr1,attr2,attr3,which_flash)
|
||||
while len(ptable)%4!=0:
|
||||
ptable += b"\xFF"
|
||||
else:
|
||||
self.error(f"Partition {partitionname} not found. Aborting.")
|
||||
return False
|
||||
else:
|
||||
rpartitions = self.streaming.get_partitions(partitionfilename)
|
||||
if self.streaming.enter_flash_mode():
|
||||
"""
|
||||
rpartitions = self.streaming.get_partitions(partitionfilename)
|
||||
if self.streaming.enter_flash_mode(ptable=ptable):
|
||||
if partitionname in rpartitions:
|
||||
spartition = rpartitions[partitionname]
|
||||
offset = spartition["offset"]
|
||||
|
@ -341,7 +369,7 @@ class streaming_client(metaclass=LogBase):
|
|||
return False
|
||||
if self.streaming.modules is not None:
|
||||
self.streaming.modules.writeprepare()
|
||||
if self.streaming.write_flash(partitionname, filename):
|
||||
if self.streaming.write_flash(lba=0, partname=partitionname, filename=filename):
|
||||
self.printer(f"Wrote {filename} to sector {str(offset)}.")
|
||||
return True
|
||||
else:
|
||||
|
|
|
@ -1,690 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) B.Kerler 2018-2021
|
||||
import io
|
||||
import logging
|
||||
|
||||
import usb.core # pyusb
|
||||
import usb.util
|
||||
import time
|
||||
import inspect
|
||||
import array
|
||||
import usb.backend.libusb0
|
||||
import usb.backend.libusb1
|
||||
from enum import Enum
|
||||
from binascii import hexlify
|
||||
from ctypes import c_void_p, c_int
|
||||
from edlclient.Library.utils import *
|
||||
from struct import pack, calcsize
|
||||
|
||||
USB_DIR_OUT = 0 # to device
|
||||
USB_DIR_IN = 0x80 # to host
|
||||
|
||||
# USB types, the second of three bRequestType fields
|
||||
USB_TYPE_MASK = (0x03 << 5)
|
||||
USB_TYPE_STANDARD = (0x00 << 5)
|
||||
USB_TYPE_CLASS = (0x01 << 5)
|
||||
USB_TYPE_VENDOR = (0x02 << 5)
|
||||
USB_TYPE_RESERVED = (0x03 << 5)
|
||||
|
||||
# USB recipients, the third of three bRequestType fields
|
||||
USB_RECIP_MASK = 0x1f
|
||||
USB_RECIP_DEVICE = 0x00
|
||||
USB_RECIP_INTERFACE = 0x01
|
||||
USB_RECIP_ENDPOINT = 0x02
|
||||
USB_RECIP_OTHER = 0x03
|
||||
# From Wireless USB 1.0
|
||||
USB_RECIP_PORT = 0x04
|
||||
USB_RECIP_RPIPE = 0x05
|
||||
|
||||
tag = 0
|
||||
|
||||
CDC_CMDS = {
|
||||
"SEND_ENCAPSULATED_COMMAND": 0x00,
|
||||
"GET_ENCAPSULATED_RESPONSE": 0x01,
|
||||
"SET_COMM_FEATURE": 0x02,
|
||||
"GET_COMM_FEATURE": 0x03,
|
||||
"CLEAR_COMM_FEATURE": 0x04,
|
||||
"SET_LINE_CODING": 0x20,
|
||||
"GET_LINE_CODING": 0x21,
|
||||
"SET_CONTROL_LINE_STATE": 0x22,
|
||||
"SEND_BREAK": 0x23, # wValue is break time
|
||||
}
|
||||
|
||||
|
||||
class UsbClass(metaclass=LogBase):
|
||||
|
||||
def load_windows_dll(self):
|
||||
if os.name == 'nt':
|
||||
windows_dir = None
|
||||
try:
|
||||
# add pygame folder to Windows DLL search paths
|
||||
windows_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "Windows")
|
||||
try:
|
||||
os.add_dll_directory(windows_dir)
|
||||
except Exception:
|
||||
pass
|
||||
os.environ['PATH'] = windows_dir + ';' + os.environ['PATH']
|
||||
except Exception:
|
||||
pass
|
||||
del windows_dir
|
||||
|
||||
def __init__(self, loglevel=logging.INFO, portconfig=None, devclass=-1):
|
||||
self.load_windows_dll()
|
||||
self.connected = False
|
||||
self.timeout = None
|
||||
self.vid = None
|
||||
self.pid = None
|
||||
self.device = None
|
||||
self.EP_IN = None
|
||||
self.EP_OUT = None
|
||||
self.interface = None
|
||||
self.stopbits = None
|
||||
self.databits = None
|
||||
self.baudrate = None
|
||||
self.parity = None
|
||||
self.configuration = None
|
||||
self.backend = None
|
||||
self.loglevel = loglevel
|
||||
self.portconfig = portconfig
|
||||
self.devclass = devclass
|
||||
self.__logger = self.__logger
|
||||
self.info = self.__logger.info
|
||||
self.error = self.__logger.error
|
||||
self.warning = self.__logger.warning
|
||||
self.debug = self.__logger.debug
|
||||
self.__logger.setLevel(loglevel)
|
||||
self.buffer = array.array('B', [0]) * 1048576
|
||||
if loglevel == logging.DEBUG:
|
||||
logfilename = "log.txt"
|
||||
fh = logging.FileHandler(logfilename)
|
||||
self.__logger.addHandler(fh)
|
||||
|
||||
if sys.platform.startswith('freebsd') or sys.platform.startswith('linux'):
|
||||
self.backend = usb.backend.libusb1.get_backend(find_library=lambda x: "libusb-1.0.so")
|
||||
elif sys.platform.startswith('win32'):
|
||||
if calcsize("P") * 8 == 64:
|
||||
self.backend = usb.backend.libusb1.get_backend(find_library=lambda x: "libusb-1.0.dll")
|
||||
else:
|
||||
self.backend = usb.backend.libusb1.get_backend(find_library=lambda x: "libusb32-1.0.dll")
|
||||
if self.backend is not None:
|
||||
try:
|
||||
self.backend.lib.libusb_set_option.argtypes = [c_void_p, c_int]
|
||||
self.backend.lib.libusb_set_option(self.backend.ctx, 1)
|
||||
except:
|
||||
self.backend = None
|
||||
|
||||
def verify_data(self, data, pre="RX:"):
|
||||
self.debug("", stack_info=True)
|
||||
if isinstance(data, bytes) or isinstance(data, bytearray):
|
||||
if data[:5] == b"<?xml":
|
||||
try:
|
||||
rdata = b""
|
||||
for line in data.split(b"\n"):
|
||||
try:
|
||||
self.debug(pre + line.decode('utf-8'))
|
||||
rdata += line + b"\n"
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
v = hexlify(line)
|
||||
self.debug(str(e))
|
||||
self.debug(pre + v.decode('utf-8'))
|
||||
return rdata
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
self.debug(str(e))
|
||||
pass
|
||||
if logging.DEBUG >= self.__logger.level:
|
||||
self.debug(pre + hexlify(data).decode('utf-8'))
|
||||
else:
|
||||
if logging.DEBUG >= self.__logger.level:
|
||||
self.debug(pre + data)
|
||||
return data
|
||||
|
||||
def getinterfacecount(self):
|
||||
if self.vid is not None:
|
||||
self.device = usb.core.find(idVendor=self.vid, idProduct=self.pid)
|
||||
if self.device is None:
|
||||
self.debug("Couldn't detect the device. Is it connected ?")
|
||||
return False
|
||||
try:
|
||||
self.device.set_configuration()
|
||||
except Exception as e:
|
||||
self.debug(str(e))
|
||||
pass
|
||||
self.configuration = self.device.get_active_configuration()
|
||||
self.debug(2, self.configuration)
|
||||
return self.configuration.bNumInterfaces
|
||||
else:
|
||||
self.error("No device detected. Is it connected ?")
|
||||
return 0
|
||||
|
||||
def setlinecoding(self, baudrate=None, parity=0, databits=8, stopbits=1):
|
||||
sbits = {1: 0, 1.5: 1, 2: 2}
|
||||
dbits = {5, 6, 7, 8, 16}
|
||||
pmodes = {0, 1, 2, 3, 4}
|
||||
brates = {300, 600, 1200, 2400, 4800, 9600, 14400,
|
||||
19200, 28800, 38400, 57600, 115200, 230400}
|
||||
|
||||
if stopbits is not None:
|
||||
if stopbits not in sbits.keys():
|
||||
valid = ", ".join(str(k) for k in sorted(sbits.keys()))
|
||||
raise ValueError("Valid stopbits are " + valid)
|
||||
self.stopbits = stopbits
|
||||
else:
|
||||
self.stopbits = 0
|
||||
|
||||
if databits is not None:
|
||||
if databits not in dbits:
|
||||
valid = ", ".join(str(d) for d in sorted(dbits))
|
||||
raise ValueError("Valid databits are " + valid)
|
||||
self.databits = databits
|
||||
else:
|
||||
self.databits = 0
|
||||
|
||||
if parity is not None:
|
||||
if parity not in pmodes:
|
||||
valid = ", ".join(str(pm) for pm in sorted(pmodes))
|
||||
raise ValueError("Valid parity modes are " + valid)
|
||||
self.parity = parity
|
||||
else:
|
||||
self.parity = 0
|
||||
|
||||
if baudrate is not None:
|
||||
if baudrate not in brates:
|
||||
brs = sorted(brates)
|
||||
dif = [abs(br - baudrate) for br in brs]
|
||||
best = brs[dif.index(min(dif))]
|
||||
raise ValueError(
|
||||
"Invalid baudrates, nearest valid is {}".format(best))
|
||||
self.baudrate = baudrate
|
||||
|
||||
linecode = [
|
||||
self.baudrate & 0xff,
|
||||
(self.baudrate >> 8) & 0xff,
|
||||
(self.baudrate >> 16) & 0xff,
|
||||
(self.baudrate >> 24) & 0xff,
|
||||
sbits[self.stopbits],
|
||||
self.parity,
|
||||
self.databits]
|
||||
|
||||
txdir = 0 # 0:OUT, 1:IN
|
||||
req_type = 1 # 0:std, 1:class, 2:vendor
|
||||
recipient = 1 # 0:device, 1:interface, 2:endpoint, 3:other
|
||||
req_type = (txdir << 7) + (req_type << 5) + recipient
|
||||
data = bytearray(linecode)
|
||||
wlen = self.device.ctrl_transfer(
|
||||
req_type, CDC_CMDS["SET_LINE_CODING"],
|
||||
data_or_wlength=data, windex=1)
|
||||
self.debug("Linecoding set, {}b sent".format(wlen))
|
||||
|
||||
def setbreak(self):
|
||||
txdir = 0 # 0:OUT, 1:IN
|
||||
req_type = 1 # 0:std, 1:class, 2:vendor
|
||||
recipient = 1 # 0:device, 1:interface, 2:endpoint, 3:other
|
||||
req_type = (txdir << 7) + (req_type << 5) + recipient
|
||||
wlen = self.device.ctrl_transfer(
|
||||
bmrequesttype=req_type, brequest=CDC_CMDS["SEND_BREAK"],
|
||||
wvalue=0, data_or_wlength=0, windex=1)
|
||||
self.debug("Break set, {}b sent".format(wlen))
|
||||
|
||||
def setcontrollinestate(self, rts=None, dtr=None, isftdi=False):
|
||||
ctrlstate = (2 if rts else 0) + (1 if dtr else 0)
|
||||
if isftdi:
|
||||
ctrlstate += (1 << 8) if dtr is not None else 0
|
||||
ctrlstate += (2 << 8) if rts is not None else 0
|
||||
txdir = 0 # 0:OUT, 1:IN
|
||||
req_type = 2 if isftdi else 1 # 0:std, 1:class, 2:vendor
|
||||
# 0:device, 1:interface, 2:endpoint, 3:other
|
||||
recipient = 0 if isftdi else 1
|
||||
req_type = (txdir << 7) + (req_type << 5) + recipient
|
||||
|
||||
wlen = self.device.ctrl_transfer(
|
||||
bmrequesttype=req_type,
|
||||
brequest=1 if isftdi else CDC_CMDS["SET_CONTROL_LINE_STATE"],
|
||||
wvalue=ctrlstate,
|
||||
windex=1,
|
||||
data_or_wlength=0)
|
||||
self.debug("Linecoding set, {}b sent".format(wlen))
|
||||
|
||||
def connect(self, EP_IN=-1, EP_OUT=-1):
|
||||
if self.connected:
|
||||
self.close()
|
||||
self.connected = False
|
||||
for usbid in self.portconfig:
|
||||
vid = usbid[0]
|
||||
pid = usbid[1]
|
||||
interface = usbid[2]
|
||||
self.device = usb.core.find(idVendor=vid, idProduct=pid, backend=self.backend)
|
||||
if self.device is not None:
|
||||
self.vid = vid
|
||||
self.pid = pid
|
||||
self.interface = interface
|
||||
break
|
||||
|
||||
if self.device is None:
|
||||
self.debug("Couldn't detect the device. Is it connected ?")
|
||||
return False
|
||||
# try:
|
||||
# self.device.set_configuration()
|
||||
# except:
|
||||
# pass
|
||||
|
||||
try:
|
||||
self.configuration = self.device.get_active_configuration()
|
||||
except usb.core.USBError as e:
|
||||
if e.strerror == "Configuration not set":
|
||||
self.device.set_configuration()
|
||||
self.configuration = self.device.get_active_configuration()
|
||||
if e.errno == 13:
|
||||
self.backend = usb.backend.libusb0.get_backend()
|
||||
self.device = usb.core.find(idVendor=self.vid, idProduct=self.pid, backend=self.backend)
|
||||
if self.configuration is None:
|
||||
self.error("Couldn't get device configuration.")
|
||||
return False
|
||||
if self.interface == -1:
|
||||
for interfacenum in range(0, self.configuration.bNumInterfaces):
|
||||
itf = usb.util.find_descriptor(self.configuration, bInterfaceNumber=interfacenum)
|
||||
if self.devclass != -1:
|
||||
if itf.bInterfaceClass == self.devclass: # MassStorage
|
||||
self.interface = interfacenum
|
||||
break
|
||||
else:
|
||||
self.interface = interfacenum
|
||||
break
|
||||
|
||||
self.debug(self.configuration)
|
||||
if self.interface > self.configuration.bNumInterfaces:
|
||||
print("Invalid interface, max number is %d" % self.configuration.bNumInterfaces)
|
||||
return False
|
||||
|
||||
if self.interface != -1:
|
||||
itf = usb.util.find_descriptor(self.configuration, bInterfaceNumber=self.interface)
|
||||
try:
|
||||
if self.device.is_kernel_driver_active(0):
|
||||
self.debug("Detaching kernel driver")
|
||||
self.device.detach_kernel_driver(0)
|
||||
except Exception as err:
|
||||
self.debug("No kernel driver supported: " + str(err))
|
||||
try:
|
||||
usb.util.claim_interface(self.device, 0)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
if self.device.is_kernel_driver_active(self.interface):
|
||||
self.debug("Detaching kernel driver")
|
||||
self.device.detach_kernel_driver(self.interface)
|
||||
except Exception as err:
|
||||
self.debug("No kernel driver supported: " + str(err))
|
||||
try:
|
||||
if self.interface != 0:
|
||||
usb.util.claim_interface(self.device, self.interface)
|
||||
except:
|
||||
pass
|
||||
|
||||
if EP_OUT == -1:
|
||||
self.EP_OUT = usb.util.find_descriptor(itf,
|
||||
# match the first OUT endpoint
|
||||
custom_match=lambda e: \
|
||||
usb.util.endpoint_direction(e.bEndpointAddress) ==
|
||||
usb.util.ENDPOINT_OUT)
|
||||
else:
|
||||
self.EP_OUT = EP_OUT
|
||||
if EP_IN == -1:
|
||||
self.EP_IN = usb.util.find_descriptor(itf,
|
||||
# match the first OUT endpoint
|
||||
custom_match=lambda e: \
|
||||
usb.util.endpoint_direction(e.bEndpointAddress) ==
|
||||
usb.util.ENDPOINT_IN)
|
||||
else:
|
||||
self.EP_IN = EP_IN
|
||||
|
||||
self.connected = True
|
||||
return True
|
||||
else:
|
||||
print("Couldn't find MassStorage interface. Aborting.")
|
||||
self.connected = False
|
||||
return False
|
||||
|
||||
def close(self, reset=False):
|
||||
if self.connected:
|
||||
try:
|
||||
if reset:
|
||||
self.device.reset()
|
||||
if not self.device.is_kernel_driver_active(self.interface):
|
||||
# self.device.attach_kernel_driver(self.interface) #Do NOT uncomment
|
||||
self.device.attach_kernel_driver(0)
|
||||
except Exception as err:
|
||||
self.debug(str(err))
|
||||
pass
|
||||
usb.util.dispose_resources(self.device)
|
||||
del self.device
|
||||
self.connected = False
|
||||
|
||||
def write(self, command):
|
||||
pktsize=self.EP_OUT.wMaxPacketSize
|
||||
if isinstance(command, str):
|
||||
command = bytes(command, 'utf-8')
|
||||
if command == b'':
|
||||
try:
|
||||
self.EP_OUT.write(b'')
|
||||
except usb.core.USBError as e:
|
||||
error = str(e.strerror)
|
||||
if "timeout" in error:
|
||||
time.sleep(0.01)
|
||||
try:
|
||||
self.EP_OUT.write(b'')
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
self.debug(str(e))
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
i = 0
|
||||
try:
|
||||
buffer=array.array('B',command)
|
||||
self.EP_OUT.write(buffer)
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
# print("Error while writing")
|
||||
if "timed out" in str(e):
|
||||
self.debug(str(e))
|
||||
time.sleep(0.01)
|
||||
i += 1
|
||||
if i == 3:
|
||||
return False
|
||||
pass
|
||||
else:
|
||||
self.error(str(e))
|
||||
return False
|
||||
if self.loglevel == logging.DEBUG:
|
||||
self.verify_data(bytearray(command), "TX:")
|
||||
return True
|
||||
|
||||
def read(self, length=None, timeout=None):
|
||||
if length is None:
|
||||
length=self.EP_IN.wMaxPacketSize
|
||||
if self.loglevel==logging.DEBUG:
|
||||
self.debug(inspect.currentframe().f_back.f_code.co_name + ":" + hex(length))
|
||||
tmp = bytearray()
|
||||
extend = tmp.extend
|
||||
if timeout is None:
|
||||
timeout = self.timeout
|
||||
buffer = self.buffer[:length]
|
||||
ep_read = self.EP_IN.read
|
||||
while len(tmp) == 0:
|
||||
try:
|
||||
length=ep_read(buffer, timeout)
|
||||
extend(buffer[:length])
|
||||
if len(tmp)>0:
|
||||
if self.loglevel == logging.DEBUG:
|
||||
self.verify_data(tmp, "RX:")
|
||||
return tmp
|
||||
except usb.core.USBError as e:
|
||||
error = str(e.strerror)
|
||||
if "timed out" in error:
|
||||
# if platform.system()=='Windows':
|
||||
# time.sleep(0.05)
|
||||
# print("Waiting...")
|
||||
self.debug("Timed out")
|
||||
self.debug(tmp)
|
||||
return tmp
|
||||
elif "Overflow" in error:
|
||||
self.error("USB Overflow")
|
||||
sys.exit(0)
|
||||
elif e.errno is not None:
|
||||
print(repr(e), type(e), e.errno)
|
||||
sys.exit(0)
|
||||
else:
|
||||
break
|
||||
return tmp
|
||||
|
||||
def ctrl_transfer(self, bmrequesttype, brequest, wvalue, windex, data_or_wlength):
|
||||
ret = self.device.ctrl_transfer(bmrequesttype=bmrequesttype, brequest=brequest, wvalue=wvalue, windex=windex,
|
||||
data_or_wlength=data_or_wlength)
|
||||
return ret[0] | (ret[1] << 8)
|
||||
|
||||
|
||||
class ScsiCmds(Enum):
|
||||
SC_TEST_UNIT_READY = 0x00,
|
||||
SC_REQUEST_SENSE = 0x03,
|
||||
SC_FORMAT_UNIT = 0x04,
|
||||
SC_READ_6 = 0x08,
|
||||
SC_WRITE_6 = 0x0a,
|
||||
SC_INQUIRY = 0x12,
|
||||
SC_MODE_SELECT_6 = 0x15,
|
||||
SC_RESERVE = 0x16,
|
||||
SC_RELEASE = 0x17,
|
||||
SC_MODE_SENSE_6 = 0x1a,
|
||||
SC_START_STOP_UNIT = 0x1b,
|
||||
SC_SEND_DIAGNOSTIC = 0x1d,
|
||||
SC_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1e,
|
||||
SC_READ_FORMAT_CAPACITIES = 0x23,
|
||||
SC_READ_CAPACITY = 0x25,
|
||||
SC_WRITE_10 = 0x2a,
|
||||
SC_VERIFY = 0x2f,
|
||||
SC_READ_10 = 0x28,
|
||||
SC_SYNCHRONIZE_CACHE = 0x35,
|
||||
SC_READ_TOC = 0x43,
|
||||
SC_READ_HEADER = 0x44,
|
||||
SC_MODE_SELECT_10 = 0x55,
|
||||
SC_MODE_SENSE_10 = 0x5a,
|
||||
SC_READ_12 = 0xa8,
|
||||
SC_WRITE_12 = 0xaa,
|
||||
SC_PASCAL_MODE = 0xff
|
||||
|
||||
|
||||
command_block_wrapper = [
|
||||
('dCBWSignature', '4s'),
|
||||
('dCBWTag', 'I'),
|
||||
('dCBWDataTransferLength', 'I'),
|
||||
('bmCBWFlags', 'B'),
|
||||
('bCBWLUN', 'B'),
|
||||
('bCBWCBLength', 'B'),
|
||||
('CBWCB', '16s'),
|
||||
]
|
||||
command_block_wrapper_len = 31
|
||||
|
||||
command_status_wrapper = [
|
||||
('dCSWSignature', '4s'),
|
||||
('dCSWTag', 'I'),
|
||||
('dCSWDataResidue', 'I'),
|
||||
('bCSWStatus', 'B')
|
||||
]
|
||||
command_status_wrapper_len = 13
|
||||
|
||||
|
||||
class Scsi:
|
||||
"""
|
||||
FIHTDC, PCtool
|
||||
"""
|
||||
SC_READ_NV = 0xf0
|
||||
SC_SWITCH_STATUS = 0xf1
|
||||
SC_SWITCH_PORT = 0xf2
|
||||
SC_MODEM_STATUS = 0xf4
|
||||
SC_SHOW_PORT = 0xf5
|
||||
SC_MODEM_DISCONNECT = 0xf6
|
||||
SC_MODEM_CONNECT = 0xf7
|
||||
SC_DIAG_RUT = 0xf8
|
||||
SC_READ_BATTERY = 0xf9
|
||||
SC_READ_IMAGE = 0xfa
|
||||
SC_ENABLE_ALL_PORT = 0xfd
|
||||
SC_MASS_STORGE = 0xfe
|
||||
SC_ENTER_DOWNLOADMODE = 0xff
|
||||
SC_ENTER_FTMMODE = 0xe0
|
||||
SC_SWITCH_ROOT = 0xe1
|
||||
"""
|
||||
//Div2-5-3-Peripheral-LL-ADB_ROOT-00+/* } FIHTDC, PCtool */
|
||||
//StevenCPHuang 2011/08/12 porting base on 1050 --
|
||||
//StevenCPHuang_20110820,add Moto's mode switch cmd to support PID switch function ++
|
||||
"""
|
||||
SC_MODE_SWITCH = 0xD6
|
||||
|
||||
# /StevenCPHuang_20110820,add Moto's mode switch cmd to support PID switch function --
|
||||
|
||||
def __init__(self, loglevel=logging.INFO, vid=None, pid=None, interface=-1):
|
||||
self.vid = vid
|
||||
self.pid = pid
|
||||
self.interface = interface
|
||||
self.Debug = False
|
||||
self.usb = None
|
||||
self.loglevel = loglevel
|
||||
|
||||
def connect(self):
|
||||
self.usb = UsbClass(loglevel=self.loglevel, portconfig=[self.vid, self.pid, self.interface], devclass=8)
|
||||
if self.usb.connect():
|
||||
return True
|
||||
return False
|
||||
|
||||
# htcadb = "55534243123456780002000080000616687463800100000000000000000000";
|
||||
# Len 0x6, Command 0x16, "HTC" 01 = Enable, 02 = Disable
|
||||
def send_mass_storage_command(self, lun, cdb, direction, data_length):
|
||||
global tag
|
||||
cmd = cdb[0]
|
||||
if 0 <= cmd < 0x20:
|
||||
cdb_len = 6
|
||||
elif 0x20 <= cmd < 0x60:
|
||||
cdb_len = 10
|
||||
elif 0x60 <= cmd < 0x80:
|
||||
cdb_len = 0
|
||||
elif 0x80 <= cmd < 0xA0:
|
||||
cdb_len = 16
|
||||
elif 0xA0 <= cmd < 0xC0:
|
||||
cdb_len = 12
|
||||
else:
|
||||
cdb_len = 6
|
||||
|
||||
if len(cdb) != cdb_len:
|
||||
print("Error, cdb length doesn't fit allowed cbw packet length")
|
||||
return 0
|
||||
|
||||
if (cdb_len == 0) or (cdb_len > command_block_wrapper_len):
|
||||
print("Error, invalid data packet length, should be max of 31 bytes.")
|
||||
return 0
|
||||
else:
|
||||
data = write_object(command_block_wrapper, b"USBC", tag, data_length, direction, lun, cdb_len, cdb)[
|
||||
'raw_data']
|
||||
print(hexlify(data))
|
||||
if len(data) != 31:
|
||||
print("Error, invalid data packet length, should be 31 bytes, but length is %d" % len(data))
|
||||
return 0
|
||||
tag += 1
|
||||
self.usb.write(data, 31)
|
||||
return tag
|
||||
|
||||
def send_htc_adbenable(self):
|
||||
# do_reserve from f_mass_storage.c
|
||||
print("Sending HTC adb enable command")
|
||||
common_cmnd = b"\x16htc\x80\x01" # reserve_cmd + 'htc' + len + flag
|
||||
'''
|
||||
Flag values:
|
||||
1: Enable adb daemon from mass_storage
|
||||
2: Disable adb daemon from mass_storage
|
||||
3: cancel unmount BAP cdrom
|
||||
4: cancel unmount HSM rom
|
||||
'''
|
||||
lun = 0
|
||||
datasize = common_cmnd[4]
|
||||
timeout = 5000
|
||||
ret_tag = self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
|
||||
ret_tag += self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
|
||||
if datasize > 0:
|
||||
data = self.usb.read(datasize, timeout)
|
||||
print("DATA: " + hexlify(data).decode('utf-8'))
|
||||
print("Sent HTC adb enable command")
|
||||
|
||||
def send_htc_ums_adbenable(self): # HTC10
|
||||
# ums_ctrlrequest from f_mass_storage.c
|
||||
print("Sending HTC ums adb enable command")
|
||||
brequesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE
|
||||
brequest = 0xa0
|
||||
wvalue = 1
|
||||
'''
|
||||
wValue:
|
||||
0: Disable adb daemon
|
||||
1: Enable adb daemon
|
||||
'''
|
||||
windex = 0
|
||||
w_length = 1
|
||||
ret = self.usb.ctrl_transfer(brequesttype, brequest, wvalue, windex, w_length)
|
||||
print("Sent HTC ums adb enable command: %x" % ret)
|
||||
|
||||
def send_zte_adbenable(self): # zte blade
|
||||
common_cmnd = b"\x86zte\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # reserve_cmd + 'zte' + len + flag
|
||||
common_cmnd2 = b"\x86zte\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # reserve_cmd + 'zte' + len + flag
|
||||
'''
|
||||
Flag values:
|
||||
0: disable adbd ---for 736T
|
||||
1: enable adbd ---for 736T
|
||||
2: disable adbd ---for All except 736T
|
||||
3: enable adbd ---for All except 736T
|
||||
'''
|
||||
lun = 0
|
||||
datasize = common_cmnd[4]
|
||||
timeout = 5000
|
||||
ret_tag = self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
|
||||
ret_tag += self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
|
||||
ret_tag = self.send_mass_storage_command(lun, common_cmnd2, USB_DIR_IN, datasize)
|
||||
ret_tag += self.send_mass_storage_command(lun, common_cmnd2, USB_DIR_IN, datasize)
|
||||
if datasize > 0:
|
||||
data = self.usb.read(datasize, timeout)
|
||||
print("DATA: " + hexlify(data).decode('utf-8'))
|
||||
print("Send HTC adb enable command")
|
||||
|
||||
def send_fih_adbenable(self): # motorola xt560, nokia 3.1, #f_mass_storage.c
|
||||
if self.usb.connect():
|
||||
print("Sending FIH adb enable command")
|
||||
datasize = 0x24
|
||||
# reserve_cmd + 'FI' + flag + len + none
|
||||
common_cmnd = bytes([self.SC_SWITCH_PORT]) + b"FI1" + pack("<H", datasize)
|
||||
'''
|
||||
Flag values:
|
||||
common_cmnd[3]->1: Enable adb daemon from mass_storage
|
||||
common_cmnd[3]->0: Disable adb daemon from mass_storage
|
||||
'''
|
||||
lun = 0
|
||||
# datasize=common_cmnd[4]
|
||||
timeout = 5000
|
||||
ret_tag = None
|
||||
ret_tag += self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, 0x600)
|
||||
# ret_tag+=self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, 0x600)
|
||||
if datasize > 0:
|
||||
data = self.usb.read(datasize, timeout)
|
||||
print("DATA: " + hexlify(data).decode('utf-8'))
|
||||
print("Sent FIH adb enable command")
|
||||
self.usb.close()
|
||||
|
||||
def send_alcatel_adbenable(self): # Alcatel MW41
|
||||
if self.usb.connect():
|
||||
print("Sending alcatel adb enable command")
|
||||
datasize = 0x24
|
||||
common_cmnd = b"\x16\xf9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
lun = 0
|
||||
timeout = 5000
|
||||
ret_tag = None
|
||||
ret_tag += self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, 0x600)
|
||||
if datasize > 0:
|
||||
data = self.usb.read(datasize, timeout)
|
||||
print("DATA: " + hexlify(data).decode('utf-8'))
|
||||
print("Sent alcatel adb enable command")
|
||||
self.usb.close()
|
||||
|
||||
def send_fih_root(self):
|
||||
# motorola xt560, nokia 3.1, huawei u8850, huawei Ideos X6,
|
||||
# lenovo s2109, triumph M410, viewpad 7, #f_mass_storage.c
|
||||
if self.usb.connect():
|
||||
print("Sending FIH root command")
|
||||
datasize = 0x24
|
||||
# reserve_cmd + 'FIH' + len + flag + none
|
||||
common_cmnd = bytes([self.SC_SWITCH_ROOT]) + b"FIH" + pack("<H", datasize)
|
||||
lun = 0
|
||||
# datasize = common_cmnd[4]
|
||||
timeout = 5000
|
||||
ret_tag = self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, 0x600)
|
||||
ret_tag += self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, 0x600)
|
||||
if datasize > 0:
|
||||
data = self.usb.read(datasize, timeout)
|
||||
print("DATA: " + hexlify(data).decode('utf-8'))
|
||||
print("Sent FIH root command")
|
||||
self.usb.close()
|
||||
|
||||
def close(self):
|
||||
self.usb.close()
|
||||
return True
|
|
@ -1,52 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) B.Kerler 2018-2021
|
||||
import argparse
|
||||
from edlclient.Library.usblib import *
|
||||
|
||||
|
||||
def main():
|
||||
info = 'MassStorageBackdoor (c) B.Kerler 2019.'
|
||||
parser = argparse.ArgumentParser(description=info)
|
||||
print("\n" + info + "\n\n")
|
||||
parser.add_argument('-vid', metavar="<vid>", help='[Option] Specify vid, default=0x2e04)', default="0x2e04")
|
||||
parser.add_argument('-pid', metavar="<pid>", help='[Option] Specify pid, default=0xc025)', default="0xc025")
|
||||
parser.add_argument('-interface', metavar="<pid>", help='[Option] Specify interface number)', default="")
|
||||
parser.add_argument('-nokia', help='[Option] Enable Nokia adb backdoor', action='store_true')
|
||||
parser.add_argument('-alcatel', help='[Option] Enable alcatel adb backdoor', action='store_true')
|
||||
parser.add_argument('-zte', help='[Option] Enable zte adb backdoor', action='store_true')
|
||||
parser.add_argument('-htc', help='[Option] Enable htc adb backdoor', action='store_true')
|
||||
parser.add_argument('-htcums', help='[Option] Enable htc ums adb backdoor', action='store_true')
|
||||
args = parser.parse_args()
|
||||
vid = None
|
||||
pid = None
|
||||
if args.vid != "":
|
||||
vid = int(args.vid, 16)
|
||||
if args.pid != "":
|
||||
pid = int(args.pid, 16)
|
||||
if args.interface != "":
|
||||
interface = int(args.interface, 16)
|
||||
else:
|
||||
interface = -1
|
||||
|
||||
usbscsi = Scsi(vid, pid, interface)
|
||||
if usbscsi.connect():
|
||||
if args.nokia:
|
||||
usbscsi.send_fih_adbenable()
|
||||
usbscsi.send_fih_root()
|
||||
elif args.zte:
|
||||
usbscsi.send_zte_adbenable()
|
||||
elif args.htc:
|
||||
usbscsi.send_htc_adbenable()
|
||||
elif args.htcums:
|
||||
usbscsi.send_htc_ums_adbenable()
|
||||
elif args.alcatel:
|
||||
usbscsi.send_alcatel_adbenable()
|
||||
else:
|
||||
print("A command is required. Use -h to see options.")
|
||||
exit(0)
|
||||
usbscsi.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -13,6 +13,7 @@ import colorama
|
|||
import copy
|
||||
import datetime as dt
|
||||
import time
|
||||
from io import BytesIO
|
||||
from struct import unpack, pack
|
||||
|
||||
try:
|
||||
|
@ -25,6 +26,85 @@ except ImportError:
|
|||
print("Keystone library is missing (optional).")
|
||||
|
||||
|
||||
class structhelper_io:
|
||||
pos = 0
|
||||
|
||||
def __init__(self, data: BytesIO = None, direction='little'):
|
||||
self.data = data
|
||||
self.direction = direction
|
||||
|
||||
def setdata(self, data, offset=0):
|
||||
self.pos = offset
|
||||
self.data = data
|
||||
|
||||
def qword(self):
|
||||
dat = int.from_bytes(self.data.read(8), self.direction)
|
||||
return dat
|
||||
|
||||
def dword(self):
|
||||
dat = int.from_bytes(self.data.read(4), self.direction)
|
||||
return dat
|
||||
|
||||
def dwords(self, dwords=1):
|
||||
dat = [int.from_bytes(self.data.read(4), self.direction) for _ in range(dwords)]
|
||||
return dat
|
||||
|
||||
def short(self):
|
||||
dat = int.from_bytes(self.data.read(2), self.direction)
|
||||
return dat
|
||||
|
||||
def shorts(self, shorts):
|
||||
dat = [int.from_bytes(self.data.read(2), self.direction) for _ in range(shorts)]
|
||||
return dat
|
||||
|
||||
def bytes(self, rlen=1):
|
||||
dat = self.data.read(rlen)
|
||||
if dat == b'':
|
||||
return dat
|
||||
if rlen == 1:
|
||||
return dat[0]
|
||||
return dat
|
||||
|
||||
def string(self, rlen=1):
|
||||
dat = self.data.read(rlen)
|
||||
return dat
|
||||
|
||||
def getpos(self):
|
||||
return self.data.tell()
|
||||
|
||||
def seek(self, pos):
|
||||
self.data.seek(pos)
|
||||
|
||||
def find_binary(data, strf, pos=0):
|
||||
t = strf.split(b".")
|
||||
pre = 0
|
||||
offsets = []
|
||||
while pre != -1:
|
||||
pre = data[pos:].find(t[0], pre)
|
||||
if pre == -1:
|
||||
if len(offsets) > 0:
|
||||
for offset in offsets:
|
||||
error = 0
|
||||
rt = offset + len(t[0])
|
||||
for i in range(1, len(t)):
|
||||
if t[i] == b'':
|
||||
rt += 1
|
||||
continue
|
||||
rt += 1
|
||||
prep = data[rt:].find(t[i])
|
||||
if prep != 0:
|
||||
error = 1
|
||||
break
|
||||
rt += len(t[i])
|
||||
if error == 0:
|
||||
return offset + pos
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
offsets.append(pre)
|
||||
pre += 1
|
||||
return None
|
||||
|
||||
class progress:
|
||||
def __init__(self, pagesize):
|
||||
self.progtime = 0
|
||||
|
@ -45,6 +125,8 @@ class progress:
|
|||
return 0, 0, ""
|
||||
|
||||
def show_progress(self, prefix, pos, total, display=True):
|
||||
if pos > total:
|
||||
pos = total
|
||||
if pos != 0:
|
||||
prog = round(float(pos) / float(total) * float(100), 1)
|
||||
else:
|
||||
|
@ -54,13 +136,14 @@ class progress:
|
|||
self.start = time.time()
|
||||
self.progtime = time.time()
|
||||
self.progpos = pos
|
||||
print_progress(prog, 100, prefix='Done',
|
||||
suffix=prefix + ' (Sector 0x%X of 0x%X) %0.2f MB/s' %
|
||||
(pos // self.pagesize,
|
||||
total // self.pagesize,
|
||||
0), bar_length=50)
|
||||
if display:
|
||||
print_progress(prog, 100, prefix='Done',
|
||||
suffix=prefix + ' (Sector 0x%X of 0x%X) %0.2f MB/s' %
|
||||
(pos // self.pagesize,
|
||||
total // self.pagesize,
|
||||
0), bar_length=50)
|
||||
|
||||
if prog > self.prog:
|
||||
if prog > self.prog or prog==100.0:
|
||||
if display:
|
||||
t0 = time.time()
|
||||
tdiff = t0 - self.progtime
|
||||
|
@ -87,12 +170,12 @@ class progress:
|
|||
hinfo = "%02dm:%02ds left" % (min, sec)
|
||||
else:
|
||||
hinfo = "%02ds left" % sec
|
||||
|
||||
print_progress(prog, 100, prefix='Progress:',
|
||||
suffix=prefix + f' (Sector 0x%X of 0x%X, {hinfo}) %0.2f MB/s' %
|
||||
(pos // self.pagesize,
|
||||
total // self.pagesize,
|
||||
throughput), bar_length=50)
|
||||
if display:
|
||||
print_progress(prog, 100, prefix='Progress:',
|
||||
suffix=prefix + f' (Sector 0x%X of 0x%X, {hinfo}) %0.2f MB/s' %
|
||||
(pos // self.pagesize,
|
||||
total // self.pagesize,
|
||||
throughput), bar_length=50)
|
||||
self.prog = prog
|
||||
self.progpos = pos
|
||||
self.progtime = t0
|
||||
|
@ -104,28 +187,39 @@ class structhelper:
|
|||
self.pos = 0
|
||||
self.data = data
|
||||
|
||||
def qword(self):
|
||||
dat = unpack("<Q", self.data[self.pos:self.pos + 8])[0]
|
||||
def qword(self, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + "Q", self.data[self.pos:self.pos + 8])[0]
|
||||
self.pos += 8
|
||||
return dat
|
||||
|
||||
def dword(self):
|
||||
dat = unpack("<I", self.data[self.pos:self.pos + 4])[0]
|
||||
def dword(self, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + "I", self.data[self.pos:self.pos + 4])[0]
|
||||
self.pos += 4
|
||||
return dat
|
||||
|
||||
def dwords(self, dwords=1):
|
||||
dat = unpack("<" + str(dwords) + "I", self.data[self.pos:self.pos + 4 * dwords])
|
||||
def dwords(self, dwords=1, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + str(dwords) + "I", self.data[self.pos:self.pos + 4 * dwords])
|
||||
self.pos += 4 * dwords
|
||||
return dat
|
||||
|
||||
def short(self):
|
||||
dat = unpack("<H", self.data[self.pos:self.pos + 2])[0]
|
||||
def qwords(self, qwords=1, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + str(qwords) + "Q", self.data[self.pos:self.pos + 8 * qwords])
|
||||
self.pos += 8 * qwords
|
||||
return dat
|
||||
|
||||
def short(self, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + "H", self.data[self.pos:self.pos + 2])[0]
|
||||
self.pos += 2
|
||||
return dat
|
||||
|
||||
def shorts(self, shorts):
|
||||
dat = unpack("<" + str(shorts) + "H", self.data[self.pos:self.pos + 2*shorts])
|
||||
def shorts(self, shorts, big=False):
|
||||
e = ">" if big else "<"
|
||||
dat = unpack(e + str(shorts) + "H", self.data[self.pos:self.pos + 2 * shorts])
|
||||
self.pos += 2 * shorts
|
||||
return dat
|
||||
|
||||
|
|
|
@ -12,8 +12,13 @@ class xmlparser:
|
|||
if line == b'':
|
||||
continue
|
||||
line = b"<?xml" + line
|
||||
if b"\xf0\xe9\x88\x14" in line:
|
||||
line=line.replace(b"\xf0\xe9\x88\x14",b"")
|
||||
parser = ET.XMLParser(encoding="utf-8")
|
||||
tree = ET.fromstring(line, parser=parser)
|
||||
try:
|
||||
tree = ET.fromstring(line, parser=parser)
|
||||
except Exception as err:
|
||||
continue
|
||||
e = ET.ElementTree(tree).getroot()
|
||||
for atype in e.findall('response'):
|
||||
for field in atype.attrib:
|
||||
|
@ -27,8 +32,13 @@ class xmlparser:
|
|||
if line == b'':
|
||||
continue
|
||||
line = b"<?xml" + line
|
||||
if b"\xf0\xe9\x88\x14" in line:
|
||||
line=line.replace(b"\xf0\xe9\x88\x14",b"")
|
||||
parser = ET.XMLParser(encoding="utf-8")
|
||||
tree = ET.fromstring(line, parser=parser)
|
||||
try:
|
||||
tree = ET.fromstring(line, parser=parser)
|
||||
except Exception as err:
|
||||
continue
|
||||
e = ET.ElementTree(tree).getroot()
|
||||
for atype in e.findall('log'):
|
||||
if 'value' in atype.attrib:
|
||||
|
|
|
@ -11,7 +11,6 @@ import argparse
|
|||
import requests
|
||||
import hashlib
|
||||
|
||||
|
||||
try:
|
||||
from edlclient.Tools.qc_diag import qcdiag
|
||||
except ImportError as e:
|
||||
|
@ -20,25 +19,28 @@ except ImportError as e:
|
|||
import usb.core
|
||||
from enum import Enum
|
||||
import crypt
|
||||
|
||||
try:
|
||||
from edlclient.Tools.sierrakeygen import SierraKeygen
|
||||
except ImportError:
|
||||
import os, sys, inspect
|
||||
|
||||
current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||
parent_dir = os.path.dirname(current_dir)
|
||||
sys.path.insert(0, parent_dir)
|
||||
from sierrakeygen import SierraKeygen
|
||||
|
||||
|
||||
try:
|
||||
from edlclient.Library.utils import LogBase
|
||||
except Exception as e:
|
||||
import os,sys,inspect
|
||||
import os, sys, inspect
|
||||
|
||||
current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||
parent_dir = os.path.dirname(current_dir)
|
||||
sys.path.insert(0, parent_dir)
|
||||
from edlclient.Library.utils import LogBase
|
||||
|
||||
|
||||
class vendor(Enum):
|
||||
sierra = 0x1199
|
||||
quectel = 0x2c7c
|
||||
|
@ -46,12 +48,15 @@ class vendor(Enum):
|
|||
telit = 0x413c
|
||||
netgear = 0x0846
|
||||
|
||||
|
||||
class deviceclass:
|
||||
vid=0
|
||||
pid=0
|
||||
def __init__(self,vid,pid):
|
||||
self.vid=vid
|
||||
self.pid=pid
|
||||
vid = 0
|
||||
pid = 0
|
||||
|
||||
def __init__(self, vid, pid):
|
||||
self.vid = vid
|
||||
self.pid = pid
|
||||
|
||||
|
||||
class connection:
|
||||
def __init__(self, port=""):
|
||||
|
@ -61,10 +66,13 @@ class connection:
|
|||
if port == "":
|
||||
port = self.detect(port)
|
||||
if port != "":
|
||||
self.serial = serial.Serial(port=port, baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=1)
|
||||
self.connected = self.serial.is_open
|
||||
try:
|
||||
self.serial = serial.Serial(port=port, baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=1)
|
||||
self.connected = self.serial.is_open
|
||||
except:
|
||||
self.connected = False
|
||||
|
||||
def waitforusb(self,vid,pid):
|
||||
def waitforusb(self, vid, pid):
|
||||
timeout = 0
|
||||
while timeout < 10:
|
||||
for device in self.detectusbdevices():
|
||||
|
@ -75,12 +83,13 @@ class connection:
|
|||
timeout += 1
|
||||
return False
|
||||
|
||||
def websend(self,url):
|
||||
def websend(self, url):
|
||||
headers = {'Referer': 'http://192.168.0.1/index.html', 'Accept-Charset': 'UTF-8'}
|
||||
r = requests.get(url, headers=headers)
|
||||
if b"FACTORY:ok" in r.content or b"success" in r.content:
|
||||
print(f"Detected a ZTE in web mode .... switching mode success (convert back by sending \"AT+ZCDRUN=F\" via AT port)")
|
||||
return self.waitforusb(vendor.zte.value,0x0016)
|
||||
print(
|
||||
f"Detected a ZTE in web mode .... switching mode success (convert back by sending \"AT+ZCDRUN=F\" via AT port)")
|
||||
return self.waitforusb(vendor.zte.value, 0x0016)
|
||||
return False
|
||||
|
||||
def getserialports(self):
|
||||
|
@ -88,40 +97,38 @@ class connection:
|
|||
|
||||
def detectusbdevices(self):
|
||||
dev = usb.core.find(find_all=True)
|
||||
ids=[deviceclass(cfg.idVendor,cfg.idProduct) for cfg in dev]
|
||||
ids = [deviceclass(cfg.idVendor, cfg.idProduct) for cfg in dev]
|
||||
return ids
|
||||
|
||||
def detect(self, port):
|
||||
atvendortable={
|
||||
0x1199:["Sierra Wireless",3],
|
||||
0x2c7c:["Quectel",3],
|
||||
0x19d2:["ZTE",2],
|
||||
0x413c:["Telit",3],
|
||||
0x0846:["Netgear",2],
|
||||
0x04E8:["Samsung", -1]
|
||||
atvendortable = {
|
||||
0x1199: ["Sierra Wireless", 3],
|
||||
0x2c7c: ["Quectel", 3],
|
||||
0x19d2: ["ZTE", 2],
|
||||
0x413c: ["Telit", 3],
|
||||
0x0846: ["Netgear", 2],
|
||||
0x04E8: ["Samsung", -1]
|
||||
}
|
||||
mode="Unknown"
|
||||
mode = "Unknown"
|
||||
for device in self.detectusbdevices():
|
||||
if device.vid==vendor.zte.value:
|
||||
if device.pid==0x0016:
|
||||
if device.vid == vendor.zte.value:
|
||||
if device.pid == 0x0016:
|
||||
print(f"Detected a {atvendortable[device.vid][0]} device with pid {hex(device.pid)} in AT mode")
|
||||
mode="AT"
|
||||
mode = "AT"
|
||||
break
|
||||
elif device.pid==0x1403:
|
||||
elif device.pid == 0x1403:
|
||||
print(f"Detected a {atvendortable[device.vid][0]} device with pid {hex(device.pid)} in Web mode")
|
||||
mode="Web"
|
||||
url = 'http://192.168.0.1/goform/goform_set_cmd_process?goformId=USB_MODE_SWITCH&usb_mode=6'
|
||||
if self.websend(url):
|
||||
print("Successfully enabled adb.")
|
||||
mode = "Web"
|
||||
self.ZTE_Web()
|
||||
break
|
||||
elif device.vid==vendor.netgear.value:
|
||||
elif device.vid == vendor.netgear.value:
|
||||
try:
|
||||
# vid 0846, netgear mr1100, mr5100
|
||||
self.tn = Telnet("192.168.1.1", 5510, 5)
|
||||
self.connected = True
|
||||
except:
|
||||
self.connected = False
|
||||
if mode=="AT" or mode=="Unknown":
|
||||
if mode in ["AT", "Unknown"]:
|
||||
for port in self.getserialports():
|
||||
if port.vid in atvendortable:
|
||||
portid = port.location[-1:]
|
||||
|
@ -130,9 +137,14 @@ class connection:
|
|||
return port.device
|
||||
return ""
|
||||
|
||||
def ZTE_Web(self):
|
||||
url = 'http://192.168.0.1/goform/goform_set_cmd_process?goformId=USB_MODE_SWITCH&usb_mode=6'
|
||||
if self.websend(url):
|
||||
print("Successfully enabled adb.")
|
||||
|
||||
def readreply(self):
|
||||
info = []
|
||||
timeout=0
|
||||
timeout = 0
|
||||
if self.serial is not None:
|
||||
while True:
|
||||
tmp = self.serial.readline().decode('utf-8').replace('\r', '').replace('\n', '')
|
||||
|
@ -141,11 +153,11 @@ class connection:
|
|||
return info
|
||||
elif "ERROR" in tmp:
|
||||
return -1
|
||||
if tmp!="":
|
||||
if tmp != "":
|
||||
info.append(tmp)
|
||||
else:
|
||||
timeout+=1
|
||||
if timeout==20:
|
||||
timeout += 1
|
||||
if timeout == 4:
|
||||
break
|
||||
return info
|
||||
|
||||
|
@ -166,7 +178,7 @@ class connection:
|
|||
elif self.serial is not None:
|
||||
self.serial.write(bytes(cmd + "\r", 'utf-8'))
|
||||
time.sleep(0.05)
|
||||
resp=self.readreply()
|
||||
resp = self.readreply()
|
||||
return resp
|
||||
|
||||
def close(self):
|
||||
|
@ -178,7 +190,7 @@ class connection:
|
|||
self.connected = False
|
||||
|
||||
def ati(self):
|
||||
data={}
|
||||
data = {}
|
||||
info = self.send("ATI")
|
||||
if info != -1:
|
||||
for line in info:
|
||||
|
@ -189,159 +201,320 @@ class connection:
|
|||
if "Quectel" in line:
|
||||
data["vendor"] = "Quectel"
|
||||
if "Manufacturer" in line:
|
||||
data["manufacturer"]=line.split(":")[1].strip()
|
||||
data["manufacturer"] = line.split(":")[1].strip()
|
||||
if "Sierra Wireless" in data["manufacturer"]:
|
||||
data["vendor"]="Sierra Wireless"
|
||||
data["vendor"] = "Sierra Wireless"
|
||||
elif "ZTE CORPORATION" in data["manufacturer"]:
|
||||
data["vendor"]="ZTE"
|
||||
data["vendor"] = "ZTE"
|
||||
elif "SIMCOM INCORPORATED" in data["manufacturer"]:
|
||||
data["vendor"]="Simcom"
|
||||
data["vendor"] = "Simcom"
|
||||
elif "Alcatel" in data["manufacturer"]:
|
||||
data["vendor"]="Alcatel"
|
||||
data["vendor"] = "Alcatel"
|
||||
elif "Netgear" in data["manufacturer"]:
|
||||
data["vendor"]="Netgear"
|
||||
data["vendor"] = "Netgear"
|
||||
elif "SAMSUNG" in data["manufacturer"]:
|
||||
data["vendor"]="Samsung"
|
||||
data["vendor"] = "Samsung"
|
||||
info = self.send("AT+CGMI")
|
||||
if info!=-1:
|
||||
if info != -1:
|
||||
for line in info:
|
||||
if "Quectel" in line:
|
||||
data["vendor"] = "Quectel"
|
||||
break
|
||||
elif "Fibucom" in line:
|
||||
data["vendor"]="Fibucom"
|
||||
data["vendor"] = "Fibucom"
|
||||
break
|
||||
elif "Netgear" in line:
|
||||
data["vendor"]="Netgear"
|
||||
data["vendor"] = "Netgear"
|
||||
break
|
||||
elif "SAMSUNG" in line:
|
||||
data["vendor"]="Samsung"
|
||||
data["vendor"] = "Samsung"
|
||||
break
|
||||
info = self.send("AT+CGMR")
|
||||
if info!=-1:
|
||||
if len(info)>1:
|
||||
data["model"]=info[1]
|
||||
if info != -1:
|
||||
if len(info) > 1:
|
||||
data["model"] = info[1]
|
||||
return data
|
||||
|
||||
|
||||
class adbtools(metaclass=LogBase):
|
||||
def sendcmd(self, tn,cmd):
|
||||
tn.write(bytes(cmd,'utf-8')+b"\n")
|
||||
def sendcmd(self, tn, cmd):
|
||||
tn.write(bytes(cmd, 'utf-8') + b"\n")
|
||||
time.sleep(0.05)
|
||||
return tn.read_eager().strip().decode('utf-8')
|
||||
|
||||
def run(self, args):
|
||||
port = args.port
|
||||
def qc_diag_auth(self, diag):
|
||||
if diag.connect():
|
||||
res = diag.send(b"\x4B\xA3\x06\x00")
|
||||
if res[0] == 0x4B:
|
||||
challenge = res[4:4 + 8]
|
||||
response = hashlib.md5(challenge).digest()
|
||||
res = diag.send(b"\x4B\xA3\x07\x00" + response)
|
||||
if res[0] == 0x4B:
|
||||
if res[3] == 0x00:
|
||||
print("Auth success")
|
||||
res = diag.send(b"\x41" + b"\x30\x30\x30\x30\x30\x30")
|
||||
if res[1] == 0x01:
|
||||
print("SPC success")
|
||||
sp = b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE"
|
||||
res = diag.send(b"\x46" + sp)
|
||||
if res[0] == 0x46 and res[1] == 0x01:
|
||||
print("SP success")
|
||||
return True
|
||||
else:
|
||||
res = diag.send(b"\x25" + sp)
|
||||
if res[0] == 0x46 and res[1] == 0x01:
|
||||
print("SP success")
|
||||
return True
|
||||
return False
|
||||
|
||||
def meta(self, port, mode=b"METAMETA"):
|
||||
while True:
|
||||
cn = connection(port)
|
||||
if cn.connected:
|
||||
while True:
|
||||
resp2 = cn.serial.read(8)
|
||||
if len(resp2)>0:
|
||||
break
|
||||
cn.serial.write(mode)
|
||||
response = cn.serial.read(8)
|
||||
if len(response) == 0:
|
||||
print("Read timeout while switching to META mode")
|
||||
elif response == b'ATEMATEM' or response == b'READYATE':
|
||||
print("META Mode enabled")
|
||||
elif response == b'METAFORB':
|
||||
print("META mode forbidden")
|
||||
else:
|
||||
print("Invalid response: ", response)
|
||||
|
||||
def run(self, port, enable):
|
||||
cn = connection(port)
|
||||
if cn.connected:
|
||||
info=cn.ati()
|
||||
info = cn.ati()
|
||||
res = False
|
||||
if "vendor" in info:
|
||||
if info["vendor"]=="Sierra Wireless" or info["vendor"]=="Netgear":
|
||||
if info["vendor"] == "Sierra Wireless" or info["vendor"] == "Netgear":
|
||||
res=self.SierraWireless(cn, info, enable)
|
||||
elif info["vendor"] == "Quectel":
|
||||
print("Sending at switch command")
|
||||
kg=SierraKeygen(cn)
|
||||
if kg.openlock():
|
||||
if cn.send('AT!CUSTOM="ADBENABLE",1\r')==-1:
|
||||
print("Error on sending adb enable command.")
|
||||
kg.openlock()
|
||||
if cn.send('AT!CUSTOM="TELNETENABLE",1\r')!=-1:
|
||||
time.sleep(5)
|
||||
tn = Telnet("192.168.1.1", 23, 15)
|
||||
tn.write(b"adbd &\r\n")
|
||||
info = tn.read_eager()
|
||||
print(info)
|
||||
print("Enabled adb via telnet")
|
||||
else:
|
||||
print("Error on sending telnet enable command.")
|
||||
if kg.openlock():
|
||||
if info["vendor"] == "Netgear":
|
||||
print("Enabling new port config")
|
||||
if cn.send("AT!UDPID=68E2"):
|
||||
print("Successfully enabled PID 68E2")
|
||||
elif info["vendor"]=="Quectel":
|
||||
print("Sending at switch command")
|
||||
salt=cn.send("AT+QADBKEY?\r")
|
||||
if salt!=-1:
|
||||
if len(salt)>1:
|
||||
salt=salt[1]
|
||||
code = crypt.crypt("SH_adb_quectel", "$1$" + salt)
|
||||
code = code[12:]
|
||||
cn.send("AT+QADBKEY=\"%s\"\r" % code)
|
||||
if cn.send("AT+QCFG=\"usbcfg\",0x2C7C,0x125,1,1,1,1,1,1,0\r")==-1:
|
||||
if cn.send("AT+QLINUXCMD=\"adbd\"")!=-1: #echo test > /dev/ttyGS0
|
||||
print("Success enabling adb")
|
||||
else:
|
||||
print("Success enabling adb")
|
||||
print("In order to disable adb, send AT+QCFG=\"usbcfg\",0x2C7C,0x125,1,1,1,1,1,0,0")
|
||||
elif info["vendor"]=="ZTE":
|
||||
res=self.Quectel(cn, enable)
|
||||
elif info["vendor"] == "ZTE":
|
||||
print("Sending switch command via diag")
|
||||
if cn.send("AT+ZMODE=1")!=-1:
|
||||
print("Success enabling adb")
|
||||
else:
|
||||
interface = 0
|
||||
diag = qcdiag(loglevel=self.__logger.level, portconfig=[[0x19d2, 0x0016, interface]])
|
||||
if diag.connect():
|
||||
res = diag.send(b"\x4B\xA3\x06\x00")
|
||||
if res[0]==0x4B:
|
||||
challenge=res[4:4+8]
|
||||
response=hashlib.md5(challenge).digest()
|
||||
res = diag.send(b"\x4B\xA3\x07\x00"+response)
|
||||
if res[0]==0x4B:
|
||||
if res[3]==0x00:
|
||||
print("Auth success")
|
||||
res=diag.send(b"\x41" + b"\x30\x30\x30\x30\x30\x30")
|
||||
if res[1]==0x01:
|
||||
print("SPC success")
|
||||
sp=b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE"
|
||||
res = diag.send(b"\x46" + sp)
|
||||
if res[0] == 0x46 and res[1]==0x01:
|
||||
print("SP success")
|
||||
else:
|
||||
res = diag.send(b"\x25" + sp)
|
||||
if res[0]==0x46 and res[1]==0x01:
|
||||
print("SP success")
|
||||
res = diag.send(b"\x4B\xFA\x0B\x00\x01") #Enable adb serial
|
||||
if res[0]!=0x13:
|
||||
print("Success enabling adb serial")
|
||||
res = diag.send(b"\x4B\x5D\x05\x00") #Operate ADB
|
||||
if res[0]!=0x13:
|
||||
print("Success enabling adb")
|
||||
diag.disconnect()
|
||||
elif info["vendor"]=="Simcom":
|
||||
print("Sending at switch command")
|
||||
# Simcom7600
|
||||
if cn.send("AT+CUSBADB=1,1")!=-1:
|
||||
print("Success enabling adb")
|
||||
elif info["vendor"]=="Fibocom":
|
||||
print("Sending at switch command")
|
||||
# FibocomL718:
|
||||
if cn.send("AT+ADBDEBUG=1")!=-1:
|
||||
print("Success enabling adb")
|
||||
elif info["vendor"]=="Alcatel":
|
||||
print("Send scsi switch command")
|
||||
print("Run \"sudo sg_raw /dev/sg0 16 f9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -v\" to enable adb")
|
||||
elif info["vendor"]=="Samsung":
|
||||
if cn.send("AT+USBMODEM=1"):
|
||||
print("Success enabling adb")
|
||||
elif cn.send("AT+SYSSCOPE=1,0,0"):
|
||||
print("Success enabling adb")
|
||||
res=self.ZTE(cn, enable)
|
||||
elif info["vendor"] == "Simcom":
|
||||
res=self.Simcom(cn)
|
||||
elif info["vendor"] == "Fibocom":
|
||||
res=self.Fibocom(cn, enable)
|
||||
elif info["vendor"] == "Alcatel":
|
||||
res=self.Alcatel(enable)
|
||||
elif info["vendor"] == "Samsung":
|
||||
res=self.Samsung(cn, enable)
|
||||
if enable:
|
||||
mode="enabled"
|
||||
else:
|
||||
mode="disabled"
|
||||
if res:
|
||||
print("ADB successfully "+mode)
|
||||
else:
|
||||
print("ADB couldn't be "+mode)
|
||||
cn.close()
|
||||
else:
|
||||
print("No device detected")
|
||||
|
||||
def SierraWireless(self, cn, info, enable):
|
||||
print("Sending at switch command")
|
||||
kg = SierraKeygen(cn)
|
||||
if kg.openlock():
|
||||
if enable:
|
||||
if cn.send('AT!CUSTOM="ADBENABLE",1\r') != -1:
|
||||
return True
|
||||
kg.openlock()
|
||||
if cn.send('AT!CUSTOM="TELNETENABLE",1\r') != -1:
|
||||
time.sleep(5)
|
||||
tn = Telnet("192.168.1.1", 23, 15)
|
||||
tn.write(b"adbd &\r\n")
|
||||
info = tn.read_eager()
|
||||
print(info)
|
||||
return True
|
||||
if kg.openlock():
|
||||
if info["vendor"] == "Netgear":
|
||||
print("Enabling new port config")
|
||||
if cn.send("AT!UDPID=68E2"):
|
||||
print("Successfully enabled PID 68E2")
|
||||
return True
|
||||
|
||||
index=-1
|
||||
type=-1
|
||||
bitmask=-1
|
||||
resp=cn.send("AT!USBCOMP?")
|
||||
if resp!=-1:
|
||||
print(resp)
|
||||
for val in resp:
|
||||
if "Config Index" in val:
|
||||
index=val[val.find("Config Index: ")+14:]
|
||||
elif "Config Type" in val:
|
||||
type=val[val.find("Config Type: ")+14:].replace(" (Generic)","")
|
||||
elif "Interface bitmask" in val:
|
||||
bitmask=val[val.find("Interface bitmask: ")+19:]
|
||||
if " " in bitmask:
|
||||
bitmask="0x"+bitmask.split(" ")[0]
|
||||
if index!=-1 and type!=-1 and bitmask!=1:
|
||||
index=int(index)
|
||||
type=int(type)
|
||||
bitmask=int(bitmask,16)
|
||||
# AT!USBCOMP=<Config Index>,<Config Type>,<Interface bitmask>
|
||||
# <Config Index> - configuration index to which the composition applies, should be 1
|
||||
# <Config Type> - 1:Generic, 2:USBIF-MBIM, 3:RNDIS
|
||||
# config type 2/3 should only be used for specific Sierra PIDs: 68B1, 9068
|
||||
# customized VID/PID should use config type 1
|
||||
# <Interface bitmask> - DIAG - 0x00000001,
|
||||
# ADB - 0x00000002,
|
||||
# NMEA - 0x00000004,
|
||||
# MODEM - 0x00000008,
|
||||
# RMNET0 - 0x00000100,
|
||||
# RMNET1 - 0x00000400,
|
||||
# RMNET2 - 0x00000800,
|
||||
# MBIM - 0x00001000,
|
||||
# RNDIS - 0x00004000,
|
||||
# AUDIO - 0x00010000,
|
||||
# ECM - 0x00080000,
|
||||
# UBIST - 0x00200000
|
||||
#if enable:
|
||||
cmd=f"AT!USBCOMP={index},{type},%08X" % 0x0080010E
|
||||
#else:
|
||||
# cmd = f"AT!USBCOMP={index},{type},%08X" % 0x0000010D
|
||||
resp=cn.send(cmd)
|
||||
if resp!=-1:
|
||||
resp=cn.send("AT!RESET")
|
||||
if resp!=-1:
|
||||
return True
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
if cn.send('AT!CUSTOM="ADBENABLE",0\r') != -1:
|
||||
return True
|
||||
kg.openlock()
|
||||
if cn.send('AT!CUSTOM="TELNETENABLE",0\r') != -1:
|
||||
return True
|
||||
return False
|
||||
|
||||
def Samsung(self, cn, enable):
|
||||
if enable:
|
||||
if cn.send("AT+USBMODEM=1"):
|
||||
return True
|
||||
elif cn.send("AT+SYSSCOPE=1,0,0"):
|
||||
return True
|
||||
else:
|
||||
if cn.send("AT+USBMODEM=0"):
|
||||
return True
|
||||
elif cn.send("AT+SYSSCOPE=1,0,0"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def Alcatel(self, enable):
|
||||
print("Send scsi switch command")
|
||||
print("Run \"sudo sg_raw /dev/sg0 16 f9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -v\" to enable adb")
|
||||
|
||||
def Fibocom(self, cn, enable):
|
||||
print("Sending at switch command")
|
||||
if enable:
|
||||
# FibocomL718:
|
||||
if cn.send("AT+ADBDEBUG=1") != -1:
|
||||
return True
|
||||
else:
|
||||
if cn.send("AT+ADBDEBUG=0") != -1:
|
||||
return True
|
||||
return False
|
||||
|
||||
def Simcom(self, cn, enable):
|
||||
print("Sending at switch command")
|
||||
if enable:
|
||||
# Simcom7600
|
||||
if cn.send("AT+CUSBADB=1,1") != -1:
|
||||
return True
|
||||
else:
|
||||
if cn.send("AT+CUSBADB=1,1") != -1:
|
||||
return True
|
||||
return False
|
||||
|
||||
def ZTE(self, cn, enable):
|
||||
if enable:
|
||||
if cn.send("AT+ZMODE=1") != -1:
|
||||
return True
|
||||
else:
|
||||
interface = 0
|
||||
diag = qcdiag(loglevel=self.__logger.level, portconfig=[[0x19d2, 0x0016, interface]])
|
||||
if self.qc_diag_auth(diag):
|
||||
res = diag.send(b"\x4B\xFA\x0B\x00\x01") # Enable adb serial
|
||||
if res[0] != 0x13:
|
||||
print("Success enabling adb serial")
|
||||
res = diag.send(b"\x4B\x5D\x05\x00") # Operate ADB
|
||||
if res[0] != 0x13:
|
||||
print("Success enabling adb")
|
||||
return True
|
||||
diag.disconnect()
|
||||
else:
|
||||
if cn.send("AT+ZMODE=F") != -1:
|
||||
return True
|
||||
else:
|
||||
interface = 0
|
||||
diag = qcdiag(loglevel=self.__logger.level, portconfig=[[0x19d2, 0x0016, interface]])
|
||||
if self.qc_diag_auth(diag):
|
||||
res = diag.send(b"\x4B\xFA\x0B\x00\x00") # Enable adb serial
|
||||
if res[0] != 0x13:
|
||||
print("Success enabling adb serial")
|
||||
res = diag.send(b"\x4B\x5D\x05\x00") # Operate ADB
|
||||
if res[0] != 0x13:
|
||||
print("Success enabling adb")
|
||||
diag.disconnect()
|
||||
return True
|
||||
return False
|
||||
|
||||
def Quectel(self, cn, enable: bool = True):
|
||||
salt = cn.send("AT+QADBKEY?\r")
|
||||
if salt != -1:
|
||||
if len(salt) > 1:
|
||||
salt = salt[1]
|
||||
code = crypt.crypt("SH_adb_quectel", "$1$" + salt)
|
||||
code = code[12:]
|
||||
cn.send("AT+QADBKEY=\"%s\"\r" % code)
|
||||
if enable:
|
||||
if cn.send("AT+QCFG=\"usbcfg\",0x2C7C,0x125,1,1,1,1,1,1,0\r") == -1:
|
||||
if cn.send("AT+QLINUXCMD=\"adbd\"") != -1: # echo test > /dev/ttyGS0
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
else:
|
||||
if cn.send("AT+QCFG=\"usbcfg\",0x2C7C,0x125,1,1,1,1,1,0,0\r") != -1:
|
||||
return True
|
||||
return False
|
||||
|
||||
cn.close()
|
||||
|
||||
def main():
|
||||
version = "1.1"
|
||||
info = 'Modem Gimme-ADB ' + version + ' (c) B. Kerler 2020-2021'
|
||||
version = "1.2"
|
||||
info = '\nModem Gimme-ADB ' + version + ' (c) B. Kerler 2020-2021\n-------------------------------------------\n'
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, description=info)
|
||||
parser.add_argument(
|
||||
'-mode', help='Mode: enable or disable',
|
||||
default="enable")
|
||||
parser.add_argument(
|
||||
'-port', '-p',
|
||||
help='use com port for at',
|
||||
help='[Optional] use com port for at',
|
||||
default="")
|
||||
parser.add_argument(
|
||||
'-logfile', '-l',
|
||||
help='use logfile for debug log',
|
||||
default="")
|
||||
args = parser.parse_args()
|
||||
ad=adbtools()
|
||||
ad.run(args)
|
||||
ad = adbtools()
|
||||
print(info)
|
||||
print("Supported modules: ZTE,Netgear,Sierra Wireless,Samsung,Alcatel,Quectel,Fibucom")
|
||||
if args.mode.lower() == "enable":
|
||||
enable = True
|
||||
else:
|
||||
enable = False
|
||||
ad.run(port=args.port, enable=enable)
|
||||
#ad.meta(port=args.port)
|
||||
|
||||
if __name__=="__main__":
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
|
|
@ -10,9 +10,11 @@ current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentfra
|
|||
parent_dir = os.path.dirname(current_dir)
|
||||
sys.path.insert(0, parent_dir)
|
||||
from edlclient.Library.utils import elf
|
||||
from edlclient.Library.sahara import convertmsmid
|
||||
from edlclient.Library.loader_db import loader_utils
|
||||
from edlclient.Config.qualcomm_config import vendor
|
||||
|
||||
lu=loader_utils()
|
||||
|
||||
class MBN:
|
||||
def __init__(self, memory):
|
||||
self.imageid, self.flashpartitionversion, self.imagesrc, self.loadaddr, self.imagesz, self.codesz, \
|
||||
|
@ -176,7 +178,7 @@ def init_loader_db():
|
|||
msmid = hwid[:8]
|
||||
devid = hwid[8:]
|
||||
pkhash = filename.split("_")[1].lower()
|
||||
msmdb = convertmsmid(msmid)
|
||||
msmdb = lu.convertmsmid(msmid)
|
||||
for msmid in msmdb:
|
||||
mhwid = (msmid + devid).lower()
|
||||
if mhwid not in loaderdb:
|
||||
|
@ -195,7 +197,7 @@ def is_duplicate(loaderdb, sign_info):
|
|||
msmid = sign_info.hw_id[:8].lower()
|
||||
devid = sign_info.hw_id[8:].lower()
|
||||
hwid = sign_info.hw_id.lower()
|
||||
for msmid in convertmsmid(msmid):
|
||||
for msmid in lu.convertmsmid(msmid):
|
||||
rid = (msmid + devid).lower()
|
||||
if hwid in loaderdb:
|
||||
loader = loaderdb[hwid]
|
||||
|
@ -355,7 +357,7 @@ def main(argv):
|
|||
print(info)
|
||||
msmid = loader_info.hw_id[:8]
|
||||
devid = loader_info.hw_id[8:]
|
||||
for msmid in convertmsmid(msmid):
|
||||
for msmid in lu.convertmsmid(msmid):
|
||||
hwid = (msmid + devid).lower()
|
||||
auth = ""
|
||||
with open(item.filename, "rb") as rf:
|
||||
|
|
File diff suppressed because it is too large
Load diff
1
edlclient/Tools/qc_diag
Symbolic link
1
edlclient/Tools/qc_diag
Symbolic link
|
@ -0,0 +1 @@
|
|||
qc_diag.py
|
|
@ -1,591 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) B.Kerler 2019-2020 under MIT license
|
||||
# If you use my code, make sure you refer to my name
|
||||
# If you want to use in a commercial product, ask me before integrating it
|
||||
|
||||
import serial
|
||||
import sys
|
||||
import argparse
|
||||
import time
|
||||
import serial.tools.list_ports
|
||||
from telnetlib import Telnet
|
||||
from binascii import hexlify, unhexlify
|
||||
|
||||
try:
|
||||
from edlclient.Library.utils import LogBase
|
||||
except Exception as e:
|
||||
import os,sys,inspect
|
||||
current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||
parent_dir = os.path.dirname(current_dir)
|
||||
sys.path.insert(0, parent_dir)
|
||||
from Library.utils import LogBase
|
||||
|
||||
'''
|
||||
C7 = 7 0 0 2 7 5 0
|
||||
C6 = 3 1 7 0 3 0 1
|
||||
C5 = 0 2 5 3 0 3 2
|
||||
C8 = 1 3 3 1 5 7 3
|
||||
C4 = 5 4 1 4 1 1 4
|
||||
'''
|
||||
prodtable = {
|
||||
"MDM8200": dict(openlock=0, openmep=1, opencnd=0, clen=8, init=[1, 3, 5, 7, 0],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 2, 4, 1, 3, 0, 3, 4, 0)"),
|
||||
# MC878XC_F1.2.3.15 verified, key may be stored in nvitem 0x4e21;MC8700 M3.0.9.0 verified
|
||||
"MDM9200": dict(openlock=0, openmep=1, opencnd=0, clen=8, init=[7, 3, 0, 1, 5],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
|
||||
# AC881U, EM8805 SWI9X15C_05.05.58.00, at!openlock?6A1F1CEA298A14B0 => AT!OPENLOCK="3A9EA70D86FEE58C"
|
||||
"MDM9200_V1": dict(openlock=2, openmep=1, opencnd=0, clen=8, init=[7, 3, 0, 1, 5],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # AC710
|
||||
"MDM9200_V2": dict(openlock=3, openmep=1, opencnd=0, clen=8, init=[7, 3, 0, 1, 5],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # AC775
|
||||
"MDM9200_V3": dict(openlock=8, openmep=1, opencnd=8, clen=8, init=[7, 3, 0, 1, 5],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # AC775
|
||||
"MDM9x15": dict(openlock=0, openmep=1, opencnd=0, clen=8, init=[7, 3, 0, 1, 5],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
|
||||
# 9x15C 06.03.32.02, AC340U 1.13.12.14 verified, #AT!CUSTOM=\"ADBENABLE\",1
|
||||
"MDM9x07": dict(openlock=9, openmep=10, opencnd=9, clen=8, init=[7, 3, 0, 1, 5],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
|
||||
# SWI9X07Y_02.25.02.01
|
||||
"MDM9x30": dict(openlock=5, openmep=4, opencnd=5, clen=8, init=[7, 3, 0, 1, 5],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
|
||||
# MC7455_2.30.01.01 #4
|
||||
"MDM9x30_V1": dict(openlock=17, openmep=15, opencnd=17, clen=8, init=[7, 3, 0, 1, 5],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
|
||||
# AC791L/AC790S NTG9X35C_02.08.29.00
|
||||
"MDM9x40": dict(openlock=11, openmep=12, opencnd=11, clen=8, init=[7, 3, 0, 1, 5],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # AC815s
|
||||
"MDM9x50": dict(openlock=7, openmep=6, opencnd=7, clen=8, init=[7, 3, 0, 1, 5],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # EM7565
|
||||
"MDM9x06": dict(openlock=20, openmep=19, opencnd=20, clen=8, init=[7, 3, 0, 1, 5],
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"), # WP77xx
|
||||
"SDX55": dict(openlock=22, openmep=21, opencnd=22, clen=8, init=[7, 3, 0, 1, 5], #MR5100
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
|
||||
"MDM9x15A": dict(openlock=24, openmep=23, opencnd=24, clen=8, init=[7, 3, 0, 1, 5], #AC779S
|
||||
run="resultbuffer[i]=self.SierraAlgo(challenge[i], 4, 2, 1, 0, 3, 2, 0, 0)"),
|
||||
|
||||
}
|
||||
|
||||
infotable = {
|
||||
"MDM8200": ["M81A", "M81B", "AC880", "AC881", "MC8780", "MC8781", "AC880E", "AC881E", "EM8780", "EM8781",
|
||||
"MC8780V", "MC8781V", "MC8700", "AC308U"],
|
||||
"MDM9200": ["AC710", "MC8775", "MC8775V", "AC875", "MC8700", "AC313U", "MC8801", "MC7700", "MC7750", "MC7710",
|
||||
"EM7700", "770S", "781S"],
|
||||
"MDM9200_V1": ["AC710", "MC8775", "MC8775V", "AC875", "MC8700", "AC313U", "MC8801", "MC7700", "MC7750",
|
||||
"MC7710", "EM7700"],
|
||||
"MDM9200_V2": ["AC775", "PC7200"],
|
||||
"MDM9200_V3": ["AC775"],
|
||||
"MDM9x07": ["SWI9X07Y", "WP76xx"],
|
||||
"MDM9x06": ["SWI9X06Y", "WP77xx"],
|
||||
"MDM9x15": ["SWI9X15C", "AR7550", "AR7552", "AR7554", "EM7355", "EM7655", "MC7354", "WP7100", "WP7102", "WP7104",
|
||||
"MC7305", "EM7305", "MC8805", "EM8805", "MC7350", "MC7350-L", "MC7802", "MC7304", "AR7556", "AR7558",
|
||||
"WP75xx", "WP85xx", "WP8548", "WP8548G", "AC340U"],
|
||||
"MDM9x15A": ["AC779S"],
|
||||
"MDM9x30": ["EM7455", "MC7455", "EM7430", "MC7430"],
|
||||
"MDM9x30_V1": ["Netgear AC790/MDM9230"],
|
||||
"MDM9x40": ["AC815s", "AC785s", "AC797S", "MR1100"],
|
||||
"MDM9x50": ["EM7565", "EM7565-9", "EM7511", "EM7411"],
|
||||
"SDX55" : ["MR5100","ac797-100eus"]
|
||||
}
|
||||
|
||||
keytable = bytearray([0xF0, 0x14, 0x55, 0x0D, 0x5E, 0xDA, 0x92, 0xB3, 0xA7, 0x6C, 0xCE, 0x84, 0x90, 0xBC, 0x7F, 0xED,
|
||||
# 0 MC8775_H2.0.8.19 !OPENLOCK, !OPENCND .. MC8765V,MC8765,MC8755V,MC8775,MC8775V,MC8775,AC850,
|
||||
# AC860,AC875,AC881,AC881U,AC875, AC340U 1.13.12.14
|
||||
0x61, 0x94, 0xCE, 0xA7, 0xB0, 0xEA, 0x4F, 0x0A, 0x73, 0xC5, 0xC3, 0xA6, 0x5E, 0xEC, 0x1C, 0xE2,
|
||||
# 1 MC8775_H2.0.8.19 AC340U, OPENMEP default
|
||||
0x39, 0xC6, 0x7B, 0x04, 0xCA, 0x50, 0x82, 0x1F, 0x19, 0x63, 0x36, 0xDE, 0x81, 0x49, 0xF0, 0xD7,
|
||||
# 2 AC750,AC710,AC7XX,SB750A,SB750,PC7000,AC313u OPENMEP
|
||||
0xDE, 0xA5, 0xAD, 0x2E, 0xBE, 0xE1, 0xC9, 0xEF, 0xCA, 0xF9, 0xFE, 0x1F, 0x17, 0xFE, 0xED, 0x3B,
|
||||
# 3 AC775,PC7200
|
||||
0xFE, 0xD4, 0x40, 0x52, 0x2D, 0x4B, 0x12, 0x5C, 0xE7, 0x0D, 0xF8, 0x79, 0xF8, 0xC0, 0xDD, 0x37,
|
||||
# 4 MC7455_02.30.01.01 OPENMEP
|
||||
0x3B, 0x18, 0x99, 0x6B, 0x57, 0x24, 0x0A, 0xD8, 0x94, 0x6F, 0x8E, 0xD9, 0x90, 0xBC, 0x67, 0x56,
|
||||
# 5 MC7455_02.30.01.01 OPENLOCK
|
||||
0x47, 0x4F, 0x4F, 0x44, 0x4A, 0x4F, 0x42, 0x44, 0x45, 0x43, 0x4F, 0x44, 0x49, 0x4E, 0x47, 0x2E,
|
||||
# 6 SWI9x50 Openmep Key SWI9X50C_01.08.04.00
|
||||
0x4F, 0x4D, 0x41, 0x52, 0x20, 0x44, 0x49, 0x44, 0x20, 0x54, 0x48, 0x49, 0x53, 0x2E, 0x2E, 0x2E,
|
||||
# 7 SWI9x50 Openlock Key SWI9X50C_01.08.04.00
|
||||
0x8F, 0xA5, 0x85, 0x05, 0x5E, 0xCF, 0x44, 0xA0, 0x98, 0x8B, 0x09, 0xE8, 0xBB, 0xC6, 0xF7, 0x65,
|
||||
# 8 MDM8200 Special
|
||||
0x4D, 0x42, 0xD8, 0xC1, 0x25, 0x44, 0xD8, 0xA0, 0x1D, 0x80, 0xC4, 0x52, 0x8E, 0xEC, 0x8B, 0xE3,
|
||||
# 9 SWI9x07 Openlock Key 02.25.02.01
|
||||
0xED, 0xA9, 0xB7, 0x0A, 0xDB, 0x85, 0x3D, 0xC0, 0x92, 0x49, 0x7D, 0x41, 0x9A, 0x91, 0x09, 0xEE,
|
||||
# 10 SWI9x07 Openmep Key 02.25.02.01
|
||||
0x8A, 0x56, 0x03, 0xF0, 0xBB, 0x9C, 0x13, 0xD2, 0x4E, 0xB2, 0x45, 0xAD, 0xC4, 0x0A, 0xE7, 0x52,
|
||||
# 11 NTG9X40C_11.14.08.11 / mdm9x40r11_core AC815s / SWI9x50 MR1100 Openlock Key
|
||||
0x2A, 0xEF, 0x07, 0x2B, 0x19, 0x60, 0xC9, 0x01, 0x8B, 0x87, 0xF2, 0x6E, 0xC1, 0x42, 0xA8, 0x3A,
|
||||
# 12 SWI9x50 MR1100 Openmep Key
|
||||
0x28, 0x55, 0x48, 0x52, 0x24, 0x72, 0x63, 0x37, 0x14, 0x26, 0x37, 0x50, 0xBE, 0xFE, 0x00, 0x00,
|
||||
# 13 SWI9x50 Unknown key
|
||||
0x22, 0x63, 0x48, 0x02, 0x24, 0x72, 0x27, 0x37, 0x19, 0x26, 0x37, 0x50, 0xBE, 0xEF, 0xCA, 0xFE,
|
||||
# 14 SWI9x50,SWI9X06Y IMEI nv key
|
||||
0x98, 0xE1, 0xC1, 0x93, 0xC3, 0xBF, 0xC3, 0x50, 0x8D, 0xA1, 0x35, 0xFE, 0x50, 0x47, 0xB3, 0xC4,
|
||||
# 15 NTG9X35C_02.08.29.00 Openmep Key AC791L/AC790S Old
|
||||
0x61, 0x94, 0xCE, 0xA7, 0xB0, 0xEA, 0x4F, 0x0A, 0x73, 0xC5, 0xC3, 0xA6, 0x5E, 0xEC, 0x1C, 0xE2,
|
||||
# 16 NTG9X35C_02.08.29.00 Openmep Key AC791/AC790S, NTGX55_10.25.15.02 MR5100 Alternative, NTG9X40C_30.00.12.00 Alternative
|
||||
0xC5, 0x50, 0x40, 0xDA, 0x23, 0xE8, 0xF4, 0x4C, 0x29, 0xE9, 0x07, 0xDE, 0x24, 0xE5, 0x2C, 0x1D,
|
||||
# 17 NTG9X35C_02.08.29.00 Openlock Key AC791/AC790S Old
|
||||
0xF0, 0x14, 0x55, 0x0D, 0x5E, 0xDA, 0x92, 0xB3, 0xA7, 0x6C, 0xCE, 0x84, 0x90, 0xBC, 0x7F, 0xED,
|
||||
# 18 NTG9X35C_02.08.29.00 Openlock Key AC791/AC790S, NTGX55_10.25.15.02 MR5100 Alternative, NTG9X40C_30.00.12.00 Alternative
|
||||
0x78, 0x19, 0xC5, 0x6D, 0xC3, 0xD8, 0x25, 0x3E, 0x51, 0x60, 0x8C, 0xA7, 0x32, 0x83, 0x37, 0x9D,
|
||||
# 19 SWI9X06Y_02.14.04.00 Openmep Key WP77xx
|
||||
0x12, 0xF0, 0x79, 0x6B, 0x19, 0xC7, 0xF4, 0xEC, 0x50, 0xF3, 0x8C, 0x40, 0x02, 0xC9, 0x43, 0xC8,
|
||||
# 20 SWI9X06Y_02.14.04.00 Openlock Key WP77xx
|
||||
0x49, 0x42, 0xFF, 0x76, 0x8A, 0x95, 0xCF, 0x7B, 0xA3, 0x47, 0x5F, 0xF5, 0x8F, 0xD8, 0x45, 0xE4,
|
||||
# 21 NTGX55 Openmep Key, NTGX55_10.25.15.02 MR5100, NTG9X40C_30.00.12.00
|
||||
0xF8, 0x1A, 0x3A, 0xCC, 0xAA, 0x2B, 0xA5, 0xE8, 0x8B, 0x53, 0x5A, 0x55, 0xB9, 0x65, 0x57, 0x98,
|
||||
# 22 NTGX55 Openlock Key, NTGX55_10.25.15.02 MR5100, NTG9X40C_30.00.12.00
|
||||
0x54, 0xC9, 0xC7, 0xA4, 0x02, 0x1C, 0xB0, 0x11, 0x05, 0x22, 0x39, 0xB7, 0x84, 0xEF, 0x16, 0xCA,
|
||||
# 23 NTG9X15A Openlock Key, NTG9X15A_01.08.02.00
|
||||
0xC7, 0xE6, 0x39, 0xFE, 0x0A, 0xC7, 0xCA, 0x4D, 0x49, 0x8F, 0xD8, 0x55, 0xEB, 0x1A, 0xCD, 0x8A
|
||||
# 24 NTG9X15A Openlock Key, NTG9X15A_01.08.02.00
|
||||
])
|
||||
|
||||
|
||||
class SierraGenerator():
|
||||
tbl = bytearray()
|
||||
rtbl = bytearray()
|
||||
|
||||
def __init__(self):
|
||||
for i in range(0, 0x14):
|
||||
self.rtbl.append(0x0)
|
||||
for i in range(0, 0x100):
|
||||
self.tbl.append(0x0)
|
||||
|
||||
def run(self, devicegeneration, challenge, type):
|
||||
challenge = bytearray(unhexlify(challenge))
|
||||
|
||||
self.devicegeneration = devicegeneration
|
||||
if not devicegeneration in prodtable:
|
||||
print("Sorry, " + devicegeneration + " not supported.")
|
||||
exit(0)
|
||||
|
||||
mepid = prodtable[devicegeneration]["openmep"]
|
||||
cndid = prodtable[devicegeneration]["opencnd"]
|
||||
lockid = prodtable[devicegeneration]["openlock"]
|
||||
clen = prodtable[devicegeneration]["clen"]
|
||||
if len(challenge) < clen:
|
||||
challenge=[0 for i in range(0, clen - len(challenge))]
|
||||
|
||||
challengelen = len(challenge)
|
||||
if type == 0: # lockkey
|
||||
idf = lockid
|
||||
elif type == 1: # mepkey
|
||||
idf = mepid
|
||||
elif type == 2: # cndkey
|
||||
idf = cndid
|
||||
|
||||
key = keytable[idf * 16:(idf * 16) + 16]
|
||||
resp = self.SierraKeygen(challenge=challenge, key=key, challengelen=challengelen, keylen=16)[:challengelen]
|
||||
resp = hexlify(resp).decode('utf-8').upper()
|
||||
return resp
|
||||
|
||||
def selftest(self):
|
||||
test_table=[
|
||||
{"challenge": "8101A18AB3C3E66A", "devicegeneration": "MDM9x15", "response": "D1E128FCA8A963ED"},
|
||||
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x40", "response": "1033773720F6EE66"},
|
||||
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x30", "response": "1E02CE6A98B7DD2A"},
|
||||
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x50", "response": "32AB617DB4B1C205"},
|
||||
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x06", "response": "28D718CCD669DEDE"},
|
||||
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x07", "response": "F5A4C9A0D402E34E"},
|
||||
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM8200", "response": "EE702212D9C12FAB"},
|
||||
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9200_V1", "response": "A9A4E76E2653F753"},
|
||||
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9200_V2", "response": "8B0FAB4B6F81B080"},
|
||||
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9200_V3", "response": "4A69AD8A69F390E0"},
|
||||
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9x30_V1", "response": "6A5E4C9CBCBDA7DC"},
|
||||
{"challenge": "BE96CBBEE0829BCA", "devicegeneration": "MDM9200", "response": "EEDBF8BFF8DAE346"},
|
||||
{"challenge": "20E253156762DACE", "devicegeneration": "SDX55", "response": "03940D7067145323"},
|
||||
{"challenge": "2387885E7D290FEE", "devicegeneration": "MDM9x15A", "response": "DC3E51897BAA9C1E"},
|
||||
]
|
||||
for test in test_table:
|
||||
challenge = test["challenge"]
|
||||
devicegeneration = test["devicegeneration"]
|
||||
response = test["response"]
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
padding = " " * (16 - len(devicegeneration))
|
||||
if openlock != response:
|
||||
print(devicegeneration+padding+" FAILED!")
|
||||
else:
|
||||
print(devicegeneration+padding+" PASSED :)")
|
||||
|
||||
def SierraPreInit(self, counter, key, keylen, challengelen, mcount):
|
||||
if counter != 0:
|
||||
tmp2 = 0
|
||||
i = 1
|
||||
while i < counter:
|
||||
i = 2 * i + 1
|
||||
while True:
|
||||
tmp = mcount
|
||||
mcount = tmp + 1
|
||||
challengelen = (key[tmp & 0xFF] + self.tbl[(challengelen & 0xFF)]) & 0xFF
|
||||
if mcount >= keylen:
|
||||
mcount = 0
|
||||
challengelen = ((challengelen & 0xFF) + keylen) & 0xFF
|
||||
tmp2 = tmp2 + 1
|
||||
tmp3 = ((challengelen & 0xFF) & i) & 0xFF
|
||||
if tmp2 >= 0xB:
|
||||
tmp3 = counter % tmp3
|
||||
if tmp3 <= counter:
|
||||
break
|
||||
counter = tmp3 & 0xFF
|
||||
return [counter, challengelen, mcount]
|
||||
|
||||
def SierraInit(self, key, keylen):
|
||||
if keylen == 0 or keylen > 0x20:
|
||||
retval = [0, keylen]
|
||||
elif 1 <= keylen <= 0x20:
|
||||
self.tbl = [(i&0xFF) for i in range(0, 0x100)]
|
||||
mcount = 0
|
||||
cl = keylen & 0xffffff00
|
||||
i = 0xFF
|
||||
while i > -1:
|
||||
t, cl, mcount = self.SierraPreInit(i, key, keylen, cl, mcount)
|
||||
m = self.tbl[i]
|
||||
self.tbl[i] = self.tbl[(t & 0xff)]
|
||||
i = i - 1
|
||||
self.tbl[(t & 0xFF)] = m
|
||||
self.rtbl[0] = self.tbl[prodtable[self.devicegeneration]["init"][0]] if \
|
||||
prodtable[self.devicegeneration]["init"][0] != 0 else self.tbl[(cl & 0xFF)]
|
||||
self.rtbl[1] = self.tbl[prodtable[self.devicegeneration]["init"][1]] if \
|
||||
prodtable[self.devicegeneration]["init"][1] != 0 else self.tbl[(cl & 0xFF)]
|
||||
self.rtbl[2] = self.tbl[prodtable[self.devicegeneration]["init"][2]] if \
|
||||
prodtable[self.devicegeneration]["init"][2] != 0 else self.tbl[(cl & 0xFF)]
|
||||
self.rtbl[3] = self.tbl[prodtable[self.devicegeneration]["init"][3]] if \
|
||||
prodtable[self.devicegeneration]["init"][3] != 0 else self.tbl[(cl & 0xFF)]
|
||||
self.rtbl[4] = self.tbl[prodtable[self.devicegeneration]["init"][4]] if \
|
||||
prodtable[self.devicegeneration]["init"][4] != 0 else self.tbl[(cl & 0xFF)]
|
||||
retval = [1, keylen]
|
||||
return retval
|
||||
|
||||
def sierra_calc8F(self, challenge, a=0, b=1, c=2, d=3, e=4, ret=0, ret2=2):
|
||||
# MDM9200
|
||||
self.rtbl[b] = (self.rtbl[b] + self.tbl[(self.rtbl[d] & 0xFF)]) & 0xFF
|
||||
uVar2 = self.rtbl[c] & 0xFF
|
||||
bVar1 = self.tbl[uVar2]
|
||||
uVar4 = self.rtbl[b] & 0xFF
|
||||
self.tbl[uVar2] = self.tbl[uVar4]
|
||||
self.rtbl[d] = (self.rtbl[d] + 1) & 0xFF
|
||||
uVar5 = self.rtbl[a] & 0xFF
|
||||
self.tbl[uVar4] = self.tbl[uVar5]
|
||||
uVar3 = self.rtbl[d] & 0xFF
|
||||
self.tbl[uVar5] = self.tbl[uVar3]
|
||||
self.tbl[uVar3] = bVar1
|
||||
self.rtbl[ret] = challenge # c
|
||||
self.rtbl[ret2] = self.tbl[self.tbl[(self.tbl[(self.rtbl[e] + self.tbl[bVar1]) & 0xFF] + (
|
||||
self.tbl[uVar5] & 0xFF) + (self.tbl[uVar2] & 0xFF) & 0xff) & 0xFF] & 0xFF] ^ self.tbl[
|
||||
((self.tbl[uVar4] & 0xFF) + (bVar1 & 0xff)) & 0xFF] ^ challenge # a
|
||||
self.rtbl[e] = (self.rtbl[e] + self.tbl[bVar1]) & 0xFF
|
||||
return self.rtbl[ret2] & 0xFF # a
|
||||
|
||||
def SierraAlgo(self, challenge, a=0, b=1, c=2, d=3, e=4, ret=3, ret2=1, flag=1): # M9x15
|
||||
v6 = self.rtbl[e]
|
||||
v0 = (v6 + 1) & 0xFF
|
||||
self.rtbl[e] = v0
|
||||
self.rtbl[c] = (self.tbl[v6 + flag & 0xFF] + self.rtbl[c]) & 0xFF
|
||||
v4 = self.rtbl[c] & 0xFF
|
||||
v2 = self.rtbl[b] & 0xFF
|
||||
v1 = self.tbl[(v2 & 0xFF)]
|
||||
self.tbl[(v2 & 0xFF)] = self.tbl[(v4 & 0xFF)]
|
||||
v5 = self.rtbl[d] & 0xFF
|
||||
self.tbl[(v4 & 0xFF)] = self.tbl[(v5 & 0xFF)]
|
||||
self.tbl[(v5 & 0xFF)] = self.tbl[(v0 & 0xFF)]
|
||||
self.tbl[v0] = v1 & 0xFF
|
||||
u = self.tbl[(self.tbl[(
|
||||
self.tbl[((self.rtbl[a] + self.tbl[(v1 & 0xFF)]) & 0xFF)] + self.tbl[(v5 & 0xFF)] + self.tbl[
|
||||
(v2 & 0xFF)] & 0xff)] & 0xFF)]
|
||||
v = self.tbl[((self.tbl[(v4 & 0xFF)] + v1) & 0xFF)]
|
||||
self.rtbl[ret] = u ^ v ^ challenge
|
||||
self.rtbl[a] = (self.tbl[(v1 & 0xFF)] + self.rtbl[a]) & 0xFF
|
||||
self.rtbl[ret2] = challenge & 0xFF
|
||||
return self.rtbl[ret] & 0xFF
|
||||
|
||||
def SierraFinish(self):
|
||||
self.tbl = [0 for _ in range(0, 0x100)]
|
||||
self.rtbl[0] = 0
|
||||
self.rtbl[1] = 0
|
||||
self.rtbl[2] = 0
|
||||
self.rtbl[3] = 0
|
||||
self.rtbl[4] = 0
|
||||
return 1
|
||||
|
||||
def SierraKeygen(self, challenge:bytearray, key: bytearray, challengelen:int, keylen:int):
|
||||
challenge = challenge
|
||||
resultbuffer=bytearray([0 for i in range(0, 0x100 + 1)])
|
||||
ret, keylen = self.SierraInit(key, keylen)
|
||||
if ret:
|
||||
for i in range(0, challengelen):
|
||||
exec(prodtable[self.devicegeneration]["run"]) # uses challenge
|
||||
self.SierraFinish()
|
||||
return resultbuffer
|
||||
|
||||
|
||||
class connection:
|
||||
def __init__(self, port=""):
|
||||
self.serial = None
|
||||
self.tn = None
|
||||
self.connected = False
|
||||
if port == "":
|
||||
port = self.detect(port)
|
||||
if port == "":
|
||||
self.tn = Telnet("192.168.1.1", 5510)
|
||||
self.connected = True
|
||||
if port != "":
|
||||
self.serial = serial.Serial(port=port, baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=1)
|
||||
self.connected = self.serial.is_open
|
||||
|
||||
def detect(self, port):
|
||||
if port == "":
|
||||
for port in serial.tools.list_ports.comports():
|
||||
if port.vid == 0x1199:
|
||||
portid = port.location[-1:]
|
||||
if int(portid) == 3:
|
||||
print("Detected Sierra Wireless device at: " + port.device)
|
||||
return port.device
|
||||
elif port.vid == 0x8046:
|
||||
portid = port.location[-1:]
|
||||
if int(portid) == 3:
|
||||
print("Detected Netgear device at: " + port.device)
|
||||
return port.device
|
||||
|
||||
return ""
|
||||
|
||||
def readreply(self):
|
||||
info = []
|
||||
if self.serial is not None:
|
||||
while (True):
|
||||
tmp = self.serial.readline().decode('utf-8').replace('\r', '').replace('\n', '')
|
||||
if "OK" in info:
|
||||
return info
|
||||
elif ("ERROR" in info) or info == "":
|
||||
return -1
|
||||
info.append(tmp)
|
||||
return info
|
||||
|
||||
def send(self, cmd):
|
||||
if self.tn is not None:
|
||||
self.tn.write(bytes(cmd + "\r", 'utf-8'))
|
||||
time.sleep(0.05)
|
||||
data = ""
|
||||
while True:
|
||||
tmp = self.tn.read_eager()
|
||||
if tmp != b"":
|
||||
data += tmp.strip().decode('utf-8')
|
||||
else:
|
||||
break
|
||||
return data.split("\r\n")
|
||||
elif self.serial is not None:
|
||||
self.serial.write(bytes(cmd + "\r", 'utf-8'))
|
||||
time.sleep(0.05)
|
||||
return self.readreply()
|
||||
|
||||
def close(self):
|
||||
if self.tn is not None:
|
||||
self.tn.close()
|
||||
self.connected = False
|
||||
if self.serial is not None:
|
||||
self.serial.close()
|
||||
self.connected = False
|
||||
|
||||
class SierraKeygen(metaclass=LogBase):
|
||||
def __init__(self,cn,devicegeneration=None):
|
||||
self.cn=cn
|
||||
self.keygen = SierraGenerator()
|
||||
if devicegeneration==None:
|
||||
self.detectdevicegeneration()
|
||||
else:
|
||||
self.devicegeneration=devicegeneration
|
||||
|
||||
def run_selftest(self):
|
||||
print("Running self-test ...")
|
||||
self.keygen.selftest()
|
||||
|
||||
def detectdevicegeneration(self):
|
||||
if self.cn.connected:
|
||||
info = self.cn.send("ATI")
|
||||
if info != -1:
|
||||
revision = ""
|
||||
model = ""
|
||||
for line in info:
|
||||
if "Revision" in line:
|
||||
revision = line.split(":")[1].strip()
|
||||
if "Model" in line:
|
||||
model = line.split(":")[1].strip()
|
||||
if revision != "":
|
||||
if "9200" in revision:
|
||||
devicegeneration = "MDM9200" #AC762S NTG9200H2_03.05.14.12ap
|
||||
if "9X07" in revision:
|
||||
devicegeneration = "MDM9x07"
|
||||
elif "9X25" in revision:
|
||||
if "NTG9X25C" in revision:
|
||||
devicegeneration = "MDM9200" #AC781S NTG9X25C_01.00.57.00
|
||||
elif "9X15" in revision:
|
||||
if "NTG9X15A" in revision:
|
||||
devicegeneration = "MDM9x15A" #Aircard 779S
|
||||
elif "NTG9X15C" in revision:
|
||||
devicegeneration = "MDM9200" #AC770S NTG9X15C_01.18.02.00
|
||||
elif "9X15A" in revision:
|
||||
devicegeneration = "MDM9x15A"
|
||||
else:
|
||||
devicegeneration = "MDM9x15"
|
||||
elif "9X30" in revision:
|
||||
if "NTG9X35C" in revision: #790S NTG9X35C_11.11.15.03
|
||||
devicegeneration = "MDM9x30_V1"
|
||||
else:
|
||||
devicegeneration = "MDM9x30"
|
||||
elif "9X40" in revision and not "9X40C" in revision:
|
||||
devicegeneration = "MDM9x40"
|
||||
elif "9X50" in revision:
|
||||
if "NTG9X50" in revision:
|
||||
devicegeneration = "MDM9x40" #MR1100,AC797S NTG9X50C_12.06.03.00
|
||||
else:
|
||||
devicegeneration = "MDM9x50"
|
||||
elif "9X06" in revision:
|
||||
devicegeneration = "MDM9x06"
|
||||
elif "X55" in revision or "9X40C" in revision:
|
||||
if "NTGX55" in revision: #MR5100 NTGX55_10.25.15.02
|
||||
devicegeneration = "SDX55"
|
||||
devicegeneration = "SDX55"
|
||||
#Missing:
|
||||
# SDX24 Sierra
|
||||
# MR2100 NTGX24_10.17.03.00
|
||||
# SDX55 Sierra
|
||||
# AC810S NTG9X40C_11.14.08.16
|
||||
# AC800S NTG9X40C_11.14.07.00
|
||||
self.devicegeneration=devicegeneration
|
||||
else:
|
||||
print("Error on getting ATI modem response. Wrong port? Aborting.")
|
||||
self.cn.close()
|
||||
exit(0)
|
||||
|
||||
def openlock(self):
|
||||
print("Device generation detected: " + self.devicegeneration)
|
||||
#print("Sending AT!ENTERCND=\"A710\" request.")
|
||||
#info = self.cn.send("AT!ENTERCND=\"A710\"")
|
||||
#if info == -1:
|
||||
# print("Uhoh ... invalid entercnd password. Aborting ...")
|
||||
# return
|
||||
print("Sending AT!OPENLOCK? request")
|
||||
info = self.cn.send("AT!OPENLOCK?")
|
||||
challenge = ""
|
||||
if info != -1:
|
||||
if len(info) > 2:
|
||||
challenge = info[1]
|
||||
else:
|
||||
print("Error on AT!OPENLOCK? request. Aborting.")
|
||||
return
|
||||
if challenge == "":
|
||||
print("Error: Couldn't get challenge. Aborting.")
|
||||
return
|
||||
resp = self.keygen.run(self.devicegeneration, challenge, 0)
|
||||
print("Sending AT!OPENLOCK=\"" + resp + "\" response.")
|
||||
info = self.cn.send("AT!OPENLOCK=\"" + resp + "\"")
|
||||
if info == -1:
|
||||
print("Damn. AT!OPENLOCK failed.")
|
||||
else:
|
||||
print("Success. Device is now engineer unlocked.")
|
||||
return True
|
||||
return False
|
||||
|
||||
def main(args):
|
||||
version = "1.4"
|
||||
info = 'Sierra Wireless Generator ' + version + ' (c) B. Kerler 2019-2021'
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,description=info)
|
||||
|
||||
parser.add_argument(
|
||||
'-openlock', '-l',
|
||||
help='AT!OPENLOCK? modem response',
|
||||
default="")
|
||||
|
||||
parser.add_argument(
|
||||
'-openmep', '-m',
|
||||
help='AT!OPENMEP? modem response',
|
||||
default="")
|
||||
|
||||
parser.add_argument(
|
||||
'-opencnd', '-c',
|
||||
help='AT!OPENCND? modem response',
|
||||
default="")
|
||||
|
||||
parser.add_argument(
|
||||
'-devicegeneration', '-d',
|
||||
help='Device devicegeneration generation',
|
||||
default="")
|
||||
|
||||
parser.add_argument(
|
||||
'-port', '-p',
|
||||
help='use com port for auto unlock',
|
||||
default="")
|
||||
|
||||
parser.add_argument(
|
||||
'-unlock', '-u',
|
||||
help='use com port for openlock',
|
||||
default=False, action='store_true')
|
||||
|
||||
parser.add_argument(
|
||||
'-selftest', '-s',
|
||||
help='run selftest',
|
||||
default=False, action='store_true')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
openlock = args.openlock
|
||||
openmep = args.openmep
|
||||
opencnd = args.opencnd
|
||||
devicegeneration = args.devicegeneration
|
||||
|
||||
if not args.selftest:
|
||||
if (devicegeneration == "" or (openlock == "" and openmep == "" and opencnd == "")) and not args.unlock:
|
||||
print(info)
|
||||
print("------------------------------------------------------------\n")
|
||||
print("Usage: ./sierrakeygen [-l,-m,-c] [challenge] -d [devicegeneration]")
|
||||
print("Example: ./sierrakeygen.py -l BE96CBBEE0829BCA -d MDM9200")
|
||||
print("or: ./sierrakeygen.py -u for auto unlock")
|
||||
print("or: ./sierrakeygen.py -u -p [portname] for auto unlock with given portname")
|
||||
print("or: ./sierrakeygen.py -s for self-test")
|
||||
print("Supported devicegenerations :")
|
||||
for key in infotable:
|
||||
info = f"\t{key}:\t\t"
|
||||
count = 0
|
||||
for item in infotable[key]:
|
||||
count += 1
|
||||
if count > 15:
|
||||
info += "\n\t\t\t\t\t"
|
||||
count = 0
|
||||
info += item + ","
|
||||
|
||||
info = info[:-1]
|
||||
print(info)
|
||||
exit(0)
|
||||
|
||||
if devicegeneration == "" and not args.unlock:
|
||||
print("You need to specific a device generation as well. Option -d")
|
||||
exit(0)
|
||||
if devicegeneration == "":
|
||||
devicegeneration=None
|
||||
if args.selftest:
|
||||
kg=SierraKeygen(None,"selftest")
|
||||
kg.run_selftest()
|
||||
elif args.unlock:
|
||||
cn = connection(args.port)
|
||||
if cn.connected:
|
||||
kg=SierraKeygen(cn,devicegeneration)
|
||||
if kg.devicegeneration == "":
|
||||
print("Unknown device generation. Please send me details :)")
|
||||
else:
|
||||
kg.openlock()
|
||||
cn.close()
|
||||
else:
|
||||
kg = SierraKeygen(None, devicegeneration)
|
||||
if openlock != "":
|
||||
resp = kg.keygen.run(devicegeneration, openlock, 0)
|
||||
print("AT!OPENLOCK=\"" + resp + "\"")
|
||||
elif openmep != "":
|
||||
resp = kg.keygen.run(devicegeneration, openmep, 1)
|
||||
print("AT!OPENMEP=\"" + resp + "\"")
|
||||
elif opencnd != "":
|
||||
resp = kg.keygen.run(devicegeneration, opencnd, 2)
|
||||
print("AT!OPENCND=\"" + resp + "\"")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
1
edlclient/Tools/sierrakeygen
Symbolic link
1
edlclient/Tools/sierrakeygen
Symbolic link
|
@ -0,0 +1 @@
|
|||
sierrakeygen.py
|
4
setup.py
4
setup.py
|
@ -4,10 +4,10 @@ import os
|
|||
|
||||
setup(
|
||||
name='edlclient',
|
||||
version='3.53',
|
||||
version='3.60',
|
||||
packages=find_packages(),
|
||||
long_description=open("README.md").read(),
|
||||
scripts=['edl','edlclient/Tools/qc_diag','edlclient/Tools/sierrakeygen','edlclient/Tools/boottodwnload','edlclient/Tools/enableadb','edlclient/Tools/fhloaderparse','edlclient/Tools/beagle_to_loader'],
|
||||
scripts=['edl','edlclient/Tools/qc_diag.py','edlclient/Tools/sierrakeygen.py','edlclient/Tools/boottodwnload','edlclient/Tools/enableadb','edlclient/Tools/fhloaderparse','edlclient/Tools/beagle_to_loader'],
|
||||
data_files = ['LICENSE','README.md'],
|
||||
long_description_content_type="text/markdown",
|
||||
url='https://github.com/bkerler/edl',
|
||||
|
|
Loading…
Reference in a new issue