lunes, 2 de julio de 2007

Cómo escribir un bootloader

Reinier Nápoles Martínez [rnapoles@ipihlg.rimed.cu]

Estaba leyendo un articulo que publicaron en BlackHat #16 sobre quitar el password al BIOS desde Windows, pero esto sólo funciona si arrancamos desde un disco inicio de MS-DOS. Creo que desde las versiones 95, 98 y Me también funciona, pero los sistemas basados en NT como XP ya no permiten el acceso directo al hardware, ni permite el direccionamiento directo de la memoria.

¿Cómo escribir un bootloader?

char *videomem = (char *) 0xb8000; // 0xb8000 es la dirección de la RAM de video
void putc(char carattere){
  videomem++ = carattere;
// caracter a imprimir
  videomem++ = 0x7;
// atributo del char
}

Códigos como éste sólo son permitidos en Sistema Operativo (SO) como MS-DOS, que permiten el acceso a toda la memoria, puertos, etc., por lo que pueden hacer caer o dañar al sistema fácilmente. Pues Windows usa un modelo de memoria llamado Flat (o plano), donde cada proceso cree que tiene asignado 4 Gb de memoria para él solo. Un proceso no conoce la dirección de memoria de otro proceso, por lo que no puede modificarla. El único que conoce las direcciones es el kernel del SO; de este modo un programa puede caer, pero no comprometer el sistema completamente (existen casos en que un programa o una biblioteca contiene un bug y su explotación permite la elevación de privilegios al atacante, ej: buffer overflow, heap overflow).

El microprocesador posee un modo de funcionamiento llamado "protegido", existente desde el 286. Éste cuenta con cuatro niveles de privilegios enumerados desde el 0 al 3, donde el mayor privilegio lo tiene el llamado anillo 0 y el menor es el 3:

0- Núcleo del SO (Modo Supervisor)
1- Servicios del sistema
2- Aplicaciones del sistema
3- Aplicaciones del usuario (Modo Usuario)

Instrucciones en ASM, como sti, cli y hlt sólo le son permitidas al modo Núcleo o Supervisor.

Windows y Linux sólo usan los anillos 0 y 3 (en Linux el usuario root tiene más privilegios que el administrador de Windows). Ahora, ¿cómo aceden al hardware las aplicaciones del usuario? Si estas no tienen suficientes privilegios, se accede mediante las llamadas a las APIs del sistema operativo (en Linux, Syscalls o Llamadas al sistema). Éstas proporcionan un gran nivel de abstracción al programador, ya que éste sabe lo que hacen éstas, no cómo funcionan internamente.

Ahora compilemos el siguiente código en XP:

// hay que usar Dev-C++ o llamar directamente al compilador de la siguiente forma
// gcc -o quitarpass quitarpass.c
#include <stdio.h>
main()
{
  asm (".intel_syntax noprefix");
  __asm ("cli");
// desactivamos las interrupciones
  __asm ("mov al,0x2e");
// movemos el valor 0x2e a registro AL
  __asm ("out 0x70,al");
// escribimos el valor de AL en el puerto 70
  __asm ("out 0x71,al");
// escribimos el valor de AL en el puerto 71
  __asm ("sti");
// habilitamos las interrupciones
  asm (".att_syntax noprefix");

 return 0;
}

Explicación del código:
Las Directivas asm (".intel_syntax noprefix"); y asm (".att_syntax noprefix"); son para que acepte la sintaxis de Intel, ya que el gcc usa por defecto la de AT&T. Por ejemplo:

intel syntax At&t syntax Mov ax,5 mov $5,%ax

Si lo compilamos veremos que no da ningún error, pero si lo ejecutamos nos dará el típico error "El programa quitarpass.exe ha efectuado una operación no válida y debe cerrarse".

¿Que sucedió entonces, que ni como administrador podemos ejecutarlo?

Sólo sé que el sistema no lo permite. Quizás lo haga si lo lanzamos con la cuenta system, ya que ésta tiene más privilegios que el Administrador. Pero no lo he probado, así que si alguien lo prueba que me lo comunique. Existen programas como el asusupdate, que como administrador te permiten flashear, actualizar, e incluso cambiarle el logo de inicio al BIOS. Estos programas usan generalmente una función que se llama DeviceIOcontrol,que también es usada en la creación de controladores de dispositivos, ya que estos necesitan acceder directamente al hardware. Dicha función no he podido probarla, ya que no he encontrado suficiente documentación sobre cómo usarla.

En el caso del debug no da ningún error, pero si reiniciamos la PC veremos que no ha eliminado el pass del BIOS.

Ahora probemos el siguiente código en Linux:

#include <sys/io.h> // contiene el prototipo de la función iopl

main()
{
  iopl(3);
// elevamos los privilegios de E/S, que normalmente es 0
  asm(".intel_syntax noprefix");
  asm("cli");
  asm("mov al,0x2e");
  asm("out 0x70,al");
  asm("out 0x71,al");
  asm("sti");
  asm(".att_syntax noprefix");
  return 0;
}

Lo compilamos:

rnapoles rodas:~/prog/asm/cm$ gcc -o clearcmos clearcmos.c

Lo ejecutamos:

rnapoles rodas:~/prog/asm/cm$ ./clearcmos
Violación de segmento
rnapoles rodas:~/prog/asm/cm$

Esto sucede porque no tenemos suficientes privilegios. Ejecutémoslo como root a ver que pasa:

rnapoles rodas:~/prog/asm/cm$ su
Password:
root rodas /home/rnapoles/prog/asm/cm :./clearcmos

Y todo sale ok. Reiniciemos la PC y entremos al BIOS. ¡Hecho está: sin password!, por lo que sólo debemos usar la cuenta de root para tareas administrativas. Ya que no soy un especialista en la materia, el texto anterior puede que quizás contenga algunos errores.

Para saber más...



Artículos relacionados


No hay comentarios: