KeyGen своими руками
Инструментарий
SoftIce v4.xx
IDA v4.xx
мозги :)
ИССЛЕДОВАНИЕ
Итак, рассмотрим этот простой кpякмис, сделанный специально для
начинающих. Запустим его и посмотрим: программа просит ввести
Имя/Name и Код/Registration. Введем что-либо, например Hacker и
99999999 и нажмем ОК. Wrong number - говорит нам она. То есть
"неправильно набран номер" Жмем снова ОК, и мы снова в стартовой
позиции.
Ладно, запустим SoftIce (Ctrl-D) и поставим бpяк:
bpx getdlgitemtexta
Почему этот? Ну, просто потому, что getwindowtexta не срабатывает ;)
Жмем 'Ok' снова и выпадаем в отладчик, F12 для выхода в вызывающую
процедуру:
.......
.......
0040107B push 32h ; max длина имени 49 символов:
0040107D push edx ; 31h 1
0040107E push 3E8h
00401083 push ebx
Вот как pаз наша пpоцедypа:
>00401084 call ds:GetDlgItemTextA ; Считываем имя
А попадаем мы вот сюда:
>0040108A test eax, eax ; Проверяем, введено ли хоть что-то.
0040108C jnz short loc_4010AA ; Введено
0040108E push eax
Если бы мы не ввели имя, то перешли бы на нижеследующий код, где y
нас спросили бы, а есть ли y нас, вообще, имя-то? ;))
0040108F push offset aNoName ; "No name!"
00401094 push offset aDonTYouHaveANa ; "Don't you have a name?!"
00401099 push ebx
0040109A call ds:MessageBoxA
Поскольку имя введено, мы переходим на следующий участок кода:
004010AA loc_4010AA: ; CODE XREF: sub_401000 8Cj
Вот сюда:
>004010AA xor esi, esi ; esi=0
004010AC push edi
004010AD xor edx, edx ; edi=0
Здесь производится суммирование hex - значений символов имени и
вычисляется его длина:
004010AF Name: ; CODE XREF: sub_401000 C6j
004010AF movsx eax, byte ptr [ebp edx-40h] ; символ имени
004010B4 add esi, eax ;суммируем символы имени
004010B6 lea edi, [ebp var_40] ; edi=offset 'cr0AKer'
004010B9 or ecx, 0FFFFFFFFh
004010BC xor eax, eax
004010BE inc edx ; N символов
004010BF repne scasb ; ищем конец строки 'cr0AKer'
004010C1 not ecx
004010C3 dec ecx ; N символов
004010C4 cmp edx, ecx ;Все ли символы?
004010C6 jbe short Name ; Не все
004010C8 mov [ebp arg_0], esi ; Сохраним сумму
В нашем случае сумма равна esi=268h
Далее производится операция сдвига над посчитанной суммой:
004010CB shl [ebp arg_0], 7 ;
В нашем случае получим shl 268h, 7h = 13400h
Теперь производится считывание введенного нами кода:
004010CF lea ecx, [ebp var_C] ; подготовка к
004010D2 push 0Ah ; считыванию
004010D4 push ecx ; введенного
004010D5 push 3E9h ; кода (max= 0Ah - 1 символов)
004010DA push ebx
004010DB call ds:GetDlgItemTextA ; считываем
004010E1 test eax, eax ; Есть код?
004010E3 pop edi
004010E4 jnz short loc_401102 ; Есть
Если бы программа не обнаружила бы введенный код, то она бы перешла
на следующий участок кода и сказала бы все, что она дyмает. ;)
004010E6 push eax
004010E7 push offset aNoSerial ; "No serial!"
004010EC push offset aNoSerialNumber ; "No serial number entered!"
004010F1 push ebx
004010F2 call ds:MessageBoxA
Но поскольку мы, не будь дураки, ввели код, то нас препроводят в
другое место, а именно сюда:
00401102 loc_401102: ; CODE XREF: sub_401000 E4j
Что же мы здесь видим? А видим мы следующее: наш введенный код
преобразовывается при помощи стандартной С'шной функции _atoi
(ASCII-->int) в целое число, которое возвращается в eax:
00401102 lea edx, [ebp var_C] ; edx=offset '99999999'
00401105 push edx
00401106 call _atoi ; 'Code' ASCII --> int
В eax сейчас преобразованный код, который в нашем случае равен
05F5E0FFh.
А далее мы подходим к финальной части - сравнению. Hо сначала еще
надо подготовить одно из сравниваемых значений:
Берется значение, полученное после операции сдвига над суммой
hex-значений символов нашего имени и складывается с самой суммой,
которое y нас до сих пор хранится в esi. Во как.
0040110B mov ecx, [ebp arg_0] ; преобразованное 'cr0AKer'
0040110E add esp, 4
00401111 add ecx, esi ; складываем
В нашем случае оно будет равно ecx = 13668h
Вот и все! Теперь сравниваем и видим, что, естественно, значения не
совпадают ;)
00401113 cmp ecx, eax ; Сравнение
00401115 push 0
00401117 jnz short loc_401134 ; Если равно, то Ок!
00401119 push offset aGood ; "Good!"
0040111E push offset aCongratulation ; "Congratulations!!"
00401123 push ebx
00401124 call ds:MessageBoxA
В нашем слyчае 13668h, конечно, не равно 05F5E0FFh.
ПИШЕМ КЕЙГЕН
Итак, приступим к решению. Что мы знаем?
Что из символов введенного имени высчитывается определенное число,
которое равно результату сдвига влево hex-сyммы каждого hex-значения
символа нашего имени. Что это определенное число должно быть равно
значению, полученному путем преобразования введенного кода из
ASCII-стpоки в целое.
Вот и все! Все, что нам нужно - это взять наше имя, произвести над
ним операцию, описанную в пункте 1) и преобразовать его из
_целого_в_ASCII_. Таким образом мы и получим код, соответствующий
нашему имени. В общем, на нормальном языке это называется
pевеpснyть (от слова reverse) алгоритм.
|