Advertisement
FlyFar

skesi_virus (disinfector)

Jun 18th, 2023
978
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.98 KB | Cybersecurity | 0 0
  1. /*
  2.  * Skeksi Virus disinfector, by ElfMaster. January 2016
  3.  *
  4.  * -= About:
  5.  * This disinfector is the first prototype, it is written for those who may have been so unfortunate
  6.  * as to infect their own system. The disinfector will work any infected ET_EXEC file, provided that
  7.  * it has section headers. This is somewhat of a weakness considering the Virus itself works on executables
  8.  * that have no section headers. If you need to change this, its pretty easy, just parse the program
  9.  * headers and get PT_DYNAMIC, and then use the D_TAG's to find the PLT/GOT, Relocation, and dynamic
  10.  * symbol table.
  11.  *
  12.  * -= Usage:
  13.  * gcc -O2 skeksi_disinfect.c -o disinfect
  14.  * ./disinfect <executable>
  15.  
  16.  * elfmaster [4t] zoho.com
  17.  */
  18.  
  19. #include <stdarg.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <stdio.h>
  24. #include <unistd.h>
  25. #include <sys/types.h>
  26. #include <fcntl.h>
  27. #include <dirent.h>
  28. #include <sys/mman.h>
  29. #include <sys/stat.h>
  30. #include <elf.h>
  31. #include <errno.h>
  32.  
  33. typedef struct elfdesc {
  34.     Elf64_Ehdr *ehdr;
  35.     Elf64_Phdr *phdr;
  36.     Elf64_Shdr *shdr;
  37.     Elf64_Addr textVaddr;
  38.     Elf64_Addr dataVaddr;
  39.     Elf64_Addr dataOff;
  40.     size_t textSize;
  41.     size_t dataSize;
  42.     uint8_t *mem;
  43.     struct stat st;
  44.     char *path;
  45. } elfdesc_t;
  46.  
  47. #define TMP ".disinfect_file.xyz"
  48.  
  49. /*
  50.  * If we find push/ret, and the address
  51.  * being pushed is within the text segment
  52.  * of the regular x86_64 text range per the
  53.  * default linker script, then we are probably
  54.  * in good shape.
  55.  * note: 0x400000 is the default text base
  56.  */
  57. uint32_t locate_orig_entry(elfdesc_t *elf)
  58. {
  59.     uint32_t i, entry;
  60.         uint8_t *mem = elf->mem;
  61.         for (i = 0; i < elf->st.st_size; i++) {
  62.                 if (mem[0] == 0x68 && mem[5] == 0xc3) {
  63.             entry = *(uint32_t *)&mem[1];
  64.             if (entry >= 0x400000 && entry < 0x4fffff)
  65.                 return entry;
  66.         }
  67.     }
  68.     return 0; // couldn't find it, uh oh!
  69. }  
  70.  
  71. uint32_t locate_glibc_init_offset(elfdesc_t *elf)
  72. {
  73.     uint32_t i;
  74.     uint8_t *mem = elf->mem;
  75.    
  76.     for (i = 0; i < elf->st.st_size; i++) {
  77.         if (
  78.         mem[i + 0] == 0x31 && mem[i + 1] == 0xed &&
  79.         mem[i + 2] == 0x49 && mem[i + 3] == 0x89 &&
  80.         mem[i + 4] == 0xd1 && mem[i + 5] == 0x5e &&
  81.         mem[i + 6] == 0x48 && mem[i + 7] == 0x89 && mem[i + 8] == 0xe2)
  82.             return i;
  83.     }
  84.  
  85.     return 0;
  86. }
  87.    
  88. int disinfect_pltgot(elfdesc_t *elf)
  89. {
  90.     Elf64_Ehdr *ehdr = elf->ehdr;
  91.     Elf64_Phdr *phdr = elf->phdr;
  92.     Elf64_Shdr *shdr = elf->shdr;
  93.     uint8_t *mem = elf->mem;
  94.     Elf64_Sym *symtab = NULL;
  95.     Elf64_Rela *rela = NULL;
  96.     Elf64_Addr addr = 0, plt_addr = 0;
  97.     Elf64_Off plt_off = 0, gotoff = 0;
  98.     size_t plt_size = 0, symtab_size = 0, rela_size = 0;
  99.     char *shstrtab = (char *)&mem[shdr[elf->ehdr->e_shstrndx].sh_offset];
  100.     char *strtab = NULL;
  101.     uint8_t *gotptr, *plt;
  102.     int i, j, symindex = 0, c = 0;
  103.  
  104.     for (i = 0; i < ehdr->e_shnum; i++) {
  105.         switch(shdr[i].sh_type) {
  106.             case SHT_DYNSYM:
  107.                 symtab = (Elf64_Sym *)&mem[shdr[i].sh_offset];
  108.                 symtab_size = shdr[i].sh_size;
  109.                 strtab = (char *)&mem[shdr[shdr[i].sh_link].sh_offset];
  110.                 break;
  111.             case SHT_RELA:
  112.                 if (!strcmp(&shstrtab[shdr[i].sh_name], ".rela.plt")) {
  113.                     rela = (Elf64_Rela *)&mem[shdr[i].sh_offset];
  114.                     rela_size = shdr[i].sh_size;
  115.                 }
  116.                 break; 
  117.             case SHT_PROGBITS:
  118.                 if (!strcmp(&shstrtab[shdr[i].sh_name], ".plt")) {
  119.                     plt_off = shdr[i].sh_offset;
  120.                     plt_addr = shdr[i].sh_addr;
  121.                     plt_size = shdr[i].sh_size;
  122.                 }
  123.                 break;
  124.         }
  125.     }
  126.     if (plt_off == 0 || symtab == NULL || rela == NULL) {
  127.         printf("Unable to find relocation/symbol/plt info\n");
  128.         return -1;
  129.     }
  130.    
  131.     plt = &mem[plt_off]; // point at PLT, right past PLT-0
  132.     for (i = 0; i < rela_size/sizeof(Elf64_Rela); i++) {
  133.        
  134.         symindex = ELF64_R_SYM(rela->r_info);
  135.         if (!strcmp(&strtab[symtab[ELF64_R_SYM(rela->r_info)].st_name], "puts")) {
  136.             printf("Attempting to disinfect PLT/GOT\n");
  137.             gotoff = elf->dataOff + (rela->r_offset - elf->dataVaddr);
  138.             gotptr = &mem[gotoff];
  139.             addr = gotptr[0] + (gotptr[1] << 8) + (gotptr[2] << 16) + (gotptr[3] << 24);
  140.             if (!(addr >= plt_addr && addr < plt_addr + plt_size)) {
  141.                 for (c = 0, j = 0; j < plt_size; j += 16, c++) {
  142.                     if (c == symindex) {
  143.                         printf("Successfully disinfected PLT/GOT table\n");
  144.                         *(uint32_t *)gotptr = plt_addr + j + 6;
  145.                         return 0;
  146.                     }  
  147.                 }  
  148.  
  149.             }
  150.             printf("Failed to disinfect PLT/GOT table\n");
  151.             return -1;
  152.         }
  153.     }
  154.    
  155.     return 0;
  156. }
  157.  
  158. /*
  159.  * Expected x86_64 base is 0x400000 in Linux. We rely on that
  160.  * here, which may end up being a bit wobbly.
  161.  */
  162. int disinfect(elfdesc_t *elf)
  163. {
  164.     size_t paddingSize;
  165.     Elf64_Phdr *phdr = elf->phdr;
  166.     Elf64_Shdr *shdr = elf->shdr;
  167.     uint32_t text_offset = 0;
  168.     char *strtab = NULL;
  169.     uint8_t *mem = elf->mem;
  170.     int i, textfound, fd;
  171.     ssize_t c, last_chunk;
  172.     if (elf->textVaddr >= 0x400000) {
  173.         printf("unexpected text segment address, this file may not actually be infected\n");
  174.         return -1;
  175.     }
  176.  
  177.     paddingSize = 0x400000 - elf->textVaddr;
  178.    
  179.     /*
  180.      * Remove PLT/GOT hooks if present
  181.      */
  182.     int ret = disinfect_pltgot(elf);
  183.    
  184.     /*
  185.      * Remove infection magic
  186.      */
  187.     *(uint32_t *)&elf->ehdr->e_ident[EI_PAD] = 0x00000000;
  188.  
  189.     /*
  190.      * PT_PHDR, PT_INTERP were pushed forward in the file
  191.      */
  192.     phdr[0].p_offset -= paddingSize;
  193.     phdr[1].p_offset -= paddingSize;
  194.    
  195.     /*
  196.      * Set phdr's back to normal
  197.      */
  198.     for (textfound = 0, i = 0; i < elf->ehdr->e_phnum; i++) {
  199.         if (textfound) {
  200.             phdr[i].p_offset -= paddingSize;
  201.             continue;
  202.         }
  203.         if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == 0 && phdr[i].p_flags & PF_X) {
  204.             if (phdr[i].p_paddr == phdr[i].p_vaddr) {
  205.                 phdr[i].p_vaddr += paddingSize;
  206.                 phdr[i].p_paddr += paddingSize;
  207.             } else
  208.                 phdr[i].p_vaddr += paddingSize;
  209.             /*
  210.              * reset segment size for text
  211.              */
  212.             phdr[i].p_filesz -= paddingSize;
  213.             phdr[i].p_memsz -= paddingSize;
  214.             phdr[i].p_align = 0x200000;
  215.             phdr[i + 1].p_align = 0x200000;
  216.             textfound = 1;
  217.         }
  218.     }
  219.    
  220.     text_offset = locate_glibc_init_offset(elf);
  221.  
  222.     /*
  223.      * Straighten out section headers
  224.      */
  225.     strtab = (char *)&mem[shdr[elf->ehdr->e_shstrndx].sh_offset];
  226.     for (i = 0; i < elf->ehdr->e_shnum; i++) {
  227.         /*
  228.          * We treat .text section special because it is modified to
  229.          * encase the entire parasite code. Lets change it back to
  230.          * only encasing the regular .text stuff.
  231.          */
  232.         if (!strcmp(&strtab[shdr[i].sh_name], ".text")) {
  233.             if (text_offset == 0) // leave unchanged :(
  234.                 continue;
  235.             shdr[i].sh_offset = text_offset - paddingSize;
  236.             shdr[i].sh_addr = (text_offset - paddingSize) + 0x400000;
  237.             continue;
  238.         }
  239.         shdr[i].sh_offset -= paddingSize;
  240.     }
  241.    
  242.     /*
  243.      * Set phdr and shdr table back
  244.      */
  245.     elf->ehdr->e_shoff -= paddingSize;
  246.     elf->ehdr->e_phoff -= paddingSize;
  247.            
  248.     /*
  249.      * Set original entry point
  250.      */
  251.     elf->ehdr->e_entry = 0x400000 + text_offset;
  252.         elf->ehdr->e_entry -= paddingSize;
  253.  
  254.     if ((fd = open(TMP, O_CREAT | O_TRUNC | O_WRONLY, elf->st.st_mode)) < 0)
  255.         return -1;
  256.  
  257.     if ((c = write(fd, mem, sizeof(Elf64_Ehdr))) != sizeof(Elf64_Ehdr))
  258.         return -1;
  259.  
  260.     mem += paddingSize + sizeof(Elf64_Ehdr);
  261.     last_chunk = elf->st.st_size - (paddingSize + sizeof(Elf64_Ehdr));
  262.    
  263.     if ((c = write(fd, mem, last_chunk)) != last_chunk)
  264.         return -1;
  265.  
  266.     if (fchown(fd, elf->st.st_uid, elf->st.st_gid) < 0)
  267.         return -1;
  268.  
  269.     rename(TMP, elf->path);
  270.    
  271.     return 0;
  272. }
  273.  
  274. int load_executable(const char *path, elfdesc_t *elf)
  275. {
  276.     uint8_t *mem;
  277.     Elf64_Ehdr *ehdr;
  278.     Elf64_Phdr *phdr;
  279.     Elf64_Shdr *shdr;
  280.     int fd;
  281.     struct stat st;
  282.     int i;
  283.  
  284.     if ((fd = open(path, O_RDONLY)) < 0) {
  285.         perror("open");
  286.         return -1;
  287.     }
  288.     fstat(fd, &st);
  289.    
  290.     mem = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
  291.     if (mem == MAP_FAILED) {
  292.         perror("mmap");
  293.         return -1;
  294.     }
  295.    
  296.     ehdr = (Elf64_Ehdr *)mem;
  297.     phdr = (Elf64_Phdr *)&mem[ehdr->e_phoff];
  298.     shdr = (Elf64_Shdr *)&mem[ehdr->e_shoff];
  299.    
  300.     elf->st = st;
  301.    
  302.     for (i = 0; i < ehdr->e_phnum; i++) {
  303.         switch(!!phdr[i].p_offset) {
  304.             case 0:
  305.                 elf->textVaddr = phdr[i].p_vaddr;
  306.                 elf->textSize = phdr[i].p_filesz;
  307.                 break;
  308.             case 1:
  309.                 elf->dataOff = phdr[i].p_offset;
  310.                 elf->dataVaddr = phdr[i].p_vaddr;
  311.                 elf->dataSize = phdr[i].p_filesz;
  312.                 break;
  313.         }
  314.     }
  315.     elf->mem = mem;
  316.     elf->ehdr = ehdr;
  317.     elf->phdr = phdr;
  318.     elf->shdr = shdr;
  319.     elf->path = (char *)path;
  320.     return 0;
  321.    
  322. }
  323.    
  324. int test_for_skeksi(elfdesc_t *elf)
  325. {
  326.     uint32_t magic = *(uint32_t *)&elf->ehdr->e_ident[EI_PAD];
  327.     return (magic == 0x15D25);
  328. }
  329.  
  330. int main(int argc, char **argv)
  331. {
  332.     elfdesc_t elf;
  333.  
  334.     if (argc < 2) {
  335.         printf("Usage: %s <executable>\n", argv[0]);
  336.         exit(0);
  337.     }
  338.    
  339.     if (load_executable(argv[1], &elf) < 0) {
  340.         printf("Failed to load executable: %s\n", argv[1]);
  341.         exit(-1);
  342.     }
  343.    
  344.     if (test_for_skeksi(&elf) == 0) {
  345.         printf("File: %s, is not infected with the Skeksi virus\n", argv[1]);
  346.         exit(-1);
  347.     }
  348.     printf("File: %s, is infected with the skeksi virus! Attempting to disinfect\n", argv[1]);
  349.  
  350.     if (disinfect(&elf) < 0) {
  351.         printf("Failed to disinfect file: %s\n", argv[1]);
  352.         exit(-1);
  353.     }
  354.  
  355.     printf("Successfully disinfected: %s\n", argv[1]);
  356.    
  357.    
  358. }
  359.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement