diff --git a/mstar-bin-tool/README.md b/mstar-bin-tool/README.md new file mode 100644 index 0000000..0bdc168 --- /dev/null +++ b/mstar-bin-tool/README.md @@ -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 + - MStar bin firmware to unpack + - directory to store unpacked stuff. Default value: ./unpacked/ +``` + + +## Pack MStar bin firmware +``` +Usage: pack.py +Example: pack.py configs/letv-x355pro-full.ini + - 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 [] [] [] +Defaults: + keys + 0x168e00 + 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 +Example: secure_partition.py ./pack/boot.img ./keys/AESbootKey ./keys/RSAboot_priv.txt ./keys/RSAboot_pub.txt ./pack/boot.img.aes ./pack/bootSign +``` diff --git a/mstar-bin-tool/__pycache__/utils.cpython-37.pyc b/mstar-bin-tool/__pycache__/utils.cpython-37.pyc new file mode 100644 index 0000000..7eadddb Binary files /dev/null and b/mstar-bin-tool/__pycache__/utils.cpython-37.pyc differ diff --git a/mstar-bin-tool/bin/win32/SubSecureInfoGen.exe b/mstar-bin-tool/bin/win32/SubSecureInfoGen.exe new file mode 100644 index 0000000..0746462 Binary files /dev/null and b/mstar-bin-tool/bin/win32/SubSecureInfoGen.exe differ diff --git a/mstar-bin-tool/bin/win32/aescrypt2.exe b/mstar-bin-tool/bin/win32/aescrypt2.exe new file mode 100644 index 0000000..c6b4139 Binary files /dev/null and b/mstar-bin-tool/bin/win32/aescrypt2.exe differ diff --git a/mstar-bin-tool/bin/win32/alignment.exe b/mstar-bin-tool/bin/win32/alignment.exe new file mode 100644 index 0000000..28c5bb2 Binary files /dev/null and b/mstar-bin-tool/bin/win32/alignment.exe differ diff --git a/mstar-bin-tool/bin/win32/lzop.exe b/mstar-bin-tool/bin/win32/lzop.exe new file mode 100644 index 0000000..076dade Binary files /dev/null and b/mstar-bin-tool/bin/win32/lzop.exe differ diff --git a/mstar-bin-tool/bin/win32/rsa_sign.exe b/mstar-bin-tool/bin/win32/rsa_sign.exe new file mode 100644 index 0000000..e7ee6ab Binary files /dev/null and b/mstar-bin-tool/bin/win32/rsa_sign.exe differ diff --git a/mstar-bin-tool/configs/LETV_USB_SCRIPT_938.ini b/mstar-bin-tool/configs/LETV_USB_SCRIPT_938.ini new file mode 100644 index 0000000..9329861 --- /dev/null +++ b/mstar-bin-tool/configs/LETV_USB_SCRIPT_938.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/dexp-madison-system.ini b/mstar-bin-tool/configs/dexp-madison-system.ini new file mode 100644 index 0000000..7d7cf5e --- /dev/null +++ b/mstar-bin-tool/configs/dexp-madison-system.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/empty-skip-example.ini b/mstar-bin-tool/configs/empty-skip-example.ini new file mode 100644 index 0000000..23eea5d --- /dev/null +++ b/mstar-bin-tool/configs/empty-skip-example.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/letv-emmc2usb.ini b/mstar-bin-tool/configs/letv-emmc2usb.ini new file mode 100644 index 0000000..2133cf7 --- /dev/null +++ b/mstar-bin-tool/configs/letv-emmc2usb.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/letv-enable-uart.ini b/mstar-bin-tool/configs/letv-enable-uart.ini new file mode 100644 index 0000000..12e5692 --- /dev/null +++ b/mstar-bin-tool/configs/letv-enable-uart.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/letv-force-bin-update.ini b/mstar-bin-tool/configs/letv-force-bin-update.ini new file mode 100644 index 0000000..720f57c --- /dev/null +++ b/mstar-bin-tool/configs/letv-force-bin-update.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/letv-x340-43-recovery-no-secure.ini b/mstar-bin-tool/configs/letv-x340-43-recovery-no-secure.ini new file mode 100644 index 0000000..afb985f --- /dev/null +++ b/mstar-bin-tool/configs/letv-x340-43-recovery-no-secure.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/letv-x355pro-full.ini b/mstar-bin-tool/configs/letv-x355pro-full.ini new file mode 100644 index 0000000..f30f0f2 --- /dev/null +++ b/mstar-bin-tool/configs/letv-x355pro-full.ini @@ -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 + diff --git a/mstar-bin-tool/configs/letv-x355pro-recovery-no-secure.ini b/mstar-bin-tool/configs/letv-x355pro-recovery-no-secure.ini new file mode 100644 index 0000000..7414b48 --- /dev/null +++ b/mstar-bin-tool/configs/letv-x355pro-recovery-no-secure.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/letv-x355pro-recovery.ini b/mstar-bin-tool/configs/letv-x355pro-recovery.ini new file mode 100644 index 0000000..92a27e0 --- /dev/null +++ b/mstar-bin-tool/configs/letv-x355pro-recovery.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/letv-x355pro-system.ini b/mstar-bin-tool/configs/letv-x355pro-system.ini new file mode 100644 index 0000000..5f95972 --- /dev/null +++ b/mstar-bin-tool/configs/letv-x355pro-system.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/letv-x4-recovery-no-secure.ini b/mstar-bin-tool/configs/letv-x4-recovery-no-secure.ini new file mode 100644 index 0000000..c9cdc17 --- /dev/null +++ b/mstar-bin-tool/configs/letv-x4-recovery-no-secure.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/letv-x4-systemless-live.ini b/mstar-bin-tool/configs/letv-x4-systemless-live.ini new file mode 100644 index 0000000..e790e02 --- /dev/null +++ b/mstar-bin-tool/configs/letv-x4-systemless-live.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/letv-x450pro-system.ini b/mstar-bin-tool/configs/letv-x450pro-system.ini new file mode 100644 index 0000000..e3b375b --- /dev/null +++ b/mstar-bin-tool/configs/letv-x450pro-system.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/tcl-s68at02-system.ini b/mstar-bin-tool/configs/tcl-s68at02-system.ini new file mode 100644 index 0000000..0752f79 --- /dev/null +++ b/mstar-bin-tool/configs/tcl-s68at02-system.ini @@ -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 \ No newline at end of file diff --git a/mstar-bin-tool/configs/xgimi.ini b/mstar-bin-tool/configs/xgimi.ini new file mode 100644 index 0000000..2cb3acd --- /dev/null +++ b/mstar-bin-tool/configs/xgimi.ini @@ -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 diff --git a/mstar-bin-tool/default_keys/AESboot.bin b/mstar-bin-tool/default_keys/AESboot.bin new file mode 100644 index 0000000..d9b0420 Binary files /dev/null and b/mstar-bin-tool/default_keys/AESboot.bin differ diff --git a/mstar-bin-tool/default_keys/AESupgrade.bin b/mstar-bin-tool/default_keys/AESupgrade.bin new file mode 100644 index 0000000..d9b0420 Binary files /dev/null and b/mstar-bin-tool/default_keys/AESupgrade.bin differ diff --git a/mstar-bin-tool/default_keys/README.md b/mstar-bin-tool/default_keys/README.md new file mode 100644 index 0000000..6e2fe7e --- /dev/null +++ b/mstar-bin-tool/default_keys/README.md @@ -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. \ No newline at end of file diff --git a/mstar-bin-tool/default_keys/RSAboot_priv.txt b/mstar-bin-tool/default_keys/RSAboot_priv.txt new file mode 100644 index 0000000..b6facfd --- /dev/null +++ b/mstar-bin-tool/default_keys/RSAboot_priv.txt @@ -0,0 +1,8 @@ +N = AA5E3FDAD01DDF4AFAFE67A1B53BBB8B931FECBAAC0F0C0ED61A66EC04C416E5A4A69AAFEFB6EE7DA3E7A559E4006BC5FCE979B28B8E81136C8AB6CC11D9A7CEA83C7A431835D04DA6AE40CD4D0414F6CA3D5EF2274EF38C8A6FBC6AC4CCD123FBCA638ABBC40514A998127671F3A36EA8B207E40E169BF75EC41915BE3A9EF2309A7661681191D6AC2C22AA46194DE8C712B7EFCE29D38BB920955C0E5A26FCF9651F568F3CDB6085364A2A357D94BDCFD0CF6C615064B12A9A7DA2AC03EC254899E013B4864E6815653206823F02BE4C0D594B4CF6548238AA0947A31A8BA1D1F8CC0911158FFD4C01460C6FF78DB822E4872851F6C0097CEAD15C46B4FB4B +E = 010001 +D = 2D26E7737D7EBD4428FB2DC9FCB745003BD0D533B01018D901C3638D9FC1BC73C64C6568C5764D04BD60D240DD9D82F2A911D3B00F2E8864F67A58F202B515B53E7F30C4017199B04AC199E90F454AAD11726C6C6F208C89ADD2E933BECEAD8B04DB61C04DFD287F8E670055A5E3B567C98BCD6D92924969A912FDB6F680A0C90E7F0899436880FC66CC7E1399E11263497A42011BE8BE9B1C003F956448C425F4A8138D9DD3B6B735474A6CB7AC5A39CC0EDE5ED74D2DD7A9CCC681B58741D4DDA496B9C0DE1EF367B6709E2488A4B2915F1CCF92CD563C25D1CBF5D719F100D2A4C1DDAC1F49EB092100F9A2276289CFB9990C7AB7D11D2D40685D165C3849 +P = D623430C4E6C9BBC5D306EBEEAA0724F0847BB7E679E7E5B3EBDF21CE642C4296422824335A488D80A6DF3B24069BBEB10D4BC331DCC2C015717F934BF0B777B96166928FB355CBB27CB383E2F2FB499B8DBDE2425FEA7A134737A0964ECA25DFE304539EBC3BBD31128FB2B295DC1FA2C5968A7969A94E37287F2A31BC56F37 +Q = CBAC7EB7B047868F65C5681253DF2451287E06F60D4D683467876AD8A27EE0514F0B29A8E667D690BBC6164B977FCBD241663F71D6238838632D9DE057DF4E4BB349BA0FF213DA9DB8F89BFD83D1B902F45B5A028094D22947CE7A06437D12820412FAE2ECF1A4606C92C844E8AB624844DFEA573B0627A047969830BBD8168D +DP = 0A863F245AB261D1172F6B31FCEC17D2249109F90374B9B718555391F20B3402E8C5FD6AFA36F4F6D1446826C99DA8BBBBDF08C4E6610384A958274A5D5D5DE8F80E6FEAB0B605B1B919F6D0AF9703A44E7E97E364EEA824772479C9FE68D6EE11B123A5DE1D879CAF0A3995FC797C30247FDC71E827FECB52F4B58B28B1426F +DQ = 6C5D61AA70030E47FB78F5AF52AA95D30C7D494CDEB501AD682BF7A03D8CCDE2D4F07680E3DDF99E5619C5C10061415BA3EA37F5645ED15A57026D4E70D262010AEA3E31BFB5EA8A22613BF5BD8DF726E8463674C05EEE16829B0BF78B2EDF8B0789E5AC992ED42B6D79074F0A902D21906BA66E34FC485711DFC127A4BA0AFD +QP = 2848FD5806119A589490ADDD419167BA952E38CBF6EF11B4B39D36156F2BE6B72372A04270D0ABFF2628F3A1E32BE9FF2C89323CABA492248FBF559E7068541E0A9238E4A61A9A5A9A77F53246693ACB12BDC3C94F83A7C6F379483E2F3CB450D3DE8FD26F7A2B1B8858C3621C7E22E0470ED225563F919658A125ECD7A0BA16 diff --git a/mstar-bin-tool/default_keys/RSAboot_pub.bin b/mstar-bin-tool/default_keys/RSAboot_pub.bin new file mode 100644 index 0000000..55c99f2 Binary files /dev/null and b/mstar-bin-tool/default_keys/RSAboot_pub.bin differ diff --git a/mstar-bin-tool/default_keys/RSAboot_pub.txt b/mstar-bin-tool/default_keys/RSAboot_pub.txt new file mode 100644 index 0000000..f0f0bcf --- /dev/null +++ b/mstar-bin-tool/default_keys/RSAboot_pub.txt @@ -0,0 +1,2 @@ +N = AA5E3FDAD01DDF4AFAFE67A1B53BBB8B931FECBAAC0F0C0ED61A66EC04C416E5A4A69AAFEFB6EE7DA3E7A559E4006BC5FCE979B28B8E81136C8AB6CC11D9A7CEA83C7A431835D04DA6AE40CD4D0414F6CA3D5EF2274EF38C8A6FBC6AC4CCD123FBCA638ABBC40514A998127671F3A36EA8B207E40E169BF75EC41915BE3A9EF2309A7661681191D6AC2C22AA46194DE8C712B7EFCE29D38BB920955C0E5A26FCF9651F568F3CDB6085364A2A357D94BDCFD0CF6C615064B12A9A7DA2AC03EC254899E013B4864E6815653206823F02BE4C0D594B4CF6548238AA0947A31A8BA1D1F8CC0911158FFD4C01460C6FF78DB822E4872851F6C0097CEAD15C46B4FB4B +E = 010001 diff --git a/mstar-bin-tool/default_keys/RSAimage_priv.txt b/mstar-bin-tool/default_keys/RSAimage_priv.txt new file mode 100644 index 0000000..296204b --- /dev/null +++ b/mstar-bin-tool/default_keys/RSAimage_priv.txt @@ -0,0 +1,8 @@ +N = 846276CCBD5A5A4030C096408728DB85EDED9F3EDE4E65E67B1B7817879DF616C3D327BCB45A031335B0965A9641744EB9D17796F78DE2E71509659C4679EAF0916735FA694C83F7DCCF9720F2A5BA72809D557917DC6E60A5E70E9E899B460652FC645602089A9641E24FDBB660C338DFF497815D1202AE2B9F0929B99D5145D29E2BAF64CA9A064E943567F78E047B2438A0DFE75F1E6D298E30D7838CB441D2FDBF5B18CA50D127D1F67D543E805F20DC8882CFBEE1462AD663B9B99DA3C7683E48CE6A626FD16AC3B6DEF33925ECF67920B5F230256E99AE3956DAAF83D6B849157881CC3C4F665D957E31D4372ABEFCB466F891010A533C3CAB86B980B7 +E = 010001 +D = 73A17978CD6F8CE30272450AE9C383331125FB713345B0F5C6D3B06A84F7310AA352DD23933807F59070C4732D48D0A92EDECA211FEB5BA451989A9B0C67D310FB3FF642DA148E344237441EF032578F49CDA2E99930DD6C279C910562D6302CB7F162464992704C0C11FB84C260F443CA41DECF8C967DA6D9CD1878CC7A9F902474E2A938933D2B51C8EF06D46019EA213379F648938A953C128F458D421E0E862144BE86FA877F6840F6CFF36EAC3E64AB682DAAE8AE194669E2B3E200E2C6E775143CB13A45D11845883F4BD06C6420BABD384269AA087A3A98DDF94574F5D78E2BAD671D42572E488522F0C91F7742C2285C8EE20C3DE3B060D1AA9987E1 +P = CE85599F5EB3800196192D5B9127499ACF77F94ECE68726DE24D708066728903430C240F175901999A522AE1420DA9C662BA0DC7AAC710B53C24EF7F365FFBDDBD8A919196172EB7B12BEB06472A9EFF1393BD400E1B62AF5AD0FE8740DDFC6DEF970CE8F4481387B0EEDBBB2310BA3E97B71F5F7022722B0BCAD2E03D3A8727 +Q = A41A13A32F07E49890E8E65FC5D1D51F54746623DF195A4F46006C15913A55F5A92534FE1C59F2FF2FCBFA74B82AF69A8709DD85512B58EF9D5EE3705990D7F548D0BDD1333BD0F229F097DCDB96909AC2FE033157E10F7F677E52317DCC671E744E4104ECF6705C0D521FD08BCAA593C29690436C4C9BFE68FCCDC72CE0B3F1 +DP = 2C3FD2361D7A6460F2A22E5FC23822C332D4C7EC24B9A85AF6F414B8CE3A9834C4B6E33B008BA7961BC4A33F6481BCF0AED2A285378833824182C07607568586BB47E76CC435EF6298698A8FEBCBAC09874E4E6C5D196D099971D23774A49BA38A8458D5C911706DD0713D4F59720A15C3380F56C995F7D455507DE261FC1A5D +DQ = 5E61B51BACC8105D03334094A2D4FD8BC86A2DF8C1AEF63713DED84B4B3CCF05BCA3EEA79C2CCBCAA375E0F5D29ABB3CC320146D41F2F972CF032D328800FB8452BDE3FE774616F5C0D364B49D032AE627F22A69EDCE3EB89B10973B69CBEF1F1FEB860FCC2E2D0F7485E05074A637B7153ABD7C59C4720FCFD85E8E08ACB031 +QP = 8310683F28ECBE7F437A6B64A489F5A8B0114A4FC41BEEB6672AF677A9D5B64FACE2E35CC5D59D6C42D4BE6ED8633203E51F8BCA8EA9BDF41B2B87238F988BAC02BD8A11C96BC90BF435749CAE8FCC7E9B37A37AD57218D6CCA127B882FB0015F59DFD87FB994518305DFFCC1C692AE796E04967B31723506F8B29FAD24DE15E diff --git a/mstar-bin-tool/default_keys/RSAimage_pub.bin b/mstar-bin-tool/default_keys/RSAimage_pub.bin new file mode 100644 index 0000000..bac1eb9 Binary files /dev/null and b/mstar-bin-tool/default_keys/RSAimage_pub.bin differ diff --git a/mstar-bin-tool/default_keys/RSAimage_pub.txt b/mstar-bin-tool/default_keys/RSAimage_pub.txt new file mode 100644 index 0000000..28ed0b1 --- /dev/null +++ b/mstar-bin-tool/default_keys/RSAimage_pub.txt @@ -0,0 +1,2 @@ +N = 846276CCBD5A5A4030C096408728DB85EDED9F3EDE4E65E67B1B7817879DF616C3D327BCB45A031335B0965A9641744EB9D17796F78DE2E71509659C4679EAF0916735FA694C83F7DCCF9720F2A5BA72809D557917DC6E60A5E70E9E899B460652FC645602089A9641E24FDBB660C338DFF497815D1202AE2B9F0929B99D5145D29E2BAF64CA9A064E943567F78E047B2438A0DFE75F1E6D298E30D7838CB441D2FDBF5B18CA50D127D1F67D543E805F20DC8882CFBEE1462AD663B9B99DA3C7683E48CE6A626FD16AC3B6DEF33925ECF67920B5F230256E99AE3956DAAF83D6B849157881CC3C4F665D957E31D4372ABEFCB466F891010A533C3CAB86B980B7 +E = 010001 diff --git a/mstar-bin-tool/default_keys/RSAupgrade_priv.txt b/mstar-bin-tool/default_keys/RSAupgrade_priv.txt new file mode 100644 index 0000000..25e05ea --- /dev/null +++ b/mstar-bin-tool/default_keys/RSAupgrade_priv.txt @@ -0,0 +1,8 @@ +N = 9BA7D26B0F3AACB837807CED2A87D54C974976E967EBBEAAB297E3A4ED0C2491896DF16319698CC4323CC8ECFD8CA209BDE194D3BEB38458D7A2C859C717826DB7688245340323953CFF94F9EE8363DFF854E22C6A7F41FC2B545B2291051CCCB09A33742D6DC02FA49723D2B481EA8C679911671565E14F65534240012C642683F98976102A4AF6E06FE130028689BA2372349CAC3E35D4CE46055C234EF4EAC4DF9636FFA8A46276DFC3EC78EE7AFF6E05236E4574AB5D15EBD2DE86A4C96E90F1F9CC00F048EDCFFBC33500251BF669F5A4F00F5437C2E4B6BAD492154FF48F420A8C7E149161A3F11F3BEB680EE394182FD3484479EA224420CC1EBCA391 +E = 010001 +D = 705CD4439E69BFB6F7B1D3FCAC800394D77D1BCEDFCAC907960699393C3950C892898000069F30138D245DF2DE1140038243AE58B0480C98C988E3D2132B40670D47EF0A1FC2C853FA0591B85DDA1125E3B0FAD80F44B0106602EE0AE4DEE8EC45EBFA8ABA2488E09B92D3344E439E5A1E8ADB8A2B6331234C44AF055F13797342E9EC86139836A825C61E63C93A6EB39ED9F8463DC914D223AF45CE8E4D80491EBC78C4E253FC0B51A5F83AADD4CB9D48A66508D82F6E54245B48FF95DEC41E17541FDFEFDAEB1F72B0E9B31E810560A06E483D2DE2A242D2D5FE52C3FF09F21CE35E99217D501C621D0CCCEB78B17BEA403C447909684577C22B364FFC0BA5 +P = F1056953D2E8AD64BB8FDF24B781F5D1CA961DC9A46786625F7AD3E3CDF50DACD005B903ADC4C16C2726A80530E15C66FE75901A218B05FC7282C8BC7DB5316CB8A9102AD0623A73B679FABD21A973C8340412EC3C04EF8818A2C35E61370DE145D5513C3B93F234C4D57318FC45E6D073D6AC9DFAB38F5B023104268A106D2B +Q = A55443B7CF7E48EE8CA0E9813350C4AF25BB302CC1025DEFB8C356C11E8A5E5702A57F306F675C7C68A971B34FC805651915EEC594863BC4CEAE7F09B4EB51A81354BD8F6BAF299F84F1EDC324C4CE7FD5B49242E8ADFE812B73B389293397F36639E097481F4EEF0AA39D25C3417E44565197876AB367E0E4EE8DC4195AAC33 +DP = CC5CCB474110FB5CEB507D637399E566424170F675C9360019775B4CD0689574CF59DADB8CAEC556C0079DF5F0D155791B0F71E54645CC0896CBE00B3B07B4E5BBD9D614876692AB64B11EF2D92506405E228A2CF66334FB0FF08A796F32B0392FEE45182E682EB9A1A05F1C73638DE7782131722E8DABE2FE03B3C23DD4D9CB +DQ = 906D1B372090FE5F3E0477D7C11F46A286C08E661A39DA1BC779057971178930538485A6A73B5124F13D4CB14AF9BE14C22451D0D25DAD2AD12EC8958F319EC4C81657FE4920DCA898B7CB6F94D844589234CB2C9E1D195E77B9FC55CEE35E5367B319CAAE5B8355F92252EEA132BE7E2E35DABC966EA1496A54270DEEE431D7 +QP = B7752EE6E5694BA1159CE9837FEAE2F9584F94DF50094A737771AD0D70F3295B3FF4D3EFCD8374999768976092E73D214B9F93B9FC1718BE886652EBF9289D02072C1177D94FBE7BEC3C0170BDB6D17B94EF84550C8FB1688AA3A8450BCE20B0ED0762903B740B7FEC56E8C5BAD166153515AB9489BEAD94493720CE67B13DF2 diff --git a/mstar-bin-tool/default_keys/RSAupgrade_pub.bin b/mstar-bin-tool/default_keys/RSAupgrade_pub.bin new file mode 100644 index 0000000..c42d7cc Binary files /dev/null and b/mstar-bin-tool/default_keys/RSAupgrade_pub.bin differ diff --git a/mstar-bin-tool/default_keys/RSAupgrade_pub.txt b/mstar-bin-tool/default_keys/RSAupgrade_pub.txt new file mode 100644 index 0000000..f532e68 --- /dev/null +++ b/mstar-bin-tool/default_keys/RSAupgrade_pub.txt @@ -0,0 +1,2 @@ +N = 9BA7D26B0F3AACB837807CED2A87D54C974976E967EBBEAAB297E3A4ED0C2491896DF16319698CC4323CC8ECFD8CA209BDE194D3BEB38458D7A2C859C717826DB7688245340323953CFF94F9EE8363DFF854E22C6A7F41FC2B545B2291051CCCB09A33742D6DC02FA49723D2B481EA8C679911671565E14F65534240012C642683F98976102A4AF6E06FE130028689BA2372349CAC3E35D4CE46055C234EF4EAC4DF9636FFA8A46276DFC3EC78EE7AFF6E05236E4574AB5D15EBD2DE86A4C96E90F1F9CC00F048EDCFFBC33500251BF669F5A4F00F5437C2E4B6BAD492154FF48F420A8C7E149161A3F11F3BEB680EE394182FD3484479EA224420CC1EBCA391 +E = 010001 diff --git a/mstar-bin-tool/docs/Introduction to MBoot.doc b/mstar-bin-tool/docs/Introduction to MBoot.doc new file mode 100644 index 0000000..ac300bc Binary files /dev/null and b/mstar-bin-tool/docs/Introduction to MBoot.doc differ diff --git a/mstar-bin-tool/extract_keys.py b/mstar-bin-tool/extract_keys.py new file mode 100644 index 0000000..97dca4a --- /dev/null +++ b/mstar-bin-tool/extract_keys.py @@ -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 [] [] []") + print ("Defaults: ") + print (" keys") + print (" 0x168e00") + print (" 0x450") + #print (" 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") \ No newline at end of file diff --git a/mstar-bin-tool/pack.py b/mstar-bin-tool/pack.py new file mode 100644 index 0000000..4295c3f --- /dev/null +++ b/mstar-bin-tool/pack.py @@ -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 ") + 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') diff --git a/mstar-bin-tool/secure_partition.py b/mstar-bin-tool/secure_partition.py new file mode 100644 index 0000000..798b17c --- /dev/null +++ b/mstar-bin-tool/secure_partition.py @@ -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 ") + 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") \ No newline at end of file diff --git a/mstar-bin-tool/unpack.py b/mstar-bin-tool/unpack.py new file mode 100644 index 0000000..329aae4 --- /dev/null +++ b/mstar-bin-tool/unpack.py @@ -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 ") + 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) + + + + diff --git a/mstar-bin-tool/utils.py b/mstar-bin-tool/utils.py new file mode 100644 index 0000000..9c13ea4 --- /dev/null +++ b/mstar-bin-tool/utils.py @@ -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, '')) )) \ No newline at end of file