Исследование CPU Indicator 1.1

Перейти на главную страницу, индексную страницу.


Привет!
Вот для вас еще одно (третье) мое практическое руководство. На этот раз наш пациент -
монитор загруженности проца. Неплохая софтина от PY Software. Какая схема защиты? Да все
тот же имя/серийник. Честно, когда я устанавливал в SoftIce бряки, чтобы начать
исследование этой проги, я думал, что бессонная ночь мне обеспечена. Не представляете,
каково было мое разочарование, когда четыре минуты спустя программа на моем компе уже
была полностью зарегистрирована и готова к употреблению. Пришлось мне самому обеспечивать
себя бессонной ночью и разбираться с алгоритмом генерации ключа, о чем я вам сейчас и
расскажу.
Итак, готовим стандартный набор инструментов:
   * SoftIce (как же без него :))
   * Пойло (обязательно)
   * Сигареты (по вкусу)
и в путь!!!

Как  всегда, начинаем с заполнения полей регистрации левыми данными, устанавливаем в
SoftIce бряк (breakpoint) на hmemcpy, давим на форме регистрации бутон "Ok"... и
вваливаемся в дебаггер...
Теперь натискните 7 раз на F12, чтобы войти в код CPU Indicator'а; а потом еще разков
пяток, чтобы перейти к этому коду:

:004388B8  mov eax, [ebp-0C]     ;в EAX идет введенное имя
:004388BB  lea edx, [ebp-08]
:004388BE  call 00435A14         ;вызов процедуры генерации серийника
:004388C3  mov eax, [ebp-08]     ;загружает ПРАВИЛЬНЫЙ серийник в EAX!
:004388C6  push eax              ;тащит правильный серийник в стек!

Все, на этом взлом можно считать проведенным успешно. Установив курсор на строку

:004388C6  push eax

и введя "d eax <ввод>", вы получите номер регистрации.

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

:004388BE  call 00435A14

давите F8, чтобы проследовать в процедуру:

:00435A14  push ebp
:00435A15  mov ebp, esp
. . .

пропустим все ненужное дерьмо

. . .
:00435A43  lea eax, [ebp-08]	;тащит в ЕАХ смещение введенного нами имени
:00435A46  mov edx, 00435AE0    ;!!! в EDX - строку "CPU Indicator v. 1.1" !!!
:00435A4B  call 00403B74        ;к имени прибавляем вышеприведенную строку.
                                ;далее я буду называть ее "именной" строкой
:00435A50  mov eax, [ebp-08]
:00435A53  call 00403B6C        ;находим длину "именной" строки...
:00435A58  push eax             ;...и кидаем ее в стек
. . .
:00435A61  pop edx
:00435A62  call 00431E20        ;* * * Вот оно!!! Процедура вычисления с/н * * *
:00435A67  mov [ebp-04], eax    ;в ЕАХ - с/н, но записаннй наоборот.
                                ;СЕРИЙНИК - содержимое ЕАХ в hex-виде !!!
. . .

Дальше идут процедуры "переворачивания" строки и другой не очень интересный кал.
Сконцентрируем все наше внимание на вызове "call 00431E20". Туда то мы сейчас и
отправимся. Давите F8 и...

:00431E20  push ebp
:00431E21  mov ebp, esp
:00431E23  add esp, -1C
:00431E26  mov [ebp-12], dx
. . .

пропустим неинтересное и перейдем сразу к делу:

:00431E49  mov [ebp-1A], ax                ;в АХ - длина "именной" строки
:00431E4D  mov word ptr [ebp-06], 0001     ;начальное значение счетчика (первый символ)
   ;Внимание! Начало цикла генерации
:00431E53  movzx eax, word ptr [ebp-06]    ;в ЕАХ пхает порядк. номер текущего символа
:00431E57  mov edx, [ebp-10]               ;"именную" строку - в EDX
:00431E5A  mov al, [eax+edx-01]            ;в AL - текущий символ
:00431E5E  mov [ebp-07], al
:00431E61  push ax                  ;сохраняем...
:00431E63  push bx
:00431E65  push cx                           ;...регистры
:00431E67  push dx
:00431E69  mov dx, [ebp-02]   ;восстанавливаем DX (в первый раз - нуль)
:00431E6D  mov bx, [ebp-04]   ;восстанавливаем BX (в первый раз - нуль)
:00431E71  mov cx, [ebp-06]   ;СХ - счетчик, содержит порядк. номер текущего символа
:00431E75  xor ax, ax         ;обнуляем АХ
:00431E78  mov al, [ebp-07]   ;в AL - текущий символ
:00431E7B  xor dx, ax       ;производим над ним...
:00431E7E  mul cl                ;...соответствующие логические...
:00431E80  add bx, ax                ;...и математические операции
:00431E83  mov [ebp-02], dx  ;сохраняем значение DX для следующего круга
:00431E87  mov [ebp-04], bx  ;сохраняем значение BX для следующего круга
:00431E8B  pop dx                    ;восстанавливаем...
:00431E8D  pop cx
:00431E8F  pop bx                             ;...регистры
:00431E91  pop ax
:00431E93  inc word ptr [ebp-06]     ;увеличиваем счетчик
:00431E97  dec word ptr [ebp-1A]     ;уменьшаем длину строки
:00431E9B  jnz 00431E53              ;конец цикла генерации
:00431E9D  mov ax, [ebp-04]
:00431EA1  mov [ebp-0C], ax
:00431EA5  mov ax, [ebp-02]
:00431EA9  mov [ebp-0A], ax
:00431EAD  mov eax, [ebp-0C] ;"перевернутый" с/н: старшее слово - последнее значение DX
                             ;после операции MUL CL, а младшее - последнее значение BX
                             ;после операции ADD BX, AX
