This commit is contained in:
Mike 2026-02-09 07:30:56 +02:00
parent a31b37d3d2
commit ded84b9cd5
41 changed files with 1957 additions and 0 deletions

77
mstar-bin-tool/README.md Normal file
View File

@ -0,0 +1,77 @@
# mstar-bin-tool
Command line tools to pack/unpack MStar bin firmware
Currently available tools:
- **unpack.py** - unpack MStar bin firmware
- **pack.py** - pack MStar bin firmware
- **extract_keys.py** - extract AES and RSA-public keys from MBOOT binary
- **secure_partition.py** - encrypt image and generate signature file
## Unpack MStar bin firmware files
```
Usage: unpack.py <firmware> <output folder [default: ./unpacked/]>
<firmware> - MStar bin firmware to unpack
<output folder> - directory to store unpacked stuff. Default value: ./unpacked/
```
## Pack MStar bin firmware
```
Usage: pack.py <config file>
Example: pack.py configs/letv-x355pro-full.ini
<config file> - Configuration file. The config file structure will be described later.
For now you can take a look at configs/letv-x355pro-full.ini
and use it as an example
```
## Extract keys from MBOOT
That tool is used to get AES and public RSA keys from the MBOOT. AES keys are needed to encrypt/decrypt
boot.img and recovery.img images. aescrypt2 tool is used.
```
Usage: extract_keys.py <path to mboot> [<folder to store keys>] [<key bank offset>] [<key bank size>]
Defaults:
<folder to store keys> keys
<key bank offset> 0x168e00
<key bank size> 0x450
Example: extract_keys.py ./unpacked/MBOOT.img
Example: extract_keys.py ./unpacked/MBOOT.img ./keys 0x169e00 0x450
```
## Encrypt/Decrypt partition
You can encrypt/decrypt partition with using *aescrypt2.exe* tool, which is located in bin/win32 folder
Default mstar key is *hex:0007FF4154534D92FC55AA0FFF0110E0* All mstar default keys are in default_keys folder. (These keys are in public access in github)
Last parameter can be hex value or path to AES key. If your vendor is using custom aes keys you can use extract_keys.py to extract them.
To encrypt image use:
```
aescrypt2 0 boot.img boot.img.aes hex:0007FF4154534D92FC55AA0FFF0110E0
or
aescrypt2 0 boot.img boot.img.aes keys/AESBootKey
```
So to decrypt image use:
```
aescrypt2 1 boot.img.aes boot.img hex:0007FF4154534D92FC55AA0FFF0110E0
or
aescrypt2 1 boot.img boot.img.aes keys/AESBootKey
```
## Encrypt partition and generate signature
All new MStar builds have SECURE_BOOT option enabled. In that case
boot.img and recovery.img is encrypted (AES) and signed with RSA priv keys.
That script is used to encrypt image and generate sign file.
To manually encrypt|decrypt image use aescrypt2 tool from bin folder.
AES key can be extracted from MBOOT with extract_keys.py script.
```
Usage: secure_partition.py <file to encrypt> <AES key file> <RSA private key file> <RSA public key file> <output encrypted file> <output signature file>
Example: secure_partition.py ./pack/boot.img ./keys/AESbootKey ./keys/RSAboot_priv.txt ./keys/RSAboot_pub.txt ./pack/boot.img.aes ./pack/bootSign
```

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,28 @@
#
# LeEco X3-50+ (6a928), Super4 (6a938)
# Enable UART and set the tv to stand by mode to allow normal bin file flashing
#
# NB! Rename generated file to LETV_USB_SCRIPT_928 if you have LeEco X3-50+ (6a928)
#
[Main]
FirmwareFileName=LETV_USB_SCRIPT_938
ProjectFolder=./pack
useHexValuesPrefix=false
SCRIPT_FIRMWARE_FILE_NAME=${FirmwareFileName}
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
Suffix:
# Enable UART
setenv ForcePowerOn 0
setenv UARTOnOff on
saveenv
reset

View File

@ -0,0 +1,32 @@
#
# Dexp H32B8200K F40B8300K F49B8200K F55B8200K TVs
# Config file to pack a single partition to firmware file (system.img)
# This will not create the partition, just erase and rewrite it
#
[Main]
FirmwareFileName=MadisonUpgrade.bin
ProjectFolder=./pack
useHexValuesPrefix=false
SCRIPT_FIRMWARE_FILE_NAME=${FirmwareFileName}
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
dont_overwrite_init
Suffix:
setenv MstarUpgrade_complete 1
setenv ResetAfterUpgrade 1
setenv ForcePowerOn 0
saveenv
[part/system]
erase=True
imageFile=${Main:ProjectFolder}/system.img
type=partitionImage
lzo=True
chunkSize=150MB

View File

@ -0,0 +1,31 @@
#
# Example of using emptySkip param. It is non-required param
# By default emptySkip is set to False for sboot partition type and True for any other partitions
#
[Main]
FirmwareFileName=LetvUpgrade938.bin
ProjectFolder=./pack
useHexValuesPrefix=true
SCRIPT_FIRMWARE_FILE_NAME=$$(UpgradeImage)
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
Suffix:
setenv MstarUpgrade_complete 1
setenv ResetAfterUpgrade 1
setenv ForcePowerOn 0
saveenv
[part/system]
erase=True
imageFile=${Main:ProjectFolder}/system.img
type=partitionImage
lzo=True
chunkSize=50MB
emptySkip=False

View File

@ -0,0 +1,38 @@
#
# All MBOOT models
# Simple config file which contains mboot commands to start backuping whole emmc content to usb drive
# Flash it as usual bin firmware. Instead of flashing it will backup emmc data to usb drive
# Change output filename according your needs
#
[Main]
#FirmwareFileName=LetvUpgrade928.bin
FirmwareFileName=LetvUpgrade938.bin
ProjectFolder=./pack
useHexValuesPrefix=false
SCRIPT_FIRMWARE_FILE_NAME=${FirmwareFileName}
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
# uncomment next line if your emmc > 4GB
# that will clone whlole emmc to usb drive (similar to dd command in linux)
# 0 - is the usb port number. In my case it's usb2.0 port on right side of the TV
#mmc dd mmc2usb 0
# uncomment next line if your emmc <= 4GB
# that will generate boot1.bin boot2.bin and emmc.bin in the root folder of the usb drive
# 0 - is the usb port number. In my case it's usb2.0 port on right side of the TV
# emmcbin 0
# let mboot know we are done to allow normal boot
setenv LetvUpgrade_complete 1
setenv ForcePowerOn 0
saveenv
Suffix:
# Nothig here

View File

@ -0,0 +1,25 @@
#
# LeEco X3-50+ (6a928), Super4 (6a938)
# Enable UART
#
[Main]
FirmwareFileName=enable_uart
ProjectFolder=./pack
useHexValuesPrefix=false
SCRIPT_FIRMWARE_FILE_NAME=${FirmwareFileName}
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
Suffix:
# Enable UART
setenv UARTOnOff on
saveenv
reset

View File

@ -0,0 +1,23 @@
#
# LeEco X3-50+ (6a928), Super4 (6a938)
# Force flash bin firmware
#
[Main]
FirmwareFileName=force_flash_bin_firmware
ProjectFolder=./pack
useHexValuesPrefix=false
SCRIPT_FIRMWARE_FILE_NAME=${FirmwareFileName}
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
Suffix:
# Start flashing
custar

View File

@ -0,0 +1,43 @@
#
# LeEco X3-40 X3-43
# Config file to pack a single partition to firmware file (recovery.img)
#
# This will NOT create the partition, just erase and rewrite it
# NO security info (signature) will be added to the bin !
# Security checking for recovery will be DISABLED
# Use it to flash plain non encrypted recovery.img
#
[Main]
FirmwareFileName=LetvUpgrade.bin
ProjectFolder=./pack
useHexValuesPrefix=false
SCRIPT_FIRMWARE_FILE_NAME=${FirmwareFileName}
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
# Nothing here
Suffix:
# Enable UART
setenv UARTOnOff on
# No auth for the recovery
setenv recoverycmd mmc read.p 0x25000000 recovery 0x00800000\; bootm 0x25000000
# Done
setenv LetvUpgrade_complete 1
setenv ResetAfterUpgrade 1
setenv ForcePowerOn 0
saveenv
[part/recovery]
erase=True
imageFile=${Main:ProjectFolder}/recovery.img
type=partitionImage

View File

