Как управлять порядком сегментов PE в Visual C++

Я пытаюсь написать упаковочную / самораспаковывающуюся программу типа exe, но у меня возникают проблемы с порядком сегментов, созданным компоновщиком Visual C++.

По сути, у меня есть программа-заглушка (загрузчик), в которой определена специальная переменная, подобная этой:

#pragma const_seg(".blah")
const char blah[1];
#pragma const_seg()

И это делает что-то с данными в blah (например, распаковывает данные).

Вторая программа (упаковщик) затем использует программу-загрузчик в качестве шаблона для создания новой программы с некоторыми данными в blah,

В основном упаковщик копирует файл загрузчика, а затем заменяет старый .blah раздел с некоторыми новыми данными. Когда новый файл выполняется, загрузчик работает с этими новыми данными.

Теперь изменение exe-файлов - хитрая работа, поэтому для простоты я бы хотел .blah чтобы быть последним сегментом в файле, чтобы я мог просто добавить данные в загрузчик, а затем исправить несколько полей размера в заголовке PE.

Однако я не могу понять, как контролировать порядок сегментов в компоновщике Visual C++, чтобы поставить .blah в конце файла, когда он компилирует загрузчик.

На данный момент порядок разделов таков:

.textbss
.text
.rdata
.data
.idata
.blah
.rsrc
.reloc

Как вы видете .rsrc а также .reloc находятся не в том месте, они нужны мне раньше .blah,

Что я могу сделать, чтобы изменить этот порядок?

2 ответа

Решение

Я закончил обойти это, не добавляя раздел.java в загрузчик во время ссылки.

Вместо этого упаковщик создает новый раздел.java в конце файла.

Когда загрузчик запускается, он получает свой базовый адрес (из GetModuleHandle), затем анализирует заголовки разделов DOS, NT и, наконец, чтобы получить относительный виртуальный адрес раздела.java.

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

Окончательный адрес раздела определяется путем добавления базового адреса к относительному адресу.

Единственный контроль, который MSVC предоставляет над сегментом, - это возможность создавать собственные и объединять существующие, а также контролировать флаги доступа каждого сегмента, все, что выходит за рамки этого, становится бессмысленным, так как нет никакого установленного правила для упорядочения, таким образом, компилятор может свободно выберите самый простой / легкий вариант.

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

Другие вопросы по тегам