原创---通过LGT和STM32“全球唯一序列号"对抗解密的应用浅谈
本帖最后由 win2kddk 于 2012-4-14 00:51 编辑“全球唯一序列号”近两年来在新兴的MCU上应用越来越广,其设计的初衷目的是让用户来做认证用的,虽然可以按想象中的把序号读出来,写进程序里,再用程序来校验。但是这样的话每个HEX文件都不一样,反而不利于系统的升级和维护了。
下面谈一种使用全球唯一序列号来做认证和加密的方式方法,大家可以探讨一下。
本方法适用于有全球唯一序列号的LGT、STM32芯片,且内部或外部E2PROM且空间尚且够用的情况下,带加密型的E2PROM可以自由发挥。
系统中有外部E2PROM的情况时,可以先通过编程器或其他手段写入到外部E2PROM中某地址一个数据,例如在0x0010处写入0x12345678,这个地址即为序列号验证的地址。如果内部有E2PROM的在编译程序时先编译好EEP文件。确定好E2PROM内容后再向单片机写入你的程序。程序刚开始运行时先要读E2PROM看看是不是0x12345678,如果是的话则为厂家模式。如果是厂家模式时则读取自身MCU的唯一ID并通过MD5+3DES或其他不可逆算法来算出一个序列号来,并写入到0x0010地址处。如果不是厂家模式,那就是用户模式了。可以随时随地用不同的方法来读自身唯一ID并通过不可逆算法来算出序列号和0x0010地址上的数据进行比较就行了。该方法的前提是如果使用外部E2PROM时需要先编好E2PROM中的数据,切不可图省事让MCU读出为0xFF即为厂家模式,这样的话人家给你换一颗没用过的芯片就完事了。如果是内部E2PROM则要省事很多,编译程序时声明产生EEP文件就行了。那个0x12345678也不要太简单了,要复杂一些,最好再更长一些。这种方法可以初步解决芯片认证的问题。如果是盗版芯片,算出来的序列号肯定与E2PROM内的不同,哪怕是整片都被复制。盗版者也不知道需要哪些数据如何进入厂家模式来生成新的正确的序列号。
系统中只有单颗STM32没有外挂E2PROM时的情况要麻烦一些,目前我能想出的办法只有用以上的方法和IAP技术,在芯片内部找一个空间让MCU自已来写入加密后的序列号。串口下载和用编程器并行下载时都可以在芯片内部先写好0x12345678。当然也可以用程序来声明
const unsigned long SafetyIDMark __at(0x803FFF0) = 0x12345678; //在芯片0x803FFF0地址写入加密ID的初始标识
其他的就只能从IAP入手了,挥刀自宫吧。
大家可以参考我发过的帖子来找到各种常用的高级加密算法的源码“加密源码大聚齐” 。如果觉得那些不可逆算法比较麻烦,或占用资源多的话可以参考下面这个简单的。
unsigned long Encryption(unsigned long input_data, unsigned long key1, unsigned long key2, unsigned long key3, unsigned long key4)
{
unsigned long x1, x2, x3, x4, x5, x6, x7;
unsigned long x, y0, y4, y5;
x = input_data &0xffff0000;
x = x >> 16;
x2 = x;
x1 = 0xffff &input_data;//input_data为将要加密的数据源
if (x1 > 65535)
x1 = x1 - 65536;
x3 = x1 ^ key2;
x4 = x2 ^ key1;
x5 = x4 + x3;
x6 = x5 << 4;
x7 = x6 % key4;
y0 = x7 * key3;
x3 = x1 + key1;
x4 = x3 % key3;
x5 = key4 ^ x2;
y4 = x4 * x5;
y5 = y0 ^ y4;
return y5;//加密后的数据出口
}
这是我以前用过的一种不可逆算法。别看这么简单,这个是源自某款并口彩虹加密狗的加密算法。通过移位和取模运算,那些原来的数据已经面目全非并且完全不可逆了。
顺便广告一下,看了下LGT的手册。armok的LGT单片机既有E2PROM又有全球唯一序列号,还能直接代替AVR,是个很不错的选择。就算哪天被解了密,那也是我们的荣幸,因为人家瞧得起咱们产品好。不过他们想用起来就没那么简单了,呵呵。
以上方法可以应用在任何一款有唯一序列号的MCU系统中。但出于安全性考虑尽量不要使用在例如有18B20之类外设的系统上,非加密型外设的通讯数据很容易采集并仿真和伪造。至于全球唯一序列号驻留在RAM中的STC单片机如何防止内嵌木马来修改,网络上各有保贬,这里不便评论。
{:lol:}armok的LGT单片机
没几天就已经深入民心了
好资料,继续学习 以后可以用这个方法 暂时还只是用外部加密芯片来解决,至于保险不保险不晓得,留待以后再学习 谢谢楼主大公无私,学习了。 顶,有唯一ID确实好玩... informative post.
x = input_data &0xffff0000;
poor coding.
x1 = 0xffff &input_data;//input_data为将要加密的数据源
if (x1 > 65535)
x1 = x1 - 65536;
brain-dead coding.
唯一ID好玩,利用它能做很多应用。 好方法,参考一下备用 学习了,楼主可以开一个加密培训班 怕就怕人家反汇编,直接把你的加密部分去掉。 无级电工 发表于 2012-4-14 08:44 static/image/common/back.gif
怕就怕人家反汇编,直接把你的加密部分去掉。
人家有这个能力反汇编的就不会去破解获得HEX code了。反汇编首先要读取hex,得破解lock bit。 好方法,参考一下备用 对抗解密啊?这个暂时不需要用到,以后再细读 STM8L系列的芯片不是带有硬件加解密模块和唯一序列号嘛。 最早使用ID来加密的应该是Xilinx公司的FPGA,他们在IC里边做了连线矩阵,Wafer测试时用激光随机烧断相应的某些位,用户可以读取,这种做法使得测试成本增加了。用户通过读取ID经过算法写到外部的配置芯片当中实现加密。 无级电工 发表于 2012-4-14 08:44 static/image/common/back.gif
怕就怕人家反汇编,直接把你的加密部分去掉。
要是有这样水平,用去的时间编都能编出来了 非常感谢,通俗易懂。。。
感觉这个方法的可操作性很强,Thanks!!! 这个要仔细看看,以前一直没有关注如何加密的事情 我的想法是在变成区中实现,编程器编程的时候读取UID,生成密钥直接放到hex指定位置即可,这样不依赖于EEPROM。当然希望LGT的SWD公布协议,这样我就可以做自己的脱机编程器了。现在的AVR我就是在脱机编程器中实现加密,读取OSCCAL然后生产密钥修改hex相关位置。MCU上电的时候进行校验。 {:mad:}楼主把我一直用的加密方式曝光了
{:lol:}不过就算曝光,估计解密得了的人不在乎去解码,想不不劳而获的人,也没那个本事解密 zhiwei 发表于 2012-4-14 11:03 static/image/common/back.gif
我的想法是在变成区中实现,编程器编程的时候读取UID,生成密钥直接放到hex指定位置即可,这样不依赖于EEPR ...
仁兄用的就是最常用的方法,加密在烧录HEX code时生成并写入相应位置,解密是在相应位置读取后用解密方法验证。 logicgreen 发表于 2012-4-14 09:50 static/image/common/back.gif
人家有这个能力反汇编的就不会去破解获得HEX code了。反汇编首先要读取hex,得破解lock bit。 ...
关于lock bit,请教一下大牛:
就目前的LGT、STM32、LPC17xx,lock bit被破的可能性有多大?成本要多高?
因为一旦FLASH内容被读出,反汇编就是时间问题。我自己的产品被破解过,所以有此一问,请不吝赐教~~ stdio 发表于 2012-4-14 11:43 static/image/common/back.gif
关于lock bit,请教一下大牛:
就目前的LGT、STM32、LPC17xx,lock bit被破的可能性有多大?成本要多高 ...
Lock bit和IC layout以及工艺有关,layout只要考虑那些bit不宜被找到,即使找到了,也要防止用FIB方法来破解,不过现在是越来越难破解的。 不错的方法! 看了一通有点云里雾里。。。 xinzhi1986 发表于 2012-4-14 12:14 static/image/common/back.gif
看了一通有点云里雾里。。。
就是利用ID经过一个算法用烧录器写把HEX code和加密的结果写到一个地方,这个过程是加密的过程;运行程序读取那个地方的数据再解密,如果吻合程序继续,否则不运行,这个是解密。
有个要点记住:加密和解密是分开的,烧录器负责加密,程序负责解密! >> 这是我以前用过的一种不可逆算法。别看这么简单,这个是源自某款并口彩虹加密狗的加密算法。通过移位和取模运算,那些原来的数据已经面目全非并且完全不可逆了。
不可逆是什么意思 ?
应该是不可重现? logicgreen 发表于 2012-4-14 22:18 static/image/common/back.gif
就是利用ID经过一个算法用烧录器写把HEX code和加密的结果写到一个地方,这个过程是加密的过程;运行程序 ...
呵呵,今天早上起来一看,果然就明白了,昨天晚上太累,不在状态啊~居然没看懂~ 没搞过加密,回头试一下 留名。必须的。 手机版好像没有收藏功能 这个算法的加密强度应该是比较弱。 wzyllgx 发表于 2012-4-15 10:07 static/image/common/back.gif
这个算法的加密强度应该是比较弱。
针对拿来就用的人来说很管用,比较好的做法是屏蔽部分功能不易即时发现,待发现后已为时已晚,使copy者损失严重。 学习了,多谢楼主. logicgreen 发表于 2012-4-14 12:12 static/image/common/back.gif
Lock bit和IC layout以及工艺有关,layout只要考虑那些bit不宜被找到,即使找到了,也要防止用FIB方法来 ...
FIB的成本不低,之前修改过一片专用芯片,大概10K左右 rifjft 发表于 2012-4-15 11:48 static/image/common/back.gif
FIB的成本不低,之前修改过一片专用芯片,大概10K左右
有见过破解apple加密ic的,是flash的mcu,一次做10颗芯片,费用接近10万。 logicgreen 发表于 2012-4-15 11:54 static/image/common/back.gif
有见过破解apple加密ic的,是flash的mcu,一次做10颗芯片,费用接近10万。
这个应该不是苹果的那个加密IC,应该是用来解析的那个IC吧! wzyllgx 发表于 2012-4-15 11:57 static/image/common/back.gif
这个应该不是苹果的那个加密IC,应该是用来解析的那个IC吧!
苹果的授权电子签名ic,有它就可以做苹果的高端的配件产品。 logicgreen 发表于 2012-4-15 12:09 static/image/common/back.gif
苹果的授权电子签名ic,有它就可以做苹果的高端的配件产品。
这个这个,呵呵,不说了。 好方法,参考一下备用 可以考虑使用国产的另外一款51单片:LS系列的51单片机,已经进化到3核,对于加密有独特的处理。 lz的思路解决了困扰我的初始化的问题
但实际使用时发现使用 const unsigned long SafetyIDMark __at(0x803FFF0) = 0x12345678; //在芯片0x803FFF0地址写入加密ID的初始标识
这样写后,文件编译后变很大,0x803FFF0之前的原来是FF的flash中全变成00了,而且程序只能第一次时运行,因为我的读取0x803FFF0的内容后把整个单元擦除,再在0x803FFF0填入一个新数,好像有些别的东西也被擦除了下次就不能运行了。
我用的是MDK,芯片是STM32。
哪位能帮忙解答下该怎么弄
路过,学习学习~~ startwar0418 发表于 2012-5-7 13:29 static/image/common/back.gif
lz的思路解决了困扰我的初始化的问题
但实际使用时发现使用 const unsigned long SafetyIDMark __at(0x803 ...
STM32的flash是按页擦除的,不能按字节擦除。 是出发点阿斯mark 汗。。。
这加密算法在本来芯片内部,这算是加密?????
程序刚开始运行时先要读E2PROM看看是不是0x12345678,如果是的话则为厂家模式。如果是厂家模式时则读取自身MCU的唯一ID并通过MD5+3DES或其他不可逆算法来算出一个序列号来,并写入到0x0010地址处。
这说明程序里面已经包含了 '0x12345678"这个独有的用户串,就是告诉了破解的人,加密还是不行。如果也用的是常见的加密算法,破解十分轻松。很容易就推算出来了。 这个要顶! logicgreen 发表于 2012-4-14 09:50 static/image/common/back.gif
人家有这个能力反汇编的就不会去破解获得HEX code了。反汇编首先要读取hex,得破解lock bit。 ...
对于汇编能力强的人来说,跟踪下程序流程,找到核对数据的地方,然后跳过去,这样的工作量是很少很少的,估计1个晚上,抽几包烟就够了。大家去看雪论坛溜达下就知道了。
这样的工作量,同开发一款产品的工作量是没有可比性的,因此破解的代价非常小。
真正防破解只有法律可能做到。但在我们这个狗屎地方,只是一个梦想。
因此,设计方案时,不要单点比较,而是要在很多函数里面,校验这个值,同时,不要一开机就校验,而是设定一个计数器,多长时间校验一次。
例如,程序里面有10个关键函数,统统会校验这个值,各自有自己的计数器,到点才校验,并且,校验完成后,只是影响某个位的设置(不动声色),然后另外一个随机计数器开始计数,当到点时,也只搞点小小的破坏,例如死机几次而已。
总之一句话:不要有明显的异常反应,多点校验,让那些汇编高手们迷糊一会,增加破解成本,降低完全破解的可能性。这是我们唯一可以做的。 补充:不要校验完成就当机或者其他明显的破坏动作,这点非常重要,因为反汇编跟踪时,就是以这个作为跟踪对象,然后回溯比较点。
所以,比较完成后,设置个标志,然后随机延长时间,再有不定时的反应,这样,会让他的跟踪时间大大增加,同时迫使他得去读汇编程序,这样代价就比较大了。 这种加密算法好像有点弱啊,对于没有硬件加密模块的MCU来说,最好还是向51楼所说的做。 本帖最后由 fsclub 于 2012-7-12 18:13 编辑
唯一好方法是pic,stc,avr,cpld,fpga,1wire,台系,日系,棒子系的各种mcu各用一片,各负责部分功能,mcu间时不时的交换一下信息,让一个mcu总负责。
芯片用手砂轮全磨了。pic的标成avr,棒子的标成鬼子的,cpld标成fpga,
让他破解去吧。 {:lol:}54楼强 最近试了一下将楼主的加密方法放到STM8S103上,在程序里面读EEPROM的指定位置,然后读UID,算出一个值,比较,结果用STVP事先往EEPROM中写入预置的KEY时死活写不进去,写一个别的数据就写得进去,在别的地方写KEY也写得进去,难道EEPROM预知了我的KEY?下面详细说这个实例:
校验函数,开机调用:
void Secure_Verify(void)
{
u8 Dat_buf;
u32 temp,uidv;
u32 id0,id1,id2;
Read_UID();
char_to_long(&id0, (UID_data+0));
char_to_long(&id1, (UID_data+4));
char_to_long(&id2, (UID_data+8));
uidv = Encryption_win2kddk(SECURE_KEY,id0,id1,id2,0);
EEPROM_Read(Dat_buf, SECURE_KEY_ADDR, 4);
char_to_long(&temp, Dat_buf);
if(temp == uidv)
{
return;
}
else if(temp == SECURE_KEY)
{
long_to_char(&uidv,Dat_buf);
FLASH_DUKR = 0xae;//解除EEPEOM写保护
FLASH_DUKR = 0x56;
EEPROM_Write(Dat_buf, SECURE_KEY_ADDR, 4);
return;
}
else
{
asm("sim");// 关全局中断
while(1);
}
}其中 Read_UID参考了Wanyou123的代码:u8 UID_data;
void Read_UID(void)
{
UID_data = *(u8*)( STM8S_UID_ADDR + 0);
UID_data = *(u8*)( STM8S_UID_ADDR + 1);
UID_data = *(u8*)( STM8S_UID_ADDR + 2);
UID_data = *(u8*)( STM8S_UID_ADDR + 3);
UID_data = *(u8*)( STM8S_UID_ADDR + 4);
UID_data = *(u8*)( STM8S_UID_ADDR + 5);
UID_data = *(u8*)( STM8S_UID_ADDR + 6);
UID_data = *(u8*)( STM8S_UID_ADDR + 7);
UID_data = *(u8*)( STM8S_UID_ADDR + 8);
UID_data = *(u8*)( STM8S_UID_ADDR + 9);
UID_data = *(u8*)( STM8S_UID_ADDR + 10);
UID_data = *(u8*)( STM8S_UID_ADDR + 11);
}
其中SECURE_KEY和SECURE_KEY_ADDR的定义为://产品密钥
#define SECURE_KEY 0x56789abc
#define SECURE_KEY_ADDR 0x00
SECURE_KEY_ADDR是以STM8S103的EEPROM的开始地址0x4000为基准的偏移量。
现在问题是:用STVP给STM8S103烧录EEPROM,在Flash中已经烧录了程序的情况下,往EEPROM中SECURE_KEY_ADDR位置写入SECURE_KEY,独独这个位置的这个值死活写不进去,其他位置写这个值、其他位置写其他值、这个位置写其他值,都能正常写进去,真是惊人!!!
修改SECURE_KEY和 SECURE_KEY_ADDR后问题依旧,这不是什么特殊值特殊地址。
在Flash为空的情况下,EEPROM正常,任何位置任何值都可以写。
现在在Flash为空的情况下,往EEPROM中SECURE_KEY_ADDR位置写入 SECURE_KEY,然后再烧Flash(用STVP仅烧Flash),烧完之后,再读EEPROM的SECURE_KEY_ADDR位置,已经不等于SECURE_KEY了,但是也不等于新计算出来的以上程序中的“uidv”,程序卡在“while(1);”。
编译器用的IAR for STM8 V1.3。
对了,有人说HEX中会有KEY的数值串,我找了一下,以我的SECURE_KEY=0x56789abc为例,在生成的HEX中没有发现连在一起的56789abc,但是5678连在一起,然后在不远处9abc连在一起。
需要认真研读。 mark收藏 LZ发的资料很有用,还有各位大神的回答,获益良多 认真学习一下
恩 的确是一个不错的方法谢谢楼主 类似的方法我也想过。 学习了,谢谢 本帖最后由 win2kddk 于 2012-11-26 10:22 编辑
yoyobbs1 发表于 2012-11-26 08:23 static/image/common/back.gif
感觉这篇文章就好像stc的介绍自己强大无比一样的文章
这个问题不好说呵。。。。 好好研读一下{:lol:} 强帖留名! 以后再深究 有文字显示.....禁止反汇编修改即可了 批量生产怎么办,应该写一段boot代码,第一次运行程序时,将id号写入FLASH,同时在FLASH写入一个标志,表明第一次运行完了,第2次运行时,当检测到标志后,就会去检验id号是否和flash 的相同,不同就拴掉部分代码,让软件运行有缺陷或有后门 Niandet 发表于 2012-7-12 17:00 static/image/common/back.gif
补充:不要校验完成就当机或者其他明显的破坏动作,这点非常重要,因为反汇编跟踪时,就是以这个作为跟踪对 ...
用定时器去触发中断,中断函数放在一个隐蔽的地方。多设几个这样的中断,层层嵌套。。。在最后一个函数里面做校检
用哪个定时器,哪些中断,中断函数的位置,嵌套的结构,以及最后校检的函数,都不止一种。
跟踪死他{:lol:}
前辈觉得怎么样?{:shocked:} 神贴,谨受教了。。。。。{:biggrin:}{:biggrin:}{:biggrin:} 路过......... Flash+EEProm被人整片读出破解怎么办? 本帖最后由 dellric 于 2014-9-14 02:52 编辑
**********************
千万不要用楼主这种方法,这种方法是有缺陷的。如果搞到你的程序BIN文件,将文件放入仿真系统,通过触发读取唯一码的地址,可以定位到具体程序指令,通过分析指令的寻址方式,反向定位获取指令操作的地址数据或基地址数据,通过修改BIN文件里这个数据,将读取唯一码地址修改到一个新的地址,如BIN镜像文件末尾,在末尾追加写入该单片机的序列号,系统即宣告破解。这里不管加密者用复杂度多高的加密算法,只要在读取这些固定ID,就能定位并修改。早些年有日本的芯片就这样加密,很轻松就给它干掉了,想不到这么些年了还有人继续用这种方式加密。正确的做法是把程序整体做多重加密,并且用复杂的算法算出序列号的基地址后用间接寻址方式获取数据,在地址解算出来前一定要间接验证地址的有效性!在做失效处理时,不能用while(1);这样简单的方式放弃控制,因为非常容易跟踪,最好是能继续使用若干小时后做放弃控制处理,加大破解的时间成本,在放弃控制前必须有非法软件的告知信息通知用户,否则,放弃控制造成的损失,可能会造成法律上的麻烦。 本帖最后由 clkyui 于 2014-9-14 08:29 编辑
我觉得防破解不能站在外人的角度上,最好的方案是,加密的作者,知道整个加密的过程,但是也不能解密,所以 if(xxx!=yyy){zzz;}是不行的 , 其实厂家可以出一款专门量产的芯片,没有调试器,只能写,不能读,每1年出一个批号,每个批号的外设地址随机变化。这样的话,就算破解了芯片,拿到hex文件,但是你没有源文件,你要每个批号破解一次,你也未必买到与作者相同的批号。 本帖最后由 clkyui 于 2014-9-14 08:28 编辑
此法本质也只是唯一ID的加强版,虽然不是无敌,但是可以阻止包括作者在内的大部分的破解者,当然厂家会有的麻烦,但是安全与方便从来都是矛盾的,如果广大的原创者追随,估计再麻烦也有厂家做,这样大家就可以放心的专心的做产品了 mark!谢谢! 借鉴学习下 标记好贴 给力,正需要{:lol:} 很好的思想,学习了。 虽然帖子很久了,但是知识永远不会过时!
页:
[1]