基于STM32的IAP技术分享

1.烧录过程说明

在这里插入图片描述
公司做产品时,在线升级用户程序是一个比较常用的功能。那么如何给用户升级APP程序呢?难道让用户像开发人员一样使用一个仿真器去下载程序吗?这显然是不行的,大批量的产品一般都是通过串口去升级APP程序。
一次烧录:通过厂家bootloader烧录用户自定义bootloader,再通过用户自定义bootloader烧录用户APP。
二次烧录:如上图所示,一个产品在出厂时为了具备在线升级的功能,在出厂时生产厂家会先烧录一个自定义bootloader,然后再烧录用户APP程序。后续升级时通过用户APP程序跳转到用户自定义bootloader,然后通过用户自定义bootloader对用户APP程序进行升级。
对于新手而言,可能不太理解整个过程,因此这里有必要解释厂家bootloader、用户自定义bootloader、用户APP的区别。
厂家bootloader:芯片厂家编写的一段程序,这段程序不可更改。它的作用是通过串口去解析上位机下发的.bin文件然后将其写入FLASH中,即从0x08000000开始写入程序。与平常通过JLINK调试器下载程序不同的是,它是用串口实现烧录的。运行厂家bootloader的程序需要设置芯片boot0、boot1引脚的状态。这个后续会讲到。
用户自定义bootloader:这是开发人员自己编写的一段程序,用于实现和厂家bootloader一样的功能。它是可以自定义的,烧录时的通讯协议也由自己定义。它做的操作就是在对FLASH进行擦除和写入,将用户APP程序的.bin写入到用户APP程序的地址区域即可。用户自定义bootloader它的起始地址也是从0x08000000开始,其大小需要根据实际情况进行确定。所以我们需要做用户自定义bootloader和用户APP的地址划分。
用户APP:这个就是我们平常编程时的用户程序,只不过设置了一个偏移地址,它不是从芯片的0x08000000地址开始运行的,而是从我们设置的偏移地址开始运行。

为什么要自己写一个bootloader呢?直接用厂家的不香吗?
前面有讲到,运行在厂家bootloader需要设置boot0、boot1的状态。如果每次升级用户APP都去设置boot0和boot1的状态,这样很麻烦。而且厂家bootloader属于明文烧录,会造成程序泄密。

2.厂家bootloader

一般情况下正常运行程序时单片机是从主闪存FLASH运行,boot0和boot1都接GND。当使用ISP工具通过厂家bootloader进行程序烧录时,需要从系统存储器运行,系统存储器有一段厂家已经写好的程序,该区域只读不可被更改。从系统存储器运行需要设置单片机boot引脚,设置boot1=0,boot0=1,单片机上电将运行芯片厂商自带的bootloader程序。当运行在厂家bootloader时就可以通过USART/CAN来下载程序了。
厂家bootloader中做的事情其实就是解析上位机下发的.bin文件并将其写入到主闪存储器(FLASH)中。
在这里插入图片描述
STM32芯片有免费使用的ISP工具,可以在其官网进https://www.st.com行下载。软件虽然是免费的,但是需要注册该网站的账号才能进行下载。这款工具可以在设置芯片的boot引脚之后,下载用户程序编译生成的.hex文件和.bin文件。这里为了方便大家,可以从我的百度云盘进行下载。
在这里插入图片描述
链接:https://pan.baidu.com/s/1Q6CRqyjgDkeFaHG2GNeT_g
提取码:0y3b

软件打开后如下图所示。如果芯片的boot0已经拉高,那么就可以点击下一步进行下载了。如果boot0没拉高,测试时发现在如下界面下点击下一步软件会卡住。必须用任务管理器关掉后再重新打开软件才行,不知道是不是这个软件的bug。
在这里插入图片描述

3.bootloader区和APP区空间划分

