Безопасность в Дельфи




Проект "АнтиКрэковые Мучения"


Ядро системы и антиотладочные приемы.
Раздел "Анти крэковые мучения"
Шифрование кода. Часть I
Шифрование кода. Часть II
Шифрование кода. Часть III
Дмитрий Логинов ,
дата публикации 10.07.00

Большая благодарность Джефу Рихтеру за просветление меня, темного.

"Give me your kings, let me squeeze them in my hands, Your puny princes, You so-called leaders of your land, I'll eat them whole before I'm done..." Брайан Мэй, группа Queen.

Привет evrИваны,

Во-первых, прошу прощения за задержку. Футбол, знаете ли. Люблю иногда смотреть, как 22 бугая за мячиком носятся. Больше всего меня прикалывает манера комментаторов разговаривать на манеру ИХ ВЫСОЧЕСТВ. "НАШ МОНИТОР", "МЫ НЕДОВОЛЬНЫ", "НАШЕ МНЕНИЕ" ну вы поняли НАС?

Во-вторых, Прошу прощения за англицкий эпиграф. Переводить его не поднялась рука. Сразу добавлю енто усе сказано не про меня. И привел я этот эпиграф, потому как, видимо, пришло время высказаться про антиотладочную защиту и перспективы АКМ.

Уж не знаю, читали ли вы статью с моим небольшим участием "ПРО влияние каких-то там экономических факторов на software". Но знаю одно ПОКА мы с моим соавтором, другом, тезкой и братом по оружию зареклись писать такие ОПУСЫ. Ведь неделю рожали! Сколько посуды было перебито! Сколько клавиш стерто! Сколько морд набито! Надеемся не зря. Вообще-то зарекался от написания он. Я молчу - кошу под умного. Мне иногда бывает страшно интересно, как рождался тот или иной продукт. Я имею ввиду те каракули на бумаге, что с дъявольской закономерностью разбросаны на столе. Я имею ввиду те вечера ( или ночи? ) проведенные до покраснения в глазах и на горизонте. История добавляет интерес и художественный привкус к сухим фактам. Почему я об этом пишу? Потому как это имеет прямое отношение к тому, что я думаю об антиотладочных приемах.

Ну вроде как дань предисловию отдал. А теперь установка! Что бы я не сказал о разных приемах защит, не стесняйтесь применять то, что знаете вы. Не создавайте себе авторитетов. Это глупо! Для большей показухи перенесем защиту ПО на бытовуху. Представьте, что у вас есть дом. И вы знаете, что какой бы вы замок не поставили - всегда найдется домушник, который этот замок откроет. При всем при этом, поставите ли вы замок? Я думаю, что да. Так же и с защитой ПО.

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

Чтобы построить ракету, надо понять почему падает яблоко.
(С) Я, из раннего.

Первый вопрос анкеты - Какая ОЗззз постоянно падает на вашем компутере? Вопрос намбер ТУУУ - для какой ОС чаще всего вам заказывают проги? Не надо иметь сертификата высших магических курсов по гаданию на волосьях забуревших в период половой активности австралийских ленивцев, чтобы знать наиболее вероятный ответ на эти вопросы. Я думаю у каждого есть свое предположение о том как устроена ВИНДА. Гипотеза номер раз: Хреново она устроена! Эта гипотеза наиболее удобна для того, чтобы привыкнуть к кривизне собственных шаловливых ручек. Но кривизна эта - вещь далеко не постоянная. Поэтому этим людям приходится распространять свое писклявое кваканье и на другое ПО. Для них не только ОС крива, но и Делфи, и Це и вообще "Почему капы на клаве расположены не в алфавитном порядке!". Прямо "королевство кривых" получается. Полная противоположность "Королевству Делфи", где появляется немало знатных профессионалов. Поэтому посмотрим на другие гипотезы.

Все они сводятся к одному. То ли по иронии судьбы, то ли потому что списывалось это все с МАКовской системы, но все упирается в большой черный ящик WIN32 API. Устройство которого можно условно разбить на две части: Систему сообщений и Объектные функции. Хочу предостеречь. Под словом "объектные" я имел ввиду, в данном случае, структуры данных, отвечающих за конкретные ресурсы системы. И хотя они имеют возможность наследования, они ничего общего не имеют с понятием класса в ООП. Поясню для всех, что я имел ввиду.

