sunnyqd 发表于 2014-8-24 17:22:59

【网友经验分享】CRC32进行程序完整性检查,bootloader程序

本帖最后由 FSL_TICS_ZJJ 于 2014-9-11 14:46 编辑

这是我自己经常采用的的一种方法,如觉得有效,欢迎支持,如有任何需要,欢迎站短。
设有两个int32值crc32Value和crc32Value2存放在FLASH存储空间的最末尾
这篇文章面向于以下几个情境:
1. 无bootloader,裸程序运行,程序运行前进行自检
2. 有bootloader,bootloader为预先由开发人员(你)烧写到MCU里,复位后先运行bootloader,bootloader进行应用程序的完整性检查,完整性检查失败后,进行bootloader操作。否则,跳转至应用程序
3. 有bootloader,或者无bootloader,原始程序里面有加密的字节,根据MCU唯一ID计算出来的校验值。为表述方便,设这个校验值为CheckValue,类型为int32。对于这种情况
        > 原始程序里有一个setCheckValue()的程序,
        > 一个erase_setCheckValue()的程序,
        > 和一个setCRC32Value2()的程序。
编译时,CheckValue的初始值为0xFFFFFF。程序第一次运行时,setCheckValue()根据MCU的唯一ID计算出一个值,FLASH在线烧写到CheckValue的地址,并且之后,erase_setCheckValue()将setCheckValue()所在地址的程序擦除,然后调用setCrc32Value2()计算新的CRC32值,FLASH在线烧写到crc32Value2。之后程序进入正常运行阶段,在程序的正常运行阶段,校验CheckValue和MCU唯一ID值的关系来确定程序合法性。

对于第1、2种情况,程序的完整性校验实现起来很简单,因为程序代码在运行时不改变,因而只需要一个crc32Value即可。

对于第3种情况,程序在第一次运行前,需要完整性检查,使用crc32Value即可。程序在第一次运行后,程序本身的代码发生了变化,需要使用另一个值crc32Value2进行检查。

总结第1、2、3种情况,检查过程可以统一为,检查crc32Value的值是否正确,若不正确,检查crc32Value2的值是否正确。若都不正确,则程序错误,进行bootloader错误处理阶段。

使用Keil MDK时,我们为了方便,需要自动生成crc32Value,下面主要说明编译器的设置,单片机代码端的上述逻辑的处理是比较方便的,以后再说
首先,在options里面添加一项

这项指定编译完成后,执行autocalcrc32.bat批处理程序
"F:\Program Files\Keil\ARM\ARMCC\bin\fromelf.exe" --bin --bincombined --output="E:\Project\Workspace\test\final.bin" "E:\Project\Workspace\test\IO_Toggle\MDK-ARM\IO_Toggle\IO_Toggle.axf"

"E:\Project\Workspace\test\Libraries\AUTHORIZSTION_LIB\crc32\crc32.exe" "E:\Project\Workspace\test\final.bin" "E:\Project\Workspace\test\Libraries\AUTHORIZSTION_LIB\authorization_auto_generated.c" 393216
其中第一条,调用fromelf文件,生成二进制程序镜像.bin
第二条,调用crc32.exe生成文件authorization_auto_generated.c,393216为bin文件的大小。.c文件内容为

变量program_crc32_chk_value_original为编译时的CRC32值
变量program_crc32_chk_value_reserved为crc32Value2作用的值


其中crc32.exe为我自己编译的程序,如下为文件crc32.c:
/*****************************************************
** Name         : crc32.c
** Author       : wsun
** Version      : 2.1
** Date         : 2014-8-24
** Description: CRC32 Checking For Cortex Embedded
******************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <errno.h>
//#include <unistd.h>
//#include <fcntl.h>
//#include <sys/stat.h>

/*指定程序的大小*/
/*实际校验字节的大小为DOCSIZE-8,留有两个int32的空间*/
/*DOCSIZE-8应该小于MAXBUFSIZE*/
#define MAXBUFSIZE   1024*1024

static void usage(void);
static int calc_img_crc(const char * in_file, unsigned int * img_crc, unsigned int docsize);

static void usage(void)
{

}


