Некто Loh_Ushastik на форуме exelab попросил в личку помощи в снятии защиты PE Password 0.2 SMT/SMF. Обычно я такие просьбы игнорирую, но эта была довольно подробно расписана, что делал, где и как искал и что вроде как кроме одного корейца больше никто и не осилил. Даже нашел древний топик на exelab, где уже спрашивали о данной защите. Поэтому я взялся. Защищенный файл есть в приложении.
Запускаем подопытного и видим:
Протектор запрашивает пароль. Закрываем программу и загружаем ее в отладчик. Ниже листинг с комментариями:
Загрузчик вычисляет ImageBase, получает адреса всех нужных API, создает окно для ввода пароля и обрабатывает стек оконных сообщений. В листинге я пометил, что адрес обработчика оконных сообщений pDlgProc = 00409153. Посмотрим, что там происходит:
Видим, что при каком то событии (не важно каком) считывается пароль и рассчитывается его контрольная сумма. Пароль как видно не может быть больше 40 символов, а его контрольная сумма должна быть равна 0x085E75C3. Осталось посмотреть как считается контрольная сумма:
Берется один символ пароля и 65536 раз применяется разными битовыми операциями к контрольной сумме. Потом берется следующий символ пароля и всё повторяется. Все данные для брута у нас есть, можно писать брут. Я его написал, и сразу же после запуска он мне выдал пароль "V12”. Прикольный пароль, вводим и… фак! Программа вылетела в ошибку. Я почему то сразу не полез проверять в чем дело, а предположил, что это плохой алгоритм CRC, который дает коллизии. Поэтому изменил брут так, что после нахождения пароля он не останавливался, а писал найденный пароль в файл и продолжал брутить. Мать моя! Почти каждый сотый пароль соответствовал контрольной сумме! Короче эта затея не увенчалась успехом, поэтому будем смотреть что с паролем делается дальше. Для этого смотрим, что там будет после закрытия окна:
Берется виртуальный размер первой секции, виртуальное смещение первой секции, смещение складывается с базой образа в памяти и получается абсолютный адрес первой секции в памяти. Далее виртуальный размер сравнивается с константой 0x12345678, которая является флагом зашифрована первая секция или нет, и если секция зашифрована, то происходит расшифровка секции. Теперь понятно, почему файл падал. Посмотрим как реализована процедура дешифровки секции:
Думаю я подробно прокомментировал листинг и в пояснениях он не нуждается. Используется 2 ключа. Первым (Key1) дешифруются 4 байта первой секции, а второй (Key2) используется для подготовки Key1 к дешифровки следующих 4 байт первой секции. Причем самое первое состояние и Key1 и Key2 получают путем вычисления CRC суммы из введенного пароля. Т.к. алгоритм весьма прост и при шифровании буфер сдвигается на 4 байта, а длинна ключей очень мала, то можно произвести plain text атаку. Если грубо, то plain text атака направлена не на подбор правильного пароля, а на подбор промежуточного значения, которое получается от пароля и которым и шифруются/упаковываются данные. В нашем случае это значения Key1 и Key2. Подумайте сами, даже грубо посчитать, есть разница перебирать пароль от 1 до 40 символов или перебирать ключ с фиксированной 8 байтовой длинной. Для plain text атаки нам нужно знать что зашифровано в какой либо части буфера. Кто часто работает с PE форматом знает, что очень большой редкостью является заполнение виртуальной секции данными до самого конца. Обычно в конце секции, идет подряд множество нулей. Возьмем последние 32 байта первой секции (берем сразу двойными словами):
Предположим, что это зашифрованы нули. Каждые 4 байта дешифруются как Buff xor Key1. Составим выражение:
BuffDecrypt = BuffEncrypt xor Key1
Теперь выразим Key1:
Key1 = BuffEncrypt xor BuffDecrypt
Зная BuffEncrypt (0xE380B32E) и BuffDecrypt (0x00000000) получим Key1:
Key1 = 0xE380B32E xor 0x00000000 = 0xE380B32E
Т.е. у нас так совпало, что данные 8 двойных слов и есть значения Key1 в момент их шифрования. Теперь осталось, подобрать такой Key2, который изменит 8 раз подряд значение Key1 и оно будет соответствовать найденным 8 значениям Key1. Для этого восстановим цикл шифрования. Вкратце алгоритм следующий: Key1 = 0xE380B32E; Key2 = 0x00000000; @NextKey2: Key2 = Key2 + 1; Key1 = CalcKey1ByKey2(Key1, Key2); If Key1 != 0x238A8551 goto @NextKey2; Key1 = CalcKey1ByKey2(Key1, Key2); If Key1 != 0x191E9086 goto @NextKey2; ***** Готовый брутфорс Key2, в приложении, называется FindKey2. Запускаем брутфорс и получаем Key2. Теперь мы знаем Key1 и Key2. Но что это нам дает? Мы знаем, что при шифровании первого из 8 двойных слов plain text, значения ключей были следующие:
Key1 = 0xE380B32E, Key2 = 0x42919B46
Пошифрованый буфер лежит по адресу 0x00404FE0. Теперь нам нужно изменить алгоритм мутации Key1 и Key2 в обратную сторону, как будто мы расшифровываем буфер не от начала к концу, а от конца к началу. Тогда, зная что буфер начинает расшифровываться с адреса 0x00401000 мы можем организовать цикл, в котором ключи Key1 и Key2 придут к своему исходному состоянию, когда они только получились путем подсчета CRC от пароля. Обратить мутацию ключей просто, нужно снизу вверх изменить все плюсы на минусы, rol на ror и т.д. Псевдокод (оригинальная мутация ключей): add BuffPtr, 4 rol Key2, byte Key1[4] xor Key1, Key2 ror Key1, byte Key2[3] add Key2, Key1
Псевдокод (обратная мутация ключей): sub Key2, Key1 rol Key1, byte Key2[3] xor Key1, Key2 ror Key2, byte Key1[4] sub BuffPtr, 4
Осталось реализовать этот алгоритм в цикле и прервать цикл, когда BuffPtr станет равен 0x401000. В приложении есть проект ReverseKeys, он за это и отвечает. Запускаем утилиту и видим:
Done! Key1: 51AC2180, Key2: EA903537
Именно эти значения получаются при подсчете CRC от введенного пароля в процедуре DecryptSection. Осталось только подменить их сразу после подсчета и дать протектору расшифровать файл. Кому непонятно я сделал скриншот:
Сохраняем изменения и запускаем файл. Вводим что то, что пройдет первую проверку, например тот самый пароль "V12” и… да, файл запустился. Требует правда start.exe, так как я понял, что это загрузчик для чего то, возможно игры, но нам это уже не интересно. Файлы во вложении разделены на папки masm и delphi. Там одинаковые утили написанные под разные компиляторы, кому как понравится. Ну и ясен пень на masm всё работает в разы быстрее.
Резюме.
Автор защиты в корне неправильно подошел к реализации алгоритма шифрования. Основная ошибка в том, что введенный пароль практически никак не участвует в алгоритме шифрования, автор максимально отодвинул его от процесса шифрования данных.
Когда едите спаржу, можно сварить слегка, но не стоит кипятить, чтобы сохранить натрия и других минералов от кипения. http://zdorovjeru.com/ - стенды по питанию в школе
Здравствуйте, я у вас тут новенькая, мне понравилось то что вы обсуждаете, на самом деле очень интересные темы. Хочется вас отблагодарить, мы совершенно недавно наткнулась на качественную косметику, по привлекательной цене и по качеству не уступает ведущим лидерам косметики.
Я знаю что вам это пригодится, сама люблю. Самый удобный каталог я нашла только здесь, больше нигде такого ассортимента нету: http://tiande24.ru - Тианде
Решусь всем доложить про http://vipgod.ru/2011/%d0%ba%d0%b0%d0%ba-%d1%81%d0%ba%d0%bb%d0%b5%d0%b8%d1%82%d1%8c-%d0%b4%d0%be%d0%bc% d0%b5%d0%bd/ - Как склеить домен - это вероятнее всего то что необходимо каждому индивидуму.