Files
rkbin/tools/boot_merger.py
liuyi adfba59723 tools: boot_merger: update to v1.3
1.change loader format
2.support to generate sha512 hash

Signed-off-by: liuyi <liuyi@rock-chips.com>
Change-Id: I0f25a6f2c93340e265abec1037da07c961edc742
2020-11-19 15:25:44 +08:00

1058 lines
47 KiB
Python

# -*- coding: utf-8 -*-
"""
name: boot_merger
date:2018.02.25
author: seth
description: pack and unpack loader
usage of generating loader:
boot_merger pack <--chip> <--loader_ver> <--471_entry 1..n> <--472_entry 1..n> <--loader_data> <--loader_code> [--rc4_off] <--output>
arguments:
--chip chip id e.g. RK3399,RK330D
--loader_ver loader version xx.xx
--entry_471 471 entrys ddr.bin
--entry_472 472 entrys usbplug.bin
--loader_data flashdata.bin
--loader_code flashboot.bin
--rc4_off loader data and code without rc4 encryption [option]
--output path of new rk loader
boot_merger pack <inifile>
inifile format:
[CHIP_NAME]
NAME=RK330A
[VERSION]
MAJOR=1
MINOR=0
[CODE471_OPTION]
NUM=1
Path1=ddr.bin
[CODE472_OPTION]
NUM=1
Path1=usbplug.bin
[LOADER_OPTION]
NUM=2
FlashData=FlashData.bin
FlashBoot=FlashBoot.bin
[OUTPUT]
PATH=RK3026Loader.bin
[FLAG]
RC4_OFF=
usage of unpacking loader:
boot_merger unpack <--loader> <--output>
arguments:
--loader rk loader
--output output dir for saving files
"""
import argparse, sys, os, struct, datetime, io, platform, re, configparser, string,subprocess
import numpy as np
from timeit import default_timer as timer
from rk_mod import crc32,rc4
from Crypto.Hash import SHA256,SHA512
# from crcmod import crc32
# from crcmod import rc4
APP_VERSION = '%(prog)s v1.3'
RKNONE_DEVICE = 0
RK27_DEVICE = 0x10
RKCAYMAN_DEVICE = 0x11
RK28_DEVICE = 0x20
RK281X_DEVICE = 0x21
RKPANDA_DEVICE = 0x22
RKNANO_DEVICE = 0x30
RKSMART_DEVICE = 0x31
RKCROWN_DEVICE = 0x40
RK29_DEVICE = 0x50
RK292X_DEVICE = 0x51
RK30_DEVICE = 0x60
RK30B_DEVICE = 0x61
RK31_DEVICE = 0x70
RK32_DEVICE = 0x80
SECTOR_SIZE = 512
PAGE_SIZE = 2048
ENTRY471 = 1
ENTRY472 = 2
ENTRYLOADER = 4
NEW_IDB_SMALL = '<I4sII8s8s88sIIII8s64sIIII8s64sIIII8s64sIIII8s64s40s'
NEW_IDB = NEW_IDB_SMALL + '512s16s32s464s512s'
def align(size, unit):
size = size + unit - 1
size = size & (~(unit - 1))
return size
# CRC32_FACTOR = 0x04C10DB7
# gTable_Crc32 =[
# 0x00000000, 0x04c10db7, 0x09821b6e, 0x0d4316d9,
# 0x130436dc, 0x17c53b6b, 0x1a862db2, 0x1e472005,
# 0x26086db8, 0x22c9600f, 0x2f8a76d6, 0x2b4b7b61,
# 0x350c5b64, 0x31cd56d3, 0x3c8e400a, 0x384f4dbd,
# 0x4c10db70, 0x48d1d6c7, 0x4592c01e, 0x4153cda9,
# 0x5f14edac, 0x5bd5e01b, 0x5696f6c2, 0x5257fb75,
# 0x6a18b6c8, 0x6ed9bb7f, 0x639aada6, 0x675ba011,
# 0x791c8014, 0x7ddd8da3, 0x709e9b7a, 0x745f96cd,
# 0x9821b6e0, 0x9ce0bb57, 0x91a3ad8e, 0x9562a039,
# 0x8b25803c, 0x8fe48d8b, 0x82a79b52, 0x866696e5,
# 0xbe29db58, 0xbae8d6ef, 0xb7abc036, 0xb36acd81,
# 0xad2ded84, 0xa9ece033, 0xa4aff6ea, 0xa06efb5d,
# 0xd4316d90, 0xd0f06027, 0xddb376fe, 0xd9727b49,
# 0xc7355b4c, 0xc3f456fb, 0xceb74022, 0xca764d95,
# 0xf2390028, 0xf6f80d9f, 0xfbbb1b46, 0xff7a16f1,
# 0xe13d36f4, 0xe5fc3b43, 0xe8bf2d9a, 0xec7e202d,
# 0x34826077, 0x30436dc0, 0x3d007b19, 0x39c176ae,
# 0x278656ab, 0x23475b1c, 0x2e044dc5, 0x2ac54072,
# 0x128a0dcf, 0x164b0078, 0x1b0816a1, 0x1fc91b16,
# 0x018e3b13, 0x054f36a4, 0x080c207d, 0x0ccd2dca,
# 0x7892bb07, 0x7c53b6b0, 0x7110a069, 0x75d1adde,
# 0x6b968ddb, 0x6f57806c, 0x621496b5, 0x66d59b02,
# 0x5e9ad6bf, 0x5a5bdb08, 0x5718cdd1, 0x53d9c066,
# 0x4d9ee063, 0x495fedd4, 0x441cfb0d, 0x40ddf6ba,
# 0xaca3d697, 0xa862db20, 0xa521cdf9, 0xa1e0c04e,
# 0xbfa7e04b, 0xbb66edfc, 0xb625fb25, 0xb2e4f692,
# 0x8aabbb2f, 0x8e6ab698, 0x8329a041, 0x87e8adf6,
# 0x99af8df3, 0x9d6e8044, 0x902d969d, 0x94ec9b2a,
# 0xe0b30de7, 0xe4720050, 0xe9311689, 0xedf01b3e,
# 0xf3b73b3b, 0xf776368c, 0xfa352055, 0xfef42de2,
# 0xc6bb605f, 0xc27a6de8, 0xcf397b31, 0xcbf87686,
# 0xd5bf5683, 0xd17e5b34, 0xdc3d4ded, 0xd8fc405a,
# 0x6904c0ee, 0x6dc5cd59, 0x6086db80, 0x6447d637,
# 0x7a00f632, 0x7ec1fb85, 0x7382ed5c, 0x7743e0eb,
# 0x4f0cad56, 0x4bcda0e1, 0x468eb638, 0x424fbb8f,
# 0x5c089b8a, 0x58c9963d, 0x558a80e4, 0x514b8d53,
# 0x25141b9e, 0x21d51629, 0x2c9600f0, 0x28570d47,
# 0x36102d42, 0x32d120f5, 0x3f92362c, 0x3b533b9b,
# 0x031c7626, 0x07dd7b91, 0x0a9e6d48, 0x0e5f60ff,
# 0x101840fa, 0x14d94d4d, 0x199a5b94, 0x1d5b5623,
# 0xf125760e, 0xf5e47bb9, 0xf8a76d60, 0xfc6660d7,
# 0xe22140d2, 0xe6e04d65, 0xeba35bbc, 0xef62560b,
# 0xd72d1bb6, 0xd3ec1601, 0xdeaf00d8, 0xda6e0d6f,
# 0xc4292d6a, 0xc0e820dd, 0xcdab3604, 0xc96a3bb3,
# 0xbd35ad7e, 0xb9f4a0c9, 0xb4b7b610, 0xb076bba7,
# 0xae319ba2, 0xaaf09615, 0xa7b380cc, 0xa3728d7b,
# 0x9b3dc0c6, 0x9ffccd71, 0x92bfdba8, 0x967ed61f,
# 0x8839f61a, 0x8cf8fbad, 0x81bbed74, 0x857ae0c3,
# 0x5d86a099, 0x5947ad2e, 0x5404bbf7, 0x50c5b640,
# 0x4e829645, 0x4a439bf2, 0x47008d2b, 0x43c1809c,
# 0x7b8ecd21, 0x7f4fc096, 0x720cd64f, 0x76cddbf8,
# 0x688afbfd, 0x6c4bf64a, 0x6108e093, 0x65c9ed24,
# 0x11967be9, 0x1557765e, 0x18146087, 0x1cd56d30,
# 0x02924d35, 0x06534082, 0x0b10565b, 0x0fd15bec,
# 0x379e1651, 0x335f1be6, 0x3e1c0d3f, 0x3add0088,
# 0x249a208d, 0x205b2d3a, 0x2d183be3, 0x29d93654,
# 0xc5a71679, 0xc1661bce, 0xcc250d17, 0xc8e400a0,
# 0xd6a320a5, 0xd2622d12, 0xdf213bcb, 0xdbe0367c,
# 0xe3af7bc1, 0xe76e7676, 0xea2d60af, 0xeeec6d18,
# 0xf0ab4d1d, 0xf46a40aa, 0xf9295673, 0xfde85bc4,
# 0x89b7cd09, 0x8d76c0be, 0x8035d667, 0x84f4dbd0,
# 0x9ab3fbd5, 0x9e72f662, 0x9331e0bb, 0x97f0ed0c,
# 0xafbfa0b1, 0xab7ead06, 0xa63dbbdf, 0xa2fcb668,
# 0xbcbb966d, 0xb87a9bda, 0xb5398d03, 0xb1f880b4]
RK_LOADER_ENTRY_FORMAT = ('<B' # struct size
'i' # entry type
'20H' # name wstring
'3I') # offset,size,delay
BOOT_TAG = 0x544F4F42
LDR_FORMAT_VER = 0x1000000
LDR_TAG = 0x2052444C
SECURE_TAG = 0x4B415352
RK_LOADER_HEAD_FORMAT = ('<I' # tag:BOOT
'H' # struct size
'2I' # version
'7s' # release time
'i' # support chip
'B' # 471 count
'I' # 471 offset
'B' # 471 entry size
'B' # 472 count
'I' # 472 offset
'B' # 472 entry size
'B' # loader count
'I' # loader offset
'B' # loader entry size
'3B' # sign flag,rc4 flag,471 rc4 flag
'56s') #reserved
# def do_crc32(buf,size):
# crc = 0
# for data in buf[0:size]:
# crc = ((crc << 8) & 0xFFFFFF00) ^ gTable_Crc32[((crc >> 24) & 0xFF) ^ data]
# return crc
# def rc4(buf):
# size = len(buf)
# buf = bytearray(buf)
# key = np.uint8([124, 78, 3, 4, 85, 5, 9, 7, 45, 44, 123, 56, 23, 13, 23, 17])
# S = np.zeros(256, dtype=np.uint8)
# K = np.zeros(256, dtype=np.uint8)
# t = np.uint8(0)
# i = j = x = 0
# for i in range(256):
# S[i] = np.uint8(i)
# j = j & 0xF
# K[i] = key[j]
# j = j + 1
#
# j = 0
# for i in range(256):
# j = (j + S[i] + K[i]) % 256
# t = S[i]
# S[i] = S[j]
# S[j] = t
#
# i = j = 0
# for x in range(size):
# i = (i + 1) % 256
# j = (j + S[i]) % 256
# S[i],S[j] = S[j],S[i]
# # t = S[i]
# # S[i] = S[j]
# # S[j] = t
# t = (S[i] + (S[j] % 256)) % 256
# buf[x] = np.uint8(buf[x]) ^ S[t]
# return buf
def usage():
print("boot_merger is a tool for generating rkloader and extracting sources from rkloader")
print("generate rkloader: boot_merger pack [args..] //input \'boot_merger pack --help\' to get details")
print("extract rkloader: boot_merger unpack [args..] //input \'boot_merger unpack --help\' to get details")
print("change version: boot_merger change_ver [args..] //change loader version")
print("insert CA: boot_merger ins_cert [args..] //insert CA cert into flashhead part")
print("delete CA: boot_merger del_cert [args..] //delete CA cert from flashhead part")
def do_sha256(message, digest, init=None):
try:
sha_obj = init
if sha_obj is None:
sha_obj = SHA256.new()
blk_size = sha_obj.block_size
msg_size = len(message)
update_size = 0
pos = 0
while msg_size > 0 :
if msg_size >= blk_size:
update_size = blk_size
else:
update_size = msg_size
sha_obj.update(message[pos:pos+update_size])
pos += update_size
msg_size -= update_size
digest[:] = sha_obj.digest()
return True
except Exception as e:
print("error:%s" % str(e))
return False
def do_sha512(message, digest, init=None):
try:
sha_obj = init
if sha_obj is None:
sha_obj = SHA512.new()
blk_size = sha_obj.block_size
msg_size = len(message)
update_size = 0
pos = 0
while msg_size > 0 :
if msg_size >= blk_size:
update_size = blk_size
else:
update_size = msg_size
sha_obj.update(message[pos:pos+update_size])
pos += update_size
msg_size -= update_size
digest[:] = sha_obj.digest()
return True
except Exception as e:
print("error:%s" % str(e))
return False
def create_new_idblock(in_files,keep_cert,hash_type,out_image):
idb_size = struct.calcsize(NEW_IDB)
idb = bytearray(idb_size)
idb_list = list(struct.unpack(NEW_IDB, idb))
idb_list[0] = 0x534E4B52 # RKNS
idb_list[2] = len(in_files) << 16
idb_list[2] += 384
if hash_type.upper() == 'SHA256':
idb_list[3] += 1
elif hash_type.upper() == 'SHA512':
idb_list[3] += 2
if not keep_cert:
image_offset = 4
else:
image_offset = 8
file_data_list = list()
for i, file in enumerate(in_files):
file_size = os.path.getsize(file)
image_sector = align(file_size, PAGE_SIZE) // SECTOR_SIZE
idb_list[7 + i * 6] = (image_sector << 16) + image_offset
idb_list[8 + i * 6] = 0xFFFFFFFF
idb_list[10 + i * 6] = i + 1
idb_list[12 + i * 6] = bytearray(idb_list[12 + i * 6])
with open(file, 'rb') as fin:
file_data = bytearray(fin.read())
file_data = file_data.ljust(image_sector * SECTOR_SIZE, b'\0')
file_data_list.append(file_data)
if hash_type.upper() == 'SHA256':
digest = bytearray(32)
do_sha256(file_data, digest)
idb_list[12 + i * 6][0:32] = digest
elif hash_type.upper() == 'SHA512':
do_sha512(file_data, idb_list[12 + i * 6])
image_offset += image_sector
idb = bytearray(struct.pack(NEW_IDB, *idb_list))
digest = bytearray(64)
if hash_type.upper() == 'SHA256':
do_sha256(idb[:-512], digest)
elif hash_type.upper() == 'SHA512':
do_sha512(idb[:-512], digest)
idb[-512:-512 + len(digest)] = digest
with open(out_image, 'wb') as fout:
fout.write(idb)
def convert_chip(chip):
value = np.int32(0)
chip_string = "".join(chip)
if (len(chip_string) < 4) or (len(chip_string) > 6):
return -1
head = chip_string[0:2]
if (head.lower() != "rk") and (head.lower() != "rv"):
return -1
chip_string = chip_string[2:]
if chip_string.lower() == "28":
value = RK28_DEVICE
elif chip_string.lower() == "281x":
value = RK281X_DEVICE
elif chip_string.lower() == "panda":
value = RKPANDA_DEVICE
elif chip_string.lower() == "27":
value = RK27_DEVICE
elif chip_string.lower() == "nano":
value = RKNANO_DEVICE
elif chip_string.lower() == "smart":
value = RKSMART_DEVICE
elif chip_string.lower() == "crown":
value = RKCROWN_DEVICE
elif chip_string.lower() == "cayman":
value = RKCAYMAN_DEVICE
elif chip_string.lower() == "29":
value = RK29_DEVICE
elif chip_string.lower() == "292x":
value = RK292X_DEVICE
elif chip_string.lower() == "30":
value = RK30_DEVICE
elif chip_string.lower() == "30b":
value = RK30B_DEVICE
elif chip_string.lower() == "31":
value = RK31_DEVICE
elif chip_string.lower() == "32":
value = RK32_DEVICE
else:
j = 0
for i,ch in enumerate(chip_string):
value += np.int32(ord(ch))
if i < 3:
value <<= np.int32(8)
j = j + 1
while j < 3:
value <<= np.int32(8)
j = j + 1
return value
def is_hex_string(str):
return all(s in string.hexdigits for s in str)
def convert_loader_ver(ver):
ver_value = ver.split('.')
if len(ver_value) != 2:
return np.uint32(-1)
if not (is_hex_string(ver_value[0]) and is_hex_string(ver_value[1])):
return np.uint32(-1)
loader_ver = np.uint32(int(ver_value[0], 10))
loader_ver = loader_ver << np.uint32(8)
loader_ver += np.uint32(int(ver_value[1], 10))
return loader_ver
def boot_merger_main():
total_start = timer()
major = sys.version_info[0]
minor = sys.version_info[1]
small = sys.version_info[2]
ver = major * 100 + minor * 10 + small
if ver < 300:
print("Error:script can not run in python2")
return
argc = len(sys.argv)
if argc > 1:
cmd = sys.argv[1];
if cmd.lower() not in ['pack','unpack','change_ver','ins_cert','del_cert']:
cmd = 'pack'
sys.argv.insert(1,'pack')
argc=argc+1
if cmd.lower() == "pack":
input_from_ini = False
need_create_head = False
keep_sec_cert = False
hash_type = 'sha256'
in_chip_str = ''
in_verion_str = ''
in_entry471 = list()
in_entry472 = list()
in_loader_entry = list()
entry_loader_name = ['FlashData','FlashBoot','FlashHead']
in_rc4_flag = 0
in_471_rc4 = 0
in_output = ''
if argc == 3:
ini_param = sys.argv[2]
if os.path.exists(ini_param):
ini_base_name = os.path.basename(ini_param)
if bool(re.search(r'\.ini$', ini_base_name, re.IGNORECASE)):
try:
ini_obj = configparser.ConfigParser()
ini_obj.read(ini_param)
in_chip_str = ini_obj.get('CHIP_NAME','NAME')
ini_major = ini_obj.get('VERSION', 'MAJOR')
ini_minor = ini_obj.get('VERSION', 'MINOR')
in_verion_str = ini_major + '.' + ini_minor
ini_471_num = ini_obj.getint('CODE471_OPTION', 'NUM')
ini_472_num = ini_obj.getint('CODE472_OPTION', 'NUM')
ini_loader_num = ini_obj.getint('LOADER_OPTION', 'NUM')
for i in range(ini_471_num):
file_entry471 = ini_obj.get('CODE471_OPTION', 'Path'+str(i+1))
in_entry471.append(file_entry471)
for i in range(ini_472_num):
file_entry472 = ini_obj.get('CODE472_OPTION', 'Path'+str(i+1))
in_entry472.append(file_entry472)
if ini_loader_num:
if ini_obj.has_option('LOADER_OPTION','FlashData'):
in_loader_data = ini_obj.get('LOADER_OPTION', 'FlashData')
in_loader_entry.append(in_loader_data)
if ini_obj.has_option('LOADER_OPTION', 'FlashBoot'):
in_loader_code = ini_obj.get('LOADER_OPTION', 'FlashBoot')
in_loader_entry.append(in_loader_code)
if ini_obj.has_option('LOADER_OPTION','FlashHead'):
in_loader_head = ini_obj.get('LOADER_OPTION', 'FlashHead')
in_loader_entry.append(in_loader_head)
in_output = ini_obj.get('OUTPUT', 'PATH')
if ini_obj.has_option('FLAG', 'RC4_OFF'):
ini_rc4_flag = ini_obj.get('FLAG', 'RC4_OFF')
ini_rc4_flag.lower()
if ini_rc4_flag == '1' or ini_rc4_flag == 'true':
in_rc4_flag = 1
if ini_obj.has_option('FLAG', '471_RC4_OFF'):
ini_rc4_flag = ini_obj.get('FLAG', '471_RC4_OFF')
ini_rc4_flag.lower()
if ini_rc4_flag == '1' or ini_rc4_flag == 'true':
in_471_rc4 = 1
if ini_obj.has_section('SYSTEM'):
if ini_obj.has_option('SYSTEM','NEWIDB'):
try:
if ini_obj.getboolean('SYSTEM','NEWIDB'):
need_create_head = True
except ValueError as e:
pass
if ini_obj.has_option('SYSTEM','KEEPCERT'):
try:
if ini_obj.getboolean('SYSTEM','KEEPCERT'):
keep_sec_cert = True
except ValueError as e:
pass
if ini_obj.has_option('SYSTEM','HASHTYPE'):
try:
temp = ini_obj.get('SYSTEM','HASHTYPE')
if temp.lower() in ['sha256','sha512']:
hash_type = temp
except ValueError as e:
pass
input_from_ini = True
except Exception as e:
print("read ini exception,%s!" % str(e))
return
if not input_from_ini:
parser = argparse.ArgumentParser(description='pack rk loader tool', prog='boot_merger pack')
parser.add_argument('--version', action='version', version=APP_VERSION)
parser.add_argument('--chip', nargs=1, help='chip id like as RK330A')
parser.add_argument('--loader_ver', nargs=1, help='version like as xx.xx')
parser.add_argument('--entry_471', nargs='+', help='usually ddr init code')
parser.add_argument('--entry_472', nargs='+', help='usually usbplug')
parser.add_argument('--entry_loader',nargs='+', help='usually flashdata flashboot flashhead')
parser.add_argument('--create_head', action='store_true', help='create head for new idb')
parser.add_argument('--rc4_off', action='store_true', help='close loader rc4')
parser.add_argument('--rc4_471_off', action='store_true', help='close 471 rc4')
parser.add_argument('--keep_cert', action='store_true', help='keep cert reserved')
parser.add_argument('--hash_type', choices=['sha256','sha512'], help='hash for new idb')
parser.add_argument('--output', nargs=1, help='loader filepath')
args = parser.parse_args(sys.argv[2:])
in_chip_str = args.chip[0]
in_verion_str = args.loader_ver[0]
in_entry471 = args.entry_471
in_entry472 = args.entry_472
in_loader_entry = args.entry_loader
if not args.rc4_off:
in_rc4_flag = 0
else:
in_rc4_flag = 1
if not args.rc4_471_off:
in_471_rc4 = 0
else:
in_471_rc4 = 1
if not args.keep_cert:
pass
else:
keep_sec_cert = True
if not args.hash_type:
pass
else:
hash_type = args.hash_type
if not args.create_head:
pass
else:
need_create_head = True
in_output = args.output[0]
if need_create_head:
out_usb_head = os.path.join(os.path.dirname(in_entry471[0]), 'UsbHead.bin')
if os.path.exists(out_usb_head):
os.unlink(out_usb_head)
# start = timer()
create_new_idblock([in_entry471[0],in_entry472[0]],keep_sec_cert,hash_type,out_usb_head)
# print('create usb head elapsed:%.2f' % (timer() - start))
if not os.path.isfile(out_usb_head):
print("Failed to create %s" % out_usb_head)
return
out_flash_head = os.path.join(os.path.dirname(in_loader_entry[0]), 'FlashHead.bin')
if os.path.exists(out_flash_head):
os.unlink(out_flash_head)
# start = timer()
create_new_idblock(in_loader_entry[0:2],keep_sec_cert,hash_type,out_flash_head)
# print('create flash head elapsed:%.2f' % (timer() - start))
if not os.path.isfile(out_flash_head):
print("Failed to create %s" % out_flash_head)
return
in_entry471.insert(0,out_usb_head)
in_loader_entry.insert(2,out_flash_head)
'''
print("chip=%s" % args.chip)
print("ver=%s" % args.loader_ver)
print("471 coutn=%d item=%s" % (len(args.entry_471), args.entry_471[0]))
print("472 count=%d item=%s" % (len(args.entry_472), args.entry_472[0]))
print("loader_data=%s" % args.entry_loader[0])
print("loader_code=%s" % args.entry_loader[1])
print("rc4_off=%d" % args.rc4_off)
print("output=%s" % args.output)
'''
if len(in_loader_entry)>3:
print('loader entry must be <= 3.')
return
if not input_from_ini:
print("packing loader start...")
loader_chip = convert_chip(in_chip_str)
if loader_chip == -1:
print("invalid chip %s" % in_chip_str)
return
loader_ver = convert_loader_ver(in_verion_str)
if loader_ver == np.uint32(-1):
print("invalid loader ver %s" % in_verion_str)
return
#1.fill up loader head
loader_head_size = struct.calcsize(RK_LOADER_HEAD_FORMAT)
loader_head_buf = bytearray(loader_head_size)
# loader_head_buf[0:] = [0 for i in range(loader_head_size)]
loader_head_struct = list(struct.unpack(RK_LOADER_HEAD_FORMAT, loader_head_buf))
loader_head_struct[0] = LDR_TAG
loader_head_struct[3] = LDR_FORMAT_VER
loader_head_struct[1] = loader_head_size
loader_head_struct[2] = loader_ver
# loader_head_struct[3] = 0
release_time_struct = list(struct.unpack('H5B', loader_head_struct[4][:]))
release_time = datetime.datetime.now()
release_time_struct[0] = release_time.year
release_time_struct[1] = release_time.month
release_time_struct[2] = release_time.day
release_time_struct[3] = release_time.hour
release_time_struct[4] = release_time.minute
release_time_struct[5] = release_time.second
loader_head_struct[4] = struct.pack('H5B', *release_time_struct)
loader_head_struct[5] = loader_chip
count_471 = len(in_entry471)
count_472 = len(in_entry472)
count_loader = len(in_loader_entry)
loader_entry_size = struct.calcsize(RK_LOADER_ENTRY_FORMAT)
loader_head_struct[6] = count_471
loader_head_struct[7] = loader_head_size #471 entry offset
loader_head_struct[8] = loader_entry_size
loader_head_struct[9] = count_472
loader_head_struct[10] = loader_head_struct[7] + count_471 * loader_entry_size #472 entry offset
loader_head_struct[11] = loader_entry_size
loader_head_struct[12] = count_loader
loader_head_struct[13] = loader_head_struct[10] + count_472 * loader_entry_size # loader entry offset
loader_head_struct[14] = loader_entry_size
for file in in_loader_entry:
with open(file,'rb') as fp:
sign = fp.read(4)
tag = int.from_bytes(sign[0:4], 'little')
if tag == SECURE_TAG or tag == 0x53534B52:
loader_head_struct[15] = ord('S')
loader_head_struct[16] = in_rc4_flag
loader_head_struct[17] = in_471_rc4
loader_head_buf = struct.pack(RK_LOADER_HEAD_FORMAT, *loader_head_struct)
# print("writing head...")
fout = open(in_output, 'wb+')
fout.write(loader_head_buf)
#2.fill up entry
if not input_from_ini:
print("writing entry...")
data_offset = loader_head_size + (count_471 + count_472 + count_loader) * loader_entry_size
loader_entry_buf = bytearray(loader_entry_size)
loader_entry_struct = list(struct.unpack(RK_LOADER_ENTRY_FORMAT, loader_entry_buf))
loader_entry_struct[0] = loader_entry_size
loader_entry_struct[1] = ENTRY471
for i in range(count_471):
item_name = in_entry471[i]
if not os.path.exists(item_name):
print("%s is not existed" % item_name)
fout.close()
return
item_size = os.path.getsize(item_name)
item_name = os.path.basename(item_name).split('.')[0]
for j in range(20):
if j < len(item_name):
loader_entry_struct[2 + j] = ord(item_name[j])
else:
loader_entry_struct[2 + j] = 0
loader_entry_struct[22] = data_offset
loader_entry_struct[23] = align(item_size,PAGE_SIZE)
data_offset += loader_entry_struct[23]
loader_entry_buf = struct.pack(RK_LOADER_ENTRY_FORMAT, *loader_entry_struct)
fout.write(loader_entry_buf)
loader_entry_struct[1] = ENTRY472
for i in range(count_472):
item_name = in_entry472[i]
if not os.path.exists(item_name):
print("%s is not existed" % item_name)
fout.close()
return
item_size = os.path.getsize(item_name)
item_name = os.path.basename(item_name).split('.')[0]
for j in range(20):
if j < len(item_name):
loader_entry_struct[2 + j] = ord(item_name[j])
else:
loader_entry_struct[2 + j] = 0
loader_entry_struct[22] = data_offset
loader_entry_struct[23] = align(item_size, PAGE_SIZE)
data_offset += loader_entry_struct[23]
loader_entry_buf = struct.pack(RK_LOADER_ENTRY_FORMAT, *loader_entry_struct)
fout.write(loader_entry_buf)
loader_entry_struct[1] = ENTRYLOADER
for i in range(count_loader):
item_name = in_loader_entry[i]
if not os.path.exists(item_name):
print("%s is not existed" % item_name)
fout.close()
return
item_size = os.path.getsize(item_name)
item_name = entry_loader_name[i]
for j in range(20):
if j < len(item_name):
loader_entry_struct[2 + j] = ord(item_name[j])
else:
loader_entry_struct[2 + j] = 0
loader_entry_struct[22] = data_offset
loader_entry_struct[23] = align(item_size, PAGE_SIZE)
data_offset += loader_entry_struct[23]
loader_entry_buf = struct.pack(RK_LOADER_ENTRY_FORMAT, *loader_entry_struct)
fout.write(loader_entry_buf)
#3.write entry data
for i in range(count_471):
item_name = in_entry471[i]
if not input_from_ini:
print("writing %s" % item_name)
file_size = os.path.getsize(item_name)
item_size = align(file_size,PAGE_SIZE)
fin = open(item_name, 'rb')
data_buf = bytearray(fin.read())
fin.close()
data_buf = data_buf.ljust(item_size, b'\0')
if not in_471_rc4:
data_buf = rc4(bytes(data_buf))
fout.write(data_buf)
for i in range(count_472):
item_name = in_entry472[i]
if not input_from_ini:
print("writing %s" % item_name)
file_size = os.path.getsize(item_name)
item_size = align(file_size,PAGE_SIZE)
fin = open(item_name, 'rb')
data_buf = bytearray(fin.read())
fin.close()
data_buf = data_buf.ljust(item_size, b'\0')
if not in_471_rc4:
data_buf = rc4(bytes(data_buf))
fout.write(data_buf)
for i in range(count_loader):
item_name = in_loader_entry[i]
if not input_from_ini:
print("writing %s" % item_name)
file_size = os.path.getsize(item_name)
item_size = align(file_size, PAGE_SIZE)
fin = open(item_name, 'rb')
data_buf = bytearray(fin.read())
fin.close()
data_buf = data_buf.ljust(item_size, b'\0')
for i in range(item_size//SECTOR_SIZE):
data_buf[i*SECTOR_SIZE:(i+1)*SECTOR_SIZE] = rc4(bytes(data_buf[i*SECTOR_SIZE:(i+1)*SECTOR_SIZE]))
fout.write(data_buf)
#calculate crc
if not input_from_ini:
print("writing crc...")
fout.seek(0, io.SEEK_SET)
new_loader_data = fout.read()
crc = crc32(new_loader_data, 0)
fout.write(np.uint32(crc))
fout.close()
print("pack loader ok.(%s)(%.2f)" % (os.path.basename(in_output),timer()-total_start))
elif cmd.lower() == "unpack":
parser = argparse.ArgumentParser(description='unpack rk loader', prog='boot_merger unpack')
parser.add_argument('--version', action='version', version=APP_VERSION)
parser.add_argument('--loader', nargs=1, help='rk loader to extract')
parser.add_argument('--output', nargs=1, help='output directory')
args = parser.parse_args(sys.argv[2:])
print("unpacking loader start...")
os_string = platform.system()
input_loader = args.loader[0]
output_dir = args.output[0]
if not os.path.exists(input_loader):
print("%s is not existed" % input_loader)
return
if not os.path.exists(output_dir):
print("%s is not existed" % output_dir)
return
if os_string.lower() == "windows":
if output_dir[-1] != '\\':
output_dir = '%s%s' % (output_dir, '\\')
else:
if output_dir[-1] != '/':
output_dir = '%s%s' % (output_dir, '/')
print("loader=%s" % input_loader)
print("output=%s" % output_dir)
loader_size = os.path.getsize(input_loader)
fin = open(input_loader, 'rb')
loader_data = bytearray(fin.read())
tag = int.from_bytes(loader_data[0:4], 'little')
if (tag != BOOT_TAG) and (tag !=LDR_TAG):
print("loader tag is invalid")
fin.close()
return
ver = int.from_bytes(loader_data[10:14], 'little')
if tag == LDR_TAG:
if ver > LDR_FORMAT_VER:
print("tool did not support this loader,please upgrade")
fin.close()
return
crc = int.from_bytes(loader_data[-4:], 'little')
new_crc = crc32(bytes(loader_data[:-4]), 0)
if crc != new_crc:
print("checking crc failed,crc=0x%08x,new=0x%08x" % (crc,new_crc))
fin.close()
return
head_size = struct.calcsize(RK_LOADER_HEAD_FORMAT)
entry_size = struct.calcsize(RK_LOADER_ENTRY_FORMAT)
head_struct = list(struct.unpack(RK_LOADER_HEAD_FORMAT,loader_data[0:head_size]))
#1.unpack 471
count_471 = head_struct[6]
offset_471 = head_struct[7]
for i in range(count_471):
entry_struct = list(struct.unpack(RK_LOADER_ENTRY_FORMAT,loader_data[offset_471:offset_471+entry_size]))
item_name = []
for j in range(20):
if entry_struct[2+j] == 0:
break
item_name.append(chr(entry_struct[2+j]))
file_name = ''.join(item_name)
print("unpacking %s..." % file_name)
file_name = output_dir + file_name + '.bin'
data_offset = entry_struct[22]
data_size = entry_struct[23]
out_data = bytearray(loader_data[data_offset:data_offset+data_size])
if not head_struct[17]:
out_data = rc4(bytes(out_data))
fout = open(file_name,'wb')
fout.write(out_data)
fout.close()
offset_471 += entry_size
# 2.unpack 472
count_472 = head_struct[9]
offset_472 = head_struct[10]
for i in range(count_472):
entry_struct = list(struct.unpack(RK_LOADER_ENTRY_FORMAT, loader_data[offset_472:offset_472+entry_size]))
item_name = []
for j in range(20):
if entry_struct[2 + j] == 0:
break
item_name.append(chr(entry_struct[2 + j]))
file_name = ''.join(item_name)
print("unpacking %s..." % file_name)
file_name = output_dir + file_name + '.bin'
data_offset = entry_struct[22]
data_size = entry_struct[23]
out_data = bytearray(loader_data[data_offset:data_offset + data_size])
if not head_struct[17]:
out_data = rc4(bytes(out_data))
fout = open(file_name, 'wb')
fout.write(out_data)
fout.close()
offset_472 += entry_size
# 2.unpack loader
count_loader = head_struct[12]
offset_loader = head_struct[13]
for i in range(count_loader):
entry_struct = list(struct.unpack(RK_LOADER_ENTRY_FORMAT, loader_data[offset_loader:offset_loader+entry_size]))
item_name = []
for j in range(20):
if entry_struct[2 + j] == 0:
break
item_name.append(chr(entry_struct[2 + j]))
file_name = ''.join(item_name)
print("unpacking %s..." % file_name)
file_name = output_dir + file_name + '.bin'
data_offset = entry_struct[22]
data_size = entry_struct[23]
out_data = bytearray(loader_data[data_offset:data_offset + data_size])
for i in range(data_size//SECTOR_SIZE):
out_data[i * SECTOR_SIZE:(i + 1) * SECTOR_SIZE] = rc4(bytes(out_data[i * SECTOR_SIZE:(i + 1) * SECTOR_SIZE]))
fout = open(file_name, 'wb')
fout.write(out_data)
fout.close()
offset_loader += entry_size
fin.close()
print("unpack loader ok.")
elif cmd.lower() == "change_ver":
parser = argparse.ArgumentParser(description='change loader version', prog='boot_merger change_ver')
parser.add_argument('--loader', nargs=1, help='rk loader to change')
parser.add_argument('--loader_ver', nargs=1, help='version like as xx.xx')
args = parser.parse_args(sys.argv[2:])
print("changing loader version start...")
os_string = platform.system()
input_loader = args.loader[0]
in_verion_str = args.loader_ver[0]
if not os.path.exists(input_loader):
print("%s is not existed" % input_loader)
return
loader_ver = convert_loader_ver(in_verion_str)
if loader_ver == np.uint32(-1):
print("invalid loader ver %s" % in_verion_str)
return
print("loader=%s" % input_loader)
print("ver=%s" % in_verion_str)
loader_size = os.path.getsize(input_loader)
with open(input_loader, 'rb+') as fin:
loader_data = bytearray(fin.read())
tag = int.from_bytes(loader_data[0:4], 'little')
if (tag != BOOT_TAG) and (tag !=LDR_TAG):
print("loader tag is invalid")
return
ver = int.from_bytes(loader_data[10:14], 'little')
if tag == LDR_TAG:
if ver > LDR_FORMAT_VER:
print("tool did not support this loader,please upgrade")
return
crc = int.from_bytes(loader_data[-4:], 'little')
new_crc = crc32(loader_data[:-4], 0)
if crc != new_crc:
print("checking crc failed,crc=0x%08x,new=0x%08x" % (crc, new_crc))
fin.close()
return
head_size = struct.calcsize(RK_LOADER_HEAD_FORMAT)
head_struct = list(struct.unpack(RK_LOADER_HEAD_FORMAT, loader_data[0:head_size]))
print("old_ver=%x.%x,new_ver=%s" % (head_struct[2]>> 8 & 0xff, head_struct[2] & 0xff, in_verion_str))
head_struct[2] = loader_ver
loader_data[0:head_size] = struct.pack(RK_LOADER_HEAD_FORMAT, *head_struct)
fin.seek(0, io.SEEK_SET)
fin.write(loader_data[0:head_size])
fin.seek(-4, io.SEEK_END)
crc = crc32(loader_data[:-4], 0)
fin.write(np.uint32(crc))
print("change version of loader ok.")
elif cmd.lower() == "ins_cert":
parser = argparse.ArgumentParser(description='insert cert into rkloader', prog='boot_merger ins_cert')
parser.add_argument('--loader', nargs=1, help='rkloader')
parser.add_argument('--cert', nargs=1, help='CA cert')
args = parser.parse_args(sys.argv[2:])
print("insert cert into loader start...")
input_loader = args.loader[0]
cert_file = args.cert[0]
if not os.path.exists(input_loader):
print("%s is not existed" % input_loader)
return
if not os.path.exists(cert_file):
print("%s is not existed" % cert_file)
return
print("loader=%s" % input_loader)
print("cert=%s" % cert_file)
loader_size = os.path.getsize(input_loader)
with open(input_loader,'rb+') as fin,open(cert_file,'rb') as fcert:
loader_data = bytearray(fin.read())
tag = int.from_bytes(loader_data[0:4], 'little')
if (tag != BOOT_TAG) and (tag !=LDR_TAG):
print("loader tag is invalid")
return
ver = int.from_bytes(loader_data[10:14], 'little')
if tag == LDR_TAG:
if ver > LDR_FORMAT_VER:
print("tool did not support this loader,please upgrade")
return
cert_data = bytearray(fcert.read())
if cert_data[0:4].decode() != 'RKPK':
print('cert tag is invalid')
return
if len(cert_data) != 2048:
print('size of cet is not 2048B')
return
for i in range(4):
cert_data[i * SECTOR_SIZE:(i + 1) * SECTOR_SIZE] = rc4(bytes(cert_data[i * SECTOR_SIZE:(i + 1) * SECTOR_SIZE]))
crc = int.from_bytes(loader_data[-4:], 'little')
new_crc = crc32(loader_data[:-4], 0)
if crc != new_crc:
print("checking crc failed,crc=0x%08x,new=0x%08x" % (crc,new_crc))
return
head_size = struct.calcsize(RK_LOADER_HEAD_FORMAT)
entry_size = struct.calcsize(RK_LOADER_ENTRY_FORMAT)
head_struct = list(struct.unpack(RK_LOADER_HEAD_FORMAT,loader_data[0:head_size]))
# modify loader entry
count_loader = head_struct[12]
offset_loader = head_struct[13]
flashhead_offset = 0
new_flashhead_data = bytearray(4096)
for i in range(count_loader):
entry_struct = list(struct.unpack(RK_LOADER_ENTRY_FORMAT, loader_data[offset_loader:offset_loader+entry_size]))
item_name = []
for j in range(20):
if entry_struct[2 + j] == 0:
break
item_name.append(chr(entry_struct[2 + j]))
file_name = ''.join(item_name)
if file_name.lower()=='flashhead':
flashhead_offset = entry_struct[22]
flashhead_size = entry_struct[23]
new_flashhead_data[0:2048] = loader_data[flashhead_offset:flashhead_offset + 2048]
new_flashhead_data[2048:] = cert_data
if flashhead_size == 4096:
break
else:
entry_struct[23] = 4096
else:
if flashhead_offset != 0:
entry_struct[22] += 2048
if flashhead_offset != 0:
loader_data[offset_loader:offset_loader + entry_size] = struct.pack(RK_LOADER_ENTRY_FORMAT,*entry_struct)
offset_loader += entry_size
if flashhead_offset == 0:
print('no found flashhead entry in the loader')
return
if flashhead_size == 4096:
new_loader_data = bytearray(loader_size)
else:
new_loader_data = bytearray(loader_size+2048)
new_loader_data[0:flashhead_offset] = loader_data[0:flashhead_offset]
new_loader_data[flashhead_offset:flashhead_offset+4096] = new_flashhead_data
new_loader_data[flashhead_offset+4096:-4] = loader_data[flashhead_offset+flashhead_size:-4]
fin.seek(0,os.SEEK_SET)
fin.truncate(0)
fin.write(new_loader_data[:-4])
crc = crc32(new_loader_data[:-4], 0)
fin.write(np.uint32(crc))
print("insert cert ok.")
elif cmd.lower() == "del_cert":
parser = argparse.ArgumentParser(description='delete cert from rkloader', prog='boot_merger del_cert')
parser.add_argument('--loader', nargs=1, help='rkloader')
args = parser.parse_args(sys.argv[2:])
print("delete cert from loader start...")
input_loader = args.loader[0]
if not os.path.exists(input_loader):
print("%s is not existed" % input_loader)
return
print("loader=%s" % input_loader)
loader_size = os.path.getsize(input_loader)
with open(input_loader,'rb+') as fin:
loader_data = bytearray(fin.read())
tag = int.from_bytes(loader_data[0:4], 'little')
if (tag != BOOT_TAG) and (tag !=LDR_TAG):
print("loader tag is invalid")
return
ver = int.from_bytes(loader_data[10:14], 'little')
if tag == LDR_TAG:
if ver > LDR_FORMAT_VER:
print("tool did not support this loader,please upgrade")
return
crc = int.from_bytes(loader_data[-4:], 'little')
new_crc = crc32(loader_data[:-4], 0)
if crc != new_crc:
print("checking crc failed,crc=0x%08x,new=0x%08x" % (crc,new_crc))
return
head_size = struct.calcsize(RK_LOADER_HEAD_FORMAT)
entry_size = struct.calcsize(RK_LOADER_ENTRY_FORMAT)
head_struct = list(struct.unpack(RK_LOADER_HEAD_FORMAT,loader_data[0:head_size]))
# modify loader entry
count_loader = head_struct[12]
offset_loader = head_struct[13]
flashhead_offset = 0
new_flashhead_data = bytearray(2048)
for i in range(count_loader):
entry_struct = list(struct.unpack(RK_LOADER_ENTRY_FORMAT, loader_data[offset_loader:offset_loader+entry_size]))
item_name = []
for j in range(20):
if entry_struct[2 + j] == 0:
break
item_name.append(chr(entry_struct[2 + j]))
file_name = ''.join(item_name)
if file_name.lower()=='flashhead':
flashhead_offset = entry_struct[22]
flashhead_size = entry_struct[23]
if flashhead_size != 2048 and flashhead_size != 4096:
print('size of flashhead is invalid')
return
new_flashhead_data[0:2048] = loader_data[flashhead_offset:flashhead_offset + 2048]
if flashhead_size == 2048:
break
else:
entry_struct[23] = 2048
else:
if flashhead_offset != 0:
entry_struct[22] -= 2048
if flashhead_offset != 0:
loader_data[offset_loader:offset_loader + entry_size] = struct.pack(RK_LOADER_ENTRY_FORMAT,*entry_struct)
offset_loader += entry_size
if flashhead_offset == 0:
print('no found flashhead entry in the loader')
return
if flashhead_size == 4096:
new_loader_data = bytearray(loader_size-2048)
new_loader_data[0:flashhead_offset] = loader_data[0:flashhead_offset]
new_loader_data[flashhead_offset:flashhead_offset+2048] = new_flashhead_data
new_loader_data[flashhead_offset+2048:-4] = loader_data[flashhead_offset+flashhead_size:-4]
fin.seek(0,os.SEEK_SET)
fin.truncate(0)
fin.write(new_loader_data[:-4])
crc = crc32(new_loader_data[:-4], 0)
fin.write(np.uint32(crc))
print("delete cert ok.")
else:
print("invalid %s command" % (cmd))
usage()
else:
usage()
if __name__ == '__main__':
boot_merger_main()