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

--------------[  Infection Win32 : Part 1  ]
--------------[  Premiers pas dans la programmation Windows en asm  ]
---------[ janvier 2001 ]
----[  by Doxtor L. <>  ]


-------[  Introduction et Sommaire


    Cet article est le premier article d'une serie qui se propose de traiter les bases ncessaires  la comprhension et la ralisation de programmes auto-reproducteurs fonctionnant dans un environnement Windows 32 bits comme windows98.  

    Dans ce qui suit vous trouverez quelques informations qui peuvent vous aider  dbuter dans la programmation de Windows en assembleur.

    Matriel ncessaire:

Les programmes et fichiers suivants sont indispensables:
  - Tasm32.exe version 5.0    De chez inprise/borland
  - Tlink32.exe            
  - Import32.lib
     
Ce qui suit n'est pas ncessaire, mais conseill:
  -Un dbuggeur peut s'avrer trs utile, je vous conseille td32 pour dbuter, mme si celui-ci s'avre tre rapidement insuffisant  l'usage. Si vous dcidez d'approfondir le sujet, optez pour softice.
  -Une liste documente des APIs (voir plus loin pour la signification de ce sigle) standard utilises par Windows. En gnral fournit avec tous les compilateurs (Vc++,c++ de Borland,..) qui produisent du code excutable sous Windows.


Voila ce que vous trouverez dans cet article: 
    1)  Comment batir un fichier excutable  partir d'un listing contenant du code source en assembleur.
    2)  Premier programme en assembleur.
    3)  Deuxime exemple : afficher une fentre.
    4)  Troisime exemple : afficher en hexadcimal (conversion dcimale-Hexa)
    5)  Conclusion
    Annexe : Exemple de fichier .bat pour automatiser le processus de compilation.



-------[  1) Comment batir un fichier excutable  partir d'un listing

    Pour batir un programme, c'est  dire en ce qui nous concerne un fichier avec l'extension ".exe", a partir d'un fichier contenant des instructions crits en assembleur (celui-ci a l' extension ".asm"). Il faut procder en deux tapes :

    On utilise tasm32.exe en premier, cela va nous batir un fichier dont l'extension est ".obj". Puis on utilise tlink32.exe pour obtenir notre fichier excutable. Si vous voulez batir un programme appel monprog.exe  partir du fichier source monprog.asm, qui contient des instructions en langage assembleur, vous pouvez procdez comme suit :

    Vous mettez  tasm32.exe, tlink32.exe, import32.lib dans le mme rpertoire que votre fichier monprog.asm  compiler. Pour dbuter le plus simple est de tout faire dans une session Msdos que vous avez ouvert apres le chargement de Windows. Pour ceux qui savent ce qu'est le path, mettez les fichiers necessaires  la cration du programme dans un rpertoire qui est dans le path.

    Sur la ligne de commande dos, tapez :

tasm32.exe /m /ml monprog.asm

    Vous allez obtenir, si le listing ne contient pas d'erreurs un fichier appel monprog.obj.

    /m et /ml sont des options de compilations.
    * /m : signifie une passe, parfois il sera ncessaire de remplacer par /m2 ou /m3. Une passe signifie que tasm32 compile tout en une seule fois. En gnral l'option /m est suffisante.
    * /ml : signifie que les majuscules et minuscules sont considres comme diffrentes par tasm32. Cela veut dire par exemple que les chanes de caractres "MICROSOFT" et "mIcrOsofT" ne seront pas considrs comme identiques par tasm32.


    Si tasm32 trouve une erreur il l'indique, en prcisant la ligne o a t trouv l'erreur. En cas d'erreur le fichier monprog.obj ne sera pas cr bien sr. Il vous faut corriger l'erreur et recommencer cette tape.

    Une fois le fichier monprog.obj  cr il faut taper la ligne de commande:

tlink32.exe /Tpe /aa /c monprog,monprog.exe,,import32.lib

    Ce qui prcde doit tre tap tel quel c'est  dire, en respectant exactement les majuscules et minuscules pour les options.

    Les options utilises:
    * /Tpe : indique que ce qui va tre construit est un fichier ".exe".
    * /aa : indique que l'on va utiliser les ressources mises  disposition du programmeur par Windows 9x.
    * /c : indique que l'on tient compte de la diffrence entre minuscules et majuscules.
    * monprog,monprog.exe : indique qu' partir du fichier monprog.obj, on va batir le programme monprog.exe.
    * ,,import32.lib : est le fichier o tlink32 prend connaissance des ressources mises  disposition par Windows. Ce fichier est indispensable pour nos applications.


