Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 12 ноября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

Исследование Marine Aquarium Time 2 или бесплатный скринсейвер всему миру!!!

Обсудить статью на форуме

Хорошая подборка видеоуроков, инструментов крэкера, книг и статей - здесь.

Автор: ARCHANGEL <Crazyangel88@mail.ru>

Вступление
Приходилось ли вам когда-нибудь видеть скринсейвер, который можно назвать настоящим шедевром? Скринсейвер, на который хочется смотреть? Скринсейвер, который вы сами можете настроить и видеть на экране не то, что захотел изобразить какой-то безвкусный занюханный программер, а то, что вы сами выберете? Мне пришлось, поскольку моего друга, у которого я раздобыл эту софтину, сильно не устраивало то, что этот сейвер постоянно показывал окно с надписью типа Please, register... Ну, представьте, тихое журчание воды в аквариуме, цветные экзотические рыбки и серо-бурая надпись на пол экрана с просьбой ввести лицензионный ключ – кому это понравиться? Своему другу я пообещал что-нибудь придумать, после чего и началось моё увлекательное путешествие в мир морепродуктов :).
Начало
Софт, который нам понадобиться: Olly Debug v1.10+CommandBar и…и всё. Дизассемблеры и другая тяжёлая артиллерия нам в этот раз не понадобятся. Ну что ж, приступим: ’’Ассистент - перчатки, зажим, скальпель, огурец:)’’
Установим наш аквариум. Для того, чтоб найти ехе-файл после установки советую создать ярлык программы на рабочем столе. Да, кстати, в нашем случае наш исполняемый файл будет иметь расширение не ехе, а scr. Но нас так просто не обмануть!:) Грузим в отладчик файл MAT2.scr. Видим, что это нормальный ехе, и продолжаем дальше. Ввод пароля должен осуществляться с помощью какой-то функции, проверим типичные API-функции. Первая функция, которая меня заинтересовала – GetDlgItemTextA (моя любимая:). Ставим бряк на эту функцию – bpx GetDlgItemTextA. Теперь запускаем прогу нажатием в отладчике F9. Появляется окно со статусом ’’Поверх всех’’ и закрывает нам отладчик. Непорядок, попытаемся его передвинуть, и сразу срабатывает один из наших бряков, потому что за позиционирование окна тоже отвечает эта функция. Это – ложное срабатывание. Но ничего, снимаем бряк с места её срабатывания и продолжаем, т.е. жмём снова F9. Теперь выберем окно для ввода серийника и что-нибудь туда введём, я, например, ввёл ARCHANGEL. Далее жмём Enter и прерываемся на бряке. Можем убедиться, что это как раз то, что нам нужно, если прокрутим чуть выше и посмотрим, какие параметры вталкивались в стек перед вызовом интересующей нас функции:


00424A5F  |. 6A 20          PUSH 20                                  ; /Count = 20 (32.)
00424A61  |. 68 8C704500    PUSH MAT2.0045708C                       ; |Buffer = MAT2.0045708C
00424A66  |. 68 92000000    PUSH 92                                  ; |ControlID = 92 (146.)
00424A6B  |. 50             PUSH EAX                                 ; |hWnd => 000903AE (class='SereneDlgClass',parent=00160206)


Так, параметры в стек вталкиваются в обратном порядке, тогда второй параметр будет действительно буфером и по этому адресу будет содержаться введенный нами серийник. Можем проверить это – в окне дампа перейдём на адрес 0045708C и увидим именно введенный нами ключ. Прекрасно, теперь будем гнать программу по F8. Далее будет происходить всяческая обработка кода, сейчас узнаем, какая.


