反静态反汇编技术的原理其实非常简单,主要弄清除反汇编程序的原理,就可以创作出多个ANTI-反汇编的方法。由于这个技术没有固定的技术形势,如何反怎么样反全靠你自己的想象力了。这里就介绍一下原理方面和几个常见的技术。
反汇编软件的原理:
反汇编软件的原理非常简单,读取可执行文件后从PE头中取出代码节的入口点文件偏移。按照X86体系结构的编码规则进行解码。然后将代码的助记符进行输出。类似IDA这样先进的反汇编软件还加入了函数头分析,跳转分析,局部变量分析等功能。其实,最基本的原理都是大学编译原理课程中所提到的词法分析和语法分析的相关知识。这里插入一个题外话,至少我感觉的是任何先进的软件,其中到最后用到的核心技术都是编译原理相关的技术。都出不了- 分析- 模拟 - 解释,这些东西。
随机加密原理:
随机加密原理最初是在多态病毒中使用的技巧,它的反反汇编语言也非常简单,就是将自身的代码进行加密,这样反汇编器反汇编后出现的是一堆乱码。这样的随机加密可以有两层随机一个是算法的随机,一种是算子的随机,算法的随机在专题下面的多态加解密中进行专门的探讨,算子的随机相对简单,只要取一个随机值就好了。而这样加密形式也有一个固定的形势存在。
如一下形式:
--- 解密头 ---
--- 被加密体 ---
--- 解密算子 ---
这样代码的功能部分被保护,保护不到的是解密头。解密头启动后如果节被设置了可写标志则直接执行,如果没有,可以使用VirusProtect这个函数修改内存的属性进行可写的设置。当然也可以开辟一个堆空间将密体写入并解密运行。如果认为一开始在没有任何重定位的情况下不想暴露太多的获取API的函数和功能,也可以将代码写入栈中,这样可以进行两个分段的解密情况,一加密的为代码体本身,另一个就是保护程序自身的功能代码。例如:解密代码和ANTI-DEBUG代码。在栈中有个很方便的事情就是天生支持可读可写可执行,分配空间方便等特点,释放轻松等特点,大有百试不爽的感觉。
此结构类似如下(可以自行发挥想象构建复杂的结构):
--- 解密头 ---
--- 被加密体 ---
--- 功能被加密体 ---
--- 加密体解密算子 ---
--- 功能体解密算子 ---
解密头首先开辟栈,将功能被加密体写入栈后解密,再次跳入执行。功能体解密真正的功能代码。当然可以在其中加入ANTI-DEBUG代码与设定异常等。
加密这种方法简单实用。如果有想些类似程序的朋友不妨常用,而且它反汇编反的很彻底,一个简单的XOR就能让IDA对主体分析失效。
不规则的函数头:
让我们先看一个标准的函数头
push ebp
mov esp, ebp
sub esp, StackSize
代码...
mov esp, ebp
pop ebp
ret
IDA在识别函数的时候也是通过识别这些指令的opcode码来识别函数的。通常在整过编译器编译过后采用[ebp+偏移]来引用参数,而使用[ebp-偏移]来引用局部变量的。
当然写壳这类的东西用汇编是最适合的,如果用高级语言当然一定也要嵌入汇编,总之因为汇编的灵活,我们就来构建自己特殊的函数形势,让IDA分析不到。其他反汇编程序全部忽略。(至今没发现比IDA还健壮的。)
这里给出一些思路吧。因为这方面也没有什么固定的东西,说白了一切看发挥,例如sub esp, StackSize,就可以使用以下函数替换,当然还有清除堆栈的指令 mov ebp, esp; pop ebp也可以替换
;; ----- 构建栈空间----- MakeStackLive: ;; arg is in eax mov ecx, 04h idiv ecx movzx eax, ax xor ecx, ecx MakeStackLiveLoop: call MakeStackLiveInsertOne MakeStackLiveInsertOne: inc ecx dec eax jnz MakeStackLiveLoop mov eax, 04h imul ecx mov eax, dword ptr [esp+eax] push eax retn 0 ;; ----- 清除栈空间 ----- ClearStackLive: ;; arg is in eax mov ecx, 04h idiv ecx mov ebx, dword ptr [esp] movzx ecx, ax pop eax ClearStackLiveLoop: pop eax loop ClearStackLiveLoop push ebx retn 0
使用:
push ebp
mov ebp, esp
mov eax, StackSize
call MakeStackLive
代码...
mov eax, StackSize
call ClearStackLive
ret
另外对于类似push ebp 这样的指令也可以进行替换,发挥一下想象3.push ebp 可以用什么指令进行替换push eax; mov eax, ebp; mov [esp], eax 同样也是将ebp写入到堆栈中。至于其他的指令替换。大家自己想吧。如果做的有规范点就是构建自己的一套标准。包括找寻局部变量与获取参数。
分段解密反dump:
dump有两个思路一个就是分段的解密。大体的思路和反反汇编的原理一样,不同的是它的算子多了。也是分段的进行加解密的。其实,如果思路再灵活点,在这方面可以准备多一些的加解密算法随机的填写和应用。
另一个是,当每次执行完后,就再次将此函数或者功能块进行加密。在使用时解密。并且准备几个这样的加解密函数。通过这样看似很笨拙的手段,可以很有效的防止实时的dump。
改变执行流程指令:
很多壳代码都有这样的功能,实时的改变代码运行流程。例如将jz变成jnz
lea edi, JmpLabel ;; 将jz变为jnz则跳转 inc byte ptr [edi] test eax, eax JmpLable: jz Label1 代码... Label1
我们不妨思路再宽阔一些。单个指令流程能进行改变。那么代码块的位置也能进行替换。当然如果要保证代码可以正常运行,在编写代码的时候要经过精心设计后的。尽量使用局部变量,跳转不要使用长跳。跳出当前代码段,这样可以使你不用去编写重定位代码。也更容易实现些。
例如:
;; 使用串指令进行传输, 如果你觉的这样太容易被人看出来,就用相同的复杂的指令进行替 ;; 换。尽量使用麻烦的代码,插入花指令也可以。 lea edi, Func1 lea esi, Func2 mov ecx, Func2Size cld rep movsb 代码... jmp Func1 代码... Func1: ... Func2: ...
利用异常处理:
WINDWOS提供了一套很完善的异常保护机制。至今我还没看到IDA有可以分析这东西的功能。呵呵关键是语法分析集合太庞大了,只限于人们的想象。估计IDA的设计师们没办法才放弃的。
让我们看一段在破解中常遇到的异常代码。由于专题后门有专门讲解WIN异常处理的,所以这里暂且不去讨论异常处理的原理了。
;; 安装异常处理 assume fs : nothing push offset ExpHandle push fs:[0] mov fs:[0],esp xor ecx, ecx ;; 造成内存访问错误 push dword ptr [ecx] 这里代码将不会执行... ExpHandle: 异常处理代码... ;; 卸载异常处理 pop fs:[0] add esp, 04h
最后的话:
这节没有给出完整的代码,个人认为没有太大的必要。反静态反汇编。其实就是和反汇编软件的词法分析系统做对抗。用数学语言描绘就是,保证集合A(反汇编的分析关键字集合)与集合B(我们编写代码的特征)互为补集。还有觉的没有必要的地方就是,这种东西全靠思路。希望这篇文章对正在学习与之相关的朋友有些启发,我的建议是,看过就看了。忘记此文在上面给出的代码。自己去想。这些和系统底层的知识联系不大,都是最基本的编码过程。只要花些心思就能写的出。你在编写程序的时候难受一些,不方便一些。破解者就会付出比你更加多的精力和时间去破解你的程序。
...