<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Волчьи IT-мысли &#187; Программирование</title>
	<atom:link href="http://sww-it.ru/category/programming/feed" rel="self" type="application/rss+xml" />
	<link>http://sww-it.ru</link>
	<description>Компьютерная безопасность, IT, антивирусная индустрия.</description>
	<lastBuildDate>Wed, 18 Jan 2012 11:20:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Ring-3 руткиты</title>
		<link>http://sww-it.ru/2011-04-21/528?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ring-3-%25d1%2580%25d1%2583%25d1%2582%25d0%25ba%25d0%25b8%25d1%2582%25d1%258b</link>
		<comments>http://sww-it.ru/2011-04-21/528#comments</comments>
		<pubDate>Thu, 21 Apr 2011 09:04:30 +0000</pubDate>
		<dc:creator>priv8v</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[anti-rootkit]]></category>
		<category><![CDATA[ring-3]]></category>
		<category><![CDATA[rootkit]]></category>

		<guid isPermaLink="false">http://sww-it.ru/?p=528</guid>
		<description><![CDATA[<p>Публикую статью автора priv8v. Мнение редакции может не совпадать с мнением автора и т.д. и т.п.</p> <p align="justify">Казалось бы, что о user-mode руткитах уже все давно сказано, и добавить тут нечего. С распространением зловредных драйверов все внимание антивирусных специалистов и хакеров переключилось туда, поэтому ring-3, по крайней мере, на три года остался практически без внимания&#8230; [...]]]></description>
			<content:encoded><![CDATA[<p><em>Публикую статью автора priv8v. Мнение редакции может не совпадать с мнением автора и т.д. и т.п.</em></p>
<p align="justify">Казалось бы, что о user-mode руткитах уже все давно сказано, и добавить тут нечего. С распространением зловредных драйверов все внимание антивирусных специалистов и хакеров переключилось туда, поэтому ring-3, по крайней мере, на три года остался практически без внимания&#8230; А зря. Появились новые технологии, новые методы защиты и нападения. Если задуматься, то изменились даже некоторые цели у конкретных технологий, поменялось поведение зловредов на компьютере, изменился и их внешний облик &#8212; теперь некоторые из них имеют красивые кнопочки и &#171;ищут вирусы&#187;. На этой ноте стоит прекратить ностальгировать и приступить непосредственно к изложению темы.</p>
<p><span id="more-528"></span></p>
<p align="justify">Открыв любую статью пятилетней давности про руткиты можно прочитать о том, что использование rootkit-технологий имеет перед собой две цели: скрытие вредоноса на ПК и усложнение его удаления (второе является следствием первого). На сегодняшний день эта информация неактуальна: удалить библиотеку/ехе-файл с диска (при условии его сигнатурного детектирования) для нормального антивируса не является проблемой, а найти его&#8230; собственно, его искать и не требуется, при работе с уровня ядра антивирус даже не будет и подозревать, что это скрытые файлы. В таком случае можно задаться вопросами:</p>
<ul>
<li>зачем применять сегодня user-mode руткиты?</li>
<li>целесообразно ли это?</li>
<li>а они часом не вымерли?</li>
</ul>
<p align="justify">Применять их можно для скрытия чего-либо на компьютере пользователя и при отсутствии сигнатурного детекта со стороны антивируса, есть возможность оставаться незамеченным сколь угодно долгое время, даже если пользователь является продвинутым и знает что такое антируткит – о том, как этого добиться далее и пойдет речь.</p>
<p align="justify">Для начала необходимо кое о чем договориться и сделать некоторые допущения:</p>
<ul>
<li>в статье не будет рассмотрен обход эмуляторов и поведенческих анализаторов;</li>
<li>обход антивирусного эвристического/сигнатурного детекта также не рассматривается;</li>
<li>основное внимание будет уделено сплайсингу;</li>
<li>в статье будет использована анти-script-киддис защита;</li>
<li>панды бамбук не курят, они им питаются;</li>
</ul>
<p align="justify">При разговоре о руткитах просто нельзя ничего не сказать о драйверах, тем более, когда не планируешь уделить им даже строки. Создание и использование Kernel-mode руткита сопряжено с определенными трудностями, из-за которых они не смогли полностью вытеснить с рынка собратьев на два кольца выше:</p>
<p><br /></p>
<p><strong>
<p align="justify">Сложность написания</p>
<p></strong></p>
<p align="justify">Конечно, можно воспользоваться готовыми исходными кодами из интернета/книг/статей, но на них, скорее всего, будет детект всеми возможными способами (начиная от сигнатурного) и подобный руткит будет расстреливаться из главных орудий еще на подлете, поэтому готовые исходные коды или модифицируются, или заново переписываются, что в любом случае сложнее этих же манипуляций с сорцами пользовательского режима.</p>
<p><br /></p>
<p><strong>
<p align="justify">Обход HIPS</p>
<p></strong></p>
<p align="justify">Каждая вторая антивирусная компания под &#171;HIPS&#187; понимает что-то свое (несмотря на то, что расшифровка аббревиатуры у всех одинаковая). У кого-то вообще этой технологии нет, у кого-то есть только галочка в настройках (типа &#171;Да, по умолчанию использовать эту супер-HIPS&#187;), но у многих эта технология присутствует и включает в себя анализ поведения и эмуляцию кода. Говоря простым языком, могут быть проблемы с установкой драйвера, т.к некоторые комбайны спрашивают совета у пользователя даже если драйвер пытается ставить доверенное приложение. Если вы не найдете какого-нибудь неведомого способа установки драйвера, то ядра вам не видать как своих ушей (и зеркало при проникновении в ring-0 не поможет). Хотя в последнее время и наблюдается некий мнимый упадок технологий в этой области, связанный с прогибом антивирусов под знания среднего юзера.</p>
<p><br /></p>
<p><strong>
<p align="justify">&#171;Бельмо на глазу&#187;</p>
<p></strong></p>
<p align="justify">Если вы будете использовать какие-то давно известные и проверенные rootkit-технологии, то обязательно будете обнаружены даже простеньким антируткитом (например, пандой). Поэтому без чего-то нового наедятся скрыться от Gmer&#8217;a, или AVZ с его километровым логом, просто бессмысленно.</p>
<p><br /></p>
<p><strong>
<p align="justify">Права на установку драйвера</p>
<p></strong></p>
<p align="justify">Для установки драйвера должны быть соответствующие права в системе, при их отсутствии, конечно, можно попытаться воспользоваться эксплоитом для повышения прав, но это создает дополнительные трудности.</p>
<p><br /></p>
<p><strong>
<p align="justify">Различия систем</p>
<p></strong></p>
<p align="justify">Прежде всего, это связано с увеличением популярности Windows 7 и х64-систем.</p>
<p align="justify">Современные антируткиты можно условно разделить на две категории:</p>
<ul>
<li>Рассчитанные на продвинутых пользователей. Это целые комбайны для убийства и извращений. Они показывают перехваты с подробной информацией о них, позволяют их снимать, могут работать с реестром, файловой системой, причем сами делают их разбор. В качестве примера можно привести Gmer или XueTr.</li>
<li>Рассчитанные на User Classic  &#8212; как правило, имеют пять кнопок, включая &#171;выход&#187; и &#171;справка&#187;, еще две это &#171;найти&#187; и &#171;уничтожить&#187;, а пятая кнопка не всегда и имеется. Подобные утилиты ничего не показывают пользователю, просто ищут скрытые на их взгляд файлы/ключи/процессы и предлагают их прибить. Образчиком этой категории может быть антируткит от Panda.</li>
</ul>
<p align="justify">Пару слов необходимо сказать пару общих слов о том, какой антируткит, где ищет и что отображает пользователю: Rootkit Unhooker и Gmer просматривают на предмет хуков все процессы в системе и ищут перехваты во всех функциях (хотя могли бы проверять только критичные) – находят даже перехват MessageBox’a. Идентифицируют тип перехвата достаточно четко (&#8230;Jump, PushRet и т.д) и указывают полный путь до библиотеки с кодом перехватчика. С помощью XueTr можно получить аналогичную информацию, только метод перехвата будет описан не столь подробно (inline, и все тут&#8230;).</p>
<p align="justify">Но анализировать перехваты в ring-3 умеют не все антируткиты (зачем руки-то марать?), к примеру, Vba32 AntiRootKit является одним из лучших на сегодняшний день антируткитов и находит хитрые заковырки в ядре, но в ring3 не видит ничего. Аналогично и DwShark.</p>
<p><br /></p>
<p align="justify">Для начала зададимся вопросом о том, как скрыть или замаскировать перехваты от тех немногих программ, которые их все-таки показывают, и рассмотрим несколько способов:</p>
<p align="justify"><strong>1)</strong> Антируткит, как правило, не может распознать какой перехват «хороший», а какой нет. Под «хорошим» имеется в виду перехват, установленный каким-либо вполне законным приложением (например, антивирус). И весь груз ответственности за вынесения вердикта свой/чужой остается на долю пользователя, который это делает либо сам, либо с помощью коллективного разума на форуме. Именно поэтому имеет право на жизнь такой глупый способ маскировки как расположение внедренной dll по похожему на лигитимный пути, а не в папку темп или в system32 с рандомным названием. Чем плохо: C:\Program Files\Agnitum\нормальное_имя.dll – подсмотреть пути, подсмотреть названия и все. При этом к библиотеке можно даже через редактор ресурсов прилепить описание и в отчете антируткита будет видно именно оно.</p>
<p align="justify"><strong>2)</strong> Перехват можно сделать целевым – в определенном процессе/процессах. Или наоборот – внедряться во все процессы, кроме строго определенных. Благодаря этому про какие-то скрытые объекты антируткит не будет и знать – если в его приложение-дразнилку ничего не внедрено и не перехвачено, то и отличий от того, что спущено свыше (с уровня ядра, хотя правильнее будет сказать «сниже», но такого слова нет) с уровня ядра не будет, то есть в системе все будет видно со всех уровней, а раз ничего антируткит не нашел скрытого, то и панику поднимать не будет. Естественно, не защита от всех антируткитов, Gmer’а этим не смутить.</p>
<p align="justify"><strong>3)</strong> На всех компьютерах с защитным ПО обязательно будут какие-то перехваты, и практически всегда, хоть небольшая часть из них (для разных целей) зиждется на ring-3 перехватчике. Поэтому будет просто некультурно не воспользоваться этим. Идея в маскировке наших перехватов под перехваты библиотеки антивируса, а там попробуй, разберись какие функции и зачем какой антивирус перехватывает. Поэтому свой jmp мы будем ставить не на свою библиотеку, а на хорошую библиотеку ав-продукта, а уже в ней будет стоять jmp на код в нашей библиотеке.</p>
<p>Перехватываемая API-функция: jmp good_library.address<br /><br />
good_library.address: jmp our_evil_library.address<br /></p>
<p align="justify"> В антирутките данный перехват будет выглядеть как родной для этого антивируса, и обнаружить подвох можно будет только при детальном изучении вручную с отладчиком в руках. Такой изврат не раскусывает ни один антируткит.</p>
<p align="justify"><strong>4)</strong> Насколько много приложений работает с системой не прямыми вызовами API-функций, а, используя функции языка программирования, на котором они написаны? Много. Вызов API-функции несомненно будет, но не сразу, поэтому и перехват можно делать в этой самой надстройке. Наиболее наглядный пример можно привести из языка С: при перехвате функции printf в библиотеке msvcrt.dll перехват не углядел ни Gmer, ни Rootkit Unhooker, при этом XueTr гордо опознал перехват и даже имя перехваченной функции. Надеюсь, что данная мысль понятна без дальнейших примеров с другими языками.</p>
<p align="justify"><strong>5)</strong> Для лучшего понимания следующего способа сокрытия перехватов необходимо рассмотреть то, как их обнаруживают.</p>
<p align="justify">Антируткит делает допущение, что лежащая на диске в system32 библиотека оригинальна, а так как все модификации ее функций находятся исключительно в памяти процессов, то механизм работы в упрощенном виде выглядит так: прочитать библиотеку с диска, принять ее за эталон чистоты и, перебирая процессы сравнивать код библиотеки в адресном пространстве с эталоном и при обнаружении отличий пытаться опознать в них метод перехвата, адрес куда ведет перехват и приложение, в которое перехват привел, таким образом антируткит покажет расхождение между оригиналом и тем, что в памяти (перехват) и куда совершается прыжок (перехватчик).
</p>
<p align="justify">Как вы уже догадались, вектор атаки будет направлен как раз на сделанное допущение:</p>
<ul>
<li>Библиотека патчится не только в памяти, но и на диске (предварительно скопированная).</li>
<li>После отключения WFP оригинал заменяется патченной. В зависимости от того, как будет реализовано отключение WFP и как выполнен перехват (в скольких процессах, как сделана обработка и т.д) библиотека заменяется на патченную или только на время работы антируткита, или на относительно вечно (здесь можно послать привет установке глобальных перехватов в user-mode).</li>
</ul>
<p align="justify"><strong>6)</strong> Если jmp отодвинуть от начала функции, к примеру, байт на 30, то Gmer все равно будет видеть перехват и правильно его отображать. Rootkit Unhooker перехват также будет видеть, но имя функции не отображает (будет показывать dll_name.dll+xxx).<br />
Следует помнить, что Gmer ругается даже при изменении одного байта в функции.</p>
<p align="justify"><strong>7)</strong> Замаскировать перехватчик. Если адрес нашего обработчика на начале функции класть в стек, а потом выполнять ret или просто поставить на него jmp, то не стоит удивляться, если антируткит покажет, куда ведет перехват, но если адрес немного обработать (прибавить, отнять, поболтать по регистрам), то это даст результат – перехватчик не будет определен.</p>
<p align="justify">Выше были рассмотрено пассивное противодействие антируткитам, но известно, что лучшая защита это нападение&#8230;</p>
<p align="justify">Философия примерно такая: в зависимости от способа противодействия собирается информация о популярных антируткитах (имена исполняемых файлов/библиотек/драйверов, классы/имена окон и т.д), затем пишется функция обнаружения руткит-детекторов в системе и разработка методов борьбы с ними. </p>
<p align="justify">При грубой реализации эти методы направлены не на скрытие себя в системе, а на противодействие удалению, т.е пользователь будет знать, что какая-то зловредная живность на ПК имеется и она мешает работе лечащих утилит, при более тонком исполнении пользователь или не заметит ничего подозрительного или спишет на &#171;глюки&#187;.</p>
<p align="justify">Рассмотрим пару приемов этого противостояния.</p>
<p><br /></p>
<p align="justify"><strong>Блокировка запуска и работы</strong></p>
<p align="justify">Этот метод достаточно популярен и путей его реализации также достаточно много, поэтому большинство антируткитов (наученные горьким опытом) как могут пассивно этому мешают. Суть: найти файл и не дать ему работать, а сделать это можно через запись в соответствующий ключ реестра имени исполняемого файла, модифицировать (побить) файл на диске, удалить нужную библиотеку/драйвер, установить в системе перехваты на запуск процессов/загрузку библиотек и сравнивать имена&#8230; </p>
<p align="justify">В ответ на это разработчики утилит используют рандомные имена файлов и пути их инсталляции, сведение к минимуму файлов вне основного исполняемого (т.е все нужные библиотеки/драйвера зашиты внутрь), рандомные имена драйверов и ключей реестра.</p>
<p align="justify">Так что все достаточно интересно.</p>
<p><br /></p>
<p align="justify"><strong>Прекращение работы</strong></p>
<p align="justify">Как правило, все достаточно банально &#8212; процесс находится и завершается. Процесс поиска процесса аналогичен предыдущему методу (нахождение по характерным признакам). Это может хорошо продемонстрировать следующий исходный код, на котором можно еще пояснить и некоторые аспекты грубого/тонкого противодействия.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> HideXueTr <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// флаг было ли уже скрыто окно или нет</span>
  <span style="color: #666666; font-style: italic;">// ..... code.... </span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>HideXueTr<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  HWND XueTr <span style="color: #339933;">=</span> FindWindow <span style="color: #009900;">&#40;</span>NULL<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;XuеTr 0.39&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>XueTr<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                  MessаgeBox <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;XueTr найден и будет скрыт!&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;OK&quot;</span><span style="color: #339933;">,</span> MB_OK<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                  ShоwWindow <span style="color: #009900;">&#40;</span>XueTr<span style="color: #339933;">,</span> SW_HIDE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// скрываем окно</span>
                  HideXueTr <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// взводим флаг</span>
               <span style="color: #009900;">&#125;</span>
      <span style="color: #009900;">&#125;</span></pre></div></div>

