单片机加密思路,相当不错的帖子

2019-04-15 19:23发布

http://www.amobbs.com/thread-5518980-1-1.html 以下是摘自帖子的一些好想法

本帖最后由 smset 于 2013-2-4 16:24 编辑


第一环:


ID-->F1(ID) -----》IDX,


将ID通过自定义的一个算法F1,转换为一个整数IDX , F1为不可逆运算,也不能被轻易分析,这个实际上是容易实现的。


然后,将IDX保存到EEPROM或FLASH的任何地方,我们通过编一个函数 GET_IDX()能够读出这个数即可。




第二环:


再编一个函数:


int getmy_1(){
   return F1(ID)-GET_IDX()+1;
}


int getmy_0(){
   return F1(ID)-GET_IDX();
}




还有一些其他自定义的函数内:都可以直接使用(F1(ID)-GET_IDX()) 来替代0; 直接用(F1(ID)-GET_IDX()+1)来替代1;




第三环:


在程序任何需要使用到1的地方,都可以考虑使用getmy_1()代替。


或即使本不使用1,也可以来用上一下:


如: x=(x+1-getmy_1())*getmy_1();  




或把 for(i=0;i<=count-1;i++) 
改为: for(i=getmy_0();i<=count-getmy_1();i++)


抑或是:


指针 p++;可以改为: p=p+getmy_1();




或者:给函数传递变量时,传递方在 变量上+F1(ID), 被调用的函数在  变量上--GET_IDX():


比如本来是 
           void f1(){
                    int i,j;
                    ....
                    j=f2(i);
                }


              int f2(i){
                     return i*2;
              }
修改为:
           void f1(){
                    int i;
                    ....
                    j=f2(i+F1(ID));
                }


              int f2(i){
                     return (i-GET_IDX())*2;
              }




如程序被非法复制:从ID无法得到IDX,那么IDX和F1(ID)不相等,


那么getmy_0不再是0,getmy_1不再是1,




程序将出现什么结果,谁都无法预料了。


---------------------------------------------------------
特点: 由于整个程序的加密,采用了“运算加密”的思路, 而非判断加密, 又没有用到任何一行 if判断,让解密者去想破脑袋吧。


即使猜测到有可能是这种加密思路,但是程序并不是基于if判断跳转,加密的作用自然分布在程序的各个地方,怎么去改,也很伤脑筋了。








直接修改getmy_1和getmy_0,这个首先是得分析出加密思路时才能作出的。


另外修改getmy_1和getmy_0只是干掉简单的部分。


还有一些是很难干掉的:


给函数传递变量时,传递方在 变量上+F1(ID), 被调用的函数在  变量上--GET_IDX():


比如本来是 
           void f1(){
                    int i,j;
                    ....
                    j=f2(i);
                }


              int f2(i){
                     return i*2;
              }
修改为:
           void f1(){
                    int i;
                    ....
                    j=f2(i+F1(ID));
                }


              int f2(i){
                     return (i-GET_IDX())*2;
              }


另外,包括一些全局部变量的处理,可以在一些函数里面加上F1(ID);
在;另外一些地方进行-GET_IDX()的操作,并不会将代码简单集中放到一点的。


当然,如果精准的理解了整个程序的加密思路来说,这个也可以花时间干掉,不过这种加密方式本身目前是很少有人用的。


总之这种加密强度远高于简单的if比较方式。这个是一个新的基本思路,我举的例子只是一些简单的例子,完全可以自己做得更加灵活。










如果是inline函数并上去的话,那么有个小问题就是代码量会超大。







goodcode 发表于 2013-2-4 23:53 
就读取id的代码内联了又能怎么样 数量级也不可能太大 尤其是通过高级编译器编译 代码形式都差不多 就算用 ...


所以说要换种形式啊。类似jmp main我写成
*(SP+1)=&main >>8;
*(SP) = &main & 0xFF;
return;
如此等等。编译器再搞得变态一点,拼命用寄存器。内存到处占,到处插垃圾代码应该就能解决问题。
















是的,这个是有破解效力的,所以前面讨论了一种方式就是把GETID  写为inline内联, 所以读ID的GETID并非一个函数了。 


而且如果大量分布在代码里,(实现时,可以在程序编写完成后,统一把 =0; 替换为 =getmy_0() , 这样原代码里所有=0;
的地方都变为加密点,对于编程者而言这个文件内容替换操作仅需要1分钟而已,但对于破解者来说,就要花很长时间去到处修改)


同样=1;也可以这样干。  只是代码会变大, 但也基本未丧失程序的可读性。


推而广之,同样可以=2; =3 。。。。。,只要flash够用。多多益善。




另外,程序空白区域的确是给破解者发挥的空间,我也考虑连空白区域都不给破解者,通过一种机制让整个Flash充满代码,哪怕是冗余代码(但也是有关联的,牵一发而动全身),不给破解代码落脚的空间。






===============================================================================================================================


















读唯一ID的时候这么读:
BYTE* p=ID_ADDRESS-__LINE__;
*(p+__LINE__-1)就是唯一ID的开头


用适当的宏把上面两句话封装起来方便操作,这样就把访问唯一ID的地址隐藏起来了。
这一段程序在每个地方编译的结果都不同,因为你的代码line不同^_^
这样就不可能简单的在反汇编里面查找唯一ID的地址了。


对此,我能想到的方法只能是开着内存断点来运行所有程序,手动修改每个检查唯一ID的地方。
但是,除非你把所有的程序分支都执行到(这基本上不可能),有任何一个检查唯一ID的地方没有找到都是白搭。
比如,每小时检查一次,每天检查一次,遇到某某条件检查一次。。。
这些检查的方法看起来都像在访问全局变量。。。
















===============================================================================================================================








我做产品防破解采用如下策略:
1)正常程序运行启动时,判断rom中的某个变量A,为0就需要读一次某个/几个端口的状态,一旦对上就将rom中的A写1。这一般需要用几个跳线在整机安装测试时完成。
2)如果A==1,程序运行正常,但有某个或者几个参数当满足一定条件时(下面的3) ,会略有改变,于是整个设备基本正常,但又性能下降,看上去完全不像是软件问题,而是很自然的会当作是某些机械或者其他方面性能下降所致。
3)我喜欢用铁电的Fram来记录运行日志,开机次数,运行时间等等,运行日志和上述方法结合使用,可以把防破解拷贝做的很隐蔽。虽然破解很容易,而且不需要分析修改代码,就能“正常”工作,产品一旦经过相当长一段时间使用都会出问题,卖的越多亏的越多。