Compare commits

...

10 Commits

Author SHA1 Message Date
ranchuan
3b73d64861 添加pg的bootram; upload flash时自动输入密码 2025-08-12 16:37:36 +08:00
ranchuan
c4eee52fb9 添加bootram 密码计算脚本 2025-08-11 16:07:00 +08:00
ranchuan
285f9a516e 添加提取bin文件中log的功能 2025-05-30 14:35:09 +08:00
ranchuan
e1fbee6ef1 规避下载固件时可能识别不到标志字符串的风险 2025-03-03 11:30:26 +08:00
ranchuan
a5a514b752 更新ram.bin为支持配置参数的版本 2025-02-28 16:50:35 +08:00
ranchuan
a749155a8b 烧录flash时配置波特率,解决只下载ram时不能下载pg的问题 2025-02-28 16:27:10 +08:00
ranchuan
2ded79544b 解决串口部分字符乱码导致全部打印异常的问题 2025-02-20 15:17:36 +08:00
ranchuan
e86adb63c9 修改pg的rom下载关键字 2025-02-19 19:15:26 +08:00
ranchuan
e2649fd66e 下载或上传flash时也可以通过 --ram_file 指定ram.bin 2025-02-19 18:51:31 +08:00
ranchuan
faa480ed9f 串口消息通过颜色区分 2025-02-19 18:33:52 +08:00
10 changed files with 233 additions and 23 deletions

View File

@@ -9,4 +9,9 @@
2024.10.15
烧录文件可能会加密bin的第一个字节表示加密方式 第二个字节表示加密种子,加密算法根据这个种子来计算
好像加密方式都用的方式3 异或所以取第一个字节与3异或就能得到加密种子
好像加密方式都用的方式3 异或所以取第一个字节与3异或就能得到加密种子
2025.8.11
添加计算bootram password的脚本 进入bootram之后输入 f i 查看chip id
然后运行python pass.py chip_id 计算password
然后在bootram中输入 PSS password 来解除限制

View File

@@ -47,6 +47,7 @@ _DevType={
0x01:"devV1kunlun1",
0x02:"devV1kunlun2",
0x03:"devV1kunlun3",
0x04:"devV1Pangu",
0xFF:"devV1Max"
}

BIN
bin/bootram_kl4.bin Normal file

Binary file not shown.

113
bin/get_log.py Normal file
View File

@@ -0,0 +1,113 @@
import os
import sys
import struct
import dataclasses
from bin.log import myprint
from bin.log import mywrite
STR_YELLOW="\033[0;33m"
STR_END="\033[0m"
@dataclasses.dataclass
class cli_msg_hdr_t:
src_mac:bytearray
target_mac:bytearray
module_id:int
cli_crc:int
msg_id:int
auto_ack:int
reserved2:int
msg_len:int
sn:int
@classmethod
def __init__(self, data:bytearray):
self.src_mac=data[0:6]
self.target_mac=data[6:12]
self.module_id=struct.unpack("<H", data[12:14])[0]
self.cli_crc=struct.unpack("<H", data[14:16])[0]
self.msg_id=struct.unpack("<H", data[16:18])[0]
self.auto_ack=struct.unpack("<B", data[18:19])[0]&0x01
self.reserved2=struct.unpack("<B", data[19:20])[0]
self.msg_len=struct.unpack("<H", data[20:22])[0]
self.sn=struct.unpack("<H", data[22:24])[0]
@dataclasses.dataclass
class payload_t:
fw_version:int
time_stamp:int
seq:int
mod_msg:int
payload_len:int
@classmethod
def __init__(self, data:bytearray):
self.fw_version=struct.unpack("<I", data[0:4])[0]
self.time_stamp=struct.unpack("<I", data[4:8])[0]
self.seq=struct.unpack("<I", data[8:12])[0]
self.mod_msg=struct.unpack("<I", data[12:16])[0]
self.payload_len=struct.unpack("<I", data[16:20])[0]>>16
def get_log(log_file:str):
with open(log_file, 'rb') as f:
data=f.read()
save=data[0x143000:0x144580]
with open("save.bin", 'wb+') as f:
f.write(save)
def find_log(data):
for i in range(0, len(data), 0x20):
if data[i:i+2]==b'$$':
myprint(f"log offset={hex(i)}")
return i
return -1
def print_log(log_file:str):
with open(log_file, 'rb') as f:
data=f.read()
off=0
# addr表示相对于bin文件的地址
addr=off
if(off<0):
myprint("not found log")
return
data=data[off:]
while len(data)>0:
off=data.find(b'$$')
if(off<0):
break
addr+=off
myprint(f"off={hex(addr)}")
data=data[off+2:]
addr+=2
end=data.find(b'&&')
if(end<0):
break
a=cli_msg_hdr_t(data[0:24])
# msg_len减去的是payload的长度
myprint(f"msg_len={a.msg_len-20}")
if(a.msg_len!=end-24):
myprint(f"msg_len error")
continue
# a=payload_t(data[24:44])
# print(a)
pstr=data[44:end]
for i in range(len(pstr)):
if(pstr[i]&0x80):
pstr=pstr[:i]
break
try:
mywrite(f"{pstr.decode('utf-8')}")
except:
mywrite(f"{pstr}")
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: python get_log.py <log_file>")
sys.exit(1)
log_file = sys.argv[1]
print_log(log_file)

