找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

帖子
查看: 60805|回復(fù): 14
打印 上一主題 下一主題
收起左側(cè)

STM32通過讀取芯片唯一ID號(hào)來實(shí)現(xiàn)程序的保護(hù),防止被抄襲

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:69862 發(fā)表于 2016-1-21 14:50 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
大家好!我叫肖亞平,從小熱愛上了電子技術(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

  1. 工欲善其事,必先利其器,準(zhǔn)備好工具,需要一個(gè)STlink及下載軟件,一個(gè)可以正常運(yùn)行的硬件。
  2. uint16_t temp[12];   //存放芯片ID的臨時(shí)變量
  3. uint16_t aa[12] = {0xee,0x01,0x02,0x03,0x04,
  4.                0x05,0x06,0x07,0x08,0x09,
  5.                0x10,0x11};//預(yù)置ID號(hào),在HEX文中修改。

  6. aa這個(gè)數(shù)組用于存放預(yù)置ID號(hào)
復(fù)制代碼



  1. /******************************************************************************
  2. 函數(shù)名稱:讀取芯片唯一ID碼
  3. 創(chuàng)建時(shí)間:2015-08-11
  4. 修改時(shí)間:2015-08-11
  5. 備    注:
  6. ******************************************************************************/

  7. void Get_ChipID(void)
  8. {
  9.     u32 temp0,temp1,temp2;
  10. temp0 = *(__IO u32*)(0x1FFFF7E8);    //產(chǎn)品唯一身份標(biāo)識(shí)寄存器(96位)
  11.     temp1 = *(__IO u32*)(0x1FFFF7EC);
  12. temp2 = *(__IO u32*)(0x1FFFF7F0);
  13.                                  
  14. //ID碼地址: 0x1FFFF7E8   0x1FFFF7EC  0x1FFFF7F0 ,只需要讀取這個(gè)地址中的數(shù)據(jù)就可以了。

  15.     temp[0] = (u8)(temp0 & 0x000000FF);
  16.     temp[1] = (u8)((temp0 & 0x0000FF00)>>8);
  17.     temp[2] = (u8)((temp0 & 0x00FF0000)>>16);
  18.     temp[3] = (u8)((temp0 & 0xFF000000)>>24);
  19.     temp[4] = (u8)(temp1 & 0x000000FF);
  20.     temp[5] = (u8)((temp1 & 0x0000FF00)>>8);
  21.     temp[6] = (u8)((temp1 & 0x00FF0000)>>16);
  22.     temp[7] = (u8)((temp1 & 0xFF000000)>>24);
  23.     temp[8] = (u8)(temp2 & 0x000000FF);
  24.     temp[9] = (u8)((temp2 & 0x0000FF00)>>8);
  25.     temp[10] = (u8)((temp2 & 0x00FF0000)>>16);
  26.     temp[11] = (u8)((temp2 & 0xFF000000)>>24);         
  27. }
復(fù)制代碼




  1. 通過void Get_ChipID(void)就可以得到ID碼了,這個(gè)ID碼可以用串口輸出,也可以用STM32 ST-LINK Utility讀出來。這里,兩種方法我都會(huì)講到。

  2. 方法一:通過串口輸出得到ID碼。

  3. /****************************************************************************************************************************
  4. 函數(shù)名稱:串口2初始化配置
  5. 創(chuàng)建時(shí)間:2015-08-11
  6. 修改時(shí)間:2015-08-11
  7. 備    注:
  8. *****************************************************************************************************************************/
  9. void USART2_Config(void)
  10. {
  11. GPIO_InitTypeDef   GPIO_InitStructure;  //定義GPIO類型結(jié)構(gòu)體
  12. USART_InitTypeDef  USART_InitStructure; //定義串口類型結(jié)構(gòu)體
  13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //配置GPIOA時(shí)鐘,并使能時(shí)鐘。
  14. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//配置USART2的時(shí)鐘,并使能時(shí)鐘
  15. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;       //配置PA.02作為TXD
  16. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //配置成推挽輸出
  17. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置GPIO時(shí)鐘為50MHZ
  18. GPIO_Init(GPIOA, &GPIO_InitStructure);           //初始化GPIO
  19. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;  //配置PA.03作為RXD
  20. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //配置GPIO輸入浮空
  21. GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化GPIO
  22. USART_InitStructure.USART_BaudRate = 115200;  //配置串口波特率為115200
  23. USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位數(shù)據(jù)位
  24. USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止位
  25. USART_InitStructure.USART_Parity = USART_Parity_No; //
  26. USART_InitStructure.USART_HardwareFlowControl = T_HardwareFlowControl_None; //硬件流程控制
  27. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //啟動(dòng)發(fā)送和接收
  28. USART_Init(USART2, &USART_InitStructure); //初始化串口2

  29. USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //使能串口2接收中斷
  30. USART_Cmd(USART2, ENABLE); //使能外部中斷
  31. }
復(fù)制代碼





  1. /****************************************************************************************************************************
  2. 函數(shù)名稱:USART2發(fā)送數(shù)據(jù)函數(shù)
  3. 創(chuàng)建時(shí)間:2015-08-11
  4. 修改時(shí)間:2015-08-11
  5. 備    注:
  6. *****************************************************************************************************************************/
  7. void Usart2_SendData(uint16_t uiSendDataNumber,uint16_t * uiData)
  8. {
  9.   static uint16_t uiTempData = 0; //發(fā)送數(shù)據(jù)臨時(shí)變量
  10. for(uiTempData = uiSendDataNumber;uiTempData > 0;uiTempData--) //數(shù)據(jù)的個(gè)數(shù)
  11. {
  12. USART_SendData(USART2, *uiData++); //調(diào)用發(fā)送函數(shù)
  13. //           uiData++; //發(fā)送數(shù)據(jù)的地址加1,切換到下一個(gè)要發(fā)送數(shù)據(jù)的地址。
  14. while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);//發(fā)送緩沖區(qū)空狀態(tài)標(biāo)志位。只有當(dāng)緩沖區(qū)為空時(shí),才發(fā)送下一個(gè)數(shù)據(jù)。
  15.   }
  16. }
