LIST_ENTRY
- это то, как Windows внутренне связывает списки. Есть много информации о них в Интернете, если вам нужно больше деталей, но здесь вам нужно знать две вещи:
- - это то, что следующие / обратные указатели не указывают на верхнюю часть объект (который распространен в большинстве реализаций); поэтому, чтобы добраться до заголовка объекта, вы должны исправить указатель на основе смещения члена LIST_ENTRY. Именно здесь вступает в действие макрос
CONTAINING_RECORD
. - состоит в том, что вы не хотите вносить исправления в первый объект LIST_ENTRY в объекте PEB_LDR_DATA, думайте о них как о указателе "head", и вам нужно чтобы перейти через Flink, прежде чем вы получите данные, которые вас интересуют.
Пример кода:
LIST_ENTRY *current_record = NULL;
LIST_ENTRY *start = &(pebLdrData->InLoadOrderModuleList);
// move off the initial list entry to the first actual object
current_record = start->Flink;
while (true)
{
// find the head of the object
LDR_DATA_TABLE_ENTRY *module_entry = (LDR_DATA_TABLE_ENTRY*)
CONTAINING_RECORD(current_record, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
printf("%wZ\n", &module_entry->BaseDllName);
// advance to the next object
current_record = current_record->Flink;
if (current_record == start)
{
break;
}
}