浅谈知识产权保护方法之加密Kinetis K60(方案一)
本帖最后由 FSL_FAE_JiCheng 于 2013-10-29 10:57 编辑所谓“知识产权保护”,其实就是在产品量产之后防止其芯片内部代码通过外部调试器被有效读取出来的手段,毕竟现在来说硬件电路是比较容易被复制的,如果软件再不设防的话,在山寨技术如此发达的今天(用发达来形容貌似不是很过分吧,呵呵)这个产品估计很快就会被淘汰了。
因为最近有很多客户问到关于Kinetis的加密锁定问题,所以我觉着还是有必要对其细说说的。其实飞思卡尔对于知识产权保护方面还是做了很大的功夫的,而且使用起来也是比较方便的(这点很重要),具体可以参考Kinetis的Reference Manual中Security这一章,这里我就以在IAR环境下锁定K60为例介绍一下使用方法:
1. 首先简单介绍一下原理,即如果将K60置于Security状态(即锁定状态),则是不能通过Debug接口或者EzPort接口对芯片内部flash有任何操作的(CPU还是可以正常读写flash的,也就是说程序还是可以正常运行的,只不过是不能被外部非法读取了),当然“mass erase”命令除外(我们平时在Jlink Command窗口中敲入的unlock Kinetis命令就是触发这个命令给芯片的),通过“mass erase”命令可以再次将芯片擦除到出厂状态(即unsecure解锁的过程),这样芯片就又可以正常使用了(方便用户之后的程序升级)。咳咳,不过不用担心,解锁之后的芯片其内部的flash已经被完全擦除掉变为空片状态,也就是说内部的代码已经没有了,所以。。。懂的。。。呵呵;
2. 说完Security的原理,下面再聊聊K60实现security的process。我们可以通过K60的FTFL_FSEC寄存器中的SEC位来设定芯片的security状态,如下图所示,芯片默认出厂状态SEC位是为10的,即非加密锁定的,而如果将SEC位设定为00、01或者11任何一种情况,则芯片都将处于锁定状态(这就是我们接下来要干的事了,呵呵)。这里可能会有人疑问,在这个寄存器在重新上电之后会保存内容吗,我只能说“咳咳,都能抢答了”,哈哈,这正是我下面要说的;
3. K60在flash中0x00000400~0x0000040F这16个字节范围的地址定义为寄存器加载地址(Flash配置区),如下图所示,而这其中0x0000040C的地址内容在芯片上电之后会被自动加载到FTFT_FSEC寄存器中,也就是说我们只需要在烧写程序的时候把相应数据写到该flash地址即可在上电之后对芯片进行加密锁定,由此实现加密锁定。
4. 好了,原理和process都说完了,准备工作就做好了,下面就撸胳膊抹袖子开工干活吧,呵呵。其实飞思卡尔已经为我们做好了相关工作,只不过我们平时因为用不到没有注意到罢了。我们打开IAR环境,然后导入需要加密的代码工程,再打开工程目录下cpu文件组中的vectors.c和vectors.h(如果你的工程架构类似于飞思卡尔官方的sample code的话就在这个路径下)。在vectors.h里的最后部分我们会看到4个config段(共16个字节大小),如下图1,这四个段就是定义了上述0x400~0x40F的内容,其中CONFIG_4中最后的0xfe即为0x40C地址的内容(注意ARM处理器默认是little end模式的,所以0x40C在低地址),0xfe表明SEC位为10,即非加密状态,这样如果我把该0x40C地址的内容改成0xfc、0xfd或者0xff任意一个都可以实现对芯片的加密锁定。至于该四个配置段定义是如何映射到K60的flash区中的呢,去vectors.c文件中中断向量表vector_table[]的最后看看就知道了,如下图2;
5. 这里我们选择将CONFIG_4内容由原来的0xfffffffe改成0xfffffffd即可,然后保存编译通过之后,在查看其生成的s19文件中可以看到如下图所示,即0x40C地址的内容被修改成了0xfd,这样烧写文件就搞定了;
6. 当然到这一步实际上还没有完,其实在IAR的新版本之后(IAR6.6之后),其自带的flashloader默认是把0x400~0x40F这段保护起来的(防止误操作对芯片意外的security),即使如上面所述修改好相应内容,在烧写的过程中flashloader也不会对这段地址的内容做任何擦除和写入。为此还需要再额外对IAR的flashloader进行配置,具体步骤如下:
(1)进入Options->Debugger->Download,选择如下:
(2)点击“OK”,然后系统会提示保存该修改后的flashloader配置,建议把自己修改好的.board文件保存到自己的工程目录下,方便以后直接调用该flashloader。
7. 至此全部设置就搞定了,点击编译连接,然后下载,即可把加密后的代码烧写到芯片的flash里面去了。注意如果我们点击调试按钮的话,一旦程序烧进去之后调试器会自动复位芯片,此时加密状态位会被load到FTFT_FSEC位中,芯片的调试端口就会被停掉,所以这时进入不到调试界面,而是弹出错误窗口,不用担心,因为此时程序已经正确烧到芯片中,我们重新插拔电源之后会看到程序已经正常执行,而此时的芯片已经处于加密状态。当然如果我们想再进入调试模式调试芯片的话,一种是通过Jlink Command窗口解锁,如下图1,另一种是再次点击调试按钮,会弹出解锁窗口,点击解锁即可,如下图2。
图1
图2
加密方案二已更新,浅谈知识产权保护方法之加密Kinetis K60(方案二) 不错期待更多这样的经验总结分享 总结的不错,顶~~ 还不错以后会用得着 MARK下...感觉挺好的,以后就不至于发生像上次电设似的问题了... 这款MCU可否支持在RAM中运行程序?
在RAM中运行Flash程序读取程序,是否可以将Flash中的数据读出? 会不会从USB 读出的呢? yinglively 发表于 2013-10-28 11:53 static/image/common/back.gif
这款MCU可否支持在RAM中运行程序?
在RAM中运行Flash程序读取程序,是否可以将Flash中的数据读出? ...
K60是支持在RAM中运行code的,至于你的意思是在UserCode中人为的加入flash读取程序吗,那这种也是原始作者才能加入的后门,所以一旦代码被加密了外部是肯定读取不到里面内容的除非整片擦除掉~ anvy178 发表于 2013-10-28 11:56 static/image/common/back.gif
会不会从USB 读出的呢?
这个是代码原始作者来决定的。 armok 发表于 2013-10-28 12:10 static/image/common/back.gif
精华 COOL贴。
谢谢阿莫~ FSL_FAE_JiCheng 发表于 2013-10-28 13:37 static/image/common/back.gif
K60是支持在RAM中运行code的,至于你的意思是在UserCode中人为的加入flash读取程序吗,那这种也是原始作 ...
那K60能否支持在RAM中调试程序?
如果可以,我写一个打印Flash内容的调试程序,在RAM中调试运行,这样就可以把Flash中的数据逐一打印出来了。 本帖最后由 Gorgon_Meducer 于 2013-10-28 15:07 编辑
我一般是用EzPort来写程序,所以不需要特别的设置,直接就会把对应的Bit给写上的。
只是说实话,用户的IAP部分编写起来要跳过关键的Security设置部分,这里不做好,
后面会很痛苦。另外K系列默认是从0x00000000启动的,虽然能修改Vector Table的
位置,但是意味着IAP必须占据头部的VectorTable的头8个字节……同时,用户程序
的VectorTable的头8个字节也要被IAP自动劫持后处理掉。这些细节都挺麻烦的。
以下是我IAP代码的参考片段,专门处理这类问题,以供参考:
/*! \brief bootloader command handler
*! \param pchStream data block
*! \param hwSize data block size
*! \retval 0 failed in parsing
*! \retval none-zero-size reply data size
*/
uint_fast16_t cmd_flash_write(uint8_t *pchStream, uint_fast16_t hwLength)
{
uint_fast32_t hwAddress = TYPE_CONVERT(&pchStream, uint16_t);//!< address
uint_fast16_t hwSize = TYPE_CONVERT(&pchStream, uint16_t); //!< size
uint8_t *pchSrc = &pchStream; //!< data
do {
//! protect the reset vector and stack address
if (hwAddress < 0x0008) {
//! protected area
uint_fast8_t chDelta = MIN((0x0008 - hwAddress), hwSize);
uint_fast16_t hwOrigionAddress = hwAddress;
//! save overlap data to protected are
uint8_t chOrigionValue;
uint_fast8_t hwCounter = 0;
for (;hwCounter < chDelta;hwCounter++) {
chOrigionValue= *pchSrc++;
}
extern uint32_t __CRITICAL_VECTOR_EXCHANGE_AREA__[];
//! write flash
if (!FLASH_WRITE(hwOrigionAddress + (uint32_t)__CRITICAL_VECTOR_EXCHANGE_AREA__, chOrigionValue, chDelta)) {
SET_IAP_REPLY(IAP_RSP_ERROR);
break;
}
//! update information
hwSize -= chDelta;
hwAddress = 0x0008;
}
if (hwSize > 0) {
//! protect system configuration flash
if (hwAddress >= FLASH_CONFIG_START && hwAddress < FLASH_CONFIG_END) {
//! start address invade the system configuration area
uint_fast16_t hwDelta = FLASH_CONFIG_END - hwAddress;
hwAddress = FLASH_CONFIG_END;
hwDelta = MIN(hwSize,hwDelta);
hwSize -= hwDelta;
pchSrc += hwDelta;
} else if (hwAddress < FLASH_CONFIG_START) {
if (hwAddress + hwSize <= FLASH_CONFIG_END) {
hwSize = FLASH_CONFIG_START - hwAddress;
} else if (hwAddress + hwSize > FLASH_CONFIG_END) {
//! write memory block before the protection area
uint_fast16_t hwTempSize = FLASH_CONFIG_START - hwAddress;
if (!FLASH_WRITE(hwAddress, pchSrc, hwTempSize)) {
SET_IAP_REPLY(IAP_RSP_ERROR);
break;
}
hwAddress = FLASH_CONFIG_END;
pchSrc += (hwTempSize + (FLASH_CONFIG_END - FLASH_CONFIG_START));
hwSize -= (hwTempSize + (FLASH_CONFIG_END - FLASH_CONFIG_START));
}
}
}
if (hwSize > 0) {
//! protect bootloader area
if (hwAddress >= IAP_BOOTLOADER_ADDRESS) {
//! bootloader overlap
SET_IAP_REPLY(IAP_RSP_ERROR_BL_OVERLAP);
break;
} else if ((hwAddress + hwSize) > IAP_BOOTLOADER_ADDRESS) {
/*! \note invade into bootloader area, we just write as more memory as
*! possible.
*/
hwSize = IAP_BOOTLOADER_ADDRESS - hwAddress;
//! write memory block
if (!FLASH_WRITE(hwAddress, pchSrc, hwSize)) {
SET_IAP_REPLY(IAP_RSP_ERROR);
break;
}
//! bootloader overlap
SET_IAP_REPLY(IAP_RSP_ERROR_BL_OVERLAP);
break;
}
//! normal area
if (!FLASH_WRITE(hwAddress, pchSrc, hwSize)) {
SET_IAP_REPLY(IAP_RSP_ERROR);
break;
}
}
//! send reply ok
SET_IAP_REPLY(IAP_RSP_OK);
} while (false);
return 1;
}
yinglively 发表于 2013-10-28 14:25 static/image/common/back.gif
那K60能否支持在RAM中调试程序?
如果可以,我写一个打印Flash内容的调试程序,在RAM中调试运行,这样就 ...
K60支持在RAM中调试的 Gorgon_Meducer 发表于 2013-10-28 15:03 static/image/common/back.gif
我一般是用EzPort来写程序,所以不需要特别的设置,直接就会把对应的Bit给写上的。
只是说实话,用户的IAP ...
“傻孩子”也开始搞Freescale的东西了?这下好了,期待傻孩子的好文章~ FSL_FAE_JiCheng 发表于 2013-10-28 15:32 static/image/common/back.gif
“傻孩子”也开始搞Freescale的东西了?这下好了,期待傻孩子的好文章~
一直在搞啊……
过几天放个EzPort的驱动出来。我之前做的小离线编程器上用的。 Gorgon_Meducer 发表于 2013-10-28 17:39 static/image/common/back.gif
一直在搞啊……
过几天放个EzPort的驱动出来。我之前做的小离线编程器上用的。 ...
好的,欢迎欢迎,谢谢分享~ 谢谢分享!加密这个问题是每个MCU都面临的问题。 赞一个!!写得非常详细!
有一点想要请教一下,这种方式是否可以被列为是"防君子不防小人"?
毕竟现在有人多山寨厂家是直接开片取二进制的,配合唯一id等加密方式是不是才更加稳妥? 支持,好贴 本帖最后由 FSL_FAE_JiCheng 于 2013-11-16 21:50 编辑
zgxcom123 发表于 2013-10-28 18:53 static/image/common/back.gif
赞一个!!写得非常详细!
有一点想要请教一下,这种方式是否可以被列为是"防君子不防小人"?
果然也是高手,呵呵,剖片取二进制的方法成本还是非常高的,另外飞思卡尔Kinetis每个芯片都有一个128位唯一ID,就像你说的可以结合加密算法实现更安全的加密方式。 FSL_FAE_JiCheng 发表于 2013-10-29 10:54
果然也是高手,呵呵,剖片取二进制的方法成本还是非常高的,另外飞思卡尔Kinetis每个芯片都有一个64位唯 ...
记得阿莫的空气净化器就是用了三种措施:唯一ID,开盖擦程序,FSL订制芯片
个人对订制芯片比较感兴趣,因为这一措施可以说从根本上杜绝了剖片这种流氓行为(有程序但是没有芯片,改二进制还不如重新写)
不过这种订制可以达到哪种程度呢?仅仅是改变封装(成本不高),或是DIE都有更改(费用高昂),或是FSL本身就为客户提供了数种非公开的型号(产量小,售价会高出一些但不至于天价)? zgxcom123 发表于 2013-10-29 11:52 static/image/common/back.gif
记得阿莫的空气净化器就是用了三种措施:唯一ID,开盖擦程序,FSL订制芯片
个人对订制芯片比较感兴趣,因 ...
可以定制封装也可以定制DIE,但是我个人觉着哈定制DIE的话买FSL的DIE不贵,贵的是你自己需要花费高成本的封装流程还要刨去可能出现的坏片之类的成本,这样小量的话根本承受不起~ 刚开始学习K10 顶一下,还没用过飞思卡尔的片子 FSL_FAE_JiCheng 发表于 2013-10-30 10:49 static/image/common/back.gif
可以定制封装也可以定制DIE,但是我个人觉着哈定制DIE的话买FSL的DIE不贵,贵的是你自己需要花费高成本的 ...
请问FSL的唯一ID是物理的还是FLASH里面的?
STM32的唯一ID实际是FLASH的,据说已经被破解了 很不错,学习了! 看起来就是对几个寄存器操作了下呀
430是烧熔丝做的,硬件上来做更让人放心啊。 学习了啊····觉得K60还是很棒的 如果出现 Unlocking device...Timeout while unlocking device. 这种情况 是不是说明该芯片完全锁掉了 不能再次解锁?? 好贴,顶一下。 精华帖子 嗯,不错,用户程序内部也可以解锁或加锁吧? lucaschou 发表于 2014-1-14 11:05
如果出现 Unlocking device...Timeout while unlocking device. 这种情况 是不是说明该芯片完全锁掉了 不能 ...
也不一定,可以尝试其他方法,可以参考此篇文章http://www.eefocus.com/bbs/article_1280_553023.html 嗯,可以的 我芯片是自己锁的,也出现这个图片那这个是要怎么解啊?我就是在JINK COMmander 输入 unlock Kinetis。然后还是解不开啊~ 学习 谢谢分享 总结的不错 帮顶一下 K60确实挺强悍,不过去年用的时候经常莫名其妙的把芯片锁了,然后又去解锁!! 顶一个! 很专业 通过寄存器来控制是否枷锁的方法个人感觉还是不可靠。 楼主总结得不错
条例清晰 步骤翔实 简直就是中文版AN 为什么我会有这个错误?Error: a value of type "pointer *" cannot be used to initialize an entity of type "unsigned int" D:\projects\cpu\vectors.c 126
ps:我用KE02 感谢楼主,分享,FLASH加密。 谢谢分享,学习一下! 加密真是不错的一个帖子,在TC这是唯一一个有效的方法 标记,浅谈知识产权保护方法之加密Kinetis K60 文章还不错!!! 感谢楼主分享, 谢谢楼主分享 谢谢楼主,楼主辛苦了。 我正在认真看啊 果断收藏,做最终产品加密很重要 谢谢,正打算用飞思卡尔的MCU 关注一下芯片的软件加密! 顶一下,好东西 不错期待更多这样的经验总结分享 挺好的,学习了 学习下{:biggrin:} {:handshake:} 很不错的经验 学习了..... 908S系列有没好的加密方法,8位机
页:
[1]