/*我的32位int数据CRC32计算程序,应该与下位机的一致*/
unsigned int CrcGen_INT32(unsigned int crc,unsigned int data[], unsigned int size)
{
unsigned int i;
    for(i=0;i<size;i++){
      unsigned int temp = data;
                unsigned int j;
      for(j=0;j<32;j++){
            if( (crc ^ temp) & 0x80000000 ){
                crc = 0x04C11DB7 ^ (crc<<1);
            }else{
                crc <<=1;
            }
            temp<<=1;
      }
    }
    return crc;
}
/*
**计算大文件的CRC校验码:crc32函数,是对一个buffer进行处理,
**但如果一个文件相对较大,显然不能直接读取到内存当中
**所以只能将文件分段读取出来进行crc校验,
**然后循环将上一次的crc校验码再传递给新的buffer校验函数,
**到最后,生成的crc校验码就是该文件的crc校验码.(经过测试)
*/
unsigned char buf;
static int calc_img_crc(const char *in_file, unsigned int *img_crc, unsigned int docsize)
{
    FILE* fd;
    int nread;
        int size;
    int ret;

    /*第一次传入的值需要固定,如果发送端使用该值计算crc校验码,
    **那么接收端也同样需要使用该值进行计算 */
    unsigned int crc = 0x6E59438A; //as "wsun", crc32value is 0x6E59438A;

    fd = fopen(in_file, "rb");
    if (!fd) {
      printf("%d:open %s.\n", __LINE__, strerror(errno));
      return -1;
    }

        size = 0;
    while ((nread = fread(buf, 1, docsize-8, fd)) > 0) {
      crc    = CrcGen_INT32(crc, (int*)buf, nread/4);
                size+= nread;
                break;
    }

    *img_crc = crc;
    printf("calculate first %d bytes of file: ",size);
    close(fd);

    if (nread < 0) {
      printf("%d:read %s.\n", __LINE__, strerror(errno));
      return -1;
    }

    return 0;
}

int main(int argc, char **argv)
{
        FILE* filsave;
        FILE* filver;
        int status;
        unsigned int ver = 0;
        unsigned int verdate = 0;
        unsigned int img_crc;
        const char          *in_file   = argv;
        const char          *out_file= argv;
        const unsigned intdocsize    = atoi(argv);
        if (argc < 3) {
                usage();
                exit(1);
        }

        /*Version 号产生程序,做相应更改以适用你自己的代码*/
        {
                int i;
                for(i=0;__DATE__;i++)
                {
                        verdate += __DATE__;
                        verdate= verdate ^ (verdate>>1)^ (verdate>>2)^ (verdate>>3)^ (verdate>>4)^ (verdate>>5);
                }
        }

        /*计算CRC32*/
    status = calc_img_crc(in_file, &img_crc, docsize);
    if (status < 0) {
      exit(1);
    }

    printf("[%s] is:\nCRC32:%08X\n", in_file, img_crc);

        /*编译次数文件,计算当前的编译次数*/
        filver = fopen("ver.txt","r");
        if(!filver)
                {
                        filver = fopen("ver.txt","w");
                        fprintf(filver,"%d",0);
                        fclose(filver);
                        filver = fopen("ver.txt","r");
                }
        if(filver)
        {
                fscanf(filver,"%d",&ver);
                fclose(filver);
                ver ++;
                filver = fopen("ver.txt","w");
                if(filver)
                        {
                          fprintf(filver,"%d",ver);
                          fclose(filver);
                  }
                  else
                          {
                                  printf("%d:open %s.\n", __LINE__, strerror(errno));
      return -1;
                          }
        }
       else
    {
                printf("%d:open %s.\n", __LINE__, strerror(errno));
                return -1;
    }

        /*生成.c文件*/
    filsave = fopen(out_file,"w");
    if(filsave)
    {
                /*!三个变量的地址需要根据项目进行更改*/
                fprintf(filsave,"const unsigned intprogram_crc32_chk_value_original __attribute__((used)) __attribute__((at(0x0806FFF8))) = 0x%08X;\r\n",img_crc);
                fprintf(filsave,"const unsigned intprogram_crc32_chk_value_reserved __attribute__((used)) __attribute__((at(0x0806FFFC))) = 0xFFFFFFFF;\r\n");
//                fprintf(filsave,"const unsigned intCompileTick __attribute__((used)) __attribute__((at(0x0806FFF4))) = %d;\r\n",verdate);
                fclose(filsave);
    }
    else
    {
                printf("%d:open %s.\n", __LINE__, strerror(errno));
                return -1;
    }

        /*输出编译次数,退出*/
    printf("ver = %d\n",ver);

    return 0;
}