@ -0,0 +1,210 @@
#
# LeEco X3-55pro (Super3 x55 Pro) packer configuration file
# The TV is based on mst6a928 cpu
#
[Main]
# Output file name
FirmwareFileName=LetvUpgrade928.bin
# Folder which contains images to pack
ProjectFolder=./pack
# Use hex values in "mmc write.p" directive.
# Check your unpacked ~header_script file for the "mmc write.p" paramers.
# Set it to True, if the paramers have "0x" prefix.
# All newest Mstar firwares uses hex values
useHexValuesPrefix=false
# Firmware file name to use in "filepartload" directive.
# All newest Mstar firwares uses $(UpgradeImage) Otherwise it should be equal FirmwareFileName value.
SCRIPT_FIRMWARE_FILE_NAME=${FirmwareFileName}
# DRAM_BUF_ADDR value
DRAM_BUF_ADDR=20200000
# Magic footer value. It's reserved for future use, usually it's "12345678" string
MAGIC_FOOTER=12345678
# Header size is always 16KB
HEADER_SIZE=16KB
[HeaderScript]
# Custom header script directives at the beginning of the script
Prefix:
mmc slc 0 1
mmc rmgpt
factory_init factory 0x02000000
# Custom directives at the end of the script
Suffix:
cleanallenv
setenv filesize 6748c0
setenv LOAD_KERNEL mmc read.p 0x25000000 boot 0x01000000\; authenticateAN 0x25000000
setenv filesize 6748c0
setenv BOOT_KERNEL bootm 0x25000000
setenv recoverycmd mmc read.p 0x25000000 recovery 0x02000000\; authenticateAN 0x25000000\; bootm 0x25000000
setenv LOAD_NUTTX mmc read.p 0x5EC70000 tee 0x600000
setenv BOOT_NUTTX bootNuttx 0x1EC70000
setenv CMA_REG0 CMA0=mali0,miu=0,hid=16,sz=0x1F000000
setenv CMA_REG1 CMA1=mali1,miu=1,hid=17,sz=0x5400000
setenv CMA_REG2 CMA2=VDEC1,miu=1,hid=19,sz=0xCC00000,st=0x6C00000
setenv bootargs console=ttyS0,115200 androidboot.console=ttyS0 root=/dev/ram rw rootwait init=/init CORE_DUMP_PATH=/data/Logs/Log.0/core_dump.%%p.gz KDebug=1 delaylogo=True androidboot.selinux=permissive $(CMA_REG0) $(CMA_REG1) $(CMA_REG2) PM51_ADDR=0x20010000 PM51_LEN=0x10000 DRAM_LEN=0xC0000000 BOOTLOGO_IN_MBOOT ENV_VAR_OFFSET=0x0 ENV_VAR_SIZE=0x10000 ENV=EMMC SECURITY=ON
setenv bootlogo_gopidx 3
setenv bootlogo_buffer E_MMAP_ID_PHOTO_INTER
setenv str_crc 1
setenv db_table 0
setenv verify n
setenv bootcmd $(LOAD_KERNEL)\; $(LOAD_NUTTX)\; $(BOOT_NUTTX)\; $(BOOT_KERNEL)
setenv ForcePowerOn 1
setenv factory_poweron_mode secondary
setenv sync_mmap 1
setenv detect_mmap 1
saveenv
setenv LetvUpgrade_complete 1
setenv factory_mode 0
setenv ResetAfterUpgrade 1
setenv ForcePowerOn 1
setenv db_table 0
saveenv
printenv
# List of partitions to pack
# [partition_name] - Name of partition. Shold begin with "part/"
# create - flag to generate "mmc create" directive. It requires "size" parameter
# size - Required parameter, if create flag sets to True. Partition size to create [hex]
# erase - flag to generate "mmc erase.p" directive.
# imageFile - Path to image file to pack
# type - partition type:
# partitionImage - Plain partition image. It generates "filepartload" and "mmc write.p" directives
# secureInfo - signature file. Uses "store_secure_info" directive
# nuttxConfig - Nuttx config file. Uses "store_nuttx_config" directive
# lzo - pack partition/chunk to lzo. Uses "mmc unlzo" directive
# chunkSize - chunk size to split partition. A single chunk uses, if chunkSize is not set. Units: B, KB, MB, GB
[part/MPOOL]
# Signatures (secureInfo) stored in that partition, so it should be erased before writing secure info.
# We erase it very first
erase=True
[part/ipanic]
create=True
size=0x00200000
[part/misc]
create=True
size=0x00080000
erase=True
[part/reserved]
create=True
size=0x02000000
[part/recovery]
create=True
size=0x02000000
erase=True
imageFile=${Main:ProjectFolder}/recovery.img
type=partitionImage
[part/recoverySign]
imageFile=${Main:ProjectFolder}/recoverySign
type=secureInfo
[part/boot]
create=True
size=0x01000000
erase=True
imageFile=${Main:ProjectFolder}/boot.img
type=partitionImage
[part/bootSign]
imageFile=${Main:ProjectFolder}/bootSign
type=secureInfo
[part/tee]
create=True
size=0x01000000
erase=True
imageFile=${Main:ProjectFolder}/tee.img
type=partitionImage
[part/teeSign]
imageFile=${Main:ProjectFolder}/teeSign
type=secureInfo
[part/NuttxConfig]
imageFile=${Main:ProjectFolder}/NuttxConfig
type=nuttxConfig
[part/RTPM]
create=True
size=0x00040000
erase=True
imageFile=pack/RTPM.img
type=partitionImage
[part/system]
create=True
size=0x60000000
erase=True
imageFile=${Main:ProjectFolder}/system.img
type=partitionImage
lzo=True
chunkSize=150MB
[part/cache]
create=True
size=0x60000000
erase=True
imageFile=${Main:ProjectFolder}/cache.img
type=partitionImage
lzo=True
[part/tvservice]
create=True
size=0x09600000
erase=True
imageFile=${Main:ProjectFolder}/tvservice.img
type=partitionImage
[part/tvconfig]
create=True
size=0x06400000
erase=True
imageFile=${Main:ProjectFolder}/tvconfig.img
type=partitionImage
[part/tvdatabase]
create=True
size=0x02000000
erase=True
imageFile=${Main:ProjectFolder}/tvdatabase.img
type=partitionImage
[part/tvcustomer]
create=True
size=0x01000000
erase=True
imageFile=${Main:ProjectFolder}/tvcustomer.img
type=partitionImage
[part/userdata]
create=True
size=0x320D3F000 variable:0x1000000,0x64D93E000,0x2A9B3F000,0xD7C3F800
erase=True
imageFile=${Main:ProjectFolder}/userdata.img
type=partitionImage
lzo=True
chunkSize=150MB
[part/sboot]
imageFile=${Main:ProjectFolder}/sboot.img
type=sboot
[part/MBOOT]
imageFile=${Main:ProjectFolder}/MBOOT.img
type=partitionImage

View File

@ -0,0 +1,43 @@
#
# LeEco X3-55pro (Super3 x55 Pro)
# Config file to pack a single partition to firmware file (recovery.img)
#
# This will NOT create the partition, just erase and rewrite it
# NO security info (signature) will be added to the bin !
# Security checking for recovery will be DISABLED
# Use it to flash plain non encrypted recovery.img
#
[Main]
FirmwareFileName=LetvUpgrade928.bin
ProjectFolder=./pack
useHexValuesPrefix=false
SCRIPT_FIRMWARE_FILE_NAME=${FirmwareFileName}
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
dont_overwrite_init
Suffix:
# Enable UART
setenv UARTOnOff on
# No auth for the recovery
setenv recoverycmd mmc read.p 0x25000000 recovery 0x02000000\; bootm 0x25000000
# Done
setenv LetvUpgrade_complete 1
setenv ResetAfterUpgrade 1
setenv ForcePowerOn 0
saveenv
[part/recovery]
erase=True
imageFile=${Main:ProjectFolder}/recovery.img
type=partitionImage

View File

@ -0,0 +1,46 @@
#
# LeEco X3-55pro (Super3 x55 Pro)
# Config file to pack a single partition to firmware file (recovery.img)
# This will not create the partition, just erase and rewrite it
# Also security info (signature) will be added to the bin
# You have to generate signature and encrypt image before pack it to the firmware.
# Use secure_partition.py script to do so. RSA production key and AES key are required.
#
[Main]
FirmwareFileName=LetvUpgrade928.bin
ProjectFolder=./pack
useHexValuesPrefix=false
SCRIPT_FIRMWARE_FILE_NAME=${FirmwareFileName}
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
dont_overwrite_init
Suffix:
# Enable UART
setenv UARTOnOff on
# Auth enabled for the recovery partition
# In that case security info (signature) is required
setenv recoverycmd mmc read.p 0x25000000 recovery 0x02000000\; authenticateAN 0x25000000\; bootm 0x25000000
# Done
setenv LetvUpgrade_complete 1
setenv ResetAfterUpgrade 1
setenv ForcePowerOn 1
saveenv
[part/recovery]
erase=True
imageFile=${Main:ProjectFolder}/recovery.img.aes
type=partitionImage
[part/recoverySign]
imageFile=${Main:ProjectFolder}/recovery.signature
type=secureInfo

View File

@ -0,0 +1,32 @@
#
# LeEco X3-55pro (Super3 x55 Pro)
# Config file to pack a single partition to firmware file (system.img)
# This will not create the partition, just erase and rewrite it
#
[Main]
FirmwareFileName=LetvUpgrade928.bin
ProjectFolder=./pack
useHexValuesPrefix=false
SCRIPT_FIRMWARE_FILE_NAME=${FirmwareFileName}
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
dont_overwrite_init
Suffix:
setenv LetvUpgrade_complete 1
setenv ResetAfterUpgrade 1
setenv ForcePowerOn 0
saveenv
[part/system]
erase=True
imageFile=${Main:ProjectFolder}/system.img
type=partitionImage
lzo=True
chunkSize=150MB

View File

@ -0,0 +1,45 @@
#
# LeEco X3-55pro (Super3 x55 Pro)
# Config file to pack a single partition to firmware file (recovery.img)
#
# This will NOT create the partition, just erase and rewrite it
# NO security info (signature) will be added to the bin !
# Security checking for recovery will be DISABLED
# Use it to flash plain non encrypted recovery.img
#
[Main]
FirmwareFileName=LetvUpgrade938-recovery.bin
ProjectFolder=./pack
useHexValuesPrefix=true
SCRIPT_FIRMWARE_FILE_NAME=$$(UpgradeImage)
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
Suffix:
# Enable UART
setenv UARTOnOff on
# No auth for the recovery
setenv recoverycmd mmc read.p 0x23000000 dtb 0x00100000\; mmc read.p 0x25000000 recovery 0x02000000\; bootm 0x25000000
# setenv recoverycmd mmc read.p 0x25000000 recovery 0x02000000\; bootm 0x25000000
# Done
setenv selinux_force_disable 1
setenv LetvUpgrade_complete 1
setenv ResetAfterUpgrade 1
setenv ForcePowerOn 0
saveenv
[part/recovery]
erase=True
imageFile=${Main:ProjectFolder}/recovery.img
type=partitionImage

View File

@ -0,0 +1,56 @@
#
# LeEco Super4 (Mstar 6a938)
#
# Config file to create "live" bin files
# which allows to use custom recovery or boot images
# without affecting the actual system
#
[Main]
FirmwareFileName=LetvUpgrade938-systemless-live.bin
ProjectFolder=./pack
useHexValuesPrefix=true
SCRIPT_FIRMWARE_FILE_NAME=$$(UpgradeImage)
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
# Init panel
panel_pre_init
hdmi init
panel_post_init
Suffix:
# Enable UART
setenv UARTOnOff on
# Disable selinux
setenv selinux_force_disable 1
# Do not boot
setenv ForcePowerOn 0
saveenv
# Boot uImage
# 0x25000000 - image offset in memory
bootm 0x25000000
[part/recovery]
imageFile=${Main:ProjectFolder}/recovery.img
# Do not store it to mmc, just load it and keep in memory
type=inMemory
memoryOffset=0x25000000
[part/dtb]
imageFile=${Main:ProjectFolder}/dtb.bin
# Do not store it to mmc, just load it and keep in memory
type=inMemory
memoryOffset=0x23000000

