|
大家好!我叫肖亞平,從小熱愛上了電子技術(shù),讀書時(shí)陰差陽錯(cuò)的選擇了電子這方面的專業(yè),學(xué)習(xí)電子技術(shù)、一直到今年畢業(yè)。對(duì)于我的理解來說,學(xué)校里面學(xué)到的技術(shù)不是全部實(shí)用,但是必須有用,所以一直奮斗在前線。我對(duì)學(xué)習(xí)總結(jié)出一句話“壓力不是有人努力,而是比你牛X N倍的人依然在努力”
STM32通過讀取芯片唯一ID號(hào)來實(shí)現(xiàn)程序的保護(hù),防止被抄襲。STM32芯片通過STlink可以把程序讀出來。只要在相同的芯片上面,就可以跑起來,那么如何才能讓一個(gè)程序只能夠在一個(gè)芯片上正常運(yùn)行呢? 經(jīng)過一個(gè)下午的時(shí)間,總結(jié)出這個(gè)方法。通過讀取ID號(hào),然后在修改HEX文件來保護(hù)自己的程序不被抄襲,相對(duì)于開發(fā)成本中等的產(chǎn)品,還是有用的。但是,有一點(diǎn)麻煩。我用的是STM32F103ZET6芯片。下面將介紹詳細(xì)的步驟和方法。
一.獲取ID碼
- 工欲善其事,必先利其器,準(zhǔn)備好工具,需要一個(gè)STlink及下載軟件,一個(gè)可以正常運(yùn)行的硬件。
- uint16_t temp[12]; //存放芯片ID的臨時(shí)變量
- uint16_t aa[12] = {0xee,0x01,0x02,0x03,0x04,
- 0x05,0x06,0x07,0x08,0x09,
- 0x10,0x11};//預(yù)置ID號(hào),在HEX文中修改。
-
- aa這個(gè)數(shù)組用于存放預(yù)置ID號(hào)
復(fù)制代碼
- /******************************************************************************
- 函數(shù)名稱:讀取芯片唯一ID碼
- 創(chuàng)建時(shí)間:2015-08-11
- 修改時(shí)間:2015-08-11
- 備 注:
- ******************************************************************************/
-
- void Get_ChipID(void)
- {
- u32 temp0,temp1,temp2;
- temp0 = *(__IO u32*)(0x1FFFF7E8); //產(chǎn)品唯一身份標(biāo)識(shí)寄存器(96位)
- temp1 = *(__IO u32*)(0x1FFFF7EC);
- temp2 = *(__IO u32*)(0x1FFFF7F0);
-
- //ID碼地址: 0x1FFFF7E8 0x1FFFF7EC 0x1FFFF7F0 ,只需要讀取這個(gè)地址中的數(shù)據(jù)就可以了。
-
- temp[0] = (u8)(temp0 & 0x000000FF);
- temp[1] = (u8)((temp0 & 0x0000FF00)>>8);
- temp[2] = (u8)((temp0 & 0x00FF0000)>>16);
- temp[3] = (u8)((temp0 & 0xFF000000)>>24);
- temp[4] = (u8)(temp1 & 0x000000FF);
- temp[5] = (u8)((temp1 & 0x0000FF00)>>8);
- temp[6] = (u8)((temp1 & 0x00FF0000)>>16);
- temp[7] = (u8)((temp1 & 0xFF000000)>>24);
- temp[8] = (u8)(temp2 & 0x000000FF);
- temp[9] = (u8)((temp2 & 0x0000FF00)>>8);
- temp[10] = (u8)((temp2 & 0x00FF0000)>>16);
- temp[11] = (u8)((temp2 & 0xFF000000)>>24);
- }
復(fù)制代碼
- 通過void Get_ChipID(void)就可以得到ID碼了,這個(gè)ID碼可以用串口輸出,也可以用STM32 ST-LINK Utility讀出來。這里,兩種方法我都會(huì)講到。
-
- 方法一:通過串口輸出得到ID碼。
-
- /****************************************************************************************************************************
- 函數(shù)名稱:串口2初始化配置
- 創(chuàng)建時(shí)間:2015-08-11
- 修改時(shí)間:2015-08-11
- 備 注:
- *****************************************************************************************************************************/
- void USART2_Config(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure; //定義GPIO類型結(jié)構(gòu)體
- USART_InitTypeDef USART_InitStructure; //定義串口類型結(jié)構(gòu)體
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //配置GPIOA時(shí)鐘,并使能時(shí)鐘。
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//配置USART2的時(shí)鐘,并使能時(shí)鐘
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //配置PA.02作為TXD
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //配置成推挽輸出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置GPIO時(shí)鐘為50MHZ
- GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIO
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //配置PA.03作為RXD
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //配置GPIO輸入浮空
- GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIO
- USART_InitStructure.USART_BaudRate = 115200; //配置串口波特率為115200
- USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位數(shù)據(jù)位
- USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止位
- USART_InitStructure.USART_Parity = USART_Parity_No; //
- USART_InitStructure.USART_HardwareFlowControl = T_HardwareFlowControl_None; //硬件流程控制
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //啟動(dòng)發(fā)送和接收
- USART_Init(USART2, &USART_InitStructure); //初始化串口2
-
- USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //使能串口2接收中斷
- USART_Cmd(USART2, ENABLE); //使能外部中斷
- }
復(fù)制代碼
- /****************************************************************************************************************************
- 函數(shù)名稱:USART2發(fā)送數(shù)據(jù)函數(shù)
- 創(chuàng)建時(shí)間:2015-08-11
- 修改時(shí)間:2015-08-11
- 備 注:
- *****************************************************************************************************************************/
- void Usart2_SendData(uint16_t uiSendDataNumber,uint16_t * uiData)
- {
- static uint16_t uiTempData = 0; //發(fā)送數(shù)據(jù)臨時(shí)變量
- for(uiTempData = uiSendDataNumber;uiTempData > 0;uiTempData--) //數(shù)據(jù)的個(gè)數(shù)
- {
- USART_SendData(USART2, *uiData++); //調(diào)用發(fā)送函數(shù)
- // uiData++; //發(fā)送數(shù)據(jù)的地址加1,切換到下一個(gè)要發(fā)送數(shù)據(jù)的地址。
- while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);//發(fā)送緩沖區(qū)空狀態(tài)標(biāo)志位。只有當(dāng)緩沖區(qū)為空時(shí),才發(fā)送下一個(gè)數(shù)據(jù)。
- }
- }
復(fù)制代碼
串口配置好后,就可以調(diào)用Usart2_SendData(12,temp);函數(shù),就能在串口助手看到ID碼了。
圖片1.png (74.13 KB, 下載次數(shù): 286)
下載附件
2016-1-21 14:55 上傳
- 芯片唯一ID碼:32 FF DA 05 43 41 38 36 30 71 02 43 96位
復(fù)制代碼
方法二:通過STlink得到ID碼。
1、打開STM32 ST-LINK Utility,確保STlink與硬件連接正常。 2、在Address中輸入“0x1FFFF7E8”芯片ID碼的首地址。輸入完成后,STlink自動(dòng)讀取ID碼。
圖片2.png (97.46 KB, 下載次數(shù): 281)
下載附件
2016-1-21 14:55 上傳
3、確定后,自動(dòng)讀取ID碼
圖片3.png (88.88 KB, 下載次數(shù): 290)
下載附件
2016-1-21 14:55 上傳
但是,用STlink讀出來的只有64位,少了32位,這個(gè)“0x1FFFF7F0”地址中讀取失敗,我也不知道是什么原因,可能是廠家不允許下載器訪問。
我們把上面ID碼整理一下:32 FF DA 05 43 41 38 36,由于在內(nèi)存中是小端存儲(chǔ)方式。所以是這樣的。
通過兩種方法,把我們想要的ID碼得到后。就可以進(jìn)行最關(guān)鍵的一步,修改HEX文件。
二.修改HEX文件加密
1、打開STM32 ST-LINK Utility,打開HEX文件。
圖片4.png (117.78 KB, 下載次數(shù): 293)
下載附件
2016-1-21 14:55 上傳
- uint16_t aa[12] = {0xee,0x01,0x02,0x03,0x04,
- 0x05,0x06,0x07,0x08,0x09,
- 0x10,0x11};//預(yù)置ID號(hào),在HEX文中修改。
復(fù)制代碼
現(xiàn)在就打HEX文件打開后。找到上面定義的數(shù)組,這個(gè)是關(guān)鍵所在,我花了一個(gè)下午時(shí)間,才搞清楚。
[size=9.0000pt]2、找到自定義ID在地址的位置后,開始修改。
圖片5.png (118.52 KB, 下載次數(shù): 245)
下載附件
2016-1-21 14:55 上傳
3、把數(shù)組“aa[12]” 里面的內(nèi)容改成與芯片的實(shí)際ID碼一致。如果程序被讀出來,在另外一片相同的芯片上面也運(yùn)行不起來。因?yàn)樵O(shè)置的ID與芯片實(shí)際ID不一致。
圖片6.png (118.52 KB, 下載次數(shù): 299)
下載附件
2016-1-21 14:55 上傳
4、現(xiàn)在如果下載,會(huì)提示你文件被修改,需要保存。我們保存成HEX文件到桌面。
圖片7.png (79.47 KB, 下載次數(shù): 314)
下載附件
2016-1-21 14:55 上傳
5、重新打開剛才保存的HEX文件。現(xiàn)在可以看到,修改的ID已經(jīng)在HEX文件里面了。
圖片8.png (123.84 KB, 下載次數(shù): 273)
下載附件
2016-1-21 14:55 上傳
6、下載程序到單片機(jī)。
圖片9.png (126.7 KB, 下載次數(shù): 290)
下載附件
2016-1-21 14:55 上傳
7、完成下載。到這兒就基本完成了。
8、看到這兒,有的人會(huì)問,為什么不在編譯時(shí)直接放在數(shù)組里,還要在HEX文件中修改,這樣做的目的是方便批量生產(chǎn)。
圖片10.png (244.55 KB, 下載次數(shù): 284)
下載附件
2016-1-21 14:55 上傳
- 在程序中,我做了一個(gè)簡(jiǎn)單的判斷。如下
- Get_ChipID(); //先讀出芯片實(shí)際ID
- for(i=0;i<12;i++)
- {
- if(temp == aa) //判斷設(shè)置的ID與實(shí)際ID是不是一致。如果一致。LED燈不亮
- {
- ;
- }
- else
- {
- GPIO_ResetBits(GPIOF, GPIO_Pin_6);
- }
- }
復(fù)制代碼
|
評(píng)分
-
查看全部評(píng)分
|