00424A7D  |. 8A0D 8C704500  MOV CL,BYTE PTR DS:[45708C]	в CL помещается код первого символа
00424A83  |. B8 8C704500    MOV EAX,MAT2.0045708C      в EAX  помещается серийник           
00424A88  |. 33F6           XOR ESI,ESI			   обнуляется ESI			
00424A8A  |. 8BD0           MOV EDX,EAX		   запись в EDX серийника
00424A8C  |. 84C9           TEST CL,CL			   проверка не пустой ли серийник	
00424A8E  |. 74 40          JE SHORT MAT2.00424AD0   если пустой, то переход
00424A90  |> 8038 30        CMP BYTE PTR DS:[EAX],30 сравнение первого символа с нулём
00424A93  |. 75 03          JNZ SHORT MAT2.00424A98   если не равно, то переход
00424A95  |. C600 6F        MOV BYTE PTR DS:[EAX],6F если равно, то заменить нуль на строчный символ буквы о
00424A98  |> 8038 31       CMP BYTE PTR DS:[EAX],31  сравнение первого символа с единицей
00424A9B  |. 75 03          JNZ SHORT MAT2.00424AA0  если не равно, то переход
00424A9D  |. C600 6C        MOV BYTE PTR DS:[EAX],6C  если равно, то заменить его на строчный символ буквы L
00424AA0  |> 8A08           MOV CL,BYTE PTR DS:[EAX] запись в CL первого символа серийника
00424AA2  |. 80F9 61        CMP CL,61                                  сравнение первого символа с буквой a
00424AA5  |. 7C 05          JL SHORT MAT2.00424AAC     если символ меньше а, то переход
00424AA7  |. 80F9 7A        CMP CL,7A		        сравнение первого символа серийника с z	
00424AAA  |. 7E 14          JLE SHORT MAT2.00424AC0     если символ меньше либо равен z, то переход
00424AAC  |> 80F9 41        CMP CL,41		        сравнение первого символа с А	
00424AAF  |. 7C 05          JL SHORT MAT2.00424AB6        если меньше, то переход
00424AB1  |. 80F9 5A        CMP CL,5A		        сравнение первого символа с Z
00424AB4  |. 7E 0A          JLE SHORT MAT2.00424AC0     если меньше либо равно, то переход
00424AB6  |> 80F9 32        CMP CL,32		        сравнение первого символа с 2
00424AB9  |. 7C 0D          JL SHORT MAT2.00424AC8       если меньше, то переход
00424ABB  |. 80F9 37        CMP CL,37                                  сравнение первого символа с 7
00424ABE  |. 7F 08          JG SHORT MAT2.00424AC8        если больше, то переход 
00424AC0  |> 46             INC ESI			         (ESI здесь выполняет роль счётчика – считает количество символов в серийнике) увеличить на 1 ESI	
00424AC1  |. 3BD0           CMP EDX,EAX		          сравнение серийника с самим собой (зачем?)
00424AC3  |. 74 02          JE SHORT MAT2.00424AC7          если равно (а как же ещё?), то переход
00424AC5  |. 880A           MOV BYTE PTR DS:[EDX],CL    если не равно, то запишем первый символ серийника по адресу в EDX 
00424AC7  |> 42             INC EDX                                           увеличим EDX на 1 
00424AC8  |> 8A48 01        MOV CL,BYTE PTR DS:[EAX+1]  записать второй символ серийника в CL
00424ACB  |. 40             INC EAX			           увеличить EAX на 1	
00424ACC  |. 84C9           TEST CL,CL		          проверить, не закончился ли серийник
00424ACE  |.^75 C0          JNZ SHORT MAT2.00424A90      если не закончился, то переход


Таким образом, данный цикл будет выполняться пока не проанализирует весь регистрационный ключ. По окончании цикла все единицы будут заменены на буквы l, все нули на о, все буквы английского алфавита и цифры от 2 до 7 останутся без изменения, а остальные не будут считаться символами серийника, т.е. к счетчику не прибавиться дополнительная единица – этот символ как бы отсутствует в серийнике. Список валидных символов в ключе мы получили, теперь идём дальше.


