Files
kunlun_ramtool/bin/bin_to_hex.py
2024-10-16 23:59:20 +08:00

321 lines
9.2 KiB
Python

import re
import os
import sys
import struct
import json
from bin.log import myprint
from bin.base import bin_path
# kunlun1,kunlun2,kunlun3的img类型
# FRW是指未压缩的fw CFRW是指压缩之后的fw
_ImgType={
0x0000:"imgROM", # Maybe,ROM doesn't need a imgType */
0xFC00:"imgSP", # sp */
0xFC01:"imgSBL", # sbl */
0xFC02:"imgFRW", # kl1: 1MB fw, uncompressed for sta, run in flash; compressed for cco, run in psram */
0xFC03:"imgCFG", # The first pib file. */
0xFC04:"imgEFUSE", # efuse */
0xFC05:"imgOEM", # oem */
0xFC06:"imgFRW2", # The second fw, maybe the backup one. not used. */
0xFC07:"imgCFG2", # The second pib file. */
0xFC08:"imgCFRW1", # kl1: 2MB fw, compressed for sta or cco, run in flash; kl2: 4M flash fw */
0xFC09:"imgCFRW2", # The second fw, maybe the backup one. not used. */
0xFC0A:"imgCFRW", # kl1: 2MB fw, compressed for sta or cco, run in psram; kl2: 4M psram fw */
0xFC0B:"imgREF", # ref */
0xFC0C:"imgCUS", # cus */
0xFC0D:"imgCFRW4F", # kl1: 4MB fw, compressed for sta or cco, run in flash */
0xFC0E:"imgCFRW4P", # kl1: 4MB fw, compressed for sta or cco, run in psram */
0xFFFF:"imgMAX", # invalid */
0x00:"imgV1ROM", # Maybe,ROM doesn't need a imgType */
0x01:"imgV1SBL", # sbl */
0x02:"imgV1FRWPLC", # FW-PLC */
0x03:"imgV1CFG", # The first pib file. */
0x05:"imgV1OEM", # oem */
0x06:"imgV1FRWCUS", # FW-CUS */
0xFF:"imgV1MAX" # invalid */
}
_DevType={
0xDC01:"devkunlun1",
0xDC02:"devkunlun2",
0xDC03:"devkunlun3",
0xFFFF:"devMax",
0x01:"devV1kunlun1",
0x02:"devV1kunlun2",
0x03:"devV1kunlun3",
0xFF:"devV1Max"
}
_PatternType={
0x00:"HTZD",
0x55:"HTZD",
0xaa:"JSMT",
0x99:"FLX",
0x66:"QJ",
0xcc:"SPE",
0x33:"GX",
0xdd:"DT",
0xa9:"YP",
0xc6:"WTZ",
0x93:"TCE"
}
_PKT_HEADER_MAGIC_NO = 0x00005566
_IMG_HEADER_MAGIC_NO = 0xa4e49a17
# 从info文件读取flash信息
def load_flash_info(file_name:str):
flash_info_list:list[dict]=[]
with open(file_name,mode='r',encoding='utf-8') as f:
lines=f.readlines()
for line in lines:
# 如果开头两个字符是数字
info = re.match(r"^\d{2}",line)
if(info):
# print(info.group(0))
sp=line.split()
flash_info={}
flash_info["DevType"]=_DevType[int(sp[1],base=16)]
flash_info["ImgType"]=_ImgType[int(sp[2],base=16)]
flash_info["Offset"]=int(sp[3],base=16)
flash_info["Size"]=int(sp[4])
flash_info_list.append(flash_info)
return flash_info_list
# 查看是不是数据头,不是返回 "",是返回解析值
def tran_pkg_header(data:bytearray):
size=len(data)
ret={}
if(size>=96):
# 大写为无符号 B 单字节 H 双字节 I 4字节 L 4字节 Q 8字节
# f 单精度浮点 d 双精度浮点 s 字符串
a=struct.unpack('>BBHIIIIIIIIIIIIIIIIIIIIIIHBB',data)
if(a[5]==_PKT_HEADER_MAGIC_NO):
ret["enctype"]=str(a[0])
ret["pattern"]=hex(a[1])
ret["dev_type"]=hex(a[2])
ret["file_crc"]=hex(a[3])
ret["file_len"]=str(a[4])
ret["magic_no"]=hex(a[5])
ret["version"]=hex(a[6])
ret["sp_start"]=hex(a[7])
ret["sp_len"]=str(a[8])
ret["sbl_start"]=hex(a[9]) # 32bytes
ret["sbl_len"]=str(a[10])
ret["oem_start"]=hex(a[11])
ret["oem_len"]=str(a[12])
ret["pib_start"]=hex(a[13])
ret["pib_len"]=str(a[14])
ret["fw_start"]=hex(a[15])
ret["fw_len"]=str(a[16])
ret["efuse_start"]=hex(a[17]) # 64bytes
ret["efuse_len"]=str(a[18])
ret["fw2_start"]=hex(a[19])
ret["fw2_len"]=str(a[20])
ret["ref_start"]=hex(a[21])
ret["ref_len"]=str(a[22])
ret["cus_start"]=hex(a[23])
ret["cus_len"]=str(a[24])
ret["vendor_id"]=hex(a[25])
ret["img_type"]=hex(a[26])
ret["img_flag"]=hex(a[27])
t=str(ret)
t=t.replace(',','\n')
# t=json.dumps(ret, sort_keys=True, indent=2, separators=(',', ': '))
return t
return ""
def tran_img_headerv0(data:bytearray):
size=len(data)
ret={}
if(size>=64):
# 大写为无符号 B 单字节 H 双字节 I 4字节 L 4字节 Q 8字节
# f 单精度浮点 d 双精度浮点 s 字符串
a=struct.unpack('>HHIHBBIIIBBBBI',data[0:32])
if(a[8]==_IMG_HEADER_MAGIC_NO):
ret["devType"]=hex(a[0])+f"({_DevType.get(a[0],'unknown')})"
ret["imgType"]=hex(a[1])+f"({_ImgType.get(a[1],'unknown')})"
ret["imgSize"]=str(a[2])
ret["imgVer"]=hex(a[3])
ret["psramSize"]=str(a[4])
ret["hdrVer"]=hex(a[5])
ret["fwSize"]=str(a[6])
ret["imgCRC"]=hex(a[7])
ret["guard"]=hex(a[8])
ret["layoutIdx"]=hex(a[9])
# reserved 3bytes
ret["fwCRC"]=hex(a[13])
ret["sha256"]=data[32:].hex()
t=str(ret)
t=t.replace(',','\n')
return t,ret
return "",{}
def tran_img_headerv1(data:bytearray):
size=len(data)
ret={}
if(size>=64):
# 大写为无符号 B 单字节 H 双字节 I 4字节 L 4字节 Q 8字节
# f 单精度浮点 d 双精度浮点 s 字符串
a=struct.unpack('>BBBBIBBBBIIIBBBBI',data[0:32])
if(a[11]==_IMG_HEADER_MAGIC_NO):
ret["devType"]=hex(a[0])+f"({_DevType.get(a[0],'unknown')})"
ret["imgType"]=hex(a[1])+f"({_ImgType.get(a[1],'unknown')})"
ret["encType"]=hex(a[2])
ret["cfg"]=hex(a[3])
ret["imgSize"]=str(a[4])
ret["zipType"]=hex(a[5])
ret["flashSize"]=str(a[6])
ret["psramSize"]=hex(a[7])
ret["hdrVer"]=hex(a[8])
ret["imgVer"]=hex(a[9])
ret["imgCRC"]=hex(a[10])
ret["guard"]=hex(a[11])
ret["layoutIdx"]=hex(a[12])
# reserved 3bytes
ret["runAddr"]=hex(a[16])
ret["sha256"]=data[32:].hex()
t=str(ret)
t=t.replace(',','\n')
return t,ret
return "",{}
# 判断是不是pkt_header
def pkt_header_check(data:bytearray):
magic=(data[12]<<24)|(data[13]<<16)|(data[14]<<8)|(data[15])
if (magic==_PKT_HEADER_MAGIC_NO):
return True
myprint(f"magic={hex(magic)}")
return False
# 判断是不是img_header
def img_header_check(data:bytearray):
if(len(data)<32):
return ''
magic=(data[20]<<24)|(data[21]<<16)|(data[22]<<8)|(data[23])
if (magic==_IMG_HEADER_MAGIC_NO):
imghdr_v=data[11]
myprint(f"magic={hex(magic)}, imghdr_v={imghdr_v}")
# 返回使用的结构体类型
if(imghdr_v==0x10):
return 'V1'
else:
return "V0"
return ""
# 转化为hex文本
def bin_to_hex(bin:bytearray,f,oem_file=None):
all_size=len(bin)
pack_size=32
turned=0
turned_old=0
out_text=''
kunlun=''
if(pkt_header_check(bin)):
out_text=tran_pkg_header(bin[0:96])+'\n'
f.write(out_text)
while turned < all_size:
if(turned+pack_size<=all_size):
data=bin[turned:turned+pack_size]
turned_old=turned
turned+=pack_size
else:
data=bin[turned:]
turned_old=turned
turned=all_size
if(all_size-turned_old>=64):
hdr_data=bin[turned_old:turned_old+64]
else:
hdr_data=bytearray()
hdr_v=img_header_check(hdr_data)
if(hdr_v=='V0'):
kunlun='kl1'
out_text,ret=tran_img_headerv0(hdr_data)
out_text+='\n'
f.write(out_text)
elif(hdr_v=='V1'):
kunlun='kl3'
out_text,ret=tran_img_headerv1(hdr_data)
out_text+='\n'
f.write(out_text)
# 截取oem部分
if(oem_file is not None):
if(_ImgType[hdr_data[1]]=="imgV1OEM"):
size=int(ret["imgSize"])
oem_bin=bin[turned_old+64:turned_old+64+size]
oem_file.write(oem_bin)
out_text=f"[{hex(turned_old)}] {data.hex(' ')}\n"
f.write(out_text)
return kunlun
def bin_to_hex_file(bin_file_name:str,hex_file_name:str,enc=0):
with open(bin_file_name,mode='rb') as f:
bin=bytearray(f.read())
if(enc):
myprint("start decrypt")
pat=(bin[12]^0x00)&0xff
myprint(f"decrypt image:{hex(pat)}({_PatternType.get(pat,'unknown')})")
for index in range(len(bin)):
bin[index]=bin[index]^pat
with open(hex_file_name,mode='w+',encoding="utf-8") as f:
# oem_bin 去除原始后缀 .bin.txt 添加新后缀 -oem.bin
oem_name=hex_file_name[0:-8]+'-oem.bin'
oem_name=os.path.normpath(oem_name)
with open(oem_name,mode='wb+') as oem_f:
kl=bin_to_hex(bin,f,oem_f)
# 调用oem_tool 打印oem信息
oem_tool=os.path.join(bin_path(),f"{kl}_oem.exe")
if(os.path.exists(oem_tool)):
cmd_str=f"{oem_tool} --parse={oem_name}"
with os.popen(cmd_str) as f:
for line in f.readlines():
myprint(line.strip())
# os.system(cmd_str)
else:
myprint(f"oem_tool not found: {oem_tool}")
def bin_file_decrypt(bin_file:str):
with open(bin_file,mode='rb') as f:
bin=bytearray(f.read())
# 自动判断是否需要解密
if ((bin[12]==bin[13])and(bin[12]!=0x00)):
pat=(bin[12]^0x00)&0xff
myprint(f"decrypt image:{hex(pat)}({_PatternType.get(pat,'unknown')})")
for index in range(len(bin)):
bin[index]=bin[index]^pat
else:
pat=bin[1]
myprint(f"copy image:{hex(pat)}({_PatternType.get(pat,'unknown')})")
with open('tmp.bin',mode='wb+') as f:
f.write(bin)
return "tmp.bin"
def clear_tmp():
tmp_list=['tmp.bin']
for item in tmp_list:
if os.path.exists(item):
os.remove(item)
# bin_to_hex.py input_file
if __name__ == "__main__":
if(len(sys.argv)>=3):
enc=1
else:
enc=0
bin_to_hex_file(sys.argv[1],"work/"+sys.argv[1]+".txt",enc)