Trampas Caza bobos y desbordamientos de buffer

Publicado 20/3/2009 11:39 por Rafael Ontivero

El blog del equipo de Visual C++ de Microsoft ha publicado una muy interesante entrada sobre trampas caza bobos para detectar e impedir desbordamientos de buffer en programas escritos en C++. Las técnicas para ello han tenido bastante éxito, llegando a detener una buena cantidad de virus y otro malware a partir de Windows Server 2003, que fue el primer sistema operativo compilado usando estas técnicas. Para aquellos que no lo sepan, los sistemas operativos de Microsoft se compilan con el mismo compilador que trae Visual C++… Bueno, no es exactamente así, ya que ellos tienen una versión interna algo más antigua y aparentemente más estable que la que sale con las ediciones comerciales (en general era –no sé si sigue siendo- la que salía en los SDK del correspondiente Windows). Así que cuando nosotros estamos compilando nuestros proyectos tenemos la certeza de que el sistema operativo tiene la misma buena (o mala) calidad de código generado.

Bueno, pero me he ido un poco por las ramas. Lo que yo llamo caza bobos se introdujo por primera vez en la versión 2002 del compilador, y ha ido evolucionando poco a poco, tal y como se cuenta en la entrada citada.

Básicamente, lo que hace la opción GS del compilador, que viene activada por defecto, es insertar una serie de firmas dentro de nuestro código generado de forma que si alguna de ellas ha cambiado, nos encontramos ante un intento de desbordamiento de buffer. Eso no quiere necesariamente decir que estén intentando inyectar código en nuestro programa, sino que también un bug en nuestro programa esté produciendo un desbordamiento, una variante de tener un puntero loco como habitualmente suele decirse.

No obstante este último problema no suele ser muy común si hemos hecho bien los deberes, ya que las compilaciones debug de Visual C++ (a partir de la versión 2005, creo) son fantásticas a la hora de cazarnos desbordamientos y memoria asignada y no liberada o justo lo contrario. Tan sólo hay que mirar la ventana de Output y ver las barrabasadas que hemos cometido.

Esta característica se hace en detrimento de otros parámetros, ya que aumenta las diferencias entre compilación debug y compilación release, de modo que en muchas situaciones un programa que funcionaba bien en debug tendrá problemas en release, que deberán ser solucionados en esa etapa.

No, no es un inconveniente, sino una ventaja, ya que hemos separado dos de los problemas más comunes en un desarrollo serio: errores en los trasteos con la memoria y errores de sincronización y procesos. No es muy infrecuente partirte los sesos pensando que tienes un puntero loco para luego descubrir que es un tema de sincronización (un hilo esté escribiendo o leyendo cuando no debe en un lugar compartido) o justo lo contrario.

Pues bien, la idea de la opción GS es la de colocar bytes sin sentido dentro de la pila de llamadas o en las fronteras de los bufferes asignados, de modo que cuando se retorne de una función se verifique dicha semilla, y si no es correcta es que tenemos un problema. Una ventaja de esta técnica es que no es necesaria en todas y cada una de las funciones de nuestro programa, sino solamente en aquellas en que la heurística del compilador así lo determine.

Es algo muy sencillo y que apenas usa memoria y tiempo de ejecución, y nos puede salvar de la entrada de un virus o de futuras corrupciones de otras variables que podrían terminar en la completa pérdida de nuestros datos.

Evidentemente todo es saltable en este mundo, pero estamos hablando de palabras mayores, ya que las citadas firmas pueden ser completamente diferentes y estar en lugares diferentes no sólo en cada compilación, sino también en cada ejecución del programa protegido, por lo que su violación es prácticamente imposible.

Quien quiera saber más detalles técnicos sobre esto, que lea el artículo en cuestión, en donde también vienen otros enlaces para seguir investigando el tema.

Actualización: Añado un comentario de Luis Guerrero:

Siguiendo con el articulo de Rafael Ontivero, en Windows Vista el equipo de producto, utilizo una caracteristica muy interesante llamada SAL (Standart Annotation Language) en el que marcaron todos los parametros de todas las funciones de WIN32 con "attributos" como "__in" "__out" "__in_opt" que permiter saber el compilador de c/c++ cual es el sentido del parametro y hacer comprobaciones en la pila de la llamada para asegurar la integridad de la pila y de stackframe de llamadas, esto junto con las cookies de seguridad que se comentan en el articulo hacen del codigo algo mucho más seguro.

Saludos. Luis.

Comparte este post:

Comentarios

# re: Trampas Caza bobos y desbordamientos de buffer

Friday, March 20, 2009 5:28 PM by Octavio Hernández

Superinteresante!

Saludos - Octavio

# re: Trampas Caza bobos y desbordamientos de buffer

Friday, March 20, 2009 11:28 PM by Luis Guerrero

Siguiendo con el articulo de Rafael Ontivero, en Windows Vista el equipo de producto, utilizo una caracteristica muy interesante llamada SAL (Standart Annotation Language) en el que marcaron todos los parametros de todas las funciones de WIN32 con "attributos" como "__in" "__out" "__in_opt" que permiter saber el compilador de c/c++ cual es el sentido del parametro y hacer comprobaciones en la pila de la llamada para asegurar la integridad de la pila y de stackframe de llamadas, esto junto con las cookies de seguridad que se comentan en el articulo hacen del codigo algo mucho más seguro.

Saludos. Luis.