Как происходит переезд базы PE?

В настоящее время у меня возникают проблемы с пониманием того, как создаются PE Base Relocations.

Я понимаю, что может быть несколько перемещений, я также понимаю, почему и как это делается, но я просто не понимаю этого программно:

Что из следующего верно (IMAGE_BASE_RELOCATION в WinNT.h)?

// Base relocation #1
DWORD   VirtualAddress;
DWORD   SizeOfBlock; // size of current relocation
WORD    TypeOffset[1];
// Base relocation #2
DWORD   VirtualAddress;
DWORD   SizeOfBlock; // size of current relocation
WORD    TypeOffset[1];
// Base relocation #3
DWORD   VirtualAddress;
DWORD   SizeOfBlock; // size of current relocation
WORD    TypeOffset[1];

Or

DWORD   VirtualAddress;
DWORD   SizeOfBlock; // size of all relocations
WORD    TypeOffset[1]; // relocation #1
WORD    TypeOffset[1]; // relocation #2
WORD    TypeOffset[1]; // relocation #3

Или оба неверны? Как мне программно перебрать все перемещения базы?

В настоящее время у меня есть этот код, который где-то кажется неправильным:

DWORD baseRelocationSize = imageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
            unsigned int baseRelocationCount = baseRelocationSize / sizeof(IMAGE_BASE_RELOCATION);
            DWORD baseDelta = (DWORD_PTR)moduleBase - (DWORD_PTR)imageNtHeaders->OptionalHeader.ImageBase;

            IMAGE_BASE_RELOCATION* baseRelocation = (IMAGE_BASE_RELOCATION*)((DWORD_PTR)moduleBase + (DWORD_PTR)imageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

            for(unsigned int i = 0; i != baseRelocationCount; ++i)
            {
                unsigned int entryCount = (baseRelocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);

                for(unsigned int j = 0; j != entryCount; ++j)
                {
                    WORD* entry = (WORD*)((DWORD_PTR)baseRelocation + (DWORD_PTR)sizeof(IMAGE_BASE_RELOCATION));
                    if((*entry >> 12) & IMAGE_REL_BASED_HIGHLOW)
                    {
                        DWORD* pdw = (PDWORD)((DWORD_PTR)moduleBase + (DWORD_PTR)baseRelocation->VirtualAddress + ((*entry) & 0xfff));
                        (*pdw) += baseDelta;
                    }

                    entry++;
                }

                baseRelocation += baseRelocation->SizeOfBlock;
            } 

person John Smith    schedule 02.07.2013    source источник
comment
Это непросто, правда?   -  person John Smith    schedule 05.07.2013
comment
Переезды - это смешно, кажется, никто не знает, как с ними справиться.   -  person iDomo    schedule 26.07.2013
comment
@JohnSmith ты понял это?   -  person Benny    schedule 19.03.2014


Ответы (2)


Ни один из указанных вами вариантов не является полностью правильным / верным.

Это отличное руководство по Как вставка кода в PE-файл показывает, что реальная структура IMAGE_BASE_RELOCATION:

typedef struct _IMAGE_BASE_RELOCATION {
  DWORD   VirtualAddress;
  DWORD   SizeOfBlock;
} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;

Раздел 5.2 этого Microsoft Portable Спецификация форматов исполняемых и общих объектных файлов описывает структуру. SizeOfBlock-8 фактически указывает, сколько WORD TypeOffset следует после VirtualAddress и SizeOfBlock.

Думаю, вам также будет интересна таблица 7 учебника, в которой показана структура блоков из таблицы перемещений. Я скопирую таблицу сюда для быстрого ознакомления.

введите описание изображения здесь

person Benny    schedule 19.03.2014
comment
Это просто идеально. И последний вопрос, как узнать, сколько там блоков? - person John Smith; 20.03.2014
comment
Номер блока нигде не пишется. Что я делаю, так это блок за блоком, пока текущий адрес не станет равным imageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + imageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size, в этот момент вы знаете, что находитесь в конце раздела .reloc. - person Benny; 20.03.2014
comment
Чтобы быть на 100%, когда вы говорите "The SizeOfBlock-8 actually indicates how many WORD TypeOffset follow after the VirtualAddress and SizeOfBlock", вы должны говорить "The (SizeOfBlock-8) / sizeof(WORD) actually indicates how many WORD TypeOffset follow after the VirtualAddress and SizeOfBlock". Поправьте меня если я ошибаюсь. - person newlog; 26.12.2017
comment
Я проверил ссылку, которую вы разместили. Действительно лучшее описание, которое я нашел в Интернете. Хотя у меня есть один вопрос. Если я получил часть asm внутри ссылки правильно, поле sizeOfBlock включает заполнение 00 00 в конце блока, верно? Хотя это не совсем запись. Кроме того, часть 00 00 существует только для дополнения массива записей до 32 бит и, следовательно, не должна существовать в каждом блоке, верно? - person crush3dice; 07.03.2021

из какого-то кода .. aldo проверить реакцию :)

BOOL FixRelocs(void *base, void *rBase, IMAGE_NT_HEADERS *ntHd, IMAGE_BASE_RELOCATION *reloc,
               unsigned int size) {
    unsigned long ImageBase = ntHd->OptionalHeader.ImageBase;
    unsigned int nBytes = 0;
    unsigned long delta = MakeDelta(unsigned long, rBase, ImageBase);
    unsigned long *locBase;
unsigned int numRelocs;
unsigned short *locData;
unsigned int i;

while(1) {
  locBase =
     (unsigned long *)GetPtrFromRVA((DWORD)(reloc->VirtualAddress), ntHd, (PBYTE)base);
  numRelocs = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);

  if(nBytes >= size) break;

  locData = MakePtr(unsigned short *, reloc, sizeof(IMAGE_BASE_RELOCATION));
  for(i = 0; i < numRelocs; i++) {       
     if(((*locData >> 12) == IMAGE_REL_BASED_HIGHLOW))
         *MakePtr(unsigned long *, locBase, (*locData & 0x0FFF)) += delta;
     locData++;
  }

  nBytes += reloc->SizeOfBlock;
  reloc = (IMAGE_BASE_RELOCATION *)locData;
   }

   return TRUE;

}
person Mike Guidry    schedule 03.08.2013