PE header: ¿Qué es la IAT (Import Address Table)?
¿Qué es la IAT?
Seguro que en muchísimos tutoriales sobre ingeniería inversa has oído hablar sobre la IAT; que si hay que reconstruir o reparar la IAT, que si está incorrecta, que si hay que calcular su tamaño... IAT son las siglas de Import Address Table (tabla de direcciones de importación) y aunque está íntimamente relacionada con la IT, no son lo mismo. Basándome en diversos escritos a los que hago referencia al final del artículo y en mi experiencia, intentaré que entiendas qué es la IAT, para qué sirve, diferencia con la IT, los saltos característicos a la IAT y mostraré un caso práctico.
Diferencia IAT - IT. IID
La IAT son las siglas de Import Address Table que normalmente no es traducido, usándose la abreviatura IAT - traduzco literalmente: tabla de direcciones de importación - y es muy importante que lo/la conozcas si sueles depurar tus aplicaciones buscando errores. Antes de comenzar, quiero que sepas que también existe la IT - Import Table - Tabla de Importaciones. Aunque la IAT y la IT están relacionadas, ¡no son lo mismo! y la IT (o sección idata, como dice la ayuda de Microsoft) en el PE header, está asignada mediante una dirección y un tamaño. La IT se inicia con una serie de estructuras IMAGE_IMPORT_DESCRIPTORs (IID) que son las que nos van a indicar las dll (librerías etc...) y funciones que el loader de Windows va a cargar. Pero esto es otro amplísimo tema, vamos a centrarnos solamente en la IAT.
De forma muy simple y para que se entienda, cuando ejecutas un programa, el loader de Windows busca en el PE header las importaciones (normalmente librerías dll, ocx...). En esas librerías, cada función, es posible que en tu ordenador esté en una dirección diferente que en el mío (olvidándonos también de Bound Import Directory). Por este y otros motivos, el loader de Windows obtiene la dirección de cada función y para que no se pierda, pueda usarla y hacer referencia a ella, la tiene que guardar en algún sitio. La guarda en la IAT.
Resumen, de forma muy general:
- La IT es una tabla con toda la información de las funciones y librerías que van a ser importadas.
- La IAT es una tabla que contiene las direcciones virtuales (virtual address) con la información obtenida de la IT
Ejemplo teórico
Imagina que en tu programa haces uso de la siguiente API:
GetModuleHandleA
Dicha función, se encuentra dentro de la librería kernel32.dll de Windows. En mi ordenador está exactamente en la dirección 75CBD8F3, que posiblemente es diferente a la tuya.
Observo (en el siguiente apartado mostraré un caso práctico para entender esto), que la dirección de la IAT donde se rellena este valor es en:
00403238
Verifico, con un editor hexadecimal, que antes de ejecutar el programa ese valor muestra lo siguiente:
00403238 00000000
Sin embargo, si cargo el programa en OllyDBG y voy a esa dirección, observo que su valor ha sido modificado y ahora tiene:
00403238 75CBD8F3 kernel32.GetModuleHandleA
Espero que, a grandes rasgos, puedas entenderlo. La dirección de la IAT para la función GetModuleHandleA es 00403238 y el loader de Windows, durante la carga del programa, la rellena automáticamente con la dirección 75CBD8F3. Seguro que te preguntarás... ¿y cómo sé dónde está la IAT en un programa?. Bien sencillo, vamos a hacer un caso práctico y entenderemos también esto último.
Ejemplo práctico. Encontrando la IAT.
Descarga el siguiente archivo zip:
Vamos a trabajar con el ejecutable que hay en la carpeta asm02, llamado asm02.exe. Yo voy a utilizar la versión 2 de OllyDBG. Existen muchas formas de encontrar la IAT, para este primer artículo vamos a ver algo básico que es muy utilizado.
Carga asm02.exe en OllyDBG 2. Si has seguido estos pasos, te encontrarás en la dirección 00401000, con el siguiente código:
CPU Disasm Address Hex dump Command Comments 00401000 /. 6A 00 push 0 ; /ModuleName = NULL 00401002 |. E8 C5010000 call 004011CC ; \KERNEL32.GetModuleHandleA 00401007 |. A3 00304000 mov dword ptr ds:[403000],eax 0040100C |. E8 FD010000 call 0040120E ; Jump comctl32.InitCommonControls ...
Observa que en la dirección 00401002 tenemos una llamada a la función GetModuleHandleA con la call 004011CC. Bien, vamos a ponernos sobre esa call y pulsamos la tecla enter para ir a la dirección 004011CC. Veremos lo siguiente:
CPU Disasm Address Command 004011C6 jmp dword ptr ds:[402010] 004011CC jmp dword ptr ds:[40200C] 004011D2 jmp dword ptr ds:[402008] 004011D8 jmp dword ptr ds:[402034] 004011DE jmp dword ptr ds:[402020] 004011E4 jmp dword ptr ds:[402018] 004011EA jmp dword ptr ds:[40201C] 004011F0 jmp dword ptr ds:[402038] 004011F6 jmp dword ptr ds:[402024] 004011FC jmp dword ptr ds:[402028] 00401202 jmp dword ptr ds:[40202C] 00401208 jmp dword ptr ds:[402030] 0040120E jmp dword ptr ds:[402000]
¡13 saltos jmp!. Estos saltos se suelen denominar saltos a la IAT, y no existen siempre en todos los programas. En nuestro caso, vemos un:
... 004011CC jmp dword ptr ds:[40200C]
Es decir, vamos a saltar a la dirección contenida en 40200C. Si en este caso te pones sobre jmp dword ptr ds:[40200C] y pulsas enter, irás directamente a la función GetModuleHandleA en kernel32.dll. Esto significa que la dirección de la función GetModuleHandleA está escrita en 40200C. Vamos a ir allí en la ventana de dumpeado. Para esto, vuelve atrás si estás en kernel32.dll y ponte encima de jmp dword ptr ds:[40200C], pulsa el botón derecho del ratón y selecciona: Follow in Dump -> Memory address. Ahora verás en la ventana de dumpeado (abajo a la izquierda) algo parecido a esto:
CPU Dump
Address Hex dump
0040200C F3 D8 CB 75 | E2 BB CC 75 | 00 00 00 00 | BB 42 3B 77
0040201C 14 3D 3E 77 | A3 3B 3B 77 | AD 64 38 77 | 11 EA 3D 77
0040202C 60 AD 38 77 | A9 F2 38 77 | 42 CF 3C 77 | 08 16 3B 77
0040203C 00 00 00 00
Cuando se tiene algo de experiencia, ya se puede apreciar que eso parecen direcciones. OllyDBG tiene una buena opción para mostrar a qué API o función corresponde cada dirección, para hacer esto pulsamos en la ventada de dump con el botón derecho del ratón y seleccionamos: Integer -> Address. Y ahí podrás ver exactamente toda la IAT:
CPU Dump
Address Value Comments
00402000 745C1541 ; comctl32.InitCommonControls
00402004 00000000
00402008 75CA9121 ; kernel32.lstrcmp
0040200C 75CBD8F3 ; kernel32.GetModuleHandleA
00402010 75CCBBE2 ; kernel32.ExitProcess
00402014 00000000
00402018 773B42BB ; user32.GetDlgItem
0040201C 773E3D14 ; user32.GetDlgItemTextA
00402020 773B3BA3 ; user32.EndDialog
00402024 773864AD ; user32.LoadIconA
00402028 773DEA11 ; user32.MessageBoxA
0040202C 7738AD60 ; user32.SendMessageA
00402030 7738F2A9 ; user32.ShowWindow
00402034 773CCF42 ; user32.DialogBoxParamA
00402038 773B1608 ; user32.LoadBitmapA
0040203C 00000000
Esta es la IAT y seguro que ahora lo ves todo mucho mejor. Como puedes observar entre cada librería existe un dword con valor 0, típico.
Calculando el tamaño de la IAT
Una de las cosas que habrás visto muchas veces en tutoriales, es que se calcula el tamaño de la IAT. Este dato es importante, sobretodo a la hora de reconstruirla. En este caso la IAT comienza en 00402000. La forma sencilla para que lo entiendas sería contar los bytes totales de la IAT (contando también los dword 0). De forma sencilla, ¿cuántas líneas ves en la IAT anterior? Voy a hacer un simple cálculo:
16 líneas x 4 bytes = 64 bytes. 64d bytes en decimal son 40h bytes en hexadecimal.
Es decir, el tamaño de la IAT es de 40h bytes. Después en el último apartado de este artículo verás que este dato está también en el PE header.
Sin embargo, para que no te lleve a confusión, en muchos tutoriales verás que calculan la IAT restando (por ejemplo en nuestro caso):
0040203C - 00402000 = 3Ch bytes
Debes entender, que aunque el tamaño de la IAT son 40h bytes, al hacer la resta anterior lo que hacemos es eliminar y obviar el último dword 0 que hay en 0040203C. Piensa que ese valor no es necesario para reconstruir la IAT y que se añadirá posteriormente.
Mostrar la IAT en el archivo físico
Ya te he enseñado a encontrar la IAT, a calcular su tamaño, ahora verás que en el archivo físico no se encuentra rellenada tal que así y que es el loader de Windows quien escribe los datos.
Aunque no lo voy a explicar en este tutorial, para no alargarlo demasiado, voy a calcular el offset que corresponde en el archivo físico a la dirección virtual de la IAT. En este ejecutable "asm02.exe", la dirección virtual 00402000 1 corresponde en el archivo físico con el offset 800 2. Esto lo puedes calcular con mi programa File Location Calculator y será también explicado (pero hoy no):
Ahora voy a abrir asm02.exe desde un editor hexadecimal, por ejemplo, desde el propio OllyDBG 2. Así que en OllyDBG 2 voy al menú View -> File, y como he dicho vamos al offset 800 y voy a mostrar los 64d bytes de la IAT. Veremos lo siguiente:
File C:\asm02.exe
Address Hex dump
00000800 A0 22 00 00 | 00 00 00 00 | F6 21 00 00 | E2 21 00 00
00000810 D4 21 00 00 | 00 00 00 00 | 2E 22 00 00 | 3C 22 00 00
00000820 22 22 00 00 | 5C 22 00 00 | 68 22 00 00 | 76 22 00 00
00000830 86 22 00 00 | 10 22 00 00 | 4E 22 00 00 | 00 00 00 00
Y para que compares, ahora muestro la IAT con asm02.exe cargado en OllyDBG 2:
CPU Dump
Address Hex dump
00402000 41 15 5C 74 | 00 00 00 00 | 21 91 CA 75 | F3 D8 CB 75
00402010 E2 BB CC 75 | 00 00 00 00 | BB 42 3B 77 | 14 3D 3E 77
00402020 A3 3B 3B 77 | AD 64 38 77 | 11 EA 3D 77 | 60 AD 38 77
00402030 A9 F2 38 77 | 42 CF 3C 77 | 08 16 3B 77 | 00 00 00 00
Otra forma de encontrar la IAT
Forma I
Esta forma que he comentado es muy utilizada para encontrar la IAT, aunque en muchos programas viene también indicada en el PE header. Vamos a verlo de forma muy sencilla. Abre asm02.exe con un editor o visor de PE header cualquiera. En dicho editor tendrás seguramente una opción denominada Directories, púlsala y verás esto:
Ahí la he marcado en amarillo. Puedes observar que el tamaño de la IAT es de 40h bytes y que RVA del comienzo es 0002000 y si observas la imagen de File Location Calculator que he puesto antes, comprobarás que la RVA 2000 corresponde con la Virtual Address 00402000.
Forma II
Otra forma que no voy a explicar aquí, pero que también nos indicará dónde está la IAT es observando la estructura IID (Image Import Descriptor).
Referencias
- Artículos de Matt Pietrek sobre el PE header en Microsoft: http://msdn.microsoft.com/en-us/magazine/ms809762.aspx
- Artículos del maestro Ricardo Narvaja sobre Import Table lento y a mano.
- Especificación PE en Microsoft: http://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx
- Formato Portable Executable bajo Windows por The Swash
- Mi experiencia
RVA : 2144
Size: 50
1.- Lo que ves en fondo de color azul es un copia-pega de OllyDBG
2.- La primera imagen con los números 1 y 2, es un programa propio que hice hace ya algunos años (no sé si será compatible con Windows 10, tendría que actualizarlo) llamado File Location Calculator
3.- La última imagen con el número 3 corresponde a un programa llamado PE voyeur.
Pero hay muchos editores de PE...
http://longinox.blogspot.com.es/2012/08/solucion-al-reto-unpackme-fsg-131-dulek.html
Me parece que es una de las mejores explicaciones que he leído.
Gracias.
De esa forma se puede apreciar mejor inicio-final y posibles entradas no válidas.
Simplemente te lo comento porque cuando seleccionas el final de la IAT hay después unas API del kernel32.dll que no sé si pertenecen a la IAT.
PERO muy buen artículo.