mirror of
https://github.com/bkerler/edl.git
synced 2024-11-21 10:38:10 -05:00
New structure
This commit is contained in:
parent
17d96e8953
commit
d13f2d22c8
46 changed files with 3919 additions and 143 deletions
|
@ -2,6 +2,7 @@ include README.md
|
|||
include LICENSE
|
||||
include fastpwn
|
||||
recursive-include Loaders *
|
||||
include edl/Windows/*.dll
|
||||
recursive-include edl/Library/TestFiles *
|
||||
include edlclient/Windows/*.dll
|
||||
include edlclient/Config/nvitems.xml
|
||||
recursive-include edlclient/Library/TestFiles *
|
||||
|
||||
|
|
128
README.md
128
README.md
|
@ -91,79 +91,79 @@ or from [here](https://github.com/bkerler/Loaders)
|
|||
|
||||
### Generic
|
||||
|
||||
- ```python edl.py -h``` -> to see help with all options
|
||||
- ```python edl.py server --memory=ufs --tcpport=1340``` -> Run TCP/IP server on port 1340, see tcpclient.py for an example client
|
||||
- ```python edl.py xml run.xml``` -> To send a xml file run.xml via firehose
|
||||
- ```python edl.py reset``` -> To reboot the phone
|
||||
- ```python edl.py rawxml <xmlstring>``` -> To send own xml string, example :
|
||||
```python edl.py rawxml "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><data><response value=\"ACK\" /></data>```
|
||||
- ```python edl.py [anycommand] --debugmode``` -> enables Verbose. Only do that is REALLY needed as it will print out everything happening !
|
||||
- ```edl -h``` -> to see help with all options
|
||||
- ```edl server --memory=ufs --tcpport=1340``` -> Run TCP/IP server on port 1340, see tcpclient.py for an example client
|
||||
- ```edl xml run.xml``` -> To send a xml file run.xml via firehose
|
||||
- ```edl reset``` -> To reboot the phone
|
||||
- ```edl rawxml <xmlstring>``` -> To send own xml string, example :
|
||||
```edl rawxml "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><data><response value=\"ACK\" /></data>```
|
||||
- ```edl [anycommand] --debugmode``` -> enables Verbose. Only do that is REALLY needed as it will print out everything happening !
|
||||
|
||||
### For EMMC Flash
|
||||
|
||||
- ```python edl.py printgpt``` -> to print gpt on device with emmc
|
||||
- ```python edl.py rf flash.bin``` -> to dump whole flash for device with emmc
|
||||
- ```python edl.py rl dumps --skip=userdata --genxml``` -> to dump all partitions to directory dumps for device with emmc and skipping userdata partition, write rawprogram0.xml
|
||||
- ```python edl.py rs 0 15 data.bin``` -> to dump 15 sectors from starting sector 0 to file data.bin for device with emmc
|
||||
- ```python edl.py rs 0 15 data.bin --skipresponse``` -> to dump 15 sectors from starting sector 0 to file data.bin for device with emmc, ignores missing ACK from phones
|
||||
- ```python edl.py r boot_a boot.img``` -> to dump the partition "boot_a" to the filename boot.img for device with emmc
|
||||
- ```python edl.py r boot_a,boot_b boot_a.img,boot_b.img``` -> to dump multiple partitions to multiple filenames
|
||||
- ```python edl.py footer footer.bin``` -> to dump the crypto footer for Androids with emmc flash
|
||||
- ```python edl.py w boot_a boot.img``` -> to write boot.img to the "boot" partition on lun 0 on the device with emmc flash
|
||||
- ```python edl.py w gpt gpt.img``` -> to write gpt partition table from gpt.img to the first sector on the device with emmc flash
|
||||
- ```python edl.py wl dumps``` -> to write all files from "dumps" folder to according partitions to flash
|
||||
- ```python edl.py wf dump.bin``` -> to write the rawimage dump.bin to flash
|
||||
- ```python edl.py e misc``` -> to erase the partition misc on emmc flash
|
||||
- ```python edl.py gpt . --genxml``` -> dump gpt_main0.bin/gpt_backup0.bin and write rawpartition0.xml to current directory (".")
|
||||
- ```edl printgpt``` -> to print gpt on device with emmc
|
||||
- ```edl rf flash.bin``` -> to dump whole flash for device with emmc
|
||||
- ```edl rl dumps --skip=userdata --genxml``` -> to dump all partitions to directory dumps for device with emmc and skipping userdata partition, write rawprogram0.xml
|
||||
- ```edl rs 0 15 data.bin``` -> to dump 15 sectors from starting sector 0 to file data.bin for device with emmc
|
||||
- ```edl rs 0 15 data.bin --skipresponse``` -> to dump 15 sectors from starting sector 0 to file data.bin for device with emmc, ignores missing ACK from phones
|
||||
- ```edl r boot_a boot.img``` -> to dump the partition "boot_a" to the filename boot.img for device with emmc
|
||||
- ```edl r boot_a,boot_b boot_a.img,boot_b.img``` -> to dump multiple partitions to multiple filenames
|
||||
- ```edl footer footer.bin``` -> to dump the crypto footer for Androids with emmc flash
|
||||
- ```edl w boot_a boot.img``` -> to write boot.img to the "boot" partition on lun 0 on the device with emmc flash
|
||||
- ```edl w gpt gpt.img``` -> to write gpt partition table from gpt.img to the first sector on the device with emmc flash
|
||||
- ```edl wl dumps``` -> to write all files from "dumps" folder to according partitions to flash
|
||||
- ```edl wf dump.bin``` -> to write the rawimage dump.bin to flash
|
||||
- ```edl e misc``` -> to erase the partition misc on emmc flash
|
||||
- ```edl gpt . --genxml``` -> dump gpt_main0.bin/gpt_backup0.bin and write rawpartition0.xml to current directory (".")
|
||||
|
||||
|
||||
### For UFS Flash
|
||||
|
||||
- ```python edl.py printgpt --memory=ufs --lun=0``` -> to print gpt on lun 0
|
||||
- ```python edl.py printgpt --memory=ufs``` -> to print gpt of all lun
|
||||
- ```python edl.py rf lun0.bin --memory=ufs --lun=0``` -> to dump whole lun 0
|
||||
- ```python edl.py rf flash.bin --memory=ufs``` -> to dump all luns as lun0_flash.bin, lun1_flash.bin, ...
|
||||
- ```python edl.py rl dumps --memory=ufs --lun=0 --skip=userdata,vendor_a``` -> to dump all partitions from lun0 to directory dumps for device with ufs and skip userdata and vendor_a partition
|
||||
- ```python edl.py rl dumps --memory=ufs --genxml``` -> to dump all partitions from all lun to directory dumps and write rawprogram[lun].xml
|
||||
- ```python edl.py rs 0 15 data.bin --memory=ufs --lun=0``` -> to dump 15 sectors from starting sector 0 from lun 0 to file data.bin
|
||||
- ```python edl.py r boot_a boot.img --memory=ufs --lun=4``` -> to dump the partition "boot_a" from lun 4 to the filename boot.img
|
||||
- ```python edl.py r boot_a boot.img --memory=ufs``` -> to dump the partition "boot_a" to the filename boot.img using lun autodetection
|
||||
- ```python edl.py r boot_a,boot_b boot_a.img,boot_b.img --memory=ufs``` -> to dump multiple partitions to multiple filenames
|
||||
- ```python edl.py footer footer.bin --memory=ufs``` -> to dump the crypto footer
|
||||
- ```python edl.py w boot boot.img --memory=ufs --lun=4``` -> to write boot.img to the "boot" partition on lun 4 on the device with ufs flash
|
||||
- ```python edl.py w gpt gpt.img --memory=ufs --lun=4``` -> to write gpt partition table from gpt.img to the lun 4 on the device with ufs flash
|
||||
- ```python edl.py wl dumps --memory=ufs --lun=0``` -> to write all files from "dumps" folder to according partitions to flash lun 0
|
||||
- ```python edl.py wl dumps --memory=ufs``` -> to write all files from "dumps" folder to according partitions to flash and try to autodetect lun
|
||||
- ```python edl.py wf dump.bin --memory=ufs --lun=0``` -> to write the rawimage dump.bin to flash lun 0
|
||||
- ```python edl.py e misc --memory=ufs --lun=0``` -> to erase the partition misc on lun 0
|
||||
- ```python edl.py gpt . --genxml --memory=ufs``` -> dump gpt_main[lun].bin/gpt_backup[lun].bin and write rawpartition[lun].xml to current directory (".")
|
||||
- ```edl printgpt --memory=ufs --lun=0``` -> to print gpt on lun 0
|
||||
- ```edl printgpt --memory=ufs``` -> to print gpt of all lun
|
||||
- ```edl rf lun0.bin --memory=ufs --lun=0``` -> to dump whole lun 0
|
||||
- ```edl rf flash.bin --memory=ufs``` -> to dump all luns as lun0_flash.bin, lun1_flash.bin, ...
|
||||
- ```edl rl dumps --memory=ufs --lun=0 --skip=userdata,vendor_a``` -> to dump all partitions from lun0 to directory dumps for device with ufs and skip userdata and vendor_a partition
|
||||
- ```edl rl dumps --memory=ufs --genxml``` -> to dump all partitions from all lun to directory dumps and write rawprogram[lun].xml
|
||||
- ```edl rs 0 15 data.bin --memory=ufs --lun=0``` -> to dump 15 sectors from starting sector 0 from lun 0 to file data.bin
|
||||
- ```edl r boot_a boot.img --memory=ufs --lun=4``` -> to dump the partition "boot_a" from lun 4 to the filename boot.img
|
||||
- ```edl r boot_a boot.img --memory=ufs``` -> to dump the partition "boot_a" to the filename boot.img using lun autodetection
|
||||
- ```edl r boot_a,boot_b boot_a.img,boot_b.img --memory=ufs``` -> to dump multiple partitions to multiple filenames
|
||||
- ```edl footer footer.bin --memory=ufs``` -> to dump the crypto footer
|
||||
- ```edl w boot boot.img --memory=ufs --lun=4``` -> to write boot.img to the "boot" partition on lun 4 on the device with ufs flash
|
||||
- ```edl w gpt gpt.img --memory=ufs --lun=4``` -> to write gpt partition table from gpt.img to the lun 4 on the device with ufs flash
|
||||
- ```edl wl dumps --memory=ufs --lun=0``` -> to write all files from "dumps" folder to according partitions to flash lun 0
|
||||
- ```edl wl dumps --memory=ufs``` -> to write all files from "dumps" folder to according partitions to flash and try to autodetect lun
|
||||
- ```edl wf dump.bin --memory=ufs --lun=0``` -> to write the rawimage dump.bin to flash lun 0
|
||||
- ```edl e misc --memory=ufs --lun=0``` -> to erase the partition misc on lun 0
|
||||
- ```edl gpt . --genxml --memory=ufs``` -> dump gpt_main[lun].bin/gpt_backup[lun].bin and write rawpartition[lun].xml to current directory (".")
|
||||
|
||||
### QFIL emulation (credits to LyuOnLine):
|
||||
|
||||
- For flashing full image:
|
||||
```
|
||||
python edl.py qfil rawprogram0.xml patch0.xml image_dir
|
||||
edl qfil rawprogram0.xml patch0.xml image_dir
|
||||
```
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
### For devices with peek/poke command
|
||||
|
||||
- ```python edl.py peek 0x200000 0x10 mem.bin``` -> To dump 0x10 bytes from offset 0x200000 to file mem.bin from memory
|
||||
- ```python edl.py peekhex 0x200000 0x10``` -> To dump 0x10 bytes from offset 0x200000 as hex string from memory
|
||||
- ```python edl.py peekqword 0x200000``` -> To display a qword (8-bytes) at offset 0x200000 from memory
|
||||
- ```python edl.py pokeqword 0x200000 0x400000``` -> To write the q-word value 0x400000 to offset 0x200000 in memory
|
||||
- ```python edl.py poke 0x200000 mem.bin``` -> To write the binary file mem.bin to offset 0x200000 in memory
|
||||
- ```python edl.py secureboot``` -> To display secureboot fuses (only on EL3 loaders)
|
||||
- ```python edl.py pbl pbl.bin``` -> To dump pbl (only on EL3 loaders)
|
||||
- ```python edl.py qfp qfp.bin``` -> To dump qfprom fuses (only on EL3 loaders)
|
||||
- ```edl peek 0x200000 0x10 mem.bin``` -> To dump 0x10 bytes from offset 0x200000 to file mem.bin from memory
|
||||
- ```edl peekhex 0x200000 0x10``` -> To dump 0x10 bytes from offset 0x200000 as hex string from memory
|
||||
- ```edl peekqword 0x200000``` -> To display a qword (8-bytes) at offset 0x200000 from memory
|
||||
- ```edl pokeqword 0x200000 0x400000``` -> To write the q-word value 0x400000 to offset 0x200000 in memory
|
||||
- ```edl poke 0x200000 mem.bin``` -> To write the binary file mem.bin to offset 0x200000 in memory
|
||||
- ```edl secureboot``` -> To display secureboot fuses (only on EL3 loaders)
|
||||
- ```edl pbl pbl.bin``` -> To dump pbl (only on EL3 loaders)
|
||||
- ```edl qfp qfp.bin``` -> To dump qfprom fuses (only on EL3 loaders)
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
### For generic unlocking
|
||||
- ```python edl.py modules oemunlock enable``` -> Unlocks OEM if partition "config" exists, fastboot oem unlock is still needed afterwards
|
||||
- ```edl modules oemunlock enable``` -> Unlocks OEM if partition "config" exists, fastboot oem unlock is still needed afterwards
|
||||
|
||||
#### Dump memory (0x900E mode)
|
||||
- ```python edl.py memorydump```
|
||||
- ```edl memorydump```
|
||||
-
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
### Streaming mode (credits to forth32)
|
||||
|
@ -173,34 +173,34 @@ or from [here](https://github.com/bkerler/Loaders)
|
|||
##### Sierra Wireless Modem
|
||||
- Send AT!BOOTHOLD and AT!QPSTDLOAD to modem port or use ```modem/boottodwnload.py``` script
|
||||
- Send AT!ENTERCND="A710" and then AT!EROPTION=0 for memory dump
|
||||
- ```python edl.py --vid 1199 --pid 9070 --loader=loaders/NPRG9x35p.bin printgpt``` -> To show the partition table
|
||||
- ```edl --vid 1199 --pid 9070 --loader=loaders/NPRG9x35p.bin printgpt``` -> To show the partition table
|
||||
|
||||
##### Netgear MR1100
|
||||
- run ```python modem/boottodownload.py```, device will enter download mode (0x900E pid)
|
||||
- ```python edl.py printgpt --loader=Loaders/qualcomm/patched/mdm9x5x/NPRG9x55p.bin```, device will reboot to 0x9008
|
||||
- now use python edl.py regulary such as ```python edl.py printgpt``` (do not use loader option)
|
||||
- ```edl printgpt --loader=Loaders/qualcomm/patched/mdm9x5x/NPRG9x55p.bin```, device will reboot to 0x9008
|
||||
- now use edl regulary such as ```edl printgpt``` (do not use loader option)
|
||||
|
||||
##### ZTE MF920V, Quectel, Telit, etc.. Modem
|
||||
- run ```python modem/enableadb.sh```, or send to at port "AT+ZCDRUN=E", or send via ```python diag.py -sahara```
|
||||
- run ```python modem/enableadb.sh```, or send to at port "AT+ZCDRUN=E", or send via ```qc_diag -sahara```
|
||||
- ```adb reboot edl```
|
||||
- ```python edl.py printgpt``` -> To show the partition table
|
||||
- ```edl printgpt``` -> To show the partition table
|
||||
|
||||
|
||||
## Run Diag port tools (examples)
|
||||
|
||||
For Oneplus 6T, enter *#801#* on dialpad, set Engineer Mode and Serial to on and try :
|
||||
|
||||
- ```python diag.py -vid 0x05c6 -pid 0x676c -interface 0 -info```
|
||||
- ```qc_diag -vid 0x05c6 -pid 0x676c -interface 0 -info```
|
||||
|
||||
### Usage
|
||||
|
||||
- ```python diag.py -vid 0x1234 -pid 0x5678 -interface 0 -info``` -> Send cmd "00" and return info
|
||||
- ```python diag.py -vid 0x1234 -pid 0x5678 -interface 0 -spc 303030303030``` -> Send spc "303030303030"
|
||||
- ```python diag.py -vid 0x1234 -pid 0x5678 -interface 0 -cmd 00``` -> Send cmd "00" (hexstring)
|
||||
- ```python diag.py -vid 0x1234 -pid 0x5678 -interface 0 -nvread 0x55``` -> Display nvitem 0x55
|
||||
- ```python diag.py -vid 0x1234 -pid 0x5678 -interface 0 -nvbackup backup.json``` -> Backup all nvitems to a json structured file
|
||||
- ```python diag.py -vid 0x1234 -pid 0x5678 -interface 0 -efsread efs.bin``` -> Dump the EFS Modem partition to file efs.bin
|
||||
- ```python diag.py -vid 0x1234 -pid 0x5678 -interface 0 -efslistdir /``` -> Display / directory listing of EFS
|
||||
- ```qc_diag -vid 0x1234 -pid 0x5678 -interface 0 -info``` -> Send cmd "00" and return info
|
||||
- ```qc_diag -vid 0x1234 -pid 0x5678 -interface 0 -spc 303030303030``` -> Send spc "303030303030"
|
||||
- ```qc_diag -vid 0x1234 -pid 0x5678 -interface 0 -cmd 00``` -> Send cmd "00" (hexstring)
|
||||
- ```qc_diag -vid 0x1234 -pid 0x5678 -interface 0 -nvread 0x55``` -> Display nvitem 0x55
|
||||
- ```qc_diag -vid 0x1234 -pid 0x5678 -interface 0 -nvbackup backup.json``` -> Backup all nvitems to a json structured file
|
||||
- ```qc_diag -vid 0x1234 -pid 0x5678 -interface 0 -efsread efs.bin``` -> Dump the EFS Modem partition to file efs.bin
|
||||
- ```qc_diag -vid 0x1234 -pid 0x5678 -interface 0 -efslistdir /``` -> Display / directory listing of EFS
|
||||
|
||||
|
||||
## Issues
|
||||
|
@ -212,7 +212,7 @@ For Oneplus 6T, enter *#801#* on dialpad, set Engineer Mode and Serial to on and
|
|||
|
||||
## Tested with
|
||||
|
||||
- Oneplus 3T/5/6T/7T/8/8t/N10/N100 (Read-Only), BQ X, BQ X5, BQ X2, Gigaset ME Pure, ZTE MF210, ZTE MF920V, Sierra Wireless EM7455, Netgear MR1100-10EUS, Netgear MR5100
|
||||
- Oneplus 3T/5/6T/7T/8/8t/9/Nord CE/N10/N100 (Read-Only), BQ X, BQ X5, BQ X2, Gigaset ME Pure, ZTE MF210, ZTE MF920V, Sierra Wireless EM7455, Netgear MR1100-10EUS, Netgear MR5100
|
||||
|
||||
Published under MIT license
|
||||
Additional license limitations: No use in commercial products without prior permit.
|
||||
|
|
362
edl
Executable file
362
edl
Executable file
|
@ -0,0 +1,362 @@
|
|||
#!/usr/bin/env python3
|
||||
# Qualcomm Sahara / Firehose Client (c) B.Kerler 2018-2021
|
||||
# Licensed under MIT License
|
||||
"""
|
||||
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]
|
||||
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]
|
||||
edl gpt <directory> [--memory=memtype] [--lun=lun] [--genxml] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl r <partitionname> <filename> [--memory=memtype] [--sectorsize==bytes] [--lun=lun] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl rl <directory> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skip=partnames] [--genxml] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl rf <filename> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid]
|
||||
edl rs <start_sector> <sectors> <filename> [--lun=lun] [--sectorsize==bytes] [--memory=memtype] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid]
|
||||
edl w <partitionname> <filename> [--partitionfilename=filename] [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skipwrite] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value]
|
||||
edl wl <directory> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skip=partnames] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value]
|
||||
edl wf <filename> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value]
|
||||
edl ws <start_sector> <filename> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skipwrite] [--skipresponse] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value]
|
||||
edl e <partitionname> [--memory=memtype] [--skipwrite] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value]
|
||||
edl es <start_sector> <sectors> [--memory=memtype] [--lun=lun] [--sectorsize==bytes] [--skipwrite] [--loader=filename] [--skipresponse] [--debugmode] [--vid=vid] [--pid=pid] [--devicemodel=value]
|
||||
edl ep <partitionname> <sectors> [--memory=memtype] [--skipwrite] [--lun=lun] [--sectorsize==bytes] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value]
|
||||
edl footer <filename> [--memory=memtype] [--lun=lun] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid]
|
||||
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]
|
||||
edl peekqword <offset> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl memtbl <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl poke <offset> <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl pokehex <offset> <data> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl pokedword <offset> <data> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl pokeqword <offset> <data> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl memcpy <offset> <size> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl secureboot [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl pbl <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl qfp <filename> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl getstorageinfo [--loader=filename] [--memory=memtype] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid]
|
||||
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]
|
||||
edl rawxml <xmlstring> [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value]
|
||||
edl reset [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl nop [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
|
||||
edl modules <command> <options> [--memory=memtype] [--lun=lun] [--loader=filename] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid] [--devicemodel=value]
|
||||
edl qfil <rawprogram> <patch> <imagedir> [--loader=filename] [--memory=memtype] [--debugmode] [--skipresponse] [--vid=vid] [--pid=pid]
|
||||
|
||||
Description:
|
||||
server # Run tcp/ip server
|
||||
printgpt # Print GPT Table information
|
||||
gpt # Save gpt table to given directory
|
||||
r # Read flash to filename
|
||||
rl # Read all partitions from flash to a directory
|
||||
rf # Read whole flash to file
|
||||
rs # Read sectors starting at start_sector to filename
|
||||
w # Write filename to partition to flash
|
||||
wl # Write all files from directory to flash
|
||||
wf # Write whole filename to flash
|
||||
ws # Write filename to flash at start_sector
|
||||
e # Erase partition from flash
|
||||
es # Erase sectors at start_sector from flash
|
||||
ep # Erase sector count from flash partition
|
||||
footer # Read crypto footer from flash
|
||||
peek # Dump memory at offset with given length to filename
|
||||
peekhex # Dump memory at offset and given length
|
||||
peekdword # Dump DWORD at memory offset
|
||||
peekqword # Dump QWORD at memory offset
|
||||
memtbl # Dump memory table to file
|
||||
poke # Write filename to memory at offset to memory
|
||||
pokehex # Write hex string data at offset to memory
|
||||
pokedword # Write DWORD to memory at offset
|
||||
pokeqword # Write QWORD to memory at offset
|
||||
memcpy # Copy memory from srcoffset with given size to dstoffset
|
||||
secureboot # Print secureboot fields from qfprom fuses
|
||||
pbl # Dump primary bootloader to filename
|
||||
qfp # Dump QFPROM fuses to filename
|
||||
getstorageinfo # Print storage info in firehose mode
|
||||
setbootablestoragedrive # Change bootable storage drive to lun number
|
||||
send # Send firehose command
|
||||
xml # Send firehose xml file
|
||||
rawxml # Send firehose xml raw string
|
||||
reset # Send firehose reset command
|
||||
nop # Send firehose nop command
|
||||
modules # Enable submodules, for example: "oemunlock enable"
|
||||
qfil # Write rawprogram xml files
|
||||
# <rawprogram> : program config xml, such as rawprogram_unsparse.xml or rawprogram*.xml
|
||||
# <patch> : patch config xml, such as patch0.xml or patch*.xml
|
||||
# <imagedir> : directory name of image files
|
||||
|
||||
Options:
|
||||
--loader=filename Use specific EDL loader, disable autodetection [default: None]
|
||||
--vid=vid Set usb vendor id used for EDL [default: -1]
|
||||
--pid=pid Set usb product id used for EDL [default: -1]
|
||||
--lun=lun Set lun to read/write from (UFS memory only)
|
||||
--maxpayload=bytes Set the maximum payload for EDL [default: 0x100000]
|
||||
--sectorsize=bytes Set default sector size
|
||||
--memory=memtype Set memory type ("NAND", "eMMC", "UFS", "spinor")
|
||||
--partitionfilename=filename Set partition table as filename for streaming mode
|
||||
--partitions=partnames Skip reading partition with names != "partname1,partname2,etc."
|
||||
--skipwrite Do not allow any writes to flash (simulate only)
|
||||
--skipresponse Do not expect a response from phone on read/write (some Qualcomms)
|
||||
--skipstorageinit Skip storage initialisation
|
||||
--debugmode Enable verbose mode
|
||||
--gpt-num-part-entries=number Set GPT entry count [default: 0]
|
||||
--gpt-part-entry-size=number Set GPT entry size [default: 0]
|
||||
--gpt-part-entry-start-lba=number Set GPT entry start lba sector [default: 0]
|
||||
--tcpport=portnumber Set port for tcp server [default: 1340]
|
||||
--skip=partnames Skip reading partition with names "partname1,partname2,etc."
|
||||
--genxml Generate rawprogram[lun].xml
|
||||
--devicemodel=value Set device model
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import logging
|
||||
import subprocess
|
||||
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.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 binascii import hexlify
|
||||
|
||||
args = docopt(__doc__, version='3')
|
||||
|
||||
print("Qualcomm Sahara / Firehose Client V3.53 (c) B.Kerler 2018-2021.")
|
||||
|
||||
|
||||
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", "qfil"]
|
||||
for cmd in cmds:
|
||||
if rargs[cmd]:
|
||||
return cmd
|
||||
return ""
|
||||
|
||||
|
||||
def console_cmd(cmd):
|
||||
read = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT, close_fds=True)
|
||||
output = read.stdout.read().decode()
|
||||
return output
|
||||
|
||||
|
||||
def parse_option(rargs):
|
||||
options = {}
|
||||
for arg in rargs:
|
||||
if "--" in arg or "<" in arg:
|
||||
options[arg] = rargs[arg]
|
||||
return options
|
||||
|
||||
|
||||
class main(metaclass=LogBase):
|
||||
def __init__(self):
|
||||
self.__logger = self.__logger
|
||||
self.info = self.__logger.info
|
||||
self.debug = self.__logger.debug
|
||||
self.error = self.__logger.error
|
||||
self.warning = self.__logger.warning
|
||||
self.cdc = None
|
||||
self.sahara = None
|
||||
|
||||
def doconnect(self, loop, mode, resp):
|
||||
while not self.cdc.connected:
|
||||
self.cdc.connected = self.cdc.connect()
|
||||
if not self.cdc.connected:
|
||||
sys.stdout.write('.')
|
||||
if loop == 5:
|
||||
sys.stdout.write('\n')
|
||||
self.info("Hint: Press and hold vol up+dwn, connect usb. For some, only use vol up.")
|
||||
self.info("Xiaomi: Press and hold vol dwn + pwr, in fastboot mode connect usb.\n" +
|
||||
" Run \"./fastpwn oem edl\".")
|
||||
self.info("Other: Run \"adb reboot edl\".")
|
||||
sys.stdout.write('\n')
|
||||
|
||||
if loop >= 20:
|
||||
sys.stdout.write('\n')
|
||||
loop = 6
|
||||
loop += 1
|
||||
time.sleep(1)
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
self.info("Device detected :)")
|
||||
try:
|
||||
mode, 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
|
||||
|
||||
def exit(self):
|
||||
self.cdc.close()
|
||||
sys.exit()
|
||||
|
||||
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')
|
||||
if re.findall(r'QCUSB', str(proper_driver)):
|
||||
self.warning(f'Please first install libusb_win32 driver from Zadig')
|
||||
|
||||
mode = ""
|
||||
loop = 0
|
||||
vid = int(args["--vid"], 16)
|
||||
pid = int(args["--pid"], 16)
|
||||
interface = -1
|
||||
if vid != -1 and pid != -1:
|
||||
portconfig = [[vid, pid, interface]]
|
||||
else:
|
||||
portconfig = default_ids
|
||||
if args["--debugmode"]:
|
||||
logfilename = "log.txt"
|
||||
if os.path.exists(logfilename):
|
||||
os.remove(logfilename)
|
||||
fh = logging.FileHandler(logfilename)
|
||||
self.__logger.addHandler(fh)
|
||||
self.__logger.setLevel(logging.DEBUG)
|
||||
else:
|
||||
self.__logger.setLevel(logging.INFO)
|
||||
|
||||
self.cdc = UsbClass(portconfig=portconfig, loglevel=self.__logger.level)
|
||||
self.sahara = sahara(self.cdc, loglevel=self.__logger.level)
|
||||
|
||||
if args["--loader"] == 'None':
|
||||
self.info("Trying with no loader given ...")
|
||||
self.sahara.programmer = ""
|
||||
else:
|
||||
loader = args["--loader"]
|
||||
self.info(f"Using loader {loader} ...")
|
||||
self.sahara.programmer = loader
|
||||
|
||||
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))
|
||||
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:
|
||||
if args["memorydump"]:
|
||||
time.sleep(0.5)
|
||||
print("Device is in memory dump mode, dumping memory")
|
||||
if args["--partitions"]:
|
||||
self.sahara.debug_mode(args["--partitions"].split(","))
|
||||
else:
|
||||
self.sahara.debug_mode()
|
||||
self.exit()
|
||||
else:
|
||||
print("Device is in streaming mode, uploading loader")
|
||||
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()
|
||||
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
|
||||
fh = firehose_client(args, self.cdc, self.sahara, self.__logger.level, print)
|
||||
cmd = parse_cmd(args)
|
||||
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":
|
||||
sc = streaming_client(args, self.cdc, self.sahara, self.__logger.level, print)
|
||||
cmd = parse_cmd(args)
|
||||
options = parse_option(args)
|
||||
if "load_" in mode:
|
||||
options["<mode>"] = 1
|
||||
else:
|
||||
options["<mode>"] = 0
|
||||
sc.handle_streaming(cmd, options)
|
||||
else:
|
||||
self.error("Sorry, couldn't talk to Sahara, please reboot the device !")
|
||||
|
||||
self.exit()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
base = main()
|
||||
base.run()
|
|
@ -3,7 +3,7 @@
|
|||
# (c) B.Kerler 2018-2021
|
||||
|
||||
import logging
|
||||
from edl.Library.utils import LogBase
|
||||
from edlclient.Library.utils import LogBase
|
||||
|
||||
|
||||
class generic(metaclass=LogBase):
|
|
@ -3,22 +3,22 @@
|
|||
# (c) B.Kerler 2018-2021
|
||||
|
||||
import logging
|
||||
from edl.Library.utils import LogBase
|
||||
from edlclient.Library.utils import LogBase
|
||||
|
||||
try:
|
||||
from edl.Library.Modules.generic import generic
|
||||
from edlclient.Library.Modules.generic import generic
|
||||
except ImportError as e:
|
||||
generic = None
|
||||
pass
|
||||
|
||||
try:
|
||||
from edl.Library.Modules.oneplus import oneplus
|
||||
from edlclient.Library.Modules.oneplus import oneplus
|
||||
except ImportError as e:
|
||||
oneplus = None
|
||||
pass
|
||||
|
||||
try:
|
||||
from edl.Library.Modules.xiaomi import xiaomi
|
||||
from edlclient.Library.Modules.xiaomi import xiaomi
|
||||
except ImportError as e:
|
||||
xiaomi = None
|
||||
pass
|
|
@ -19,10 +19,10 @@ import time
|
|||
import random
|
||||
from struct import pack
|
||||
import logging
|
||||
from edl.Library.utils import LogBase
|
||||
from edlclient.Library.utils import LogBase
|
||||
|
||||
try:
|
||||
from edl.Library.cryptutils import cryptutils
|
||||
from edlclient.Library.cryptutils import cryptutils
|
||||
except Exception as e:
|
||||
print(e)
|
||||
from ..cryptutils import cryptutils
|
||||
|
@ -75,6 +75,7 @@ deviceconfig = {
|
|||
|
||||
# OP Nord, avicii
|
||||
"20801": dict(version=2, cm="eacf50e7", param_mode=0),
|
||||
|
||||
# OP N10 5G Metro, billie8t
|
||||
"20885": dict(version=3, cm="3a403a71", param_mode=1),
|
||||
# OP N10 5G Global, billie8
|
||||
|
@ -153,7 +154,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):
|
|
@ -3,7 +3,7 @@
|
|||
# (c) B.Kerler 2018-2021
|
||||
|
||||
import logging
|
||||
from edl.Library.utils import LogBase
|
||||
from edlclient.Library.utils import LogBase
|
||||
|
||||
|
||||
class xiaomi(metaclass=LogBase):
|
|
@ -11,12 +11,12 @@ from struct import unpack
|
|||
from binascii import hexlify
|
||||
from queue import Queue
|
||||
from threading import Thread
|
||||
from edl.Library.utils import *
|
||||
from edl.Library.gpt import gpt
|
||||
from edl.Library.sparse import QCSparse
|
||||
from edlclient.Library.utils import *
|
||||
from edlclient.Library.gpt import gpt
|
||||
from edlclient.Library.sparse import QCSparse
|
||||
|
||||
try:
|
||||
from edl.Library.Modules.init import modules
|
||||
from edlclient.Library.Modules.init import modules
|
||||
except ImportError as e:
|
||||
pass
|
||||
|
||||
|
@ -174,23 +174,17 @@ class firehose(metaclass=LogBase):
|
|||
tdiff=t0-self.progtime
|
||||
datasize=(pos-self.progpos)/1024/1024
|
||||
throughput=(((datasize)/(tdiff)))
|
||||
max_pos_len = len(str(total // self.cfg.SECTOR_SIZE_IN_BYTES))
|
||||
print_progress(prog, 100,
|
||||
prefix='Progress:',
|
||||
suffix=prefix+' (Sector {} of {}) {:0.2f} MB/s'.format(
|
||||
'{0:>{1}d}'.format(pos // self.cfg.SECTOR_SIZE_IN_BYTES, max_pos_len),
|
||||
total // self.cfg.SECTOR_SIZE_IN_BYTES,
|
||||
throughput),
|
||||
bar_length=50)
|
||||
print_progress(prog, 100, prefix='Progress:',
|
||||
suffix=prefix+' (Sector %d of %d) %0.2f MB/s' %
|
||||
(pos // self.cfg.SECTOR_SIZE_IN_BYTES,
|
||||
total // self.cfg.SECTOR_SIZE_IN_BYTES,
|
||||
throughput), bar_length=50)
|
||||
self.prog = prog
|
||||
self.progpos = pos
|
||||
self.progtime = t0
|
||||
else:
|
||||
if display:
|
||||
print_progress(100, 100,
|
||||
prefix='Progress:',
|
||||
suffix=prefix+' Complete (Sector {0} of {0})'.format(total // self.cfg.SECTOR_SIZE_IN_BYTES),
|
||||
bar_length=50)
|
||||
print_progress(100, 100, prefix='Progress:', suffix='Complete', bar_length=50)
|
||||
except:
|
||||
pass
|
||||
|
|
@ -8,12 +8,12 @@ import logging
|
|||
import json
|
||||
from binascii import hexlify, unhexlify
|
||||
from struct import unpack, pack
|
||||
from edl.Library.firehose import firehose
|
||||
from edl.Library.xmlparser import xmlparser
|
||||
from edl.Library.utils import do_tcp_server
|
||||
from edl.Library.utils import LogBase, getint
|
||||
from edl.Config.qualcomm_config import memory_type
|
||||
from edl.Config.qualcomm_config import infotbl, msmids, secureboottbl, sochw
|
||||
from edlclient.Library.firehose import firehose
|
||||
from edlclient.Library.xmlparser import xmlparser
|
||||
from edlclient.Library.utils import do_tcp_server
|
||||
from edlclient.Library.utils import LogBase, getint
|
||||
from edlclient.Config.qualcomm_config import memory_type
|
||||
from edlclient.Config.qualcomm_config import infotbl, msmids, secureboottbl, sochw
|
||||
|
||||
try:
|
||||
import xml.etree.cElementTree as ET
|
||||
|
@ -23,7 +23,7 @@ except ImportError:
|
|||
from xml.etree import ElementTree
|
||||
|
||||
try:
|
||||
from edl.Library.Modules.init import modules
|
||||
from edlclient.Library.Modules.init import modules
|
||||
except ImportError as e:
|
||||
pass
|
||||
|
|
@ -10,7 +10,7 @@ from struct import unpack, pack
|
|||
from binascii import hexlify
|
||||
|
||||
try:
|
||||
from edl.Library.utils import LogBase, structhelper
|
||||
from edlclient.Library.utils import LogBase, structhelper
|
||||
except:
|
||||
from utils import LogBase, structhelper
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
# (c) B.Kerler 2018-2019
|
||||
import ctypes
|
||||
from enum import Enum
|
||||
from edl.Config.qualcomm_config import secgen, secureboottbl
|
||||
from edlclient.Config.qualcomm_config import secgen, secureboottbl
|
||||
|
||||
c_uint8 = ctypes.c_uint8
|
||||
|
|
@ -11,8 +11,8 @@ from struct import unpack, pack
|
|||
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 edl.Library.utils import read_object, print_progress, rmrf, LogBase
|
||||
from edl.Config.qualcomm_config import sochw, msmids, root_cert_hash
|
||||
from edlclient.Library.utils import read_object, print_progress, rmrf, LogBase
|
||||
from edlclient.Config.qualcomm_config import sochw, msmids, root_cert_hash
|
||||
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ from struct import unpack
|
|||
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 edl.Library.utils import LogBase, print_progress
|
||||
from edlclient.Library.utils import LogBase, print_progress
|
||||
|
||||
|
||||
class QCSparse(metaclass=LogBase):
|
|
@ -3,9 +3,9 @@
|
|||
# (c) B.Kerler 2018-2021
|
||||
from struct import pack
|
||||
from binascii import unhexlify
|
||||
from edl.Library.utils import *
|
||||
from edl.Library.hdlc import *
|
||||
from edl.Library.nand_config import BadFlags, SettingsOpt, nandregs, NandDevice
|
||||
from edlclient.Library.utils import *
|
||||
from edlclient.Library.hdlc import *
|
||||
from edlclient.Library.nand_config import BadFlags, SettingsOpt, nandregs, NandDevice
|
||||
|
||||
|
||||
class Streaming(metaclass=LogBase):
|
|
@ -6,8 +6,8 @@ import os
|
|||
import logging
|
||||
from binascii import hexlify, unhexlify
|
||||
from struct import unpack, pack
|
||||
from edl.Library.streaming import Streaming
|
||||
from edl.Library.utils import do_tcp_server, LogBase, getint
|
||||
from edlclient.Library.streaming import Streaming
|
||||
from edlclient.Library.utils import do_tcp_server, LogBase, getint
|
||||
|
||||
|
||||
class streaming_client(metaclass=LogBase):
|
|
@ -14,7 +14,7 @@ import usb.backend.libusb1
|
|||
from enum import Enum
|
||||
from binascii import hexlify
|
||||
from ctypes import c_void_p, c_int
|
||||
from edl.Library.utils import *
|
||||
from edlclient.Library.utils import *
|
||||
|
||||
USB_DIR_OUT = 0 # to device
|
||||
USB_DIR_IN = 0x80 # to host
|
||||
|
@ -102,7 +102,10 @@ class UsbClass(metaclass=LogBase):
|
|||
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'):
|
||||
self.backend = usb.backend.libusb1.get_backend(find_library=lambda x: "libusb-1.0.dll")
|
||||
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]
|
||||
|
@ -259,30 +262,26 @@ class UsbClass(metaclass=LogBase):
|
|||
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:
|
||||
if self.device is not None:
|
||||
self.configuration = self.device.get_active_configuration()
|
||||
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=vid, idProduct=pid, backend=self.backend)
|
||||
|
||||
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)
|
||||
try:
|
||||
if self.device.is_kernel_driver_active(interfacenum):
|
||||
self.debug("Detaching kernel driver")
|
||||
self.device.detach_kernel_driver(interfacenum)
|
||||
except Exception as err:
|
||||
self.debug("No kernel driver supported: " + str(err))
|
||||
|
||||
usb.util.claim_interface(self.device, interfacenum)
|
||||
if self.devclass != -1:
|
||||
if itf.bInterfaceClass == self.devclass: # MassStorage
|
||||
self.interface = interfacenum
|
||||
|
@ -295,20 +294,46 @@ class UsbClass(metaclass=LogBase):
|
|||
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:
|
||||
# match the first OUT endpoint
|
||||
self.EP_OUT = usb.util.find_descriptor(itf,
|
||||
custom_match=lambda em: usb.util.endpoint_direction(
|
||||
em.bEndpointAddress) == usb.util.ENDPOINT_OUT)
|
||||
# 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:
|
||||
# match the first OUT endpoint
|
||||
self.EP_IN = usb.util.find_descriptor(itf,
|
||||
custom_match=lambda em: usb.util.endpoint_direction(
|
||||
em.bEndpointAddress) == usb.util.ENDPOINT_IN)
|
||||
# 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
|
||||
|
||||
|
@ -321,17 +346,18 @@ class UsbClass(metaclass=LogBase):
|
|||
|
||||
def close(self, reset=False):
|
||||
if self.connected:
|
||||
usb.util.dispose_resources(self.device)
|
||||
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)
|
||||
if reset:
|
||||
self.device.reset()
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
self.debug(str(e))
|
||||
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
|
|
@ -2,7 +2,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# (c) B.Kerler 2018-2021
|
||||
import argparse
|
||||
from edl.Library.usblib import *
|
||||
from edlclient.Library.usblib import *
|
||||
|
||||
|
||||
def main():
|
43
edlclient/Tools/beagle_to_loader
Executable file
43
edlclient/Tools/beagle_to_loader
Executable file
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env python3
|
||||
# Beagle to EDL Loader (c) B.Kerler 2021
|
||||
|
||||
import os,sys
|
||||
from struct import unpack
|
||||
|
||||
def main():
|
||||
if len(sys.argv)<2:
|
||||
print("Usage: ./beagle_to_loader.py [beagle_log.bin] [loader.elf]")
|
||||
sys.exit(0)
|
||||
with open(sys.argv[1],"rb") as rf:
|
||||
data=rf.read()
|
||||
outdata=bytearray()
|
||||
i=0
|
||||
seq=b"\x03\x00\x00\x00\x14\x00\x00\x00\x0D\x00\x00\x00"
|
||||
with open(sys.argv[2], "wb") as wf:
|
||||
while True:
|
||||
idx=data.find(seq)
|
||||
if idx==-1:
|
||||
if i==0:
|
||||
seq=b"\x12\x00\x00\x00\x20\x00\x00\x00\x0D\x00\x00\x00\x00\x00\x00\x00"
|
||||
i+=1
|
||||
continue
|
||||
else:
|
||||
break
|
||||
else:
|
||||
cmd=unpack("<I", data[idx:idx+4])[0]
|
||||
if cmd==0x03:
|
||||
cmd,tlen,slen,offset,length=unpack("<IIIII",data[idx:idx+0x14])
|
||||
elif cmd==0x12:
|
||||
cmd, tlen, slen, offset, length = unpack("<IIQQQ", data[idx:idx + 0x20])
|
||||
data = data[idx + 0x14:]
|
||||
print("Offset : %08X Length: %08X" %(offset,length))
|
||||
while len(outdata)<offset+length:
|
||||
outdata.append(0xFF)
|
||||
outdata[offset:offset+length]=data[:length]
|
||||
i+=1
|
||||
wf.write(outdata)
|
||||
|
||||
print("Done.")
|
||||
|
||||
if __name__=="__main__":
|
||||
main()
|
282
edlclient/Tools/boottodwnload
Executable file
282
edlclient/Tools/boottodwnload
Executable file
|
@ -0,0 +1,282 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) B.Kerler 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 time
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
import argparse
|
||||
import requests
|
||||
from telnetlib import Telnet
|
||||
import usb.core
|
||||
from enum import Enum
|
||||
|
||||
import os, sys, inspect
|
||||
current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||
sys.path.insert(0, current_dir)
|
||||
|
||||
try:
|
||||
from edlclient.Tools.qc_diag import qcdiag
|
||||
except ImportError as e:
|
||||
print(current_dir)
|
||||
from qc_diag import qcdiag
|
||||
pass
|
||||
|
||||
try:
|
||||
from edlclient.Library.utils import LogBase
|
||||
except ImportError as e:
|
||||
from Library.utils import LogBase
|
||||
|
||||
|
||||
class vendor(Enum):
|
||||
sierra = 0x1199
|
||||
quectel = 0x2c7c
|
||||
zte = 0x19d2
|
||||
netgear = 0x0846
|
||||
telit = 0x413c
|
||||
|
||||
class deviceclass:
|
||||
vid=0
|
||||
pid=0
|
||||
def __init__(self,vid,pid):
|
||||
self.vid=vid
|
||||
self.pid=pid
|
||||
|
||||
|
||||
class connection(metaclass=LogBase):
|
||||
def __init__(self, port=""):
|
||||
self.serial = None
|
||||
self.tn = None
|
||||
self.connected = False
|
||||
if port == "":
|
||||
port = self.detect(port)
|
||||
if port == "":
|
||||
try:
|
||||
self.tn = Telnet("192.168.1.1", 5510, 5)
|
||||
self.connected = True
|
||||
except:
|
||||
self.connected = False
|
||||
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 waitforusb(self,vid,pid):
|
||||
timeout = 0
|
||||
while timeout < 10:
|
||||
for device in self.detectusbdevices():
|
||||
if device.vid == vid:
|
||||
if device.pid == pid:
|
||||
return True
|
||||
time.sleep(1)
|
||||
timeout += 1
|
||||
return False
|
||||
|
||||
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)
|
||||
return False
|
||||
|
||||
def getserialports(self):
|
||||
return [port for port in serial.tools.list_ports.comports()]
|
||||
|
||||
def detectusbdevices(self):
|
||||
dev = usb.core.find(find_all=True)
|
||||
ids=[deviceclass(cfg.idVendor,cfg.idProduct) for cfg in dev]
|
||||
return ids
|
||||
|
||||
def detect(self, port):
|
||||
vendortable={
|
||||
0x1199:["Sierra Wireless",3],
|
||||
0x2c7c:["Quectel",3],
|
||||
0x19d2:["ZTE",2],
|
||||
0x0846:["Netgear", 2],
|
||||
0x413c:["Telit",0]
|
||||
}
|
||||
mode="Unknown"
|
||||
for device in self.detectusbdevices():
|
||||
if device.vid==vendor.zte.value:
|
||||
if device.pid==0x0016:
|
||||
print(f"Detected a {vendortable[device.vid][0]} device with pid {hex(device.pid)} in Diag mode")
|
||||
mode="AT"
|
||||
break
|
||||
elif device.pid==0x1403:
|
||||
print(f"Detected a {vendortable[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=1' #adb
|
||||
url = 'http://192.168.0.1/goform/goform_process?goformId=MODE_SWITCH&switchCmd=FACTORY'
|
||||
if self.websend(url):
|
||||
mode="AT"
|
||||
break
|
||||
elif device.vid==vendor.telit.value:
|
||||
if device.pid==0x81d7:
|
||||
print(f"Detected a {vendortable[device.vid][0]} device with pid {hex(device.pid)} in Diag mode")
|
||||
print("Sending download mode command")
|
||||
interface = 5
|
||||
diag = qcdiag(loglevel=self.__logger.level, portconfig=[[0x413c, 0x81d7, interface]])
|
||||
if diag.connect():
|
||||
data=diag.hdlc.receive_reply()
|
||||
res = diag.send(b"\x4b\x65\x01\x00")
|
||||
if res[0]==0x4B:
|
||||
print("Sending download mode succeeded")
|
||||
diag.disconnect()
|
||||
break
|
||||
if mode=="AT" or mode=="Unknown":
|
||||
for port in self.getserialports():
|
||||
if port.vid in vendortable:
|
||||
portid = port.location[-1:]
|
||||
if int(portid) == vendortable[port.vid][1]:
|
||||
print(f"Detected a {vendortable[port.vid][0]} at interface at: " + port.device)
|
||||
return port.device
|
||||
return ""
|
||||
|
||||
def readreply(self):
|
||||
info = []
|
||||
timeout=0
|
||||
if self.serial is not None:
|
||||
while True:
|
||||
tmp = self.serial.readline().decode('utf-8').replace('\r', '').replace('\n', '')
|
||||
if "OK" in tmp:
|
||||
info.append(tmp)
|
||||
return info
|
||||
elif "ERROR" in tmp:
|
||||
return -1
|
||||
if tmp!="":
|
||||
info.append(tmp)
|
||||
else:
|
||||
timeout+=1
|
||||
if timeout==20:
|
||||
break
|
||||
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
|
||||
|
||||
def ati(self):
|
||||
data={}
|
||||
info = self.send("ATI")
|
||||
if info != -1:
|
||||
for line in info:
|
||||
if "Revision" in line:
|
||||
data["revision"] = line.split(":")[1].strip()
|
||||
if "Model" in line:
|
||||
data["model"] = line.split(":")[1].strip()
|
||||
if "Quectel" in line:
|
||||
data["vendor"] = "Quectel"
|
||||
if "Manufacturer" in line:
|
||||
data["manufacturer"]=line.split(":")[1].strip()
|
||||
if "Sierra Wireless" in data["manufacturer"]:
|
||||
data["vendor"]="Sierra Wireless"
|
||||
elif "ZTE CORPORATION" in data["manufacturer"]:
|
||||
data["vendor"]="ZTE"
|
||||
elif "Netgear" in data["manufacturer"]:
|
||||
data["vendor"]="Netgear"
|
||||
elif "Telit" in data["manufacturer"]:
|
||||
data["vendor"]="Telit"
|
||||
return data
|
||||
|
||||
class dwnloadtools(metaclass=LogBase):
|
||||
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
|
||||
cn = connection(port)
|
||||
if cn.connected:
|
||||
info=cn.ati()
|
||||
if "vendor" in info:
|
||||
if info["vendor"]=="Sierra Wireless" or info["vendor"]=="Netgear":
|
||||
print("Sending download mode command")
|
||||
print(cn.send("AT!BOOTHOLD\r"))
|
||||
print(cn.send('AT!QPSTDLOAD\r'))
|
||||
print("Done switching to download mode")
|
||||
elif info["vendor"]=="Quectel":
|
||||
print("Sending download mode command")
|
||||
interface=0
|
||||
diag = qcdiag(loglevel=self.__logger.level, portconfig=[[0x2c7c,0x0125,interface]])
|
||||
if diag.connect():
|
||||
diag.hdlc.receive_reply()
|
||||
res = diag.send(b"\x4b\x65\x01\x00")
|
||||
diag.disconnect()
|
||||
print("Done switching to download mode")
|
||||
elif info["vendor"]=="Telit":
|
||||
print("Sending download mode command")
|
||||
interface=0
|
||||
diag = qcdiag(loglevel=self.__logger.level, portconfig=[[0x2c7c,0x0125,interface]])
|
||||
if diag.connect():
|
||||
diag.hdlc.receive_reply()
|
||||
res = diag.send(b"\x4b\x65\x01\x00")
|
||||
diag.disconnect()
|
||||
print("Done switching to download mode")
|
||||
elif info["vendor"]=="ZTE":
|
||||
print("Sending download mode command")
|
||||
interface=0
|
||||
diag = qcdiag(loglevel=self.__logger.level, portconfig=[[0x19d2,0x0016, interface]])
|
||||
if diag.connect():
|
||||
diag.hdlc.receive_reply()
|
||||
res = diag.send(b"\x4b\x65\x01\x00")
|
||||
if res[0]==0x4B:
|
||||
print("Done switching to ENANDPRG mode")
|
||||
else:
|
||||
res = diag.send(b"\x3a")
|
||||
if res[0]==0x3A:
|
||||
while True:
|
||||
state=cn.waitforusb(vendor.zte.value,0x0076)
|
||||
if not state:
|
||||
diag.disconnect()
|
||||
if diag.connect():
|
||||
res = diag.send(b"\x3a")
|
||||
else:
|
||||
break
|
||||
if state:
|
||||
print("Done switching to NANDPRG mode")
|
||||
else:
|
||||
print("Failed switching to download mode")
|
||||
diag.disconnect()
|
||||
cn.close()
|
||||
|
||||
def main():
|
||||
version = "1.1"
|
||||
info = 'Modem Gimme-EDL ' + version + ' (c) B. Kerler 2020-2021'
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,description=info)
|
||||
parser.add_argument(
|
||||
'-port', '-p',
|
||||
help='use com port for auto unlock',
|
||||
default="")
|
||||
parser.add_argument(
|
||||
'-logfile', '-l',
|
||||
help='use logfile for debug log',
|
||||
default="")
|
||||
args = parser.parse_args()
|
||||
dw=dwnloadtools()
|
||||
dw.run(args)
|
||||
|
||||
if __name__=="__main__":
|
||||
main()
|
347
edlclient/Tools/enableadb
Executable file
347
edlclient/Tools/enableadb
Executable file
|
@ -0,0 +1,347 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) B.Kerler 2020-2021 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 time
|
||||
from telnetlib import Telnet
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
import argparse
|
||||
import requests
|
||||
import hashlib
|
||||
|
||||
|
||||
try:
|
||||
from edlclient.Tools.qc_diag import qcdiag
|
||||
except ImportError as e:
|
||||
pass
|
||||
|
||||
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
|
||||
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
|
||||
zte = 0x19d2
|
||||
telit = 0x413c
|
||||
netgear = 0x0846
|
||||
|
||||
class deviceclass:
|
||||
vid=0
|
||||
pid=0
|
||||
def __init__(self,vid,pid):
|
||||
self.vid=vid
|
||||
self.pid=pid
|
||||
|
||||
class connection:
|
||||
def __init__(self, port=""):
|
||||
self.serial = None
|
||||
self.tn = None
|
||||
self.connected = False
|
||||
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
|
||||
|
||||
def waitforusb(self,vid,pid):
|
||||
timeout = 0
|
||||
while timeout < 10:
|
||||
for device in self.detectusbdevices():
|
||||
if device.vid == vid:
|
||||
if device.pid == pid:
|
||||
return True
|
||||
time.sleep(1)
|
||||
timeout += 1
|
||||
return False
|
||||
|
||||
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)
|
||||
return False
|
||||
|
||||
def getserialports(self):
|
||||
return [port for port in serial.tools.list_ports.comports()]
|
||||
|
||||
def detectusbdevices(self):
|
||||
dev = usb.core.find(find_all=True)
|
||||
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]
|
||||
}
|
||||
mode="Unknown"
|
||||
for device in self.detectusbdevices():
|
||||
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"
|
||||
break
|
||||
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.")
|
||||
break
|
||||
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":
|
||||
for port in self.getserialports():
|
||||
if port.vid in atvendortable:
|
||||
portid = port.location[-1:]
|
||||
if int(portid) == atvendortable[port.vid][1]:
|
||||
print(f"Detected a {atvendortable[port.vid][0]} at interface at: " + port.device)
|
||||
return port.device
|
||||
return ""
|
||||
|
||||
def readreply(self):
|
||||
info = []
|
||||
timeout=0
|
||||
if self.serial is not None:
|
||||
while True:
|
||||
tmp = self.serial.readline().decode('utf-8').replace('\r', '').replace('\n', '')
|
||||
if "OK" in tmp:
|
||||
info.append(tmp)
|
||||
return info
|
||||
elif "ERROR" in tmp:
|
||||
return -1
|
||||
if tmp!="":
|
||||
info.append(tmp)
|
||||
else:
|
||||
timeout+=1
|
||||
if timeout==20:
|
||||
break
|
||||
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
|
||||
if "ERROR" in data:
|
||||
return -1
|
||||
return data.split("\r\n")
|
||||
elif self.serial is not None:
|
||||
self.serial.write(bytes(cmd + "\r", 'utf-8'))
|
||||
time.sleep(0.05)
|
||||
resp=self.readreply()
|
||||
return resp
|
||||
|
||||
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
|
||||
|
||||
def ati(self):
|
||||
data={}
|
||||
info = self.send("ATI")
|
||||
if info != -1:
|
||||
for line in info:
|
||||
if "Revision" in line:
|
||||
data["revision"] = line.split(":")[1].strip()
|
||||
if "Model" in line:
|
||||
data["model"] = line.split(":")[1].strip()
|
||||
if "Quectel" in line:
|
||||
data["vendor"] = "Quectel"
|
||||
if "Manufacturer" in line:
|
||||
data["manufacturer"]=line.split(":")[1].strip()
|
||||
if "Sierra Wireless" in data["manufacturer"]:
|
||||
data["vendor"]="Sierra Wireless"
|
||||
elif "ZTE CORPORATION" in data["manufacturer"]:
|
||||
data["vendor"]="ZTE"
|
||||
elif "SIMCOM INCORPORATED" in data["manufacturer"]:
|
||||
data["vendor"]="Simcom"
|
||||
elif "Alcatel" in data["manufacturer"]:
|
||||
data["vendor"]="Alcatel"
|
||||
elif "Netgear" in data["manufacturer"]:
|
||||
data["vendor"]="Netgear"
|
||||
elif "SAMSUNG" in data["manufacturer"]:
|
||||
data["vendor"]="Samsung"
|
||||
info = self.send("AT+CGMI")
|
||||
if info!=-1:
|
||||
for line in info:
|
||||
if "Quectel" in line:
|
||||
data["vendor"] = "Quectel"
|
||||
break
|
||||
elif "Fibucom" in line:
|
||||
data["vendor"]="Fibucom"
|
||||
break
|
||||
elif "Netgear" in line:
|
||||
data["vendor"]="Netgear"
|
||||
break
|
||||
elif "SAMSUNG" in line:
|
||||
data["vendor"]="Samsung"
|
||||
break
|
||||
info = self.send("AT+CGMR")
|
||||
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")
|
||||
time.sleep(0.05)
|
||||
return tn.read_eager().strip().decode('utf-8')
|
||||
|
||||
def run(self, args):
|
||||
port = args.port
|
||||
cn = connection(port)
|
||||
if cn.connected:
|
||||
info=cn.ati()
|
||||
if "vendor" in info:
|
||||
if info["vendor"]=="Sierra Wireless" or info["vendor"]=="Netgear":
|
||||
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":
|
||||
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")
|
||||
|
||||
cn.close()
|
||||
|
||||
def main():
|
||||
version = "1.1"
|
||||
info = 'Modem Gimme-ADB ' + version + ' (c) B. Kerler 2020-2021'
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, description=info)
|
||||
parser.add_argument(
|
||||
'-port', '-p',
|
||||
help='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)
|
||||
|
||||
if __name__=="__main__":
|
||||
main()
|
||||
|
411
edlclient/Tools/fhloaderparse
Executable file
411
edlclient/Tools/fhloaderparse
Executable file
|
@ -0,0 +1,411 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
from os import walk
|
||||
import hashlib
|
||||
from struct import unpack, pack
|
||||
from shutil import copyfile
|
||||
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 elf
|
||||
from edlclient.Library.sahara import convertmsmid
|
||||
from edlclient.Config.qualcomm_config import vendor
|
||||
|
||||
class MBN:
|
||||
def __init__(self, memory):
|
||||
self.imageid, self.flashpartitionversion, self.imagesrc, self.loadaddr, self.imagesz, self.codesz, \
|
||||
self.sigptr, self.sigsz, self.certptr, self.certsz = unpack("<IIIIIIIIII", memory[0xC:0xC + 40])
|
||||
|
||||
|
||||
class Signed:
|
||||
filename = ''
|
||||
filesize = 0
|
||||
oem_id = ''
|
||||
model_id = ''
|
||||
hw_id = ''
|
||||
sw_id = ''
|
||||
app_id = ''
|
||||
sw_size = ''
|
||||
qc_version = ''
|
||||
image_variant = ''
|
||||
oem_version = ''
|
||||
pk_hash = ''
|
||||
hash = b''
|
||||
|
||||
|
||||
def grabtext(data):
|
||||
i = len(data)
|
||||
j = 0
|
||||
text = ''
|
||||
while i > 0:
|
||||
if data[j] == 0:
|
||||
break
|
||||
text += chr(data[j])
|
||||
j += 1
|
||||
i -= 1
|
||||
return text
|
||||
|
||||
|
||||
def extract_hdr(memsection, sign_info, mem_section, code_size, signature_size):
|
||||
try:
|
||||
md_size = \
|
||||
unpack("<I", mem_section[memsection.file_start_addr + 0x2C:memsection.file_start_addr + 0x2C + 0x4])[0]
|
||||
md_offset = memsection.file_start_addr + 0x2C + 0x4
|
||||
major, minor, sw_id, hw_id, oem_id, model_id, app_id = unpack("<IIIIIII",
|
||||
mem_section[md_offset:md_offset + (7 * 4)])
|
||||
sign_info.hw_id = "%08X" % hw_id
|
||||
sign_info.sw_id = "%08X" % sw_id
|
||||
sign_info.oem_id = "%04X" % oem_id
|
||||
|
||||
sign_info.model_id = "%04X" % model_id
|
||||
sign_info.hw_id += sign_info.oem_id + sign_info.model_id
|
||||
sign_info.app_id = "%08X" % app_id
|
||||
md_offset += (7 * 4)
|
||||
|
||||
# v=unpack("<I", mem_section[md_offset:md_offset + 4])[0]
|
||||
'''
|
||||
rot_en=(v >> 0) & 1
|
||||
in_use_soc_hw_version=(v >> 1) & 1
|
||||
use_serial_number_in_signing=(v >> 2) & 1
|
||||
oem_id_independent=(v >> 3) & 1
|
||||
root_revoke_activate_enable=(v >> 4) & 0b11
|
||||
uie_key_switch_enable=(v >> 6) & 0b11
|
||||
debug=(v >> 8) & 0b11
|
||||
md_offset+=4
|
||||
soc_vers=hexlify(mm[md_offset:md_offset + (12*4)])
|
||||
md_offset+=12*4
|
||||
multi_serial_numbers=hexlify(mm[md_offset:md_offset + (8*4)])
|
||||
md_offset += 8 * 4
|
||||
mrc_index=unpack("<I", mm[md_offset:md_offset + 4])[0]
|
||||
md_offset+=4
|
||||
anti_rollback_version=unpack("<I", mm[md_offset:md_offset + 4])[0]
|
||||
'''
|
||||
|
||||
signatureoffset = memsection.file_start_addr + 0x30 + md_size + code_size + signature_size
|
||||
try:
|
||||
if mem_section[signatureoffset] != 0x30:
|
||||
print("Error on " + sign_info.filename + ", unknown signaturelength")
|
||||
return None
|
||||
except:
|
||||
return None
|
||||
if len(mem_section) < signatureoffset + 4:
|
||||
print("Signature error on " + sign_info.filename)
|
||||
return None
|
||||
len1 = unpack(">H", mem_section[signatureoffset + 2:signatureoffset + 4])[0] + 4
|
||||
casignature2offset = signatureoffset + len1
|
||||
len2 = unpack(">H", mem_section[casignature2offset + 2:casignature2offset + 4])[0] + 4
|
||||
rootsignature3offset = casignature2offset + len2
|
||||
len3 = unpack(">H", mem_section[rootsignature3offset + 2:rootsignature3offset + 4])[0] + 4
|
||||
sign_info.pk_hash = hashlib.sha384(mem_section[rootsignature3offset:rootsignature3offset + len3]).hexdigest()
|
||||
except:
|
||||
return None
|
||||
return sign_info
|
||||
|
||||
|
||||
def extract_old_hdr(signatureoffset, sign_info, mem_section, code_size, signature_size):
|
||||
signature = {}
|
||||
if mem_section[signatureoffset] != 0x30:
|
||||
print("Error on " + sign_info.filename + ", unknown signaturelength")
|
||||
return None
|
||||
if signatureoffset != -1:
|
||||
if len(mem_section) < signatureoffset + 4:
|
||||
print("Signature error on " + sign_info.filename)
|
||||
return None
|
||||
len1 = unpack(">H", mem_section[signatureoffset + 2:signatureoffset + 4])[0] + 4
|
||||
casignature2offset = signatureoffset + len1
|
||||
len2 = unpack(">H", mem_section[casignature2offset + 2:casignature2offset + 4])[0] + 4
|
||||
rootsignature3offset = casignature2offset + len2
|
||||
len3 = unpack(">H", mem_section[rootsignature3offset + 2:rootsignature3offset + 4])[0] + 4
|
||||
sign_info.pk_hash = hashlib.sha256(mem_section[rootsignature3offset:rootsignature3offset + len3]).hexdigest()
|
||||
idx = signatureoffset
|
||||
|
||||
while idx != -1:
|
||||
if idx >= len(mem_section):
|
||||
break
|
||||
idx = mem_section.find('\x04\x0B'.encode(), idx)
|
||||
if idx == -1:
|
||||
break
|
||||
length = mem_section[idx + 3]
|
||||
if length > 60:
|
||||
idx += 1
|
||||
continue
|
||||
try:
|
||||
text = mem_section[idx + 4:idx + 4 + length].decode().split(' ')
|
||||
signature[text[2]] = text[1]
|
||||
except:
|
||||
text = ""
|
||||
idx += 1
|
||||
idx = mem_section.find('QC_IMAGE_VERSION_STRING='.encode(), 0)
|
||||
if idx != -1:
|
||||
sign_info.qc_version = grabtext(mem_section[idx + len("QC_IMAGE_VERSION_STRING="):])
|
||||
idx = mem_section.find('OEM_IMAGE_VERSION_STRING='.encode(), 0)
|
||||
if idx != -1:
|
||||
sign_info.oem_version = grabtext(mem_section[idx + len("OEM_IMAGE_VERSION_STRING="):])
|
||||
idx = mem_section.find('IMAGE_VARIANT_STRING='.encode(), 0)
|
||||
if idx != -1:
|
||||
sign_info.image_variant = grabtext(mem_section[idx + len("IMAGE_VARIANT_STRING="):])
|
||||
if "MODEL_ID" in signature:
|
||||
sign_info.model_id = signature["MODEL_ID"]
|
||||
if "OEM_ID" in signature:
|
||||
sign_info.oem_id = signature["OEM_ID"]
|
||||
if "HW_ID" in signature:
|
||||
sign_info.hw_id = signature["HW_ID"]
|
||||
if "SW_ID" in signature:
|
||||
sign_info.sw_id = signature["SW_ID"]
|
||||
if "SW_SIZE" in signature:
|
||||
sign_info.sw_size = signature["SW_SIZE"]
|
||||
return sign_info
|
||||
|
||||
|
||||
def init_loader_db():
|
||||
loaderdb = {}
|
||||
for (dirpath, dirnames, filenames) in os.walk(current_dir):
|
||||
for filename in filenames:
|
||||
file_name = 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()
|
||||
msmdb = convertmsmid(msmid)
|
||||
for msmid in msmdb:
|
||||
mhwid = (msmid + devid).lower()
|
||||
if mhwid not in loaderdb:
|
||||
loaderdb[mhwid] = {}
|
||||
if pkhash not in loaderdb[mhwid]:
|
||||
loaderdb[mhwid][pkhash] = file_name
|
||||
else:
|
||||
loaderdb[mhwid][pkhash].append(file_name)
|
||||
except:
|
||||
continue
|
||||
return loaderdb
|
||||
|
||||
|
||||
def is_duplicate(loaderdb, sign_info):
|
||||
lhash = sign_info.pk_hash[:16].lower()
|
||||
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):
|
||||
rid = (msmid + devid).lower()
|
||||
if hwid in loaderdb:
|
||||
loader = loaderdb[hwid]
|
||||
if lhash in loader:
|
||||
return True
|
||||
if rid in loaderdb:
|
||||
loader = loaderdb[rid]
|
||||
if lhash in loader:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def main(argv):
|
||||
file_list = []
|
||||
path = ""
|
||||
if len(argv) < 3:
|
||||
print("Usage: fhloaderparse [FHLoaderDir] [OutputDir]")
|
||||
exit(0)
|
||||
else:
|
||||
path = argv[1]
|
||||
outputdir = argv[2]
|
||||
if not os.path.exists(outputdir):
|
||||
os.mkdir(outputdir)
|
||||
|
||||
# First hash all loaders in Loader directory
|
||||
hashes = {}
|
||||
loaderdb = init_loader_db()
|
||||
for mhwid in loaderdb:
|
||||
for pkhash in loaderdb[mhwid]:
|
||||
fname = loaderdb[mhwid][pkhash]
|
||||
with open(fname, 'rb') as rhandle:
|
||||
data = rhandle.read()
|
||||
sha256 = hashlib.sha256()
|
||||
sha256.update(data)
|
||||
hashes[sha256.digest()] = fname
|
||||
|
||||
# Now lets hash all files in the output directory
|
||||
for (dirpath, dirnames, filenames) in walk(outputdir):
|
||||
for filename in filenames:
|
||||
fname = os.path.join(dirpath, filename)
|
||||
with open(fname, 'rb') as rhandle:
|
||||
data = rhandle.read()
|
||||
sha256 = hashlib.sha256()
|
||||
sha256.update(data)
|
||||
hashes[sha256.digest()] = fname
|
||||
|
||||
# Now lets search the input path for loaders
|
||||
extensions = ["txt", "idb", "i64", "py"]
|
||||
for (dirpath, dirnames, filenames) in walk(path):
|
||||
for filename in filenames:
|
||||
basename = os.path.basename(filename).lower()
|
||||
ext = basename[basename.rfind(".") + 1:]
|
||||
if ext not in extensions:
|
||||
file_list.append(os.path.join(dirpath, filename))
|
||||
|
||||
if not os.path.exists(os.path.join(outputdir, "Unknown")):
|
||||
os.makedirs(os.path.join(outputdir, "Unknown"))
|
||||
if not os.path.exists(os.path.join(outputdir, "Duplicate")):
|
||||
os.mkdir(os.path.join(outputdir, "Duplicate"))
|
||||
|
||||
# Lets hash all the input files and extract the signature
|
||||
filelist = []
|
||||
rt = open(os.path.join(outputdir, argv[1] + ".log"), "w")
|
||||
for filename in file_list:
|
||||
with open(filename, 'rb') as rhandle:
|
||||
mem_section = rhandle.read()
|
||||
sha256 = hashlib.sha256()
|
||||
sha256.update(mem_section)
|
||||
|
||||
signinfo = Signed()
|
||||
signinfo.hash = sha256.digest()
|
||||
signinfo.filename = filename
|
||||
signinfo.filesize = os.stat(filename).st_size
|
||||
if len(mem_section) < 4:
|
||||
continue
|
||||
hdr = unpack("<I", mem_section[0:4])[0]
|
||||
|
||||
if hdr&0xFFFFFF == 0x4C457F:
|
||||
elfheader = elf(mem_section, signinfo.filename)
|
||||
if 'memorylayout' in dir(elfheader):
|
||||
memsection = elfheader.memorylayout[1]
|
||||
try:
|
||||
version = unpack("<I", mem_section[
|
||||
memsection.file_start_addr + 0x04:memsection.file_start_addr + 0x04 + 0x4])[
|
||||
0]
|
||||
code_size = \
|
||||
unpack("<I", mem_section[
|
||||
memsection.file_start_addr + 0x14:memsection.file_start_addr + 0x14 + 0x4])[
|
||||
0]
|
||||
signature_size = \
|
||||
unpack("<I", mem_section[
|
||||
memsection.file_start_addr + 0x1C:memsection.file_start_addr + 0x1C + 0x4])[
|
||||
0]
|
||||
# cert_chain_size=unpack("<I", mem_section[memsection.file_start_addr + 0x24:memsection.file_start_addr + 0x24 + 0x4])[0]
|
||||
except:
|
||||
continue
|
||||
if signature_size == 0:
|
||||
print("%s has no signature." % filename)
|
||||
copyfile(filename,
|
||||
os.path.join(outputdir, "Unknown", filename[filename.rfind("/") + 1:].lower()))
|
||||
continue
|
||||
if version < 6: # MSM,MDM
|
||||
signatureoffset = memsection.file_start_addr + 0x28 + code_size + signature_size
|
||||
signinfo = extract_old_hdr(signatureoffset, signinfo, mem_section, code_size, signature_size)
|
||||
if signinfo is None:
|
||||
continue
|
||||
filelist.append(signinfo)
|
||||
elif version >= 6: # SDM
|
||||
signinfo = extract_hdr(memsection, signinfo, mem_section, code_size, signature_size)
|
||||
if signinfo is None:
|
||||
continue
|
||||
filelist.append(signinfo)
|
||||
else:
|
||||
print("Unknown version for " + filename)
|
||||
continue
|
||||
elif hdr == 0x844BDCD1:
|
||||
mbn = MBN(mem_section)
|
||||
if mbn.sigsz == 0:
|
||||
print("%s has no signature." % filename)
|
||||
copyfile(filename, os.path.join(outputdir, "Unknown", filename[filename.rfind("/") + 1:].lower()))
|
||||
continue
|
||||
signatureoffset = mbn.imagesrc + mbn.codesz + mbn.sigsz
|
||||
signinfo = extract_old_hdr(signatureoffset, signinfo, mem_section, mbn.codesz, mbn.sigsz)
|
||||
if signinfo is None:
|
||||
continue
|
||||
filelist.append(signinfo)
|
||||
else:
|
||||
print("Error on " + filename)
|
||||
continue
|
||||
|
||||
sorted_x = sorted(filelist, key=lambda x: (x.hw_id, -x.filesize))
|
||||
|
||||
class loaderinfo:
|
||||
hw_id = ''
|
||||
item = ''
|
||||
|
||||
loaderlists = {}
|
||||
for item in sorted_x:
|
||||
if item.oem_id != '':
|
||||
oemid=int(item.oem_id,16)
|
||||
if oemid in vendor:
|
||||
oeminfo = vendor[oemid]
|
||||
else:
|
||||
oeminfo=item.oem_id
|
||||
if len(item.sw_id)<16:
|
||||
item.sw_id="0"*(16-len(item.sw_id))+item.sw_id
|
||||
info = f"OEM:{oeminfo}\tMODEL:{item.model_id}\tHWID:{item.hw_id}\tSWID:{item.sw_id}\tSWSIZE:{item.sw_size}\tPK_HASH:{item.pk_hash}\t{item.filename}\t{str(item.filesize)}"
|
||||
if item.oem_version != '':
|
||||
info += "\tOEMVER:" + item.oem_version + "\tQCVER:" + item.qc_version + "\tVAR:" + item.image_variant
|
||||
loader_info = loaderinfo()
|
||||
loader_info.hw_id = item.hw_id
|
||||
loader_info.pk_hash = item.pk_hash
|
||||
if item.hash not in hashes:
|
||||
if loader_info not in loaderlists:
|
||||
if not is_duplicate(loaderdb, item):
|
||||
loaderlists[loader_info] = item.filename
|
||||
print(info)
|
||||
msmid = loader_info.hw_id[:8]
|
||||
devid = loader_info.hw_id[8:]
|
||||
for msmid in convertmsmid(msmid):
|
||||
hwid = (msmid + devid).lower()
|
||||
auth = ""
|
||||
with open(item.filename, "rb") as rf:
|
||||
data = rf.read()
|
||||
if b"sig tag can" in data:
|
||||
auth = "_EDLAuth"
|
||||
if b"peek\x00" in data:
|
||||
auth += "_peek"
|
||||
fna = os.path.join(outputdir, (
|
||||
hwid + "_" + loader_info.pk_hash[0:16] + "_FHPRG" + auth + ".bin").lower())
|
||||
if not os.path.exists(fna):
|
||||
copyfile(item.filename,
|
||||
os.path.join(outputdir, hwid + "_" + (
|
||||
loader_info.pk_hash[0:16] + "_FHPRG" + auth + ".bin").lower()))
|
||||
elif item.filesize > os.stat(fna).st_size:
|
||||
copyfile(item.filename, os.path.join(outputdir,
|
||||
(hwid + "_" + loader_info.pk_hash[
|
||||
0:16] + "_FHPRG" + auth + ".bin").lower()))
|
||||
else:
|
||||
print("Duplicate: " + info)
|
||||
copyfile(item.filename, os.path.join(outputdir, "Duplicate",
|
||||
(loader_info.hw_id + "_" + loader_info.pk_hash[
|
||||
0:16] + "_FHPRG.bin").lower()))
|
||||
else:
|
||||
copyfile(item.filename, os.path.join(outputdir, "Unknown", os.path.basename(item.filename).lower()))
|
||||
else:
|
||||
copyfile(item.filename,
|
||||
os.path.join(outputdir, "Duplicate",
|
||||
(loader_info.hw_id + "_" + loader_info.pk_hash[0:16] + "_FHPRG.bin").lower()))
|
||||
print(item.filename + " does already exist. Skipping")
|
||||
try:
|
||||
rt.write(info + "\n")
|
||||
except:
|
||||
continue
|
||||
else:
|
||||
print("Unknown :"+item.filename)
|
||||
copyfile(item.filename, os.path.join(outputdir, "Unknown", os.path.basename(item.filename).lower()))
|
||||
|
||||
for item in filelist:
|
||||
if item.oem_id == '' and (".bin" in item.filename or ".mbn" in item.filename or ".hex" in item.filename):
|
||||
info = "Unsigned:" + item.filename + "\t" + str(item.filesize)
|
||||
if item.oem_version != '':
|
||||
info += "\tOEMVER:" + item.oem_version + "\tQCVER:" + item.qc_version + "\tVAR:" + item.image_variant
|
||||
print(info)
|
||||
rt.write(info + "\n")
|
||||
if not os.path.exists(os.path.join(outputdir, "Unknown", item.filename)):
|
||||
copyfile(item.filename,
|
||||
os.path.join(outputdir, "Unknown", os.path.basename(item.filename).lower()))
|
||||
|
||||
rt.close()
|
||||
|
||||
|
||||
main(sys.argv)
|
1
edlclient/Tools/qc_diag
Symbolic link
1
edlclient/Tools/qc_diag
Symbolic link
|
@ -0,0 +1 @@
|
|||
qc_diag.py
|
1329
edlclient/Tools/qc_diag.py
Executable file
1329
edlclient/Tools/qc_diag.py
Executable file
File diff suppressed because it is too large
Load diff
1
edlclient/Tools/sierrakeygen
Symbolic link
1
edlclient/Tools/sierrakeygen
Symbolic link
|
@ -0,0 +1 @@
|
|||
sierrakeygen.py
|
634
edlclient/Tools/sierrakeygen.py
Executable file
634
edlclient/Tools/sierrakeygen.py
Executable file
|
@ -0,0 +1,634 @@
|
|||
#!/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"]
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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:
|
||||
for i in range(0, clen - len(challenge)):
|
||||
challenge.append(0)
|
||||
|
||||
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, key, challengelen, 16)[:challengelen]
|
||||
resp = hexlify(resp).decode('utf-8').upper()
|
||||
return resp
|
||||
|
||||
def selftest(self):
|
||||
challenge = "8101A18AB3C3E66A" # Verified, EM7305
|
||||
devicegeneration = "MDM9x15" # MSM9200
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != 'D1E128FCA8A963ED':
|
||||
return False
|
||||
|
||||
challenge = "BE96CBBEE0829BCA" # Verified
|
||||
devicegeneration = "MDM9x40"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != '1033773720F6EE66':
|
||||
return False
|
||||
|
||||
devicegeneration = "MDM9x30"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != '1E02CE6A98B7DD2A':
|
||||
return False
|
||||
|
||||
devicegeneration = "MDM9x50"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != '32AB617DB4B1C205':
|
||||
return False
|
||||
|
||||
devicegeneration = "MDM9x06"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != '28D718CCD669DEDE':
|
||||
return False
|
||||
|
||||
devicegeneration = "MDM9x07"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != 'F5A4C9A0D402E34E':
|
||||
return False
|
||||
|
||||
devicegeneration = "MDM8200"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != 'EE702212D9C12FAB':
|
||||
return False
|
||||
|
||||
devicegeneration = "MDM9200_V1"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != 'A9A4E76E2653F753':
|
||||
return False
|
||||
|
||||
devicegeneration = "MDM9200_V2"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != '8B0FAB4B6F81B080':
|
||||
return False
|
||||
|
||||
devicegeneration = "MDM9200_V3"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != '4A69AD8A69F390E0':
|
||||
return False
|
||||
|
||||
devicegeneration = "MDM9x30_V1"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != '6A5E4C9CBCBDA7DC':
|
||||
return False
|
||||
|
||||
challenge = "BE96CBBEE0829BCA" # Verified
|
||||
devicegeneration = "MDM9200"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != 'EEDBF8BFF8DAE346':
|
||||
return False
|
||||
|
||||
challenge = "20E253156762DACE" # Verified
|
||||
devicegeneration = "SDX55"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != '03940D7067145323':
|
||||
return False
|
||||
|
||||
challenge = "2387885E7D290FEE" # Verified
|
||||
devicegeneration = "MDM9x15A"
|
||||
openlock = self.run(devicegeneration, challenge, 0)
|
||||
if openlock != '676E10308BF05EE3':
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
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 keylen >= 1 and keylen <= 0x20:
|
||||
for i in range(0, 0x100):
|
||||
self.tbl[i] = i & 0xFF
|
||||
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):
|
||||
for i in range(0, 0x100):
|
||||
self.tbl[i] = 0
|
||||
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, key, challengelen, keylen):
|
||||
resultbuffer = bytearray()
|
||||
for i in range(0, 0x100 + 1):
|
||||
resultbuffer.append(0x0)
|
||||
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()
|
||||
print("Running self-test ...")
|
||||
if self.keygen.selftest():
|
||||
print("PASSED!")
|
||||
else:
|
||||
print("FAILED!")
|
||||
if devicegeneration==None:
|
||||
self.detectdevicegeneration()
|
||||
else:
|
||||
self.devicegeneration=devicegeneration
|
||||
|
||||
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
|
||||
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:
|
||||
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:
|
||||
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.3"
|
||||
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')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
openlock = args.openlock
|
||||
openmep = args.openmep
|
||||
opencnd = args.opencnd
|
||||
devicegeneration = args.devicegeneration
|
||||
|
||||
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("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.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)
|
BIN
edlclient/Windows/libusb32-1.0.dll
Normal file
BIN
edlclient/Windows/libusb32-1.0.dll
Normal file
Binary file not shown.
6
setup.py
6
setup.py
|
@ -3,11 +3,11 @@ from setuptools import setup, find_packages
|
|||
import os
|
||||
|
||||
setup(
|
||||
name='edl',
|
||||
version='3.5',
|
||||
name='edlclient',
|
||||
version='3.53',
|
||||
packages=find_packages(),
|
||||
long_description=open("README.md").read(),
|
||||
scripts=['edl.py','diag.py','modem/sierrakeygen.py','modem/boottodwnload.py','modem/enableadb.py','Loaders/fhloaderparse.py','Loaders/beagle_to_loader.py'],
|
||||
scripts=['edl','edlclient/Tools/qc_diag','edlclient/Tools/sierrakeygen','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',
|
||||
|
|
344
sierrakeygen_README.md
Executable file
344
sierrakeygen_README.md
Executable file
|
@ -0,0 +1,344 @@
|
|||
# Challenge/Response Generator for Sierra Wireless Cards V1.2
|
||||
(c) B. Kerler 2019-2020
|
||||
MIT License
|
||||
|
||||
## Why
|
||||
|
||||
- For enabling development mode and tests
|
||||
- For setting band options if locked
|
||||
|
||||
## Supported devices
|
||||
"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"],
|
||||
"MDM9200_V1": ["AC710", "MC8775", "MC8775V", "AC875", "MC8700", "AC313U", "MC8801", "MC7700", "MC7750",
|
||||
"MC7710", "EM7700"],
|
||||
"MDM9200_V2": ["AC775", "PC7200"],
|
||||
"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"],
|
||||
"MDM9x30": ["EM7455", "MC7455", "EM7430", "MC7430"],
|
||||
"MDM9x30_V1": ["Netgear AC790S/AC791L"],
|
||||
"MDM9x40": ["AC815s", "AC785s","Netgear MR1100"],
|
||||
"MDM9x50": ["EM7565", "EM7565-9", "EM7511"],
|
||||
"MDM9x06": ["WP77xx"],
|
||||
"MDM9x07": ["SWI9X07Y", "WP76xx"]
|
||||
|
||||
## Usage
|
||||
|
||||
- Get a specific challenge for your task from the modem
|
||||
```
|
||||
AT!OPENLOCK?
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
AT!OPENMEP?
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
AT!OPENCND?
|
||||
```
|
||||
|
||||
- Run generator:
|
||||
For automatic unlock, use -u:
|
||||
```bash
|
||||
~> sierrakeygen -u
|
||||
```
|
||||
|
||||
For AT!OPENLOCK use -l, for AT!OPENMEP use -m and for AT!OPENCND use -c accordingly
|
||||
(here challenge is BE96CBBEE0829BCA and device generation is MDM9200)
|
||||
```bash
|
||||
~> sierrakeygen -l BE96CBBEE0829BCA -d MDM9200
|
||||
```
|
||||
|
||||
- Send generated response back to the modem
|
||||
|
||||
```
|
||||
AT!OPENLOCK=[response from generator]
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
AT!OPENMEP=[response from generator]
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
AT!OPENCND=[response from generator]
|
||||
```
|
||||
|
||||
- Open up a terminal and enable enhanced commands (generic pwd is "A710")
|
||||
|
||||
```
|
||||
AT!ENTERCND=A710
|
||||
```
|
||||
|
||||
Other known pwds are (thx to 4PDA):
|
||||
|
||||
```
|
||||
AC815s: "fallow"
|
||||
MR1100: “lindeman”
|
||||
AC790-Telstra: "sunflower"
|
||||
LB1111: "granville"
|
||||
AC810-100EUS: "whistler"
|
||||
AC810S-1P1PLS: "seymour"
|
||||
AC810S-1TLAUS: "grouse"
|
||||
AC810S-1RDQAS: "cypress"
|
||||
AC790-100EUS: "lavender"
|
||||
AC790S-1SPSUS : "bluebell"
|
||||
```
|
||||
|
||||
After unlocking via AT!OPENLOCK, you can also set a new password via AT!SETCND="pwd",
|
||||
in case the password isn't known
|
||||
|
||||
## Help
|
||||
|
||||
```bash
|
||||
~> sierrakeygen -h
|
||||
```
|
||||
|
||||
## Remarks
|
||||
|
||||
- MDM9200/MDM9x15/MDM9x30/MDM9x40/MDM9x50 confirmed to work
|
||||
|
||||
- For AC785/AC790/AC810/MR1100, you can access the serial port via tcp:
|
||||
|
||||
```bash
|
||||
HostName: 192.168.1.1
|
||||
Port: 5510
|
||||
ConnectionType: Telnet
|
||||
```
|
||||
|
||||
- Get firmware details :
|
||||
|
||||
```
|
||||
ATI
|
||||
AT!PACKAGE?
|
||||
```
|
||||
|
||||
- Get flash memory info :
|
||||
|
||||
```
|
||||
AT!FMBADBLOCKS?
|
||||
AT!BSINFO
|
||||
```
|
||||
|
||||
- Set password for opencnd:
|
||||
|
||||
```
|
||||
AT!SETCND="[pwd]"
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
AT!SETCND="A710"
|
||||
```
|
||||
|
||||
- For band selection, see possible bands via :
|
||||
|
||||
```
|
||||
AT!BAND=?
|
||||
```
|
||||
|
||||
- Set Modem to use all bands :
|
||||
|
||||
```
|
||||
AT!BAND=00
|
||||
```
|
||||
|
||||
- Set Modem to only use LTE :
|
||||
|
||||
```
|
||||
AT!SELRAT=06
|
||||
```
|
||||
|
||||
- Reboot modem and save settings :
|
||||
|
||||
```
|
||||
AT!RESET
|
||||
```
|
||||
|
||||
- To add a new band :
|
||||
|
||||
```
|
||||
AT!BAND=[index],"[name]",0,8000000
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
AT!BAND=03,"LTE B28 700",0,8000000
|
||||
AT!BAND=04,"LTE B1 2100",0,1
|
||||
AT!BAND=05,"LTE B3 1800",0,4
|
||||
AT!BAND=06,"LTE B7 2600",0,40
|
||||
AT!BAND=07,"LTE B8 900",0,80
|
||||
```
|
||||
|
||||
- To remove a band :
|
||||
|
||||
```
|
||||
AT!BAND=[index],"",0,0
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
AT!BAND=03,"",0,0
|
||||
```
|
||||
|
||||
- Get signal info :
|
||||
|
||||
```
|
||||
AT!GSTATUS?
|
||||
```
|
||||
|
||||
- Get partition info :
|
||||
|
||||
```
|
||||
AT!PARTINFO?
|
||||
```
|
||||
|
||||
- Switch to qc download mode :
|
||||
|
||||
```
|
||||
AT!BOOTHOLD
|
||||
AT!QPSTDLOAD
|
||||
```
|
||||
|
||||
- Show Secure Boot info :
|
||||
|
||||
```
|
||||
AT!SECBOOTCFG? Show Secure Boot config
|
||||
AT!SECBOOTPKHASH? Show Secure Boot PKHASH
|
||||
```
|
||||
|
||||
- Show Product Info :
|
||||
|
||||
```
|
||||
AT!USBPRODUCT?
|
||||
Sierra Wireless EM7565 Qualcomm® Snapdragon™ X16 LTE-A
|
||||
|
||||
AT!USBMANUFACTURER?
|
||||
Sierra Wireless, Incorporated
|
||||
```
|
||||
|
||||
- Set vid and pid :
|
||||
|
||||
```
|
||||
AT!USBVID=1199 Set usb vid of 0x1199
|
||||
AT!USBPID=9091,9090 Set usb pid (app=0x9091, boot=0x9090)
|
||||
```
|
||||
|
||||
- Set product identifier :
|
||||
|
||||
```
|
||||
AT!PRIID? Show product identifier
|
||||
PRI Part Number: 9907344
|
||||
Revision: 002.001
|
||||
Customer: Generic-M2M
|
||||
Carrier PRI: 9999999_9907259_SWI9X50C_01.08.04.00_00_GENERIC_002.012_000
|
||||
|
||||
|
||||
AT!USBPID="9907344","002.001","Generic-M2M" Set PartNr, Revision and Customer
|
||||
```
|
||||
|
||||
- Set preferred modem image :
|
||||
|
||||
```
|
||||
AT!IMPREF="GENERIC"
|
||||
|
||||
AT!IMAGE=?
|
||||
AT!IMAGE=<op>[,<type>[,<slot>[,"<build_id>","<unique_id>"]]]
|
||||
op - 0:delete 1:list 2:get max num images
|
||||
type - 0:FW 1:CONFIG
|
||||
slot - FW slot index - none implies all slots
|
||||
AT!IMAGE?[<op>[,<type>]]
|
||||
|
||||
AT!IMAGE=0,0,1 Op=0 (Delete), Type=0 (FW), Slot Index=1
|
||||
```
|
||||
|
||||
- Reset to factor settings :
|
||||
|
||||
```
|
||||
AT!RMARESET=1
|
||||
```
|
||||
|
||||
- Lenovo laptop whitelist bypass :
|
||||
|
||||
```
|
||||
AT!ENTERCND="A710"
|
||||
AT!CUSTOM="FASTENUMEN",2 Disable fast enumeration and only show up after init
|
||||
AT!PCOFFEN=2 Ignore W_DISABLE pin
|
||||
AT!USBSPEED=0 Force usb2 mode
|
||||
AT!RESET
|
||||
```
|
||||
|
||||
- Set usb composition (diag, nmea, modem, mbim, same as USBCOMP=8):
|
||||
|
||||
```
|
||||
AT!USBCOMP=1,3,0000100D
|
||||
```
|
||||
|
||||
- List custom settings :
|
||||
|
||||
```
|
||||
AT!CUSTOM?
|
||||
```
|
||||
|
||||
- Enable telnet (after sending valid openlock request)
|
||||
|
||||
```
|
||||
at!custom="TELNETENABLE",1
|
||||
```
|
||||
|
||||
- Enable adb (after sending valid openlock request, here: MC7304/AC810)
|
||||
|
||||
```
|
||||
AT!CUSTOM="ADBENABLE", 1
|
||||
```
|
||||
|
||||
Regulary, tcp port 5555 is used for adb
|
||||
|
||||
```
|
||||
adb tcpip 5555
|
||||
adb connect 192.168.1.1
|
||||
```
|
||||
|
||||
- Enable telnet (after sending valid openlock request, here: MR1100)
|
||||
|
||||
```
|
||||
AT!TELEN=1
|
||||
AT!CUSTOM="RDENABLE", 1
|
||||
AT!CUSTOM="TELNETENABLE", 1
|
||||
```
|
||||
then reboot the device. Afterwards, telnet should be available on MR1100 via 192.168.1.1:23
|
||||
|
||||
- Flash firmware :
|
||||
|
||||
```bash
|
||||
~ > sudo apt install libqmi-glib5 libqmi-proxy libqmi-utils -y
|
||||
~ > qmi-firmware-update --update -d 1199:9091 firmware.cwe firmware.nvu 1199:9091 is usb vid/pid
|
||||
```
|
||||
|
||||
## Other useful links
|
||||
|
||||
- https://github.com/danielewood/sierra-wireless-modems/blob/master/README.md
|
||||
|
||||
## ToDo
|
||||
|
||||
- Nothing :)
|
||||
|
||||
## License
|
||||
|
||||
Published under MIT license
|
||||
Additional license limitations: No use in commercial products without prior permit by me.
|
||||
|
||||
Enjoy !
|
Loading…
Reference in a new issue