系统 : Windows xp
程序 : RCA_CRACKME
程序下载地址 :http://pan.baidu.com/s/1bnoOQ6
要求 : 注册机编写
使用工具 : IDA Pro & OD
可在“PEDIY CrackMe 2007”中查找关于此程序的讨论,标题为“RCA Crackme 简单分析”。
运行程序输入测试用户名密码,准备进行测试。发现check it!!!按钮被隐藏了,无法单击。怀疑这里用了隐藏按钮窗口的API函数,这里我们使用IDA载入程序,发现左侧函数名称中的确有“EnableWindow”函数。双击定位,双击交叉参考进入程序调用它的位置:
.text:00401064 push 3EEh ; nIDDlgItem
.text:00401069 push [ebp+hDlg] ; hDlg
.text:0040106C call GetDlgItem
.text:00401071 mov [ebp+hWnd], eax
.text:00401074 or eax, eax
.text:00401076 jnz short loc_401087
.text:00401078 push 1 ; bEnable
.text:0040107A push [ebp+hWnd] ; hWnd
.text:0040107D call EnableWindow
.text:00401082 jmp loc_40112A
.text:00401087 ; ---------------------------------------------------------------------------
.text:00401087
.text:00401087 loc_401087: ; CODE XREF: DialogFunc+36j
.text:00401087 push 0 ; bEnable
.text:00401089 push [ebp+hWnd] ; hWnd
.text:0040108C call EnableWindow
.text:00401091 jmp loc_40112A
可以看到,程序调用GetDlgItem的返回值做判断,根据参数不难发现,这里的GetDlgItem是WinAPI函数。打开OD,将401076处的代码改成“jz short 00401087”即可解除隐藏按钮。
接着一开始,我们输入测试用户名密码,并根据提供的错误字串找到关键算法:
0040115E |. 57 push edi ; /String => ""
0040115F |. E8 48010000 call <jmp.&kernel32.lstrlenA> ; \lstrlenA
00401164 |. 8BD8 mov ebx, eax ; 用户名长度保存在ebx中
00401166 |. 33C0 xor eax, eax
00401168 |> 50 /push eax
00401169 |. 53 |push ebx ; 长度入栈
0040116A |. 57 |push edi ; 字串地址入栈
0040116B |. 0FBE0C38 |movsx ecx, byte ptr [eax+edi] ; 逐个取字符
0040116F |. 51 |push ecx ; /<%x>
00401170 |. 68 59304000 |push 00403059 ; |Format = "%x"
00401175 |. 68 68314000 |push 00403168 ; |s = CrackMe.00403168
0040117A |. E8 D3000000 |call <jmp.&user32.wsprintfA> ; \wsprintfA
0040117F |. 83C4 0C |add esp, 0C ; 平衡堆栈
00401182 |. 68 68314000 |push 00403168 ; /StringToAdd = ""
00401187 |. 68 68324000 |push 00403268 ; |ConcatString = ""
0040118C |. E8 0F010000 |call <jmp.&kernel32.lstrcatA> ; \lstrcatA
00401191 |. 5F |pop edi
00401192 |. 5B |pop ebx
00401193 |. 58 |pop eax
00401194 |. 40 |inc eax ; 循环变量自增
00401195 |. 3BC3 |cmp eax, ebx
00401197 |.^ 7C CF \jl short 00401168
00401199 |. 68 68334000 push 00403368 ; /String2 = ""
0040119E |. 68 68324000 push 00403268 ; |String1 = ""
004011A3 |. E8 FE000000 call <jmp.&kernel32.lstrcmpA> ; \lstrcmpA
004011A8 |. 0BC0 or eax, eax
004011AA |. 75 4A jnz short 004011F6
004011AC |. 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
004011AE |. 68 00304000 push 00403000 ; |Title = "Reverse Engineering Association"
004011B3 |. 68 20304000 push 00403020 ; |Text = "Congratulation! You've done with it"
004011B8 |. FF75 08 push dword ptr [ebp+8] ; |hOwner
004011BB |. E8 C2000000 call <jmp.&user32.MessageBoxA> ; \MessageBoxA
004011C0 |. 68 EC030000 push 3EC ; /ControlID = 3EC (1004.)
004011C5 |. FF75 08 push dword ptr [ebp+8] ; |hWnd
004011C8 |. E8 A3000000 call <jmp.&user32.GetDlgItem> ; \GetDlgItem
004011CD |. 8945 FC mov dword ptr [ebp-4], eax
004011D0 |. 6A 00 push 0 ; /Enable = FALSE
004011D2 |. FF75 FC push dword ptr [ebp-4] ; |hWnd
004011D5 |. E8 8A000000 call <jmp.&user32.EnableWindow> ; \EnableWindow
004011DA |. 68 ED030000 push 3ED ; /ControlID = 3ED (1005.)
004011DF |. FF75 08 push dword ptr [ebp+8] ; |hWnd
004011E2 |. E8 89000000 call <jmp.&user32.GetDlgItem> ; \GetDlgItem
004011E7 |. 8945 F8 mov dword ptr [ebp-8], eax
004011EA |. 6A 00 push 0 ; /Enable = FALSE
004011EC |. FF75 F8 push dword ptr [ebp-8] ; |hWnd
004011EF |. E8 70000000 call <jmp.&user32.EnableWindow> ; \EnableWindow
004011F4 |. EB 14 jmp short 0040120A
004011F6 |> 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
004011F8 |. 68 00304000 push 00403000 ; |Title = "Reverse Engineering Association"
004011FD |. 68 44304000 push 00403044 ; |Text = "No,no! Try it again!"
00401202 |. FF75 08 push dword ptr [ebp+8] ; |hOwner
00401205 |. E8 78000000 call <jmp.&user32.MessageBoxA> ; \MessageBoxA
以上就是关键处算法,用户名字串的十六进制码既是密钥。
打开http://www.cnblogs.com/ZRBYYXDM/p/5002789.html中搭建的MFC窗口程序,修改OnOk函数如下:
void CSerialNumber_KeygenDlg::OnOK() { // TODO: Add extra validation here CString str; GetDlgItem( IDC_EDIT_NAME )->GetWindowText( str ); //获取用户名 int len = str.GetLength(); //获取长度 CString SerialNumber,Temp; for ( int i = 0 ; i != len ; i++ ){ Temp.Format( "%x",str[i] ); SerialNumber += Temp; } GetDlgItem( IDC_EDIT_Number )->SetWindowText( SerialNumber ); //CDialog::OnOK(); //屏蔽基类OnOk函数 }
再在OnInitDialog中添加此代码修改标题:SetWindowText(_T("RCA_CRACKME_Keygen"));
运行效果:
我们一路奋战,不是为了改变世界,而是不让世界改变我们
——《熔炉》