Binary file not shown.

Binary file not shown.

BIN
bin/kl4_ram_build.bin Normal file

Binary file not shown.

View File

@@ -5,6 +5,11 @@ import sys
# 同一个进程中所有调用这个文件的 .py 文件都使用这个变量
_log_fp=None
STR_RED="\033[0;31m"
STR_BLUE="\033[0;34m"
STR_YELLOW="\033[0;33m"
STR_END="\033[0m"
def _time():
return '['+time.strftime("%Y-%m-%d %H:%M:%S")+']'
@@ -30,7 +35,7 @@ def mywrite(data:str):
txt=txt.replace('\n\n','\n')
_log_fp.write(txt)
_log_fp.flush()
sys.stdout.write(data)
sys.stdout.write(f"{STR_YELLOW}{data}{STR_END}")
sys.stdout.flush()
def log_init(file_name:str):

103
kunlun.py
View File

@@ -12,6 +12,7 @@ import os
import binascii
import threading
import argparse
import base64
from bin.log import myprint
from bin.log import log_init
from bin.log import mywrite
@@ -22,6 +23,9 @@ from bin.bin_to_hex import load_flash_info
from bin.bin_to_hex import check_bin_type
from bin.base import bin_path
from bin.factory_mode import ftm_handle
from bin.crc import CRC16
from bin.get_log import print_log
from password import bootram_pssword
def init_send(s_port:serial.Serial, send_str:str):
@@ -29,7 +33,7 @@ def init_send(s_port:serial.Serial, send_str:str):
send_str=send_str.encode('utf-8')
key_words={
b"WQKL":b"Recieving RAM-IMAGE in xmodem : C",
b"HZPG":b"waiting recieve image: C"
b"HZPG":b"waiting receive image: C"
}
while True:
s_port.write(send_str)
@@ -73,7 +77,7 @@ def burn_flash_bin(s_port:serial.Serial, x_modem:xmodem.XMODEM, f_file):
continue
print_device_str(tmp)
s_info += tmp
if(s_info.find(b'CCC')>=0 and bytes2read==1):
if(s_info.find(b'CCC')>=0 and bytes2read==1) or (s_info.find(b'Recieving FLASH-IMAGE in xmodem : C')>=0):
m_flash=True
else:
m_flash=False
@@ -119,13 +123,20 @@ def download_callback(total_packets, success_count, error_count):
# 打印串口收到的字符
def print_device_str(data:bytearray):
data:list[bytearray]=data.split(b"\r\n")
for item in data:
try:
d=item.decode('utf-8')
myprint("DEVICE:",d.strip())
except Exception as e:
myprint("DEVICE:",item)
data=data.replace(b"\r\n",b"\n")
index=0
while index<len(data):
if(bytes([data[index]]).isascii()):
index+=1
else:
break
try:
d=data[:index].decode('utf-8')
mywrite(d)
if(index<len(data)):
mywrite(f"{data[index:]}")
except Exception as e:
mywrite(f"{data}\n")
@@ -244,6 +255,16 @@ def calc_flash_info_name():
# 计算bootram密码
def calc_bootram_pssword(info_file:str):
with open(info_file,mode='r',encoding='utf-8') as f:
lines=f.readlines()
for line in lines:
if(line.startswith('Chip Id')):
chip_id=line.split(':')[-1].strip()
password=bootram_pssword(chip_id)
return f"{password:08x}"
# 上传固件
def upload_fun():
@@ -254,6 +275,12 @@ def upload_fun():
print_device_str(ser_read_data)
with open(calc_flash_info_name(),mode='w+',encoding='utf-8') as f:
f.writelines(ser_read_data.decode('utf-8').split('\r\n'))
# 输入密码
password=calc_bootram_pssword(calc_flash_info_name())
ser.write(f"PSS {password}\n".encode("utf-8"))
time.sleep(0.5)
ser_read_data=ser.read(4096)
print_device_str(ser_read_data)
# 显示image信息
ser.write(b"f s\n")
time.sleep(1)
@@ -273,9 +300,30 @@ def upload_fun():
myprint("Transform to hex end.")
# 发送配置信息
def send_cfg_fun():
global nb_rate
rate_table={
115200:0,
460800:1,
1500000:2
}
baud_cfg=f"u_baud={rate_table.get(nb_rate,0)}"
cfg_str=base64.b64encode(baud_cfg.encode(encoding='utf-8')).decode(encoding='utf-8')
text=f"ram_config:{cfg_str}:gifnoc_mar"
crc=CRC16(text.encode('utf-8'))
cfg_text=f"{text}#crc={crc}"
# print(cfg_text)
ser.write(f"{cfg_text}\n".encode("utf-8"))
# 烧录固件
def burn_fun():
time.sleep(3)
# time.sleep(1)
send_cfg_fun()
# time.sleep(0.02)
ser_read_data=ser.read(4096)
print_device_str(ser_read_data)
ser.baudrate=nb_rate
@@ -349,6 +397,7 @@ def global_def():
global layout_index
global log_file
global skip_ram
global extract_log
args = parser.parse_args()
init_str="WQKL"
@@ -359,23 +408,28 @@ def global_def():
log_timeout=args.timeout
layout_index=args.layout_index
skip_ram=args.skip_ram
extract_log=args.extract_log
# 上传或者下载flash镜像
if(args.flash_file is not None):
iot_flash_file=args.flash_file
log_file=iot_flash_file
if(args.ram_file is not None):
ram_file=ram_file_redirect(args.ram_file)
if(os.path.exists(iot_flash_file)):
function_type='download'
iot_flash_file=bin_file_decrypt(iot_flash_file)
if args.kunlun_version is None:
args.kunlun_version=check_bin_type(iot_flash_file)
ram_file=f'kl{args.kunlun_version}_ram_build.bin'
ram_file=os.path.join(bin_path(),ram_file)
if ram_file is None:
ram_file=f'kl{args.kunlun_version}_ram_build.bin'
ram_file=ram_file_redirect(ram_file)
else:
function_type='upload'
ram_file=f'bootram_kl{args.kunlun_version}.bin'
ram_file=os.path.join(bin_path(),ram_file)
if ram_file is None:
ram_file=f'bootram_kl{args.kunlun_version}.bin'
ram_file=ram_file_redirect(ram_file)
if(args.kunlun_version is None):
print("请指定参数 -k")
sys.exit(-1)
@@ -389,6 +443,11 @@ def global_def():
function_type='ram'
ram_file=ram_file_redirect(args.ram_file)
log_file=args.ram_file
if(args.kunlun_version is None):
print("请指定参数 -k")
sys.exit(-1)
elif(args.kunlun_version == "4"):
init_str="HZPG"
elif(args.bin_convert is not None):
function_type='convert'
iot_flash_file=args.bin_convert
@@ -421,10 +480,11 @@ def parser_init():
parser.add_argument('-t','--timeout',action='store',type=float,default=5,help='启用log时接收log的时间')
parser.add_argument('-i','--layout_index',action='store',type=int,help='解析接收到的flash文件或转换bin文件时使用的layout不指定则不解析')
parser.add_argument('--b_rate',action='store',type=int,default=115200,help='下载ram程序 上传flash数据 控制台 接收log等 使用的串口波特率')
parser.add_argument('--nb_rate',action='store',type=int,default=1500000,help='下载flash程序使用的串口波特率')
parser.add_argument('--nb_rate',action='store',type=int,default=1500000,help='下载flash程序使用的串口波特率支持115200,460800,1500000')
parser.add_argument('--ftm',action='store_true',default=False,help='进入工厂模式')
parser.add_argument('--list',action='store_true',default=False,help='列出所有.bin文件')
parser.add_argument('--skip_ram',action='store_true',default=False,help='下载flash文件时是否跳过下载ram.bin的步骤默认否')
parser.add_argument('--extract_log',action='store_true',default=False,help='是否提取bin中的log信息默认否')
@@ -438,15 +498,11 @@ def print_help():
'''
print(help)
# 如果不指定上传还是下载 脚本会根据输入文件是否存在来决定上传还是下载
# kunlun.py [com] [kl1/kl3] [upload.bin/download.bin] <key>
# kunlun.py [com] [ram.bin]
# kunlun.py [file.bin] <enc>
if __name__ == '__main__':
function_type=None # 功能类型 "download" 下载,"upload" 上传,"ram" 下载ram"convert"" 转换bin
time_stamp_start, time_stamp_end = 0, 0
init_str, serial_com, b_rate, nb_rate, ram_file, iot_flash_file, ser = None, None, None, None, None, None, None
upload_key, parser, layout_index, log_file=None, None, None, None
upload_key, parser, layout_index, log_file, extract_log=None, None, None, None, False
user_log=False
log_timeout=0
skip_ram=False
@@ -459,6 +515,8 @@ if __name__ == '__main__':
log_init(calc_log_file_name())
if(function_type=='convert'):
bin_to_hex_file(iot_flash_file,calc_hex_name(),layout_index)
if(extract_log):
print_log(iot_flash_file)
sys.exit(0)
if(function_type=="list"):
l=list_bin_file()
@@ -491,6 +549,8 @@ if __name__ == '__main__':
if(function_type=='upload'):
upload_fun()
if(extract_log):
print_log(calc_upload_name())
elif(function_type=='download'):
burn_fun()
clear_tmp()
@@ -511,4 +571,5 @@ if __name__ == '__main__':
read_input(ser)
# if __name__ == "__main__":
# read_input(None)
# nb_rate=115200
# send_cfg_fun()

25
password.py Normal file
View File

@@ -0,0 +1,25 @@
import sys
from bin.crc import CRC32
def bootram_pssword(chip_id:str):
data=bytearray(b'Aerospace C.Power')
data+=bytearray(chip_id.encode('utf-8'))
off=64-len(data)
if(off>0):
data+=bytearray(b'\x5A'*off)
pss=CRC32(data)
# print(f"data={data} len={len(data)}")
print(f"bootram_pssword:{pss:08x}")
return pss
print(f"chip_id err.")
return 0
if __name__ == '__main__':
bootram_pssword(sys.argv[1])