|
KеyGеn для GIF Moviе Geаr v.4.0.2.
GIF Movie Gear v.4.0.2
[941 KB-ZIP] http://biocyborg.narod.ru/soft/MovieGear402.zip OllyDbg
v1.10 [1087
KB-ZIP] http://biocyborg.narod.ru/soft/OllyDbg110.zip
GIF Movie Gear v.4.0.2 - программа для создания
и работы с анимированными картинками
(GIF ).Может экспортировать данные из
файлов формата GIF, AVI, BMP, JPEG, ICO, PNG и PSD.
Но не будем перечислять все
возможности этой программы, ведь в
ней нас интересует только одно - ее
алгоритм проверки регистрационных
данных ;).
Пробный период - 30
дней. Рядового юзера может
обрадовать то, что пробная версия
программы функционально не
ограничена. Но при каждом запуске и
выходе из программы появляется
сообщение об необходимости
зарегистрироваться. Такое положение
вещей нас не устраивает. Поэтому мы
исследуем эту программку в отладчике.
GIF Movie Gear написан на
Visual C++ v7.0. Исполнимый файл ни чем не
упакован, о чем нам говорит PEiD.
Запускаем
программу из OllyDbg и пробуем
зарегистрироваться (Help->Register Now). Я
ввел в поле "Name" имя BioCyborG, а
регистрационный номер взял как
обычно - 123456789. Чтобы отловить
программку при считывании
регистрационных данных я поставил
breakpoint на GetWindowTextA (в отладчике жмем
Cntrl+N, в открывшемся списке ищем
указанную функцию, щелкаем на ней
правой кнопкой и в контекстном меню
выбираем "Set breakpoint on every reference").
После установки бряков и ввода рег.
данных в окне регистрации жмем "ОК"
и оказываемся в отладчике:
00431EB4 8B1D 54B34700 MOV EBX,DWORD PTR DS:[<&USER32.GetWindow>; мы оказались здесь
00431EBA 50 PUSH EAX
00431EBB FFD3 CALL EBX
00431EBD 6A 64 PUSH 64
00431EBF 8D8424 C800000>LEA EAX,DWORD PTR SS:[ESP+C8]
00431EC6 50 PUSH EAX
00431EC7 68 50040000 PUSH 450
00431ECC 57 PUSH EDI
00431ECD FFD6 CALL ESI
00431ECF 50 PUSH EAX
00431ED0 FFD3 CALL EBX
00431ED2 8D8C24 C400000>LEA ECX,DWORD PTR SS:[ESP+C4] ;в ЕСХ наш код
00431ED9 51 PUSH ECX
00431EDA 8D5424 64 LEA EDX,DWORD PTR SS:[ESP+64] ;в ЕDХ наше имя
00431EDE 52 PUSH EDX
00431EDF E8 1CFCFFFF CALL MOVGEAR.00431B00 ;здесь проверка рег данных
00431EE4 83C4 08 ADD ESP,8
00431EE7 85C0 TEST EAX,EAX ;если в ЕАХ 0, то данные не верные
00431EE9 0F84 B6000000 JE MOVGEAR.00431FA5 ;и тогда сообщение об ошибке
00431EEF 8D4424 10 LEA EAX,DWORD PTR SS:[ESP+10]
00431EF3 50 PUSH EAX ; /pDisposition
Теперь мы знаем, что
проверка регистрационных данных при
регистрации происходит в процедуре,
которая вызывается с адреса 00431EDF.
При трассировке зайдем в эту
процедуру (F7):
00431B00 PUSH EBX
00431B01 MOV EBX,DWORD PTR SS:[ESP+C];в ЕВХ наш код
00431B05 CMP BYTE PTR DS:[EBX],6D ;первый символ код должен быть буквой m (6D-ASCII код)
00431B08 PUSH EBP ;хехе :) мы-то ввели 123456789
00431B09 PUSH ESI ;поэтому вводим в командной строке d ebx
00431B0A PUSH EDI ;и в нижнем левом окне отладчика меняем 1 на m
00431B0B JNZ MOVGEAR.00431BB8 ;сообщение об ошибке в рег.инф. если первый символ не "m"
00431B11 CMP BYTE PTR DS:[EBX+1],67 ;второй символ должен быть буквой g
00431B15 JNZ MOVGEAR.00431BB8 ;иначе сообщаем о неправильной рег. инфе
00431B1B CMP BYTE PTR DS:[EBX+2],33 ;третий символ кода - цифра 3
00431B1F JNZ MOVGEAR.00431BB8
00431B25 CMP BYTE PTR DS:[EBX+3],37 ;четвертым символом кода должна быть цифра 7
00431B29 JNZ MOVGEAR.00431BB8
00431B2F XOR EBP,EBP ;итак, если наш код начинается символами mg37, то идем дальше и
;проверяем, не занесен ли наш рег. номер в "черный список"
00431B31 /MOV EDI,DWORD PTR SS:[EBP+486948]; берем номер из "черного списка"
00431B37 |MOV EAX,EDI
00431B39 |LEA EDX,DWORD PTR DS:[EAX+1]
00431B3C |LEA ESP,DWORD PTR SS:[ESP]
00431B40 |/MOV CL,BYTE PTR DS:[EAX]
00431B42 ||INC EAX
00431B43 ||TEST CL,CL
00431B45 |\JNZ SHORT MOVGEAR.00431B40
00431B47 |SUB EAX,EDX
00431B49 |MOV ECX,EAX
00431B4B |MOV ESI,EBX ;в ESI наш код
00431B4D |XOR EAX,EAX
00431B4F |REPE CMPS BYTE PTR ES:[EDI],BYTE PTR DS>;побайтовое сравнение нашего кода и "паленого"
00431B51 |JE SHORT MOVGEAR.00431BB8 ;если они равны, то "все! Кина не будет!" (с)
00431B53 |ADD EBP,4 ;а если не равны, то смотрим
00431B56 |CMP EBP,80 ;все ли "паленые" рег. номера проверили
00431B5C \JB SHORT MOVGEAR.00431B31 ;если не все, то берем следующий
;продолжаем проверку
00431B5E CMP BYTE PTR DS:[EBX+4],73 ;рег. номер может содержать букву "s", т.е. начинаться mg37s...
00431B62 JNZ SHORT MOVGEAR.00431B65
00431B64 INC EBX
00431B65 ADD EBX,7 ;отбрасываем первые 7 символов (или 8, если есть s)из нашего рег.кода
00431B68 PUSH EBX
00431B69 CALL MOVGEAR.0046C1BE ;здесь оставшаяся часть рег.кода преобразуется
;из десятичной в шестнадцатеричную систему (результат будет в ЕАХ)
00431B6E MOV EDX,DWORD PTR SS:[ESP+18];наше имя в EDX
00431B72 MOV EDI,EDX ;и в EDI
00431B74 MOV DL,BYTE PTR DS:[EDX] ;проверка
00431B76 ADD ESP,4
00431B79 XOR ECX,ECX
00431B7B TEST DL,DL ;если в поле "Name" ничего нет, значит (читай розовое :)
00431B7D MOV ESI,0BDF ;в ESI помещается число 0BDFh
00431B82 JE SHORT MOVGEAR.00431BAA ;имя не ввели - ошибка
00431B84 /MOVSX EDX,DL ;берем код первой буквы нашего имени
00431B87 |INC ECX ;ЕСХ - это множитель, меняется последовательно от 1 до 10
00431B88 |IMUL EDX,ECX ;код символа имени умножаем на множитель
00431B8B |ADD ESI,EDX ;результат умножения прибавляем к ESI
00431B8D |CMP ESI,17BE ;если в ESI получилось число меньше или равно 17BEh,
00431B93 |JLE SHORT MOVGEAR.00431B9B ;то следующую операцию перепрыгиваем (т.е. не вычитаем из ESI)
00431B95 |SUB ESI,17BE ;вычитаем из ESI число 17BEh
00431B9B |CMP ECX,0A
00431B9E |JLE SHORT MOVGEAR.00431BA2 ;если ECX>10, то
00431BA0 |XOR ECX,ECX ;обнуляем множитель
00431BA2 |MOV DL,BYTE PTR DS:[EDI+1] ;берем следующий символ из нашего имени
00431BA5 |INC EDI
00431BA6 |TEST DL,DL ;если символы в UserName не кончились (в dl не 0),
00431BA8 \JNZ SHORT MOVGEAR.00431B84 ;повторяем цикл
00431BAA CMP ESI,EAX ;в ESI - число, сгенерированное на основе UserName (нашего имени)
;в EAX - то число, которое получилось, когда отбросили 7 (или 8)
;первых символов из нашего кода (у меня: EAX=79h, ESI=54Fh
00431BAC JNZ SHORT MOVGEAR.00431BB8 ;если эти числа не равны (а у нас они не равны ;), то ошибка
00431BAE POP EDI
00431BAF POP ESI
00431BB0 POP EBP
00431BB1 MOV EAX,1 ;а если числа совпали, то в EAX помещается 1->рег. данные верны
00431BB6 POP EBX
00431BB7 RETN
Теперь все по порядку
объясню словами: для каждого имени
пользователя может быть 2 серийных
номера, которые обязательно
начинаются с символов mg37... или mg37s... Т.е.
отличие состоит в наличии буквы "s",
которая, очевидно, определяет тип
лицензии (site или для одного юзера).
Далее идут три символа, которые ни на
что не влияют (помните, в листинге отбрасываются
первые 7 или 8 символов, т.е.
отбрасываются mg37xxx или mg37sxxx, где x-любой
печатный символ). После этого на
основе введенного пользователем
имени генерируется число Z по такому
алгоритму: сначала Z=BDFh. затем код
символа имени умножается на число Y,
которое последовательно изменяется
от 1 до 10, и произведение прибавляется
к Z. Если после сложения получилось число
>17BE,
то из этого числа вычитается 17EB и
результат присваивается Z. Так
обрабатываются все символы имени. В
итоге правильный код должен выглядеть
так: mg37xxxZ или mg37sxxxZ.
Вот код процедуры
генерации рег. номера на Delphi+KOL:
procedure TForm1.Button1Click(Sender: PObj);
var
i,n,y,x: integer; //i-номер симвора имени,n-ASCII код символа, y-множитель
// x-произвольное 3-х значное число
SerNum:integer; //это число, которое генерируется на основе UserName
RegCode1,RegCode2:string; //полный серийный номер
b:char; //b - переменная для символов из UserName
begin
y:=0; //y-множитель, изменяется от 1 до 10
SerNum:=$0BDF; // значек "$" показывает, что число в шестнадцатеричном формате
For I:=1 To Length(Editbox1.Text) Do
begin
b:=editbox1.text[i]; //считываем очередной символ
n:=ord(b); //ord возвращает ascii-код символа
y:=y+1;
SerNum:=SerNum+n*y;
if SerNum>$17be
then SerNum:=SerNum-$17be;
if y>10
then y:=0;
end;
x:=random(899)+100; //получаем произвольное трехзначное число
RegCode1:='mg37'+int2str(x)+ int2str(SerNum); //собираем все в одну строку
RegCode2:='mg37s'+int2str(x)+ int2str(SerNum);//site license
editbox2.Text:=RegCode1; //выводим полученный рег. номер
editbox3.Text:=RegCode2; //выводим второй рег. номер
end;
initialization
randomize; //инициализируем генератор случайных чисел
Должен сказать, что
предложенный алгоритм генерации
ключа будет работать только в том
случае, если UserName не содержит русских
букв. Так что необходимо сделать
запрет на ввод русских букв или
добавить такую строку в текст
программы:
if n>127
then n:=n-256; //если используются символы из расширенной таблицы ASCII
Здесь
лежат исходники кейгена [31 KB-ZIP]. Если
вы хотите сделать генератор кодов на
Delphi с использованием VCL, просто
замените int2str на inttostr и вместо editbox
испльзуйте edit. Но я все-таки
рекомендую использовать библиотеку
KOL ( http://bonanzas.rinet.ru
).
Вместо заключения.
Довольно часто "добрые"
разработчики шароварных прог
предусматривают бесплатный апгрейд
своих программ для
зарегистрированных юзеров. Чтобы
старые рег. ключи работали на новых
версиях программы, им приходится
всегда использовать один и тот же
алгоритм проверки рег. данных. Это
серьезная ошибка, особенно если
прогаммеры хотят получать деньги за
свой продукт. Тогда уж не поможет
даже включение в проверку краденых
номеров. Поясню: в нашем примере в
ресурсах прогаммы хранился целый
массив краденых рег. номеров в
открытом виде (этакий "черный
список"). Эти номера можно
подсмотреть в любой программе,
которая умеет искать в бинарных
файлах текстовые строки (например, OgreGUI ).Т.к.
эти номера попали в "черный список"
по понятной причине, то их можно
найти в инете и посмотреть для какого
имени они были сгенерированы (а ведь
бывают случаи, когда код вообще не
зависит от имени!). А дальше все просто: выбираем любой
из краденых номеров, запоминаем его,
а в редакторе ресурсов удаляем
его из массива (ну или заменяем
произвольным). И все! Таким образом мы
удалили рег. номер из черного списка
и можем его использовать! Вот такой
серьезный баг есть в большинстве программ,
которые включают проверку рег.
номера на принадлежность к "черному
списку".
Информация
приведена в образовательных целях. Повторение
описанных в статье действий
запрещается.
© BioCyborG, 2005
|