4.1. Адресное пространство процесса
4.1.0. Виртуальная память
Для каждого процесса система Win32 выделяет отдельную память размером ~2Gb, из имеющихся в наличии 4Gb. Пространство это виртуальное и к физической памяти DDR имеет лишь посредственное отношение, поэтому в ОЗУ одновременно могут находиться сразу несколько 2-гигабайтных процессов. По большому счёту, в Р-моде понятие ‘физическая память’ отсутствует как-таковое - им оперирует только ядро ОСи. На машине может быть одна планка DDR размером 512Мб, но для винды всё-равно будет 4Gb виртуальной. От куда берётся столько памяти? Давайте разбираться..
В основе виртуальной памяти лежит идея, что у каждой программы имеется собственное адресное пространство, которое разбивается страницы. Эти страницы отображаются на физ.память, но для запуска программы одновременное присутствие в памяти всех страниц необязательно – большая часть из них ожидают своей очереди на диске. Когда программа ссылается на часть своего пространства, которого на данный момент нет в физ.памяти, ОС генерит исключение Page-Fault и отсутствующая страница подгружается в память с диска, после чего потерпевшая неудачу команда повторяется. Отработавшие страницы выгружаются обратно на диск, в т.н. файл-подкачки ‘pagefile.sys’.
Все линейки NT работают в 'гибридном режиме', когда на сегментную модель накладывается страничная. Размеры страниц могут быть двух типов – 4Кб (стандартная) или 4Мб, если включён режим
4.1.1. Аппаратная поддержка виртуальной памяти
Страничная трансляция включается битом(31) управляющего регистра
Так адресуется глобальное пространство памяти процесса:
При такой схеме памяти, все запускаемые процессы получают одинаковые виртуальные адреса, например базу загрузки образа в память
Чтобы исключить такую ситуацию, система ведёт список адресов физических DRAM-страниц, выделенных для каждого процесса. Этот список назвали MDL - Memory Descriptor List, или ‘таблица распределения физической памяти’. Важно понять, что виртуальный адрес
4.1.2. Секции программы
Пространство каждого процесса делится на секции, по аналогии с сегментами реального режима. Распространённый их список в формате fasm’a приводится ниже:
Обратите внимание, что исполняемой является только секция-кода, которой нужно выставить флаг 'executable'. Политика безопасности Win рекомендует запрещать в неё запись, чтобы предотвратить модификацию кода, но как-всегда это написано ‘вилами на воде’. Fasm – один из немногих компиляторов, который позволяет задавать атрибуты секциям. Эти атрибуты можно комбинировать нужным образом:
На форумах можно встретить советы, мол нужно закрывать доступ на запись в секцию-кода, и если авер обнаружит обратное, мы у него точно окажемся под колпаком. Он посчитает, что код нашей программы занимается само/модификацией, а это присуще вирусам. Попробуем опровергнуть этот миф, и напишем пример такой программы. Это просто смена байта с нуль на 90h, после чего байт превратится в инструкцию NOP (опкод 0x90).
Теперь идём на virusscan и проверяем этот код на малвару.
Как видим, из 15-ти антивирусов никто-ничего не заподозрил и это доказывает,
что само/модифицируемый код и под виндой имеет место быть, а не только под досом:
4.1.0. Виртуальная память
Для каждого процесса система Win32 выделяет отдельную память размером ~2Gb, из имеющихся в наличии 4Gb. Пространство это виртуальное и к физической памяти DDR имеет лишь посредственное отношение, поэтому в ОЗУ одновременно могут находиться сразу несколько 2-гигабайтных процессов. По большому счёту, в Р-моде понятие ‘физическая память’ отсутствует как-таковое - им оперирует только ядро ОСи. На машине может быть одна планка DDR размером 512Мб, но для винды всё-равно будет 4Gb виртуальной. От куда берётся столько памяти? Давайте разбираться..
В основе виртуальной памяти лежит идея, что у каждой программы имеется собственное адресное пространство, которое разбивается страницы. Эти страницы отображаются на физ.память, но для запуска программы одновременное присутствие в памяти всех страниц необязательно – большая часть из них ожидают своей очереди на диске. Когда программа ссылается на часть своего пространства, которого на данный момент нет в физ.памяти, ОС генерит исключение Page-Fault и отсутствующая страница подгружается в память с диска, после чего потерпевшая неудачу команда повторяется. Отработавшие страницы выгружаются обратно на диск, в т.н. файл-подкачки ‘pagefile.sys’.
Все линейки NT работают в 'гибридном режиме', когда на сегментную модель накладывается страничная. Размеры страниц могут быть двух типов – 4Кб (стандартная) или 4Мб, если включён режим
РАЕ – Physical Address Extension. В большинстве случаях страницы 4К-байтные. Такой размер позволяет менеджеру памяти более гибко управлять общим пространством. Размеры сегментов больше, чем размеры страниц и ОС имеет отдельные аллокаторы памяти для каждого из слоёв: Virtual, Local и Heap Alloc. VirtualAlloc() требует выравнивания выделяемых блоков памяти на 64К-байтную границу, т.е. ориентируется на сегменты. LocalAlloc() выделяет память страницами, а HeapAlloc() уже произвольное кол-во байт.4.1.1. Аппаратная поддержка виртуальной памяти
Страничная трансляция включается битом(31) управляющего регистра
CR0. На вход транслятора страниц приходит линейный адрес, который MMU разбивает на 3 части: старшие 10-бит выделяются под каталог страниц (10-бит = 1024 записи PDE), средние 10-бит под таблицу страниц (одна из 1024 страниц PTE), и младшие 12-бит выбирают смещение в странице физической памяти. Страницу физ.памяти назвали Physical Frame, или страничный кадр в памяти DDR-SDRAM. Размеры страничных кадров всегда равны страницам виртуальной памяти, т.е. 4Кб.Так адресуется глобальное пространство памяти процесса:
1024*1024*4096=4Gb. У каждого процесса свой каталог-страниц, линейный адрес которого лежит в его регистре CR3 (PDBR) - Page Directory Base Register. Схематически это выглядит так:При такой схеме памяти, все запускаемые процессы получают одинаковые виртуальные адреса, например базу загрузки образа в память
0х00400000. Если-бы это была не виртуальная память а физическая, то процесс(А) мог-бы запросто затереть данные процесса(В), ведь адрес у них совпадает.Чтобы исключить такую ситуацию, система ведёт список адресов физических DRAM-страниц, выделенных для каждого процесса. Этот список назвали MDL - Memory Descriptor List, или ‘таблица распределения физической памяти’. Важно понять, что виртуальный адрес
0х00400000 процесса(А) отображается на одну физическую страницу DDR, а тот-же адрес процесса(В) отображается уже на другую физическую страницу памяти. Таким образом, процесс(А) никогда не затерёт данные процесса(В), хоть у них и одинаковый виртуальный адрес. Общая схема трансляции адреса от процессора и до физической DRAM, представлена ниже:4.1.2. Секции программы
Пространство каждого процесса делится на секции, по аналогии с сегментами реального режима. Распространённый их список в формате fasm’a приводится ниже:
C-подобный:
section '.code' code (атрибуты) - исполняемый код;
section '.data' data (атрибуты) - инициал.данные (строки и переменные);
section '.bss' data (атрибуты) - неинициал.данные ('0' или '?');
section '.idata' data (атрибуты) - импорт функций;
section '.edata' data (атрибуты) - экспорт функций;
section '.reloc' data (атрибуты) - релокация адресов при смене ImageBase;
section '.rsrc' data (атрибуты) - ресурсы (иконки, курсоры и пр.);
section '.tls' data (атрибуты) - локальная память потока (Thread Local Storage);
section '.rdata' data (атрибуты) - отладочная информация;
section '.marylin' data (атрибуты) - своя секция под барахло.
C-подобный:
executable - исполняемая секция;
readable - секция доступна на чтение;
writable - секция доступна на запись;
discardable - при ограниченной физ.памяти, это первый кандидат на выгрузку в своп;
notpageable - из физ.памяти секцию сбрасывать нельзя! (невыгружаемая);
fixups - авто/коррекция адресов и ошибок;
shareable - расшаренная секция (вреда от которой больше, чем пользы).
C-подобный:
include 'win32ax.inc'
.data
text db 'Самомодификация!',0
;// Открываем секции-кода доступ на запись ---------------------
section '.code' code executable writable ;<-- волшебный атрибут
start: nop
mov byte[@01],90h ; запись в секцию-кода!
@01: db 0 ; модифицируемый байт
invoke MessageBox,0,text,0,0
invoke ExitProcess,0
.end start
Как видим, из 15-ти антивирусов никто-ничего не заподозрил и это доказывает,
что само/модифицируемый код и под виндой имеет место быть, а не только под досом:
Комментарии
59