00424AD0  |> 83FE 14        CMP ESI,14			сравнение длины введенного ключа с 20
00424AD3  |. C602 00        MOV BYTE PTR DS:[EDX],0         запись 0 в адресное пространство после ключа
00424AD6  |. 0F85 73060000  JNZ MAT2.0042514F                  если длина ключа не 20 символов, то переход (который ничего хорошего не обещает)
00424ADC  |. BF 8C704500    MOV EDI,MAT2.0045708C       запись в EDI нашего ключа           
00424AE1  |. BA ACA74500    MOV EDX,MAT2.0045A7AC  запись в EDX значения 0045A7AC (там нули)
00424AE6  |. 8BEF           MOV EBP,EDI			запись ключа в EBP
00424AE8  |. C74424 10 0000>MOV DWORD PTR SS:[ESP+10],0 обнуление значений по адресу ESP+10 (хотя там и так вначале нули)
00424AF0  |> 8A07           MOV AL,BYTE PTR DS:[EDI]        запись в AL первого символа ключа
00424AF2  |. 3C 61         CMP AL,61				сравниваем символ ключа с символом а
00424AF4  |. 72 08          JB SHORT MAT2.00424AFE		если меньше, то переход
00424AF6  |. 3C 7A          CMP AL,7A				сравниваем символ ключа с символом z
00424AF8  |. 77 04          JA SHORT MAT2.00424AFE		если больше, то переход
00424AFA  |. 2C 5B          SUB AL,5B				если нет, то произойдёт 
вычитание шестнадцатеричного числа 5B из значения кода n-ого символа нашего ключа (n-ого, потому что проверяться ведь не только первый символ будет)
00424AFC  |. EB 1E          JMP SHORT MAT2.00424B1C	переход по указанному адресу
00424AFE  |> 3C 41          CMP AL,41				сравниваем символ серийника с символом А
00424B00  |. 72 08          JB SHORT MAT2.00424B0A		переход, если меньше, чем А
00424B02  |. 3C 5A          CMP AL,5A				сравниваем символ ключа с символом Z
00424B04  |. 77 04          JA SHORT MAT2.00424B0A		переход, если больше, чем Z
00424B06  |. 2C 3B          SUB AL,3B				если нет, то из кода n-ого символа нашего ключа вычтем 3B
00424B08  |. EB 12          JMP SHORT MAT2.00424B1C	переход по указанному адресу
00424B0A  |> 3C 32          CMP AL,32                                        сравниваем символ серийника с 2
00424B0C  |. 0F82 3D060000  JB MAT2.0042514F		если меньше, чем 2, то переход
00424B12  |. 3C 37          CMP AL,37				сравниваем символ ключа с 7
00424B14  |. 0F87 35060000  JA MAT2.0042514F		если меньше, то переход
00424B1A  |. 2C 32          SUB AL,32                               	если нет, то вычитаем из кода n-ого символа нашего ключа значение 32 (шестнадцатеричное) 


Остановимся и проанализируем полученную информацию. Длина нашего регистрационного ключа должна составлять 20 единиц. Ключ должен состоять из букв верхнего и/или нижнего регистров английского алфавита и цифр от 0 до 7. В процессе преобразования 0 обрабатывается как буква о, 1 – как L, остальные символы обрабатываются такими, какими они являются. Дальше из значений букв от a до z вычитается 5B, из букв A-Z вычитается 3B, после чего одна и та же буква независимо от регистра преобразуется в один и тот же символ. Таким образом, ключ, как говориться, case-insensitive, т.е. нечувствителен к регистру вводимых символов. А с цифрами тоже происходят некоторые превращения: из кода символа цифр вычитается 32h. Сейчас разберёмся, зачем это нужно. В дальнейшем для удобства все шестнадцатеричные значения я буду помечать как h, чтоб не было путаницы.


00424B1C  |> B1 10          MOV CL,10				запись в CL значения 10h
00424B1E  |. BE 05000000    MOV ESI,5			запись в ESI значения 5
	А вот этот код меня заинтересовал:
00424B23  |> 84C8           TEST AL,CL
00424B25  |. 0F95C3         SETNE BL
00424B28  |. 83C3 30        ADD EBX,30
00424B2B  |. 881A           MOV BYTE PTR DS:[EDX],BL
00424B2D  |. 42             INC EDX
00424B2E  |. D0E9           SHR CL,1
00424B30  |. 4E             DEC ESI
00424B31  |.^75 F0          JNZ SHORT MAT2.00424B23


В регистре AL находится преобразованное значение n-ого символа ключа. В CL – значение 10h. Команда TEST проводит побитовое сравнение двух операндов следующим образом: допустим, в AL у нас 6, что в двоичной системе равно 00110, а в CL у нас 10h, что в двоичной системе – 10000. Как говориться в одном из справочников по асму, команда TEST возвращает значение истина (1) только в том случае, если соответствующие разряды источника и приемника установлены в 1, т.е. в нашем случае команда вернёт значение ложь, ведь такого соответствия нет.


00110
10000