Со времен ДОСа, сложилось так, что MS стремилось стандартизировать API. У нас имелся все тот же ящик, который лежал по конкретным адресам памяти. И у нас имелся набор вызовов программных прерываний INT 21H, INT 2FH и других, используя которые мы могли писать программы. Как давно это было. Операционка была кусочком пластилина. Мышь была врагом номер РАЗ для пользователей. Но прошли годы. Постепенно выпрямляются извилины, а пальцы наоборот становятся крючковатыми. И вот седой старец, искря статическим электричеством, молвит окружившим его отрокам низким закадровым голосом: "А потом был Windows... "

Сторожилы, вспоминая эти времена компьютерной перестройки, закатывают в старческом экстазе глаза и шепчут как молитву "KERNEL! Хранит нас всех KERNEL!". Лысеватые филологи яростно пишут в учебниках, что это не что иное, как ЯДРО. И расположилось ОНО своими просторными телесами не на небе, а в бесчисленном количестве DLL и VXD. А потом была первая и весьма неудачная попытка перехода от WIN16 к Win32s. Это на 60% были заглушки и 40% вызов win16. Кодеры махнули на это рукой. Но все-таки ребята, когда-то работавшие в DEC, сделали свое дело - появилась Windows NT. Юниксоиды показали язык 16-разрядному коду и привнесли в Винду ЧИСТА юниксовое понятие - поток. Только вместо STREAM назвали его THREAD. Также по старой привычке они написали HAL (Слой абстрагирования от оборудования). Было только одно НО. Вся эта прелесть не работала на тех хиленьких персоналках.

- Мама, мама, а память измеряется в метрах или в килограммах?

Но все равно это был успех. С точки зрения продуктов MS - это был первый прорыв в область качественного ПО. Поэтому было логично поддержать этот успех и выпустить Windows95... "А сейчас я буду петь свою прощальную песню" (С) Акелла.

Чтобы вся прелесть win32 работала на ПК, ее начали кастрировать. ДА ИМЕННО ТАК, а не урезать. В первую очередь отправили на свалку HAL. Дальше выбросили новую эмуляцию ДОС и win16, т.е. решили просто оставить старый глючный код. Такая же судьба постигла асинхронный ввод/ввывод на диск. Помните анекдот про форматирование флопа? Туда же, в корзину, полетели функции безопасности. Да и в завершении всего. Посадили за кастрацию не авторов, т.е. юниксоидов из DEC, а других очкариков. Объснялось это все тем, что Windows95 должна была послужить полигоном для создания и обкатки нового интуитивного интерфейса плюс работа с мультимедиа, на которую сделал ставку Гейтс. И он угадал! Когда вышло это лысое, бесполое, удушенное тугими пеленками дитя, ее начали отрывать вместе с полками. Многим нравилось, что по телефону возможен не только секс, но и техническая поддержка. Но это уже другая история, которую не все, наверное, хотят слушать! А?

"ШЕСТОГО приняли роды без ШЕСТИ минут ШЕСТЬ !" (С) Ю.Шевчук

Кхе-кхе, извините, отвлекся. Но, по крайней мере, вы знаете историю болезни пациента. Вот так MS намудрила, что не хватило ни OSR1, ни OSR2, ни Win98 c ее оэсэрами. Даже выпуском windows ME не могли закончить - образовался новый проект Tiger. Будем дружить, меня зовут ТИГРА. Дальше начинается ересь. Порисуем немного вместо болтовни:

Пользователь << тот кто оплачивает ваше пиво, курево и инет
Windows Message System << прозрачный необязательный слой
ЯДЕРНЫЕ или ЯДРЕНЫЕ объекты << вобщем-то самое главное
ДРАЙВЕРА << то о чем забывают
H A R D W A R E << то к чему ревнуют