:00431EB0  mov esp, ebp
:00431EB2  pop ebp
:00431EB3  ret

Что ж, давайте подведем итог и сделаем вывод на основе проведенного исследования.
1. Введенное нами имя записывается в верхнем регистре (заглавными буквами)
2. К имени прибавляется строка "CPU Indicator v. 1.1".
   Так, если вы ввели имя "JOHN", то в итоге получите строку "JOHNCPU Indicator v. 1.1"
3. Производим над каждым символом строки логические (xor) и математические (mul)
   операции. По окончании цикла, в EAX формируется "перевернутый" серийник:
     Т. е. содержимое EAX выглядит так:  "xx yy zz ww", где
     в слово "zzww" помещается значение BX,
     в "xxyy" - DX, таким образом, "xx" постоянно остается нулем. Скажите почему?
4. Серийник выглядит как последовательность байт и вводится в hex-виде.
5. Чтобы получить окончательный с/н, содержимое АХ надо "прочитать" наоборот, т. е.
   если в ЕАХ у нас число "0035ABEF", то правильный с/н: "EFAB3500"

Ну, разжевал как мог. Даже наверное слишком :)

Ниже привожу код процедуры генерации ключа, написанный на Delphi.
Может он не оптимален, но работает:

----------------- вырезать --------------------------------------
procedure Generate();
const
    Str='CPU Indicator v. 1.1';
var
    RegStr, Ost           :dword;
    UsName, NamStr, Serial:string;
    NamStrLen, i          :integer;
    Sym, C                :byte;
    B, D                  :word;
    MemB, MemD            :variant;

begin
 for i:=1 to Length(UsName) do
   UsName[i]:=UpCase(UsName[i]);    //меняем буквы имени на заглавные

 NamStr:=UsName+Str;                //к имени приписываем строку "CPU Indicator v. 1.1"
 NamStrLen:=Length(NamStr);         //находим длину полученной строки
 RegStr:=0;
 HexVal:='';
 MemB:=0;
 MemD:=0;
// начало цикла генерации ключа
 for C:=1 to NamStrLen do begin
   Sym:=byte(NamStr[C]);      //Берем символ для преобразований
   D:=MemD;
   B:=MemB;
   asm
     xor ax, ax
     mov al, Sym
     xor D, ax
     mul C
     add B, ax    //в конце цикла в переменной "B" будет сидеть 1-я половина ключа
   end;
   MemB:=B;
   MemD:=D
 end;            //конец цикла генерации ключа

//записываем будущий серийник (в десятичном виде) в переменную RegStr:
 asm
   mov bx, B                   // <------+
   mov dx, D                   //        |--- меняем местами байты первой половины с/н...
   mov byte ptr RegStr+3, bl   // <------|
   mov byte ptr RegStr+2, bh   // <------|
   mov byte ptr RegStr+1, dl   // ...и дописываем вторую половину
 end;

//а сейчас переведем его в правильный (шестнадцатиричный) формат:
 while RegStr>0 do begin
  ost:= RegStr mod 16;
  RegStr:=RegStr div 16;
  case ost of
   10: Serial:='A'+Serial;
   11: Serial:='B'+Serial;
   12: Serial:='C'+Serial;
   13: Serial:='D'+Serial;
   14: Serial:='E'+Serial;
   15: Serial:='F'+Serial;
  else Serial:=IntToStr(Ost)+Serial;
  end;
 end;
end;
----------------- вырезать --------------------------------------

Все, успехов!!! Надеюсь вам было понятно :)
Возникнут вопросы - мыльте.

P. S. Да, вашим домашним заданием будет сломать AnySpeed от все тех же PY Software.
      Она использует похожую схему защиты.

Keep on cracking...



Date  :05.09.2002
Author:Cryo
E-mail:cryo@cydem.zp.ua


Материалы размещены на http://cracklab.narod.ru/doc/ с разрешения http://cydem.zp.ua/






Hosted by uCoz