STM32F407读取ID号+加密+验证+验证失败自宫

 首先要清楚,单片机程序破解不仅仅是获得了源程序,即使没有获得源程序,获得了可执行文件并且可以随意复制使用,这种情况也算是被破解了。

所以单片机程序加密,也分两个方面:第一,不能让别人获得你的bin文件或者hex文件;第二,即使获得了bin文件或者hex文件,烧写进新的单片机也运行不了。

第一方面的解决办法常见的是借用软件对程序存储flash区进行读保护,要想读取这部分flash区域,只能先擦除,这样就防止别人轻易读取我们的程序。比如flash loader demonstrator就是针对stm单片机的专用烧写、读取程序,进行程序区读保护的软件。但借助更高级的工具,依然可以p破解这种读保护,从而把程序读取出去,所以我们要进行第二方面的加密。

第二方面是借用软件方法来实现的,今天介绍的就是这种方法的基本操作方法。

每一片单片机的id号是全球唯一的,在单片机第一次运行程序的时候,把单片机id号读出来,再进行加密,把加密后的内容烧写到程序区的空白处,和程序混合在一起。这样单片机里的程序其实已经融合了单片机的id号,是绑定了这个id号的单片机专用程序。在主程序的某些地方加入验证程序,验证读取到的id号加密后和加密区的内容是否一致,如果一致,说明程序是单片机的原程序,如果不一致,说明这个程序是从别的单片机复制过来的。我们再加入自宫程序,就是验证出不是单片机原程序,那就执行擦除代码区的指令。这样单片机就成了一个空机,防止了别人复制我们的程序。

目录

一、读取单片机ID并加密

1、读取id并加密程序

2、写入flash函数

3、stmflash.h文件

二、验证程序

三、自宫程序

四、主程序中调用

1、在程序运行开始调用ReadId_Encrypt() 

2、在程序多个地方调用验证程序并对不同结果进行处理


一、读取单片机ID并加密

stm32f407的id号是96位,由三个32位地址来存放。存放的地址为0x1FFF7A10、0x1FFF7A14、0x1FFF7A18。所以我们需要到这三个地址去读取。

需要注意的是,在程序中不能直接出现这三个地址,因为这些地址是公开的,破解者可以在bin文件或者hex文件中,通过搜索这三个地址找到读取id号和加密的代码位置,很容易破解出加密后的内容存放地址。假如破解者把加密内容清空,这样程序就变成了一个未运行过的原始程序,没有绑定id号,就可以随意复制到其他单片机。

所以,在声明这3个地址的时候要进行偏移,读取id号的时候再把偏移过的地址进行反偏移计算出真正的地址。

1、读取id并加密程序

volatile u32 ID_Shifted_Add=0x1FF367C4;//偏移过的id号存放首地址

const  u32 ID_Encrypted[3] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};//加密后的内容存放地址

void Id_Encrypt(void)  
{   
    //如果内容为0xFFFFFFFF,则未写入过加密内容,则执行写入加密内容代码
    if(McuIDEncrypt[0]==0xFFFFFFFF)  
   {  
        uint32_t Stm32_ID[3];
		uint32_t ID_Encrypted_value;		 
        //反偏移计算出真正的id存放地址
        Stm32_ID[0]=*(vu32*)(ID_Shifted_Add+791116);
        Stm32_ID[1]=*(vu32*)(ID_Shifted_Add+791116+4);  
        Stm32_ID[2]=*(vu32*)(ID_Shifted_Add+791116+8); 

  
        //简单加密
        ID_Encrypted_value=(Stm32_ID[0]>>8)+(Stm32_ID[1]>>2)+(Stm32_ID[2]>>9);

        //加密后的内容存放到flash内
		STMFLASH_Write((u32)ID_Encrypted,(u32*)&ID_Encrypted_value,1);		
		
        //写操作需要一定时间,所以延时一定时间,保证写入成功	
		delay_ms(3000);
    }

		
}  

2、写入flash函数

STMFLASH_Write()是写入flash函数,是库函数stmflash.c中的函数。