Это, конечно, не имеет ничего общего с документацией MS. Это очень абстрактные слои, но даст вам хорошее представление о том как же это все ломается. Пользователь посылает сообщение объектам системы, там что-то щелкнуло, треснуло, хрякнуло и выплюнуло на языке понятном драйверам. Те подхватывают ЭТО и передают ЭТО оборудованию. И наоборот. Сильно упрощенная схема. ВОПРОС! А почему бы не напрямую использовать методы объектов. вместо - SendMessage( hWnd, WM_SETTEXT, sizeof(buf), buf ); //---------------------------------------------------------------------- делать - hWnd.WM_SetText( sizeof(buf), buf ); // если бы этот метод был Почему? А как быть если вы собираетесь написать свое сообщение? Ответ: Мнэээээ... А я бы описал производный класс! (Достает пистолет, стреляет. Шум падающего тела) -Еще есть версии? (Где-то скрипнул стул, кто-то откашлялся и посмотрел на дверь) -Версий нет. Объясняю ошибочность предыдущей. Запомните навсегда словосочетание, которое легло в основу виндовозов."ВЫТЕСНЯЮЩАЯ МНОГОЗАДАЧНОСТЬ". Т.е. та задача, которая очень настырна "вытеснит" другие. Об этом позже. Итак, исходя из этого, используя ПРОЦЕДУРНЫЙ вид работы, как вы будете поступать если:
  1. Как быть если несколько процессов вызывают этот метод WM_SetText?
  2. Как быть если я хочу вызвать другой метод, например WM_GetText, а выполнение предыдущего WM_SetText еще не закончилось?

Я думаю хватит. Всем и так понятна идея очередей. Но почему бы ее не сделать так же как в Юнихе? Поток памяти, поток портов и т.д. Ответ на этот вопрос дело вкуса разработчика. И это не имеет отношения к теме настоящего выпуска АКМ. Конечно модель используемая в Юнихе лучше, просто потому что более гибкая и обладает встроенными функциями безопасности. Таких вещей в интерфейсных частях виндовозов не наблюдается, что сильно упрощает взлом. Но прежде чем говорить об объектах системы сообщений винды, давайте вкратце рассмотрим тех кто их пораждает - "ядреные" объекты. Что такое "ядреные" объекты? Это процессы, потоки, файлы, семафоры, события и т.д. Отличить их "конструкторы" очень просто. Это все функции обычно начинающиеся на Create (СreateProcess) и имеют в качестве одного из параметров указатель на SECURITY_ATTRIBUTES. Вообще если хотите знать об этом подробней - читайте Джефри Рихтера "Windows для профессионалов". Если вы хотите сказать что-то в качестве критики в адрес Windows, освойте сначала win32 API на уровне этой книги. Я лишь добавлю, что еще одной скрытой особенностью этих объектов является статичность. Это как в СЯХ static свойства. Поясню для паскалистов. Если вы вызываете CreateProcess, то система смотрит - есть ли такой объект? Если нет - создает, если да - увеличивает счетчик процессов в системе и усе. Ловко?

Учитель: Гиви, докажи эту теорему. Гиви: Мамой клянусь, да! Видимо не совсем врубились? Объясняю по-русски и в последний раз. Код, отвечающий за поведение объекта, грузится один раз. Т.е. винда выделяет память единожды и единожды грузит туда код объекта. А что же с данными? А вот тут все как у людей. Данными-то эти объекты и отличаются, поэтому данные грузятся в разные блоки памяти. Например, когда вы вызываете два раза приложение "Калькулятор". То что же происходит?
  1. - CreateFile
  2. - CreateFileMapping
  3. - MapViewOfFileEx
  4. - CreateThread
  5. - Передача управления первичному потоку/нитке.
Система ни в коем случае не сравнивает экземпляры процессов! Просто она уже знает, что с таким именем процесс ужо стартовал. Как? Очень просто, исполняемы файлы винды - это файлы-проекции. Научное название этих зверюшек - файлы проецируемые в память, FILE MAPPING. Чтоб не маятся зубрежкой этого трехэтажного мата, просто запомните, что "ПРОЕКЦИЯ" - это маленькая копия файла свопинга, или как его называют в книжках "страничного файла". Башка еще не болит? Если да, то вернитесь к тому месту, когда было понятно и найдите во что вы не врубились. И проясните ЭТО. Самое сложное позади, поехали дальше.