復(fù)制代碼




串口配置好后,就可以調(diào)用Usart2_SendData(12,temp);函數(shù),就能在串口助手看到ID碼了。



  1. 芯片唯一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碼。





3、確定后,自動(dòng)讀取ID


但是,用STlink讀出來的只有64位,少了32位,這個(gè)“0x1FFFF7F0”地址中讀取失敗,我也不知道是什么原因,可能是廠家不允許下載器訪問。


地  址
0x1FFFF7E8
0x1FFFF7EC
0x1FFFF7F0
ID數(shù)據(jù)
05 DA FF 32
36 38 41 43
空(不允許讀)

我們把上面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文件。


  1. uint16_t  aa[12] = {0xee,0x01,0x02,0x03,0x04,
  2.                0x05,0x06,0x07,0x08,0x09,
  3.                0x10,0x11};//預(yù)置ID號(hào),在HEX文中修改。
復(fù)制代碼



現(xiàn)在就打HEX文件打開后。找到上面定義的數(shù)組,這個(gè)是關(guān)鍵所在,我花了一個(gè)下午時(shí)間,才搞清楚。



[size=9.0000pt]2、找到自定義ID在地址的位置后,開始修改。





3、把數(shù)組“aa[12]” 里面的內(nèi)容改成與芯片的實(shí)際ID碼一致。如果程序被讀出來,在另外一片相同的芯片上面也運(yùn)行不起來。因?yàn)樵O(shè)置的ID與芯片實(shí)際ID不一致。




4、現(xiàn)在如果下載,會(huì)提示你文件被修改,需要保存。我們保存成HEX文件到桌面。



5、重新打開剛才保存的HEX文件。現(xiàn)在可以看到,修改的ID已經(jīng)在HEX文件里面了。





6、下載程序到單片機(jī)。


7、完成下載。到這兒就基本完成了。

8、看到這兒,有的人會(huì)問,為什么不在編譯時(shí)直接放在數(shù)組里,還要在HEX文件中修改,這樣做的目的是方便批量生產(chǎn)。



  1. 在程序中,我做了一個(gè)簡(jiǎn)單的判斷。如下
  2.   Get_ChipID();  //先讀出芯片實(shí)際ID         
  3.   for(i=0;i<12;i++)
  4.         {
  5.                         if(temp == aa) //判斷設(shè)置的ID與實(shí)際ID是不是一致。如果一致。LED燈不亮
  6.                         {
  7.                                 ;
  8.                         }
  9.                         else
  10.                         {
  11.                                  GPIO_ResetBits(GPIOF, GPIO_Pin_6);
  12.             }
  13.   }
復(fù)制代碼