View File

@ -0,0 +1,35 @@
#
# LeEco X4-50pro (Super4 x50 Pro)
# Config file to pack a single partition to firmware file (system.img)
# This will not create the partition, just erase and rewrite it
#
[Main]
FirmwareFileName=LetvUpgrade938.bin
ProjectFolder=./pack
useHexValuesPrefix=true
SCRIPT_FIRMWARE_FILE_NAME=$$(UpgradeImage)
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
Suffix:
setenv str_crc 2
setenv db_table 0
setenv verify n
setenv ForcePowerOn 0
saveenv
setenv LetvUpgrade_complete 1
saveenv
printenv
[part/system]
erase=True
imageFile=${Main:ProjectFolder}/system.img
type=partitionImage
lzo=True
chunkSize=150MB

View File

@ -0,0 +1,35 @@
#
# TCL P1US-series (L43P2US etc)
# Should work on all TV based on S68AT02 (MS68A-AP board)
# Config file to pack a single partition to firmware file (system.img)
# This will not create the partition, just erase and rewrite it
#
[Main]
FirmwareFileName=V8-S68AT02-LF1V108.bin
ProjectFolder=./pack
useHexValuesPrefix=true
SCRIPT_FIRMWARE_FILE_NAME=$$(UpgradeImage)
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
[HeaderScript]
Prefix:
Suffix:
setenv str_crc 1
setenv db_table 0
setenv verify n
setenv ForcePowerOn 0
saveenv
setenv MstarUpgrade_complete 1
saveenv
[part/system]
erase=True
imageFile=${Main:ProjectFolder}/system.img
type=partitionImage
lzo=True
chunkSize=150MB

View File

@ -0,0 +1,27 @@
[Main]
FirmwareFileName=GIMI_XF11G_MONACO_WMP_H1S.bin
ProjectFolder=./pack
useHexValuesPrefix=true
SCRIPT_FIRMWARE_FILE_NAME=${FirmwareFileName}
DRAM_BUF_ADDR=20200000
MAGIC_FOOTER=12345678
HEADER_SIZE=16KB
USE_XGIMI_CRC2=True
[HeaderScript]
Prefix:
Suffix:
setenv MstarUpgrade_complete 1
setenv sync_mmap 1
setenv db_table 0
saveenv
printenv
[part/system]
erase=True
imageFile=${Main:ProjectFolder}/system.img
type=partitionImage
lzo=True
chunkSize=150MB

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
# MSTAR default AES and RSA keys
These keys I found on github in a few public repositories. It seems like it's mstar default keys provided with their sdk.

View File

@ -0,0 +1,8 @@
N = AA5E3FDAD01DDF4AFAFE67A1B53BBB8B931FECBAAC0F0C0ED61A66EC04C416E5A4A69AAFEFB6EE7DA3E7A559E4006BC5FCE979B28B8E81136C8AB6CC11D9A7CEA83C7A431835D04DA6AE40CD4D0414F6CA3D5EF2274EF38C8A6FBC6AC4CCD123FBCA638ABBC40514A998127671F3A36EA8B207E40E169BF75EC41915BE3A9EF2309A7661681191D6AC2C22AA46194DE8C712B7EFCE29D38BB920955C0E5A26FCF9651F568F3CDB6085364A2A357D94BDCFD0CF6C615064B12A9A7DA2AC03EC254899E013B4864E6815653206823F02BE4C0D594B4CF6548238AA0947A31A8BA1D1F8CC0911158FFD4C01460C6FF78DB822E4872851F6C0097CEAD15C46B4FB4B
E = 010001
D = 2D26E7737D7EBD4428FB2DC9FCB745003BD0D533B01018D901C3638D9FC1BC73C64C6568C5764D04BD60D240DD9D82F2A911D3B00F2E8864F67A58F202B515B53E7F30C4017199B04AC199E90F454AAD11726C6C6F208C89ADD2E933BECEAD8B04DB61C04DFD287F8E670055A5E3B567C98BCD6D92924969A912FDB6F680A0C90E7F0899436880FC66CC7E1399E11263497A42011BE8BE9B1C003F956448C425F4A8138D9DD3B6B735474A6CB7AC5A39CC0EDE5ED74D2DD7A9CCC681B58741D4DDA496B9C0DE1EF367B6709E2488A4B2915F1CCF92CD563C25D1CBF5D719F100D2A4C1DDAC1F49EB092100F9A2276289CFB9990C7AB7D11D2D40685D165C3849
P = D623430C4E6C9BBC5D306EBEEAA0724F0847BB7E679E7E5B3EBDF21CE642C4296422824335A488D80A6DF3B24069BBEB10D4BC331DCC2C015717F934BF0B777B96166928FB355CBB27CB383E2F2FB499B8DBDE2425FEA7A134737A0964ECA25DFE304539EBC3BBD31128FB2B295DC1FA2C5968A7969A94E37287F2A31BC56F37
Q = CBAC7EB7B047868F65C5681253DF2451287E06F60D4D683467876AD8A27EE0514F0B29A8E667D690BBC6164B977FCBD241663F71D6238838632D9DE057DF4E4BB349BA0FF213DA9DB8F89BFD83D1B902F45B5A028094D22947CE7A06437D12820412FAE2ECF1A4606C92C844E8AB624844DFEA573B0627A047969830BBD8168D
DP = 0A863F245AB261D1172F6B31FCEC17D2249109F90374B9B718555391F20B3402E8C5FD6AFA36F4F6D1446826C99DA8BBBBDF08C4E6610384A958274A5D5D5DE8F80E6FEAB0B605B1B919F6D0AF9703A44E7E97E364EEA824772479C9FE68D6EE11B123A5DE1D879CAF0A3995FC797C30247FDC71E827FECB52F4B58B28B1426F
DQ = 6C5D61AA70030E47FB78F5AF52AA95D30C7D494CDEB501AD682BF7A03D8CCDE2D4F07680E3DDF99E5619C5C10061415BA3EA37F5645ED15A57026D4E70D262010AEA3E31BFB5EA8A22613BF5BD8DF726E8463674C05EEE16829B0BF78B2EDF8B0789E5AC992ED42B6D79074F0A902D21906BA66E34FC485711DFC127A4BA0AFD
QP = 2848FD5806119A589490ADDD419167BA952E38CBF6EF11B4B39D36156F2BE6B72372A04270D0ABFF2628F3A1E32BE9FF2C89323CABA492248FBF559E7068541E0A9238E4A61A9A5A9A77F53246693ACB12BDC3C94F83A7C6F379483E2F3CB450D3DE8FD26F7A2B1B8858C3621C7E22E0470ED225563F919658A125ECD7A0BA16

Binary file not shown.

View File

@ -0,0 +1,2 @@
N = AA5E3FDAD01DDF4AFAFE67A1B53BBB8B931FECBAAC0F0C0ED61A66EC04C416E5A4A69AAFEFB6EE7DA3E7A559E4006BC5FCE979B28B8E81136C8AB6CC11D9A7CEA83C7A431835D04DA6AE40CD4D0414F6CA3D5EF2274EF38C8A6FBC6AC4CCD123FBCA638ABBC40514A998127671F3A36EA8B207E40E169BF75EC41915BE3A9EF2309A7661681191D6AC2C22AA46194DE8C712B7EFCE29D38BB920955C0E5A26FCF9651F568F3CDB6085364A2A357D94BDCFD0CF6C615064B12A9A7DA2AC03EC254899E013B4864E6815653206823F02BE4C0D594B4CF6548238AA0947A31A8BA1D1F8CC0911158FFD4C01460C6FF78DB822E4872851F6C0097CEAD15C46B4FB4B
E = 010001

View File

@ -0,0 +1,8 @@
N = 846276CCBD5A5A4030C096408728DB85EDED9F3EDE4E65E67B1B7817879DF616C3D327BCB45A031335B0965A9641744EB9D17796F78DE2E71509659C4679EAF0916735FA694C83F7DCCF9720F2A5BA72809D557917DC6E60A5E70E9E899B460652FC645602089A9641E24FDBB660C338DFF497815D1202AE2B9F0929B99D5145D29E2BAF64CA9A064E943567F78E047B2438A0DFE75F1E6D298E30D7838CB441D2FDBF5B18CA50D127D1F67D543E805F20DC8882CFBEE1462AD663B9B99DA3C7683E48CE6A626FD16AC3B6DEF33925ECF67920B5F230256E99AE3956DAAF83D6B849157881CC3C4F665D957E31D4372ABEFCB466F891010A533C3CAB86B980B7
E = 010001
D = 73A17978CD6F8CE30272450AE9C383331125FB713345B0F5C6D3B06A84F7310AA352DD23933807F59070C4732D48D0A92EDECA211FEB5BA451989A9B0C67D310FB3FF642DA148E344237441EF032578F49CDA2E99930DD6C279C910562D6302CB7F162464992704C0C11FB84C260F443CA41DECF8C967DA6D9CD1878CC7A9F902474E2A938933D2B51C8EF06D46019EA213379F648938A953C128F458D421E0E862144BE86FA877F6840F6CFF36EAC3E64AB682DAAE8AE194669E2B3E200E2C6E775143CB13A45D11845883F4BD06C6420BABD384269AA087A3A98DDF94574F5D78E2BAD671D42572E488522F0C91F7742C2285C8EE20C3DE3B060D1AA9987E1
P = CE85599F5EB3800196192D5B9127499ACF77F94ECE68726DE24D708066728903430C240F175901999A522AE1420DA9C662BA0DC7AAC710B53C24EF7F365FFBDDBD8A919196172EB7B12BEB06472A9EFF1393BD400E1B62AF5AD0FE8740DDFC6DEF970CE8F4481387B0EEDBBB2310BA3E97B71F5F7022722B0BCAD2E03D3A8727
Q = A41A13A32F07E49890E8E65FC5D1D51F54746623DF195A4F46006C15913A55F5A92534FE1C59F2FF2FCBFA74B82AF69A8709DD85512B58EF9D5EE3705990D7F548D0BDD1333BD0F229F097DCDB96909AC2FE033157E10F7F677E52317DCC671E744E4104ECF6705C0D521FD08BCAA593C29690436C4C9BFE68FCCDC72CE0B3F1
DP = 2C3FD2361D7A6460F2A22E5FC23822C332D4C7EC24B9A85AF6F414B8CE3A9834C4B6E33B008BA7961BC4A33F6481BCF0AED2A285378833824182C07607568586BB47E76CC435EF6298698A8FEBCBAC09874E4E6C5D196D099971D23774A49BA38A8458D5C911706DD0713D4F59720A15C3380F56C995F7D455507DE261FC1A5D
DQ = 5E61B51BACC8105D03334094A2D4FD8BC86A2DF8C1AEF63713DED84B4B3CCF05BCA3EEA79C2CCBCAA375E0F5D29ABB3CC320146D41F2F972CF032D328800FB8452BDE3FE774616F5C0D364B49D032AE627F22A69EDCE3EB89B10973B69CBEF1F1FEB860FCC2E2D0F7485E05074A637B7153ABD7C59C4720FCFD85E8E08ACB031
QP = 8310683F28ECBE7F437A6B64A489F5A8B0114A4FC41BEEB6672AF677A9D5B64FACE2E35CC5D59D6C42D4BE6ED8633203E51F8BCA8EA9BDF41B2B87238F988BAC02BD8A11C96BC90BF435749CAE8FCC7E9B37A37AD57218D6CCA127B882FB0015F59DFD87FB994518305DFFCC1C692AE796E04967B31723506F8B29FAD24DE15E