Хочу напомнить для незнающих такое понятие как страница памяти. Так уж сложилась архитектура процессоров, что у всех кроме ALPHA она равна 4Кило. Это минимальный размер памяти, с которым имеет дело система. Сохранят в файл, копирует, защищает, освобождает, все это делает система страницами. Это очень удобно. Лично мне очень нравится, но это не имеет отношения к теме АКМ. Так вот, из-за этих проекций загрузка файла сильно упрощается и убыстряется. А когда юзер желает запустить прогу есче раз, система просто увеличивает счетчик этого объекта. Ну хорошо, а какже глобальные переменные и прочее? Как же защита данных у разных процессов? Просто система делает копию той страницы памяти, которую пытается изменить процесс. Вуаля. В результате, неизменные данные лежат в одном экземпляре, а изменившиеся в стольких копиях сколько экземпляров процесса запущено! Исключение составляют файлы, запускаемые с флоппов. Винда делает копию в файле подкачки. Здесь 95 винда всех наколола и работает не так как НТ. Но это неважно.

Вернемся к списочку. Если пускается второй "Калькулятор" первые два этапа пропускаются( CreateFile и CreateFileMapping см. выше). На третьем этапе просто меняется адрес для тех страниц, которые изменились в результате работы первого "Калькулятора" и все. Физические страницы памяти использовались те же, а адресное пространство другое. Быстро! И защита данных осталась. Подробности в упомянутой ранее книге Рихтера. Но их можно исследовать самостоятельно. Особенно, если в вашем распоряжении SoftICE и другие тулзы. Вы извините, но сырцов винды у меня нет и показать это на пальцах не могу. Только на словах. Конечно, если есть желание увидеть это все в ассемблерном виде, то ради бога - пишите.