評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏12 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:12816 發(fā)表于 2016-8-10 21:34 | 只看該作者
人家寫保護(hù)了也不容易讀出來吧,還考慮ID
回復(fù)

使用道具 舉報(bào)

板凳
ID:251314 發(fā)表于 2017-11-21 09:17 | 只看該作者
我怎么感覺那么麻煩噶
回復(fù)

使用道具 舉報(bào)

地板
ID:341087 發(fā)表于 2018-6-14 08:32 | 只看該作者
您只要提供hex文件(為了保密,可以把一些功能注銷了),我反匯編后找出程序id加密的缺陷,相當(dāng)于對(duì)您的程序id加密進(jìn)行測(cè)試
歡迎交流
回復(fù)

使用道具 舉報(bào)

5#
ID:608322 發(fā)表于 2019-9-9 12:07 | 只看該作者
//STM32F10X軟加密方法及實(shí)例代碼

#define ID_ENCRYPT_EOR_RESULT_ADDRESS (0x0800F000)
#define ID_ENCRYPT_ADD_RESULT_ADDRESS (0x0800F004)
volatile uint32 gU32IdAdressVar;//這里一定要定義此變量,否則會(huì)被優(yōu)化器優(yōu)化掉
void Stm32F10xEncryptDemo(void)
{
        uint32 *u32IdAddress;
  uint32 u32EorRslt, u32AddRslt;
        #IF 0
        //如果直接賦值0X1FFFF7E8,則程序編譯結(jié)果里會(huì)有0X1FFFF7E8,這樣破解人員會(huì)很輕松
        //的找到這個(gè)內(nèi)容,然后非常容易進(jìn)行修改,去掉軟加密
        u32IdAddress = (uint32*)0x1ffff7e8;
        #else
        //千萬別顯式的讀取ID,即要把0X1FFFF7E8運(yùn)算成隱式的,例如此例中0x1FFFF7E8 = (0x455873a * 4) + 0xEA9DB00;
        //這樣,別人就算破解出了你的程序,也查找不到0X1FFFF7E8,這樣就不能輕易的軟解密,這樣處理后如果要軟解密,
        //一定要反匯編出來進(jìn)行復(fù)雜逆向分析,難度極大,代價(jià)極高,很難搞定軟加密了,達(dá)到保護(hù)產(chǎn)品的目的。
        gU32IdAdressVar = 0x455873a;
        gU32IdAdressVar <<= 2;//0x11561CE8
        u32IdAddress = (uint32*)(gU32IdAdressVar + 0xEA9DB00);//0x1ffff7e8
        #endif
        //讀取單片機(jī)的ID,并進(jìn)行運(yùn)算,具體算法可以自己定,這里只用到簡(jiǎn)單的異或及和運(yùn)算
        u32EorRslt = (*u32IdAddress) ^ (*(u32IdAddress + 1)) ^ (*(u32IdAddress + 2));
        u32AddRslt = (*u32IdAddress) + (*(u32IdAddress + 1)) + (*(u32IdAddress + 2));
        //進(jìn)行對(duì)比,如果運(yùn)算結(jié)果與FLASH保存的結(jié)果不一樣,說明非法,運(yùn)行錯(cuò)誤代碼
        if(u32EorRslt != *((uint32*)ID_ENCRYPT_EOR_RESULT_ADDRESS))
        {
                while(1);//異或算法結(jié)果不正確,進(jìn)行錯(cuò)誤分支
        }
        if(u32AddRslt != *((uint32*)ID_ENCRYPT_ADD_RESULT_ADDRESS))
        {
                while(1);//和算法結(jié)果不正確,進(jìn)行錯(cuò)誤分支
        }
}
//QQ9272078
回復(fù)

使用道具 舉報(bào)

6#
ID:608322 發(fā)表于 2020-6-29 08:36 | 只看該作者
現(xiàn)在stm32f103破解出程序只要1000塊,如果用id做軟件加密,id地址直接出現(xiàn)的,只要500就可以改軟件加密
回復(fù)

使用道具 舉報(bào)

7#
ID:757976 發(fā)表于 2020-6-29 08:49 | 只看該作者
ID加密也可能是個(gè)好方法
回復(fù)

使用道具 舉報(bào)

8#
ID:73435 發(fā)表于 2020-6-29 09:17 | 只看該作者
有點(diǎn)麻煩了,而且不太實(shí)用,生產(chǎn)的時(shí)候不可能每一片ID都查出來然后改燒錄文件燒錄
回復(fù)

