Вопрос по загрузке PE и распределению в адресов в режиме пользователя. Насколько я знаю, PE-секции выгружаются в общую для всех пользовательских программ область, в зависимости от доступности, и адреса задаются при загрузке в память, но тут вопрос - как происходит адресация внутри программы, раз мы не меняя кода получаем работоспособную программу и при этом можем через ту же память обращаться в адресное пространство других процессов? К примеру, у меня в программе по адресу 0x1 лежит mov ax,bx и когда происходит jmp 0x1 он перекидывает меня именно в мою программу, а не в чужую, при этом я могу прочитать тот же 0x1 другой программы как? И как бы мне выцепить user32 и kernel32 без таблицы импорта, но из своего pe-файла? И чего там ещё интересного можно найти?
Ответ
Насколько я знаю PE-секции выгружаются в общую для всех пользовательских программ область в зависимости от доступности и адреса задаются при загрузке в память
Так было до Windows 3.1 включительно, когда виртуальной памяти попросту не существовало, и разделение производилось по отовсюду доступным сегментам. В современных же операционных системах каждый процесс находится в собственном, изолированном адресном пространстве («песочнице»).
Согласен, если файл (в том числе исполняемый) отображается в несколько процессов в режиме только на чтение и без каких-либо изменений, то операционная система может (но не обязана) сэкономить немного ОЗУ и отобразить соответствующие страницы виртуальной памяти этих процессов в один и тот же регион памяти физической
Однако это всего лишь трюк на уровне отображения виртуальной памяти на физическую силами железа. С точки зрения самих программ никакого общего региона не существует.
к примеру у меня в программе по адресу 0x1 лежит mov ax,bx и когда происходит jmp 0x1 он перекидывает меня именно в мою программу а не в чужую
Перед тем, как переключить выполнение на какой-либо поток вашего процесса, операционная система производит определённую донастройку процессора. В частности, она извлекает из своих внутренних структур физический адрес карты отображения памяти и передаёт его специальному блоку процессора, мапперу
Маппер же использует указанную карту примерно следующим образом:
(Иллюстрация взята из ответа на вопрос «Какую модель памяти сегментную или страничную использует windows, linux, macos?»)
при этом я могу прочитать тот же 0x1 другой программы как?
Надо попросить операционную систему не выделять пустую страницу, как она это обычно делает, а создать привязку к уже существующей странице. Иными словами, как бы прорубить окно в чужое адресное пространство.
Однако отображаемый блок не должен накладываться на уже занятый регион виртуальной памяти вашего процесса. С другой стороны, это окно можно создать в любом месте памяти вашей программы.
Для этого необходимо вызвать системную функцию MapViewOfFileEx(), указав целевой процесс и адрес в его виртуальной памяти.
И как бы мне выципить user32 и kernel32 без таблицы импорта но из своего pe-файла?
LoadLibrary() + GetProcAddress(). Всё остальное — хаки и ненадёжно.
Комментариев нет:
Отправить комментарий