Binary file not shown.

View File

@ -0,0 +1,2 @@
N = 846276CCBD5A5A4030C096408728DB85EDED9F3EDE4E65E67B1B7817879DF616C3D327BCB45A031335B0965A9641744EB9D17796F78DE2E71509659C4679EAF0916735FA694C83F7DCCF9720F2A5BA72809D557917DC6E60A5E70E9E899B460652FC645602089A9641E24FDBB660C338DFF497815D1202AE2B9F0929B99D5145D29E2BAF64CA9A064E943567F78E047B2438A0DFE75F1E6D298E30D7838CB441D2FDBF5B18CA50D127D1F67D543E805F20DC8882CFBEE1462AD663B9B99DA3C7683E48CE6A626FD16AC3B6DEF33925ECF67920B5F230256E99AE3956DAAF83D6B849157881CC3C4F665D957E31D4372ABEFCB466F891010A533C3CAB86B980B7
E = 010001

View File

@ -0,0 +1,8 @@
N = 9BA7D26B0F3AACB837807CED2A87D54C974976E967EBBEAAB297E3A4ED0C2491896DF16319698CC4323CC8ECFD8CA209BDE194D3BEB38458D7A2C859C717826DB7688245340323953CFF94F9EE8363DFF854E22C6A7F41FC2B545B2291051CCCB09A33742D6DC02FA49723D2B481EA8C679911671565E14F65534240012C642683F98976102A4AF6E06FE130028689BA2372349CAC3E35D4CE46055C234EF4EAC4DF9636FFA8A46276DFC3EC78EE7AFF6E05236E4574AB5D15EBD2DE86A4C96E90F1F9CC00F048EDCFFBC33500251BF669F5A4F00F5437C2E4B6BAD492154FF48F420A8C7E149161A3F11F3BEB680EE394182FD3484479EA224420CC1EBCA391
E = 010001
D = 705CD4439E69BFB6F7B1D3FCAC800394D77D1BCEDFCAC907960699393C3950C892898000069F30138D245DF2DE1140038243AE58B0480C98C988E3D2132B40670D47EF0A1FC2C853FA0591B85DDA1125E3B0FAD80F44B0106602EE0AE4DEE8EC45EBFA8ABA2488E09B92D3344E439E5A1E8ADB8A2B6331234C44AF055F13797342E9EC86139836A825C61E63C93A6EB39ED9F8463DC914D223AF45CE8E4D80491EBC78C4E253FC0B51A5F83AADD4CB9D48A66508D82F6E54245B48FF95DEC41E17541FDFEFDAEB1F72B0E9B31E810560A06E483D2DE2A242D2D5FE52C3FF09F21CE35E99217D501C621D0CCCEB78B17BEA403C447909684577C22B364FFC0BA5
P = F1056953D2E8AD64BB8FDF24B781F5D1CA961DC9A46786625F7AD3E3CDF50DACD005B903ADC4C16C2726A80530E15C66FE75901A218B05FC7282C8BC7DB5316CB8A9102AD0623A73B679FABD21A973C8340412EC3C04EF8818A2C35E61370DE145D5513C3B93F234C4D57318FC45E6D073D6AC9DFAB38F5B023104268A106D2B
Q = A55443B7CF7E48EE8CA0E9813350C4AF25BB302CC1025DEFB8C356C11E8A5E5702A57F306F675C7C68A971B34FC805651915EEC594863BC4CEAE7F09B4EB51A81354BD8F6BAF299F84F1EDC324C4CE7FD5B49242E8ADFE812B73B389293397F36639E097481F4EEF0AA39D25C3417E44565197876AB367E0E4EE8DC4195AAC33
DP = CC5CCB474110FB5CEB507D637399E566424170F675C9360019775B4CD0689574CF59DADB8CAEC556C0079DF5F0D155791B0F71E54645CC0896CBE00B3B07B4E5BBD9D614876692AB64B11EF2D92506405E228A2CF66334FB0FF08A796F32B0392FEE45182E682EB9A1A05F1C73638DE7782131722E8DABE2FE03B3C23DD4D9CB
DQ = 906D1B372090FE5F3E0477D7C11F46A286C08E661A39DA1BC779057971178930538485A6A73B5124F13D4CB14AF9BE14C22451D0D25DAD2AD12EC8958F319EC4C81657FE4920DCA898B7CB6F94D844589234CB2C9E1D195E77B9FC55CEE35E5367B319CAAE5B8355F92252EEA132BE7E2E35DABC966EA1496A54270DEEE431D7
QP = B7752EE6E5694BA1159CE9837FEAE2F9584F94DF50094A737771AD0D70F3295B3FF4D3EFCD8374999768976092E73D214B9F93B9FC1718BE886652EBF9289D02072C1177D94FBE7BEC3C0170BDB6D17B94EF84550C8FB1688AA3A8450BCE20B0ED0762903B740B7FEC56E8C5BAD166153515AB9489BEAD94493720CE67B13DF2

Binary file not shown.

View File

@ -0,0 +1,2 @@
N = 9BA7D26B0F3AACB837807CED2A87D54C974976E967EBBEAAB297E3A4ED0C2491896DF16319698CC4323CC8ECFD8CA209BDE194D3BEB38458D7A2C859C717826DB7688245340323953CFF94F9EE8363DFF854E22C6A7F41FC2B545B2291051CCCB09A33742D6DC02FA49723D2B481EA8C679911671565E14F65534240012C642683F98976102A4AF6E06FE130028689BA2372349CAC3E35D4CE46055C234EF4EAC4DF9636FFA8A46276DFC3EC78EE7AFF6E05236E4574AB5D15EBD2DE86A4C96E90F1F9CC00F048EDCFFBC33500251BF669F5A4F00F5437C2E4B6BAD492154FF48F420A8C7E149161A3F11F3BEB680EE394182FD3484479EA224420CC1EBCA391
E = 010001

Binary file not shown.

View File