使用道具 舉報(bào)

9#
ID:608322 發(fā)表于 2020-7-1 14:30 | 只看該作者
294479435 發(fā)表于 2020-6-29 09:17
有點(diǎn)麻煩了,而且不太實(shí)用,生產(chǎn)的時(shí)候不可能每一片ID都查出來然后改燒錄文件燒錄

1,如果板子上有外部存儲(chǔ)器,可以先編寫一個(gè)程序,利用算法把id計(jì)算得到一些值存入外部存儲(chǔ)器,然后再燒寫真正的程序,真正的程序去校驗(yàn)外部存儲(chǔ)器的數(shù)據(jù)是否合法即可

2,利用板子上按鍵組合,或是上電按住某些鍵,程序在這個(gè)時(shí)候利用算法把id計(jì)算得到一些值存入程序區(qū)(stm8為EE區(qū)),程序運(yùn)行時(shí)去驗(yàn)證程序區(qū)數(shù)據(jù)是否正確

3,軒微編程器有軟件加密的功能,編程器會(huì)讀芯片id,根據(jù)算法直接改寫緩沖區(qū),達(dá)到軟件加密的作用

4,讀出的id通過一定算法,例如異或加上一個(gè)數(shù),得到的數(shù)據(jù)存入flash(只運(yùn)行一次,運(yùn)行后標(biāo)志位也存入flash),下次讀到這個(gè)標(biāo)志位,就不運(yùn)行這個(gè)程序。

四、做軟件加密時(shí)注意
1,不要在程序中直接出現(xiàn)id地址,例如STM32:1FFFF7E8 1FFFF7EC 1FFFF7F0   STM8: 0x4865~0x4870
2, 利用校驗(yàn)和或是crc對(duì)程序區(qū)進(jìn)行校驗(yàn),防止改程序

評(píng)分

參與人數(shù) 1黑幣 +40 收起 理由
admin + 40 回帖助人的獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

10#
ID:595237 發(fā)表于 2020-7-1 21:07 | 只看該作者
加密與解密都是相互相成的。

懂功能程序的人基本上也可以根據(jù)功能來寫出程序,
不懂程序的人也不一定能夠仿出來,

如果能夠有人仿自己寫出來這個(gè)程序的產(chǎn)品,證明自己還可以,
有創(chuàng)新的頭腦,如果都是自己和人家一樣仿來仿去的,
說明只是停留在仿的位置。


回復(fù)

使用道具 舉報(bào)

11#
ID:595237 發(fā)表于 2020-7-1 21:18 | 只看該作者
多多創(chuàng)新一定能夠賺取更多錢,
停留在一個(gè)上面保護(hù),
也不一定能夠賺取比創(chuàng)新賺錢來的多。

每位程序員工程師的數(shù)字頭腦都比老板靈敏的多,
但是現(xiàn)實(shí)中都是老板賺錢比工程師多多nn倍,這是為什么?
回復(fù)

使用道具 舉報(bào)

12#
ID:367957 發(fā)表于 2021-6-23 14:31 | 只看該作者
meifan2010 發(fā)表于 2019-9-9 12:07
//STM32F10X軟加密方法及實(shí)例代碼

#define ID_ENCRYPT_EOR_RESULT_ADDRESS (0x0800F000)

沒用的。抄出來可以反匯編然后進(jìn)行仿真的。一步步走怎么都會(huì)把你的破掉
回復(fù)

使用道具 舉報(bào)

13#
ID:367957 發(fā)表于 2021-6-23 14:32 | 只看該作者
juncedz 發(fā)表于 2020-7-1 21:18
多多創(chuàng)新一定能夠賺取更多錢,
停留在一個(gè)上面保護(hù),
也不一定能夠賺取比創(chuàng)新賺錢來的多。

因?yàn)槟憔褪浅绦騿T
回復(fù)

使用道具 舉報(bào)

14#
ID:949399 發(fā)表于 2021-7-5 15:00 | 只看該作者
芯片讀出的HEX文件可以反匯編出來嗎,
回復(fù)

使用道具 舉報(bào)

15#
ID:65369 發(fā)表于 2021-12-2 10:54 | 只看該作者
juncedz 發(fā)表于 2020-7-1 21:18
多多創(chuàng)新一定能夠賺取更多錢,
停留在一個(gè)上面保護(hù),
也不一定能夠賺取比創(chuàng)新賺錢來的多。

就是這個(gè)道理,你是程序員
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表