понедельник, 1 декабря 2008 г.

Когда программы начинают закапываться в недокументированные структуры...

Это перевод When programs grovel into undocumented structures... Автор: Реймонд Чен.

Вот навскидку три примера программ, которые полагались на недокументированные структуры.

Дефрагментирую то, не знаю что
В Windows 2000 есть несколько категорий вещей, которые не могут быть дефрагментированы. Каталоги, эксклюзивно открытые файлы, MFT, файл подкачки... Но это не остановило некоторые компании от дефрагментации таких вещей в своих продуктах. Они залезли в режим ядра, расшифровали внутренние структуры данных NTFS и изменяли их на лету. Иххх-хха, ковбой! А когда позже ребята, отвечающие за NTFS, добавили поддержку дефрагментации MFT в Windows XP, эти программы влезали и модифицировали структуры NTFS (которые, кстати, поменялись) и полностью портили ваш диск.

Конечно же, в документации не было никакого упоминания об изменившемся поведении. Поэтому когда фоновый дефрагментатор повреждал диск, все помидоры летели в Microsoft.

Парсинг структур данных Проводника
Одна софтверная компания решила, что им нужно модифицировать поведение окна Проводника из расширителя оболочки (shell extension). Поскольку нет никакого способа сделать это легально (расширение оболочки не должно влиять на пользовательские настройки окна - они принадлежат пользователю), то они решили сделать это другим способом.

Из расширения оболочки они использовали недокументированное сообщение, которое позволяло получить указатель на внутренние структуры данных Проводника. Потом они проходились вдоль структуры, пока не находили часть, которую они узнавали. Потом они говорили: "штука, что я хочу, лежит сразу за штукой, что я сейчас опознал".

Ну, той "штукой", что они хотели и той штукой, что они опознавали, являлись базовые классы другого класса с множественным наследованием (такое не поддерживается в Delphi - прим. пер.). Если у вас есть класс, который наследуется от нескольких других классов, то нет никаких способов узнать порядок классов - это зависит от компилятора. Так уж случилось, что порядок этот был X,Y,Z во всех версиях Windows, в которых они протестировали свой продукт.

Кроме Windows 2000.

В Windows 2000 компилятор решил, что порядок будет X,Z,Y. Теперь, когда они просматривали структуру, видели "X" и говорили: "ага, следующей штукой здесь должен быть Y", но вместо этого там был Z. И тогда чуть позже они крэшили всю вашу систему.

Поэтому мне пришлось создать "фальшивый X,Y", поэтому когда программа начинала искать X (чтобы взять Y), то она находила и брала фальшивый Y.

Этот случай отнял у меня добрую половину недели на анализ.

Достигая стека
Ещё одна софтверная компания решила, что слишком тяжело брать координаты из уведомления NM_DBLCLK и тестировать их по объекту treeview, чтобы определить по чему же дважды щёлкнул пользователь. Поэтому вместо этого они взяли адрес структуры NMHDR, передаваемой уведомлению, добавляли к нему 60 и разыменовывали получившийся указатель в число типа DWord. Если это был ноль, то они делали одну вещь, а если нет - то другую.

Так уж получилось, что NMHDR размещалась в стеке, поэтому программа добиралась до стека и тырила с него значение некоторой локальной переменной (которая, так получилось, была ровно на два фрейма выше по стеку!) и использовали её для контролирования своей логики.

Для Windows 2000 мы обновили компилятор до нового уровня, когда он начал по-умному распоряжаться локальными переменными, и теперь программа не могла найти свою локальную переменную и переставала работать.

Меня назначили на поиск и устранение этой проблемы. Мне пришлось создать специальную структуру NMHDR, которая "выглядела как" стек, который хотела увидеть программа, и передавать в обработчик именно этот "фальшивый стек".

Думаю, что этот случай занял у меня два дня.



Я думаю, что вы понимаете, почему я буквально взрываюсь, когда люди рекомендуют использовать недокументированные вещи. Ладно это были бы просто любители, ковыряющиеся у себя в гараже, чтобы посмотреть, что они могут сделать. Но все эти случаи были от крупных компаний, занимающихся коммерческим софтом.

Когда вы обновляетесь до новой версии Windows и испытываете (a) порчу диска (b) случайные вылеты Проводника (c) случайные потери функциональности в своей любимой программе, то будете ли вы винить программу или Windows?

Если вы сказали: "я буду винить программу", то первая ваша проблема: конечно же, определить программу-виновника. В первом и втором случае вредитель совершенно не очевиден.

Читать далее: Почему бы просто не заблокировать приложения, которые используют недокументированное поведение?

2 комментария:

  1. Дефрагментирую то, не знаю что

    Правильное решение - дефрагментировать эти файлы до их открытия, на ранней стадии загрузки. Как это делает, скажем, PageDefrag.

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.