Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Subj: Как был взломан POCSAG 32_____________



О качестве программы судить воздержусь (потому что не знаю), но как ее взломать (т.е. зарегистрировать), расскажу. Как обычно, нас просят ввести 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 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.01 с)...