-------[  2) Premier programme en assembleur


    Voici le listing d'un programme crit en assembleur, c'est un programme trs simple puisqu'il ne fait rien!

--- DO_NOTHING.ASM ------------------------------------------------------------

.386p               
.model flat         


.data              

db 0              

.code

    extrn ExitProcess:Proc  


DEBUT:

    push 0
    call ExitProcess

end DEBUT


--- DO_NOTHING.ASM ------------------------------------------------------------


    Si vous recopiez ce listing dans un fichier monprog.asm, la compilation du  programme, en suivant la mthode indiquee, va crer un fichier monprog.exe dont la taille est de 4096 octets.

    Commentaires sur le listing:

    .386p

    indique que les instructions utilises appartiennent au jeu fournit par le processeur 80386 de Intel. Ces instructions sont bien sur excutables sur n'importe quel processeur de type pentium ou clone/compatible le p indique que le programme fonctionne en mode protg. Tous les programmes conus exclusivement pour Windows fonctionnent de cette faon.

    .model flat

    indique le modle mmoire utilis. Pour un programme Windows, la mmoire est un bloc qui peut faire jusqu' 4 GiGa octets en thorie, chaque octet a une adresse. Une adresse mmoire est un groupe de 4 octets appel aussi double mot (DWORD). Chaque programme a son propre espace mmoire, deux programmes ne partagent pas le mme espace de travail. Pour avoir une idee approximative de la faon dont marche les choses, ouvrez deux sessions Msdos sous Windows simultanment, dmarrer un programme Msdos dans l'une des fnetres, vous pourriez vrifier que dans l'autre session le programme n'est pas dans la mmoire utilise par cette copie de Msdos! Les deux sessions Msdos s'ignorent superbement!

    .data

    est la zone du listing ou vous devez declarer les variables qui seront initialiss pendant le droulement du programme. tasm32 ne permet pas de laisser cette partie vide. Le "db 0" est l pour eviter ca. Cela signifie que la zone des donnes contient un octet initialis  0.

    .code
    
    est la zone du listing qui contient le code du programme proprement dit. Si vous dclarez une variable dans cette partie et que celle ci est initialise au cours de l'excution du programme, vous allez obtenir une superbe erreur lorsque Windows va excuter votre code. Ce problme doit tre surmonter pour qu'un excutable puisse greffer son code dans un autre. Dans certaines conditions on peut rsoudre ce problme. On aurra l'occasion d'y revenir dans un prochain article.

    extrn ExitProcess:Proc
    
    signifie que l'on va importer un sous-programme externe  notre listing qui est appel aussi API (Application Programming Interface) dans notre programme. La grande force de Windows est lie a la notion l'importer-exporter des fonctions. Pour viter qu'un fichier excutable contienne tout le code qui est rellement ncessaire pour son bon fonctionnement, un fichier excutable IMPORTE des fonctions d'autres modules de Windows qui sont en gnral des fichiers .dll. Ce sont des librairies de fonctions qui sont EXPORTEES  l'attention d'autres modules de Windows, un module tant un fichier qui contient du code. L'IMPORTATION de ces fonctions se fait DYNAMIQUEMENT. Cela veut dire que les modules qui EXPORTENT des APIs ne sont pas tous prsents en mmoire  un moment donn. Une dll est charge en mmoire lorsqu'un module qui est dja en mmoire a besoin d'une fonction qu'elle EXPORTE. Certaines .dll, comme kernel32.dll, EXPORTE des APIs qui sont trs souvent utilises, elles rsident en permanence en mmoire. Chaque dll regroupe des fonctions ddies  une tche. Windows met a notre disposition des centaines d'API pour nous aider  dvelopper des programmes. ExitProcess est le nom d'une de ces APIs. Remarquez bien la faon dont son nom est crit, car ne l'oubliez pas les minuscules sont diffrentes des majuscules. Si vous crivez exitprocess,  la place, dans le listing tasm32 et tlink32 seront incapables de crer le programme attendu. N'ommtez pas non plus ":Proc", sinon vous allez voir apparatre l'cran bleu d'erreur de Windows  l'excution du programme fraichement compil. Comme dja indiqu, le fichier import32.lib est ncessaire pour que