@ -0,0 +1,186 @@
'''
Tool to extract security keys from the MBOOT
That tool can be used only if you have Mstar.Key.Bank section in the mboot
To check that you need to enable debug mode in the mboot console,
and check for next lines during the boot:
[DEBUG] isCustomerKeyBankCipher:926: keyBankOffset=0x168e00
[DEBUG] isCustomerKeyBankCipher:927: keyBankSize=0x450
keyBankOffset - is an offset of the key bank section in the mboot
keyBankSize - section size
There will be similar lines for the key bank backup.
Another way to check it is to open MBOOT binary in the hex editor and
do search for u8MagicID, which is most of the time equals to "Mstar.Key.Bank" string.
You should get two equal sections, the key bank and the key bank backup.
==== Key bank structures ===
#define AES_IV_LEN 16
#define AES_KEY_LEN 16
#define HMAC_KEY_LEN 32
#define SIGNATURE_LEN 256
#define RSA_PUBLIC_KEY_N_LEN 256
#define RSA_PUBLIC_KEY_E_LEN 4
#define RSA_PUBLIC_KEY_LEN (RSA_PUBLIC_KEY_N_LEN+RSA_PUBLIC_KEY_E_LEN)
typedef struct
{
U32 u32Num;
U32 u32Size;
}IMAGE_INFO;
typedef struct
{
U8 u8SecIdentify[8];
IMAGE_INFO info;
U8 u8Signature[SIGNATURE_LEN];
}_SUB_SECURE_INFO;
typedef struct
{
U8 N[RSA_PUBLIC_KEY_N_LEN];
U8 E[RSA_PUBLIC_KEY_E_LEN];
}RSA_PUBLIC_KEY;
typedef struct
{
_SUB_SECURE_INFO customer;
RSA_PUBLIC_KEY u8RSABootPublicKey;
RSA_PUBLIC_KEY u8RSAUpgradePublicKey;
RSA_PUBLIC_KEY u8RSAImagePublicKey;
U8 u8AESBootKey[AES_KEY_LEN];
U8 u8AESUpgradeKey[AES_KEY_LEN];
U8 u8MagicID[16];
U8 crc[4];
}CUSTOMER_KEY_BANK;
==== End Key bank structures ===
'''
from ctypes import *
import os
import sys
import utils
DEBUG = False
# Default values
defOutFolder = "keys"
defOffet = "0x168e00"
defSize = "0x450"
#defKey="hex:E01001FF0FAA55FC924D535441FF0700"
# Structures
AES_IV_LEN = 16
AES_KEY_LEN = 16
HMAC_KEY_LEN = 32
SIGNATURE_LEN = 256
RSA_PUBLIC_KEY_N_LEN = 256
RSA_PUBLIC_KEY_E_LEN = 4
RSA_PUBLIC_KEY_LEN = RSA_PUBLIC_KEY_N_LEN + RSA_PUBLIC_KEY_E_LEN
class IMAGE_INFO(Structure):
_fields_ = [("u32Num", c_uint32),
("u32Size", c_uint32)]
class SUB_SECURE_INFO(Structure):
_fields_ = [("u8SecIdentify", c_uint8 * 8),
("info", IMAGE_INFO),
("u8Signature", c_uint8 * SIGNATURE_LEN)]
class RSA_PUBLIC_KEY(Structure):
_fields_ = [("N", c_uint8 * RSA_PUBLIC_KEY_N_LEN),
("E", c_uint8 * RSA_PUBLIC_KEY_E_LEN)]
class CUSTOMER_KEY_BANK(Structure):
_fields_ = [("customer", SUB_SECURE_INFO),
("u8RSABootPublicKey", RSA_PUBLIC_KEY),
("u8RSAUpgradePublicKey", RSA_PUBLIC_KEY),
("u8RSAImagePublicKey", RSA_PUBLIC_KEY),
("u8AESBootKey", c_uint8 * AES_KEY_LEN),
("u8AESUpgradeKey", c_uint8 * AES_KEY_LEN),
("u8MagicID", c_uint8 * 16),
("crc", c_uint8 * 4)]
# Command line args
if len(sys.argv) == 1:
print ("Usage: extract_keys.py <path to mboot> [<folder to store keys>] [<key bank offset>] [<key bank size>]")
print ("Defaults: ")
print (" <folder to store keys> keys")
print (" <key bank offset> 0x168e00")
print (" <key bank size> 0x450")
#print (" <custom decription key> Efuse Key")
print ("Example: extract_keys.py ./unpacked/MBOOT.img")
print ("Example: extract_keys.py ./unpacked/MBOOT.img ./keys 0x169e00 0x450")
quit()
mboot = sys.argv[1]
outFolder = sys.argv[2] if len(sys.argv) >= 3 else defOutFolder
offestStr = sys.argv[3] if len(sys.argv) >= 4 else defOffet
sizeStr = sys.argv[4] if len(sys.argv) >= 5 else defSize
#hwKey = sys.argv[5] if len(sys.argv) >= 6 else defKey
offset = int(offestStr, 16)
size = int(sizeStr, 16)
# Create out directory
print ("[i] Create output directory")
utils.createDirectory(outFolder)
# Get the key bank section and store it
outEncKeyBankFile = os.path.join(outFolder, 'key_bank.bin')
print ("[i] Save mstar key bank to {}".format(outEncKeyBankFile))
utils.copyPart(mboot, outEncKeyBankFile, offset, size)
# Unpack the key bank to key bank structure
print ("[i] Unpack key bank structure")
keyBankBytes = utils.loadPart(outEncKeyBankFile, 0, size)
keyBank = utils.unpackStructure(CUSTOMER_KEY_BANK, keyBankBytes)
if (DEBUG):
# Print all
print ( "[i] u8SecIdentify:\n{}".format( utils.hexString(keyBank.customer.u8SecIdentify) ) )
print ( "[i] u32Num: 0x{:08x}".format( keyBank.customer.info.u32Num ) )
print ( "[i] u32Size: 0x{:08x}".format( keyBank.customer.info.u32Size ) )
print ( "[i] u8Signature:\n{}".format( utils.hexString(keyBank.customer.u8Signature) ) )
print ( "[i] u8RSABootPublicKey N:\n{}".format( utils.hexString(keyBank.u8RSABootPublicKey.N) ) )
print ( "[i] u8RSABootPublicKey E:\n{}".format( utils.hexString(keyBank.u8RSABootPublicKey.E) ) )
print ( "[i] u8RSAUpgradePublicKey N:\n{}".format( utils.hexString(keyBank.u8RSAUpgradePublicKey.N) ) )
print ( "[i] u8RSAUpgradePublicKey E:\n{}".format( utils.hexString(keyBank.u8RSAUpgradePublicKey.E) ) )
print ( "[i] u8RSAImagePublicKey N:\n{}".format( utils.hexString(keyBank.u8RSAImagePublicKey.N) ) )
print ( "[i] u8RSAImagePublicKey E:\n{}".format( utils.hexString(keyBank.u8RSAImagePublicKey.E) ) )
print ( "[i] u8AESBootKey:\n{}".format( utils.hexString(keyBank.u8AESBootKey) ) )
print ( "[i] u8AESUpgradeKey:\n{}".format( utils.hexString(keyBank.u8AESUpgradeKey) ) )
print ( "[i] u8MagicID:\n{}".format( utils.hexString(keyBank.u8MagicID) ) )
print ( "[i] CRC:\n{}".format( utils.hexString(keyBank.crc) ) )
# Save keys
print ("[i] Save keys")
# RSA Boot
utils.writeFile(os.path.join(outFolder, 'RSAboot_pub.bin'), keyBank.u8RSABootPublicKey)
utils.writeRSAPublicKey(os.path.join(outFolder, 'RSAboot_pub.txt'), keyBank.u8RSABootPublicKey)
# RSA Upgrade
utils.writeFile(os.path.join(outFolder, 'RSAupgrade_pub.bin'), keyBank.u8RSAUpgradePublicKey)
utils.writeRSAPublicKey(os.path.join(outFolder, 'RSAupgrade_pub.txt'), keyBank.u8RSAUpgradePublicKey)
# RSA Image
utils.writeFile(os.path.join(outFolder, 'RSAimage_pub.bin'), keyBank.u8RSAImagePublicKey)
utils.writeRSAPublicKey(os.path.join(outFolder, 'RSAimage_pub.txt'), keyBank.u8RSAImagePublicKey)
# AES
utils.writeFile(os.path.join(outFolder, 'AESBoot.bin'), keyBank.u8AESBootKey)
utils.writeFile(os.path.join(outFolder, 'AESUpgrade.bin'), keyBank.u8AESUpgradeKey)
print ("Done")

337
mstar-bin-tool/pack.py Normal file
View File