编译工具采用VC,命令行调用compile crc32.c进行编译

其中compile.bat为
@echo off

path=.\VCPack\Bin;.\VCPack\Bin;%path%

set lib=.\VCPack\Lib
set include=.\VCPack\Include

(cl kernel32.libLIBC.lib OLDNAMES.lib %1
)&&(
    link kernel32.libLIBC.lib OLDNAMES.lib%~n1.obj
)

pause


crc32.c可以根据需要修改。这里计算略去了最后的八个字节,因为是program_crc32_chk_value_original和program_crc32_chk_value_reserved的保留空间。并且文件大小需要整字大小。

Keil编译完后,会调用autocalcrc32.bat,计算出CRC32的值之后,更改文件authorization_auto_generated.c中的program_crc32_chk_value_original
之后需要重新手动编译一遍Keil,使得新的program_crc32_chk_value_original编译到最终的二进制文件里

以上是编译起部分的操作。主要实现的功能是自动生成程序的CRC32校验值,希望对大家有所帮助。

PS:我尝试了许多个CRC32计算的网站,发现应该选择http://www.zorc.breitbandkatze.de/crc.html如下的设定,和我的CRC校验结果一直
测试结果如下,可以发现结果一致:
CRC32选项:

CRC32.exe运行结果

其中text.txt为
0000

不知解释的是否清楚,希望对大家有帮助~,单片机端的实现比较简单,有需要的话,我再另写一篇{:lol:}
整个的文件

cn_x 发表于 2014-8-24 17:48:53

这又是一个精华·················· 好强的节奏,加油

丢丢时光机 发表于 2014-8-24 17:56:16

先收藏,这个后面自己有空调试玩玩

bbglx 发表于 2014-8-24 18:12:14

火钳留名,收藏了
楼主神人{:lol:}

sunnyqd 发表于 2014-8-24 18:13:37

bbglx 发表于 2014-8-24 18:12
火钳留名,收藏了
楼主神人

不敢不敢,以前我用的东西,顺便整理一下,要不我都忘了。。
这个估计用的人会比较少吧

步之道 发表于 2014-8-24 18:23:03

莫大的加精计划太有刺激性了。。。大家都开始放大招了。

slotg 发表于 2014-8-24 18:27:54

很有技术档次的帖子,感谢分享

PCBBOY1991 发表于 2014-8-24 18:34:46

不知楼主在说啥~难道是因为我不会ARM么?{:funk:}

qwert1213131 发表于 2014-8-24 18:34:52

此贴必火啊,火钳刘明

wangpengcheng 发表于 2014-8-24 18:36:23

非常详细啊,谢谢哥们了!

机器人天空 发表于 2014-8-24 18:49:53

好贴,收藏一下

chenchaoting 发表于 2014-8-24 19:00:58

楼主的飞币涨得很快啊

qinshiysb 发表于 2014-8-24 19:06:46

穿裤子的节奏哈,赞

qinshiysb 发表于 2014-8-24 19:09:35

学习了,,楼主好人

qinshiysb 发表于 2014-8-24 19:10:26

怎么飞币分分钟就破3000了

sunnyqd 发表于 2014-8-24 19:13:03

wangpengcheng 发表于 2014-8-24 18:36
非常详细啊,谢谢哥们了!

keil 下的,思想就是编译完成后自动生成含有crc32校验值的.c文件,然后编译第二次把新的校验值给编译进去,同样的方法也可以用在其它地方,嘿嘿

sunnyqd 发表于 2014-8-24 19:14:32

步之道 发表于 2014-8-24 18:23
莫大的加精计划太有刺激性了。。。大家都开始放大招了。

哈哈,我这里还有好多好东西呢,可惜手头上没有板子呢

sunnyqd 发表于 2014-8-24 19:15:20

qinshiysb 发表于 2014-8-24 19:10
怎么飞币分分钟就破3000了

