Главная Случайная страница Контакты | Мы поможем в написании вашей работы! | ||
|
О качестве программы судить воздержусь (потому что не знаю), но как ее взломать (т.е. зарегистрировать), расскажу. Как обычно, нас просят ввести User Name и соответствующий ему код. Не особо напрягаясь, под Windows можно считать содержимое окна редактирования двумя функциями Win32 API GetWin-dowTextA и GetDIgItemTextA. Но, может быть автор использовал уникод? Или кодировал под Win 16? Так на какую же функцию нам поставить брейк-поинт? Первая здравая мысль, пришедшая на ум, — посмотреть таблицу импорта функций user.dll. Воспользуемся тем, что всегда под рукой, — Quick View.
Среди множества импортируемых функций user32.dll GetDIgItemText отсутствует, зато есть GetWindowTextA. Вот на нее мы и поставим Ьрх. Без сюрпризов и неожиданностей мы оказываемся во всплывшем Win-Ice. Теперь самое время узнать адрес буфера строки. Для этого необходимо вспомнить, какие параметры принимает функция. Воспользуемся Visual Studio C++, а точнее, электронной документацией MSDN. Через пару секунд выясняем следующее:
int GetWindowText (
HWND hWnd, // handle of window or control
with text LPTSTR IpString, // address of buffer for text
int nMaxCount); // maximum number of characters to copy
Таким образом, необходимый нам ipString находится по адресу SS:[ESP+8+8]. Попутно замечаем, что этот адрес совпадает со значением еах. Это очень похоже на Visual C++ (впрочем, и на другие компиляторы Си). Нашу догадку подтверждает копирайт, который легко найти в исполняемом файле. Судя по размеру исполняемого файла, а также по отсутствию импортируемых функций mfc.(Ill, нетрудно предположить, что mfc скомпонована как статичная библиотека. А вот это уже нехорошо. Символьной информации о классах mfc мы не получим. Да и места на винте мне, ей-богу, жалко. Но с другой стороны, функции каркасной библиотеки — это большей частью простые переходники к соответствующим функциям API. Поэтому, подняв хвост, кидаемся в гущу событий. Выполняем следующую последовательность команд:
{ dd
d ssiesp+IO
d еах
bpm еах
bd * p ret
be *
x)
Убеждаемся, что программа считала введенный нами от балды регистрационный номер. Вскоре мы вываливаемся в очень тривиальный кусок кода, сравнивающий две строки каким-то странным способом. Дамп esi-I покажет нам сгенерированную строку. Аккуратно запишем ее и... Все! Мы зарегистрированные пользователи. А как быть с нашими друзьями? Думаете, им будет по вкусу ваше имя? Ну что же, напишем генератор регистрационных номеров. Сразу предупреждаю, что это на порядок сложнее, чем подсмотреть регнум, не вникая в механизм его генерации.
Возвращаемся к исходной точке. Опять вводим имя и произвольный номер. Нас будет интересовать сам процесс генерации ключа, поэтому теперь мы трапим не регнум, а имя. И дожидаемся кода, который его читает. Им оказывается movsx ebp, byte ptr [esi+eax]. Сразу видно, что сделано со вкусом и размахом. Судя по тому, что идущие подряд команды модифицируют один регистр, оптимизацией тут и не пахнет.
Теперь нам необходимо вникнуть в суть данного фрагмента кода и написать аналогичный для своего генератора. Обратите внимание на цикл в строке Ох40Е2ЕВ. Даже беглого взгляда на код достаточно, чтобы понять, что это простая и нестандартная хеш-функция, возвращающая сразу две свертки! (Видно, стандартное CRC32 автору реализовать было лень, впрочем, в данном случае это не страшно.) Пишем собственный код генератора:
void KeyGen::GenPolyO(CString Name)
(
unsigned long int poliO = OxADACAFFE;
unsigned long int polil = OxAFFEADAC;
unsigned long int Len = Hame.GetLength();
unsigned long int tempO;
unsigned long int tempi;
unsigned char transmit;
for (unsigned int а=0;а<Ьеп;а++)
(
transmit=Name.GetAt(a);
temp=transinit;
temp0= (tempO «(a & 0х7));
poliO = (poliO ^ tempO);
transmit=llame.GetAt (Len-a-I);
templ=transmit;
templ=(templ «(a & OxF));
polil= (polil " tempi);
}
TRACEC'lx polyl = %x \n",poliO,polil);
)
Просматривая код дальше, мы видим два вызова функции Ox41D150, принимающей полученные свертки. Тут надо полагать, что свертки превратятся в развертки, ибо 64 бита ключа автору защиты показалось мало, и он ухитрился обеспечить работой и себя, и нас.
Заходим внутрь функции развертки. Автор делит свертку на 0х24 и к остатку прибавляет 0х30, если тот меньше 0х9, и 0х57 в противном случае. И так до тех пор, пока в результате не получится ноль. После чего, преследуя одному Богу понятную цель, переворачивает строку?! Пишем еще немного кода.
CString KeyGen::GenSeq(unsigned long int poly)
{
CString s0="";
unsigned char zzz;
while (true)
(
zzz = (unsigned char) (poly % 0х24);
if (zzz<=9) zzz°zzz+0x30;
else zzz=zzz+0x57;
s0=s0+(char) zzz;
if (! (poly = poly / 0х24)) break;
}
for (int a=0;a<(sO.GetLength()/2);a++)
(
char c=s0[a];
sO.SetAt(a,sO.GetAt(sO.GetLength()-a-l));
sO.SetAt (sO.GetLengthO -a-l,c);
}
TRACEO(sO);
return sO;
}
Осталось превратить это в готовый продукт. О вкусах и привычках не спорят, поэтому примите Visual C++ не как руководство к действию, а как возможный вариант. Ничем не хуже будет сделать то же на ассемблере, Дельфи и даже на Visual Basic.
Дата публикования: 2014-12-08; Прочитано: 224 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!