Написание кейгена к Ad Muncher 4.3d
|
Три способа, которыми советские программисты достают программное обеспечение: воровство, грабеж, и обмен награбленным.
|
Target: Ad Muncher v4.3d
Tools:
- Some brains
- Soft-Ice v3.4
- Win32Dasm 8.93
- UPX (или другой unpack'ер UPX)
- Delphi
Вступление
Что делает прога? Удаляет баннеры с Web-страниц закачиваеммых из
Инета.
Что побудило меня сломать эту прогу? Да вообщем-то сущий пустяк,
было нечего делать. Включил комп. Взял один из последних дисков журнала
Hard&Soft за 4.2002. Установил первую попавшуюся на глаза прогу и тут
оно началось...
Начало
Первое с чего начинается любой взлом это определить какую защиту
имеет программа. В основном это имя-код, код, ключ-файл (отсортированы
в порядке встречаемости в природе). Запускаем прогу, заходим в About,
нажимаем нужную кнопочку и видим Name/Code, что и следовало ожидать.
Все понятно.
Активные действия
Пишем любые имя и код. Нажимаем зарегистрировать. А нам фигу на
чем-то очень похожим на MessageBox. Ладно лезем в Soft-Ice ставим бряк
на GetWindowsTextA должна же как-то параметры брать? Опять жмем на
кнопочку... Что не можете нажать? Функция говорите постоянно вызывается
ну пойдем от обратного. Ставим бряк на MessageBoxA. Опять жмем.
Вываливаемся в айсе. И видим это место.
0057C5E3 030D7FD04000 add ecx, dword ptr [0040D07F]
0057C5E9 6A00 push 00000000
0057C5EB 51 push ecx
0057C5EC 50 push eax
0057C5ED FF7508 push [ebp+08]
0057C5F0 6A5C push 0000005C
0057C5F2 E819AAFFFF call 00407010
0057C5F7 EB2E jmp 0040C627
0057C5F9 663D6B00 cmp ax, 006B
0057C5FD 7513 jne 0040C612
|
А почему сегмент кода в начинается с 5, а не 4. Наверное мы в какой-то
библиотеке программы. Посмотрим... Да точно есть у нее библиотека.
AdMunch.dll. Попробуем подсунуть ее Win32Dasm'у - не хочет. Значит
запакована чем-то. Попробуем определить чем запакована на глазок.
Запускаем любую смотрелку, смотрим, а там в начале написано UPX 1.2.
Ну все понятно. Распаковываем. Я использовал сам паковщик UPX с ключем
-d. Вот так-то лучше. Он в отличие от AsPack'a не портит заголовок
файла. Так что можно его смело кидать в Win32Dasm. Дизассемблировался
хорошо. Смотрим ссылки на строки. А там ничего связанного с регистрацией.
Жаль. Можно посмотреть и в AdMuncher.exe, но и там тоже нет. Значит строки
зашифрованы. (К сведению: по-моему глубокому мнению прога написана на асме
отсюда и такой маленький размер).
Погоревали и ладно. Мы же знаем откуда вызывался MessageBox
c 0057C5F2. Посмотрим - НЕТ! Аааа догадываемся мы, просто файл дизасмен
со смещения 400000, а в память грузится с 570000. Тогда все ясно идем к
точке 40C5F2. Да точно тотже call. Посмотрим кто его пользует. Мотаем
вверх и видим
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0040C4D4(U), :0040C4E7(C), :0040C529(C)
|
Значит возможен вызов из этих точек. Снова лезем в программу, ставим
бряки на все три точки, запускаем регистрацию и вываливаемся в 57C4E7.
Поосмотримся вокруг нее...
:0040C4D9 BF7B484600 mov edi, 0046487B
:0040C4DE B02D mov al, 2D <- Символ "-"
:0040C4E0 B914000000 mov ecx, 00000014 <- 14 символов
:0040C4E5 F2 repnz
:0040C4E6 AE scasb
:0040C4E7 0F85E6000000 jne 0040C5D3 <- если не найден MessageBox
:0040C4ED C647FF00 mov [edi-01], 00 <- Найден, заменяем его 0
|
Из фрагмента кода становится понятно, что где-то в 14 символах ищется
символ "-" (минус). Яснее ясного, что в коде. Ведь имя же может быть
любым сказал я себе и написал в пароле один минус. Мой пароль был таков
11-22334455. Да, еще не забудьте поставить бряк на 57C4D9 (bpx 57C4D9).
Генерация ключа
Вываливаемся вна этом фрагменте и начинаем трассировать по шагам F8.
Доходим до процедуры
:0057C4FC E8B1070000 call 0040CCB2
|
И заходим в нее. И видим следующий текст. Я написал комментарии и надеюсь
из них все станет ясно.
:0057CCB2 33DB xor ebx, ebx <- Обнуление регистров
:0057CCB4 33C0 xor eax, eax <- перед
:0057CCB6 33D2 xor edx, edx <- использованием
:0057CCB8 8A1E mov bl, byte ptr [esi] <-Первый байт кода (ESI указывает на код)
:0057CCBA 46 inc esi <-Увеличиваем указатель
:0057CCBB F7E7 mul edi <-Умножаем eax на edi (edi=10h)
:0057CCBD 83EB30 sub ebx, 00000030 <-Получаем реальное цисло из кода
:0057CCC0 83FB09 cmp ebx, 00000009 <-Если число больше 9 (в пароле
:0057CCC3 7603 jbe 0057CCC8 <- это цифры). Переходим
:0057CCC5 83EB07 sub ebx, 00000007 <-Если буквы - вычитаем еще 7
:0057CCC8 03C3 add eax, ebx <-Добавляем к eax ebx
:0057CCCA 8A1E mov bl, byte ptr [esi] <-Второй байт кода
:0057CCCC 83D200 adc edx, 00000000 <-Бессмыслица
:0057CCCF 80FB00 cmp bl, 00 <-Если 2-й байт 0, то
:0057CCD2 7426 je 0057CCFA <-выход из процедуры
:0057CCD4 85D2 test edx, edx <-Если edx<>0, то снова
:0057CCD6 75E2 jne 0057CCBA <-то снова
:0057CCD8 8BC8 mov ecx, eax <- ecx=eax
:0057CCDA 8BC2 mov eax, edx <-eax=edx=0
:0057CCDC 46 inc esi <-Увелич.указаеля на код
:0057CCDD F7E7 mul edi <-Умножаем eax на edi (edi=10h)
:0057CCDF 91 xchg eax,ecx <-Меняем местами ecx и eax
:0057CCE0 33D2 xor edx, edx <-edx=0
:0057CCE2 F7E7 mul edi <-Умножаем eax на edi (edi=10h)
:0057CCE4 83EB30 sub ebx, 00000030 <-Получаем реальное цисло из кода
:0057CCE7 83FB09 cmp ebx, 00000009 <-Если число больше 9 (в пароле
:0057CCEA 7603 jbe 0057CCEF <- это цифры). Переходим
:0057CCEC 83EB07 sub ebx, 00000007 <-Если буквы - вычитаем еще 7
:0057CCEF 03C3 add eax, ebx <- eax=eax+ebx
:0057CCF1 8A1E mov bl, byte ptr [esi] <-Следующие байты кода
:0057CCF3 13D1 adc edx, ecx <-edx=edx+ecx
:0057CCF5 80FB00 cmp bl, 00 <-Если еще есть символы в коде
:0057CCF8 75DE jne 0057CCD8 <-То повторяем
:0057CCFA C3 ret <-Иначе выход из процедуры
|
Общий смылс этого куска кода: вычисление контрольного числа 1 куска кода
(до знака минус). И сводится к такому куску кода
edx=0,eax=0
метка:
bl=один байт из адреса кода
если bl=00 (все символы кончились) то метка 3
eax=eax*10h
bl=bl-30
если это число (т.е. bl<=9),то метка2
иначе bl=bl-7
метка2:
иди к метке
|
Вот такая штука получается. Вышли из процедуры и видим такой код:
:0057C501 8BD8 mov ebx, eax <-Результат процедуры поместили в ebx
:0057C503 BE7B474600 mov esi, 0046477B <-Указатель на имя
:0057C508 33C9 xor ecx, ecx <-Обнуляем
:0057C50A 33C0 xor eax, eax <-регистры
:0057C50C AC lodsb <-Берем 1 байт кода и указатель
< увеличиваем на 1 (eax=байт,esi=esi+1)
:0057C50D 03C8 add ecx, eax <- ecx=ecx+eax
:0057C50F C1C908 ror ecx, 08 <- Сдвиг вправо на 8 байт
:0057C512 03CB add ecx, ebx <- ecx=ecx+ebx(результат предыдущей
< процедуры)
:0057C514 3C00 cmp al, 00 < Символы кончились?
:0057C516 75F4 jne 0040C50C < Нет. Следующий символ
:0057C518 F7D1 not ecx < Да. Инверсия ecx.
|
Здесь даже выделять ничего не надо в кейген чистый код.
Нашли еще один результат (в ecx). Смотрим дальше
:0057C51A 5E pop esi
:0057C51B 51 push ecx <-Сохраняется результат 2-го подсчета
:0057C51C BF10000000 mov edi, 00000010
:0057C521 E88C070000 call 0040CCB2 <-Вызываем еще раз функцию подсчета
< аналогична первой за исколючением
< считается 2-я часть кода
:0057C526 59 pop ecx
:0057C527 3BC8 cmp ecx, eax <-Сравнение результата 2-го подсчета
< и последней процедуры.
:0057C529 0F85A4000000 jne 0040C5D3
|
Смотрите результат первой процедуры влияет только на вторую процедуру,
где подсчитывается контрольная сумма имени. Значит ее можно взять
статической. Например, если код начинается так 1-, то добавка в ebx
при подсчете будет 1. (Можете взять что-то другое). Кстати, если
понаблюдать, то можно заметить, что все имя преобразуется в нижний
регистр.
Написание кейгена
За неимением времени C++, я пока выучить не озаботился, по-этому,
кейген будет на Delphi. Если прочитаете статью Dr.Golova, как писать
маленькие проги на Делфи, можете переделать его. Но я сляпал просто.
1) Создаем форму и два компонента Edit с именами Code и Name
2) Одну кнопку.
Нажимаем два раза на кнопку и начинаем писать кейген.
(Если немножко присмотреться, то обратная к третьей процедуре
будет генерация из результата второй ее hex-вида)
Вот моя процедура, я ее прокоментрирую и разобраться не составит труда:
procedure TForm1.Button1Click(Sender: TObject);
Var
B:Byte; // Щетчик цикла
Col: Dword; // Переменная для хранения котрольной суммы
Name_: String; // Переменная для хранения имени
begin
COl:=0; //Обнуление переменной контрольной суммы
Name_:=LowerCase(Name.Text); //Все буквы в имени строчные (Помните)
For B:=1 To Length(Name_)+1 Do //
Begin //
Col := Col + Ord(Name_[B]); //
asm // Цикл генерации котрольной суммы
mov ecx, Col // из имени
ror ecx, 08 //
add ecx, 1 //
mov Col, Ecx //
end; //
End; //
Col:= not Col; // Инвертирование контрольной суммы
Code.Text := '1-'+IntToHex(Col,8); //Вывод на экран полученного ключа
end;
|
Вот и все! Дело сделано. 3 часа парился писал это. Ломал немного дольше,
спасибо автору за сие творение. Как вы видите писать кейгены не так
сложно как кажется. Хотя иногда понять смысл формулы пропущенной через
хреновый компилятор бывает не легко.
Удачи в Reversing Engeneering!
З.Ы. Товарищи по оружию будьте снисходительны не выкладывайте кряки на
всеобщее использование. Товарищи программисты не надейтесть на совесть
крякеров - делайте защиту лучше!
Все ругательства отправлять в null
Все остальное на lomovskih@yandex.ru
P.S. Запомните все материалы публикуются только в учебных целях и автор за их использование ответственности не несет!!
P.P.S. Возможно имеют место опечатки, заранее извините!
With best wishes Fess
И да пребудет с вами великий дух bad-сектора.
|