Значит флаг нуля установиться в 1. Следующая команда SETNE BL установит значение регистра BL в 1, если значение флага нуля составляет 0. Но в нашем примере значение BL так и останется нулевым. Да и значение всего регистра EBX тоже равно нулю – это видно под отладчиком. Дальше к EBX прибавляется число 30h, таким образом сейчас в EBX код нуля – символа 0. А точнее – в BL. Если бы команда TEST вернула истинное значение, то сейчас бы в BL был шестнадцатеричный код символа 1. Теперь по адресу, расположенном в EDX, записываем наш 0. В любом случае, по этому адресу могут записываться либо 0, либо 1. Далее EDX увеличивается на 1 – подготовка к записи следующего символа. Следующая инструкция – сдвиг вправо на один разряд. Скажу по-простому – осуществляется деление значения в CL на 2 в первой степени (второй операнд указывает, в какую степень нужно возвести 2 для деления). Было там 10h, а стало 8h. Далее значение в ESI уменьшается на 1. И последняя инструкция – переход, если в ESI не нуль.
Из этого кода становиться ясно, что каждый символ нами введенного ключа представляется комбинацией из 5 символов, причём в этой комбинации могут быть только 1 и 0. Скорее всего, этот приём применяется здесь для защиты от столь любимого многими поиска в Soft-Ice

s 0 l -1 "наш_серийник"

хотя это спорный вопрос, я так до конца и не понял назначение такого преобразования. Возможно, эта процедура была вставлена в код чтоб намеренно усложнить отладку, но мы во всём разберёмся:).
Я так подробно описываю здесь назначение инструкций не от нечего делать, а потому, что ещё ни в одном тьюторе не видел их описания, а вопросы по поводу назначения этих команд возникают довольно часто. Ну, да что-то я отвлёкся, продолжаем.


00424B33  |. 8B4424 10      MOV EAX,DWORD PTR SS:[ESP+10] инструкция, которая, по сути, ничего не делает, т.к. у этих операндов всегда одинаковые значения
00424B37  |. 40             INC EAX	увеличение на 1 EAX (это – счетчик)
00424B38  |. 47             INC EDI	переход к следующему символу ключа
00424B39  |. 83F8 14        CMP EAX,14 	не 14h ли в EAX?
00424B3C  |. 894424 10      MOV DWORD PTR SS:[ESP+10],EAX	запись количества преобразованных символов по адресу ESP+10
00424B40  |.^7C AE          JL SHORT MAT2.00424AF0	переход, если преобразованы не все символы


После прохода по этому коду я нажал Restart и начал отладку заново, но теперь с другим серийником, с серийником из двадцати символов, которые бы отвечали требованиям проги. А выглядел он так:

AAAAAAAAAAAAAAAAAAAA

Не очень-то оригинально, но всё-таки ключик:) Далее с этим ключиком я прошёл по F8 весь вышеописанный код. А потом идёт одна любопытная конструкция:


00424B42  |. B9 05000000    MOV ECX,5			запись числа 5 в ECX
00424B47  |> 8A45 00        MOV AL,BYTE PTR SS:[EBP]	запись в AL первого символа нашего ключа (в EBP ведь по-прежнему адрес нашего ключа в памяти)
00424B4A  |. 3C 61          CMP AL,61				сравнение символа из нашего ключа с а
00424B4C  |. 7C 06          JL SHORT MAT2.00424B54		переход, если меньше, чем а
00424B4E  |. 3C 7A          CMP AL,7A				если нет, то сравнить этот же символ с символом z
00424B50  |. 7F 02          JG SHORT MAT2.00424B54		переход, если больше, чем z
00424B52  |. 2C 20          SUB AL,20				если нет, то вычесть из кода символа 20h (на практике это значит перевести символы из нижнего регистра в верхний)
00424B54  |> 8802           MOV BYTE PTR DS:[EDX],AL	записать значение символа ключа по адресу из EDX
00424B56  |. 42             INC EDX				увеличить EDX на 1 (подготовка места для записи следующего символа)
00424B57  |. 45             INC EBP				увеличить EBP на 1 (переход к следующему символу)
00424B58  |. 49             DEC ECX				уменьшить ECX на 1 (ECX – счётчик)
00424B59  |.^75 EC          JNZ SHORT MAT2.00424B47	переход, если не 0 в ECX


Как говориться, выделим главное – в результате вышеизложенного алгоритма первые пять символов нашего серийника записались в память процесса сразу после совокупности единиц и нулей:


