Запомните: плохих парней не заботит, если вы добавили код лишь для целей отладки. Если есть код - они его атакуют.
Посмотрите на такой код:
type TDocLoadingProc = procedure(Stream: TStream); var OnDocLoading: TDocLoadingProc; procedure LoadDebuggingHooks; var hmodDebug: HMODULE; begin hmodDebug := LoadLibrary('DebugHooks.dll'); if hmodDebug = 0 then Exit; OnDocLoading := GetProcAddress(hmodDebug, 'OnDocLoading'); end; function LoadDocument({...}): HRESULT; begin // ... if Assigned(OnDocLoading) // Дадим отладочной ловушке изменить документ перед загрузкой OnDocLoading(DocStream); // ... end;Если вы хотите отлаживать вашу программу, вы копируете
DebugHooks.dll
в папку приложения. Код выше ищет эту DLL и загружает её, если она есть. Для примера я включил код одной из возможных ловушек из этой отладочной DLL. Идея примера (и это просто пример, так что давайте не будем обсуждать, хороший ли это пример) состоит в том, что непосредственно перед загрузкой документа мы вызываем функцию OnDocLoading
. Эта функция может обернуть переданный ей поток в другой поток, так что содержимое потока можно логгировать при его чтении - в попытке локализовать на чём стопорится загрузка документа. Или её можно использовать для инъекции ошибок ввода-вывода с целью тестирования. В общем, используйте своё воображение.Но этот отладочный код также содержит уязвимость.
Вспомните, что пути для поиска DLL ищут библиотеки в таком порядке:
- Каталог приложения;
- Каталог system32;
- Каталог system;
- Каталог Windows;
- Текущий каталог;
- Пути из PATH.
DebugHooks.dll
в папку приложения, откуда она и загружается (шаг 1 в списке выше). Но если вы не отлаживаете свою программу, то шаг 1 пропускается, и поиск продолжается дальше. DLL не будет найдена на шаге 2, 3 и 4, и в итоге мы достигаем шага 5: текущего каталога.И теперь вас хакнули.
Как правило, ваше приложение не имеет прямого контроля над текущим каталогом. Пользователь может запустить вашу программу из любого каталога - и это каталог станет вашим текущим каталогом. И когда вызов
LoadLibrary
будет искать DLL в текущем каталоге, плохие парни могут положить в него их собственную DLL, ваша программа станет жертвой инъекции кода.Это особенно опасно, если ваше приложение ассоциировано с каким-то типом файла, поскольку пользователь может запустить вашу программу просто дважды-щёлкнув по файлу, с которым вы ассоциированы.
Когда вы дважды-щёлкаете по файлу, Проводник устанавливает текущий каталог для приложения-обработчика этого файла равным каталогу, в котором расположен этот файл. Это необходимо для правильной работы приложений, которые ищут в текущем каталоге вспомогательные файлы. Например, представьте гипотетическое приложение LitWare Writer, ассоциированное с файлами
*.LIT
. Документ приложения LitWare Writer, представленный файлом ABC.LIT
- это просто представитель семейства файлов: ABC.LIT (главный документ), ABC.LTC
(индекс документа и содержание), ABC.LDC
(словарь грамматики для документа), ABC.LLT
(пользовательский шаблон для документа) и так далее. Когда вы открываете документ C:\PROPOSAL\ABC.LIT
, LitWare Writer ищет остальные части документа в текущей папке, вместо C:\PROPOSAL
. Чтобы помочь таким приложениям найти все необходимые файлы, Проводник указывает функции CreateProcess
, что текущий каталог для приложения LitWare Writer должен быть равен C:\PROPOSAL
.Так, вы можете сказать, что программы вроде этого LitWare Writer (которые ищут файлы в текущей папке вместо папки с главным документом) плохо написаны, и я в этом с вами соглашусь. Однако Windows нужно работать даже с плохо написанными программами (упреждающее ехидное замечание: Windows сама плохо написана). В реальном мире есть слишком много плохо написанных программ, некоторые из которых являются лидерами в своих сегментах (см. выше упреждающий остроумный комментарий), и если Windows перестанет их запускать, люди скажут, что это вина Windows, а не этих программ.
Мне даже не надо закрывать глаза, чтобы представить, как нам присылают баг-отчёт с этим поведением:
"Эта программа отлично работает в MS-DOS, но в Windows она не работает. Тупая Windows".Клиент не будет счастлив услышать следующий ответ: "Вообще-то, эта программа никогда и не работала верно, ей просто везло все эти X лет. Авторы этой программы никогда не рассматривали случай, если открываемый документ расположен вне текущего каталога. Им это сошло с рук, потому что обычно вы открываете файлы в MS-DOS следующим образом: вы переходите в каталог с документом и потом набираете
LWW ABC.LIT
. Но если вы выполните в MS-DOS LWW C:\PROPOSAL\ABC.LIT
, то увидите то же (неверное) поведение программы. Иными словами, это поведение системы - не баг, а дизайн".Ответ на "Это поведение по проекту" обычно звучит как "Я скажу так, что дизайн, который не даёт мне выполнять мою работу - отстойный дизайн" или кратко: "Нет, это не дизайн, это баг" (вы не верите мне, что такое происходит? Просто почитайте Slashdot).
Итак, чтобы все такие программы продолжили бы работу в Windows, система устанавливает текущий каталог для программы в каталог, содержащий открываемый документ. Это вовсе не чрезмерное и не безрассудное решение - ведь благодаря ему начала работать программа. Не то чтобы запускаемой программе было важно конкретное значение текущего каталога - ведь у неё нет контроля над ним!
Но сказанное также означает, что если вы запустили программу двойным щелчком по ассоциированному документу, то программа будет удерживать каталог с документом - потому что этот каталог будет текущим. Если только, конечно, сама программа потом не изменит свой текущий каталог.
Бонус-замечание: изначально я написал эту серию заметок более двух лет назад. Но даже тогда я не считал их чем-то удивительным, новаторским или интересным. Но, похоже, некоторые люди вновь открыли это несколько месяцев назад, и вылезли из кожи вон, чтобы присвоить себе лавры первооткрывателей. Это как новое поколение подростков, которые думают, что они изобрели секс. Чисто для протокола: вот некоторые официальные инструкции (и, чтобы расставить все точки над i: это официальные инструкции по атаке на текущий каталог, а не официальные инструкции по сексу).
Историческое замечание: почему вообще есть текущий каталог? Ответ: это идёт со времён CP/M. В CP/M не было
PATH
. Всё запускалось из текущего каталога. Сегодняшнее состояние вещей - это цепочка из обратных совместимостей.
Комментариев нет:
Отправить комментарий
Можно использовать некоторые HTML-теги, например:
<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>
Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку.
Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.
Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.
Примечание. Отправлять комментарии могут только участники этого блога.