@ -0,0 +1,337 @@
'''
Mstar bin firmware packer
'''
'''
Header structure
-------
Multi-line script which contains MBOOT commands
The header script ends with line: '% <- this is end of file symbol'
Line separator is '\n'
The header is filled by 0xFF to 16KB
The header size is always 16KB
'''
'''
Bin structure
-------
Basically it's merged parts:
[part 1]
[part 2]
....
[part n]
Each part is 4 byte aligned (filled by 0xFF)
'''
'''
Footer structure
|MAGIC|CRC1: SWAPPED HEADER CRC32|CRC2: SWAPPED BIN CRC32|FIRST 16 BYTES OF HEADER|
# NB XGIMI uses HEADER+BIN+MAGIC+HEADER_CRC to calculate crc2
# Use USE_XGIMI_CRC2=True option to enable "XGIMI" mode
'''
import configparser
import sys
import time
import os
import struct
import utils
import shutil
tmpDir = 'tmp'
headerPart = os.path.join(tmpDir, '~header')
binPart = os.path.join(tmpDir, '~bin')
footerPart = os.path.join(tmpDir, '~footer')
# Command line args
if len(sys.argv) == 1:
print ("Usage: pack.py <config file>")
print ("Example: pack.py configs/letv-x355pro.ini")
quit()
configFile = sys.argv[1]
# Parse config file
config = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation())
#config = configparser.ConfigParser()
config.read(configFile)
# Main
main = config['Main'];
firmwareFileName = main['FirmwareFileName']
projectFolder = main['ProjectFolder']
useHexValuesPrefix = utils.str2bool(main['useHexValuesPrefix'])
SCRIPT_FIRMWARE_FILE_NAME = main['SCRIPT_FIRMWARE_FILE_NAME']
DRAM_BUF_ADDR = main['DRAM_BUF_ADDR']
MAGIC_FOOTER = main['MAGIC_FOOTER']
HEADER_SIZE = utils.sizeInt(main['HEADER_SIZE'])
# XGIMI uses HEADER+BIN+MAGIC+HEADER_CRC to calculate crc2
if 'USE_XGIMI_CRC2' in main:
USE_XGIMI_CRC2 = utils.str2bool(main['USE_XGIMI_CRC2'])
else:
USE_XGIMI_CRC2 = False
# Header
header = config['HeaderScript'];
headerScriptPrefix = config.get('HeaderScript', 'Prefix', raw = True)
headerScriptSuffix = config.get('HeaderScript', 'Suffix', raw = True)
# Parts
parts = list(filter(lambda s: s.startswith('part/'), config.sections()))
print("\n")
print ("[i] Date: {}".format(time.strftime("%d/%m/%Y %H:%M:%S")))
print ("[i] Firmware file name: {}".format(firmwareFileName))
print ("[i] Project folder: {}".format(projectFolder))
print ("[i] Use hex values: {}".format(useHexValuesPrefix))
print ("[i] Script firmware filename: {}".format(SCRIPT_FIRMWARE_FILE_NAME))
print ("[i] DRAM_BUF_ADDR: {}".format(DRAM_BUF_ADDR))
print ("[i] MAGIC_FOOTER: {}".format(MAGIC_FOOTER))
print ("[i] HEADER_SIZE: {}".format(HEADER_SIZE))
# Create working directory
print ('[i] Create working directory ...')
utils.createDirectory(tmpDir)
print ('[i] Generating header and bin ...')
# Initial empty bin to store merged parts
open(binPart, 'w').close()
with open(headerPart, 'wb') as header:
header.write('#\n'.encode())
header.write('# Generated by mstar-bin-tools\n'.encode())
header.write('# https://github.com/dipcore/mstar-bin-tool\n'.encode())
header.write('# dipcore@gmail.com\n'.encode())
header.write('#\n\n'.encode())
# Directive tool
directive = utils.directive(header, DRAM_BUF_ADDR, useHexValuesPrefix)
header.write('# Header prefix'.encode())
header.write(headerScriptPrefix.encode())
header.write('\n\n'.encode())
header.write('# Partitions'.encode())
for sectionName in parts:
part = config[sectionName]
name = sectionName.replace('part/', '')
create = utils.str2bool(utils.getConfigValue(part, 'create', ''))
size = utils.getConfigValue(part, 'size', 'NOT_SET')
erase = utils.str2bool(utils.getConfigValue(part, 'erase', ''))
type = utils.getConfigValue(part, 'type', 'NOT_SET')
imageFile = utils.getConfigValue(part, 'imageFile', 'NOT_SET')
chunkSize = utils.sizeInt(utils.getConfigValue(part, 'chunkSize', '0'))
lzo = utils.str2bool(utils.getConfigValue(part, 'lzo', ''))
memoryOffset = utils.getConfigValue(part, 'memoryOffset', 'NOT_SET')
emptySkip = utils.str2bool(utils.getConfigValue(part, 'emptySkip', 'True'))
print("\n")
print("[i] Processing partition")
print("[i] Name: {}".format(name))
print("[i] Create: {}".format(create))
print("[i] Size: {}".format(size))
print("[i] Erase: {}".format(erase))
print("[i] Type: {}".format(type))
print("[i] Image: {}".format(imageFile))
print("[i] LZO: {}".format(lzo))
print("[i] Memory Offset: {}".format(memoryOffset))
print("[i] Empty Skip: {}".format(emptySkip))
emptySkip = utils.bool2int(emptySkip) # 0 - False, 1 - True
header.write('\n'.encode())
header.write('# {}\n'.format(name).encode())
if (create):
directive.create(name, size)
if (erase and imageFile == 'NOT_SET'):
directive.erase_p(name)
if (type == 'partitionImage'):
if (chunkSize > 0):
print ('[i] Splitting ...')
chunks = utils.splitFile(imageFile, tmpDir, chunksize = chunkSize)
else:
# It will contain whole image as a single chunk
chunks = utils.splitFile(imageFile, tmpDir, chunksize = 0)
for index, inputChunk in enumerate(chunks):
print ('[i] Processing chunk: {}'.format(inputChunk))
(name1, ext1) = os.path.splitext(inputChunk)
if lzo:
outputChunk = name1 + '.lzo'
print ('[i] LZO: {} -> {}'.format(inputChunk, outputChunk))
utils.lzo(inputChunk, outputChunk)
else:
outputChunk = inputChunk
# Size, offset (hex)
size = "{:02X}".format(os.path.getsize(outputChunk))
offset = "{:02X}".format(os.path.getsize(binPart) + HEADER_SIZE)
directive.filepartload(SCRIPT_FIRMWARE_FILE_NAME, offset, size)
if (index == 0 and erase):
directive.erase_p(name)
print ('[i] Align chunk')
utils.alignFile(outputChunk)
print ('[i] Append: {} -> {}'.format(outputChunk, binPart))
utils.appendFile(outputChunk, binPart)
if lzo:
if index == 0:
directive.unlzo(name, size, DRAM_BUF_ADDR, emptySkip)
else:
directive.unlzo_cont(name, size, DRAM_BUF_ADDR, emptySkip)
else:
if len(chunks) == 1:
directive.write_p(name, size, DRAM_BUF_ADDR, emptySkip)
else:
# filepartload 50000000 MstarUpgrade.bin e04000 c800000
# mmc write.p.continue 50000000 system 0 c800000 1
# filepartload 50000000 MstarUpgrade.bin d604000 c800000
# mmc write.p.continue 50000000 system 64000 c800000 1
# Why offset is 64000 but not c800000 ???
print ('[!] UNSUPPORTED: mmc write.p.continue')
quit()
if (type == 'secureInfo'):
chunks = utils.splitFile(imageFile, tmpDir, chunksize = 0)
outputChunk = chunks[0]
size = "{:02X}".format(os.path.getsize(outputChunk))
offset = "{:02X}".format(os.path.getsize(binPart) + HEADER_SIZE)
directive.filepartload(SCRIPT_FIRMWARE_FILE_NAME, offset, size)
print ('[i] Align')
utils.alignFile(outputChunk)
print ('[i] Append: {} -> {}'.format(outputChunk, binPart))
utils.appendFile(outputChunk, binPart)
directive.store_secure_info(name)
if (type == 'nuttxConfig'):
chunks = utils.splitFile(imageFile, tmpDir, chunksize = 0)
outputChunk = chunks[0]
size = "{:02X}".format(os.path.getsize(outputChunk))
offset = "{:02X}".format(os.path.getsize(binPart) + HEADER_SIZE)
directive.filepartload(SCRIPT_FIRMWARE_FILE_NAME, offset, size)
print ('[i] Align')
utils.alignFile(outputChunk)
print ('[i] Append: {} -> {}'.format(outputChunk, binPart))
utils.appendFile(outputChunk, binPart)
directive.store_nuttx_config(name)
if (type == 'sboot'):
chunks = utils.splitFile(imageFile, tmpDir, chunksize = 0)
outputChunk = chunks[0]
size = "{:02X}".format(os.path.getsize(outputChunk))
offset = "{:02X}".format(os.path.getsize(binPart) + HEADER_SIZE)
directive.filepartload(SCRIPT_FIRMWARE_FILE_NAME, offset, size)
print ('[i] Align')
utils.alignFile(outputChunk)
print ('[i] Append: {} -> {}'.format(outputChunk, binPart))
utils.appendFile(outputChunk, binPart)
directive.write_boot(size, DRAM_BUF_ADDR, emptySkip)
if (type == 'inMemory'):
chunks = utils.splitFile(imageFile, tmpDir, chunksize = 0)
outputChunk = chunks[0]
size = "{:02X}".format(os.path.getsize(outputChunk))
offset = "{:02X}".format(os.path.getsize(binPart) + HEADER_SIZE)
directive.filepartload(SCRIPT_FIRMWARE_FILE_NAME, offset, size, memoryOffset=memoryOffset)
print ('[i] Align')
utils.alignFile(outputChunk)
print ('[i] Append: {} -> {}'.format(outputChunk, binPart))
utils.appendFile(outputChunk, binPart)
header.write('\n'.encode())
header.write('# Header suffix'.encode())
header.write(headerScriptSuffix.encode())
header.write('\n'.encode())
header.write('% <- this is end of file symbol\n'.encode())
header.flush()
print ('[i] Fill header script to 16KB')
header.write( ('\xff' * (HEADER_SIZE - os.path.getsize(headerPart))).encode(encoding='iso-8859-1') )
print ('[i] Generating footer ...')
if (USE_XGIMI_CRC2):
# NB XGIMI uses HEADER+BIN+MAGIC+HEADER_CRC to calculate crc2
headerCRC = utils.crc32(headerPart)
header16bytes = utils.loadPart(headerPart, 0, 16)
# Step #1. Merge HEADER+BIN+MAGIC+HEADER_CRC to one file
mergedPart = os.path.join(tmpDir, '~merged')
open(mergedPart, 'w').close()
utils.appendFile(headerPart, mergedPart)
utils.appendFile(binPart, mergedPart)
with open(mergedPart, 'ab') as part:
print ('[i] Magic: {}'.format(MAGIC_FOOTER))
part.write(MAGIC_FOOTER.encode())
print ('[i] Header CRC: 0x{:02X}'.format(headerCRC))
part.write(struct.pack('L', headerCRC))
# Step #2 Calculate CRC2
mergedCRC = utils.crc32(mergedPart)
with open(footerPart, 'wb') as footer:
print ('[i] Merged CRC: 0x{:02X}'.format(mergedCRC))
footer.write(struct.pack('L', mergedCRC))
print ('[i] First 16 bytes of header: {}'.format(header16bytes))
footer.write(header16bytes)
print ('[i] Merging parts ...')
open(firmwareFileName, 'w').close()
utils.appendFile(mergedPart, firmwareFileName)
utils.appendFile(footerPart, firmwareFileName)
else:
headerCRC = utils.crc32(headerPart)
binCRC = utils.crc32(binPart)
header16bytes = utils.loadPart(headerPart, 0, 16)
with open(footerPart, 'wb') as footer:
print ('[i] Magic: {}'.format(MAGIC_FOOTER))
footer.write(MAGIC_FOOTER.encode())
print ('[i] Header CRC: 0x{:02X}'.format(headerCRC))
footer.write(struct.pack('L', headerCRC)) # struct.pack('L', data) <- returns byte swapped data
print ('[i] Bin CRC: 0x{:02X}'.format(binCRC))
footer.write(struct.pack('L', binCRC))
print ('[i] First 16 bytes of header: {}'.format(header16bytes))
footer.write(header16bytes)
print ('[i] Merging header, bin, footer ...')
open(firmwareFileName, 'w').close()
utils.appendFile(headerPart, firmwareFileName)
utils.appendFile(binPart, firmwareFileName)
utils.appendFile(footerPart, firmwareFileName)
shutil.rmtree(tmpDir)
print ('[i] Done')

View File

@ -0,0 +1,73 @@
'''
This tool is used to sign (aka generate "secureinfo") and encrypt partition
Almost all new Mstar builds I saw have SECURITY_BOOT option enebled. Which means it uses AES to
encrypt boot.img and recovery.img and RSA to generate signature (Plus multiple internal security updates).
This script will generate two files: encrypted image and signature file
'''
import os
import sys
# Command line args
if len(sys.argv) == 1:
print ("Usage: secure_partition.py <file to encrypt> <AES key file> <RSA private key file> <RSA public key file> <output encrypted file> <output signature file>")
print ("Example: secure_partition.py ./pack/boot.img ./keys/AESbootKey ./keys/RSAboot_priv.txt ./keys/RSAboot_pub.txt ./pack/boot.img.aes ./pack/boot.signature.bin")
quit()
INPUT_FILE_NAME = sys.argv[1]
AES_KEY = sys.argv[2]
RSA_PRIVATE_KEY = sys.argv[3]
RSA_PUBLIC_KEY = sys.argv[4]
OUTPUT_FILE_NAME = sys.argv[5]
OUTPUT_SIGNATURE_FILE_NAME = sys.argv[6]
# Aditional SubSecureInfoGen params
BLOCK_SIZE_FOR_INTERLEAVE = 2097152
ENABLE_PARTIAL_AUTHENTICATION = 0 # 0 - disable, 1 - enable
NUMBER_FOR_PARTIAL_AUTHENTICATION = 8 # ???
ENABLE_INTERLEAVE_MODE = 1 # 0 - disable, 1 - enable
DISPLAY_DEBUGGING_INFO = 1 # 0 - disable, 1 - enable
# Binary tools
TOOLS_DIR = 'bin\\win32\\' if os.name == 'nt' else 'bin/linux-x86/'
alignment = os.path.join(TOOLS_DIR, 'alignment')
SubSecureInfoGen = os.path.join(TOOLS_DIR, 'SubSecureInfoGen')
aescrypt2 = os.path.join(TOOLS_DIR, 'aescrypt2')
# Alignment
os.system(alignment + ' {}'.format(INPUT_FILE_NAME))
# Generate signature
os.system(SubSecureInfoGen + ' {} {} {} {} {} {} {} {} {} {}'.format(
OUTPUT_SIGNATURE_FILE_NAME,
INPUT_FILE_NAME,
RSA_PRIVATE_KEY,
RSA_PUBLIC_KEY,
ENABLE_PARTIAL_AUTHENTICATION,
NUMBER_FOR_PARTIAL_AUTHENTICATION,
ENABLE_INTERLEAVE_MODE,
BLOCK_SIZE_FOR_INTERLEAVE,
DISPLAY_DEBUGGING_INFO,
TOOLS_DIR))
print (SubSecureInfoGen + ' {} {} {} {} {} {} {} {} {} {}'.format(
OUTPUT_SIGNATURE_FILE_NAME,
INPUT_FILE_NAME,
RSA_PRIVATE_KEY,
RSA_PUBLIC_KEY,
ENABLE_PARTIAL_AUTHENTICATION,
NUMBER_FOR_PARTIAL_AUTHENTICATION,
ENABLE_INTERLEAVE_MODE,
BLOCK_SIZE_FOR_INTERLEAVE,
DISPLAY_DEBUGGING_INFO,
TOOLS_DIR))
# Crypt input image
os.system(aescrypt2 + ' 0 {} {} {}'.format(INPUT_FILE_NAME, OUTPUT_FILE_NAME, AES_KEY))
print ("Done")