这里说的boot区指的就是用户自定义的bootloader程序。根据芯片的型号查看其FLASH存储器的地址划分,本例中以STM32F103ZET6为例,它属于大容量产品,大小为512K,一共256页,每页2K。这里在划分区域时最好按照页大小进行划分,因为FLASH写入时必须先擦除页后在进行页的写入。
bootloader区需要多大的空间,根据编译后的map文件进行估算即可。记得留出一定的裕量。如下图所示总的大小为6.45KB,它是code+RO Data+RW Data的总和。
考虑到一定裕量和芯片页大小为2K,本次设置bootloader区域为16K。
得出:
bootloader的区域就是0x08000000~0x08003FFF
APP的区域就是0x08004000~0x0807FFFF

Code: 代码段,存放程序的代码部分;
RO-data: 只读数据段,存放程序中定义的常量;
RW-data: 读写数据段,存放程序中定义并且初始化的全局变量和静态变量;
ZI-data: 0数据段,存放程序中定义了但没有初始化的全局变量和静态变量;
在这里插入图片描述
在这里插入图片描述

4.bootloader区和APP程序内容说明

bootloader程序需要实现的内容:
1.解析上位机下发的.bin文件的内容,然后写入到FLASH中,写入完成之后跳转到APP用户程序
2.正常上电时,如果没有升级APP的指令则跳转至APP用户区运行。这里后续可以进行改进,首先对APP区进行一个检测,如果没有APP程序则不进行跳转。本次实例中没有做这个功能,而是通过串口连续发送3次0xf3指令后跳转到APP区。
APP程序需要实现的内容:
1.正常情况下,上电后最终会运行APP程序。APP程序中需要做一个跳转到bootloader区的操作,接收到上位机的特定指令进行跳转。这个操作的目的就是让bootloader区运行的程序去重新对APP区的FLASH进行编程。也就是所谓的在线升级啦。bootloader区操作完成之后再跳转到APP区就完成了用户APP的升级。

5.实验

5.1实验所用到的上位机软件

1.STMFlashLoader Demo(ST厂家的串口烧录工具,用于烧录bootloader程序)。本次试验的芯片为STM32F103ZET6。
2.fireTools(野火的一款上位机,基于Ymodem文件传输协议,用于烧录APP程序),可以在野火的官网上进行下载https://doc.embedfire.com/products/link/zh/latest/deskapp/ebf_trace_tool.html。这里使用的上位机版本为V1.0.2.9。
在这里插入图片描述
由于本人也是需要工作,精力有限,所以都是用的现成的软件,懒得再去造轮子了。这里讲一下为什么使用野火的这款串口调试软件,因为这个软件定义了一套文件传输协议,可以对发送的数据进行校验,保证了数据的可靠性,使得APP程序的升级更加稳妥,不至于出现错误。这种现成的软件肯定还有很多,看自己的需要进行选择。

5.2 bootloader和APP用户程序的偏移地址设置

根据之前已经划分好的bootloader和APP的区域,在keil中进行设置。
bootloader程序的keil工程中地址设置如下:
在这里插入图片描述

APP程序的keil工程中设置如下:
在这里插入图片描述

5.3 bootloader和APP用户程序中的细节

1.APP程序中需要设置APP用户程序的栈顶地址,也就是0x08004000,代码如下所示,将其放在SystemInit函数中,SystemInit函数是上电后执行的第一个函数,在启动文件里面可以看到,执行完SystemInit后才去执行的main函数。实际试验时将设置偏移地址的语句放在main函数的第一条语句也是可以的。
在这里插入图片描述
在这里插入图片描述

STM32单片机的上电启动过程可以查看野火的《STM32库开发实战指南——基于野火霸道开发板-20211109》手册。
手册中的第15章和第47章看完之后能对其有更深入的了解。这里要知道的是,单片机上电后在进入main前还做了很多其他的操作,而不是直接进入main函数的。

2.生成.bin文件,正常我们编译都只会在obj文件夹下生成一个hex文件。我们在进行APP升级时需要将.bin文件中的内容写入到FLASH中才行。那么怎么生成.bin文件呢。在keil中输入做如下设置,即可在生成.hex的地方生成.bin文件。
fromelf.exe --bin -o “$L@L.bin” “#L”
在这里插入图片描述