l'importation de l'API se fasse dans notre programme. ExitProcess sert  revenir  Windows c'est  dire  quitter
le programme qui appelle cet API. Notez bien la facon de faire l'appel:

    push  0
    call ExitProcess

    Le "push 0" sert  passer un paramtre  l'API ExitProcess 0 est considr comme un double mot ici. "push 0" met la valeur 00 00 00 00 sur la pile. La pile est un endroit que Windows met a notre disposition dans le mmoire pour sauvegarder des valeurs. Cette pile est comme une pile d'assiettes entasses les unes sur les autres. Pour pouvoir rcuprer l'assiette qui est tout en bas de la pile, on doit enlever une par une les assiettes du dessus. L'instruction "push" permet de mettre sur le sommet de la pile un nouvel lment. Ne chercher pas de label "ExitProcess:" dans le listing il n'y en a pas, pour appeler un API, on utilise la syntaxe: "call Nom_De_L'api". Les paramtres utiliss par l'API sont passs  Windows dans un ordre convenu par l'intermdiaire de la pile. Pour connaitre la liste des API , leur noms, les paramtres ncessaires  leur bonne excution et l'ordre dans lequel ceux ci doivent tre mis sur la pile, il vous faut une liste de rfrence.

    Le label "DEBUT:" et "end DEBUT" indiquent que votre code se trouve entre ces deux balises.

    Pour commencer  programmer, ce listing est un bon modle qui s'avre tres utile pour crire un programme. Vous pouvez le rutiliser pour crire vos propres applications.


-------[  3) Deuxime exemple : afficher une fentre


--- WINDOW.ASM ----------------------------------------------------------------

.386p

.model flat


.data

Titre      db "mon programme",0             ;titre de la fentre
Message    db "Chouette une fentre!",0     ;message  afficher


.code

    extrn MessageBoxA: Proc
    extrn ExitProcess: Proc


DEBUT:
 
    push 0                                  ;style de la fentre
    push offset Titre 
    push offset Message
    push 0

    call MessageBoxA                        ;crer la fentre

    push 0                                  ;sortie du programme
    call ExitProcess

end DEBUT

--- WINDOW.ASM ----------------------------------------------------------------


    Commentaires sur le listing:

    Si vous voulez ajouter des commentaires dans un listing utiliser le symbole ";" ce qui suit est ignor par tasm32.
    Dans ce programme nous utilisons une API de plus, MessageBoxA. Cette API a besoin de quatre paramtres qui sont tous des doubles mots c'est  dire compos de 4 octets chacun.
    * Le premier paramtre  passer est le "style", il indique de quel type sera la fentre  afficher et quelle icne sera utilise parmi la liste des icones fournies par Windows. Ici, on a choisit une fentre simple, pas d'icne affiche.
    * Le deuxieme paramtre est un pointeur vers le dbut de la chane de caractres qui compose le titre de la fentre. Remarquez que les chanes de caractres se terminent par l'octet 0, pour pouvoir tre affiches. Le 0 indique la fin de la chane de caractres. Les " " sont indispensables, elles indiquent  tasm32 que ce qui est plac entre est du texte. Noter bien que c'est l'instruction "push offset Titre" qui est utilis et pas "push [Titre]". C'est un pointeur vers le dbut d'une chaine de caractres que requiert l'API, MessageBoxA et pas le contenu des 4 premiers octets de cette chaine!
    * Troisieme paramtre, c'est un pointeur vers la chaine de caractres qui contient le message  afficher.
    * Le quatrieme paramtre est un handle qui indique quelle application est propritaire de cette fentre, 0 = aucun propritaire. Un handle est en gnral un double mot, utilis par Windows pour son bon fonctionnement. Windows attribue des handles pour tout.
 

