Кое-что об устойчивости и защищенности Windows CE на ARM-платформе — Архив WASM.RU

Все статьи

Кое-что об устойчивости и защищенности Windows CE на ARM-платформе — Архив WASM.RU

     Надеюсь, не найдется человека, который никогда не слышал о таких нелепых дырах в защите Win 9x, как незащищенные системные структуры и последствия к которым приводит такая халатность (создание своего callgate-а в таблице дескрипторов, или запись в незащищенные таблицы страниц). В данной статье будет проведено небольшое исследование, посвященное аналогичным проблемам WinCE на ARM v5 - платформе. Почему именно на ARM? Во-первых, потому что другой просто нет под рукой. Во-вторых, это чуть ли не самая распространенная на сегодняшний день платформа для КПК (последние процессоры Intel xScale и Samsung используют именно эту архитектуру).

     Для начала придется рассмотреть основные защитные механизмы ARM, использующиеся на аппаратном уровне. По ходу дела будут приводиться аналогии (иногда не совсем удачные) архитектуры x86 (Intel).

Наверное, у всех слово «сопроцессор» так или иначе ассоциируется с обработкой чисел с плавающей запятой. Однако, на самом деле «сопроцессор» гораздо более обширное и глубокое понятие. Так, все управляющие структуры (аналоги регистров CRn в x86) в ARM расположены в регистрах сопроцессоров.

Кстати, ARM поддерживает до 16 сопроцессоров.

Только два сопроцессора (CP0 и CP1) отвечают за обработку чисел с плавающей запятой.

Сопроцессор управления системой (System Control Coprocessor) CP15 (можно назвать аналогом CR-регистров в x86) отвечает за управление внутренней архитектурой (MMU, кэш, буфера), в том числе и защитными механизмами. Состоит он из 15 регистров. Я не буду приводить здесь структуры этих регистров, т.к. по сути статья превратиться в мануал по ARM-у, а затрону только защитные аспекты.

Структуры, отвечающие за аппаратную защищенность в ARM v5:

Запись вида CPn_CRm [x:y] означает «биты [x:y] регистра CRm в сопроцессоре CPn»

Название

Где

Mode bits in Current Program Status Register

CPSR [4:0]

ROM protection bit (R)

CP15_CR01 [9]

System protection bit (S)

CP15_CR01 [8]

Memory management unit enable/disable (M)

CP15_CR01 [0]

Domain Access Control Register

CP15_CR03 [31:0]

Coprocessor Access Register

CP15_CR15 [13:0]

Access Permissions

TTE

Mode bits in Current Program Status Register – 5 бит в регистре CPSR (Current Program Status Register). Раньше эти биты (а также другие– аналоги флагов из EFLAGS: ZF, CF и т.п.) находились в регистре R15 (PC) (аналог EIP), но с переходом на 32-битную адресацию гордо вынесены в отдельный регистр (R16 – CPSR). Вот молодцы все-же ребята из Acorn – не пошли они по аналогиям Intel-овских Франкенштейнов.

Аналогом «битов режима» в x86 могут послужить биты CPL из селектора CS. Как видим, разнообразие режимов по сравнению с x86 довольно велико. Более того, мы можем добавлять свои собственные режимы! Так Intel и поступило в своем xScale, добавив новый отладочный (debug) режим. Видите насколько более профессиональна и гибка ARM-архитектура по сравнению с x86?

ROM protection bit (R)

System protection bit (S)

Два этих бита рассматриваются только на пару с битами Access Permissions из записей таблиц трансляций (аналоги каталогов и таблиц страниц на x86). Вот нехитрая табличка:

AP

S

R

Привилегированный режим

Режим пользователя

00

0

0

нет доступа

нет доступа

00

1

0

только чтение

нет доступа

00

0

1

только чтение

только чтение

00

1

1

-

-

01

x

x

чтение/запись

нет доступа

10

x

x

чтение/запись

только чтение

11

x

X

чтение/запись

чтение/запись

Memory management unit (M) – бит отвечает за включение/выключение модуля управления памятью (MMU). Одной из важнейших функций MMU является преобразование логических адресов в физические.

Аналогично в x86 бит 31 в CR0 отвечает за включение страничной адресации памяти.

Однако, в ARM-архитектуре вообще нет понятия сегментной организации памяти – при отключении MMU логический адрес = физическому.