0045A7A0  00 00 00 00 00 00 00 00 00 00 00 00 30 30 31 31  ............0011
0045A7B0  30 30 30 31 31 30 30 30 31 31 30 30 30 31 31 30  0001100011000110
0045A7C0  30 30 31 31 30 30 30 31 31 30 30 30 31 31 30 30  0011000110001100
0045A7D0  30 31 31 30 30 30 31 31 30 30 30 31 31 30 30 30  0110001100011000
0045A7E0  31 31 30 30 30 31 31 30 30 30 31 31 30 30 30 31  1100011000110001
0045A7F0  31 30 30 30 31 31 30 30 30 31 31 30 30 30 31 31  1000110001100011
0045A800  30 30 30 31 31 30 30 30 31 31 30 30 30 31 31 30  0001100011000110
0045A810  41 41 41 41 41 00 00 00 00 00 00 00 00 00 00 00  AAAAA...........


Вот так это выглядит в окне дампа. Странно, зачем нужны эти символы? Трассируем дальше – там видно будет:).


00424B5B  |. C602 00        MOV BYTE PTR DS:[EDX],0		запись нуля после пяти первых символов ключа
00424B5E  |. 33D2           XOR EDX,EDX				обнуление EDX
00424B60  |. BF 14E64400    MOV EDI,MAT2.0044E614		запись значения 0044E614 в EDI
00424B65  |. C74424 10 0000>MOV DWORD PTR SS:[ESP+10],0	вместо количества символов в нашем введенном ключе по адресу в ESP+10 записывается 0
00424B6D  |. 33C9           XOR ECX,ECX				обнуляется ECX
00424B6F  |. BD 01000000    MOV EBP,1				запись единицы в EBP
00424B74  |> 8A81 10A84500  MOV AL,BYTE PTR DS:[ECX+45A810]	ECX вначале равен нулю, тогда в AL запишется первый из пяти вышеупомянутых символов
00424B7A  |. 85C9           TEST ECX,ECX				сравнение, не ноль ли в ECX
00424B7C  |. 75 0A          JNZ SHORT MAT2.00424B88		переход, если не 0
00424B7E  |. 3C 63          CMP AL,63					если 0, тогда сравнить первый символ с символом с
00424B80  |. 74 3F          JE SHORT MAT2.00424BC1			если равны, то переход
00424B82  |. 3C 43          CMP AL,43					если не равны, то сравнить первый символ с символом С
00424B84  |. 75 3C          JNZ SHORT MAT2.00424BC2		если не равны, то переход
00424B86  |. EB 39          JMP SHORT MAT2.00424BC1		если равны, то переход сюда
00424B88  |> 83F9 02        CMP ECX,2				(на этот код мы бы попали с адреса 00424B7C, если б ECX был не 0, т.е. если б проверяли не первый символ) сравнить ECX c 2
00424B8B  |. 75 0A          JNZ SHORT MAT2.00424B97		если не равны, то переход
00424B8D  |. 3C 72          CMP AL,72					если равны, то сравнить теперь уже третий символ из пяти с r
00424B8F  |. 74 30          JE SHORT MAT2.00424BC1			переход, если равно
00424B91  |. 3C 52          CMP AL,52					если не равно, сравнить с R
00424B93  |. 75 2D          JNZ SHORT MAT2.00424BC2		если третий символ не равен R, то переход
00424B95  |. EB 2A          JMP SHORT MAT2.00424BC1		если равен, то переход по этой инструкции
00424B97  |> 83F9 04        CMP ECX,4				сравнить ECX с четвёркой
00424B9A  |. 75 0A          JNZ SHORT MAT2.00424BA6		переход, если не равно
00424B9C  |. 3C 6B          CMP AL,6B					если равно, значит в AL – пятый символ, и он сравнивается с k
00424B9E  |. 74 21          JE SHORT MAT2.00424BC1			переход, если равно
00424BA0  |. 3C 4B          CMP AL,4B					если не равно, то сравнить пятый символ с K
00424BA2  |. 75 1E          JNZ SHORT MAT2.00424BC2		если не равно, то переход
00424BA4  |. EB 1B          JMP SHORT MAT2.00424BC1		если равно, то переход сюда - 00424BC1
00424BA6  |> 3BCD           CMP ECX,EBP				(эта конструкция меня приколола – помните по адресу 00424B6F в EBP записалась единица? Но вместо того, чтоб сравнить ECX с 1 напрямую, как это делалось до этого, программер придумал такую вот загогулину:) Тем не менее, сравнение ECX с 1
00424BA8  |. 75 0A          JNZ SHORT MAT2.00424BB4		если не равно, то переход
00424BAA  |. 3C 6F          CMP AL,6F					если равно, то в AL находиться код второго символа из ключа, и он сравнивается с буквой o
00424BAC  |. 74 13          JE SHORT MAT2.00424BC1		переход, если равно	
00424BAE  |. 3C 4F          CMP AL,4F					если не равно, то сравнить символ с О
00424BB0  |. 75 10          JNZ SHORT MAT2.00424BC2		если не равно, то переход
00424BB2  |. EB 0D          JMP SHORT MAT2.00424BC1		если равно, то переход на 00424BC1
00424BB4  |> 83F9 03        CMP ECX,3				по поводу этого кода
00424BB7  |. 75 09          JNZ SHORT MAT2.00424BC2		скажу без лишних слов,
00424BB9  |. 3C 65          CMP AL,65					что четвёртый символ
00424BBB  |. 74 04          JE SHORT MAT2.00424BC1		сравнивается с e и с E
00424BBD  |. 3C 45          CMP AL,45
00424BBF  |. 75 01          JNZ SHORT MAT2.00424BC2
00424BC1  |> 42             INC EDX					увеличение на 1 счетчика совпадений, т.е. если наши символы совпадали с проверяемыми, за каждое совпадение EDX увеличивался на 1
00424BC2  |> 41             INC ECX					увеличение на 1 счетчика проверенных символов
00424BC3  |. 83F9 05        CMP ECX,5					все ли символы уже проверены?
00424BC6  |.^7C AC          JL SHORT MAT2.00424B74		если нет, то переход


