Estructura de un archivo PE (Portable Executable)

Autor: | Última modificación: 18 de abril de 2024 | Tiempo de Lectura: 4 minutos

Algunos de nuestros reconocimientos:

Premios KeepCoding

En este post veremos cuál es la estructura de un archivo PE, cuyas siglas significan Portable Executable, y por qué es importante conocerla para realizar análisis de malware.

En la mayoría de ocasiones, los malwares más elaborados cuentan con técnicas de desarrollo que les permiten ocultarse de los sistemas de ciberseguridad. Una de estas técnicas es el uso de packers y, para identificarlos, es necesario conocer la estructura de un archivo PE.

¿Qué es un packer?

Antes de ver la estructura de un archivo PE, hablaremos brevemente sobre lo que es un packer. Un packer es un empaquetador o compresor de archivos, que reduce significativamente el tamaño del malware y, a la vez, sirve para evadir sistemas de seguridad informática.

Estructura de un archivo PE

Un archivo de formato PE sirve para decirle a los cargadores de los sistemas operativos qué información necesitan para administrar el código ejecutable empaquetado. La información que requiere el sistema, a grandes rasgos, contiene:

  • Referencias a bibliotecas dinámicas a importar.
  • Importar/exportar tablas de API.
  • Cuánto espacio de memoria reservar. (En la memoria irán el código, los datos y los recursos que necesitará el proceso en el sistema. El PE nunca se mapea entero, solo por partes).

La estructura de dicha información se puede ver de la siguiente manera:

Encabezado DOS

  • Ocupa 64 bytes.
  • Tiene un magic number «e_magic» que identifica si es un fichero compatible con DOS. En ASCII es «MZ», las iniciales de Mark Zibkowski.
  • Los últimos 4 bytes indican dónde está la cabecera del PE (e_lfanew).

Stub DOS

  • Se ejecuta al inicio de forma predeterminada.
  • Imprime «Este programa no se puede ejecutar en modo DOS» si el PE no es compatible con los sistemas operativos.
  • Cuando el PE se asigna a memoria, el primer byte asignado corresponde al primer byte del Stub DOS.
  • Suele ocupar 57 bytes.

Encabezado del PE

  • Se localiza mediante la dirección que aparece en el «e_lfanew» en la cabecera DOS.
  • Este encabezado PE es una estructura de tipo IMAGE_NT_HEADERS, que contiene:
    • SIGNATURE: es la firma DWORD de 4 bytes (suele ser 50 45 00 00, que es PE más dos bytes a 0).
    • IMAGE_FILE_HEADER: contiene la información más básica sobre el diseño del fichero:
      • Machine: define la arquitectura o emulador sobre la que se puede ejecutar el programa.
      • NumberOfSections: son dos bytes después de machine. Definen el número de secciones que existen en ese ejecutable. El número máximo de secciones se establece en 96.
      • TimeDataStamp: indica el número de segundos transcurridos a partir del 1 de enero de 1970 o, lo que es lo mismo, la fecha exacta de creación del fichero.
      • Son 4 bytes y están a continuación de NumberOfSections.
      • PointerToSymbolTable & NumberOfSymbols: son 8 bytes después de TimeDataStamp. Corresponden a funciones de debug, que, por lo general, están deshabilitadas. Los primeros 4 bytes corresponden al puntero para la tabla de símbolos y los siguientes 4 al número de símbolos. De forma predeterminada, en ejecutables, están a 0.
      • SizeOfOptionalHeader: son los dos bytes siguientes al anterior campo e indican el tamaño del encabezado opcional. Los campos son obligatorios, no opcionales, excepto en los ficheros objetos, donde es 0.
      • Characteristics.
    • IMAGE_OPTIONAL_HEADER: esta cabecera proporciona información adicional al loader para que cargue correctamente el ejecutable. Esta información, en los archivos COFF, es opcional, pero en los archivos ejecutables es obligatoria. El tamaño de esta estructura no es fijo y lo define el campo SizeOfOptionalHeader.

Encabezado opcional de imagen

Esta parte de la estructura de un archivo PE contiene información que puede tener un alto nivel de detalle, por lo que solo nos concentraremos en algunas de sus secciones más importantes:

  • Magic: son dos bytes que determinan la arquitectura del sistema operativo:
    • 0x010B para PE32 (x86).
    • 0x020B para PE32+ (x64).
  • AddressOfEntryPoint: los siguientes 4 bytes. Indican la dirección de entrada o EntryPoint. Esta dirección es un RVA (Relative Virtual Address), es decir, es una dirección relativa con respecto a la dirección base. Para encontrar esta dirección en memoria, debemos sumar su valor con el de la dirección base.
  • BaseOfCode & BaseOfData: contienen el RVA de comienzo de código y el RVA del comienzo de los datos, respectivamente. Ambas son 4 bytes.

Directorio de datos

  • Indica dónde encontrar los otros componentes importantes de la información ejecutable en el archivo.
  • Las estructuras de este campo se encuentran en la parte inferior de la estructura de encabezado opcional.
  • El formato de archivo PE actual define 16 posibles estructuras de datos, de las cuales 11 se utilizan actualmente.
  • Algunos de los componentes importantes son:
    • ExportTableAddress.
    • ImportTableAdress.
    • ResourcesTable.
    • ImportAdressTable.

Tabla de encabezado de sección

🔴 ¿Quieres entrar de lleno a la Ciberseguridad? 🔴

Descubre el Ciberseguridad Full Stack Bootcamp de KeepCoding. La formación más completa del mercado y con empleabilidad garantizada

👉 Prueba gratis el Bootcamp en Ciberseguridad por una semana

Esta sección de la estructura de un archivo PE contiene una matriz con información relativa a las diferentes secciones del ejecutable:

  • SizeOfRawData: especifica el tamaño real de la sección en el archivo.
  • VirtualSize: indica el tamaño de la sección en la memoria.
  • PointerToRawData: es el desplazamiento donde comienza la sección de datos sin procesar del archivo.

Secciones

La última parte de la estructura de un archivo PE son sus secciones:

  • .text: contiene el código ejecutable y su EP.
  • .data: contiene datos inicializados, como cadenas.
  • .rdata/.idata: contienen la tabla de importaciones que enumera la API de Windows usada.
  • .reloc: contiene información acerca de las reubicaciones. Contiene RVA en caso de que se usen para reubicar partes de PE en memoria.
  • .rsrc: contenedor de recursos como imágenes.
  • .debug: contiene información de depuración.
  • .edata: contiene una enumeración de funciones y DLL que se exportarán para usarse por otros binarios.

¿Cómo aprender más?

Ahora conoces la estructura de un archivo PE, este conocimiento te ayudará a analizar ficheros maliciosos. Si quieres convertirte en un experto en análisis de malware, entra a nuestro Ciberseguridad Full Stack Bootcamp. ¡Apúntate y especialízate en solo 7 meses!

¡CONVOCATORIA ABIERTA!

Ciberseguridad

Full Stack Bootcamp

Clases en Directo | Profesores en Activo | Temario 100% actualizado