[CRACKING] [MISC.] [DOWNLOADS] [LINKS] [CONTACTS]

Взлом и защита программного обеспечения

 

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

 © BioCyborG
www.biocyborg.narod.ru

Hosted by uCoz