Таким образом, если бы первые пять символов нашего серийника выглядели без учёта регистра как COREK, то счётчик совпадений (значение EDX) было бы равно пяти. Что же нам это дало бы? А где проверка остальных символов? Они, что, никому не нужны? Сейчас проверим. Посмотрим ниже:


00424BC8  |. 8B1D 20514400  MOV EBX,DWORD PTR DS:[<&KERNEL32.GetWind>;  kernel32.GetWindowsDirectoryA
00424BCE  |. 83FA 05        CMP EDX,5
00424BD1  |. 0F85 17010000  JNZ MAT2.00424CEE


Отсюда ясно, что если в EDX не 5, мы перейдём на адрес 00424CEE. А если 5? Стоя на переходе, изменим флаг нуля на противоположный, чтоб переход не произошел, и нажмём F9. И, о чудо, мы зарегистрированы!:)
Отсюда вывод, что первые пять символов должны быть COREK, а остальные пятнадцать – любые буквы и цифры от 0 до 7. Я не стану выкладывать алгоритм keygen’а, т.к. он очень прост, но можно считать, что мы не просто подобрали ключ, но и создали генератор ключей:)

Благодарности

Хотелось бы поблагодарить cracklab за размещение этого тьютора, авторов программы за отличный скринсейвер, ну, и тебя, читатель, тоже. Ещё хотелось бы поблагодарить моего друга Deniska за его ценнейшую моральную поддержку (он рядом сидел, когда я эту статью отправлял :) Всем респект и всего самого наилучшего:-)!!!



Обсуждение статьи: Исследование Marine Aquarium Time 2 или бесплатный скринсейвер всему миру!!! >>>


Комментарии к статье: Исследование Marine Aquarium Time 2 или бесплатный скринсейвер всему миру!!!

Rascal 06.08.2006 13:34:19
"потому что за позиционирование окна тоже отвечает эта функция"
Аффтор, поясни, каким образом GetWindowTextA отвечает за позиционирование
---
PE_Kill 15.08.2006 16:21:31
Автор, ты мега ЛОЛ. Выкладывать непровереные алгоритмы. А ты в курсе что после твоего ключа прога будет работать только 30 дней? Готов поспорить на ящик водки что нет. Ты бы почитал старые статьи где чел что бы написать кейген к игре прошел её всю до конца. А эта статья поможет только продлить триал. Мда.. Кракеры пошли...
---
PE_Kill 18.08.2006 08:31:31
где автор, чтобы написать кейген, прошел все уровни игры...
---

Материалы находятся на сайте https://exelab.ru



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS