lunes, 11 de abril de 2011

Ofuscación de la Import Table

Leyendo y probando cosas sobre la Import Table, IT, di con una forma de ofuscar o hacer mas difícil de leer la IT.

La idea es poner la Import Table entre 2 secciones, al final de una y comienzo de la siguiente. Estas secciones en disco están separadas, pero una vez cargadas en memoria estarán juntas de modo que el cargador de Windows podrá leer correctamente la IT pero las herramientas que leen la IT en disco fallaran, como LordPE.

Veámoslo mas detalladamente.

Para las pruebas he compilado este programa en ensamblador(MASM) que solo muestra un MessageBox y finaliza:

.386
.model flat, stdcall
option casemap:none

include windows.inc
include user32.inc
include kernel32.inc

includelib user32.lib
includelib kernel32.lib

.data

mensaje  db "Primer programa de prueba", 0
titulo   db "Sector Virus", 0

.code

codigo:

push MB_OK + MB_ICONINFORMATION
push  offset titulo
push  offset mensaje
push  0
call  MessageBox

push  0
call  ExitProcess

end codigo

Cuelgo aquí el ejecutable.

Podemos ver con Olly que el ejecutable tiene 3 secciones y que la IT está en la segunda sección, rdata:

image

Veamos un resumen de las secciones con los valores que nos interesan:

.text: VirtualAddress 1000h VirtualSize 26h PointerToRawData 400h SizeOfRawData 200h .rdata VirtualAddress 2000h VirtualSize 92h PointerToRawData 600h SizeOfRawData 200h

.data VirtualAddress 3000h VirtualSize 27h PointerToRawData 800h SizeOfRawData 200h

Otro dato importante es que la IT empieza en la RVA 2010h

image

Traducido a dirección física es la 610h.

He realizado un esquema de como estaría el ejecutable en disco y en memoria para que se entienda mas fácilmente:

image

Nuestro objetivo es poner la IT al final de .rdata y comienzo de .data. Que estas secciones en disco estén separadas pero que en memoria estén juntas.

Pero como vemos en el esquema en memoria la seccion .rdata y .data no están juntas, .rdata acaba en 2200h y .data empieza en 3000h. El valor SectionAlignment es 1000h así que las secciones tienen que empezar en valores múltiplos de 1000h por lo que no podemos hacer que la sección .data virutalmente empiece en 2200h, donde acaba .rdata. La única opción que nos queda es ampliar el tamaño de .rdata para que ocupe todo el espacio en memoria, desde 2000h hasta 3000h.

image

Para ello debemos añadir D00h 00’s al final de .rdata para hacer que el tamaño de está sea 1000h. Hay que corregir los valores de las secciones tmb:

.text: VirtualAddress 1000h VirtualSize 26h PointerToRawData 400h SizeOfRawData 200h .rdata VirtualAddress 2000h VirtualSize 92h PointerToRawData 600h SizeOfRawData 1000h

.data VirtualAddress 3000h VirtualSize 27h PointerToRawData 1600h SizeOfRawData 200h

Ahora ya podemos probar a mover la IT de sitio y ponerla entre las secciones .rdata y .data:

image

La IT ahora estará en disco en la posición 15FCh, que corresponde a la sección .rdata, pero finaliza en la sección .data. En memoria la IT estará en la posición 2FFCh, así que corregimos ese valor en la cabecera PE:

image

Probamos el ejecutable y vemos que funciona correctamente. Ya lo último que nos queda es separar las secciones .rdata y .data en disco. Esto se hace simplemente insertando 00’s y corrigiendo los valores de las secciones. El esquema quedará así:

image

Y las secciones:

.text: VirtualAddress 1000h VirtualSize 26h PointerToRawData 400h SizeOfRawData 200h .rdata VirtualAddress 2000h VirtualSize 92h PointerToRawData 600h SizeOfRawData 1000h

.data VirtualAddress 3000h VirtualSize 27h PointerToRawData 1800h SizeOfRawData 200h

El espacio entre 1600h y 1800h contiene 00’s y no será mapeado en memoria cuando se cargue el ejecutable ya que no corresponde a ninguna sección.

Subo aquí el ejecutable modificado.

De este modo, como vemos en el esquema, la IT en memoria está junta pero en disco separada de modo que LordPE se confunde:

image

No es la única herramienta que se confunde de hecho supongo que casi todas las herramientas que leen la IT en disco se confundirán. Por ejemplo en VirusTotal en la parte de información de un ejecutable nos muestra las funciones importadas. Con el ejecutable original podemos ver las 2 funciones que utiliza el exe:

image

Pero con la IT ofuscada no es capaz de leerla correctamente:

image

Las heurísticas de los antivirus una de las cosas que hacen es fijarse en la IT ver que funciones usa el ejecutable y dependiendo de lo peligrosas que sean identificar un exe como un posible malware. ¿Será posible usando esta técnica engañar a la heurística de un AV?

En la siguiente entrada hacemos unas pruebas. Saludos! PD: Hay un detalle que me he saltado para hacer la explicación mas sencilla de seguir. En la sección data están las cadenas que se usaran en el MessageBox, nosotros ahí hemos puesto parte de la IT de modo que es necesario desplazarlas de lugar y corregir el código.

3 comentarios:

  1. la pregunta sonará tonta, pero la verdad estoy atorado en esto y no sé como salir, tampoco tengo a quien preguntarle. Estaba intentando trasladar tu codigo del comienzo a c, pero me tira un error. Sé que tiene que ver con las variables, pero no entiendo mucho de ensamblador, tampoco de c y ambas carencias se potencian:

    #include
    #include

    void main()
    {
    char txt[]= "v";
    char txt2[]="d";

    _asm{
    push 0
    push dword ptr txt
    push dword ptr txt2
    push 0
    call MessageBox
    }

    }

    si me decis cual es mi error te lo agradezco.
    Saludos. Y perdon si la pregunta es un poco desubicada

    ResponderEliminar
  2. Que compilador usas? GCC?
    La verdad creo que nunca he utilizado la directiva de _asm para incluir codigo ensamblador en un programa.

    Dime que compilador usas y lo intento.
    Un saludo.

    ResponderEliminar
  3. GCC no es de linux?....
    Pensé que gcc solamente estaba en linux.
    Ahora uso visual c, pero tambien puedo probarlo con borland.

    ResponderEliminar