Цель взлома: 

#c4n crackme #3 — http://c4nprojects.cjb.net

Инструментарий

SoftIce v4.xx 
IDA v4.xx 
мозги 🙂 

ВСТУПЛЕНИЕ 

Этот крякмис является очередным из серии
заданий для новичков проекта Cracking 4 Newbies — IRC (EFNet)
at #cracking4newbies. Задание таково: объяснить, как
генерируется серийный номер и написать
кейген. 

ИССЛЕДОВАНИЕ 

Итак, рассмотрим этот простой кpякмис,
сделанный специально для начинающих.
Запустим его и посмотрим: программа просит
ввести Имя/Name и Код/Registration. Введем что-либо,
например cr0AKer и 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) алгоритм.

Тепеpь мы можем написать кейген, как того
от нас требует задание. Если вы хотите
взглянуть на исходник моего, то можете
посмотреть его в этом архиве,
который заодно включает и сам туториал.
Претензии по качеству кода не принимаются (может
и кривовато, но работает ;)):

ПРИВЕТСТВИЯ 

FIDO echo Ru.hacker.Dummy и всем ее обитателям 
Всем хакерам в мире 🙂

Оставить мнение

Check Also

Tips’n’Tricks из арсенала андроидовода. Самые интересные, полезные и нестандартные трюки с Android

Многие годы мы рассказывали про самые разные способы оптимизировать, модифицировать и твик…