Вы спросите меня, "А нам-то что с этого?". А я вам отвечу. Это можно очень широко использовать, как для защиты ПО так и для взлома. Знания - всегда палка о двух концах. Все зависит от ответственности и целей того у кого эти знания. Но вернемся к области применения того, чего я тут наговорил.

  1. Самое банальное, для разминки. ВЫНЬдоуз95 и иже с ним грузят процесс по адресу не ниже 400000Н. Конечно, вы можете указать линковщику другой адрес. А вот НТ грузит не ниже адреса 10000Н. Вот и подумайте, для разминки, как это использовать. То же касается данных.

  2. Следующий пункт гораздо полезней. Из знания о ядреных объектах вытекает следующее. Как вы думаете, что означает сл. код: hFile = CreateFile( ... ); hFileMap = CreateFileMapping( hFile, ... ); CloseHandle( hFile ); buffer = MapViewOfFile( hFileMap, ... ); CloseHandle( hFileMap ); buffer[1] = 1; UnmapViewOfFile( buffer ); Захватывающие занятие читать ХЕЛП? Гораздо полезней читать сырцы! Итак, вернемся к нашему тесту. 50% из вас посмотрели хелп по этим функциям или знали их семантику раньше. Остальная большая половина схалтурила и решила прочитать ответ в низлежащем тексте. Ничего страшного. У вас еще многое впереди. В чем-то вам можно позавидовать. Ну да ладно. Кое-кто из вас подумал:
    • а) создается/открывается файл
    • б) создание проекции файла
    • в) закрытие файла
    • г) привязка проекции к адресу процесса
    • д) закрытие проекции
    • е) или Ё) поймите меня правильно
    • ж) загадочное присваивание
    • з) отвязать буффер. Браво! Вы просто ходячая энциклопедия. Вопрос на засыпку. А изменения в буффере куда денутся? Непривычно, не правда ли? Конечно, если все параметры верные, то изменения запишутся в файл! Здорово. Это РАЗ. С первого разу немного странно видеть операции с файлом ПОСЛЕ ТОГО КАК ФАЙЛ ЗАКРЫТ. Это можно очень, очень, очень хорошо использовать. Ну самое банальное, это непривычно выглядит. Хакер пытается сначала мониторить FileOpen и др 32 или 16-разрядные функции. Поэтому этот способ "не наследит" в FileMonintor-e. Ведь дальше с файлом вы будете работать как с массивом. Но это не главное. Главное вот что. Дело в том, что вызов CreateFile необязателен. Звучит не совсем понятно. Пишу: вместо hFile = CreateFile(...); hFileMap = CreateFileMapping( hFile, ...); новая версия hFileMap = CreateFileMapping( HANDLE(0xFFFFFFFFH), ... ); Дальше, также как с обычными файлами. Область применения? SHAREWARE программы. Представьте ваша прога работает с файлами, ведет журналы, базу, ну и что-то еще. Но только на диске это все не хранится! Идет работа с файлом подкачки. И после выхода из проги не остается ни следа. И при сборке проекта вам не надо много мудровствовать! Просто убираете CreateFile и CloseHandle! Ну как? Можно использовать? продано.

      Лично я использовал это для написания шаблона класса виртуального массива, число элементов которого исчисляется 100-ми тысяч и миллионами. А в памяти занимет всего 64К! И небольше 100 строк исходников. Черт, но это другая интересная тема. Я тут как бы АКМ пишу.

      ЗЫ:
      все ядреные объекты относительно независимы (исключение, процесс без потока не создашь). А посему, открыв файл и создав его проекцию, можно со спокойной совестью закрыть файл. И так далее. Так даже нужно делать! Прога эфективней использует ресурсы и устойчива к апшибкам.

    • Еще хотите? Их есть у меня. Внимание, волшебное слово. Когерентность! КооХерентность. Коо... чего? Звиняйте тетки.
      "Стирай свой файл. Выкинь винчестер в кусты." (С) БГ, не Гейтс. Теперь только в монастырь. Там я буду по очереди просить у вас прощения, милые дамы. Но только умоляю - по очереди! "Хе, какой я гадкий. Самому противно!", как говорит мой друг, использующий в качестве ProgressBar-a мыслительного процесса сигареты.

      КОГЕРЕНТНОСТЬ (от лат. cohaerens — находящийся в связи) - синхронизация данных одного ядреного объекта между разными потоками/нитками. Т.е. раньше со времен win16 народ пользовался для передачи данных между процессами собщениями WM_SETTEXT и WM_GETTEXT. Что очень легко пронаблюдать, занести в журнал или поставить точку останова. Теперь, создав проекцию, о передаче данных не надо беспокоится. Дело в том, что ядренные объекты в 95 и 98-ых виндах хранятся в области памяти между 0х80000000 и 0хВFFFFFFF, т.е. там же где живут DLL-ки. Выше только VXD и код системы, которые кстати открыты для записи и чтения. Парадокс! Система защищает процессы от воздействия друг на друга, но не защищается от них самих. НТ совсем другое, там такое не пройдет! Для тех кто не в курсе, о любви ОС к большим числам типа 0хFFFFFFFF. Первые интеловские камни создавались на базе ТТЛ логики и все АЛУ строились без всяких флэшей на основе схем И-НЕ и ИЛИ-НЕ. Поэтому при подаче питания на входы камня, на шине данных появлялись единички, т.е FFFFFFFF и т.д. В результате POST-код БИОСа располагается по таким страшным адресам и код винды туда же! Отсюда и нечеловеческая логика в расположении программ в адресном пространстве.
      Итак, что же отсюда следует? Следует, что область памяти выше БОЛЬШОЙ ВОСЬМЕРКИ, т.е. 0x80000000, доступна для всех процессов, как зашареные диски. Пынятно? Если процесс А запишет по адресу в этой области "1", то процесс В запросто увидит эту единичку. Вот так. И никаких WM_SETTEXT и WM_GETTEXT! Ну не стоит, конечно, идеализировать в ICE можно брейк на обращение к этому участку памяти поставить, что сильно тормознет системку. Но идеальных, т.е. абсолютных защит нет. Абсолюты ваще не достижимы.

    • Черт, ужо многовато получается. Пропустим некоторые детали. Закруглимся с ядренными объектами. Самое вкусное. Вы, наверное, уже частенько встречали в инете и в умных книжках, что проклятушшша винда не дает писать в сегмент кода. Т.е. про динамические расшифровки (код, который расшифровывает себя на лету) можно забыть и уйти на другую сторону баррикад. Слышали? А я, много много много раз слышал. Ну в принципе - это так. Но фирма Борланд подготовила нам приятный сюрприз.

      Я как-то задумался, если в VCL возможна загрузка компонент из потока не только в design-time режиме, но и в run-time режиме - то как же быть с записью в сегмент кода? Захожу в сырцы, открываю forms.pas, прыгаю к функции MakeObjectInstance и что же???!!! Block := VirtualAlloc(nil, PageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); Упссс! Комментарии не лишни. Тута функция требует от системы, чтобы та выделила регион виртуальной памяти и тут же передала его в физическую память. А режим доступа - PAGE_EXECUTE_READWRITE. Но вынь, которая 95, такой флаг по-умному преобразует в PAGE_READWRITE, как сегмент данных. Ура! Значица мы могем вспомнить старые анархичные времена. Доказательства? А вспомните в предыдущем выпуске АКМ прием с процедуркой TryToCall. Когда я данные расположил в сегменте кода и менял его! Ну как, полезно?

    Все это лирика. Теперь главное. Система сообщений. То, что делает ваши проги столь простыми к взлому. Я уже начинал о ней говорить, но отвлекся на "ядреные" объекты. Если еще не забыли,то эти объекты имеют прямое отношение к ресурсам ПК, конструируются один раз и имеют функции безопасности. Есть у них еще две черты, о которых я хотел бы упомянуть.

    1. Слой. Это не программная вещь. Это аппаратная штука, определенная в селекторе задач проца. Она определяет все распальцовку в системе. За номером НОЛЬ идут главные отцы. Без их ведома в системе ничего не происходит. В вашей проге написано OUT DX,AL и винда бежит к главному авторитету и грит: "Тут эта, юзер в порт плюется! Че делать будем?" И так далее. Вот за таким НУЛЕМ и сидит SoftICE и все о вас знает и все может, а вы нет!
    2. Handle. Описатели - это индексы в списке созданных объектов. У всех объектов ядра они, хэндлы, процессо-зависимы, т.к. список всех хэндлов создается в рамках одного процесса. Т.е. если ваша прога открывает файл hFile = CreateFile и hFile равен 1, то в другой проге он будет отнюдь не 1, а если и будет равен, то это случайное совпадение в таблице хэндлом, создаваемой каждым процессом. А вот хэндлы(описатели) объектов системы сообщений наоборот одинаковы для всех процессов. Потому как лежат в самой бесправной области данных, куда лазят все кому не поподя. Но и не только поэтому.
    Итак, из чего же состоит эта пресловутая система сообщений? Первое - это объекты интерфейса (лежат в user32.dll и gdi32.dll) общего использования. Второе - это такое незаметное понятие, как ThreadInfo. Дело в том, что каждый процесс думает, что он один в системе. И виндоуз за этим следит, чтобы аварии одного процесса не влияли на ход выполнения другого процесса. Система создает некое окружение вокруг процесса, например, у каждого процесса своя текущая директория. Тоже самое с сообщениями. В win16 была общая очередь сообщений. Это вызывало массу проблем. Сейчас стоит потоку/нитке создать объект интерфейса появляется такая штука THREADINFO. Она хранит в себе очередь ввода, очередь сообщений и прочую асинхронную чушь. Для заблудших: синхронный ввод - это когда сидишь в школе на уроке и ждешь звонка. Звонок, перемена. Начинается нормальная жизнь. Асинхронный ввод, когда вам дают в глаз, а вы этого не ждали. Так вот, эти очереди фурынциклируют в асинхронном режиме.

    И третья часть. Рихтер называет ее RIT(raw input thread). Для себя я назвал ЭТО диспетчером разупорядоченного ввода. Вы, как человек жмакающий пимпы, заполняете очередь ввода. Диспетчер следит за тем, в очередь ввода какого объекта интерфейса положить эти жмаканья. Ваша прога заполняет просто очередь сообщений того окна, которое вы укажите. Не буду заниматься описанием работы RIT, лишь вкратце остановлюсь на очереди обычных сообщений. Каждый объект интерфейса обязан иметь цикл выборки сообщений GetMessage. Обычно это происходит в процедурке WndProc. Иногда используют Hook-и, вешая их на конкретные сообщения. Реже генерят объект ядра СОБЫТИЕ. Отвлекся. Вопрос: что обработается первым? ... PostQuitMessage(0); // посылаем сообщение WM_QUIT PostMessage( hwnd, WM_USER, 0, 0 ); // посылаем сообщение WM_USER ...

    Когда я увидел такой код, я долго водил пальцем по схеме работы GetMessage, пока не увидел ответ на вопрос. Сначала обработается WM_USER, а потом WM_QUIT. Давайте посмотрим:
    Порядок обработки
    1. То что послано SendMessage, т.к. пославший процесс "висит"-ждет обработки.
    2. То что послано PostMessage, пославший не ждет, но надеется.
    3. WM_QUIT
    4. Ввод, т.е. работаем с клавой, мышой, ВУ.
    5. Всякая прорисовка, т.к. черезвычайно тормознута
    6. WM_TIMER, т.к. больно частое и чтобы часы успевали рисоваться.
    Вот! Следует отметить, что если установлен HOOK, то вызовется сначала он. Т.е. это шаг 0. Поэтому точки останова на сообщение окна сработают раньше вашего обработчика. Даже если вы повесите свой HOOK, все равно сначала вызовется брейк, т.к. SoftICE повесил свой HOOK первым. К хукам мы еще вернемся в другом выпуске АКМ. Вот в кратце, что нам нужно сейчас знать о винде вообще и системе сообщений в частности. Хотя это всего лишь 10% того что есть на самом деле. Но обидно, что многие (не все) разработчики защит иногда не знают и этих 10%. Теперь про защиту.

    Откуда вообще появились эти "защиты" от отладки и дизассемблирования? Из больных мозгов программеров, с детства любящих прятаться в отдаленных школьных коридорах, чавкая мамины бутерброды. Дело в том, что если вы хотите снять защиту с какой-нить несчастной проги, вам надо узнать, как она работает в нужное время, в нужном месте. Например, у вас 20-метровая бухгалтерская прога, которая спрашивает пароль при выборе любого пункта меню. Была бы огромной тратой времени попытка узнать, как эта прога печатает отчеты. Вам нужно то место программы, где идет непосредственный вызов процедуры защиты. И то насколько точно вы можете это сделать, и будет характеризовать ваш кракерский талант.

    Со времен ДОСа использовались для этого отладчики или дизассемблеры. Это зависит от ваших приемов обнаружения кода защиты. Например, если вы знаете, что ввод с клавы - это функция ДОС или БИОС - вы открываете дизассемблер и ищите эти команды по маске. Так первые антивирусы искали первые вирусы - по маске. Это метод обладает малой селективностью. Т.е. таких функций может быть превеликое множество. Или процедурка одна, а места ее вызывающие занимают лист формата А4 при распечатке. Поэтому большей популярностью пользуется метод характерных сообщений. Например, "Введите пароль" или "Неверный пароль" или "Поздравляю! Вы ввели правильный пароль". Этот метод обладает максимальной селективностью, т.к. это конкретные сообщения процедуры защиты. Как он работает? Два подхода (для ДОСа):
    1. "Дурацкий". Ищется сигнатура MOV AH,9 INT 21H или MOV DX,что-то INT 21H Принцип - пытающийся стать кракером ищет функцию телетайпного вывода и смотрит не выводит ли код ИНТЕРЕСНУЮ строку? дурацкий метод.

    2. "Правильный". Отрыть дизассемблером прогу. Найти ИНТЕРЕСНУЮ строку. Дизассемблер сам покажет вам в каком месте кода происходит обращение к строке. Все! Этот метод настолько правильный, что работает и будет работать в любой системе.
    У отладчиков свои приемы обнаружения процедуры защиты. Их множество, они просты и разработчикам защит стало обидно. Они тратят недели или месяцы на защиту. А кракеры лоамют это максимум за час. Абыдно, да! И тогда у большинства пришла глупая мысль "ПРЯТАТЬСЯ". Большинству всегда приходят в голову глупые мысли. Настоящие рациональные идеи индивидуальны.

    Ловушка в том, что приемы ЭТИ стандартны. Их можно пересчесть по пальцем рук и ног. Нет, пожалуй только рук! А раз приемы эти стандартны, то у них есть сигнатуры! Значит, я по этим "приемам" могу, как по указателям, найти процедуру защиты. Или же локализовать эти фрагменты от воздействия на систему. Просто смешно видеть, как на "серьезных" сайтах пишут про методы обнаружения SoftICE. И за это они получают деньги? Детский подход. Если висит замок на самой толстой двери, то можно предположить, что там что-то прячут. В качестве демонстрации, напомню такую игру. Вы просите человека загадать целое число от 1 до 10. А потом задаете вопросы "Оно больше ?" применяете двоичный поиск. Можно предварительно посчитать и поспорить "Я угадаю на четвертом вопросе." Просто. Так же защита от отладки и от дизассемблирования. Она просто наводит на след.

    И по поводу нейтраилизации этих защит. Лично у меня есть 3 утилиты с исходниками, которые устраняют ВСЕ методы защиты от SoftICE.

    Вы слышали что-нибудь о DES? А о IDEA? А о CAST? А о RSA? Да, да, да и исходники достать могу. А делает ли то, что вы знаете алгоритм шифра, делает ли это его менее надежным? Нет! Вы знаете кто был первым ХАКЕРОМ? Аристотель. Раньше секретные сообщения передавли так. Пергамент наматывали на вал(бревнышко, хе-хе), именуя его скитал. Наматывали так, как обычно женщины мотают на палец волосы. Потом, не снимая пергамента, писали сообщение, но не по спирали, а в правильном порядке вдоль оси скитала. Если размотать пергамент порядок букв и слов нарушался. Восстановить его можно было, только имея "бревнышко", на котором нарезался этот пергамент. Аристотель "выстругал" своим бронзовым тесаком КОНУС. Наматывая пергамент на него, можно было увидеть совпавшие буквы. Они совпадали там, где диаметр конуса равнялся диаметру, потерявшегося бревнышка! ХАК. Пива и конф не было тогда, поэтому сей факт остался заметным только для кошелька Аристотеля. Да, раньше криптография болела той же болезнью, что и "защита ПО" болеет сейчас. Секретность основывалась на секретности алгоритма. Стоило узнать алгоритм - каюк шифру.

    Процедуре защиты должно быть глубоко по... Обнаружат ее или нет. Узнают, как она работает или нет. Если это не так - вы лоханулись. Как же быть? Кто виноват и что делать? Знакомые вопросы. Но мне пора закруглятся больно много написал. Хорошего по немногу. В завершении...

    Виновата ли ОС? Нет. Возьмем Уних. Она больше приспособлена к взлому ПО, т.к. несет с собой исходники, обладает большей склонностью к "ЖУРНАЛистике" и имеет меньший объем. Даже если бы это было не так. Разработчики SoftICE и разработчики IDA делают все по закону. Они ходют на семинары и курсы, покупают инфу по ОС у самой MS. Спрашивается нахрена так делает MS? Смотри статью с моим участием "Про замороченные экономические факторы".

    Что делать? Внедрять повсеместно шифрование в ПО, плюс "Управляемая ошибка". Последнее - это альтернатива прямой рекции ПО на обнаружении конца SHAREWARE или обнаружении, что НАС сломали. Например, у вас прога расчета полета консервной банки в безвоздушном пространстве близ Юпитера. Каков будет правильный ответ не знает никто. И сомневаюсь, что хакеры когда-нить будут знать релятивисткую механику. Вы просто вводите ошибку в расчеты. Программа работает, выдает результат. Только результат этот нифига не значит! Способ этот хорош тем, что это можно спрятать в электронный ключ. Исходя из этого становится ясно следующее. Если вы хотите писать, что-то серьезное и не сойти с ума от приступов паранои. Вам волей не волей придется переходить на С++. Я сам писал на паскакале большинство своих прог (за редким исключением) до сего года(7 лет). Мне нравится паскакаль и я не чего не имею против него. Но для задач, которые стали вставать передо мной, мне потребовался C++. Это не флейм и не камень в чей-то огород. У меня есть несколько классов, которые я бы с удовольствием показал на Королевстве, но это "Королество Делфи". Поэтому я показываю решения, которые доступны делфинистам. Без обид. Дома у меня тоже Делфи, но лишь потому, что тачка слабая. Работа другое дело. Функционально все, что есть у меня, можно написать на Делфи. Но выглядеть это будет ГАДКО. Тот же виртуальный массив. В сях мне пофигу тип элементов, т.к. класс у меня написан через шаблон(template). В Делфи мне бы пришлось описать это все через нетипизирванные указатели, а в проге мучится с преобразованием типов и страхом пропустить непарную скобку. Ну все хватит. Это не наезд. Это критерий выбора. Тут много факторов. Универсального ответа быть не может. В моем случае единственным решением был переход на С++, который безболезненно прошел меньше чем за месяц.

    В принципе, на этом можно было бы на время прекратить выпуски АКМ. Так как методы шифрования известны всем. А способы их применения я уже показывал. Но есть некоторые приемы "затуманивания" мозгов кракеров и интересный способ невозможности изменить код вашей программы. Я о них даже не упоминал. Так что как только время появится раскажу. Жаль, что пока все это на моей совести. Написал бы кто-нибудь что-нибудь... Ну, ладно еще на один выпуск силенок хватит. Пока.

    Дмитрий Логинов. 6 июля 2000г.










    Начало  Назад  Вперед


    Книжный магазин