void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)	
{ 
  FLASH_Status status = FLASH_COMPLETE;
	u32 addrx=0;
	u32 endaddr=0;	
  if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;
	FLASH_Unlock();									
  FLASH_DataCacheCmd(DISABLE);
 		
	addrx=WriteAddr;				
	endaddr=WriteAddr+NumToWrite*4;	
	if(addrx<0X1FFF0000)			
	{
		while(addrx<endaddr)		
		{
			if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)
			{   
				status=FLASH_EraseSector(STMFLASH_GetFlashSector(addrx),VoltageRange_3);
				if(status!=FLASH_COMPLETE)break;	
			}else addrx+=4;
		} 
	}
	if(status==FLASH_COMPLETE)
	{
		while(WriteAddr<endaddr)
		{
			if(FLASH_ProgramWord(WriteAddr,*pBuffer)!=FLASH_COMPLETE)
			{ 
				break;	
			}
			WriteAddr+=4;
			pBuffer++;
		} 
	}
  FLASH_DataCacheCmd(ENABLE);	
	FLASH_Lock();
} 

3、stmflash.h文件

#ifndef __STMFLASH_H__
#define __STMFLASH_H__
#include "sys.h"   
//	 


#define STM32_FLASH_BASE 0x08000000 	
 


#define ADDR_FLASH_SECTOR_0     ((u32)0x08000000) 	
#define ADDR_FLASH_SECTOR_1     ((u32)0x08004000) 	 
#define ADDR_FLASH_SECTOR_2     ((u32)0x08008000) 	  
#define ADDR_FLASH_SECTOR_3     ((u32)0x0800C000) 	  
#define ADDR_FLASH_SECTOR_4     ((u32)0x08010000) 	  
#define ADDR_FLASH_SECTOR_5     ((u32)0x08020000) 	  
#define ADDR_FLASH_SECTOR_6     ((u32)0x08040000) 	  
#define ADDR_FLASH_SECTOR_7     ((u32)0x08060000) 	  
#define ADDR_FLASH_SECTOR_8     ((u32)0x08080000) 	  
#define ADDR_FLASH_SECTOR_9     ((u32)0x080A0000) 	  
#define ADDR_FLASH_SECTOR_10    ((u32)0x080C0000) 	  
#define ADDR_FLASH_SECTOR_11    ((u32)0x080E0000) 	  

u32 STMFLASH_ReadWord(u32 faddr);
void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite);
void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead);
#endif

二、验证程序

bool Check(void)  
{         
    u8 i;
	uint32_t Stm32_ID[3];
		
	uint32_t ID_Encrypted_value;
	
	
	u32 datatemp[3]={0};
    
    //读id号
    Stm32_ID[0]=*(vu32*)(ID_Shifted_Add+791116);  
    Stm32_ID[1]=*(vu32*)(ID_Shifted_Add+791116+4);  
    Stm32_ID[2]=*(vu32*)(ID_Shifted_Add+791116+8);  
		

    //计算加密结果
	ID_Encrypted_value=(Stm32_ID[0]>>8)+(Stm32_ID[1]>>2)+(Stm32_ID[2]>>9);
		
	//读取存入加密区内容,存入到datatemp中
	STMFLASH_Read((u32)ID_Encrypted,(u32*)datatemp,1);
	
    //判断加密结果和存入的内容是否一致,并返回比较的结果	
	return (datatemp[0]==ID_Encrypted_value);
		
} 

三、自宫程序

void Erase(void)
{
		
			FLASH_Unlock();									
			FLASH_DataCacheCmd(DISABLE);		
			
			FLASH_EraseAllSectors(VoltageRange_3);
	

			FLASH_DataCacheCmd(ENABLE);	
			FLASH_Lock();
	
}

注意,本部分所用的函数都在官方库函数stm32f4xx_flash.c中。

四、主程序中调用

1、在程序运行开始调用ReadId_Encrypt() 

2、在程序多个地方调用验证程序并对不同结果进行处理

	if(Check()==0)//如果验证不通过
	{
	
    Erase();//执行自宫程序

	}

(全文结束)

  • 10
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值