【保護你的程式碼】
~~~~~~~~~~~~~~
這個話題在業界是一個很熱門的話題。許多病毒編寫者保護它們的程式碼是為了使病毒查殺工具更困難。當然,我們我們還要討論反除錯的方法。有許多眾所周知的技術...但是,在這裡能看到是一件很好的事情...你說呢?
關於這個,有很多可能的方法。它們許多都是可配置的。你也可以利用傳統的方法。我認為應該至少要放一個例程到你的多型引擎中(在長-例程表裡,如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?