3.bootloader的keil配置不需做其他的特殊处理,平时怎么编程就怎么弄。APP的keil工程一般会配置两个工程,一个用于正常调试时使用不设置偏移地址,目的是为了方便调试。另一个keil工程需要设置一个偏移地址。APP程序中可以使用一个宏定义去配置偏移地址,开启了宏则设置偏移,不开启则不设置。宏定义放在keil的设置中,如下所示。当调试完成之后,使用带偏移地址的keil工程生成一个.bin文件,该.bin文件用做程序升级时往单片机下载的.bin。
在这里插入图片描述

4.APP程序设置偏移地址后,如何调试问题。可以配置一个.ini文件。这里网上有很多教程,所以就不多做介绍了。值得注意的就是配置完.ini文件后,Debug时不要擦除FLASH,否则会导致bootloader区被擦除。这样就看不到bootloader区对APP区的影响了。

5.4烧录的操作步骤以及实验中遇到的问题

1.首先烧录bootloader程序,在烧录前将boot0设置为高电平,让其进入厂家boot,然后通过STMFlashLoader Demo去烧录编译好的bootloader程序,.bin和.hex都可以。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.等待bootloader烧录完成后,通过串口1烧录APP程序。烧录完APP后,bootloader进行跳转,通过串口发送跳转指令,跳转到APP后,APP能正常运行说明成功。
如果发现bootloader跳转后,APP没有运行,怎么查问题?
(1)确定APP烧录的正确性,利用J-FLASH软件将芯片的FLASH内容读上来。
在这里插入图片描述

截取APP程序的地址段的内容和APP烧录的.bin文件作对比,如果一致说明APP正确烧录,那么就是bootloader和APP之间的跳转处理有问题。重点查看跳转的代码写的是不是有问题,APP程序中的偏移设置的是不是有问题,或者APP本身程序有跑飞的问题。
如果内容不一致,说明bootloader在写入APP的FLASH地址段的处理有问题,导致写入了错误的APP程序。

3.跳转到APP后能正常运行,但是串口却死活进不了空闲中断。通过printf查看寄存器的方式,打印出了RCC、USART1、AFIO这几个寄存器中的内容,发现配置是正确的,和正常运行下的寄存器的值一样。bootloader跳转前有去关中断、清除时钟配置、清除所有中断标志位的操作。跳转到APP后开启了中断,APP中开了一个定时器,定时器中断中有一个LED取反操作,对外的现象是LED在闪,说明跳转到APP后还是能进中断的。但是APP的串口1死活接收不到数据,进不了空闲中断,但是可以发送数据,这个问题卡了很久。想了想是不是在串口中断中跳转APP导致的呢,因为bootloader跳转的操作是在串口中断中做的,做了关中断、复位时钟、清除所有中断标志的等操作。
后来将跳转放在串口中断外面处理则解决该问题,串口中断中只是打一个标记。

6.不足之处与思考

