воскресенье, 12 марта 2017 г.

Мои быстрые 1500

В пятницу вечером после работы мне было скучно, и я решил скоротать время за просмотром заказов на fl.ru. Как обычно я искал что-нибудь простое на один вечер. Среди кучи однотипных заказов был один с ТЗ на 56 строк, с подробнейшим описанием того что надо сделать, как будет проходить проверка работы, какими долями и когда будут переводится деньги и т.д. Основное задание же звучало так: "Изменить файл программы exe", и короткое описание: "Изменить файл Viewer.exe таким образом, чтобы окно ввода пароля вообще не появлялось, а зашифрованный файл (.mp3) запускался из зашифрованного контейнера сразу при открытии двойным щелчком."

Качаю приложенные архивы и в них вижу файл Viewer.exe. После запуска (естественно после проверки всего на virustotal, а запуск производится в виртуалке), я увидел вырвиглазное окно:
В ТЗ было сказано, что при клике на файл "OST Главный калибр - Лети пёрышко" появляется окно с паролем, если пароль ввести правильно, то запустится проигрыватель и программа больше не будет спрашивать пароль. Выглядит это вот так: http://recordit.co/7NVFcL0xB0
Также в более подробном файле с ТЗ было написано, что программу надо не просто отвязать от пароля, а надо сделать так, чтобы конкретно эта программа могла работать только с зашифрованными конкретно этим паролём файлами. Т.е. занопить условные переходы - не вариант. 
В принципе задача ясна. Я себе пообещал, что, если не уложусь по этой задаче в один час, плюну и потрачу вечер на что-нибудь другое.
Итак, что у нас есть в начале. Программа явно где-то сохраняет пароль, который мы ввели или выставляет у себя где-то флаг, что пароль был введён правильно. Значит нам надо найти какой из этих двух вариантов верный и думать потом что дальше.
Первым делом как всегда скармливаем Viewer.exe в PEiD. Последний нам заботливо сообщает что версия компилятора у Viewer.exe Borland Delphi 6.0 - 7.0. Значит возможно наша задача облегчается в разы. 
Тогда скармливаем Viewer.exe в IDR (Interactive Delphi Reconstructor http://kpnc.org/idr32/ru/), переходим в формы и видим в Form2 наше окно с паролем:
Можно заметить, что на форме есть невидимый лейбл Label1. Зачем он там пока я не знаю. Нас сейчас интересует что происходит при клике на кнопку OK. Переходим в TForm2.Button1Click:
Что же у нас здесь происходит? Тут всё просто. Приблизительно этот код выглядит так:
string password = Edit1.Text;
Label1.Text = password;
if (Edit1.Text == ""){
  Label1.Text = "none";
}
this.Close();
Т.е. получается, что берётся введённый пароль, сохраняется в невидимый лейбл, и форма закрывается. Все проверки проводятся потом где-то ещё. В этот момент у меня появилась гениальная мысль: что, если для сохранения пароля действительно используется этот лейбл. Т.е. потом где-то, где будет сверка введённого пароля и того, которым зашифрован файл, введённый пароль будет браться из Label1 а не из Edit1. Если эта теория верна, то можно явно вставить нужный нам пароль в Label1 и тогда мы выполним все условия заказчика.
Чтобы проверить эту теорию нам надо либо внимательно поизучать код в IDR, либо более быстрый вариант - поотлаживаться. Для этого сначала в IDR выберем пункт меню Tools - IDC Generator, чтобы сделать файл скрипта для IDA, который упростит разбор Viewer.exe. После этого запускаем IDA, выбираем там Viewer.exe, после автоанализа делаем File-Script file и скармливаем IDA полученный ранее IDC файл. Запускаем Viewer.exe в IDA. Теперь переходим в метод TForm2.Button1Click ( G + 543D64) и ставим там бряку. Во Viewer.exe дважды кликаем на "OST Главный калибр - Лети пёрышко", вводим какой-нибудь пароль, например, BEEF и нажимаем OK. Получаем в IDA что-то похожее на это:
Дальше идея такая. В метод TControl.GetText передаются два параметра: в eax указатель на контрол, из которого мы хотим получить текст, а в edx указатель на то место, куда TControl.GetText должен положить указатель на текст контрола. У одного и того же контрола указатель, передающийся через eax, должен быть одинаковым. В таком случае стоит просто проверить вызывается ли TControl.GetText для Form2.Edit1 ещё хоть где-нибудь кроме TForm2.Button1Click. Для этого надо внутри метода TControl.GetText, в самом начале поставить бряку с условием что eax равняется указателю на TForm2.Edit1.
Чтобы получить указатель на TForm2.Edit1 дойдём в отладчике до 00543D85. Как раз перед этим в eax кладут то, что нам надо:
В моём случае в eax лежит 024039A0. Для чистоты эксперимента получим указатель на TForm2.Label1. Для этого достаточно посмотреть, что будет в eax на строчке 00543D93. В моём случае там 02437220. Теперь спускаемся до строчки 00543DA6, чтобы пройти все вызовы TControl.GetText в этом методе, чтобы при срабатывании бряка они нам не мешали. Теперь добавляем бряк в TControl.GetText с условием что EAX==0x024039A0:
И запускаем дальше программу. Как видим, больше мы для TForm2.Edit1 текст нигде не запрашиваем. Ок. Для чистоты эксперимента изменим бряк в TControl.GetText на то, чтобы он срабатывал для TForm2.Label1. Для этого поменяем условие срабатывания точки останова на EAX == 0x 02437220. И опять попытаемся запустить  "OST Главный калибр - Лети пёрышко". Новый бряк сработает 2 раза до появления окна с паролем: в TForm1.JamShellList1DblClick (ну это понятно - авторы использовали кастомный ShellList, и в нём на Form1 отображает содержимое текущей папки), в TForm1.ZipForge1Password (уже интересно). И после нажатия кнопки OK в окне с паролем бряк сработает ещё два раза: в методе TForm2.Button1Click внутри TControl.SetText, и опять внутри  TForm1.ZipForge1Password.
Шикарно это то, что нам надо. Наша идея подтвердилась: программа сохраняет пароль в TForm2.Label1 и везде сверяет его с тем, которым зашифрован файл. Теперь нам надо намертво руками вбить пароль в TForm2.Label1 и всё будет так, как хочет заказчик.
Для выполнения этого я воспользовался проверенным Restorator 2007, Изменив в нём описание формы TForm2 я добился того, чтобы форма создавалась сразу же с нужным текстом в TForm2.Label1. Вот как это было:  http://recordit.co/uTBw2b7JQl
После этого можно запускать файл Viewer.exe и наслаждаться тем, что пароль никто не спрашивает:  http://recordit.co/8PKkNq2a2h
На выполнение этого задания у меня ушло чуть больше получаса. Это действительно были мои самые быстрые 1500 руб. Мне повезло, что программа была написана на Delphi, скомпилирована с полной отладочной информацией, и что проверка пароля была сделана так топорно и примитивно.

Комментариев нет:

Отправить комментарий

Небольшой обзор SIMD в .NET

Вашему вниманию предлагается небольшой обзор возможностей векторизации алгоритмов в .NET Framework и .NETCORE. Цель статьи познакомить с эт...