Bump to 3.60 pre-release

This commit is contained in:
Bjoern Kerler 2022-01-26 10:08:33 +01:00
parent d5ff2d474a
commit d81e857379
22 changed files with 1815 additions and 3891 deletions

View file

@ -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
View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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))

View file

@ -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:

View file

@ -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

View file

@ -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
"""

View file

@ -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:

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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:

View file

@ -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()

View file

@ -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
View file

@ -0,0 +1 @@
qc_diag.py

View file

@ -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)

View file

@ -0,0 +1 @@
sierrakeygen.py

View file

@ -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',