2015-09-03 2 views
1

В настоящее время я работаю над тем, что требует от меня удалить раздел из исполняемого файла в формате PE. Сначала я только что удалил IMAGE_SECTION_HEADER, изменил поле NumberOfSections в IMAGE_FILE_HEADER, пересчитал SizeOfImage/SizeOfHeaders в IMAGE_OPTIONAL_HEADER и переместил необработанный адрес следующих разделов по необработанному размеру удаленной секции. Однако Windows отказалась загрузить файл с сообщением об ошибке «XXX не является допустимым приложением Win32». Некоторое время я боролся, но пытался также перемещать виртуальный адрес следующих разделов по виртуальному размеру удаленных разделов, и все работает нормально.Почему виртуальные адреса раздела должны быть непрерывными?

В чем причина того, что виртуальные адреса должны быть непрерывными и не может быть пробелов? Я попытался прочитать официальную документацию PE, но безуспешно. Я всегда думал, что не имеет значения, какие адреса имеют отдельные разделы, если значение имеет значение ValueOfImage.

+0

Вы пытались сравнить результаты 'dumpbin' от трех файлов? – Luaan

+0

И я только что протестировал - у вас могут быть промежутки между разделами RVAs. На самом деле они могут даже перекрываться. Однако они всегда должны быть в порядке RVA, но не должны быть проблемой, если вы просто * удаляете разделы. – Luaan

+0

Могу ли я спросить вас, как вы протестировали это? Я пытался воспроизвести описанное вами поведение, но безуспешно. –

ответ

1

Большинство приложений не должны иметь большие промежутки между разделами - те, которые делают, могут использовать отдельные библиотеки DLL или динамически распределять память через VirtualAlloc.

ОБНОВЛЕНИЕ: после большего количества испытаний я обнаружил, что промежуток между разделами должен быть соответствующим, чтобы выровнять следующий раздел, чтобы удовлетворить требованиям SectionAlignment. Следовательно, расстояние между двумя 4096-байтовыми секциями размером 0x20000 байт требует установки поля sectionAlignment всего exe в 0x20000. (Расстояние между, скажем, 0x12000 невозможно.) Этот разрыв в 128 КБ не отображается на карте памяти процесса и не потребляет памяти, но VirtualAlloc все равно будет терпеть неудачу с ERROR_INVALID_ADDRESS, если вы попытаетесь выделить память в промежутке.

Вот минимальный тестовый пример для GCC/MinGW, демонстрирующий, что разделы в Win32 exe должны быть смежными.

testcase.S:

.global _main 
.section .text 
_main: 
    push $1 
    call [email protected] 
    xor %eax, %eax 
    ret 

.section .bss 
    .lcomm buf, NUMBYTES 

Это создает действительный исполняемый файл:

gcc -m32 -Wl,--image-base=0x00400000 -Wl,-Ttext=0x00401000 -Wl,-Tbss=0x00402000 -DNUMBYTES=0xfe000 -Wl,--section-start=.idata=0x00500000 -s -nostartfiles -o contiguous.exe testcase.S

Это производит неверный исполняемый (gap.exe не является допустимым приложением Win32):

gcc -m32 -Wl,--image-base=0x00400000 -Wl,-Ttext=0x00401000 -Wl,-Tbss=0x00402000 -DNUMBYTES=0x200 -Wl,--section-start=.idata=0x00500000 -s -nostartfiles -o gap.exe testcase.S

Сравнивая с шестнадцатеричным редактором и objdump, разница между этими двумя файлами составляет только 16 байт. Что изменилось:

  1. Временная метка (изменение 4 байта).
  2. Контрольная сумма (изменение 4 байта).
  3. Размер секции .bss (смена 8 байтов). В contiguous.exe раздел .bss имеет размер 0xfe000 байт, а в файле gap.exe .bss-файл имеет размер 0x200 байт, создавая промежуток в размере 0xfc000 байт между ним и секцией .idata.
Смежные вопросы