每天这样的话,赶上工资了。。。

yanpenghao 发表于 2014-8-24 19:33:19

楼主这节奏简直快到不行啊~PS:楼主的win8用的还不错吧

motodefy 发表于 2014-8-24 19:33:45

好棒···收藏了

浪里白条 发表于 2014-8-24 19:36:20

楼主高手,好强悍!!

sunnyqd 发表于 2014-8-24 19:46:32

yanpenghao 发表于 2014-8-24 19:33
楼主这节奏简直快到不行啊~PS:楼主的win8用的还不错吧

被发现了啊。。lz的win8可是正版的喔

浪里白条 发表于 2014-8-24 19:56:27

sunnyqd 发表于 2014-8-24 19:46
被发现了啊。。lz的win8可是正版的喔

楼主,WIN8下用软件 兼容性好不?

浪里白条 发表于 2014-8-24 19:57:28

sunnyqd 发表于 2014-8-24 19:46
被发现了啊。。lz的win8可是正版的喔

我一直想玩玩WIN8 怕兼容性不好 WIN7下常用软件KEIL CW Cadence 这些软件能稳定运行不

tim 发表于 2014-8-24 20:00:13

好帖!先谢楼主再收藏{:victory:}

sunnyqd 发表于 2014-8-24 20:08:54

浪里白条 发表于 2014-8-24 19:56
楼主,WIN8下用软件 兼容性好不?

兼容性和win7差不多,要用的都能用,还没遇到过兼容性问题。
万一某个程序真的用不了,用兼容性选项选择XP就可以了

sunnyqd 发表于 2014-8-24 20:09:13

浪里白条 发表于 2014-8-24 19:57
我一直想玩玩WIN8 怕兼容性不好 WIN7下常用软件KEIL CW Cadence 这些软件能稳定运行不 ...

没问题,可以用的

chenguanghua 发表于 2014-8-24 20:11:05

期待楼主的MD5进行程序完整性检查

sunnyqd 发表于 2014-8-24 20:12:37

chenguanghua 发表于 2014-8-24 20:11
期待楼主的MD5进行程序完整性检查

没啥必要啊。。要的话,把crc32.c改成md5.c就可以了,将一个字的校验数据,改成四个字的

yanpenghao 发表于 2014-8-24 20:43:43

sunnyqd 发表于 2014-8-24 19:46
被发现了啊。。lz的win8可是正版的喔

哈哈,我从win8的第一个测试版用到现在哦

正版的话,刚开始是电话激活,后来就开始使用软件激活了,所以~

还是lz叼,哈哈哈

laotui 发表于 2014-8-24 20:48:36

帖子质量越来越高了,好有难度。

wangpengcheng 发表于 2014-8-24 20:52:08

sunnyqd 发表于 2014-8-24 19:13
keil 下的,思想就是编译完成后自动生成含有crc32校验值的.c文件,然后编译第二次把新的校验值给编译进去 ...

正在借鉴,谢谢!

sunnyqd 发表于 2014-8-24 20:58:45

yanpenghao 发表于 2014-8-24 20:43
哈哈,我从win8的第一个测试版用到现在哦

正版的话,刚开始是电话激活,后来就开始使用软件激活了,所以 ...

我是新配的本本,当时我还想要个win7的,不想要个win8的。。可惜人家没有。。只好悻悻的要了个win8的。。

yanpenghao 发表于 2014-8-24 21:06:31

sunnyqd 发表于 2014-8-24 20:58
我是新配的本本,当时我还想要个win7的,不想要个win8的。。可惜人家没有。。只好悻悻的要了个win8的。。 ...

原来是酱紫的呀,好像最近买的电脑都是预装win8了
今儿买了一个think pad也是预装的win8


不过在等不久就要出来win9 了,想想怎么就这么开心呢,哈哈哈

star_tale 发表于 2014-8-24 21:44:28

crc是整个应用程序算出的值吗

sunnyqd 发表于 2014-8-24 22:35:36

star_tale 发表于 2014-8-24 21:44
crc是整个应用程序算出的值吗

整个应用的.bin文件

lcptw 发表于 2014-8-24 22:53:24

关注,适合做产品用{:sweat:}