154
mstar-bin-tool/unpack.py Normal file
View File

@ -0,0 +1,154 @@
import sys
import os
import re
import shutil
import utils
DEBUG = False
HEADER_SIZE = 16 * utils.KB # Header size is always 16KB
# Vars
headerScript = ""
headerScriptFound = False
counter = {}
env = {} # Environment variables, set by setenv command
# Parse args
if len(sys.argv) == 1:
print ("Usage: unpack.py <firmware> <output folder [default: ./unpacked/]>")
quit()
inputFile = sys.argv[1]
if not os.path.exists(inputFile):
print ("No such file: {}".format(inputFile))
quit()
if len(sys.argv) == 3:
outputDirectory = sys.argv[2]
else:
outputDirectory = 'unpacked'
# Create output directory
utils.createDirectory(outputDirectory)
# Find header script
# Header size is 16KB
# Non used part is filled by 0xFF
print ("[i] Analizing header ...")
header = utils.loadPart(inputFile, 0, HEADER_SIZE)
utils.copyPart(inputFile, os.path.join(outputDirectory, "~header"), 0, HEADER_SIZE)
offset = header.find('\xff'.encode(encoding='iso-8859-1'))
if offset != -1:
headerScript = header[:offset].decode()
headerScriptFound = True
if not headerScriptFound:
print ("[!] Could not find header script!")
quit()
if DEBUG:
print (headerScript)
# Save the script
print ("[i] Saving header script to " + os.path.join(outputDirectory, "~header_script") + " ...")
with open(os.path.join(outputDirectory, "~header_script"), "w") as f:
f.write(headerScript)
# Parse script
print ("[i] Parsing script ...")
# Supporting filepartload, mmc, store_secure_info, store_nuttx_config
for line in headerScript.splitlines():
if DEBUG:
print (line)
if re.match("^setenv", line):
params = utils.processSetEnv(line)
key = params["key"]
if not "value" in params:
del env[key]
else:
value = params["value"]
env[key] = value
print ("[i] Parsing setenv {} -> {}".format(key, value))
if re.match("^filepartload", line):
line = utils.applyEnv(line, env)
params = utils.processFilePartLoad(line)
offset = params["offset"]
size = params["size"]
if re.match("^store_secure_info", line):
line = utils.applyEnv(line, env)
params = utils.processStoreSecureInfo(line)
outputFile = os.path.join(outputDirectory, params["partition_name"])
utils.copyPart(inputFile, outputFile, int(offset, 16), int(size, 16))
if re.match("^store_nuttx_config", line):
line = utils.applyEnv(line, env)
params = utils.processStoreNuttxConfig(line)
outputFile = os.path.join(outputDirectory, params["partition_name"])
utils.copyPart(inputFile, outputFile, int(offset, 16), int(size, 16))
if re.match("^mmc", line):
line = utils.applyEnv(line, env)
params = utils.processMmc(line)
if params:
# if params["action"] == "create":
# nothing here
if params["action"] == "write.boot":
outputFile = utils.generateFileName(outputDirectory, params, ".img")
utils.copyPart(inputFile, outputFile, int(offset, 16), int(size, 16))
print ("[i] Partition: {}\tOffset: {}\tSize {} ({}) -> {}".format(params["partition_name"], offset, size, utils.sizeStr(int(size, 16)), outputFile))
if params["action"] == "write.p":
outputFile = os.path.join(outputDirectory, params["partition_name"] + ".img")
utils.copyPart(inputFile, outputFile, int(offset, 16), int(size, 16))
print ("[i] Partition: {}\tOffset: {}\tSize {} ({}) -> {}".format(params["partition_name"], offset, size, utils.sizeStr(int(size, 16)), outputFile))
if params["action"] == "write.p.continue":
outputFile = os.path.join(outputDirectory, params["partition_name"] + ".img")
utils.copyPart(inputFile, outputFile, int(offset, 16), int(size, 16), append = True)
print ("[i] Partition: {}\tOffset: {}\tSize {} ({}) append to {}".format(params["partition_name"], offset, size, utils.sizeStr(int(size, 16)), outputFile))
if params["action"] == "unlzo":
outputLzoFile = utils.generateFileName(outputDirectory, params, ".lzo")
outputImgFile = utils.generateFileName(outputDirectory, params, ".img")
# save .lzo
print ("[i] Partition: {}\tOffset: {}\tSize {} ({}) -> {}".format(params["partition_name"], offset, size, utils.sizeStr(int(size, 16)), outputLzoFile))
utils.copyPart(inputFile, outputLzoFile, int(offset, 16), int(size, 16))
# unpack .lzo -> .img
print ("[i] Unpacking LZO (Please be patient) {} -> {}".format(outputLzoFile, outputImgFile))
utils.unlzo(outputLzoFile, outputImgFile)
# delete .lzo
os.remove(outputLzoFile)
if params["action"] == "unlzo.continue":
if not params["partition_name"] in counter:
counter[params["partition_name"]] = 0
counter[params["partition_name"]] += 1
outputImgFile = os.path.join(outputDirectory, params["partition_name"] + ".img")
outputChunkLzoFile = os.path.join(outputDirectory, params["partition_name"] + str(counter[params["partition_name"]]) + ".lzo")
outputChunkImgFile = os.path.join(outputDirectory, params["partition_name"] + str(counter[params["partition_name"]]) + ".img")
# save .lzo
print ("[i] Partition: {}\tOffset: {}\tSize {} ({}) -> {}".format(params["partition_name"], offset, size, utils.sizeStr(int(size, 16)), outputChunkLzoFile))
utils.copyPart(inputFile, outputChunkLzoFile, int(offset, 16), int(size, 16))
# unpack chunk .lzo -> .img
print ("[i] Unpacking LZO (Please be patient) {} -> {}".format(outputChunkLzoFile, outputChunkImgFile))
utils.unlzo(outputChunkLzoFile, outputChunkImgFile)
# append the chunk to main .img
print ("[i] {} append to {}".format(outputChunkImgFile, outputImgFile))
utils.appendFile(outputChunkImgFile, outputImgFile)
# delete chunk
os.remove(outputChunkLzoFile)
os.remove(outputChunkImgFile)

348
mstar-bin-tool/utils.py Normal file
View File

