Bound Import Directory II - PE header
IMAGE BOUND FORWARDER REF
En el artículo anterior hemos visto qué es el Bound Import Directory y cómo nos puede ayudar en la optimización de la carga de nuestros ejecutables. Como vimos, la estructura IMAGE_BOUND_IMPORT_DESCRIPTOR tiene un elemento llamado NumberOfModuleForwardefRefs que nos indica el número de estructuras IMAGE_BOUND_FORWARDER_REF que contiene.
Dicha estructura se define así:
typedef struct IMAGE_BOUND_FORWARDER_REF
{
DWORD TimeDateStamp;
WORD OffsetModuleName;
WORD Reserved;
}
Como ves es similar a la IMAGE_BOUND_IMPORT_DESCRIPTOR, únicamente varía el segundo WORD que en este caso está reservado. Esta estructura se utiliza ya que es posible enlazar determinadas API que necesiten de otras DLL diferentes y que también hay que comprobar. Por ejemplo, como menciona Matt Pietrek en el enlace que puse, imagina que haces uso de la función HeapAlloc, dicha función te remitirá a RtlAllocateHeap que se encuentra en NTDLL. Tras ejecutar BIND en el ejecutable (esto es cuando se vincula las librerías para generar el Bound Import Directory como vimos en el anterior tutorial), tu ejecutable tendrá:
- IMAGE_BOUND_IMPORT_DESCRIPTOR para Kernel32.dll seguido de:
- IMAGE_BOUND_FORWARDER_REF para Ntdll.dll
Un ejemplo, por favor
Voy a burcar un archivo con formato PE que cumpla lo anterior. He encontrado una librería. Lo primero que voy a hacer es examinarlo con un visor PE y ver los datos del IMAGE DATA DIRECTORY en lo relativo a este tema, veo lo siguiente:
| RVA | Size |
BoundImport | 00000218 | 0000004C |
Ahora voy al RVA 218 y mostraré los 4C bytes:
00000218 24 98 21 34 28 00 00 00 25 98 21 34 32 00 01 00 $.˜!4(...%˜.!42...
00000228 24 98 21 34 28 00 00 00 51 82 21 34 3F 00 00 00 $.˜!4(...Q‚!4?...
00000238 00 00 00 00 00 00 00 00 6E 74 64 6C 6C 2E 64 6C ........ntdll.dl
00000248 6C 00 4B 45 52 4E 45 4C 33 32 2E 64 6C 6C 00 49 l.KERNEL32.dll.I
00000258 4D 41 47 45 48 4C 50 2E 64 6C 6C 00 MAGEHLP.dll.
Aunque a primera vista no las veas, contiene 3 estructuras IMAGE BOUND IMPORT DESCRIPTOR que las voy a resaltar en verde:
00000218 24 98 21 34 28 00 00 00 25 98 21 34 32 00 01 00 $.˜!4(...%˜.!42...
00000228 24 98 21 34 28 00 00 00 51 82 21 34 3F 00 00 00 $.˜!4(...Q‚!4?...
00000238 00 00 00 00 00 00 00 00 6E 74 64 6C 6C 2E 64 6C ........ntdll.dl
00000248 6C 00 4B 45 52 4E 45 4C 33 32 2E 64 6C 6C 00 49 l.KERNEL32.dll.I
00000258 4D 41 47 45 48 4C 50 2E 64 6C 6C 00 MAGEHLP.dll.
Voy a analizar la primera estructura IMAGE BOUND IMPORT DESCRIPTOR:
TimeDateStamp: 34219824h == Jueves, 18 de septiembre de 1997. 21:07:48 horas
OffsetModuleName: 0028h == 218h + 28h = 240h == ntdll.dll
NumberOfModuleforwarderRefs: 0000h / 0d
Ahora voy a analizar la tercera estructura:
TimeDateStamp: 34218251h == Jueves, 18 de septiembre de 1997. 19:34:41 horas
OffsetModuleName: 003Fh == 218h + 3Fh = 257h == IMAGEHLP.dll
NumberOfModuleforwarderRefs: 0000h / 0d
Y finalmente voy a analizar la segunda estructura:
TimeDateStamp: 34219825h == Jueves, 18 de septiembre de 1997. 21:07:49 horas
OffsetModuleName: 0032h == 218h + 32h = 24Ah == KERNEL32.dll
NumberOfModuleforwarderRefs: 0001h / 1d
Como ves esta segunda estructura IMAGE BOUND IMPORT DESCRIPTOR nos dice que seguida a ella, existe una estructura IMAGE_BOUND_FORWARDER_REF. Veamos estas estructuras de nuevo con el color que las he marcado:
00000218 24 98 21 34 28 00 00 00 25 98 21 34 32 00 01 00 $.˜!4(...%˜.!42...
00000228 24 98 21 34 28 00 00 00 51 82 21 34 3F 00 00 00 $.˜!4(...Q‚!4?...
00000238 00 00 00 00 00 00 00 00 6E 74 64 6C 6C 2E 64 6C ........ntdll.dl
00000248 6C 00 4B 45 52 4E 45 4C 33 32 2E 64 6C 6C 00 49 l.KERNEL32.dll.I
00000258 4D 41 47 45 48 4C 50 2E 64 6C 6C 00 MAGEHLP.dll.
Es muy sencillo de entender viendo esto. Simplemente voy a analizar esta estructura IMAGE_BOUND_FORWARDER_REF:
TimeDateStamp: 34219824h == Jueves, 18 de septiembre de 1997. 21:07:48 horas
OffsetModuleName: 0028h == 218h + 28h = 240h == ntdll.dll
Reserved: 0000h / 0d
Conclusiones
La verdad, que todo el tema relacionado con el Bound Import Directory es un tema interesante, más que interesante quiero decir curioso que no afecta en la ejecución de un ejecutable (archivo con formato PE), pero puedes optimizar el tiempo de carga.
No he querido hablar de por qué al añadir una nueva sección a un ejecutable en VB6 da error. Creo que aunque está relacionado con este tema no es para comentarlo en este artículo, será en el siguiente.
Referencias
Sin las referencias hubiese sido imposible hacer este tutorial. He seguido 2 referencias:
- Un excelente tutorial de Matt Pietrek publicado en la MSDN: http://msdn.microsoft.com/en-us/magazine/cc301808.aspx
- Otro excelente tutorial que recibí por correo electrónico de su autor: The Swash. Titulado: Formato Portable Executable bajo Windows. ¡Qué gran trabajo!. Sigue así, un saludo.