【破文标题】CRACKME破解分析
【破文作者】逍遥风
【破解工具】OD, WINHEX, PEID
【破解平台】WEINXP
【软件名称】 TDC KeyFile ME [#2]
【原版下载】http://www.crackmes.de/users/tdcnl/tdc_keyfile_me_2/
【软件简介】Difficulty: 2 - Needs a little brain (or luck)
Platform: Windows
Language: Assembler
【破解声明】菜鸟偶得一点心得,与大家分享
------------------------------------------------------------------------
1)PEID检查:MASM32 / TASM32,无壳
2)OD,载入,开始分析:
在命令行下断点:bp GetDlgItem
004010EE . A3 6E604000 MOV DWORD PTR DS:[40606E],EAX
004010F3 . 6A 75 PUSH 75 ; /ControlID = 75 (117.)
004010F5 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004010F8 . E8 BB030000 CALL <JMP.&user32.GetDlgItem> ; \GetDlgItem
004010FD . A3 72604000 MOV DWORD PTR DS:[406072],EAX 中断在这里
00401102 . 6A 76 PUSH 76 ; /ControlID = 76 (118.)
00401104 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401107 . E8 AC030000 CALL <JMP.&user32.GetDlgItem> ; \GetDlgItem
0040110C . A3 76604000 MOV DWORD PTR DS:[406076],EAX
00401111 . 68 7A604000 PUSH keyfilem.0040607A ; /name
00401116 . 6A 74 PUSH 74 ; |ControlID = 74 (116.)
00401118 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
0040111B . E8 B0030000 CALL <JMP.&user32.SetDlgItemTextA> ; \SetDlgItemTextA
00401120 . 68 7F604000 PUSH keyfilem.0040607F ; /serial
00401125 . 6A 75 PUSH 75 ; |ControlID = 75 (117.)
00401127 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
0040112A . E8 A1030000 CALL <JMP.&user32.SetDlgItemTextA> ; \SetDlgItemTextA
0040112F . 68 1F604000 PUSH keyfilem.0040601F ; /unregistered
00401134 . 6A 76 PUSH 76 ; |ControlID = 76 (118.)
00401136 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401139 . E8 92030000 CALL <JMP.&user32.SetDlgItemTextA> ; \SetDlgItemTextA
0040113E . E8 F0010000 CALL keyfilem.00401333 重要CALL,跟进
----------------------------------------------------------------------------------------------------------------------------------------------------------
跟进后来到这里
00401333 /$ 6A 00 PUSH 0 ; /hTemplateFile = NULL
00401335 |. 68 80000000 PUSH 80 ; |Attributes = NORMAL
0040133A |. 6A 03 PUSH 3 ; |Mode = OPEN_EXISTING
0040133C |. 6A 00 PUSH 0 ; |pSecurity = NULL
0040133E |. 6A 01 PUSH 1 ; |ShareMode = FILE_SHARE_READ
00401340 |. 68 00000080 PUSH 80000000 ; |Access = GENERIC_READ
00401345 |. 68 32604000 PUSH keyfilem.00406032 ; |keyfile.dat
0040134A |. E8 93010000 CALL <JMP.&kernel32.CreateFileA> ; \CreateFileA
0040134F |. A3 62604000 MOV DWORD PTR DS:[406062],EAX ; 检测文件
00401354 |. 83F8 FF CMP EAX,-1 ; 有KEY文件吗?
00401357 |. 0F84 DB000000 JE keyfilem.00401438 ; 没有就OVER
先检测有没有KEY文件,根据OD提示,KEY文件的文件名应为:keyfile.dat
用WINHEX建立一个keyfile.dat的文件
0040135D |. 6A 00 PUSH 0 ; /pFileSizeHigh = NULL
0040135F |. FF35 62604000 PUSH DWORD PTR DS:[406062] ; |hFile = 00000130 (window)
00401365 |. E8 8A010000 CALL <JMP.&kernel32.GetFileSize> ; \GetFileSize
0040136A |. 83F8 20 CMP EAX,20 ; 文件大小是32字节吗?
0040136D |. 0F85 CE000000 JNZ keyfilem.00401441 ; 不是就跳向失败
检测KEY文件的大小是否为32字节。
将keyfile.dat文件的字节数定为32字节
00401373 |. 6A 00 PUSH 0 ; /pOverlapped = NULL
00401375 |. 68 48634000 PUSH keyfilem.00406348 ; |pBytesRead = keyfilem.00406348
0040137A |. 6A 10 PUSH 10 ; |BytesToRead = 10 (16.)
0040137C |. 68 3E604000 PUSH keyfilem.0040603E ; |Buffer = keyfilem.0040603E
00401381 |. FF35 62604000 PUSH DWORD PTR DS:[406062] ; |hFile = 00000130 (window)
00401387 |. E8 86010000 CALL <JMP.&kernel32.ReadFile> ; \ReadFile
0040138C |. FF35 62604000 PUSH DWORD PTR DS:[406062] ; /hObject = 00000130 (window)
00401392 |. E8 45010000 CALL <JMP.&kernel32.CloseHandle> ; \CloseHandle
00401397 |. 33C9 XOR ECX,ECX ; ECX清零
00401399 |. 33D2 XOR EDX,EDX ; EDX清零
0040139B |. BA 0F000000 MOV EDX,0F ; 使EDX=0x0F
{ 004013A0 |> 0FBE8A 3E6040>/MOVSX ECX,BYTE PTR DS:[EDX+40603E]
004013A7 |. 4A |DEC EDX
004013A8 |. 83F9 20 |CMP ECX,20
004013AB |. 75 09 |JNZ SHORT keyfilem.004013B6
004013AD |. C682 3F604000>|MOV BYTE PTR DS:[EDX+40603F],0
004013B4 |.^ EB EA \JMP SHORT keyfilem.004013A0 注意这个循环。后面还要用,设为循环A}
开始读取文件内容,并检验文件的第16个字节是不是空格。
如果第16个字节不是空格经过2个跳转后来到这里,对前16个字节的内容进行计算
0040146E |> /0FB681 3E6040>/MOVZX EAX,BYTE PTR DS:[ECX+40603E] ; 取每一个字符的ASCII码
00401475 |. |83C0 0F |ADD EAX,0F ; 每一个字符的ASCII码加上0x0F
00401478 |. |83F0 20 |XOR EAX,20 ; 与0x20做XOR运算
0040147B |. |03D8 |ADD EBX,EAX ; 把每一位的计算结果累加
0040147D |. |41 |INC ECX ; 每计算一次ECX+1
0040147E |. |3BCA |CMP ECX,EDX ; 计算完了吗?
00401480 |.^\75 EC \JNZ SHORT keyfilem.0040146E ; 没有就继续
00401482 |. 33C9 XOR ECX,ECX ; ECX清零
00401484 |. 69DB 697A0000 IMUL EBX,EBX,7A69 ; 累加的结果乘以0x7A69
0040148A |. 53 PUSH EBX ; /<%X>
0040148B |. 68 84624000 PUSH keyfilem.00406284 ; |%x
00401490 |. 68 87624000 PUSH keyfilem.00406287 ; |s = keyfilem.00406287
00401495 |. E8 0C000000 CALL <JMP.&user32.wsprintfA> ; \wsprintfA
0040149A |. 83C4 0C ADD ESP,0C
0040149D |. 5F POP EDI
0040149E |. 5B POP EBX
0040149F |.^ E9 17FFFFFF JMP keyfilem.004013BB 计算完毕后跳回到开始读取文件的地方,对后16个字节进行检验
中间过程省略,直接再次来到循环A
0040140C |> /0FBE8A 4E6040>/MOVSX ECX,BYTE PTR DS:[EDX+40604E] ; 倒序取后16个字节的每个字节的内容
00401413 |. |4A |DEC EDX
00401414 |. |83F9 20 |CMP ECX,20 ; 是空格吗?
00401417 |. |75 09 |JNZ SHORT keyfilem.00401422 ; 不是就跳走
00401419 |. |C682 4F604000>|MOV BYTE PTR DS:[EDX+40604F],0
00401420 |.^\EB EA \JMP SHORT keyfilem.0040140C ; 取下一位继续计算
一直取到第一个不是空格的地方
00401422 |> 68 87624000 PUSH keyfilem.00406287 ;
00401427 |. 68 4E604000 PUSH keyfilem.0040604E ;
0040142C |. E8 ED000000 CALL <JMP.&kernel32.lstrcmpA> ; 比较后16个字节的内容与前16个字节累加计算和是否相等
00401431 |. 83F8 00 CMP EAX,0 ; 如果EAX=0就成功
00401434 |. 74 1D JE SHORT keyfilem.00401453 ; 跳向成功
注意:
建立KEY文件时:
因为程序对文件中的内容反复进行读取。
所以前16个字节的内容与后16个字节的内容最好不一样,以便于分析和得出正确的结论
------------------------------------------------------------------------
破解总结:
1)KEY文件的文件名为keyfile.dat,大小为32字节
2)对KEY文件的前16个字节每一字节的字符进行计算:(ASCII码-0x0F) XOR 0x20。并把每一位的结果累加,结果设为A
3)后16个字节的内容格式为:A+“空格”。(注意:后16个字节的前N位必须为累加结果A,再用空格将其补足16个字节)N为累加结果A的位数。
4)NAME=全部32个字节的内容
SERIAL=后16个字节的内容
例:
文件名:keyfile.dat
大小:32字节
内容:7869616F79616F66656E676C6F76656533304543313644202020202020202020
(xiaoyaofenglovee30EC16D )
------------------------------------------------------------------------
【版权声明】本文只为交流,转载请保留作者及文章完整性
[招生]系统0day安全班,企业级设备固件漏洞挖掘,Linux平台漏洞挖掘!