<p align="justify">В данном примере показана блокировка уже активного XueTr: находится по имени главного окна, после чего окно скрывается, причем только один раз. Пропажа окна будет воспринята пользователем как &#171;глюк&#187;, и XueTr будет запущен повторно, при этом он больше скрываться не будет в виду того, что никакие перехваты он показать уже не сможет, все данные поступают в скрытое окно, а в новом можно будет только обозреть сервисы и файловую систему. Антируткит работает, но показывает &#171;местами&#187;, что будет воспринято пользователем как несовместимость с его ОС, глюками, неумением работать с этой программой и т.д, но никаких подозрений у него не возникнет.</p>
<p><br /></p>
<p align="justify">При глюках обычно тянет на философию, чем и предлагаю заняться. Поразмышляем…</p>
<p align="justify">В логике работы всех антируткитов присутствует следующая аксиома: если скрытый &#8212; значит руткит. Соответственно найденный скрытый объект выделяется всеми цветами радуги (в данном случае для меня все цвета это красный) и уведомляет пользователя о том, что руткит найден. Далее в работе антируткитов имеется небольшая, но существенная разница, о которой мы уже говорили выше, а именно подробность отчета. Те утилиты, которые дают подробный отчет, покажут все что смогут (перехваты, перехватчик) и сам скрытый объект выделят, а те, что попроще в общении с пользователем просто покажут руткит и на выбор предложат: &#171;Удавить его? Утопить его? Стереть в порошок?&#187;. В целом, подход, конечно, правильный, но при большом желании и везении можно использовать его слабое место, ведь не все то золото, что блестит &#8212; не все то руткит, что скрывается, тем более в данном случае между словами &#171;скрывается&#187; и &#171;скрыт&#187; нет никакой разницы. По сути, руткиту (назовем так код, который что-то скрывает) нет никакой разницы, что скрывать &#8212; что ему сказали прятать, то он и прячет. Скажут скрывать readme.txt, и будет это делать. К чему это? А все к тому&#8230; В расчете на применение антируткита или при нахождении его активности (например, процесса) в системе, можно скрыть что-то специально для него. Возьмем и легким движением руки сделаем процесс/файл антивируса злостным руткитом, причем сам антивирус будет сильно удивлен, если вдруг прознает это, а вот антируткит будет этому только рад. Раз руткит &#8212; приговор &#171;Расстрел!&#187;. Особым цинизмом будет скрытие процесса/файла самого антируткита от него же. McAfee Rootkit Detective при обнаружении скрытого процесса предлагает только два способа борьбы с ним &#8212; завершить или переименовать. При скрытии его самого, прекрасно себя переименовывает. Панда также не ожидает, что ему подложат такую свинью и предлагает два варианта: удалять руткит и не удалять руткит. При выборе первого варианта мишка с успехом самовыпиливается: после перезагрузки бамбуковый мишка начинает использовать бамбук по назначению.</p>
<p><br /></p>
<p align="justify">Напоследок мне бы хотелось напомнить о том, что файл от юзера можно спрятать и в ADS – даже если антируткит их показывает, то покажет он их очень много, вот среди этого множества можно и затесаться. Атаку на GUI антируткитов также никто не отменял, взяли и как нужно отредактировали данные в его окошке, или не допустили их туда, аналогично и с диспетчером задач.</p>
<p align="justify">Закончить статью хотелось бы пожеланиями разработчикам антируткитов:</p>
<p align="justify"><strong>1)</strong> Еще больше рандомизировать (а тем, у кого этого нет &#8212; сделать) имена файлов/путей/окон/размера/и т.д.</p>
<p align="justify"><strong>2)</strong> Сделать более читабельной информацию об установленном перехвате:</p>
<ul>
<li>улучшить распознавание имен функций;</li>
<li>информацию о перехвате выводить не только набором байт, но и мнемоникой вида jmp xxx, а при невозможности определить четко перехватчик, выводить мнемоникой весь код установленного перехвата, например:</li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="asm" style="font-family:monospace;"><span style="color: #00007f; font-weight: bold;">xor</span> <span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #00007f;">eax</span>
<span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> xxx
<span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #00007f;">eax</span>
<span style="color: #00007f; font-weight: bold;">ret</span></pre></div></div>

