软件保护壳技术专题 - 识别函数与数据区域












做壳很容易,有点做病毒知识的人都可以编写出壳来。但强度就有所差别了。
什么才是凶猛的壳?
我觉的是这样的 "猛壳 = 识别 + 重定位".识别用于让壳更了解要保护的程序。重定位为了可以保证保护程序的正常运行。如果能把识别与重定位做好。那么很多新的玩意就都可以玩了。如果你能把一个壳做成一个2进制文件的2次编译器。这个编译器的输入是以编译好的程序。输出是进行重编译的程序。那么这个壳因该相当的犀利。不过事与愿违。要完美的解决以上技术问题。有相当大的难度。我们也许不能把这个程序进行这样的重编译。但是局部的代码因该还是可以的。例如"VMP"不正是这样的产物吗? 写篇文章把我最近搞的一个函数识别的小算法奉献给朋友们。
<算法流程>
0.单函数识别
从一个地址开始,在未知长度的情况下,识别出这个函数的长度。
流程算法如下:
1) 从当前位置开始进行反汇编
2) 记录所有跳转流程指令
3) 遇到ret或者retn指令后,回溯整个跳转流程链表
4) 如果找到jcc则判断是否跳转后的地址是否大于当前的指令地址
5-1) 大于,则跳转到流程,进入预分析结尾流程
5-2) 无大于的情况,此函数分析完毕,返回
预分析结尾:
这里鉴别函数帧也可能造成不稳定,有些函数在ret之后还有一些指令在这些指令之后必定有一个JMP跳转到最后一个ret或者之前利用此来进行预分析结尾
这里出现种情况:
1) 找到上述那个最后的JMP则将此视为结尾
2) 如果找到nop视为结尾(用户可以指定此选项,默认存在)
3) 如果找到int3视为结尾(用户可以指定此选项,默认存在)
4) 如果找到视为结尾(用户可以指定此选项,默认存在)
1.交叉引用
从一个函数开始,检查它的对外跳转的语句以便达到另一个函数,如此循环识别出代码段中的所有被直接引用的函数体。
识别交叉引用采用三遍分析,并在分析过程中记录每天指令,并设置是否可以HOOK(用于代码乱序)
流程算法如下:
第一遍分析
1) 依次对所有指令进行分析,设定指令是否可以交换,并进行初步HOOK分析刺探,将通过偏移的的跳转指令进行识别,并鉴别HOOK成功率,并填充这条指令对标志寄存器的影响和通用寄存器的影响
2) 通过单函数鉴别 (上述已经阐述了其算法)函数确立入口函数的长度
3) 再次遍历入口函数,通过分析入口函数的CALL指令,分析出其他函数
4) 循环,2过程直到把映射中所有的函数都鉴别出来
5) 进行链表排序(地址由低到高)
6) 将链表与映射内存由高到低依次进行对比,找出未找到的代码块,并使用,1,2方法进行鉴别将无法分析的代码识为数据
第二遍分析
1) 遍历函数链
2) 在识别过程中,鉴别出一个函数开辟的局部变量所需的空间,具体监视sub esp, XXX指令
3) 在遍历过程中如果发现有指令直接对全局变量进行引用,记录其访问地址
4) 如果遇到跳转指令,则设置它目标地址指令的跳转引用链表
第三遍分析
1) 遍历函数链
2) 找到所有动态跳转指令,并对它进行反馈分析,直到找出动态跳转寄存器值的合成结果,并进行运算
这里反馈的结束算法是:
查看当前跳转指令,是否由引用指令
如果有则遍历这个引用链
如果没有则向上分析条指令,如果没有存在可以影响寄存器的mov,lea指令,则直接视此指令为不可HOOK的指令,如果动态跳转出现使用两个寄存器做内存跳转的直接视为不可HOOK的指令。
当然这里有些步骤是可以合并的。在实际CODE中我将上面三遍合成为两遍原则。
2.识别代码段的数据与代码
在理论上代码与数据是不可分的,通过分析将代码与数据进行分离。这也是难度最大的地方。
这里给出一些代码。
很多朋友要问为什么要再次鉴别这些东西。从交叉引用就可以识别为什么还要继续在重新识别一遍
原因很简单:为了可以保证所有函数和无用区域都作为信息传递给壳。有些动态调用的从交叉引用很难分析得出。在引用链上没有。所以要采取这个方案重新把他找出来。还有那些函数与函数之间的区域,这些区域你没感觉到对于做壳来说很珍贵吗?发挥你想象力去利用这些空白区域。。。
下面算法没给出深度分析的算法。那个可以自己总结规则了。现在我的那个代码已经过W行了。太多了规则了。 规则越细,可以保证识别程度越准确。
注意:上传附件及图片大小不得大于30M。
⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。
