Цель взлома: 

#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

LUKS container vs Border Patrol Agent. Как уберечь свои данные, пересекая границу

Не секрет, что если ты собрался посетить такие страны как США или Великобританию то, прежд…