<p align="justify"><strong>3)</strong> Выполнять сравнение библиотек в system32 и в dllcache. Для повышения точности определения чистоты библиотеки можно носить с собой в массиве т.н базу чистых &#8212; хэш суммы проверяемых библиотек с разных систем (хотя бы популярных). Размер базы будет следующим: количество_проверяемых_в_системе_библиотек * количество_популярных_систем.</p>
<p align="justify"><strong>4)</strong> Выполнять поиск перехватов не только в своем процессе/некоторых, а во всех.</p>
<p align="justify"><strong>5)</strong> Научиться (тем, кто не умеет) опознавать перехваты, установленные антивирусными программами. Тут, собственно, три основных пути:</p>
<ul>
<li>иметь на борту базу чистых;</li>
<li>проверять подписи (хотя в свете последних событий тут следует быть осторожным);</li>
<li>подгружать базу чистых из &#171;облака&#187;;</li>
</ul>
<p align="justify"><strong>6)</strong> Для получения слепка файлов/процессов/ключей из user-mode для последующего сравнения со списком из ядра, пользоваться не консольной программой, а чем-то имитирующим обычную программу &#8212; нужно хотя бы user32.dll подгружать&#8230;</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fsww-it.ru%2F2011-04-21%2F528&amp;title=Ring-3%20%D1%80%D1%83%D1%82%D0%BA%D0%B8%D1%82%D1%8B" id="wpa2a_2"><img src="http://sww-it.ru/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sww-it.ru/2011-04-21/528/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Функции уведомления и функции обратного вызова в Windows (ч.1, Ps*)</title>
		<link>http://sww-it.ru/2010-02-21/362?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25d1%2584%25d1%2583%25d0%25bd%25d0%25ba%25d1%2586%25d0%25b8%25d0%25b8-%25d1%2583%25d0%25b2%25d0%25b5%25d0%25b4%25d0%25be%25d0%25bc%25d0%25bb%25d0%25b5%25d0%25bd%25d0%25b8%25d1%258f-%25d0%25b8-%25d1%2584%25d1%2583%25d0%25bd%25d0%25ba%25d1%2586%25d0%25b8%25d0%25b8-%25d0%25be%25d0%25b1%25d1%2580%25d0%25b0%25d1%2582%25d0%25bd</link>
		<comments>http://sww-it.ru/2010-02-21/362#comments</comments>
		<pubDate>Sun, 21 Feb 2010 11:35:19 +0000</pubDate>
		<dc:creator>SWW</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[callback]]></category>
		<category><![CDATA[notify]]></category>
		<category><![CDATA[wdk]]></category>
		<category><![CDATA[драйвер]]></category>

		<guid isPermaLink="false">http://sww-it.ru/?p=362</guid>
		<description><![CDATA[<p style="text-align: justify;">В операционной системе Windows разработчиками было предусмотрено довольно много механизмов получения каких-либо уведомлений и событий. В некоторых случаях разработчик может влиять на возвращаемый результат, в некоторых – нет. В основном считается, что программист не может влиять на возвращаемый результат функций уведомления (notifications) и может влиять на возвращаемый результат функций обратного вызова (callbacks). Однако [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">В операционной системе Windows разработчиками было предусмотрено довольно много механизмов получения каких-либо уведомлений и событий. В некоторых случаях разработчик может влиять на возвращаемый результат, в некоторых – нет. В основном считается, что программист не может влиять на возвращаемый результат функций уведомления (notifications) и может влиять на возвращаемый результат функций обратного вызова (callbacks). Однако это совсем не означает, что функции уведомления вызываются асинхронно, поэтому необходимо обязательно возвращать управление из тех и из других.</p>
<p style="text-align: justify;">Предоставленные функции связаны с различными объектами операционной системы, такими как  процессы, потоки, файловые образы, объекты системного реестра и так далее.</p>
<p><span id="more-362"></span></p>
<h3 style="text-align: center;">PsSetLoadImageNotifyRoutine</h3>
<p style="text-align: justify;"><span style="color: #0000ff;">PsSetLoadImageNotifyRoutine</span> регистрирует функцию уведомления, которая вызывается в момент загрузки образа или отображения образа в память.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">NTSTATUS
  PsSetLoadImageNotifyRoutine<span style="color: #009900;">&#40;</span>
    IN PLOAD_IMAGE_NOTIFY_ROUTINE  NotifyRoutine
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p style="text-align: justify;">Функция уведомления должна быть определена следующим образом:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">VOID
<span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>PLOAD_IMAGE_NOTIFY_ROUTINE<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span>
    IN PUNICODE_STRING  FullImageName<span style="color: #339933;">,</span>
    IN HANDLE  ProcessId<span style="color: #339933;">,</span>
    IN PIMAGE_INFO  ImageInfo
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p style="text-align: justify;">После регистрации данной функции она будет вызываться операционной системой после отображения в память исполняемого образа в пространстве ядра или в пользовательском пространстве, до начала исполнения образа. Данная функция вызывается, в том числе и в момент загрузки DLL в пользовательском пространстве.</p>
<p style="text-align: justify;">В момент загрузки основного исполняемого образа в память нового процесса данная функция уведомления вызывается в контексте создаваемого процесса.</p>
<p style="text-align: justify;">Пример регистрации функции уведомления:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">NTSTATUS SetLoadImageNotifyRoutine<span style="color: #009900;">&#40;</span>IN PLOAD_IMAGE_NOTIFY_ROUTINE Routine<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	PAGED_CODE<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span>Routine <span style="color: #009900;">&#41;</span>
		<span style="color: #b1b100;">return</span> STATUS_INVALID_PARAMETER<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">return</span> PsSetLoadImageNotifyRoutine<span style="color: #009900;">&#40;</span> Routine <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
VOID LoadImageNotifyRoutine<span style="color: #009900;">&#40;</span>IN PUNICODE_STRING FullImageName<span style="color: #339933;">,</span> IN HANDLE ProcessId<span style="color: #339933;">,</span> IN PIMAGE_INFO ImageInfo<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	PAGED_CODE<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	KdPrint<span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#40;</span> <span style="color: #ff0000;">&quot;LoadImageNotifyRoutine called with FullImageName = %wZ, ProcessId = 0x%08X<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> FullImageName<span style="color: #339933;">,</span> ProcessId <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p style="text-align: justify;">Из переменной <span style="color: #0000ff;">ImageInfo</span> можно получить дополнительную информацию. Причем для систем Windows Vista и выше данная структура содержит больше информации, чем для предыдущих версий ОС (см. WDK Help).</p>
<p style="text-align: justify;">Операционная система содержит список (массив) функций уведомления. Например, для Windows XP/2003 – это глобальный массив <span style="color: #0000ff;">PspLoadImageNotifyRoutine</span>. Вызов каждой зарегистрированной процедуры происходит последовательно в функции <span style="color: #0000ff;">PsCallImageNotifyRoutines</span>.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">NTSTATUS
MmLoadSystemImage <span style="color: #009900;">&#40;</span>
    IN PUNICODE_STRING ImageFileName<span style="color: #339933;">,</span>
    IN PUNICODE_STRING NamePrefix OPTIONAL<span style="color: #339933;">,</span>
    IN PUNICODE_STRING LoadedBaseName OPTIONAL<span style="color: #339933;">,</span>
    IN ULONG LoadFlags<span style="color: #339933;">,</span>
    OUT PVOID <span style="color: #339933;">*</span>ImageHandle<span style="color: #339933;">,</span>
    OUT PVOID <span style="color: #339933;">*</span>ImageBaseAddress
    <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
…
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>PsImageNotifyEnabled<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            IMAGE_INFO ImageInfo<span style="color: #339933;">;</span>
&nbsp;
            ImageInfo.<span style="color: #202020;">Properties</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
            ImageInfo.<span style="color: #202020;">ImageAddressingMode</span> <span style="color: #339933;">=</span> IMAGE_ADDRESSING_MODE_32BIT<span style="color: #339933;">;</span>
            ImageInfo.<span style="color: #202020;">SystemModeImage</span> <span style="color: #339933;">=</span> TRUE<span style="color: #339933;">;</span>
            ImageInfo.<span style="color: #202020;">ImageSize</span> <span style="color: #339933;">=</span> DataTableEntry<span style="color: #339933;">-&gt;</span>SizeOfImage<span style="color: #339933;">;</span>
            ImageInfo.<span style="color: #202020;">ImageBase</span> <span style="color: #339933;">=</span> <span style="color: #339933;">*</span>ImageBaseAddress<span style="color: #339933;">;</span>
            ImageInfo.<span style="color: #202020;">ImageSelector</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
            ImageInfo.<span style="color: #202020;">ImageSectionNumber</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
&nbsp;
            PsCallImageNotifyRoutines<span style="color: #009900;">&#40;</span>ImageFileName<span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span>HANDLE<span style="color: #009900;">&#41;</span>NULL<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>ImageInfo<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
…
<span style="color: #009900;">&#125;</span>
&nbsp;
PsCallImageNotifyRoutines<span style="color: #009900;">&#40;</span>
    IN PUNICODE_STRING FullImageName<span style="color: #339933;">,</span>
    IN HANDLE ProcessId<span style="color: #339933;">,</span>
    IN PIMAGE_INFO ImageInfo
    <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    ULONG i<span style="color: #339933;">;</span>
    PEX_CALLBACK_ROUTINE_BLOCK CallBack<span style="color: #339933;">;</span>
    PLOAD_IMAGE_NOTIFY_ROUTINE Rtn<span style="color: #339933;">;</span>
&nbsp;
    PAGED_CODE<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>PsImageNotifyEnabled<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> 
        <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> PSP_MAX_LOAD_IMAGE_NOTIFY<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            CallBack <span style="color: #339933;">=</span> ExReferenceCallBackBlock <span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>PspLoadImageNotifyRoutine<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>CallBack <span style="color: #339933;">!=</span> NULL<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                Rtn <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>PLOAD_IMAGE_NOTIFY_ROUTINE<span style="color: #009900;">&#41;</span> ExGetCallBackBlockRoutine <span style="color: #009900;">&#40;</span>CallBack<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                Rtn <span style="color: #009900;">&#40;</span>FullImageName<span style="color: #339933;">,</span>
                     ProcessId<span style="color: #339933;">,</span>
                     ImageInfo<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                ExDereferenceCallBackBlock <span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>PspLoadImageNotifyRoutine<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> CallBack<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p style="text-align: justify;">Удалить функцию уведомления можно с помощью вызова <span style="color: #0000ff;">PsRemoveLoadImageNotifyRoutine</span>, передав указатель на зарегистрированный обработчик.</p>
<h3 style="text-align: center;">PsSetCreateProcessNotifyRoutine и PsSetCreateProcessNotifyRoutineEx</h3>
<p style="text-align: justify;"><span style="color: #0000ff;">PsSetCreateProcessNotifyRoutine</span> и <span style="color: #0000ff;">PsSetCreateProcessNotifyRoutineEx</span> позволяют зарегистрировать функцию уведомления на создание и завершение процессов в системе. Последняя из перечисленных функций присутствует только начиная с Windows Vista SP1 и предоставляет больше информации и более удобный интерфейс для использования.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">NTSTATUS
  PsSetCreateProcessNotifyRoutine<span style="color: #009900;">&#40;</span>
    IN PCREATE_PROCESS_NOTIFY_ROUTINE  NotifyRoutine<span style="color: #339933;">,</span>
    IN BOOLEAN  Remove
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
NTSTATUS
  PsSetCreateProcessNotifyRoutineEx<span style="color: #009900;">&#40;</span>
    IN PCREATE_PROCESS_NOTIFY_ROUTINE_EX  NotifyRoutine<span style="color: #339933;">,</span>
    IN BOOLEAN  Remove
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p style="text-align: justify;">В отличие от <span style="color: #0000ff;">PsSetLoadImageNotifyRoutine</span> для удаления обработчика не нужно вызывать другую функцию, достаточно вызвать ту же самую с параметром <span style="color: #0000ff;">Remove</span> равным TRUE.</p>
<p style="text-align: justify;">Обработчики должны быть определены следующим образом:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">VOID
<span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>PCREATE_PROCESS_NOTIFY_ROUTINE<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span>
    IN HANDLE  ParentId<span style="color: #339933;">,</span>
    IN HANDLE  ProcessId<span style="color: #339933;">,</span>
    IN BOOLEAN  Create
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
VOID
  CreateProcessNotifyEx<span style="color: #009900;">&#40;</span>
    __inout PEPROCESS  Process<span style="color: #339933;">,</span>
    __in HANDLE  ProcessId<span style="color: #339933;">,</span>
    __in_opt PPS_CREATE_NOTIFY_INFO  CreateInfo
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p style="text-align: justify;">Структура с дополнительной информацией:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">typedef</span> <span style="color: #993333;">struct</span> _PS_CREATE_NOTIFY_INFO <span style="color: #009900;">&#123;</span>
  __in SIZE_T  Size<span style="color: #339933;">;</span>
  <span style="color: #993333;">union</span> <span style="color: #009900;">&#123;</span>
    __in ULONG  Flags<span style="color: #339933;">;</span>
    <span style="color: #993333;">struct</span> <span style="color: #009900;">&#123;</span>
      __in ULONG  FileOpenNameAvailable <span style="color: #339933;">:</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
      __in ULONG  Reserved <span style="color: #339933;">:</span> <span style="color: #0000dd;">31</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
  __in HANDLE  ParentProcessId<span style="color: #339933;">;</span>
  __in CLIENT_ID  CreatingThreadId<span style="color: #339933;">;</span>
  __inout <span style="color: #993333;">struct</span> _FILE_OBJECT  <span style="color: #339933;">*</span>FileObject<span style="color: #339933;">;</span>
  __in PCUNICODE_STRING  ImageFileName<span style="color: #339933;">;</span>
  __in_opt PCUNICODE_STRING  CommandLine<span style="color: #339933;">;</span>
  __inout NTSTATUS  CreationStatus<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> PS_CREATE_NOTIFY_INFO<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>PPS_CREATE_NOTIFY_INFO<span style="color: #339933;">;</span></pre></div></div>

<p style="text-align: justify;">После регистрации функции уведомления операционная система вызывает зарегистрированный обработчик  в двух случаях: когда процесс создается и когда процесс завершается. В случае создания процесса функция уведомления вызывается после того как создан начальный поток, но исполнение его еще не началось. В случае завершения процесса операционная система вызывает функцию уведомления, перед тем как последний поток в процессе завершится. В обработчике, зарегистрированном с помощью <span style="color: #0000ff;">PsSetCreateProcessNotifyRoutineEx</span>, можно влиять на результат создания процесса. Для этого необходимо использовать член <span style="color: #0000ff;">CreationStatus</span> структуры <span style="color: #0000ff;">PS_CREATE_NOTIFY_INFO</span>.</p>
<p style="text-align: justify;">В момент создания нового процесса функция уведомления вызывается в контексте потока, который инициировал создание этого процесса. В момент уничтожения процесса функция уведомления вызывается в контексте последнего потока завершаемого процесса.</p>
<p style="text-align: justify;">Пример регистрации функции уведомления:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">typedef</span> NTSTATUS <span style="color: #009900;">&#40;</span>NTAPI<span style="color: #339933;">*</span> PSSETCREATEPROCESSNOTIFYROUTINEEX_PROC<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span>
	IN PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine<span style="color: #339933;">,</span>
	IN BOOLEAN Remove
	<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
NTSTATUS SetCreateProcessNotifyRoutine<span style="color: #009900;">&#40;</span>VOID<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	NTSTATUS                               status<span style="color: #339933;">;</span>
	UNICODE_STRING                         szCreateProcessEx <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
	PSSETCREATEPROCESSNOTIFYROUTINEEX_PROC pCreateProcessEx  <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span>
&nbsp;
	PAGED_CODE<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	RtlInitUnicodeString<span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>szCreateProcessEx<span style="color: #339933;">,</span> L<span style="color: #ff0000;">&quot;PsSetCreateProcessNotifyRoutineEx&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	pCreateProcessEx <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>PSSETCREATEPROCESSNOTIFYROUTINEEX_PROC <span style="color: #009900;">&#41;</span>MmGetSystemRoutineAddress<span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>szCreateProcessEx <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> pCreateProcessEx <span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		status <span style="color: #339933;">=</span> pCreateProcessEx<span style="color: #009900;">&#40;</span> CreateProcessNotifyRoutineEx<span style="color: #339933;">,</span> FALSE <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">else</span>
	<span style="color: #009900;">&#123;</span>
		status <span style="color: #339933;">=</span> PsSetCreateProcessNotifyRoutine<span style="color: #009900;">&#40;</span> CreateProcessNotifyRoutine<span style="color: #339933;">,</span> FALSE <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">return</span> status<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
VOID CreateProcessNotifyRoutine<span style="color: #009900;">&#40;</span>IN HANDLE ParentId<span style="color: #339933;">,</span> IN HANDLE ProcessId<span style="color: #339933;">,</span> IN BOOLEAN Create<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	PAGED_CODE<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	KdPrint<span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#40;</span> <span style="color: #ff0000;">&quot;CreateProcessNotifyRoutine called with ParentId = 0x%08X, ProcessId = 0x%08X, Create = %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> ParentId<span style="color: #339933;">,</span> ProcessId<span style="color: #339933;">,</span> Create <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
VOID CreateProcessNotifyRoutineEx<span style="color: #009900;">&#40;</span>__inout PEPROCESS Process<span style="color: #339933;">,</span> __in HANDLE ProcessId<span style="color: #339933;">,</span> __in_opt PPS_CREATE_NOTIFY_INFO CreateInfo<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	PAGED_CODE<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	KdPrint<span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#40;</span> <span style="color: #ff0000;">&quot;CreateProcessNotifyRoutineEx called with Process = 0x%08X, ProcessId = 0x%08X<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> Process<span style="color: #339933;">,</span> ProcessId <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p style="text-align: justify;">Как и в случае с <span style="color: #0000ff;">PsLoadImageNotifyRoutine</span> операционная система содержит список (массив) функций уведомления в глобальной переменной <span style="color: #0000ff;">PspCreateProcessNotifyRoutine</span> (Windows XP/2003). Вызов каждой зарегистрированной функции происходит из системных функций <span style="color: #0000ff;">PspCreateThread</span> и <span style="color: #0000ff;">PspExitProcess</span>.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">VOID
PspExitProcess<span style="color: #009900;">&#40;</span>
    IN BOOLEAN LastThreadExit<span style="color: #339933;">,</span>
    IN PEPROCESS Process
    <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
&nbsp;
…
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>LastThreadExit<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
…
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>PspCreateProcessNotifyRoutineCount <span style="color: #339933;">!=</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            ULONG i<span style="color: #339933;">;</span>
            PEX_CALLBACK_ROUTINE_BLOCK CallBack<span style="color: #339933;">;</span>
            PCREATE_PROCESS_NOTIFY_ROUTINE Rtn<span style="color: #339933;">;</span>
&nbsp;
            <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> PSP_MAX_CREATE_PROCESS_NOTIFY<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                CallBack <span style="color: #339933;">=</span> ExReferenceCallBackBlock <span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>PspCreateProcessNotifyRoutine<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>CallBack <span style="color: #339933;">!=</span> NULL<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                    Rtn <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>PCREATE_PROCESS_NOTIFY_ROUTINE<span style="color: #009900;">&#41;</span> ExGetCallBackBlockRoutine <span style="color: #009900;">&#40;</span>CallBack<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                    Rtn <span style="color: #009900;">&#40;</span>Process<span style="color: #339933;">-&gt;</span>InheritedFromUniqueProcessId<span style="color: #339933;">,</span>
                         Process<span style="color: #339933;">-&gt;</span>UniqueProcessId<span style="color: #339933;">,</span>
                         FALSE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                    ExDereferenceCallBackBlock <span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>PspCreateProcessNotifyRoutine<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
                                                CallBack<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
…
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<h3 style="text-align: center;">PsSetCreateThreadNotifyRoutine</h3>
<p style="text-align: justify;"><span style="color: #0000ff;">PsSetCreateThreadNotifyRoutine</span> регистрирует функцию уведомления, которая вызывается в момент создания и уничтожения потока.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">NTSTATUS
  PsSetCreateThreadNotifyRoutine<span style="color: #009900;">&#40;</span>
    IN PCREATE_THREAD_NOTIFY_ROUTINE  NotifyRoutine
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p style="text-align: justify;">Функция уведомления должна быть определена следующим образом:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">VOID
<span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>PCREATE_THREAD_NOTIFY_ROUTINE<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span>
    IN HANDLE  ProcessId<span style="color: #339933;">,</span>
    IN HANDLE  ThreadId<span style="color: #339933;">,</span>
    IN BOOLEAN  Create
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p style="text-align: justify;">Для удаления обработчика необходимо использовать функцию <span style="color: #0000ff;">PsRemoveCreateThreadNotifyRoutine</span>.</p>
<p style="text-align: justify;">В момент создания нового потока функция уведомления вызывается в контексте потока, который инициировал его создание. В момент уничтожения потока функция уведомления вызывается в контексте завершаемого потока.</p>
<p style="text-align: justify;">Пример регистрации функции уведомления:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">NTSTATUS SetCreateThreadNotifyRoutine<span style="color: #009900;">&#40;</span>IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	PAGED_CODE<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span>NotifyRoutine <span style="color: #009900;">&#41;</span>
		<span style="color: #b1b100;">return</span> STATUS_INVALID_PARAMETER<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">return</span> PsSetCreateThreadNotifyRoutine<span style="color: #009900;">&#40;</span> NotifyRoutine <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
VOID CreateThreadNotifyRoutine<span style="color: #009900;">&#40;</span>IN HANDLE ProcessId<span style="color: #339933;">,</span> IN HANDLE ThreadId<span style="color: #339933;">,</span> IN BOOLEAN Create<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	PAGED_CODE<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	KdPrint<span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#40;</span> <span style="color: #ff0000;">&quot;CreateThreadNotifyRoutine called with ProcessId = 0x%08X, ThreadId = 0x%08X, Create = %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> ProcessId<span style="color: #339933;">,</span> ThreadId<span style="color: #339933;">,</span> Create <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p style="text-align: justify;">Как и во всех вышеперечисленных функциях, операционная система хранит список (массив) функций уведомления в глобальной переменной <span style="color: #0000ff;">PspCreateThreadNotifyRoutine</span> (Windows XP/2003). Вызов каждой зарегистрированной функции происходит из функций <span style="color: #0000ff;">PspCreateThread</span> и <span style="color: #0000ff;">PspExitThread</span>.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">NTSTATUS
PspCreateThread<span style="color: #009900;">&#40;</span>
    OUT PHANDLE ThreadHandle<span style="color: #339933;">,</span>
    IN ACCESS_MASK DesiredAccess<span style="color: #339933;">,</span>
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL<span style="color: #339933;">,</span>
    IN HANDLE ProcessHandle<span style="color: #339933;">,</span>
    IN PEPROCESS ProcessPointer<span style="color: #339933;">,</span>
    OUT PCLIENT_ID ClientId OPTIONAL<span style="color: #339933;">,</span>
    IN PCONTEXT ThreadContext OPTIONAL<span style="color: #339933;">,</span>
    IN PINITIAL_TEB InitialTeb OPTIONAL<span style="color: #339933;">,</span>
    IN BOOLEAN CreateSuspended<span style="color: #339933;">,</span>
    IN PKSTART_ROUTINE StartRoutine OPTIONAL<span style="color: #339933;">,</span>
    IN PVOID StartContext
    <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
&nbsp;
…
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>PspCreateThreadNotifyRoutineCount <span style="color: #339933;">!=</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        ULONG i<span style="color: #339933;">;</span>
        PEX_CALLBACK_ROUTINE_BLOCK CallBack<span style="color: #339933;">;</span>
        PCREATE_THREAD_NOTIFY_ROUTINE Rtn<span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> PSP_MAX_CREATE_THREAD_NOTIFY<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            CallBack <span style="color: #339933;">=</span> ExReferenceCallBackBlock <span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>PspCreateThreadNotifyRoutine<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>CallBack <span style="color: #339933;">!=</span> NULL<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                Rtn <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>PCREATE_THREAD_NOTIFY_ROUTINE<span style="color: #009900;">&#41;</span> ExGetCallBackBlockRoutine <span style="color: #009900;">&#40;</span>CallBack<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                Rtn <span style="color: #009900;">&#40;</span>Thread<span style="color: #339933;">-&gt;</span>Cid.<span style="color: #202020;">UniqueProcess</span><span style="color: #339933;">,</span>
                     Thread<span style="color: #339933;">-&gt;</span>Cid.<span style="color: #202020;">UniqueThread</span><span style="color: #339933;">,</span>
                     TRUE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                ExDereferenceCallBackBlock <span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>PspCreateThreadNotifyRoutine<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
                                            CallBack<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
…
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p style="text-align: justify;">На этом первая часть цикла о функциях уведомления и функциях обратного вызова закончена. Исходные тексты к статье можно <a href="http://sww-it.ru/wp-content/uploads/2010/cbtest.zip">скачать здесь</a>. После каждой новой главы я буду их обновлять.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fsww-it.ru%2F2010-02-21%2F362&amp;title=%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8%20%D1%83%D0%B2%D0%B5%D0%B4%D0%BE%D0%BC%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%20%D0%B8%20%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8%20%D0%BE%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D0%BE%D0%B3%D0%BE%20%D0%B2%D1%8B%D0%B7%D0%BE%D0%B2%D0%B0%20%D0%B2%20Windows%20%28%D1%87.1%2C%20Ps%2A%29" id="wpa2a_4"><img src="http://sww-it.ru/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sww-it.ru/2010-02-21/362/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows 7 WDK documentation</title>
		<link>http://sww-it.ru/2009-08-11/303?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=windows-7-wdk-documentation</link>
		<comments>http://sww-it.ru/2009-08-11/303#comments</comments>
		<pubDate>Tue, 11 Aug 2009 17:56:59 +0000</pubDate>
		<dc:creator>SWW</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[wdk]]></category>
		<category><![CDATA[windows 7]]></category>

		<guid isPermaLink="false">http://sww-it.ru/?p=303</guid>
		<description><![CDATA[<p>На сайте WDKDocs доступна обновленная документация с поддержкой Windows 7.</p> <p>Документацию можно загрузить в двух форматах, как обычный апдейт и в формате .chm:</p> <p>WDKDocs_08072009.exe</p> <p>wdkchm_08072009.exe</p> ]]></description>
			<content:encoded><![CDATA[<p>На сайте <a href="http://www.microsoft.com/whdc/DevTools/WDK/WDKdocs.mspx" target="_blank">WDKDocs</a> доступна обновленная документация с поддержкой Windows 7.</p>
<p>Документацию можно загрузить в двух форматах, как обычный апдейт и в формате .chm:</p>
<p><a href="http://download.microsoft.com/download/3/3/C/33CFEF4D-21DA-4229-BC17-3EAC7A7EABE1/WDKDocs_08072009.EXE">WDKDocs_08072009.exe</a></p>
<p><a href="http://download.microsoft.com/download/3/3/C/33CFEF4D-21DA-4229-BC17-3EAC7A7EABE1/wdkchm_08072009.chm">wdkchm_08072009.exe</a></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fsww-it.ru%2F2009-08-11%2F303&amp;title=Windows%207%20WDK%20documentation" id="wpa2a_6"><img src="http://sww-it.ru/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sww-it.ru/2009-08-11/303/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WDK 7.0.0 доступен для загрузки</title>
		<link>http://sww-it.ru/2009-08-07/297?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=wdk-7-0-0-%25d0%25b4%25d0%25be%25d1%2581%25d1%2582%25d1%2583%25d0%25bf%25d0%25b5%25d0%25bd-%25d0%25b4%25d0%25bb%25d1%258f-%25d1%2581%25d0%25ba%25d0%25b0%25d1%2587%25d0%25b8%25d0%25b2%25d0%25b0%25d0%25bd%25d0%25b8%25d1%258f</link>
		<comments>http://sww-it.ru/2009-08-07/297#comments</comments>
		<pubDate>Fri, 07 Aug 2009 11:09:09 +0000</pubDate>
		<dc:creator>SWW</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[wdk]]></category>

		<guid isPermaLink="false">http://sww-it.ru/?p=297</guid>
		<description><![CDATA[<p>Hello WDK Program Participants:</p> <p>We are pleased to announce the release of the Windows Driver Kit Version 7.0.0. This latest production release of the WDK is now available for download on Connect.</p> <p>In this WDK release, the WDK is delivering the latest updates to create drivers for: • Windows 7 • Windows Vista • Windows [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Hello WDK Program Participants:</p>
<p>We are pleased to announce the release of the Windows Driver Kit Version 7.0.0. This latest production release of the WDK is now available for download on Connect.</p>
<p>In this WDK release, the WDK is delivering the latest updates to create drivers for:<br />
• Windows 7<br />
• Windows Vista<br />
• Windows XP<br />
• Windows Server 2008 R2<br />
• Windows Server 2008<br />
• Windows Server 2003</p>
<p>A few of the highlights in this release are:<br />
• A number of additional headers<br />
• Update of KMDF and UMDF to Version 1.9<br />
• Co-installers for WinUSB v2 added<br />
• Update of DIFx redistributable files<br />
• Addition of Offreg DLLs<br />
• Sample additions in 1394, Audio, Biometric, Build, Bus, File System, HID, Input, Network, Print, Sensors, Storage, WMI, WPD, and general samples<br />
• Tools added in Biometrics, Bluetooth, Driver Coverage, Enhanced Storage, Test tools, Networking, Print and general tools<br />
• Improvements to PFD and Static Driver Verifier<br />
• Updated documentation</p>
<p>This release is available as a download only. The image posted is a DVD image and the recommended approach is to download and burn a DVD.</p>
<p>Thank you for your continued support!</p>
<p>Regards,<br />
The Windows Driver Kit (WDK) team</p></blockquote>
<p>Доступен для загрузки на <a href="https://connect.microsoft.com/site148/Downloads/DownloadDetails.aspx?DownloadID=26935" target="_blank">Windows Connect</a></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fsww-it.ru%2F2009-08-07%2F297&amp;title=WDK%207.0.0%20%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%B5%D0%BD%20%D0%B4%D0%BB%D1%8F%20%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B8" id="wpa2a_8"><img src="http://sww-it.ru/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sww-it.ru/2009-08-07/297/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Ребутни меня жестко</title>
		<link>http://sww-it.ru/2009-03-17/76?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25d1%2580%25d0%25b5%25d0%25b1%25d1%2583%25d1%2582%25d0%25bd%25d0%25b8-%25d0%25bc%25d0%25b5%25d0%25bd%25d1%258f-%25d0%25b6%25d0%25b5%25d1%2581%25d1%2582%25d0%25ba%25d0%25be</link>
		<comments>http://sww-it.ru/2009-03-17/76#comments</comments>
		<pubDate>Tue, 17 Mar 2009 09:45:26 +0000</pubDate>
		<dc:creator>SWW</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[reboot]]></category>
		<category><![CDATA[драйвер]]></category>

		<guid isPermaLink="false">http://sww-it.ru/?p=76</guid>
		<description><![CDATA[<p style="text-align: justify">В некоторых ситуациях возникает потребность перезагрузить операционную систему прямо из ядра. Когда-то давно я был озадачен такой проблемой, так как существующие способы меня не устраивали по разным причинам. Пришлось копать, искать и спрашивать. В результате были найдены следующие варианты.</p> <p style="text-align: justify"></p> <p style="text-align: justify">В режиме пользователя можно использовать функцию ExitWindowsEx (она ведет [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify">В некоторых ситуациях возникает потребность перезагрузить операционную систему прямо из ядра. Когда-то давно я был озадачен такой проблемой, так как существующие способы меня не устраивали по разным причинам. Пришлось копать, искать и спрашивать. В результате были найдены следующие варианты.</p>
<p style="text-align: justify"><span id="more-76"></span></p>
<p style="text-align: justify">В режиме пользователя можно использовать функцию <strong>ExitWindowsEx</strong> (она ведет в <strong>NtShutdownSystem</strong>):</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">BOOL WINAPI ExitWindowsEx<span style="color: #009900;">&#40;</span>
                                       __in UINT    uFlags<span style="color: #339933;">,</span>
                                       __in DWORD dwReason
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

</p>
<p>Все достаточно подробно <a href="http://msdn.microsoft.com/en-us/library/aa376868(VS.85).aspx" target="_blank">описано</a> в MSDN и, конечно, не забываем про включенную <strong>Shutdown</strong> привилегию.</p>
<p>Давайте рассмотрим варианты, которые нам доступны из режима ядра. Один из них &#8212; это использование функции <strong>NtShutdownSystem</strong>. Конечно, она недокументированная. Реализация для Windows XP выглядит так (вот такой забавный switch, видимо из-за оптимизаций):</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">NTSTATUS __stdcall NtShutdownSystem<span style="color: #009900;">&#40;</span>SHUTDOWN_ACTION Action<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
        POWER_ACTION SystemAction<span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> Action <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
                <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> Action <span style="color: #339933;">==</span> <span style="color: #0000dd;">1</span> <span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">// ShutdownReboot</span>
                <span style="color: #009900;">&#123;</span>
                        SystemAction <span style="color: #339933;">=</span> <span style="color: #0000dd;">5</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// PowerActionShutdownReset</span>
                <span style="color: #009900;">&#125;</span>
                <span style="color: #b1b100;">else</span> <span style="color: #666666; font-style: italic;">// ShutdownPowerOff</span>
                <span style="color: #009900;">&#123;</span>
                        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> Action <span style="color: #339933;">!=</span> <span style="color: #0000dd;">2</span> <span style="color: #009900;">&#41;</span>
                                <span style="color: #b1b100;">return</span> STATUS_INVALID_PARAMETER<span style="color: #339933;">;</span>
                        SystemAction <span style="color: #339933;">=</span> <span style="color: #0000dd;">6</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// PowerActionShutdownOff</span>
                <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">else</span> <span style="color: #666666; font-style: italic;">// ShutdownNoReboot</span>
        <span style="color: #009900;">&#123;</span>
                SystemAction <span style="color: #339933;">=</span> <span style="color: #0000dd;">4</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// PowerActionShutdown</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #b1b100;">return</span> NtSetSystemPowerState<span style="color: #009900;">&#40;</span>SystemAction<span style="color: #339933;">,</span> PowerSystemSleeping3<span style="color: #339933;">,</span> 0xC0000004u<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">typedef</span> <span style="color: #000000; font-weight: bold;">enum</span> _POWER_ACTION <span style="color: #009900;">&#123;</span>
        PowerActionNone            <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span>
        PowerActionReserved<span style="color: #339933;">,</span>
        PowerActionSleep<span style="color: #339933;">,</span>
        PowerActionHibernate<span style="color: #339933;">,</span>
        PowerActionShutdown<span style="color: #339933;">,</span>
        PowerActionShutdownReset<span style="color: #339933;">,</span>
        PowerActionShutdownOff<span style="color: #339933;">,</span>
        PowerActionWarmEject
<span style="color: #009900;">&#125;</span> POWER_ACTION<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>PPOWER_ACTION<span style="color: #339933;">;</span></pre></div></div>

</p>
<p>Вышеуказанные функции нужно использовать тогда, когда вам необходимо все сделать красиво и чисто.</p>
<p>Следующий вариант &#8212; это использовать функцию <strong>HalReturnToFirmware</strong>. Она также <a href="http://msdn.microsoft.com/en-us/library/bb510367.aspx" target="_blank">описана</a> в MSDN.</p>
<p>VOID <strong>HalReturnToFirmware</strong>(IN FIRMWARE_REENTRY  <span style="color: #0000ff;">Routine</span>);</p>
<p>На вход функция может принимать параметр <strong>HalRebootRoutine</strong>, что нам собственно и нужно. Честно говоря, меня смущает то, что написано в MSDN:</p>
<p style="text-align: justify"><em>Requirements</em></p>
<p style="text-align: justify"><em>Versions: Available in Microsoft Windows Server 2003 and Windows XP.</em></p>
<p><em> DLL: Requires Hal.dll.</em></p>
<p style="text-align: justify">Под рукой у меня нет Hal.dll от Windows 2000, так что проверить экспортируется ли она или нет, я не могу, а память меня подводит.</p>
<p>Третий вариант &#8212; это спровоцировать BSOD. Шучу, шучу, но близко к правде. Вызовем <strong>KeBugcheckEx</strong> с параметром <strong>POWER_FAILURE_SIMULATE</strong>. <strong>KeBugcheckEx</strong> &#8212; это обыкновенная обертка над <strong>KeBugcheck2</strong>:</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> __stdcall KeBugCheck2<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> BugCheckCode<span style="color: #339933;">,</span> <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> BugCheckCode <span style="color: #339933;">==</span> POWER_FAILURE_SIMULATE <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
                KiScanBugCheckCallbackList<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                HalReturnToFirmware<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// HalRebootRoutine</span>
        <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</p>
<p>Знакомая картина, но помнится мне, что на каких-то системах вместо перезагрузки я получал самый натуральный BSOD с <strong>POWER_FAILURE_SIMULATE</strong>. Однако поехали дальше.</p>
<p>Мне, как любителю минимализма хотелось чего-нибудь быстрого, без проверок. Хоп и готово. Не знаю, что может быть быстрее этого:</p>
<pre>WRITE_PORT_UCHAR( (PUCHAR )0x64, 0xFE ); // пишем RESET
                                         // в контроллер клавиатуры</pre>
<p>При таких перезагрузках не забывайте предупреждать ваших пользователей о том, чтобы они сохранили свои документы.</p>
<p>Кто какие способы знает еще?</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fsww-it.ru%2F2009-03-17%2F76&amp;title=%D0%A0%D0%B5%D0%B1%D1%83%D1%82%D0%BD%D0%B8%20%D0%BC%D0%B5%D0%BD%D1%8F%20%D0%B6%D0%B5%D1%81%D1%82%D0%BA%D0%BE" id="wpa2a_10"><img src="http://sww-it.ru/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sww-it.ru/2009-03-17/76/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>VAD&#8217;о-рекурсия</title>
		<link>http://sww-it.ru/2009-02-23/16?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=vad%25d0%25be-%25d1%2580%25d0%25b5%25d0%25ba%25d1%2583%25d1%2580%25d1%2581%25d0%25b8%25d1%258f</link>
		<comments>http://sww-it.ru/2009-02-23/16#comments</comments>
		<pubDate>Mon, 23 Feb 2009 11:51:54 +0000</pubDate>
		<dc:creator>SWW</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[vad]]></category>
		<category><![CDATA[бинарное дерево]]></category>
		<category><![CDATA[рекурсия]]></category>

		<guid isPermaLink="false">http://sww-it.ru/?p=16</guid>
		<description><![CDATA[<p style="text-align: justify">В свое время, при написании анти-руткита мне понадобилось восстановить структуру спроецированных файлов в пользовательское пространство процесса. Выделения памяти и проекции секций процесса описываются механизмом Virtual Address Descriptors (VAD), указатель, на вершину которого находится в структуре _EPROCESS. VAD в Windows &#8212; это сбалансированное бинарное дерево. Первое, что приходит в голову &#8212; обходить это дерево [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify">В свое время, при написании анти-руткита мне понадобилось восстановить структуру спроецированных файлов в пользовательское пространство процесса. Выделения памяти и проекции секций процесса описываются механизмом <strong>Virtual Address Descriptors (VAD)</strong>, указатель, на вершину которого находится в структуре <strong>_EPROCESS</strong>. VAD в Windows &#8212; это сбалансированное бинарное дерево. Первое, что приходит в голову &#8212; обходить это дерево рекурсивно. Это оказалось большой ошибкой.</p>
<p><span id="more-16"></span></p>
<p style="text-align: justify">Указатель на вершину дерева можно получить из информации о процессе:</p>
<p>lkd&gt; !process 88a61670<br />
PROCESS 88a61670  SessionId: 0  Cid: 1068    Peb: 7ffdc000  ParentCid: 0534<br />
DirBase: 7f4b48c0  ObjectTable: e3227a00  HandleCount:  31.<br />
Image: Far.exe<br />
<strong>VadRoot 88b984e8</strong> Vads 53 Clone 0 Private 331. Modified 1. Locked 0.<br />
DeviceMap                                          e2693a78<br />
Token                                                   e483d9e0<br />
ElapsedTime                                        00:00:31.000<br />
UserTime                                             00:00:00.031<br />
KernelTime                                          00:00:00.265<br />
QuotaPoolUsage[PagedPool]           48236<br />
QuotaPoolUsage[NonPagedPool]    2216<br />
Working Set Sizes (now,min,max)  (917, 50, 345) (3668KB, 200KB, 1380KB)<br />
PeakWorkingSetSize                           917<br />
VirtualSize                                            28 Mb<br />
PeakVirtualSize                                   30 Mb<br />
PageFaultCount                                  1023<br />
MemoryPriority                                  BACKGROUND<br />
BasePriority                                         8<br />
CommitCharge                                   387</p>
<p>WinDbg может обойти дерево и вывести необходимую информацию:</p>
<p>lkd&gt; !vad 88b984e8 0<br />
VAD     level      start      end    commit<br />
88dc2268 ( 6)         10       11         2 Private      READWRITE<br />
89038678 ( 5)         20       20         1 Private      READWRITE<br />
8a64c350 ( 6)         30      12f        67 Private      READWRITE<br />
88fbdea8 ( 4)        130      134         0 Mapped       READONLY<br />
8919ac60 ( 6)        140      23f        10 Private      READWRITE<br />
8909d2e8 ( 5)        240      24f         0 Mapped       READWRITE<br />
88e7a368 ( 6)        250      265         0 Mapped       READONLY<br />
89852ef8 ( 3)        270      2b0         0 Mapped       READONLY<br />
888a0a28 ( 5)        2c0      300         0 Mapped       READONLY<br />
8924fdc0 ( 4)        310      315         0 Mapped       READONLY<br />
88accba0 ( 5)        320      3e7         0 Mapped       EXECUTE_READ<br />
89070470 ( 6)        3f0      3f0         1 Private      READWRITE<br />
8a712130 ( 2)        400      45c        16 Mapped  Exe  EXECUTE_WRITECOPY<br />
88a11e70 ( 6)        460      562         0 Mapped       READONLY<br />
88cf6e70 ( 5)        570      86f         0 Mapped       EXECUTE_READ<br />
8968a6f8 ( 4)        870      870         1 Private      READWRITE<br />
88d44148 ( 6)        880      880         0 Mapped       READONLY<br />
891d0b10 ( 5)        890      89f         4 Private      READWRITE<br />
88d69538 ( 6)        8a0      8a2         0 Mapped       READONLY<br />
88c0a1f8 ( 3)        8b0      8b0         0 Mapped       READONLY<br />
88c51528 ( 5)        8c0      8cf         4 Private      READWRITE<br />
887ca3d8 ( 4)        8d0      8d0         0 Mapped       READONLY<br />
897081e8 ( 1)        8e0      8ef         4 Private      READWRITE<br />
88aa1e70 ( 6)        8f0      8f0         0 Mapped       READONLY<br />
88aae5e8 ( 5)        900      90f         4 Private      READWRITE<br />
8908de90 ( 6)        910      91f         3 Private      READWRITE<br />
8a720680 ( 4)        920      921         0 Mapped       READONLY<br />
89599ce0 ( 6)        930      a2f        16 Private      READWRITE<br />
890d3408 ( 5)        a30      e2f       128 Private      NO_ACCESS<br />
8905bec8 ( 3)       1110     1111         0 Mapped       READONLY<br />
88864880 ( 4)      6d020    6d034         4 Mapped  Exe  EXECUTE_WRITECOPY<br />
890963e8 ( 5)      6d4c0    6d4c5         2 Mapped  Exe  EXECUTE_WRITECOPY<br />
894e2630 ( 2)      6d710    6d722         3 Mapped  Exe  EXECUTE_WRITECOPY<br />
88b841b8 ( 5)      6d730    6d742         3 Mapped  Exe  EXECUTE_WRITECOPY<br />
88a63440 ( 4)      71bd0    71be0         2 Mapped  Exe  EXECUTE_WRITECOPY<br />
890bd8c8 ( 3)      73070    73096         3 Mapped  Exe  EXECUTE_WRITECOPY<br />
895b6a18 ( 5)      76290    762ac         2 Mapped  Exe  EXECUTE_WRITECOPY<br />
895ab100 ( 4)      76b70    76b7a         5 Mapped  Exe  EXECUTE_WRITECOPY<br />
8967a328 ( 5)      76f50    76f62         2 Mapped  Exe  EXECUTE_WRITECOPY<br />
88b984e8 ( 0)      77380    77410         3 Mapped  Exe  EXECUTE_WRITECOPY<br />
89680c28 ( 4)      77420    77522         2 Mapped  Exe  EXECUTE_WRITECOPY<br />
88fd42c8 ( 3)      77ba0    77bf9         8 Mapped  Exe  EXECUTE_WRITECOPY<br />
88ff3c68 ( 2)      77c00    77c48         3 Mapped  Exe  EXECUTE_WRITECOPY<br />
88fcc868 ( 3)      77c50    77cee         2 Mapped  Exe  EXECUTE_WRITECOPY<br />
895481b0 ( 4)      77da0    77df1         3 Mapped  Exe  EXECUTE_WRITECOPY<br />
896999d0 ( 1)      77e40    77f41         6 Mapped  Exe  EXECUTE_WRITECOPY<br />
88ce7810 ( 4)      77f50    77feb         5 Mapped  Exe  EXECUTE_WRITECOPY<br />
8887ec88 ( 3)      7c800    7c8bf         6 Mapped  Exe  EXECUTE_WRITECOPY<br />
88fa00e8 ( 5)      7c8d0    7d0ce        31 Mapped  Exe  EXECUTE_WRITECOPY<br />
88faf9a8 ( 4)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ<br />
89545a38 ( 2)      7ffb0    7ffd3         0 Mapped       READONLY<br />
88c670e0 ( 4)      7ffdc    7ffdc         1 Private      READWRITE<br />
88c036e8 ( 3)      7ffdf    7ffdf         1 Private      READWRITE</p>
<p>Total VADs:    53  average level:    5  maximum depth: 6</p>
<p>Почему же использование рекурсии в ядре является ошибкой? В частном случае, на x86 системе размер ядерного стека равен двенадцати килобайтам (12Kb). Как известно, рекурсия сильно «пожирает» стек, особенно если вы используете структуры, выделяемые на стеке. Когда ядерный стек закончится, вы увидите прекрасное синее окно, на котором чаще всего будет написано:</p>
<p><span style="color: #0000ff;">Bug Check 0x7F: UNEXPECTED_KERNEL_MODE_TRAP</span></p>
<p>Первым параметром, скорее всего, будет число 0&#215;00000008, означающее Double Fault.</p>
<p>Выходом из данной ситуации является полнейший отказ от использования рекурсии или же использование лимитированной рекурсии со счетчиком. Я выбрал первый вариант и полностью отказался от использования рекурсии, учитывая то, что бинарное дерево можно обойти нерекурсивно (см. приложение к статье).</p>
<p style="padding-left: 30px;"><strong>Ссылки по теме:</strong></p>
<ul>
<li><a href="http://www.microsoft.com/whdc/driver/tips/KMstack.mspx" target="_blank">How do I keep my driver from running out of kernel-mode stack?</a></li>
</ul>
<ul>
<li><a href="http://www.wasm.ru/article.php?article=mem_management" target="_blank">Управление памятью в ядре Windows XP.</a></li>
</ul>
<p style="padding-left: 30px;"><strong>Приложения:</strong></p>
<div class="attachments"><dl class="attachments attachments-small"><dt class="icon"><a title="binary_tree_traverse" href="?aid=21&amp;sa=0" ><img src="http://sww-it.ru/wp-content/plugins/eg-attachments/img/flags/pdf.png" width="16" height="16" alt="binary_tree_traverse" /></a></dt><dd class="caption"><a title="binary_tree_traverse" href="?aid=21&amp;sa=0" >binary_tree_traverse.pdf</a> (169 kB)</dd></dl></div>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fsww-it.ru%2F2009-02-23%2F16&amp;title=VAD%26%238217%3B%D0%BE-%D1%80%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D1%8F" id="wpa2a_12"><img src="http://sww-it.ru/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sww-it.ru/2009-02-23/16/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Супер BUILD</title>
		<link>http://sww-it.ru/2009-02-22/11?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25d1%2581%25d1%2583%25d0%25bf%25d0%25b5%25d1%2580-build</link>
		<comments>http://sww-it.ru/2009-02-22/11#comments</comments>
		<pubDate>Sun, 22 Feb 2009 14:04:45 +0000</pubDate>
		<dc:creator>SWW</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[build]]></category>
		<category><![CDATA[wdk]]></category>
		<category><![CDATA[драйвер]]></category>

		<guid isPermaLink="false">http://sww-it.ru/?p=11</guid>
		<description><![CDATA[<p>Рано или поздно драйверописатель сталкивается с необходимостью использовать в своем проекте чужой код. Обычно, для сборки драйвера используется утилита BUILD, идущая в поставке WDK. Буквально недавно я столкнулся с очевидной проблемой данного инструмента:</p> <p>С:\path1\path2\path3&#62;build -g BUILD: Compile and Link for x86 BUILD: Loading c:\winddk\6001\build.dat&#8230; BUILD: Computing Include file dependencies: BUILD: Start time: Fri Feb 06 [...]]]></description>
			<content:encoded><![CDATA[<p>Рано или поздно драйверописатель сталкивается с необходимостью использовать в своем проекте чужой код. Обычно, для сборки драйвера используется утилита <strong>BUILD</strong>, идущая в поставке WDK. Буквально недавно я столкнулся с очевидной проблемой данного инструмента:</p>
<p>С:\path1\path2\path3&gt;<span style="color: #3366ff;">build -g</span><br />
<span style="color: #339966;">BUILD: Compile and Link for x86<br />
BUILD: Loading c:\winddk\6001\build.dat&#8230;<br />
BUILD: Computing Include file dependencies:<br />
BUILD: Start time: Fri Feb 06 15:50:51 2009</span><br />
<span style="color: #ff0000;">errors in directory С:\path1\path2\path3</span></p>
<p><span style="color: #ff0000;">Ignoring invalid directory prefix in SOURCES= entry: D:\somepath1\somepath2\somepath3\somepath4\somepath5\file.c</span></p>
<p><span style="color: #ff0000;"><span id="more-11"></span><span style="color: #000000;">Поиск в гугле вывел меня на <a href="http://www.osronline.com/showThread.cfm?link=59562" target="_blank">ветку</a> форума OSR Online:</span></span></p>
<blockquote><p><span style="color: #000000;">&#171;Welcome to the wonderful world of BUILD. It can only deal with source code in the same or parent directory of the &#171;sources&#187; file. It cannot use source files from arbitrary locations.&#187;</span></p></blockquote>
<p><span style="color: #000000;"> Таким образом, подключить в свой проект чужие исходные коды по произвольному пути не получится. Выходов из сложившейся ситуации я вижу два:</span></p>
<ol>
<li><span style="color: #000000;">Чужой код должен быть реализован в виде статической библиотеки. У этого способа есть как очевидные плюсы, так и очевидные минусы. Одним из минусов я считаю то, что разработчику, который пишет код для вас, придется часто собирать эту самую библиотеку или это должна делать build-машина.</span></li>
<li>Использовать преимущества современных <a href="http://ru.wikipedia.org/wiki/Система_управления_версиями" target="_blank">систем управления версиями</a>. Проблема решается выкачиванием нужного проекта в директорию, которая доступна инструменту <strong>BUILD</strong>. Свою проблему я решил именно так. Конечно, не стоит забывать и о синхронизации выкаченных файлов.</li>
</ol>
<p>Иногда на форумах появляются вопросы, в которых люди спрашивают можно ли управлять инструментом <strong>BUILD</strong>. В MSDN есть отдельный раздел, посвященный этой утилите: <strong>Win32 and COM Development -&gt; Windows Driver Kit -&gt; Driver Development Tools -&gt; Tools for Building Drivers -&gt; Build</strong>. Подраздел <strong>Build Utility Macros</strong> самый интересный.</p>
<p><span style="color: #000000;"> </span></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fsww-it.ru%2F2009-02-22%2F11&amp;title=%D0%A1%D1%83%D0%BF%D0%B5%D1%80%20BUILD" id="wpa2a_14"><img src="http://sww-it.ru/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sww-it.ru/2009-02-22/11/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>

