菜农的加密理论---天下无贼论
1.版权信息的保存 虽然芯片被解密而能够得到BIN及HEX格式的文件,但产品的版权信息 并未被篡改。
这个信息被明文或密文读出后会通过一定途径发布出去。 那么解密芯片者必须再进行逆向工程来掩盖他们不光彩的事实。 所以保护产品的版权信息可能最为重要。
2.程序入口的保护 在逆向工程,最终要做到真正的代码和数据的分离工作。 其首要解决的就是如何找到正确的程序入口地址,然后在进行二次扫描 等基础工作。 当扫描程序遇到分支后,必然要做出正确的判断。 其一路分支继续往后扫描,另一路分支将记录分支的入口地址的分支状态 以便为二(多)次扫描做出前期的准备工作。
分支状态对于51来讲可简化用扫描次数及位置号来替代。 即 0--从未扫描到过 最后生成为数据。例 DB 55H 1--操作码 2--操作数1 3--操作数2 4--待定入口(入口进待扫描队列)
每次扫描的选择入口地址的分支状态必须为0。否则本次扫描失败! 直到遇到LJMP/AJMP/SJMP/JMP @DPTR/RET/RETI停止本次扫描
依此类推。直到全部扫描结束。
分析以上的扫描原理及步骤,我们可以造假一些数据或代码使其1次或二次 扫描终止,最后迫使其采用强行(不按以上规则)扫描,从而得不出人能看懂 的汇编代码。
3.程序出口的保护 当全部扫描工作结束后,代码和数据将会自然分离。 由于扫描规则的约束,数据中也会包含一些代码。 例如源程序中从未调用过的子程序的“泄露代码”。
他们一般以RET/RETI结束,以PUSH XXX开始。故很容易将泄露代码逆向出来。 从而找出原作者没调用或没成型的方法。
4.CRC变量位置和CRC运算子程序保护 要想实现以上3种保护,必须防止逆向者篡改版权信息,代码入口地址及相应 的出入口保护的代码不被其强行改写或用NOP,DB 00H等填充,以便达到最终 逆向成功的目的。
由于MCU资源和时间速度等限制,应该采用简洁而枯燥乏味的代码组合。常见 的有累加/异或/移位等算法。
累加和异或是基于单(多)字节操作的,而移位是基于单个位操作的。
故要枯燥乏味肯定要数移位更胜任了,所以常用CRC运算。
CRC运算有正运算和逆运算(菜农没看过相应报道和**)之分,也有左右移位 之别。更有变化无测的“权”(菜农想不了起什么好听的名字)
分析和论述到此,上述4点本人认为比较重要。
现在举2个实际例子说明如何保护代码和数据不被逆向为汇编助记符。
例1 如何保护版本信息 ;------------------------------------------------------------------------------; ; 版本信息区 ;------------------------------------------------------------------------------; DB 02H;伪造LJMP指令 ;------------------------------------------------------------------------------; ;大家可以试试修改下面任意数据的结果~~~ ;------------------------------------------------------------------------------; HotPowerMessage:;敌人找看不见HotPowerMessage入口地址但能知道~~~ DB "HotPower@126.com 2007.11.13";CRC8结果为0xc5 DB 0C5H;以上版本信息区字符串的CRC8结果,这样可以保证全局变量CRC永远为0!!! DB 0;版本信息区结尾标志 ;------------------------------------------------------------------------------; 程序祥见:阻止反汇编软件汇编演示程序(天下无贼版),当然这还只是个入门之类的提高版
假设版本信息区为字符串"HotPower@126.com 2007.11.13",那么其右移CRC8运算后结果为0C5H 如果我们再以0C5H做一次运算后,CRC的结果必为0!!!!!!!!!!!!!!!!!
为什么我们还要不辞劳苦地再进行一次CRC运算呢???为什么很多软件被轻易解码呢???
道理就在这里面!!!
如果逆向者找到相应的条件分支语句中包含比较05CH的信息,那么这个程序不攻自破!!!
举个我1分钟就逆向的一个例子: 有个PC软件和PC并口0x378通信,但俺的并口地址为0x3bc.故它不支持俺。要求对方改成可选地址的。 回复是忘了,即使改也要收费即3天左右。
晕!!不就是将78 03改为bc 03吗???
俺用UE搜索整个EXE文件就只有3个地方有。几次实验通过了。
所以重要信息不要留给逆向者空子!!!
当然所谓“艺高人胆大”,你明码给他版本信息,他“汉化”后程序用不成就知道遇到对手了。 他会坐下来与你较量。
所以CRC运算后千万不敢立即做出处理!!!而要像病毒一样随后爆发,这会使他更难受的。且记!!!
例2 如何保护代码出口(RET/RETI)
;---------------------------------------------------------------------; ; 出口保护代码 ;---------------------------------------------------------------------; COMMAND0_EXIT: MOV A,CRC;因为信息没修改CRC就为0,修改程序就就飞~~~哈哈,看你晕不晕 JZ $+3;肯定运行NOP;RETI DB 12H;CRC校验和,伪装的LCALL指令 DB 00H;结尾符实际为NOP指令 ;用RETI迷惑反汇编,以为是某个中断服务程序 RETI;返回到MAINLOOP
菜农一生发表和隐藏的一些自已都认为是臭美的方法和独到见解,都包含着运气的成分。 当然这也和辛勤耕作有很大关系,回报也是很自然的事。
拿这个CRC的地址来说吧,我随手将他定义在30H处,根本没多想。应该这是51人最开始想的地方。 他们绝不会想20H~2FH这奢侈的地方,所以30H自然作为首选。
开始编程时是这样写的: COMMAND0_EXIT: MOV A,CRC;因为信息没修改CRC就为0,修改程序就就飞~~~哈哈,看你晕不晕 JZ $+3;肯定运行NOP;RETI DW 1200H ;用RETI迷惑反汇编,以为是某个中断服务程序 RETI;返回到MAINLOOP DB 00H;待计算CRC校验和,伪装的LCALL指令 DB 00H;结尾符实际为NOP指令
写完后才发现前面已经有00H结尾符,故改为 COMMAND0_EXIT: MOV A,CRC;因为信息没修改CRC就为0,修改程序就就飞~~~哈哈,看你晕不晕 JZ $+3;肯定运行NOP;RETI DB 00H;待计算CRC校验和,伪装的LCALL指令 DB 00H;结尾符实际为NOP指令 ;用RETI迷惑反汇编,以为是某个中断服务程序 RETI;返回到MAINLOOP
对 MOV A,CRC;因为信息没修改CRC就为0,修改程序就就飞~~~哈哈,看你晕不晕 JZ $+3;肯定运行NOP;RETI 两句进行CRC运算后惊奇地发现---苍天呀,是我需要的12H!!!!!!!!!!
故就成了最终的程序: COMMAND0_EXIT: MOV A,CRC;因为信息没修改CRC就为0,修改程序就就飞~~~哈哈,看你晕不晕 JZ $+3;肯定运行NOP;RETI DB 12H;已计算出上2句的CRC校验和值,伪装的LCALL指令 DB 00H;结尾符实际为NOP指令 ;用RETI迷惑反汇编,以为是某个中断服务程序 RETI;返回到MAINLOOP
原因:当初CRC这个全局变量位置在30H才导致了这个神仙想要得到的结果之一(还有02H)
至于为什么要有这些保护及它的作用,为了不晕到一大片观众,就到这里吧。
菜农被21IC的程序匠人双规并令俺面壁思过逼交脑浆之作,俺无奈献出本文。
望大家不晕~~~先到这里,以后再提高提高~~~
雁塔山野村夫 菜农HotPower 2007.11.15 思过于西安大雁塔菜地.
相关链接:https://bbs.21ic.com/upfiles/img/200711/20071115193754630.rar |