Intel-у пришлось тянуть сегментные регистры из реального режима… бедняги.

Пара слов о самом механизме преобразования виртуальных адресов в физические: точно так же, как и в x86 существует две таблицы трансляции адресов (первого и второго уровней).

Кстати, таблицу трансляции первого уровня Intel-овцы у себя окрестили «Каталогом страниц».

Физический адрес таблицы преобразования первого уровня хранится в регистре CP15_CR2.

Аналог CP15_CR2 в x86 – регистр CR3.

Domain Access Control Register – 32-х разрядный регистр, содержащий права доступа к 16 возможным доменам (по два бита на домен). Домен (domain) – набор секций, больших и малых страниц памяти, права доступа к которым можно быстро изменить с помощью записи в этот (CP15_CR03) регистр. Т.е. каждой странице (либо секции, см. дальше что такое секция) мы указываем, к какому домену она принадлежит (в записях таблиц трансляций). Затем, при желании, изменяя всего два бита в регистре DACR мы можем изменить права доступа хоть ко всей памяти.

Секция (section) – область памяти размером 1Мб, доступная через одноуровневый механизм преобразования адреса.

Аналог x86: адресация с использованием 4Мб страниц.

Страница (page) – область памяти размером 1 (tiny), 4 (small) либо 64 (large) Кб.

Coprocessor Access Register – 32-х разрядный регистр, содержащий права доступа к 16 возможным сопроцессорам (точнее к его регистрам) - по одному биту на сопроцессор. Старшие 16 бит – зарезервированы. 16 младших и отвечают за 16 сопроцессоров. Хочется отметить, что биты 14 и 15 ВСЕГДА равны нулю. Что сие означает? А означает это то, что доступ к сопроцессорам 14 и 15 (CP14 и CP15) не может регулироваться этим регистром и возможен только в режиме с системными привилегиями.

Access Permissions

См. табличку к битам R и S. Стоит только отметить, что AP при использовании секций задается в таблице трансляции первого уровня, а при использовании страниц – в таблице второго уровня, причем в этом случае задается сразу четыре разных значения AP – каждое отвечает за свою четверть области страницы.

Итак, приступим. Обязательно следует отметить, что эксперименты проводились на КПК Toshiba e755 с PocketPC 4.20.1081 (build 13100). Почему это так важно? Да потому, что вся манера поведения (в том числе и защитная) встроенных ОС целиком и полностью зависит от OEM (Original Equipment Manufacturer), т.е. в данном случае от программистов из компании Toshiba. Имеется ввиду следующее: тактику поведения ОС по отношению к чужеродным (user-level) программам определяют параметры, заданные при компиляции окончательного билда (я имею ввиду такие механизмы, как установки флагов ROMFLAGS в секции CONFIG, полноценное использование функции OEMCertifyModule, и т.п.).

Несколько слов о механизме OEMCertifyModule. Дело в том, что изначально, при проектировании окончательного билда, OEM может задать т.н. доверительные программы, расположив их в секции MODULES. Только эти программы могут использовать все API и имеют привилегии. Остальным недоступна целая группа API-функций (т.н. Trusted API), полный список которых приведен в MSDN-е. При загрузке любого процесса загрузчик передает управление на функцию OEMCertifyModule, в которой производится проверка загружаемого процесса на «доверительность» - по определенным сигнатурам в заголовке.

Т.о. во всех защитных слабостях виноваты только программисты, компилирующие ядро под определенное устройство, и никто больше, т.к. ни ARM, ни WinCE (?) сами по себе не содержат уязвимостей по крайней мере на уровне OAL. Поэтому интересно было бы провести подобные исследования на КПК от других производителей.

Итак, попробуем почитать что-нибудь по адресу 0x80000000:

ldr  R0, =0x80000000
ldr  R1, [R0]

Хе… нет проблем! Никаких Access Violation! И вот что повергает в «легкий трепет» с самого начала: ВСЕ процессы WinCE запускает в привилегированном режиме (privileged-mode)! Где-то мы все это уже наблюдали…

Для справки: в ARM-процессорах привилегированным режимом называется ЛЮБОЙ режим, отличный от пользовательского (user-mode).

