document.write('
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. /*
  2.  *    Segunda iteración del programa que se mide a sí mismo.
  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 <stdint.h>
  21.  
  22. /* He utilizado el mismo marcador en ambos, la cadena "KPAX". KPAX es una
  23.    cadena más o menos segura y es realmente complicada encontrarla por ca-
  24.    sualidad en un binario (se puede hacer la prueba con un simple grep KPAX
  25.    en todos los ficheros de /bin, /usr/bin, y /usr/lib, no hay una sola
  26.    coincidencia) */
  27.    
  28. #define BOTTOM_MARKER_LOW  0x504b
  29. #define BOTTOM_MARKER_HIGH 0x5841
  30. #define TOP_MARKER_LOW     BOTTOM_MARKER_LOW
  31. #define TOP_MARKER_HIGH    BOTTOM_MARKER_HIGH
  32.  
  33. #define BOTTOM_MARKER      0x5841504b
  34. #define TOP_MARKER         BOTTOM_MARKER
  35.  
  36. /* Pequeño hack del preprocesador de C para convertir palabras a cadenas */
  37. /* Cuando hagamos algo como STRINGIFY(palabra), el preprocesador nos lo
  38.    sustituirá por la cadena "palabra" */
  39.    
  40. #define _STRINGIFY(x) #x
  41. #define STRINGIFY(x) _STRINGIFY (x)
  42.  
  43. /* El flag "x" le indica a GCC que la sección debe ser código ejecutable y
  44.    el flag "a" le obliga a que la sección se cargue en memoria */
  45.    
  46. asm (".section .code_bottom, \\"xa\\"");
  47. asm (".long " STRINGIFY (BOTTOM_MARKER));
  48.  
  49. asm (".section .code_top, \\"xa\\"");
  50. asm (".long " STRINGIFY (TOP_MARKER));
  51.  
  52.  
  53. /* Nuestra implementación de write, haciendo la llamada al sistema
  54.    correspondiente. Nótese que tenemos que salvar el %ebx en %esi
  55.    y luego recuperarlo. Esto es culpa del direccionamiento relativo
  56.    al %eip utilizando %ebx como registro puente. */
  57. int
  58. write (int fd, const void *buf, int size)
  59. {
  60.   int ret;
  61.  
  62.   asm volatile ("xchg %%ebx, %%esi\\n"
  63.                  "int $0x80\\n"
  64.                  "xchg %%ebx, %%esi\\n" : "=a" (ret) :
  65.     "a" (__NR_write), "S" (fd), "c" (buf), "d" (size));
  66.    
  67.   return ret;
  68. }
  69.  
  70. /* long2hex: convierte un número en hexadecimal, no tiene más cosa. Será
  71.    muy útil para depurar. */
  72. void
  73. long2hex (unsigned int number, char *buf)
  74. {
  75.   int i;
  76.   char hexa[] = "0123456789abcdef";
  77.  
  78.   buf[8] = 0;
  79.  
  80.   for (i = 0; i < 8; i++)
  81.   {
  82.     buf[7 - i] = hexa[number & 0xf];
  83.     number >>= 4;
  84.   }
  85. }
  86.  
  87. /* Esto lo utilizaré para buscar los marcadores del código. Saco la dirección
  88.    del %eip mediante un call (ya que no podemos calcular las direcciones de
  89.    nuestras funciones sin acceder a la GOT) y a partir de ahí doy saltos
  90.    hacia arriba o hacia abajo hasta encontrarlos */
  91.    
  92. void
  93. get_code_limits (uint32_t *bottom, uint32_t *top)
  94. {
  95.   int i;
  96.   uint32_t this_addr;
  97.  
  98.   /* Voy a hacer un call cortito, sólo para que meta en la pila la dirección
  99.      de código en la que me hallo. El popl %0 saca la dirección de retorno
  100.      que metí con call y ¡zasca! tengo el %eip en this_addr. Gracias,
  101.      inline assembly de GCC */
  102.      
  103.   /* call 1f quiere decir "call 1 forward", es decir, saltar hacia la etiqueta
  104.      que llamé 1 y que está hacia adelante. Esto de utilizar números para
  105.      etiquetas se suele hacer mucho cuando la etiqueta hace referencia
  106.      a un cacho de código que no está especialmente diferenciado del resto. */
  107.      
  108.   asm volatile ("call 1f\\n"
  109.                  "1:\\n"
  110.                  "popl %0\\n" : "=g" (this_addr));
  111.                  
  112.  
  113.   /* Alineamos a 4 bytes. Esto lo hacemos poniendo los dos
  114.      últimos bits a cero. */
  115.      
  116.   this_addr &= ~3; /* this_addr = this_addr & ~3 equivale a
  117.                       this_addr = this_addr & 0xfffffffc que es un and
  118.                       en binario con todo 1 menos los dos últimos bits,
  119.                       esto fuerza a que el número esté alineado a 4. */
  120.  
  121.  
  122.   /* Búsqueda del marcador inferior. Como hemos forzado al enlazador a que
  123.      nos alinee los marcadores a 4 bytes, podemos alinear también nuestra
  124.      dirección de inicio y saltar de 4 en 4 para encontrarlo antes.
  125.      
  126.      El marcador está hacia "atrás", o sea que recorreremos la memoria
  127.      restando. */
  128.      
  129.   for (i = this_addr; ; i -= 4)
  130.   {
  131.     if (*(uint16_t *) i == BOTTOM_MARKER_LOW) /* Primero la parte alta */
  132.       if (*(uint16_t *) (i + 2) == BOTTOM_MARKER_HIGH) /* Y luego la baja */
  133.       {
  134.         *bottom = i;
  135.         break;
  136.       }
  137.   }
  138.  
  139.   /* Búsqueda del marcador superior, ahora tenemos que dar saltos en
  140.      nuestra memoria hacia adelante, sumando. */
  141.   for (i = this_addr; ; i += 4)
  142.   {
  143.     if (*(uint16_t *) i == TOP_MARKER_LOW)
  144.       if (*(uint16_t *) (i + 2) == TOP_MARKER_HIGH)
  145.       {
  146.         *top = i + 4; /* Le sumo cuatro porque el marcador superior (que mide
  147.                          4 bytes) también pertenece al código. */
  148.         break;
  149.       }
  150.   }
  151.  
  152. }
  153.  
  154. /* Punto de entrada, como el main () pero en cutre y sin ayudas de ningún tipo */
  155. void
  156. _start (void)
  157. {
  158.   char buffer[9];
  159.   uint32_t limit_bottom;
  160.   uint32_t limit_top;
  161.  
  162.   get_code_limits (&limit_bottom, &limit_top);
  163.  
  164.   /* Límite inferior */
  165.   long2hex (limit_bottom, buffer);
  166.   buffer[8] = 10;
  167.   write (1, buffer, 9);
  168.  
  169.   /* Límite superior */
  170.   long2hex (limit_top, buffer);
  171.   buffer[8] = 10;
  172.   write (1, buffer, 9);
  173.  
  174.   /* Tamaño del código */
  175.   long2hex (limit_top - limit_bottom, buffer);
  176.   buffer[8] = 10;
  177.   write (1, buffer, 9);
  178.  
  179.  
  180.  
  181.   for (;;);
  182. }
');