-------[  4) Troisime exemple : affichage hexadcimal.

    On veut crire un programme capable de visualiser dans une fentre  le contenu du registre eax, en hexadcimal. Que signifie hexadcimal? Il existe plusieurs systmes de numration possible pour compter. Le plus utilis est le systme dcimal. Il est dit dcimal car nous utilisons dix symboles pour crire un nombre dans ce systme : 0,1,2,3,4,5,6,7,8,9
    Lorsque nous lisons 156 en fait nous avons  l'esprit que:

                 1 x  100
               + 5 x   10
               + 6 x    1
               ----------
               =      156

    Les chiffres 1,5,6 ont t utiliss pour crire ce nombre. Tout ceci semble un peu stupide de faire cela mais lisez ce qui suit.
    
    En base 16, nous avons 16 symboles pour crire un nombre : 0,1,2,3,4,5,6,7,8,9,A,B,C,E,F
    Le nombre qui s'crit AB en base 16 a bien sur une criture en base 10. On veut faire cette conversion. Le tableau de conversion suivant est utile :

    hexadcimal       0  1  2  3  4  5  6  7  8  9   A   B   C   D   E   F      
    dcimal           0  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15 

    A correspond  10 , multipli par 16 = 160
    B correspond  11 , multipli par  1 =  11
                                         -----                               
                                  total  = 171
     
    171 est l'criture dcimale de AB

    Pour convertir le nombre hexadecimal 17DE on fait de mme:

 
    1 correspond  1  , multipli par 16*16*16  =  4096
    7 correspond  7  , multipli par 16*16     =  1792
    D correspond  12 , multipli par 16        =   192
    E correspond  14 , multipli par 1         =    14
                                                -------
                                      total     =  6094



    Pour distinguer l'criture d' un nombre crit en hexadcimal, de celle d'un nombre crit en dcimal on ajoute un h  ce nombre: ABh, 17DEh. C'est la faon retenue ,par dfaut par tasm pour distinguer l'criture des nombres. Par dfaut si "156" non suivi d'un "h" apparait dans un listing contenant des instructions en assembleur, tasm va supposer que 156 est l'criture dcimale d'un nombre. Notez bien que 156h ,nombre crit en hexadcimal, ne s'crit pas 156 en notation dcimale.

    En effet,  1   x  256 = 256
               5   x   16 =  80
               6   x    1 =   6
                          -----
                   total  = 342

    342 est l'criture dcimale de 156h

    Pour pouvoir crire notre programme nous avons besoin de lire un nombre crit en hexadcimal c'est a dire d'tre capable de savoir quels chiffres hexadcimaux (0,1,..9,a,...,f) le composent. En dcimal pour lire le nombre 123 on fait comme suit :
    On divise 123 par 10 le quotient fait 12 le reste 3, 3 est le chiffre le plus  droite.
    On divise  12 par 10 le quotient fait  1 le reste 2, 2 est le chiffre suivant prcdant.
    On divise   1 par 10 le quotient fait 0  le reste 1, 1 est le chiffre le plus a gauche.

    Tout ceci semble stupide, une fois de plus, mais lisez la suite. En base 16 il faut juste remplacer la division par 10 par une division par 16 les restes successifs sont les chiffres en base 16 qui composent le nombre. Voici une manire de programmer ceci :


      mov eax,342  ;342 est le nombre qu'on veut voir afficher en hexadcimal
      mov ecx,10h  ;on met 16 dans le registre ecx               

      Chiffre:

      xor edx,edx  ;on met  zro  le registre edx
      div ecx      ;on divise edx:eax par ecx
                   ;le reste est dans edx, le quotient dans eax
                   ;le reste contient le chiffre Hexadcimal 
      or eax,eax   ;est ce que le quotient est nul? 
      jnz Chiffre  ;il n'est pas nul ,il y'a encore des chiffres
                   
 
    Les valeurs successives de edx : 6,5,1 sont les chiffres utiliss pour crire 342 en hexadcimal. 342 a 156h pour criture hexadcimale.
    Nous avons crit dans le paragraphe III) un programme qui crait une fentre. Le titre de la fentre tait: "mon programme". Je vous ai indiqu alors de ne pas oublier les guillemets. Les symboles:  m,o,n,p,r,a,m,e que nous utilisons, nous autres francais, pour orthographier les mots "mon" et "programme" ne veulent rien dire pour le microprocesseur de votre machine. Celui-ci ne sait lire que des valeurs hexadcimales. En fait, tasm32 traduit la chaine de caractre: "mon programme" en :

    6dh,6fh,6eh,20h,70hh,72h,6fh,67h,72h,61h,6dh,6dh,65h

    20h est utilis pour traduire l'espace entre les deux mots. En fait, toutes les lettres et les chiffres ont un code qui permet  Windows de les afficher  l'cran. Cette codification utilise les nombres 00h,01h,02h,..,ffh. C'est le code ASCII. Tous les ordinateurs quips de Windows comprennent cette codification. Nous, pour notre programme, nous avons besoin d'afficher les caractres suivants:

    0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f

    Les  valeurs ASCII correspondantes sont:

      Caractre      "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f"
      Code ASCII     30h,31h,32h,33h,34h,35h,36h,37h,38h,39h,61h,62h,63h,64h,65h,66h

    Pour pouvoir afficher les caractres "0","1",....,"9","a",..."f" qui servent  crire un nombre en hexadcimal on peut penser  faire 16 tests:

 si le chiffre est  0  alors   30h est son code ASCII
 si le chiffre est  1  alors   31h est son code ASCII
         [...]
 si le chiffre est  f  alors   66h est son code ASCII 

    Mais si vous observez bien on peut faire autrement. Plus simplement on a :
    * Pour obtenir le code ASCII d'un chiffre X Hexadcimal compris entre 0 et 9, il suffit de faire l'addition:
        X+30h
    * Pour obtenir le code ASCII d'un chiffre Y Hexadcimal compris entre a et f, il suffit de faire :
        Y+61h-0ah
    Pour Y=0ah on obtient bien: 0ah+61h-0ah=61h           

    L'algorithme pour calculer le code ASCII d'un chiffre Hexadcimal est simple :
 soit Hexa ce chiffre
 si Hexa>=0Ah  faire CodeASCII=Hexa+61h-0ah
 sinon         faire CodeASCII=Hexa+30h

    Le programme qui suit n'est pas indispensable pour la comprhension des mthodes d'infection sous Win32. Nammoins, la comprhension du systme d'criture binaire et surtout hexadcimal est ncessaire pour programmer en assembleur.

    Ce qui suit est un exemple de programme un peu plus labor que ceux dja rencontrs. On peut crire un programme, plus court, accomplissant la mme tche, en utilisant une API supplmentaire, mais le code source ncessaire est sans grande utilit pour notre sujet.

    Voici le programme promis :


--- HEXAVIEW.ASM --------------------------------------------------------------


.386p
.model flat

.data

db 0                            ; cet octet a une fonction qui se justifie dans ce qui suit
HEX_Message db 0,0,0,0,0,0,0    ;
FIN_Message db 0                ;
            db 0                ;

.code                           ;

    extrn ExitProcess:Proc      ;
    extrn MessageBoxA:Proc      ;


DEBUT:                          ;

; Ce programme affiche le contenu de eax en notation Hexadcimale


    lea esi,FIN_Message         ; esi contient un pointeur vers le dernier caractre
                                ; de la chaine qui va contenir la reprsentation
                                ; en code ASCII du nombre  afficher en Hexadcimal.
    mov eax,14789               ; valeur dont on veut connaitre l'criture hexadcimale.
    inc esi                     ; ajouter 1  la valeur dans esi
    mov ecx,10h                 ; mettre 16 dans ecx


HEX_chiffre:                    ;

    dec esi                     ; soustraire 1  la valeur dans esi
    xor edx,edx                 ; mettre  zero edx 
    div ecx                     ; division de edx:eax par ecx
                                ; le quotient est dans eax
                                ; le reste dans edx, edx contient la valeur du 
                                ; nombre hexa: 0  F
 
    cmp eax,0Ah                 ; la valeur dans eax est gale ou plus grande que
    jge Lettre                  ; 10? si oui aller au label Lettre 


    add edx,30h                 ; le chiffre est compris entre 0 et 9 
    mov byte ptr [esi],dl       ; la chaine de caractre est compltee avec le code
                                ; ASCII du chiffre Hexa lu
    or eax,eax                  ; eax est nul?
    jnz HEX_chiffre             ; non? il reste des chiffres  lire
                      

Lettre:

    add edx,61h-0Ah             ; le chiffre lu est compris entre A et F
    mov byte ptr [esi],dl       ;
    or eax,eax                  ;
    jnz HEX_chiffre             ;
       
 
; Afficher le rsultat


    push 0                      ;
    push offset Titre           ;
    push offset Hex_Message     ;
    push 0                      ;
    call MessageBoxA            ;

; Exit

    push 0                      ;
    call ExitProcess            ;
      
end DEBUT
    

--- HEXAVIEW.ASM --------------------------------------------------------------


-------[  5) Conclusion


    J'espre que tout ceci vous aidera dans vos premiers pas dans la programmation de Windows en assembleur. L'article qui devrait suivre celui-ci traitera de la faon de manipuler des fichiers sous Windows (lecture, criture) en assembleur videmment!

    A bientot.


-------[  Annexe:


    Pour commencer  programmer en assembleur sous Windows9x vous avez besoin des programmes cits et de deux fichiers supplmentaires qui vont vous faciliter la tche. Un modle de listing, dans lequel vous allez ajouter vos propres instructions pour crire vos programme ; un fichier bat qui va vous viter de resaisir  chaque fois les options de compilation pour compiler votre code source.
    Voici un fichier bat possible : copier ce qui suit dans un fichier que vous appellerez compile.bat

--- COMPILE.BAT ---------------------------------------------------------------

   tasm32  /m /ml %1.asm
   tlink32 /Tpe /aa /c %1,%.exe,,import32.lib
   del %.obj
   del %.map 

--- COMPILE.BAT ---------------------------------------------------------------


    Commentaires:

    Vous devez avoir tasm32.exe, tlink32.exe, import32.lib et votre listing dans le mme rpertoire (ou dans le mme sous-rpertoire). Il faut taper :

        compile.bat monprog

    Si vous voulez compiler un listing qui s'appelle monprog.asm et non pas :

        compile.bat monprog.asm


-------[  EOF