Проверить сие очень просто: мы можем свободно пользоваться ЛЮБЫМИ привилегированными инструкциями, а также читать/писать в регистры CP15. Как думаете, что произойдет если процессу, к примеру, вздумается изменить себе адрес таблицы преобразования первого уровня? Или вовсе отключить MMU? Пожалуйста! Ничего ужасающего не произойдет (хотя бы потому, что ОС сидит в ROM-е и всегда на помощь придет Hard Reset) – просто все очень крепко зависнет.

Виснет КПК довольно прозаично: никаких BSOD, просто на дисплее замирает последний кадр и подсветка остается в том состоянии, в котором была на момент ошибки – и все. Оживить его можно только утопленной сбоку кнопочкой Soft Reset-а.

Проверим, с какими привилегиями работает наш процесс:

MRS  R0, CPRS
R0=0x1F

Хм, интересно… Смотрим табличку:

M[4:0]

Режим

Описание

10000

User

Пользовательский режим (аналог процесса с CPL=3 в x86).

10001

FIQ

Режим «быстрой» обработки прерывания. Т.е. когда время на обработку прерывания сверхкритично! FIQ может «перебить» IRQ, но не наоборот.

10010

IRQ

Режим, в который процессор переключается после прихода сигнала прерываний (от клавиатуры, дисковода, таймера и т.п.).

10011

Supervisor

Режим супервизора (аналог процесса с CPL=0 в x86).

10111

Abort