dgtg 发表于 2014-8-24 23:18:17

这个一定要mark!

sunnyqd 发表于 2014-8-24 23:37:03

laotui 发表于 2014-8-24 20:48
帖子质量越来越高了,好有难度。

多谢支持呐

sunnyqd 发表于 2014-8-24 23:37:41

dgtg 发表于 2014-8-24 23:18
这个一定要mark!

多谢支持,写的不是很有条理,如果遇到的话比较好理解

sunnyqd 发表于 2014-8-24 23:38:12

lcptw 发表于 2014-8-24 22:53
关注,适合做产品用

是呢,加上这功能蛮好的

fengyunyu 发表于 2014-8-25 06:44:42

crc校验稍微有点费时间。校验可以做简单些,重要的是双备份区

shejian001 发表于 2014-8-25 07:00:34

技术僧,膜拜。

wxfje 发表于 2014-8-25 07:17:37

谢谢分享,这个可以加入到产品中去

wxfje 发表于 2014-8-25 07:19:11

fengyunyu 发表于 2014-8-25 06:44
crc校验稍微有点费时间。校验可以做简单些,重要的是双备份区

大神,请推荐你认为合适的算法

whuctx 发表于 2014-8-25 07:36:18

楼主高手,收藏!

star_tale 发表于 2014-8-25 08:14:27

sunnyqd 发表于 2014-8-24 22:35
整个应用的.bin文件

嗯,值得借鉴
弱弱的问一句,每个芯片的id都不一样吗

zhaojun_xf 发表于 2014-8-25 08:14:29

不错,值得学习。。。。。。。。

DiaoMao_Huang 发表于 2014-8-25 08:40:43

楼主强人,知道这么多

DiaoMao_Huang 发表于 2014-8-25 08:41:35

wangpengcheng 发表于 2014-8-24 18:36
非常详细啊,谢谢哥们了!

你太猛了,飞币都飞成啥样子了

laotui 发表于 2014-8-25 08:54:50

楼主果然是高手。

ddz123abcdef 发表于 2014-8-25 10:00:23

楼主的资料高,以后的的程序里都用上。。。

sunnyqd 发表于 2014-8-25 10:31:05

fengyunyu 发表于 2014-8-25 06:44
crc校验稍微有点费时间。校验可以做简单些,重要的是双备份区

一般CM3和CM4的MCU有硬件CRC的,要不就可以做校验和,但要注意给数据移位再加,这样重复的概率小

sunnyqd 发表于 2014-8-25 10:34:21

wxfje 发表于 2014-8-25 07:19
大神,请推荐你认为合适的算法

校验和和,如checkval = ((checkval<<1)|(((uint32)checkval)>>31) ) + *(dataptr++)

sunnyqd 发表于 2014-8-25 10:35:48

star_tale 发表于 2014-8-25 08:14
嗯,值得借鉴
弱弱的问一句,每个芯片的id都不一样吗

如果有唯一ID的话,每个芯片的ID都不一样的

szpspike 发表于 2014-8-25 11:27:15

果然强大

zndz410 发表于 2014-8-25 11:43:54

楼主高人,币真是飞一样啊。

sunnyqd 发表于 2014-8-25 12:02:18

zndz410 发表于 2014-8-25 11:43
楼主高人,币真是飞一样啊。

大家都发力转fb呢

crm 发表于 2014-8-25 12:15:51

思路很好!

sunnyqd 发表于 2014-8-25 13:51:50

crm 发表于 2014-8-25 12:15
思路很好!

这种方法可以经过了实践检验的喔

advarx21ic 发表于 2014-8-25 21:06:26

非常棒!谢谢!

wxfje 发表于 2014-8-25 21:39:19

sunnyqd 发表于 2014-8-25 10:34
校验和和,如checkval = ((checkval31) ) + *(dataptr++)

谢谢回复,抽空试试先

sunnyqd 发表于 2014-8-25 21:47:57

wxfje 发表于 2014-8-25 21:39
谢谢回复,抽空试试先

但这样重复的概率是比较大的,你可以自己改进一下

fengyunyu 发表于 2014-8-25 22:09:06

LZ貌似半天涨了2000飞币

wxfje 发表于 2014-8-25 22:12:44

