Сейчас на форуме: ==DJ==[ZLO], Magister Yoda, Rio (+6 невидимых) |
![]() |
eXeL@B —› Основной форум —› Интересует мнение о статье :) |
Посл.ответ | Сообщение |
|
Создано: 17 февраля 2005 13:33 · Личное сообщение · #1 |
|
Создано: 17 февраля 2005 15:11 · Личное сообщение · #2 |
|
Создано: 17 февраля 2005 15:22 · Личное сообщение · #3 |
|
Создано: 17 февраля 2005 15:22 · Поправил: MoonShiner · Личное сообщение · #4 Статья весьма познавательная=) Можно было бы добавить "Аффтар жжот", если бы не несколько замечаний: 1) Насчет фразы о невозможности противостоять табличной эмуляции... Предположим следующую ситуацию. У меня была (действительно ![]() 2) Логгер может быть неспособен отловить все обращения к ключу. Опять таки, разработчики не всегда полные кретины и могут (проверено) обращаться к ключу используя несколько экземпляров АПИ в коде... Т.е., например, функция nskRead (извиняюсь, что примеры только гвардант, но у софта, их пользующего, эти трюки видел) может присутствовать в коде несколько раз... Т.о., придется писать логгер, который будет определять все возможные вхождения в АПИ ключа. 3) Еще один минус табличной эмуляции... Есть громоздкий профессиональный софт, на качественный тест которого, как правило, у крякера нет ни желания, ни терпения, ни знаний. А функции кодирования\декодирования могут вызываться при каких угодно операциях и, в том числе, по случайному алгоритму (может вызовется, а может и нет)... Т.о., нет никакой гарантии, что логгер, даже при большом количестве запусков, соберет полную инфу об операциях с ключом. 4) Насчет неинтересности RNBOsproFindFirstUnit. Встречаются проверки на эмуляторы, которые пытаются найти десяток-другой подходящих затычек в компе. Эмулятор, необрабатывающий эти операции, как правило, будет рапортовать, что да, есть такой ключик.... Это одна из квазипродвинутых проверок на эмулирование. 5) CRC файла... А также - защита может быть разбросана по десятку либ... Неужели для каждой из них писать логгер? К чему клоню... Отвязывание прог от затычек намного эстетичнее (и законнее=) происходит путем написания драйвера-эмулятора (может фильтр, может нет). Но проблему с секретными функциями можно снять лишь зная "секретные" функции ключа. Так что, без логгирования результатов этих функций непосвященному, видимо, не обойтись. Приведенные замечания (и придирки ![]() ![]() ЗЫ Ну почему ж сорцы на дельфи? =) ЗЗЫ Сорри, что запостил в форуме, в комментах почему-то не получилось (мож размер...) ![]() |
|
Создано: 17 февраля 2005 16:07 · Поправил: Dr0x · Личное сообщение · #5 Отвечаю: 1)Цитирую фрагмент статьи: "Таким образом, построение защищенного ПО сводится к максимальному "запудриванию" работы с ключом как то, динамическая дешифрация ресурсов, данных, кода; недетерминированность трека ключа; ложные запросы к ключу и т.п. И то, насколько эффективно разработчик сможет реализовать подобные приемы и будет характеризовать стойкость ПО к взлому." Я и не говорил никогда о том, что табличная эмуляция эффективна или неэффективна . В каждом конкретном случаё - свои заморочки. Я лишь продолжаю утверждать о её ПРИНЦИПИАЛЬНОЙ возможности. Всегда. Без исключений. 2) ЭТОТ ЛОГГЕР может быть неспособен отловить все обращения к ключу. Причём с МИНИМАЛЬНЫМИ доработками - сможет ![]() 3) Именно так. Я никогда не говорил, что голова на плечах не нужна. ![]() ![]() 4):Видимо, всё таки RNBOsproFindNextUnit имелся в виду ? Это экзотика, но даже если и так, принципиально ничего не меняется. Я думаю, каждый кто прочитал статью сможет его проэмулировать (вернуть константу) ![]() 5) CRC файла - это уже совсем из другой оперы ![]() А насчёт десятка либ - логгер то один, а вот точки входа в АПИ придётся смотреть в них во всех ![]() ![]() Написание драйвера - да, это вариант безусловно имеющий свои плюсы. Но для ПОДАВЛЯЮЩЕГО большинства задач это будет как из пушки по воробьям За респект отдельное спасибо ![]() P.S. А потому что на дельфи. Исторически так сложилось ![]() ![]() |
|
Создано: 17 февраля 2005 16:21 · Личное сообщение · #6 1) Я имел в виду фрагмент, расположенный выше приведенного - о неспособности программы, использующей "секретные" функции противостоять табличным эмуляторам. Это несколько не "принципиальная возможность" табличной эмуляции ![]() 4) Именно она, ашипка вышла. 5) Драйвер хорош тем, что при минимальных изменениях (память+аппаратные алгоритмы ключа) не будет зависеть от другого софта, а без изменений - от версии софта (разные смещения для патча)... И потом, написание своего драйвера - намного более законное дело, чем патч чужой ![]() ![]() |
|
Создано: 17 февраля 2005 16:44 · Личное сообщение · #7 |
|
Создано: 17 февраля 2005 17:02 · Поправил: Dr0x · Личное сообщение · #8 To ssx: У Snow Panther просто подмена длл, т.е. для случая динамической линковки. В любом случае куски отработчиков API Sentinel из неё можно использовать для доведения логгера до боевого варианта ![]() To MoonShiner: 1) Иначе говоря, ты утверждаеш, что есть случаи когда программы, использующие "секретные" функции способны противостоять табличным эмуляторам. Т.е. принципиально ? Если генерить рандомные запросы к ключу, то безусловно, лог будет громаден (правда, при использовании PRNG, всё равно конечен, а других у нас считай что нет ![]() Так вот, отсечение ложных запросов это задача не логгера, а человека. Именно человек сам, или при помощи каких-либо тулзеней должен ПОНЯТЬ когда и где случаются эти запросы. Это можно делать прогоняя несколько раз прогу и сравнивая логи, или копанием дизассемблере\дебуггере или ещё как. Не важно. После выяснения мест и ситуаций, когда это может происходить достаточно пропадчить программу так, чтобы эти запросы никогда не происходили или просто не эмулировать их, возвращать OK и любой мусор подходящего размера. Именно для этих целей в статье показано, как получить return address, зная конверсию вызовов в каждом конкретном случае стэк можно раскрутить еще глубже и в дальнейшем использовать, к примеру, полученный адрес как критерий "не рандомности" запроса к ключу. 5) К сожалению, понятие законности здесть относительное. Драйвер законен до тех пор, пока он сам по себе, пока не использует какую-либо информацию о эмуляции конкретной программы (конкретные запросы-ответы и т.п. ) Если эта информация присутсвует где-либо в комплекте "поставки драйвера", то всё выходит за рамки законности, т.к. эту информацию можно получить только посредством исследовани ПО. А это выходит за рамки лицензионного соглашения ![]() Usermode эмулятор в этом смысле ничем не отличается от драйвера. Пока эта его длл лежит сама по себе, с незаполненными таблицами вопросов-ответов и т.п. она законна, но как только она начинает использоватся для эмуляции конкретного ключа - законность заканчивается ![]() |
|
Создано: 17 февраля 2005 20:41 · Поправил: Privet · Личное сообщение · #9 |
|
Создано: 17 февраля 2005 21:04 · Личное сообщение · #10 |
|
Создано: 17 февраля 2005 21:41 · Личное сообщение · #11 |
|
Создано: 28 февраля 2005 12:11 · Личное сообщение · #12 если вернуться к первоначальной теме: Dr0x пологаю, нужно было приложить API.txt и сам объект исследования или как min указать ссылки на них.. Теперь о главном: есть простой пример когда табличная эмулюция не поможет, точнее в одном примере придется дополнительно "фиксировать" несколько переменных, задействованных в формировании "запроса" к ключу. Если их удастся локализовать и их "фиксация" не приведет к "слому" программы... Пример: 004D6A1F . A0 FC4A7C00 MOV AL,BYTE PTR DS:[7C4AFC] 004D6A24 . B2 29 MOV DL,29 004D6A26 . F6EA IMUL DL 004D6A28 . 884424 17 MOV BYTE PTR SS:[ESP+17],AL 004D6A2C > 8AC1 MOV AL,CL 004D6A2E . B2 78 MOV DL,78 004D6A30 . F6EA IMUL DL 004D6A32 . 8A5424 16 MOV DL,BYTE PTR SS:[ESP+16] 004D6A36 . 2AD0 SUB DL,AL 004D6A38 . 8A4424 17 MOV AL,BYTE PTR SS:[ESP+17] 004D6A3C . 2AD0 SUB DL,AL 004D6A3E . 80EA 24 SUB DL,24 004D6A41 . 88540C 74 MOV BYTE PTR SS:[ESP+ECX+74],DL 004D6A45 . 41 INC ECX 004D6A46 . 83F9 38 CMP ECX,38 004D6A49 .^7C E1 JL SHORT zmx_20.004D6A2C 004D6A4B . 33C0 XOR EAX,EAX 004D6A4D > 8A4C24 1E MOV CL,BYTE PTR SS:[ESP+1E] 004D6A51 . 8A5424 1F MOV DL,BYTE PTR SS:[ESP+1F] 004D6A55 . 32CA XOR CL,DL 004D6A57 . 8A5404 74 MOV DL,BYTE PTR SS:[ESP+EAX+74] 004D6A5B . 32D1 XOR DL,CL 004D6A5D . 885404 74 MOV BYTE PTR SS:[ESP+EAX+74],DL 004D6A61 . 40 INC EAX 004D6A62 . 83F8 38 CMP EAX,38 004D6A65 .^7C E6 JL SHORT zmx_20.004D6A4D 004D6A67 . 8B15 04B47C00 MOV EDX,DWORD PTR DS:[7CB404] 004D6A6D . 399A E4E10000 CMP DWORD PTR DS:[EDX+E1E4],EBX 004D6A73 . 74 22 JE SHORT zmx_20.004D6A97 004D6A75 . 8B15 08B47C00 MOV EDX,DWORD PTR DS:[7CB408] 004D6A7B . 6A 38 PUSH 38 004D6A7D . 8D8424 D404000>LEA EAX,DWORD PTR SS:[ESP+4D4] 004D6A84 . 68 D8817E00 PUSH zmx_20.007E81D8 004D6A89 . 8D4C24 7C LEA ECX,DWORD PTR SS:[ESP+7C] 004D6A8D . 50 PUSH EAX 004D6A8E . 51 PUSH ECX 004D6A8F . 6A 16 PUSH 16 004D6A91 . 52 PUSH EDX 004D6A92 . E8 09702700 CALL zmx_20.0074DAA0 MOV AL,BYTE PTR DS:[7C4AFC] - введение в расчет-формирование кода запроса переменной величины CALL zmx_20.0074DAA0 - начало обращения к API ключа. А вот при использовании дизактивации/активации или модифицировании ячеек ключа - на один и тот же код запроса в некий промежуток времени будет получено несколько (даже двух будет достаточно) различных ответов !! и что сможет предложить таблица?! Собирать все запросы - глупо и не возможно, особо при использовании периодических проверок на наличие ключа.. В моем случае было от 21hex (в старой версии) до 90hex (в новой) [b]уникальных запросов[\b].. Часть из которых регулярно подвергалась изменениям (см. выше).. О самой статье - достойно, весма достойно... на мой взгляд, было бы полезно осветить некоторые нюансы: 0074DC24 |. E8 F71A0000 CALL zmx_20.0074F720 0074DC29 |. 8BF8 MOV EDI,EAX 0074DC2B |. 66:8B07 MOV AX,WORD PTR DS:[EDI] 0074DC2E |. 66:3D 4372 CMP AX,7243 Что такое "7243"? Или как интерпретировать API ключа в случае вложенности при использовании? т.е. вызывается API + 3 параметра 0054024A . 55 PUSH EBP 0054024B . 55 PUSH EBP 0054024C . 52 PUSH EDX 0054024D . E8 BED92000 CALL zmx_20.0074DC10 из которой вызывается 0074DC23 |> 56 PUSH ESI 0074DC24 |. E8 F71A0000 CALL zmx_20.0074F720 дальше 0074DC43 |. 50 PUSH EAX 0074DC44 |. 51 PUSH ECX 0074DC45 |. 56 PUSH ESI 0074DC46 |. E8 552B0000 CALL zmx_20.007507A0 дальше 0074DC87 |. 50 PUSH EAX ; /Arg3 0074DC88 |. 51 PUSH ECX ; |Arg2 0074DC89 |. 56 PUSH ESI ; |Arg1 0074DC8A |. E8 51420000 CALL zmx_20.00751EE0 ; \zmx_20.00751EE0 и все эти процедуры - API .. по наличию описанного в статье признака 0074DC2E |. 66:3D 4372 CMP AX,7243 0074DC32 |. 75 2E JNZ SHORT zmx_20.0074DC62 и 0074DC62 |> 66:3D 4272 CMP AX,7242 0074DC66 |. 75 17 JNZ SHORT zmx_20.0074DC7F [b]Итог[\b] Все выше перечисленное совершенно не умаляет достоинств статьи и подхода автора... Искренние поздравления! Но есть еще что исследовать и описывать. Успехов! ps. форматирование приведенных кодов уж как получилось - не обессудьте!! ![]() |
|
Создано: 28 февраля 2005 12:35 · Личное сообщение · #13 и последнее: я почти соглашусь: сбор данных max близко в ключу (в API) как правило max корректен. НО всегда ли оправдан?! вот пример: 004CC323 . A1 08B47C00 MOV EAX,DWORD PTR DS:[7CB408] 004CC328 . 6A 38 PUSH 38 004CC32A . 8D8C24 D404000>LEA ECX,DWORD PTR SS:[ESP+4D4] 004CC331 . 68 D8817E00 PUSH zmx_20.007E81D8 004CC336 . 8D5424 7C LEA EDX,DWORD PTR SS:[ESP+7C] 004CC33A . 51 PUSH ECX 004CC33B . 52 PUSH EDX 004CC33C . 6A 16 PUSH 16 004CC33E . 50 PUSH EAX 004CC33F . E8 5C172800 CALL zmx_20.0074DAA0 Это начало обращения к ключу .Почему, собственно, не снять данные по имеющимся параметрам?! В этом примере фактически я "снимал" код запроса, длинну получаемых данных и адрес их размещения через стек и соответственно эмулировал наличие ключа поиском в mini-base "запрос-ответ". При таком решении все нижележащие API просто НЕ используются (очевидно). Конечно, пришлось отдельно "исправлять" определение номера ключа и соответствии ключа и версии софта, но это уже пустяки..... Вот, пожалуй, и все... Успехов всем! ![]() |
|
Создано: 03 марта 2005 11:29 · Личное сообщение · #14 если я правилоьно понял - основная идея - это патч приложения в точках входа в апи (при статической линковке) и снятие логов работы. Так ? Тогда на 3 порядка эффективнее использование логгера на уровне драйвера. Причины: 1. логгер универсален. не надо заниматся херней и каждый раз заново искать АПИ 2. логгер легким движением руки преобразуется в табличный эмулятор Согласен что написание подобного логгера - это уже не уровень делфи прог, однако цель вполне оправдывает затраты. Теперь по самому принципу табличной эмуляции - я согласен что таблицу построить можно в 99% случаев. Однако есть такие моменты, как например по рандому генерим число, прогоняем его через функцию ключа и полученным результатом шифруем файл. Ессно в файле сохраняем и первоначальное число. Таким образом без знания "секретной функции" принципиально невозможно обеспечить совместимость сломанной версии с легальными (в направлении легальная -> сломанная). Также есть вариант с шифрованием на ключе всех текстовых строк приложения. Т.е. от строки берется хеш, затем ключ и получаем константу шифровки. Могу совершенно определенно сказать что без знания "сф" экономически нецелесообразно (а это один из определяющих факторов) строить таблицу. Ибо к моменту завершения простроения выйдет новый билд, в котором пару строк поменяли и начинай все с начала. Примеры можно продолжать - фантазия _НОРМАЛЬНЫХ_ разработчиков неистощима. Вывод - таблица - не панацея. ![]() |
|
Создано: 03 марта 2005 11:52 · Личное сообщение · #15 infern0 пишет: таблицу построить можно в 99% случаев а вот с этим позвольт не согласиться. Хотя итоговый вывод верен... Возможная причина в том, что при добавлении в формирование "запросов" для обрабоки в ключе min изменений в зависимости от каких-либо внешних причин (см пример выше) таблица прекращает свое существование по опредению. Кстати, драйвер тоже не сможет в такой ситуации помочь.. Особо если, должны быть получены данные не только для определения корректной регистрации, но и для последующей работы софта. Именно поэтому все описанные выше методы имеют право на "жизнь". Панацея, как обычно, отсутствует... Все, как всегда, определяется с помощью серого вещества в каждом конкретном случае. ![]() |
|
Создано: 03 марта 2005 16:09 · Личное сообщение · #16 |
|
Создано: 03 марта 2005 16:11 · Личное сообщение · #17 |
|
Создано: 03 марта 2005 16:24 · Личное сообщение · #18 infern0 пишет: именно поэтому лучше один раз написать драйвер и потом просто таблички набивать (в большинстве случаев даже не заглядывая в код проги) чем каждый раз парится с точками входа в АПИ. На 10-й раз заебет ;) гм.... написание банального дампера/граббера (называй как хочешь) дело пары дней с перерывами и перекурами а драйвера?! впрочем, каждый имеет право на свой путь..... ![]() |
|
Создано: 03 марта 2005 18:05 · Личное сообщение · #19 |
|
Создано: 03 марта 2005 18:36 · Личное сообщение · #20 |
|
Создано: 04 марта 2005 19:30 · Поправил: Dr0x · Личное сообщение · #21 Спасибо всем отозвавшимся . bi0w0rM обязательно ![]() DMD пологаю, нужно было приложить API.txt и сам объект исследования или как min указать ссылки на них.. Забыл однако. Добавил в комменты ссылку.. есть простой пример когда табличная эмулюция не поможет, точнее в одном примере придется дополнительно "фиксировать" несколько переменных, задействованных в формировании "запроса" к ключу. Если их удастся локализовать и их "фиксация" не приведет к "слому" программы... Если я правильно понял то, о чём ты говориш то отвечаю: Про проблему, которую ты обозначил, я уже говорил ранее. Да, сбор данных усложняется, возможно придётся вручную "отключать" подобные ветки в программе, но, всё равно, после такого рода предварительной подготовки можно будет собрать _действительно_ значимые запросы к ключу и проэмулировать их. А вот при использовании дизактивации/активации или модифицировании ячеек ключа - на один и тот же код запроса в некий промежуток времени будет получено несколько (даже двух будет достаточно) различных ответов !! и что сможет предложить таблица?! Никто не мешает отслеживать активации\дизактивации в логгере и вести себя соответственно. Насчет недоосвещенностей ряда деталей - тут как уж вышло. В любом случае я не считаю эти _детали_ критичными для понимания сути. Все выше перечисленное совершенно не умаляет достоинств статьи и подхода автора... Искренние поздравления! Но есть еще что исследовать и описывать. Спасибо на добром слове ![]() и последнее: я почти соглашусь: сбор данных max близко в ключу (в API) как правило max корректен. НО всегда ли оправдан?! ... Это начало обращения к ключу .Почему, собственно, не снять данные по имеющимся параметрам?! В этом примере фактически я "снимал" код запроса, длинну получаемых данных и адрес их размещения через стек и соответственно эмулировал наличие ключа поиском в mini-base "запрос-ответ". Ещё раз повторюсь, для каждой задачи - почти всегда можно найти свой подход, лучший базового. Моя цель была описать максимально _общее_ решение. Частные случаи - дело будущих статей ![]() infern0 1. логгер универсален. не надо заниматся херней и каждый раз заново искать АПИ 2. логгер легким движением руки преобразуется в табличный эмулятор Согласен что написание подобного логгера - это уже не уровень делфи прог, однако цель вполне оправдывает затраты. Было уже много сказано по этой теме. Хочу превести ещё один аргумент. Предполжим, мы встретили очень редкую защиту на донгле, но при этом у нас есть описание её API ![]() ![]() Что выбрать ? Писать драйвер и разбиратся дополнительно с тем, какие преобразования претерпивают данные по пути API->DeviceIoControl->API в надежде, что в дальнейшем ПО с такой защитой ещё встретится или отэмулировать всё по документированным апи, описанным в "мануале" и не парится ? Таким образом без знания "секретной функции" принципиально невозможно обеспечить совместимость сломанной версии с легальными (в направлении легальная -> сломанная). Также есть вариант с шифрованием на ключе всех текстовых строк приложения. Т.е. от строки берется хеш, затем ключ и получаем константу шифровки. Могу совершенно определенно сказать что без знания "сф" экономически нецелесообразно (а это один из определяющих факторов) строить таблицу. Ибо к моменту завершения простроения выйдет новый билд, в котором пару строк поменяли и начинай все с начала. Здесь ты затрагиваеш вопросы, котрые, увы, слабо связаны с темой статьи. Цель - получить работоспособную, без ключа, версию ПО - _может_ быть достигнута. Экономическая составляющая задачи - это отдельный разговор. таблицу построить можно в 99% случаев А 100% случаев можно _свести_ всё к таблице, при условии светлой головы и прямых рук ![]() ![]() ![]() |
|
Создано: 05 марта 2005 10:47 · Личное сообщение · #22 |
|
Создано: 05 марта 2005 12:48 · Личное сообщение · #23 |
![]() |
eXeL@B —› Основной форум —› Интересует мнение о статье :) |