@ -0,0 +1,348 @@
import re
import os
import shutil
import string
import binascii
import math
import ctypes
B = 2**00
KB = 2**10
MB = 2**20
GB = 2**30
def sizeInt(s):
value = int(s.strip(string.ascii_letters))
unit = s.strip(string.digits)
if not unit:
unit = 'B'
return value * globals()[unit]
def sizeStr(s):
if (s == 0):
return '0B'
size_name = ('B', 'KB', 'MB', 'GB')
i = int(math.floor(math.log(s, 1024)))
p = math.pow(1024 ,i)
s = round(s / p, 2)
return '%s %s' % (s,size_name[i])
def str2bool(v):
return v.lower() in ("yes", "true", "True", "1")
def bool2int(v):
return 1 if v else 0
def getConfigValue(config, name, defValue):
try:
value = config[name]
except Exception as e:
value = defValue
return value
def createDirectory(dir):
if not os.path.exists(dir): # if the directory does not exist
os.makedirs(dir) # make the directory
else: # the directory exists
#removes all files in a folder
for the_file in os.listdir(dir):
file_path = os.path.join(dir, the_file)
try:
if os.path.isfile(file_path):
os.unlink(file_path) # unlink (delete) the file
except e:
print (e)
def splitFile(file, destdir, chunksize):
(name, ext) = os.path.splitext(os.path.basename(file))
chunks = []
# Just copy file if its size is less than chunk size
if os.path.getsize(file) < chunksize or chunksize == 0:
chunk = os.path.join(destdir, name + ext)
shutil.copyfile(file, chunk)
return [chunk]
# Split in chunks and copy
data = True
while data:
data = loadPart(file, len(chunks) * chunksize, chunksize)
if data:
chunk = os.path.join(destdir, ('%s.%04d%s' % (name, len(chunks), ext)))
chunks.append(chunk)
with open(chunk, 'wb') as f2:
f2.write(data)
assert len(chunks) <= 9999
return chunks
# Append src file to dest file
# bufsize - chunk size
def appendFile(src, dest, bufsize = 16 * MB):
with open(src, 'rb') as f1:
with open(dest, 'ab') as f2:
data = True
while data:
data = f1.read(bufsize)
f2.write(data)
# Copy part of src file to dest file.
# offset - beginning of the part to copy
# size - length of the part to copy
# bufsize - chunk size
# append - if True then append to dest file
# if dest file does not exist it will be created
def copyPart(src, dest, offset, size, bufsize = 16 * MB, append = False):
if not os.path.exists(dest):
append = False
with open(src, 'rb') as f1:
f1.seek(offset)
with open(dest, 'ab' if append else 'wb') as f2:
while size:
chunk = min(bufsize, size)
data = f1.read(chunk)
f2.write(data)
size -= chunk
# Load and return part
# file - source file
# offset - beginning of the part
# size - length of the part
def loadPart(file, offset, size):
with open(file, 'rb') as f:
f.seek(offset)
return f.read(size)
# Align file
# file - input file to align
# base - alignment base
def alignFile(file, base = 0x1000):
result = base - os.path.getsize(file) % base
if result:
with open(file, 'ab') as f:
f.write(('\xff' * result).encode(encoding='iso-8859-1'))
# unlzo
# if NT then use ./bin/lzo.exe
def unlzo(src, dest):
lzop = 'bin\\win32\\lzop.exe' if os.name == 'nt' else 'bin/linux-x86/lzop'
os.system(lzop + ' -o {} -d {}'.format(dest, src))
# lzo
# if NT then use ./bin/lzo.exe
def lzo(src, dest):
lzop = 'bin\\win32\\lzop.exe' if os.name == 'nt' else 'bin/linux-x86/lzop'
os.system(lzop + ' -o {} -1 {}'.format(dest, src))
# Calculate crc32
# file - filename of a file to calculate
def crc32(file):
buf = open(file,'rb').read()
buf = (binascii.crc32(buf) & 0xFFFFFFFF)
return buf
# Apply env variable to line, i.e.
# setenv imageSize 0x13800
# setenv imageOffset 0x4000
# filepartload 0x20200000 LetvUpgrade938.bin $(imageOffset) $(imageSize)
# So we replace it to filepartload 0x20200000 LetvUpgrade938.bin 0x4000 0x13800
def applyEnv(line, env):
keys = re.findall('\$\((\w+)\)', line)
for key in keys:
if key in env and env[key]:
line = line.replace("$({})".format(key), env[key])
return line
def processSetEnv(line):
args = re.findall('([^\s]+)\s+([^\s]+)\s*(.*)', line)
args = args[0]
if len(args) == 3:
return {'cmd': args[0], 'key': args[1], 'value': args[2]}
else:
return {'cmd': args[0], 'key': args[1]}
def parceArgs(string):
return re.findall('([^\s]+)', string)
def processFilePartLoad(line):
args = parceArgs(line)
return {'cmd': args[0], 'addr': args[1], 'sourceFile': args[2], 'offset': args[3], 'size': args[4]}
def processStoreSecureInfo(line):
args = parceArgs(line)
return {'cmd': args[0], 'partition_name': args[1], 'addr': args[2]}
def processStoreNuttxConfig(line):
args = parceArgs(line)
return {'cmd': args[0], 'partition_name': args[1], 'addr': args[2]}
def processMmc(line):
args = parceArgs(line)
if args[1] == 'create':
# mmc create [name] [size]- create/change mmc partition [name]
return {'cmd': args[0], 'action': args[1], 'partition_name': args[2], 'size': args[3]}
if args[1] == 'erase.p':
# mmc erase.p partition_name
return {'cmd': args[0], 'action': args[1], 'partition_name': args[2]}
# TODO Add support:
# mmc create.gp part_no size enh_attr ext_attr relwr_attr - create/change eMMC GP partition No.[part_no(0~3)] with size and enhance/extended/reliable_write attribute
# mmc create.enhusr start_addr size enha_attr relwr_atrr - create/change eMMC enhance user partition(slc mode) from start_addr with size and enhance/reliable_write attribute
# mmc create.complete - complete eMMC gp, enhance user, reliable write partition setting
elif args[1] == 'write.p':
# mmc write.p addr partition_name size [empty_skip:0-disable,1-enable]
res = {'cmd': args[0], 'action': args[1], 'addr': args[2], 'partition_name': args[3], 'size': args[4]}
try:
res['empty_skip'] = args[5]
except IndexError:
res['empty_skip'] = 0
return res
elif args[1] == 'write.p.continue' or args[1] == 'write.p.cont':
# mmc write.p(.continue|.cont) addr partition_name offset size [empty_skip:0-disable,1-enable]\n
res = {'cmd': args[0], 'action': 'write.p.continue', 'addr': args[2], 'partition_name': args[3], 'offset': args[4], 'size': args[5]}
try:
res['empty_skip'] = args[6]
except IndexError:
res['empty_skip'] = 0
return res
elif args[1] == 'write.boot' or args[1] == 'write':
# mmc write[.boot] bootpart addr blk# size [empty_skip:0-disable,1-enable]
res = {'cmd': args[0], 'action': args[1], 'bootpart': args[2], 'addr': args[3], 'blk#': args[4], 'size': args[5], 'partition_name': 'sboot'}
try:
res['empty_skip'] = args[6]
except IndexError:
res['empty_skip'] = 0
return res
elif args[1] == 'unlzo':
# mmc unlzo[.continue|.cont] addr size partition_name [empty_skip:0-disable,1-enable]- decompress lzo file and write to mmc partition
res = {'cmd': args[0], 'action': args[1], 'addr': args[2], 'size': args[3], 'partition_name': args[4]}
try:
res['empty_skip'] = args[5]
except IndexError:
res['empty_skip'] = 0
return res
elif args[1] == 'unlzo.continue' or args[1] == 'unlzo.cont':
# mmc unlzo[.continue|.cont] addr size partition_name [empty_skip:0-disable,1-enable]- decompress lzo file and write to mmc partition
res = {'cmd': args[0], 'action': 'unlzo.continue', 'addr': args[2], 'size': args[3], 'partition_name': args[4]}
try:
res['empty_skip'] = args[5]
except IndexError:
res['empty_skip'] = 0
return res
# else:
# print 'Unknown mmc action'
# print args
# TODO rewrite it
fileNameCounter = {}
def generateFileName(outputDirectory, part, ext):
fileName = os.path.join(outputDirectory, part['partition_name'] + ext)
if os.path.exists(fileName):
try:
fileNameCounter[part['partition_name']] += 1
except:
fileNameCounter[part['partition_name']] = 1
fileName = os.path.join(outputDirectory, part['partition_name'] + str(fileNameCounter[part['partition_name']]) + ext)
return fileName
def directive(header, dramBufAddr, useHexValuesPrefix):
def filepartload(filename, offset, size, memoryOffset=dramBufAddr):
if (useHexValuesPrefix):
header.write('filepartload 0x{} {} 0x{} 0x{}\n'.format(memoryOffset, filename, offset, size).encode())
else:
header.write('filepartload {} {} {} {}\n'.format(memoryOffset, filename, offset, size).encode())
# Create directive always uses 0x format
def create(name, size):
#if (useHexValuesPrefix):
header.write('mmc create {} 0x{}\n'.format(name, size).encode())
#else:
# header.write('mmc create {} {}\n'.format(name, size).encode())
def erase_p(name):
header.write('mmc erase.p {}\n'.format(name).encode())
# mmc unlzo[.continue|.cont] addr size partition_name [empty_skip:0-disable,1-enable]- decompress lzo file and write to mmc partition
def unlzo(name, size, memoryOffset=dramBufAddr, emptySkip = 1):
if (useHexValuesPrefix):
header.write('mmc unlzo 0x{} 0x{} {} {}\n'.format(memoryOffset, size, name, emptySkip).encode())
else:
header.write('mmc unlzo {} {} {} {}\n'.format(memoryOffset, size, name, emptySkip).encode())
# mmc unlzo[.continue|.cont] addr size partition_name [empty_skip:0-disable,1-enable]- decompress lzo file and write to mmc partition
def unlzo_cont(name, size, memoryOffset=dramBufAddr, emptySkip = 1):
if (useHexValuesPrefix):
header.write('mmc unlzo.cont 0x{} 0x{} {} {}\n'.format(memoryOffset, size, name, emptySkip).encode())
else:
header.write('mmc unlzo.cont {} {} {} {}\n'.format(memoryOffset, size, name, emptySkip).encode())
# mmc write.p addr partition_name size [empty_skip:0-disable,1-enable]
def write_p(name, size, memoryOffset=dramBufAddr, emptySkip = 1):
if (useHexValuesPrefix):
header.write('mmc write.p 0x{} {} 0x{} {}\n'.format(memoryOffset, name, size, emptySkip).encode())
else:
header.write('mmc write.p {} {} {} {}\n'.format(memoryOffset, name, size, emptySkip).encode())
# TODO Add support
# mmc write.p(.continue|.cont) addr partition_name offset size [empty_skip:0-disable,1-enable]
def store_secure_info(name, memoryOffset=dramBufAddr):
if (useHexValuesPrefix):
header.write('store_secure_info {} 0x{}\n'.format(name, memoryOffset).encode())
else:
header.write('store_secure_info {} {}\n'.format(name, memoryOffset).encode())
def store_nuttx_config(name, memoryOffset=dramBufAddr):
if (useHexValuesPrefix):
header.write('store_nuttx_config {} 0x{}\n'.format(name, memoryOffset).encode())
else:
header.write('store_nuttx_config {} {}\n'.format(name, memoryOffset).encode())
# mmc write[.boot|.gp] [bootpart|gppart] addr blk# size [empty_skip:0-disable,1-enable]
def write_boot(size, memoryOffset=dramBufAddr, emptySkip = 0):
if (useHexValuesPrefix):
header.write('mmc write.boot 1 0x{} 0 0x{} {}\n'.format(memoryOffset, size, emptySkip).encode())
else:
header.write('mmc write.boot 1 {} 0 {} {}\n'.format(memoryOffset, size, emptySkip).encode())
#####
directive.filepartload = filepartload
directive.create = create
directive.erase_p = erase_p
directive.unlzo = unlzo
directive.unlzo_cont = unlzo_cont
directive.write_p = write_p
directive.store_secure_info = store_secure_info
directive.store_nuttx_config = store_nuttx_config
directive.write_boot = write_boot
return directive
def hexString(v, delimiter = ' '):
return (delimiter.join([format(i, '02X') for i in v]))
def unpackStructure(s, b):
result = s()
ctypes.memmove(ctypes.addressof(result), b, ctypes.sizeof(s))
return result
def writeFile(file, data):
with open(file, 'wb') as f:
f.write(data)
def writeRSAPublicKey(file, key):
writeFile(file,
str.encode( "N = {}\nE = {}".format(hexString(key.N, ''), hexString(key.E, '')) ))