1.其实做在线升级不单单是为为了在线升级,更多的是为了保护自己的劳动成果不被窃取。这里就需要做一些加密的工作。
2.关于加密的一些思考:
由于在烧录用户bootloader的时候是用的芯片厂家定义的下载协议,因此属于明文烧录,如果这个过程被截获了报文。那么用户自定义bootloader程序内容就会被截获(通讯链路焊接飞线+逻辑分析仪抓取数据即可)。获取者通过反编译即可知道用户自定义bootloader中做了啥事。一般对于公司而言,烧录APP的上位机都是自己做的,公司想加密,必定在烧录APP的上位机上做文章。这个APP烧录软件与用户自定义bootloader之间的交互,肯定会定义一套加密和解密的算法,烧录APP上位机做加密,用户自定义bootloader做解密。类似于密码本,即使你抓取了通讯之间的内容,但是没有密码本,就没办法知晓数据内容。
说到这里,试想如果用户自定义bootloader程序内容被截取,通过反编译技术即可知晓用户自定义bootloader的程序内容,从而破解这套加密解密算法,那么整个APP程序的烧录将无秘密可言,APP程序也将被破解。
既然这样,那么就必须保证用户自定义bootloader内容不被截获,但是烧录用户自定义bootloader的时候是用的芯片厂家定义的协议,这个属于明文,大家都知道的呀,这是无解的,因为这个是用户改变不了的。
因此这里衍生出一个思路就是:烧录用户自定义bootloader也自己做一个上位机,在这个上位机中做权限设置,就是在拿到用户自定义bootloader的.bin文件后,必须有特定权限的人才能烧录,简单来说就是设置一个密码。但是这个烧录协议还是属于明文,当这个用户自定义bootloader的.bin文件外泄时,其他人换一个烧录软件按照芯片厂家的下载协议还是照样烧录。像是陷入死胡同了。。。。。。所以单单是做这个上位机的权限设置还是不行的,还得在.bin文件上下功夫,可以将.bin文件利用一套特定的规则打乱并进行加密,上位机中对这个被打乱的.bin文件进行重组并且解密。
感觉这样比较稳妥了吧?但还是有被破解的可能,如果.bin和上位机软件全部外泄,那么也就被破解了。所以当这两个机制建立完成之后,还得设置上位机软件权限,提到另外一个技术“加密狗”,只有手里掌握加密狗的人才可以使用这个上位机软件。加密狗就是钥匙,没有钥匙插入电脑,那么上位机将不能被使用,也就不能对被加密重组的.bin文件进行解密了。只有同时拿到加密狗+.bin文件+上位机才可以进行破解。这三样东西也是有可能的被同时获取的,但这个技术机制相对来说已经很完善,在此基础上进行修补即可。比如说加密狗中做烧录次数限制、定时更换加密算法,类似于电视剧中的定期更换密码本。
以上是软件层面的防破解,一般破解者为了复刻产品,肯定是从两个方面下手,软件是一方面,第二个方面就是抄板。所以硬件上也要做防抄板技术,比如说设计多层板、埋盲孔、各种误导陷阱、芯片上丝印擦除等。
但是从人的角度出发,没有完善不可破解的机制,因为机制都是被人设计出来的。技术上防破解做足了功夫,也需要考虑从人的角度。因为设计这个机制的人以及在这套机制流程下工作的人肯定是可以找到漏洞的,如果有足够的利益,那么这个机制是有可能被出卖的。当然,这是领导者需要考虑的问题,这里留给大家一个思考的空间。
3.实验中的bootloader程序和APP程序的.bin都是独立的,后续可以利用一个软件工具将其合并成一个。然后根据对加解密的思考,合并后的.bin通过两个上位机软件分别进行烧录,一个上位机专门用于烧录bootloader,一个上位机专门用户烧录APP。
4.以上提到的加解密,所要做的内容太多了,可能需要集合多人的技能才可以完成,毕竟不是每个人都是全能人才。这里想到一个简单的加密方式,就是利用芯片的唯一的序列号做加密,先读取序列,程序中做一个判断芯片序列号的操作,如果芯片序列号不正确则while1死循环,不执行往下的程序。但是这个方法的缺点不适合大批量生产,因为每个芯片都需要上电读一次序列号,并且修改程序内容,将其需要判断的序列号设置为当前芯片的序列号。但是这个方法简单粗暴,小批量的时候可以考虑一下。
5.APP区域的FLASH需进行CRC自检,所以在编译生成HEX文件时需要在HEX文件末尾添加CRC校验值,可以借助工具进行添加。本次试验没去做这个功能,后续可以加上。bootloader里面校验APP的FLASH,错误不进行跳转

7.参考资料

《STM32F10X闪存编程手册》
《STM32库开发实战指南——基于野火霸道开发板-20211109》
知乎:
https://www.baidu.com/link?url=DG2Zc2Zfo8r2B2etnxAfUC-8r2HTCO2HEdTVCKvi-MXonB6a-9rsJKQw1jIbIPBP&wd=&eqid=f3bf01c50038199000000004645793da
正点原子相关教程

8.试验代码

bootloader程序:
链接:https://pan.baidu.com/s/1iQRH89u6o1mASJEu2ZDUIA
提取码:4a0h
APP程序:
链接:https://pan.baidu.com/s/1KwZlSpaWeMMxjOxoT11vLA
提取码:47b1
Ymodem协议说明:
链接:https://pan.baidu.com/s/15v7nRoC_n5wgrF-nVsgo6g
提取码:8e0x

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZuoYoPaPa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值