|
【标题】:PEDIYCrackme竞赛2009-(Atom队-CrackMe)爆破分析
【作者】:hflywolf
【下载】:http://bbs.pediy.com/showthread.php?t=97183
【工具】:SOD+0D
【声明】:纯属技术学习,水平有限,如有错误之处,烦请指出!
CM 有anti,SOD直接无视(膜拜ing 海风大大)
第一部份:权
(一)、关键代码如下:
00401FF0 /. 55 push ebp ;
................................................................................................................
00402068 |. E8 930B0000 call 00402C00 ; 取当前时间的运算值
0040206D |. 8945 E0 mov dword ptr [ebp-20], eax ; 保存运算值(作为校验代码运行时间的初始值)
00402070 |. 33C0 xor eax, eax
取name和Serial
0040208F |. 6A 01 push 1 ;bSaveAndValidate = TRUE(获取数据)
0040209C |. E8 1D180000 call <jmp.&MFC42.#CWnd::UpdateData_6334> ;取name和Serial有关数据(长度和字符)
校验name和Serial的合法性
004020A1 |. 8B4B 60 mov ecx, dword ptr [ebx+60]
004020A4 |. 8B41 F8 mov eax, dword ptr [ecx-8]
004020A7 83F8 06 cmp eax, 6 ;这里改cmp eax,0
004020AA |. 0F8C 49020000 jl 004022F9 ;name长度要大于等于6
004020B0 |. 83F8 20 cmp eax, 20
004020B3 |. 0F8F 40020000 jg 004022F9 ;name长度要小于等于32(0x20)
................................................................................................................
004020B9 |. 8B53 64 mov edx, dword ptr [ebx+64]
004020BC |. 8B52 F8 mov edx, dword ptr [edx-8]
004020BF 83FA 06 cmp edx, 6 ;这里改cmp edx,0
004020C2 |. 0F8C 31020000 jl 004022F9 ;Serial长度要大于等于6
004020C8 |. 81FA A0000000 cmp edx, 0A0
004020CE |. 0F8F 25020000 jg 004022F9 ;Serial长度要大于等于160(0xA0)
................................................................................................................
004020D4 |. 8B35 E8414000 mov esi, dword ptr [<&MSVCRT.strncpy>] ; msvcrt.strncpy
004020DA |. 50 push eax ; /maxlen
004020DB |. 51 push ecx ; |src
004020DC |. 68 34534000 push 00405334 ; |dest = CrackMe1.00405334
004020E1 |. FFD6 call esi ; \strncpy
; 将name字符串复制到405335地址中去
................................................................................................................
004020E3 |. 8B43 64 mov eax, dword ptr [ebx+64]
004020E6 |. 8B48 F8 mov ecx, dword ptr [eax-8]
004020E9 |. 51 push ecx
004020EA |. 50 push eax
004020EB |. 68 68534000 push 00405368
004020F0 |. FFD6 call esi ; 将Serial字符串复制到405368地址中去
................................................................................................................
0040210A |> 8A82 34534000 /mov al, byte ptr [edx+405334]
00402110 |. 3C 30 |cmp al, 30
00402112 |. 7C 04 |jl short 00402118
00402114 |. 3C 39 |cmp al, 39
00402116 |. 7E 10 |jle short 00402128
00402118 |> 3C 61 |cmp al, 61
0040211A |. 7C 04 |jl short 00402120
0040211C |. 3C 7A |cmp al, 7A
0040211E |. 7E 08 |jle short 00402128
00402120 |> 3C 41 |cmp al, 41
00402122 |. 7C 1A |jl short 0040213E
00402124 |. 3C 5A |cmp al, 5A
00402126 |. 7F 16 |jg short 0040213E
00402128 |> BF 34534000 |mov edi, 00405334
0040212D |. 83C9 FF |or ecx, FFFFFFFF
00402130 |. 33C0 |xor eax, eax
00402132 |. 42 |inc edx
00402133 |. F2:AE |repne scas byte ptr es:[edi]
00402135 |. F7D1 |not ecx
00402137 |. 49 |dec ecx
00402138 |. 3BD1 |cmp edx, ecx
0040213A |.^ 75 CE \jnz short 0040210A ;校验name是否由0-9,a-z,A-Z间的字符组成的
0040213C |. EB 05 jmp short 00402143
0040213E BE 01000000 mov esi, 1 ;这里改成mov esi,0(name含不合法字符的标志)
................................................................................................................
00402156 |> 8A82 68534000 /mov al, byte ptr [edx+405368]
0040215C |. 3C 30 |cmp al, 30
0040215E |. 7C 04 |jl short 00402164
00402160 |. 3C 39 |cmp al, 39
00402162 |. 7E 10 |jle short 00402174
00402164 |> 3C 61 |cmp al, 61
00402166 |. 7C 04 |jl short 0040216C
00402168 |. 3C 7A |cmp al, 7A
0040216A |. 7E 08 |jle short 00402174
0040216C |> 3C 41 |cmp al, 41
0040216E |. 7C 1D |jl short 0040218D
00402170 |. 3C 5A |cmp al, 5A
00402172 |. 7F 19 |jg short 0040218D
00402174 |> BF 68534000 |mov edi, 00405368
00402179 |. 83C9 FF |or ecx, FFFFFFFF
0040217C |. 33C0 |xor eax, eax
0040217E |. 42 |inc edx
0040217F |. F2:AE |repne scas byte ptr es:[edi]
00402181 |. F7D1 |not ecx
00402183 |. 49 |dec ecx
00402184 |. 3BD1 |cmp edx, ecx
00402186 |.^ 75 CE \jnz short 00402156 ;校验Serial是否由0-9,a-z,A-Z间的字符组成的
00402188 |> 83FE 01 cmp esi, 1 ;判断name是否含不合法字符
0040218B |. 75 0B jnz short 00402198 ;name合法跳
0040218D |> 8B45 F0 mov eax, dword ptr [ebp-10]
00402190 |. 6A 00 push 0
00402192 |. 50 push eax
00402193 |. E9 64010000 jmp 004022FC ;name不合法跳
校验代码运行时间(代码中有多处校验,调用的都是同一个CALL 00402C00)
00402198 |> B9 58544000 mov ecx, 00405458
0040219D |. E8 5E0A0000 call 00402C00 ;取当前时间的运算值
004021A2 |. 8B75 E0 mov esi, dword ptr [ebp-20] ;取上面保存的初始时间的运算值
004021A5 |. 2BC6 sub eax, esi ;计算两个运算值的差值
004021A7 |. 83F8 02 cmp eax, 2 ;判断差值是否小于等于2
004021AA |. 7E 07 jle short 004021B3 ;是就跳走(OD中调试要注意这里必须跳)
004021AC |. 8BCB mov ecx, ebx
004021AE |. E8 0F160000 call <jmp.&MFC42.#CDialog::OnCancel_4376> ;大于2就关闭对话框
Serial长度是否不小于32
004021B3 |> BF 68534000 mov edi, 00405368
004021B8 |. 83C9 FF or ecx, FFFFFFFF
004021BB |. 33C0 xor eax, eax
004021BD |. F2:AE repne scas byte ptr es:[edi]
004021BF |. F7D1 not ecx
004021C1 |. 49 dec ecx
004021C2 83F9 20 cmp ecx, 20 ;这里改成cmp ecx,0
004021C5 |. 73 0A jnb short 004021D1 ;Serial长度是否不小于32(0x20),不小于跳走
004021C7 |. 8B4D F0 mov ecx, dword ptr [ebp-10]
004021CA |. 50 push eax
004021CB |. 51 push ecx
004021CC |. E9 2B010000 jmp 004022FC ;小于跳走
加密name和Serial的字符串
004021D1 |> 8B53 64 mov edx, dword ptr [ebx+64]
004021D4 |. 8D4D E4 lea ecx, dword ptr [ebp-1C]
004021D7 |. 8B42 F8 mov eax, dword ptr [edx-8]
004021DA |. 50 push eax
004021DB |. 68 68534000 push 00405368
004021E0 |. E8 4B110000 call 00403330 ; 这个CALL跟Serial有关(时间关系不看了)
004021E5 |. B9 58544000 mov ecx, 00405458
................................................................................................................
004021FD |> 68 BC514000 push 004051BC ; /Arg3 = 004051BC ASCII "Name"
00402202 |. 6A 20 push 20 ; |Arg2 = 00000020
00402204 |. 68 34534000 push 00405334 ; |Arg1 = 00405334
00402209 |. 8D4D E4 lea ecx, dword ptr [ebp-1C] ; |
0040220C |. E8 2F0F0000 call 00403140 ; \CrackMe1.00403140
; 将name字符串加密
................................................................................................................
00402211 |. 68 B4514000 push 004051B4 ; /Arg3 = 004051B4 ASCII "Serial"
00402216 |. 6A 20 push 20 ; |Arg2 = 00000020
00402218 |. 68 68534000 push 00405368 ; |Arg1 = 00405368
0040221D |. 8D4D E4 lea ecx, dword ptr [ebp-1C] ; |
00402220 |. E8 1B0F0000 call 00403140 ; \CrackMe1.00403140
; 将Serial字符串加密
校验name和Serial加密后的字符串
00402225 |. 0FBE05 695340>movsx eax, byte ptr [405369] ;EAX=Serial加密后第二个字符的ASCII值
0040222C |. 0FBE0D 685340>movsx ecx, byte ptr [405368] ;ECX=Serial加密后第一个字符的ASCII值
00402233 |. 0FBE15 355340>movsx edx, byte ptr [405335] ;EDX=name加密后第二个字符的ASCII值
0040223A |. 50 push eax ;保存EAX
0040223B |. 51 push ecx ;保存ECX
0040223C |. 0FBE05 345340>movsx eax, byte ptr [405334] ;EAX=name加密后第一个字符的ASCII值
00402243 |. 52 push edx ;保存EDX
00402244 |. 50 push eax ;保存EAX
00402245 |. 6A 01 push 1 ;Arg1 = 00000001
00402247 |. 8D4D A8 lea ecx, dword ptr [ebp-58] ;
0040224A |. E8 21F1FFFF call 00401370 ;关键CALL(时间关系不看了)
................................................................................................................
0040227D |. 0FBE0D 6A5340>movsx ecx, byte ptr [40536A] ;ECX=Serial加密后第三个字符的ASCII值
00402284 |. 0FBE15 375340>movsx edx, byte ptr [405337] ;EDX=name加密后第四个字符的ASCII值
0040228B |. 0FBE05 365340>movsx eax, byte ptr [405336] ;EAX=name加密后第三个字符的ASCII值
00402292 |. 6A 00 push 0 ;Arg6 = 00000000
00402294 |. 51 push ecx ;保存ECX
00402295 |. 0FBE0D 005340>movsx ecx, byte ptr [405300] ;ECX=byte ptr [405300](这个405300地址是个关键)
0040229C |. 52 push edx ;保存EDX
0040229D |. 50 push eax ;保存EAX
0040229E |. 51 push ecx ;保存ECX
0040229F |. 6A 02 push 2 ;Arg1 = 00000002
004022A1 |. 8D4D A8 lea ecx, dword ptr [ebp-58] ;
004022A4 |. E8 17F2FFFF call 004014C0 ;关键CALL(时间关系不看了)
(二)、关键代码如下:
004022F2 |. E8 19030000 call 00402610 ;进这个CALL
402610 代码如下:(注意的是:程序的"关于"也调用这个CALL)
00402610 /$ 56 push esi ;
00402611 |. 8BF1 mov esi, ecx
00402613 |. 6A 03 push 3
00402615 |. E8 66FEFFFF call 00402480 ;关键CALL(时间关系不看了)返回的eax必须为1
0040261A 83F8 01 cmp eax, 1 ;
0040261D 74 04 je short 00402623 ;eax为1跳,所以这里改成jmp 00402623
0040261F |. 33C0 xor eax, eax
00402621 |. 5E pop esi
00402622 |. C3 retn
00402623 |> 8BCE mov ecx, esi ;跳到这里来
00402625 |. E8 8E120000 call <jmp.&MFC42.#CDialog::DoModal_2514> ;调用CDialog::DoModal()函数
0040262A |. 5E pop esi
0040262B \. C3 retn
4025E0 代码如下:
004025E0 . 56 push esi
004025E1 . 8BF1 mov esi, ecx
004025E3 . 6A 07 push 7
004025E5 . E8 66FDFFFF call 00402350 ;进入CALL(校验是否注册失败)返回的exe为1
004025EA . 85C0 test eax, eax
004025EC . 8BCE mov ecx, esi
004025EE 75 09 jnz short 004025F9 ;必须跳,改成jmp 004025f9
004025F0 . E8 CD110000 call <jmp.&MFC42.#CDialog::OnCancel_4>
004025F5 . 33C0 xor eax, eax
004025F7 . 5E pop esi
004025F8 . C3 retn
004025F9 > E8 B4120000 call <jmp.&MFC42.#CDialog::OnInitDial>
004025FE . B8 01000000 mov eax, 1
00402603 . 5E pop esi
00402604 . C3 retn ;
402350 代码如下:(其实是用加密后的name和Serial的某个位字符的ASCII来运算,将得到的值来判断是否显示"注册失败"这个Static Text控件)
00402350 8B4424 04 mov eax, dword ptr [esp+4]
00402354 56 push esi
00402355 0FBE90 685340>movsx edx, byte ptr [eax+405368]
0040235C |. 0FBEB0 345340>movsx esi, byte ptr [eax+405334]
00402363 |. 2BF2 sub esi, edx
00402365 |. 8D56 02 lea edx, dword ptr [esi+2]
00402368 |. 83FA 0A cmp edx, 0A
0040236B 0F87 92000000 ja 00402403 ;这里直接改成jmp 0040240E
00402371 |> FF2495 4C2440>/jmp dword ptr [edx*4+40244C] ;以下循环时间关系不分析了
004023FD |.^ 0F86 6EFFFFFF \jbe 00402371
00402403 33C0 xor eax, eax
00402405 |. 5E pop esi
00402406 |. C2 0400 retn 4
................................................................................................................
0040240E |. 0FBE05 875340>movsx eax, byte ptr [405387] ;上面跳来这里
00402415 |. 0FBE15 535340>movsx edx, byte ptr [405353]
0040241C 2BD0 sub edx, eax ;这里改成xor edx,edx(为啥这么改,后面会说明)
0040241E 52 push edx ;保存edx,作为CWnd::ShowWindow的nCmdShow参数
0040241F |. 68 ED030000 push 3ED ;CWnd::GetDlgItem的控件ID参数(记下0x3ED,后面要用)
00402424 |. E8 A1140000 call <jmp.&MFC42.#CWnd::GetDlgItem_30> ;调用CWnd::GetDlgItem,取得Static Text控件(ID为Ox3ED)的指针
00402429 |. 8BC8 mov ecx, eax
0040242B |. E8 94140000 call <jmp.&MFC42.#CWnd::ShowWindow_62> ;调用CWnd::ShowWindow
00402430 |. 0FBE05 415340>movsx eax, byte ptr [405341]
00402437 |. 0FBE0D 755340>movsx ecx, byte ptr [405375]
0040243E |. 2BC1 sub eax, ecx
00402440 |. 5E pop esi
00402441 |. F7D8 neg eax
00402443 1BC0 sbb eax, eax
00402445 |. 40 inc eax
00402446 \. C2 0400 retn 4 ;返回的eax
402630 代码如下:(其实是用加密后的name和Serial的某个位字符的ASCII来运算,将得到的值来判断是否显示"注册成功"这个Static Text控件)
00402630 . 6A FF push -1
00402632 . 68 C83A4000 push 00403AC8 ; SE handler installation
00402637 . 64:A1 0000000>mov eax, dword ptr fs:[0]
0040263D . 50 push eax
0040263E . 64:8925 00000>mov dword ptr fs:[0], esp
00402645 . 83EC 54 sub esp, 54
00402648 . 56 push esi
00402649 . 8BF1 mov esi, ecx
0040264B . 56 push esi
0040264C . 8D4C24 08 lea ecx, dword ptr [esp+8]
00402650 . E8 4B120000 call <jmp.&MFC42.#CPaintDC::CPaintDC_>
00402655 . A0 00534000 mov al, byte ptr [405300] ;al=[405300](这个405300地址是个关键)
0040265A . C74424 60 000>mov dword ptr [esp+60], 0
00402662 . 3C 61 cmp al, 61
00402664 75 29 jnz short 0040268F ;这里不能跳,NOP掉
00402666 . 0FBE05 865340>movsx eax, byte ptr [405386]
0040266D . 0FBE0D 525340>movsx ecx, byte ptr [405352]
00402674 . 2BC8 sub ecx, eax
00402676 . F7D9 neg ecx
00402678 1BC9 sbb ecx, ecx ;这里改xor ecx,ecx(为啥这么做,后面说明)
0040267A . 41 inc ecx
0040267B . 51 push ecx ;保存ecx,作为CWnd::ShowWindow的nCmdShow参数
0040267C . 68 EB030000 push 3EB ;CWnd::GetDlgItem的控件ID参数(记下0x3EB,后面要用)
00402681 . 8BCE mov ecx, esi
00402683 . E8 42120000 call <jmp.&MFC42.#CWnd::GetDlgItem_30> ;调用CWnd::GetDlgItem,取得Static Text控件(ID为Ox3EB)的指针
00402688 . 8BC8 mov ecx, eax
0040268A . E8 35120000 call <jmp.&MFC42.#CWnd::ShowWindow_62> ;调用CWnd::ShowWindow
0040268F > 8D4C24 04 lea ecx, dword ptr [esp+4]
00402693 . C74424 60 FFF>mov dword ptr [esp+60], -1
0040269B . E8 FA110000 call <jmp.&MFC42.#CPaintDC::~CPaintDC>
004026A0 . 8B4C24 58 mov ecx, dword ptr [esp+58]
004026A4 . 5E pop esi
004026A5 . 64:890D 00000>mov dword ptr fs:[0], ecx
004026AC . 83C4 60 add esp, 60
004026AF . C3 retn
这里我们用资源工具PE Explorer打开CM来看看!我们里可以发现CM资源里有ID为100的对话框。
而这个对话框中有两个ID分别为1005(Ox3ED)和1003(Ox3EB)的Static Text控件
如下:
100 DIALOGEX 0, 0, 167, 42, 0
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP
EXSTYLE WS_EX_STATICEDGE
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
FONT 9, "宋体"
{
ICON 128, -1, 67, 11, 20, 20
LTEXT "CrackMe 1.0 版", -1, 95, 7, 65, 8, SS_NOPREFIX
DEFPUSHBUTTON "确定", 1, 95, 21, 50, 14, WS_GROUP
LTEXT "注册失败", 1005, 20, 18, 37, 11, 0, WS_EX_TRANSPARENT
LTEXT "注册成功", 1003, 20, 18, 37, 11, 0, WS_EX_TRANSPARENT
}
我们再来看看CWnd::ShowWindow的nCmdShow参数(指定了窗口显示的状态)
当nCmdShow=0 时 状态值为SW_HIDE(隐藏窗口并激活另一窗口)
当nCmdShow=1 时 状态值为SW_SHOWNORMAL(激活并显示一个窗口。若窗口是最小化或最大化,则恢复到其原来的大小和位置)
到这里我们就知道,只要不让ID为1005(Ox3ED)的Static Text控件显示,而让ID为1003(Ox3EB)的Static Text控件显示,这样就可以达到爆破了。
所以我们回过头看call 00402350 和call 00402630 的代码,
0040240E |. 0FBE05 875340>movsx eax, byte ptr [405387] ;eax=[405387]
00402415 |. 0FBE15 535340>movsx edx, byte ptr [405353] ;edx=[405353]
0040241C 2BD0 sub edx, eax ;edx=edx-eax
0040241E 52 push edx ;这个edx要为0(现在明白上面的改法作用了吧)
0040241F |. 68 ED030000 push 3ED ;ID为1005(Ox3ED)的Static Text控件
00402424 |. E8 A1140000 call <jmp.&MFC42.#CWnd::GetDlgItem_30>
00402429 |. 8BC8 mov ecx, eax
0040242B |. E8 94140000 call <jmp.&MFC42.#CWnd::ShowWindow_62>
................................................................................................................
00402666 . 0FBE05 865340>movsx eax, byte ptr [405386] ;eax=[405386]
0040266D . 0FBE0D 525340>movsx ecx, byte ptr [405352] ;ecx=[405352]
00402674 . 2BC8 sub ecx, eax ;ecx=ecx-eax
00402676 . F7D9 neg ecx ;ecx=neg ecx
00402678 1BC9 sbb ecx, ecx ;ecx=ecx sbb ecx
0040267A . 41 inc ecx ;ecx=ecx+1
0040267B . 51 push ecx ;这个ecx要为1(现在明白上面的改法作用了吧)
0040267C . 68 EB030000 push 3EB ;ID为1003(Ox3ED)的Static Text控件
00402681 . 8BCE mov ecx, esi
00402683 . E8 42120000 call <jmp.&MFC42.#CWnd::GetDlgItem_30>
00402688 . 8BC8 mov ecx, eax
0040268A . E8 35120000 call <jmp.&MFC42.#CWnd::ShowWindow_62>
至此CM的爆破分析第一部份就完成了.经下面的方法改动后,保存为CrackMe_CR.exe文件后,继续第二部份.
004020A7 83F8 06 cmp eax, 6 ;这里改cmp eax,0
004020BF 83FA 06 cmp edx, 6 ;这里改cmp edx,0
0040213E BE 01000000 mov esi, 1 ;这里改mov esi,0
004021C2 83F9 20 cmp ecx, 20 ;这里改cmp ecx,0
0040261D 74 04 je short 00402623 ;这里改jmp short 00402623
004025EE /75 09 jnz short 004025F9 ;这里改jmp short 004025F9
0040236B /0F87 92000000 ja 00402403 ;这里改jmp 0040240E
0040241C 2BD0 sub edx, eax ;这里改xor edx,edx
00402664 /75 29 jnz short 0040268F ;这里改nop 掉
00402678 1BC9 sbb ecx, ecx ;这里改xor ecx,ecx
第二部份:
CM要校验自身程序代码完整性!校验的HASH值作为二进制值存放到CrackMe.Atom中.
我们上面已经将程序代码改动了,这样CM的HASH值就发生了变化,所以我们必须将改
动后的HASH值替换CrackMe.Atom原来的值.那怎么做呢?
OD载入CrackMe_CR.exe文件.
CTRL+G 输入401C60 ,回车后来到这里.(
00401C60 . 64:A1 0000000>mov eax, dword ptr fs:[0] ;校验代码HASH值开始(此处的原理我就不分析了)
00401DDF . E8 2C140000 call 00403210 ;这个就是计算CM程序代码HASH值的CALL
00401DE4 . 8D7C24 30 lea edi, dword ptr [esp+30] ;下断,F9执行后。查看一下13f5e0-13f5f0地址里的值
以下的二进制就是CrackMe_CR.exe文件代码的HASH值
0013F5E0 AF FB 35 57 9F 37 8E B6 1B B6 5E 06 2C 90 82 1C ?5W?幎禴,悅
0013F5F0 00 .
以下的二进制就是CrackMe.Atom文件里存放的HASH值
.
0013F600 1F F5 35 57 9A 9E 8E B6 03 BC 5E E0 4B 77 F8 1B ?W殲幎糬郖w?
0013F610 00 .
将13f5f0-13f5f0间的值替换CrackMe.Atom文件的值,保存即可. 到此此CM的爆破分析就完成了。谢谢观看!
[ 本帖最后由 hflywolf 于 2009-9-10 02:40 编辑 ] |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?加入我们
x
评分
-
查看全部评分
|