В этот режим процессор входит после ошибок (что-то типа #GP).

11011

Undefined

Аналог #UD на x86 (Invalid Opcode Exception)

11111

System

Привилегированный режим пользователя

В xScale, как уже упоминалось выше, добавлен еще один – debug (0x15) режим.

У нас последний случай (0x15), т.е. процесс запускается в привилегированном режиме System. Что это за режим? System – это некий промежуточный уровень между Supervisor и User режимами. Т.е. мы уже не пользователь со связанными ногами, но еще и не супервизор. Кстати сказать, практически никакой разницы между System и Supervisor-ом нет – лишь в теории в будущих модификациях ARM-а System-режиму могут порезать привилегий.

Что ж, попробуем повысить себе уровень до супервизора:

MRS 	R0,CPSR 		; CPSR -> R0
BIC 	R0,R0,#0x1F 	; очистим биты режима
ORR 	R0,R0,#0x13 	; режим Supervisor-а
MSR 	CPSR_C,R0 	; R0 -> CPSR

Как думаете, что произошло после MSR CPSR_C,R0 ??? Мда… похоже WinCE по любому поводу впадает в глубокую кому. Не понимаю, как она вообще работать может…

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

Поехали дальше. Команды CPS (изменить биты режима в CPRS) на ARM v5 еще не было, она появилась только на v6.

Есть еще один способ получить супервизора – через SWI. SWI (Software Interrupt) механизм вызова программных прерываний, что то типа INT на x86. При этом мы автоматически получаем супервизора. Проблема только в том, что мы не знаем какое именно прерывание даст нам супервизора. И вообще, не нужен нам никакой супервизор – мы и так обладаем всеми возможными привилегиями.

Попробуем посмотреть, что у нас с доменами.

mrc  P15, 0, R0, C3, C0, 0

Ну слава Богу! Хоть здесь нули! Кстати, ничего не мешает нам исправить их на единицы, что мы и проделаем:

mvn	R0, #0
mcr	P15, 0, R0, C3, C0, 0

Ну вот и все – теперь защита на уровне доменов отключена.

Вообще я в замешательстве – о чем думали производители? На кого может быть рассчитана система, где любой процесс может творить что ему угодно, причем обработкой исключений никто не хочет заниматься? Полнейшая анархия!

Позже, на XDA-developers.com я обнаружил старую статью об управлению памятью – там мужик поднимает точно такие-же проблемы.

Ладно, вернемся к программированию. Тут вы можете скачать мою прогу по конвертации виртуального адреса в физический. Обратите внимание, что все секции (страницы) расположены в нулевом домене. Все секции имеют AP = 1, т.е. мы с нашими привилегиями можем гадить в любые адреса. Программа работает с одним ограничением – обрабатывает только секции. Обработать страницы мне не удалось по простой причине – VirtualCopy в большинстве случаев просто вешает систему, причем происходит это с каким-то мерзким пост-эффектом, когда система виснет на второй, а то и на третий VirtualCopy. Позже по данной теме в нете я обнаружил чела с теми же проблемами – его пост в форуме датирован 2002 годом, и там он утверждал, что на какой-то модели Casio VirtualCopy работало нормально. В любом случае, в исходнике есть строка, помеченная как “comment me”. Попробуйте запуститься, закомментировав эту строку и напишите о результатах в обсуждениях.

Хотелось бы поведать об одном кошмаре программиста на ассемблере под PocketPC – программа запускается и прекрасно работает на устройстве (!) под отладчиком, однако при запуске непосредственно на устройстве (без отладчика) либо, как вы уже догадались, все виснет, либо просто ничего не происходит. К обнаруженным мною подобным причудам можно отнести следующую:

- в маленьких прогах я не создаю секции данных, а располагаю их в секции кода, задав ей атрибуты RWE. Так вот я с самого начала забыл про эти атрибуты и что удивительно – при запуске под отладчиком ему плевать на атрибуты секции, он как то сам то ли по уму то ли по глупости разрешает запись в сегмент кода (при загрузке в устройство сам выставляет атрибуты). Естественно, загрузив прогу без отладчика мне долго пришлось выискивать проблему.

Также очень намучился со следующим - в исходнике есть код, по типу такого:

	…
BL	PROC1
	…

PROC1
	…
	BL	PROC2
	…
	mov	PC,LR

PROC2
	…
	mov	PC,LR

По привычке, руководствуясь интеловской психологией, я как-то совершенно не задумывался о выходе из вложенных процедур – у интела нужный адрес всегда на вершине стека и мы выходим по ret-у. Из-за того, что в ARM-е адрес возврата сохраняется в регистр R14 (LR) во вложенных процедурах в начале нужно сохранять старое значение LR. Опять же, пустяковая ошибка, но нервов попортила немало.

     Ну что еще по мелочи – по аналогии с *nix если параметров слишком много (больше четырех), то часть из них передается в стеке.

Да, стоит также отметить, что в WinCE по GetLastError ничего кроме 0x57 (неверный параметр) вы не добьетесь.

P.S. Сколько же мата было в сторону пресловутого OEM за невозможность Hard Reset-нуть КПК без доставания из крэдла… (утопленная кнопка расположена сбоку и закрывается пластмассовой стенкой). После примерно полсотни зависаний процесс сброса КПК начал проводится с особым остервенением – честно говоря, не ожидал что КПК выживет к концу статьи. Один раз произошла вообще уникальная вещь – после очередного VirtualCopy КПК завис так, что даже Hard Reset не помогал – пришлось полностью убивать всю систему переключателем.

P.P.S. Пара слов о вирусах под WinCE. До сих пор якобы не зарегистрировано ни единого вируса для WinCE. Такая ситуация казалась мне довольно непонятной, т.к. как не может быть ни единого вируса в такой, во-первых, уязвимой системе как WinCE, а во вторых – хочешь не хочешь, а запиши свой код во все файлы в текущей директории и тебя окрестят вирусом. Только мне захотелось «прославиться» на этом поприще, как вдруг абсолютно случайно зайдя на сайт pocketnow.com обнаружилось, что сегодня (!) (19 июля 2004 года) был создан первый вирус под PocketPC (парнем из 29A) J. Тут же в yahoo по запросу Windows CE virus первые пять ссылок указывают на этот замечательный случай (хотя еще вчера не было ни одной по теме). Я не удивлюсь, если о нем еще будут неделю трубить по всем новостям. Ну что ж, единственный шанс прославиться безвозвратно упущен… ). Вирус, кстати, довольно безобиден, и даже сам спрашивает у пользователя, можно ли ему нашалить в системе. Но ничего, думаю троян произведет гораздо больший эффект. Заодно можно будет узнать, сколько же людей в мире пользуются инетом через КПК. Кто хочет поучаствовать и у кого есть определенный опыт и интерес к удаленному администрированию – прошу в соавторы (хоть срок мотать вместе не скучно будет J).

Ссылки:

ARM Architecture Reference Manual.pdf (можно БЕСПЛАТНО(!) заказать диск со всей документацией к ARM-у с сайта www.arm.com, в Украину первым классом летит три дня!!!)

MSDN (ну эта забесплатно и с места не сдвинется)

2002-2013 (c) wasm.ru