///////////////////////////////////////////////////////////////////////////////////
Program : Zart's Keygenme
Download :
http://www.crackmes.de/users/zart/mishka_tribute/download
Description : make a keygen, do whatever you need to for this, just submit solution and keygen.
Tools : IDA, OllyDbg
Difficult : Easy
Packer/Protector/Compiler : N/A
Objective : Keygen
Cracker : kienmanowar{REATEAM}
///////////////////////////////////////////////////////////////////////////////////
Trước tiên phải nói bản thân cái keygenme này nó có Bug dẫn đến keygen ko thỏa hết các trường hợp và cũng rất khó chịu
1. Chạy keygenme, hehe tác giả cho nghe một bài tune. Nhập Name và Serial vào và nhấn Enter, blah biến mất luôn không để lại em Nag nào!!
2. Load thử vào Olly trước, tìm tất cả các Ref strings nhưng ko có em nào thú vi cả. Bật IDA lên và load keygenme vào, chờ analyse xong thì nhấn Shift+F12 đẻ mở cửa số Strings.Dạo một lượt ta tìm được Good Boy
Code: .data:00407028 szSerialcheckedout-nowrightakeygen_ db 0Ah ; DATA XREF: _main+15Ao_main
.data:00407028 db 'Serial checked out - now right a keygen.',0Ah,0
3. Nhấn đúp chuột vào _main+15Ao sẽ trở lai asm code :
Code: .text:00401246 push offset szSerialcheckedout-nowrightakeygen_ ; "\nSerial checked out - now right a keyge"...
.text:0040124B jmp short loc_401252 ; Jump
.text:0040124B
.text:0040124D ; ---------------------------------------------------------------------------
.text:0040124D
.text:0040124D loc_40124D: ; CODE XREF: _main+158j
.text:0040124D push offset szSerialfailedcheck ; "\nSerial failed check!\n"
.text:0040124D
4. Giờ thì reload lại keygenme trong Olly và nhấn Ctrl+G, nhập vào địa chỉ 0x00401246. Cuộn lên trên đầu và đặt một BP tại điểm bắt đầu của thủ tục này :
Code: 004010EC >/$ B8 69414000 MOV EAX, <keygenme.loc_404169> ; _main <== set BP here
004010F1 |. E8 DA2E0000 CALL <keygenme.__EH_prolog>
004010F6 |. 83EC 24 SUB ESP, 24
004010F9 |. 53 PUSH EBX
5. Nhấn F9 để rụn, dừng lại tại BP. Trace down cho tới khi tới đoạn asm code nhận UserName và Serial. Trong đoạn code này ta sẽ thấy nó lấy từng kí tự một và so sánh xem có phải kí tự có mã 0xD (Phím enter), còn không nó sẽ chuẩn bị một vùng Buffer để thực hiện việc nối chuỗi.Cụ thể đoạn code như sau, anh em đọc sẽ hiểu :
Code: 0040119A >|> /FF15 9C604000 /CALL NEAR DWORD PTR DS:[<&MSVCRT._kbhit>] ; [loc_40119A
004011A0 |. |85C0 |TEST EAX, EAX
004011A2 |.^ 74 F6 |JE SHORT <keygenme.loc_40119A>
004011A4 |. |FF15 98604000 |CALL NEAR DWORD PTR DS:[<&MSVCRT._getch>] ; [_getch
004011AA |. |837D E4 00 |CMP DWORD PTR SS:[EBP-1C], 0
004011AE |. |8845 E8 |MOV BYTE PTR SS:[EBP-18], AL
004011B1 |. |75 5E |JNZ SHORT <keygenme.loc_401211>
004011B3 |. |3C 0D |CMP AL, 0D
004011B5 |. |75 33 |JNZ SHORT <keygenme.loc_4011EA>
004011B7 |. |837D EC 00 |CMP DWORD PTR SS:[EBP-14], 0
004011BB |. |75 0F |JNZ SHORT <keygenme.loc_4011CC>
004011BD |. |8B0D 10604000 |MOV ECX, DWORD PTR DS:[<&MSVCIRT.cout>] ; MSVCIRT.cout
004011C3 |. |68 60704000 |PUSH keygenme.00407060 ; ASCII 0A,"You must enter a name!\n Name: "
004011C8 |. |FFD6 |CALL NEAR ESI
004011CA |.^ EB CE |JMP SHORT <keygenme.loc_40119A>
004011CC >|> |8B0D 10604000 |MOV ECX, DWORD PTR DS:[<&MSVCIRT.cout>] ; loc_4011CC
004011D2 |. |68 54704000 |PUSH keygenme.00407054 ; ASCII "Serial: "
004011D7 |. |C745 E4 01000000 |MOV DWORD PTR SS:[EBP-1C], 1
004011DE |. |FFD6 |CALL NEAR ESI
004011E0 |. |50 |PUSH EAX
004011E1 |. |FF15 18604000 |CALL NEAR DWORD PTR DS:[<&MSVCIRT.flush>] ; MSVCIRT.flush
004011E7 |. |59 |POP ECX
004011E8 |.^ EB B0 |JMP SHORT <keygenme.loc_40119A>
004011EA >|> |FF75 E8 |PUSH DWORD PTR SS:[EBP-18] ; loc_4011EA
004011ED |. |8B0D 10604000 |MOV ECX, DWORD PTR DS:[<&MSVCIRT.cout>] ; MSVCIRT.cout
004011F3 |. |FFD7 |CALL NEAR EDI
004011F5 |. |50 |PUSH EAX
004011F6 |. |FF15 18604000 |CALL NEAR DWORD PTR DS:[<&MSVCIRT.flush>] ; MSVCIRT.flush
004011FC |. |59 |POP ECX
004011FD |. |FF75 E8 |PUSH DWORD PTR SS:[EBP-18]
00401200 |. |8D4D D0 |LEA ECX, DWORD PTR SS:[EBP-30]
00401203 |. |FF75 EC |PUSH DWORD PTR SS:[EBP-14]
00401206 |. |FF15 24604000 |CALL NEAR DWORD PTR DS:[<&MSVCP60.std::basic_string<char,std::c>; MSVCP60.std::basic_string<char,std::char_traits<char>,std::allocator<char> >::append
0040120C |. |FF45 EC |INC DWORD PTR SS:[EBP-14]
0040120F |.^ EB 89 |JMP SHORT <keygenme.loc_40119A>
00401211 >|> |3C 0D |CMP AL, 0D ; loc_401211
00401213 |. |74 23 |JE SHORT <keygenme.loc_401238>
00401215 |. |FF75 E8 |PUSH DWORD PTR SS:[EBP-18]
00401218 |. |8B0D 10604000 |MOV ECX, DWORD PTR DS:[<&MSVCIRT.cout>] ; MSVCIRT.cout
0040121E |. |FFD7 |CALL NEAR EDI
00401220 |. |50 |PUSH EAX
00401221 |. |FF15 18604000 |CALL NEAR DWORD PTR DS:[<&MSVCIRT.flush>] ; MSVCIRT.flush
00401227 |. |59 |POP ECX
00401228 |. |8D049B |LEA EAX, DWORD PTR DS:[EBX+EBX*4]
0040122B |. |0FBE4D E8 |MOVSX ECX, BYTE PTR SS:[EBP-18]
0040122F |. |8D5C41 D0 |LEA EBX, DWORD PTR DS:[ECX+EAX*2-30]
00401233 |.^\E9 62FFFFFF \JMP <keygenme.loc_40119A>
Dùng IDA dựng mã giả của đoạn trên :
Code: while ( TRUE )
{
while ( TRUE )
{
while ( !kbhit() )
;
iKeyInput = getch();
LOBYTE(iTempChar) = iKeyInput;
if ( v18 )
break;
if ( iKeyInput == Enter_key )
{
if ( iSize )
{
v18 = 1;
szStr = ostream__operator__(cout, "\nSerial: ");
flush(szStr);
}
else
{
ostream__operator__(cout, "\nYou must enter a name!\nName: ");
}
}
else
{
v11 = ostream__operator__(cout, iTempChar);
flush(v11);
std__basic_string_char_std__char_traits_char__std__allocator_char____append(&szStrBuffer, iSize++, iTempChar); //Append String
}
}
if ( iKeyInput == Enter_key )
break;
v12 = ostream__operator__(cout, iTempChar);
flush(v12);
szSerial = (char)iTempChar + 10 * szSerial - 48;
}
6. Ok sau khi có được mảng buffer chứa chuỗi vừa tính toán, ta trace tiếp tới đoạn code sau :
Code: 00401238 >|> \8D45 D0 LEA EAX, DWORD PTR SS:[EBP-30] ; loc_401238
0040123B |. 50 PUSH EAX ;
0040123C |. E8 BFFDFFFF CALL <keygenme.sub_calculate_serial()> ; <== Trace Into
7. Trace into sub_calculate_serial() :
Code: 00401005 |. 33C0 XOR EAX, EAX ; <== eax = 0
00401007 |. 33F6 XOR ESI, ESI ; <== esi = 0
00401009 |. 8B51 08 MOV EDX, DWORD PTR DS:[ECX+8] ; <== Length(szTempString)
0040100C |. 57 PUSH EDI
0040100D |. 85D2 TEST EDX, EDX
0040100F |. BF BA430000 MOV EDI, 43BA ; <== edi = 0x43BA
00401014 |. 76 25 JBE SHORT <keygenme.loc_40103B>
00401016 |. 53 PUSH EBX
00401017 |. 8B59 04 MOV EBX, DWORD PTR DS:[ECX+4] ; <== ebx : szTempString[]
0040101A >|> 8B0D 2C604000 /MOV ECX, DWORD PTR DS:[<&MSVCP60.`std::basic_string<char,std::>; loc_40101A
00401020 |. 85DB |TEST EBX, EBX
00401022 |. 74 03 |JE SHORT <keygenme.loc_401027>
00401024 |. 8D0C33 |LEA ECX, DWORD PTR DS:[EBX+ESI]
00401027 >|> 0FBE09 |MOVSX ECX, BYTE PTR DS:[ECX] ; <== ecx = szTempString[i]
0040102A |. 0FAFC7 |IMUL EAX, EDI ; <== eax = eax * edi
0040102D |. 03C1 |ADD EAX, ECX ; <== eax = eax + ecx
0040102F |. 69FF FAE60600 |IMUL EDI, EDI, 6E6FA
00401035 |. 46 |INC ESI ; <== esi++
00401036 |. 3BF2 |CMP ESI, EDX ; <== while esi < Length(szTempString)
00401038 |.^ 72 E0 \JB SHORT <keygenme.loc_40101A> ; <== Then continue
Sử dụng IDA để dựng mã giả :
Code: int iReaKey; // eax@1
unsigned int iLenszStrBuffer; // edx@1
unsigned int iInit; // edi@1
unsigned int iIndex; // esi@1
int v5; // ebx@2
void *szChar; // ecx@3
iReaKey = 0;
iIndex = 0;
iLenszStrBuffer = *(_DWORD *)(a1 + 8); // Length of szStrBuffer
iInit = 0x43BAu;
if ( iLenszStrBuffer )
{
v5 = *(_DWORD *)(a1 + 4); // Point to szStrBuffer
do
{
szChar = _C;
if ( v5 )
szChar = (void *)(v5 + iIndex); // Get char for szStrBuffer
iReaKey = *(_BYTE *)szChar + iInit * iReaKey;
iInit *= 0x6E6FAu;
++iIndex;
}
while ( iIndex < iLenszStrBuffer );
}
return iReaKey;
Dòm vào đoạn mã giả trên, ta thấy mảng Buffer sẽ được sử dụng để tính toán, kết quả iRealKey cuối cùng sẽ được lưu trọng thanh ghi EAX.
8. Đây là đoạn check key sau khi tính toán và key ta nhập vào, đúng thì show Good Boy :
Code: 00401241 |. 3BC3 CMP EAX, EBX <== Compare iReal Key with szSerial
00401243 |. 59 POP ECX
00401244 |. 75 07 JNZ SHORT <keygenme.loc_40124D>
00401246 |. 68 28704000 PUSH keygenme.00407028 ; ASCII 0A,"Serial che"
0040124B |. EB 05 JMP SHORT <keygenme.loc_401252>
0040124D >|> 68 10704000 PUSH keygenme.00407010 ; loc_40124D
00401252 >|> 8B0D 10604000 MOV ECX, DWORD PTR DS:[<&MSVCIRT.cout>] ; loc_401252
00401258 |. FFD6 CALL NEAR ESI
0040125A |. FF75 E0 PUSH DWORD PTR SS:[EBP-20]
0040125D |. E8 35040000 CALL <keygenme.sub_401697>
00401262 |. 59 POP ECX
00401263 |. E8 59010000 CALL <keygenme.sub_4013C1>
00401268 |. 834D FC FF OR DWORD PTR SS:[EBP-4], FFFFFFFF
0040126C |. 6A 01 PUSH 1
0040126E |. 8D4D D0 LEA ECX, DWORD PTR SS:[EBP-30]
00401271 |. FF15 30604000 CALL NEAR DWORD PTR DS:[<&MSVCP60.std::basic_string<char,std::ch>; MSVCP60.std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Tidy
00401277 |. 5F POP EDI
00401278 |. 33C0 XOR EAX, EAX
0040127A |. 5E POP ESI
0040127B >|> 8B4D F4 MOV ECX, DWORD PTR SS:[EBP-C] ; loc_40127B
0040127E |. 5B POP EBX
0040127F |. 64:890D 00000000 MOV DWORD PTR FS:[0], ECX
00401286 |. C9 LEAVE
00401287 \. C3 RETN
Tổng kết là toàn bộ source của keygenme(hehe sẽ có bug không tránh khỏi nhé ):
Code: char szName[64]={0};
char szSerial[64]={0};
char szTempString[128]={0};
char szTemp[64]={0};
int i=0,j=0,LenUser=0,iRealKey=0,iValue=0;
LenUser=GetDlgItemText(IDC_Name,szName,70);
if (LenUser < 1 || LenUser > 14)
{
MessageBox("----------===== Your name atleast 1 chart ====---------- \n\n ----------===== But not over 14 charts ====---------- ","Hey !! Please input your name again !! ");
}
else
{
i = 0;
while (i < LenUser)
{
i++;
for (j=i;j>0;j--)
{
szTemp[j-1] = szName[i];
}
strncat(szTempString,szTemp,i);
}
LenUser = strlen(szTempString);
i = 0;
_asm
{
xor eax,eax
xor esi,esi
xor edx,edx
mov edi,0x43BA
}
while (i < LenUser)
{
_asm
{
mov eax, iRealKey
lea ecx, dword ptr[szTempString]
movsx ecx,byte ptr[ecx+esi]
imul eax, edi
add eax, ecx
imul edi, edi, 0x6E6FA
inc esi
mov iRealKey,eax
}
i++;
}
wsprintf(szSerial,"%d",iRealKey);
}
SetDlgItemText(IDC_Serial,szSerial);
That's all. Thanx for reading my tutor.
--++--==[ Greatz Thanks To ]==--++--
My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix aka mfeng, dqtln, ARTEAM .... all my friend, and YOU.
--++--==[ Thanks To ]==--++--
iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl, moth, XIANUA, nhc1987 v..v..