> For the complete documentation index, see [llms.txt](https://ymmfty0.gitbook.io/ymmfty0/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ymmfty0.gitbook.io/ymmfty0/pe-file-format/headers/data-directories.md).

# Data Directories

В прошлой части мы говорили про OptionalHeader. DataDirectories так же является членом OptionalHeader в NT Headers.

## Data Directories

В конце структуры `IMAGE_OPTIONAL_HEADER` находится значение `DataDirectory`, которое является одним из самых важных членов Optional Header. Это массив структур `IMAGE_DATA_DIRECTORY`. Data Directories содержат полезную информацию, необходимую загрузчику. Примером очень важной директории является директория импорта, которая содержит список внешних функций, импортированных из других библиотек.

`IMAGE_DATA_DIRECTORY` — это структура, которая состоит из двух значений: `RVA`, указывающего на начало каталога данных, и размера самого каталога в байтах. Все эти записи каталога данных загружаются в память, чтобы система могла использовать их во время выполнения программы.

Вот как она выглядит:

```cpp
typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
```

Если посмотреть на структуру OptionaHeader, то в официальной [документации](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header32) , мы можем увидеть, то что массив DataDirectory имеет размер которого определяется макросом `IMAGE_NUMBEROF_DIRECTORY_ENTRIES`. Этот макрос хранит в себе значение 16

```cilkcpp
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16
```

Для получение любого каталога данных, мы можем использовать вот такой код.

```cpp
IMAGE_DATA_DIRECTORY relocationTable =
	ntHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
```

Все индексы каталогов данных хранятся в winnt.h.

```cpp
#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory
//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor
```

Давайте попробуем высчитать адрес из каталогов при помощи RVA и получить до него адрес. В нашем примере мы будем использовать `IMAGE_DIRECTORY_ENTRY_BASERELOC`.

Для начала нам нужно получить сам этот элемент каталога данных из массива DataDirectories, как я показывал выше

```cilkcpp
IMAGE_DATA_DIRECTORY relocationTable =
	ntHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
```

Чтобы высчитать адрес, нам просто стоит прибавить RVA на наш BaseAddress

<pre class="language-cpp"><code class="lang-cpp"><strong>
</strong><strong>std::cout &#x3C;&#x3C; "reloc addr " &#x3C;&#x3C; std::hex &#x3C;&#x3C; reinterpret_cast&#x3C;PVOID>(pBaseAddr + relocationTable.VirtualAddress);
</strong><strong>
</strong></code></pre>

Я использую преобразование, потому что в нашем случае `pBaseAddr` — это `PBYTE`, и я хочу корректно вывести адрес для обращения к нему.

Посмотрим, что находится по этому адресу.

<figure><img src="/files/ow1L6FeYriKjDx7wdxQR" alt=""><figcaption></figcaption></figure>

И перейдем в секцию .reloc в PE-Bear , чтобы сверить данные, корректный ли адрес мы получили.

<figure><img src="/files/9eckjXJWaSUbZTgC84Zj" alt=""><figcaption></figcaption></figure>

Как видим, данные правильны и мы корректно получили адрес на секцию. Давайте получим размер этого каталога данных, в данном случае таблицы Relocation

Если перейдем в PE-Bear видим размер тут BC

<figure><img src="/files/TnCvfHylRplEmde8BRbo" alt=""><figcaption></figcaption></figure>

Мы будем использовать вот такой код

<pre class="language-cpp"><code class="lang-cpp"><strong>
</strong><strong>std::cout &#x3C;&#x3C; "reloc table size " &#x3C;&#x3C; relocationTable.Size &#x3C;&#x3C; std::endl;
</strong><strong>
</strong></code></pre>

Как видим по выводу , результат такой же и все работает правильно.

<figure><img src="/files/kyae48scUkOj1YZI36oS" alt=""><figcaption></figcaption></figure>

Мы так же можем это использовать для получение количества элементов внутри этого каталога данных. Но это уже зависит от ваших задач и даю вам на размышление.

В следующей части мы более подробно рассмотрим, что такое секции и как с ними работать.

## Итог

В этой части мы рассмотрели массив DataDirectory, который содержит ключевую информацию для загрузчика PE-файлов. Мы узнали, что каждый элемент IMAGE\_DATA\_DIRECTORY, включая таблицу релокаций, представлен структурой, содержащей RVA и размер данных, что позволяет системе правильно загружать и использовать их во время выполнения программы . И подвели практический итог используя ее на практике

Для практического понимания работы с заголовком PE-файла, вы можете ознакомиться с кодом в моем репозитории Github: <https://github.com/ymmfty0/PEFormatTutorial/tree/master/DataDirectories>
