2016-08-07 3 views
1

Низкоуровневые подробности по связыванию и загрузке программ (PE) в Windows.Низкоуровневые подробности по связыванию и загрузке программ (PE) в Windows

Я ищу ответ или учебное пособие, в котором разъясняется, как программа Windows связана и загружается в память после ее сборки.

Тем более, я не уверен в следующих точках:

  • После того, как программа будет собрана, некоторые команды могут ссылаться на памяти в разделе .DATA. Как эти ссылки переводится, когда программа загружается в память, начиная с какого-либо произвольного адреса? Учитываются ли ссылки RVA и относительной памяти эти проблемы (BaseOfCode и BaseOfData RVA-поля PE-заголовка)?

  • Является ли программа всегда загружаемой по адресу, указанному в ImageBase заголовок поля? Что делать, если загруженный (DLL) модуль указывает одну и ту же базу?

Спасибо,

+0

* «Является ли программа всегда загружается по адресу, указанному в поле заголовка ImageBase? Что делать, если загруженный модуль (DLL) определяет ту же базу?» * - Не отвечает ли этот второй вопрос первым? – IInspectable

+1

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

+0

@HansPassant - не могли бы вы указать мне ресурс по этому вопросу. Кажется, я не могу найти ничего, кроме очень высокого уровня. – Shuzheng

ответ

0

Сначала я собираюсь ответить на ваш второй вопрос: Нет, модуль (будучи ех или DLL) не загружаются в ВСЕГДА базовый адресе. Это может произойти по двум причинам: либо есть еще один загруженный модуль, и нет места для его загрузки по базовому адресу, содержащемуся в заголовках, или из-за ASLR (рандомизация макета адресного пространства), которые означают, что модули загружаются в случайные интервалы для использования смягчающих целей.

Для решения первого вопроса (относится ко второму): Способ определения местоположения памяти может быть относительным или абсолютным. Обычно переходы и вызовы функций относительны (хотя они могут быть абсолютными), которые говорят: «Идите это много байтов из текущего указателя инструкции». Независимо от того, где загружен модуль, будут выполняться относительные переходы и вызовы.

Когда речь идет об адресации данных, они, как правило, являются абсолютными ссылками, то есть «доступ к этим 4-байтным данным по этому адресу». И указан полный виртуальный адрес, а не RVA, а VA.

Если модуль не загружен на своем базовом адресе, абсолютные ссылки будут разбиты, они больше не указывают на правильное место, которое предполагается использовать компоновщику, на который они указывают. Предположим, что ImageBase равен 0x04000000, и у вас есть переменная в RVA 0x000000F4, VA будет 0x040000F4. Теперь представьте, что модуль загружен не в его BaseAddress, но в 0x05000000 все перемещается на 0x1000 байт вперед, поэтому VA вашей переменной на самом деле 0x050000F4, но машинный код, который имеет доступ к функции, по-прежнему имеет старый адрес, жестко запрограммированный, поэтому программа поврежден. Чтобы исправить это, компоновщики хранят в исполняемом файле, где эти абсолютные ссылки на код, поэтому их можно устранить, добавив к ним, насколько исполняемый файл был смещен: смещение дельта, разность между местом загрузки изображения и изображением содержащуюся в заголовках исполняемого файла. В этом случае это 0x1000. Это называется Перемещение базы данных

Иногда модуль не имеет перемещений, поэтому его нельзя загрузить нигде, кроме его базового адреса.См How do I determine if an EXE (or DLL) participate in ASLR, i.e. is relocatable?

Для получения дополнительной информации о ASLR: https://insights.sei.cmu.edu/cert/2014/02/differences-between-aslr-on-windows-and-linux.html

Это на самом деле не совсем верно, вы можете иметь то, что называется позиционно-независимый код. Код создан таким образом, что он будет работать в любом месте в памяти без необходимости того, чтобы загрузчик выполнял базовые перемещения. Это очень распространено в общих библиотеках Linux, и это делается для сопоставления данных относительно. В x64 имеется относительная адресация RIP, такая же, как для адресации кода (доступ к этому элементу данных на этом расстоянии от указателя инструкции), в x86 трюк используется для получения содержимого указателя инструкции, а затем для вычисления VA переменной, добавляя к ней постоянное смещение. Это очень хорошо объяснено здесь: https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html

Я не думаю, что ПИК код является общим в Windows, чаще всего, модули для Windows содержат базовые переезды, чтобы исправить абсолютные адреса, когда он будет загружен в другом месте, чем его предпочитаемая база адрес, хотя я не совсем уверен в этом последнем абзаце, поэтому возьмите его с солью.

Подробнее:

http://opensecuritytraining.info/LifeOfBinaries.html

How are windows DLL actually shared? (немного сбивает с толку, потому что я не объяснить себя хорошо, когда задают вопрос).

https://www.iecc.com/linker/

Я надеюсь, что я помог :)

Смежные вопросы