Альтернативный Метод написания КейГена на примере Professional Minesweeper v1.2 Shareware versionDelphi , Программа и Интерфейс , Исследование программАльтернативный Метод написания КейГена на примере Professional Minesweeper v1.2 Shareware version
Оформил: DeeCo 1) SoftIce 2) С++ 3) Знание С++&&Asm (и опыт работы :) На примере этой простой (в плане защиты) программки я покажу, как просто научится писать КейГены. Конечно же эта статья не распространяется на защиты, в которых быстрый перебор невозможен, однако... Моё мнение таково: в каждом отдельно взятом случае своя ситуация, по-своему неповторимая и интересная. Так что применять какие-то алгоритмы или правила в данных ситуациях просто глупо. Однако, из таких вот пустяшных туториалов можно почерпнуть много общих идей, при помощи которых позже вы сможете сами анализировать защитный механизм и сами писать КейГен. Итак, в данной статье мы: - Найдём процедуру проверки РН (рег.номер). - Проанализируем все действия этой процедуры - Напишем на С++ КейГен, который будет емулировать эту процедуру. - Лирические отступления. (1) Локализовываем защиту. Итак, найдя окно регистрации, введём в него "vallkor" и "123321" нажмём "ОК" и увидим MessageBox с инфой о том, что РН неправильный. Вываливаем Айс и ставим бряк: bpx MessageBoxA do "p ret" и выйдя из айса, опять нажмём "ОК", при этом окажемся тут: 015F:00404FE3 PUSH 0041EDC8 015F:00404FE8 PUSH 65 015F:00404FEA PUSH EBX 015F:00404FEB CALL USER32!GetDlgItemTextA <--Считали имя 015F:00404FF0 PUSH 0A 015F:00404FF2 PUSH 0041EE18 015F:00404FF7 PUSH 66 015F:00404FF9 PUSH EBX 015F:00404FFA CALL USER32!GetDlgItemTextA <--Считали РН 015F:00404FFF PUSH 0041EE18 <--сохранили адрес РН 015F:00405004 PUSH 0041EDC8 <--сохранили адрес имени 015F:00405009 CALL 00405657 <--!!!Процедура проверки 015F:0040500E ADD ESP,08 015F:00405011 MOV [0041EE22],AL 015F:00405016 TEST AL,AL 015F:00405018 JZ 0040502B <--Если её результаты плохи - прыжок на плохое сообщение 015F:0040501A MOV BYTE PTR [0041C074],00 015F:00405021 PUSH 00 015F:00405023 PUSH EBX 015F:00405024 CALL USER32!EndDialog <--иначе - закроем окно 015F:00405029 JMP 0040503E 015F:0040502B PUSH 30 015F:0040502D PUSH DWORD PTR [0041C078] 015F:00405033 PUSH 0041EF13 015F:00405038 PUSH EBX 015F:00405039 CALL USER32!MessageBoxAКак вы уже поняли, процедура считывания Имени и РН да и сам вызов Функции проверки РН на валидность очень прозрачны и сразу можно догадаться, что CALL 00405657 - вызов необходимой нам процедуры. Теперь необходимо понять логику этой процедуры... (2) Анализ защитного механизма. Зайдём в функцию, которую мы обнаружили и увидим: 015F:00405657 PUSH EBP 015F:00405658 MOV EBP,ESP 015F:0040565A ADD ESP,-1C 015F:0040565D PUSH EBX 015F:0040565E PUSH ESI 015F:0040565F PUSH EDI 015F:00405660 MOV EBX,[EBP+0C] 015F:00405663 MOV ECX,[EBP+08] 015F:00405666 XOR EAX,EAX 015F:00405668 MOVSX EDX,BYTE PTR [EAX+EBX] <--Загружаем первую цифру РН 015F:0040566C ADD EDX,-30 <--Переводим её из символьного в цифровой вид 015F:0040566F MOV [EAX*4+EBP-1C],EDX <--сохраняем по адресу EBP-1C 015F:00405673 CMP DWORD PTR [EAX*4+EBP-1C],00 <--сравниваем, цифра ли это 015F:00405678 JL 00405681 <--если 015F:0040567A CMP DWORD PTR [EAX*4+EBP-1C],09 <-- нет 015F:0040567F JLE 004056A4 <-- то выходим из функции проверки 015F:00405681 PUSH 0041C42D 015F:00405686 PUSH ECX 015F:00405687 CALL 00414780 015F:0040568C ADD ESP,08 015F:0040568F PUSH 0041C435 015F:00405694 PUSH EBX 015F:00405695 CALL 00414780 015F:0040569A ADD ESP,08 015F:0040569D XOR EAX,EAX 015F:0040569F JMP 00405749 015F:004056A4 INC EAX 015F:004056A5 CMP EAX,07 <--Символов, судя по счётчику, должно быть 7 015F:004056A8 JL 00405668В этом куске кода программа проверяет, чтобы РН состоял только из Цифр и чтобы их было ровно 7. Смотрим дальше: 015F:004056AA IMUL EAX,[EBP-0C],000003E8 015F:004056B1 IMUL EDX,[EBP-14],64 015F:004056B5 ADD EAX,EDX 015F:004056B7 MOV EDX,[EBP-04] 015F:004056BA ADD EDX,EDX 015F:004056BC LEA EDX,[EDX*4+EDX] 015F:004056BF ADD EAX,EDX 015F:004056C1 ADD EAX,[EBP-1C] 015F:004056C4 IMUL ESI,EAX,0D 015F:004056C7 MOV EAX,ESI 015F:004056C9 MOV ESI,000000C5 015F:004056CE CDQ 015F:004056CF IDIV ESI 015F:004056D1 MOV ESI,EDX =================== 015F:004056D3 XOR EDI,EDI 015F:004056D5 XOR EAX,EAX 015F:004056D7 CMP BYTE PTR [EAX+ECX],00 015F:004056DB JZ 004056E9 015F:004056DD MOVSX EDX,BYTE PTR [EAX+ECX] 015F:004056E1 ADD EDI,EDX 015F:004056E3 INC EAX 015F:004056E4 CMP EAX,50 015F:004056E7 JL 004056D7 ===================== 015F:004056E9 MOV EAX,ESI 015F:004056EB PUSH ECX 015F:004056EC MOV ECX,0000000A 015F:004056F1 CDQ 015F:004056F2 IDIV ECX 015F:004056F4 POP ECX 015F:004056F5 ADD EAX,EDI 015F:004056F7 MOV EDI,00000064 015F:004056FC CDQ 015F:004056FD IDIV EDI 015F:004056FF MOV EDI,EDX 015F:00405701 MOV EAX,ESI 015F:00405703 MOV ESI,0000000A 015F:00405708 CDQ 015F:00405709 IDIV ESI 015F:0040570B MOV EAX,EDI 015F:0040570D ADD EAX,EAX 015F:0040570F LEA EAX,[EAX*4+EAX] 015F:00405712 ADD EDX,EAX 015F:00405714 MOV ESI,EDX 015F:00405716 IMUL EAX,[EBP-10],64 015F:0040571A MOV EDX,[EBP-18] 015F:0040571D ADD EDX,EDX 015F:0040571F LEA EDX,[EDX*4+EDX] 015F:00405722 ADD EAX,EDX 015F:00405724 ADD EAX,[EBP-08] 015F:00405727 CMP EAX,ESI 015F:00405729 JZ 00405749Здесь можно было бы начать анализировать алгоритм, но я решил поступить оригинально, я выяснил, что скрывается под [EBP-xx]: [EBP-04]=7цифра РН [EBP-08]=6цифра РН [EBP-0C]=5цифра РН [EBP-10]=4цифра РН [EBP-14]=3цифра РН [EBP-18]=2цифра РН [EBP-1С]=1цифра РНПотом я выяснил, что делается в этом цикле: 015F:004056D3 XOR EDI,EDI 015F:004056D5 XOR EAX,EAX 015F:004056D7 CMP BYTE PTR [EAX+ECX],00 015F:004056DB JZ 004056E9 015F:004056DD MOVSX EDX,BYTE PTR [EAX+ECX] 015F:004056E1 ADD EDI,EDX 015F:004056E3 INC EAX 015F:004056E4 CMP EAX,50 015F:004056E7 JL 004056D7А именно сумируются все сиволы введённого имени и результат записывается в EDI Заня это я решил не упрощать задачу, а просто "эмулировать" процедуру проверки. Т.е. я взял C++ и там создал переменные unsigned long eax,ebx,edx,ecx,edi,esi,SUM;Т.е. все необходимые регистры процессора и переменная SUM, в которой будет хранится сумма всех символов введённого имени. Завёл переменную char number[7]="\0\0\0\0\0\0\0";это будет число, которое мы будем наращивать в цикле и смотреть, является ли оно правильным РН или нет. Вобщем сделал все так, как в программе (Люди, которые мало-мальски знакомы с программированием поймут меня, а люди, которые нет - им в писании кейгена места нету). (3) Сам КейГен. #include <iostream.h> #include <conio.h>void inc(char *number) //Функция увеличения на 1 нашего перебираемого числа { int i; number[6]++; if (number[6]>9) { for (i=6;i>=0;i--) { number[i]=0; number[i-1]++; if (number[i-1]<10) break; } } } void main() { char name[50]; //наше имя char number[7]="\0\0\0\0\0\0\0"; //перебираемое число unsigned long eax,ebx,edx,ecx,edi,esi,SUM,i,passcount=0; int k,l; cout<<"KeyGen For Professional Minesweeper v1.2 Shareware version \n"; cout<<"cracked by vallkor (vallkor@chat.ru) or http://vallkor/chat.ru \n\n"; cout<<"Enter your name:"; cin>>name; SUM=0; for (i=0;name[i]!=0;i++) //в этом цикле считаем сумму всех букв имени SUM=SUM+name[i]; for (i=0;i<9999999;i++) //главный цикл перебора //в котором мы переписываем всю логическую //часть функции проверки //преобразовывая ассемблерный код в C++ { eax=number[4]*0x3E8; edx=number[2]*0x64; eax+=edx; edx=10*number[6]; eax+=edx; eax+=number[0]; esi=eax*0x0D; eax=esi; esi=0xC5; edx=eax%esi; eax=eax/esi; esi=edx; edi=SUM; eax=esi; ecx=0x0A; edx=eax%ecx; eax=eax/ecx; eax+=edi; edi=0x64; edx=eax%edi; eax=eax/edi; edi=edx; eax=esi; esi=0x0A; edx=eax%esi; eax=eax/esi; eax=edi*10; edx+=eax; esi=edx; eax=number[3]*0x64; edx=number[1]*10; eax+=edx; eax+=number[5]; if (eax==esi) { for(k=0;k<7;k++) cout<<number[k]+0; cout<<"\n"; passcount++; } inc(number); //наращиваем перебираемое число и на следующее прохождение } cout<<"\n Password's Found:"<<passcount; //вывели количество найденых правильных РН для нашего имени getch(); } (4) Как оказалось, для любого имени всегда можно найти 10000 правильных РН. Т.е. даже простой чудак, перебрав сотню-другую паролей смог бы найти правильный для себя, но в том-то и прикол, что простой чувак не знает об этом. Вообще приведеный метод анализа и построения перебора без детального разбора алгоритма хорош только в таких вот "слабых" защитах, где время, затраченное на перебор в 100 раз меньше, чем нужно для детального анализа. К тому же если оптимизировать цикл (а там много чего можно оптимизировать, т.к. он просто сконвертирован в С++ из ассемблерного вида безо всякого изменения), то все пароли переберутся ещё в 10-ки раз быстрее. Вобщем задача выполнена, программа закейгенена без особых усилий. А остальное уже флейм, а значит позвольте мне откланяться и идти переписывать конспекты закошенных по вине написания этого туториала лекций :) Извращался, исследовал и наваял туториал: vallkor //PTDS E-mail: vallkor@chat.ru Page : http://vallkor.chat.ru
Альтернативный метод написания КейГена на примере Professional Minesweeper v1.2 Shareware version. Комментарии и вопросыПолучайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта. :: Главная :: Исследование программ ::
|
||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 |