sunnyqd 发表于 2014-8-25 21:47
但这样重复的概率是比较大的,你可以自己改进一下

好的,谢谢指教

wxfje 发表于 2014-8-25 22:13:19

fengyunyu 发表于 2014-8-25 22:09
LZ貌似半天涨了2000飞币

是呀,楼主的飞币这两天涨到很猛呀!

sunnyqd 发表于 2014-8-25 22:24:28

fengyunyu 发表于 2014-8-25 22:09
LZ貌似半天涨了2000飞币

明天楼主就要干活了。。

sunnyqd 发表于 2014-8-25 22:25:00

wxfje 发表于 2014-8-25 22:13
是呀,楼主的飞币这两天涨到很猛呀!

这两天刚好没啥事情,嘿嘿

jiang887786 发表于 2014-9-1 18:39:04

楼主厉害啊,学习一下。

wangpengcheng 发表于 2014-9-1 20:18:31

挺好用,呵呵!

sunnyqd 发表于 2014-9-1 21:10:24

wangpengcheng 发表于 2014-9-1 20:18
挺好用,呵呵!

那是啊,产品上用的很爽

wangpengcheng 发表于 2014-9-1 21:11:23

sunnyqd 发表于 2014-9-1 21:10
那是啊,产品上用的很爽

再次表示感谢!{:titter:}

sunnyqd 发表于 2014-9-1 21:12:05

wangpengcheng 发表于 2014-9-1 21:11
再次表示感谢!

{:sweat:}

cn_x 发表于 2014-9-1 21:25:02

马上应该就用得着了,赶紧的copy,锁进保险柜

dxgdsx 发表于 2014-9-7 21:08:35

CRC校验,标记一下。

successliufei 发表于 2014-9-7 21:28:47

谢谢分享。。。

zhq0571 发表于 2014-9-8 09:34:30

楼主高手,好强悍!!

D138138 发表于 2014-9-8 11:09:37

非常好的帖子,谢谢楼主分享

gujiamao_love 发表于 2014-10-3 17:24:08

crc = 0x04C11DB7 ^ (crc<<1);
里面的0x04C11DB7 ,怎么来的。
原来MDK还能这么用。

gujiamao_love 发表于 2014-10-3 17:25:42

gujiamao_love 发表于 2014-10-3 17:24
crc = 0x04C11DB7 ^ (crc

用你给你网页,原来是CRC polynom。

laojiao 发表于 2014-10-3 21:42:16

好东西      

lovecxm 发表于 2014-10-4 14:07:23

这个很有价值,有理有据。

jxcrg_t35 发表于 2014-10-4 17:08:28

高手,学习啦

Xplain 发表于 2014-10-4 17:37:57

谢谢,学习了

hchkfh 发表于 2014-10-4 17:40:55

学习了!!!

723cheng 发表于 2014-10-7 12:04:38

mark,有空学习下

lihuaping0357 发表于 2014-10-7 13:49:05

收藏了!!谢谢

霸气侧漏 发表于 2014-10-7 14:04:21

CRC32校验这个写的不错,不知道这个校验速度你测过没有,我觉得你在写一点关于加密解密的。

good_hccy 发表于 2014-10-7 14:10:46

有用。。收藏着。。会用到。

fraser 发表于 2014-10-7 14:24:36

谢谢分享。。。

xiayuan 发表于 2014-10-7 17:20:12

这个不错

astankvai 发表于 2014-10-7 20:18:10

标记,日后慢慢看.

hover_007 发表于 2014-10-7 21:12:38

收藏了,多谢楼主。

xiepan2010 发表于 2014-10-7 21:30:46

学习了
。。。

rabbit512 发表于 2014-10-7 21:31:50

谢谢分享,收藏了!

ddcour 发表于 2014-10-8 17:34:40

不错,多谢分享!

32MCU 发表于 2014-10-9 09:46:46

好东西。收藏一下。

sedulity11 发表于 2014-10-9 09:55:54

谢谢分享

lovecxm 发表于 2014-12-7 17:45:06

这个帖子很有深度

beihai326 发表于 2014-12-8 14:26:19

mark!!!!
页: [1] 2
查看完整版本: 【网友经验分享】CRC32进行程序完整性检查,bootloader程序