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:
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
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:
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.
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:
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:
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í:
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:
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:
Pero con la IT ofuscada no es capaz de leerla correctamente:
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.
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:
ResponderEliminar#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
Que compilador usas? GCC?
ResponderEliminarLa 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.
GCC no es de linux?....
ResponderEliminarPensé que gcc solamente estaba en linux.
Ahora uso visual c, pero tambien puedo probarlo con borland.