PEDIYCrackme竞赛2009-(Atom队-CrackMe)爆破分析
【标题】: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 , 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
004020A4|.8B41 F8 mov eax, dword ptr
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
004020BC|.8B52 F8 mov edx, dword ptr
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
004020E6|.8B48 F8 mov ecx, dword ptr
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
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:
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
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:
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
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 ;取上面保存的初始时间的运算值
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:
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
004021CA|.50 push eax
004021CB|.51 push ecx
004021CC|.E9 2B010000 jmp 004022FC ;小于跳走
加密name和Serial的字符串
004021D1|>8B53 64 mov edx, dword ptr
004021D4|.8D4D E4 lea ecx, dword ptr
004021D7|.8B42 F8 mov eax, dword ptr
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 ; |
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 ; |
00402220|.E8 1B0F0000 call 00403140 ; \CrackMe1.00403140
; 将Serial字符串加密
校验name和Serial加密后的字符串
00402225|.0FBE05 695340>movsx eax, byte ptr ;EAX=Serial加密后第二个字符的ASCII值
0040222C|.0FBE0D 685340>movsx ecx, byte ptr ;ECX=Serial加密后第一个字符的ASCII值
00402233|.0FBE15 355340>movsx edx, byte ptr ;EDX=name加密后第二个字符的ASCII值
0040223A|.50 push eax ;保存EAX
0040223B|.51 push ecx ;保存ECX
0040223C|.0FBE05 345340>movsx eax, byte ptr ;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 ;
0040224A|.E8 21F1FFFF call 00401370 ;关键CALL(时间关系不看了)
................................................................................................................
0040227D|.0FBE0D 6A5340>movsx ecx, byte ptr ;ECX=Serial加密后第三个字符的ASCII值
00402284|.0FBE15 375340>movsx edx, byte ptr ;EDX=name加密后第四个字符的ASCII值
0040228B|.0FBE05 365340>movsx eax, byte ptr ;EAX=name加密后第三个字符的ASCII值
00402292|.6A 00 push 0 ;Arg6 = 00000000
00402294|.51 push ecx ;保存ECX
00402295|.0FBE0D 005340>movsx ecx, byte ptr ;ECX=byte ptr (这个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 ;
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
00402354 56 push esi
00402355 0FBE90 685340>movsx edx, byte ptr
0040235C|.0FBEB0 345340>movsx esi, byte ptr
00402363|.2BF2 sub esi, edx
00402365|.8D56 02 lea edx, dword ptr
00402368|.83FA 0A cmp edx, 0A
0040236B 0F87 92000000 ja 00402403 ;这里直接改成jmp 0040240E
00402371|>FF2495 4C2440>/jmp dword ptr ;以下循环时间关系不分析了
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 ;上面跳来这里
00402415|.0FBE15 535340>movsx edx, byte ptr
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
00402437|.0FBE0D 755340>movsx ecx, byte ptr
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:
0040263D .50 push eax
0040263E .64:8925 00000>mov dword ptr fs:, 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
00402650 .E8 4B120000 call <jmp.&MFC42.#CPaintDC::CPaintDC_>
00402655 .A0 00534000 mov al, byte ptr ;al=(这个405300地址是个关键)
0040265A .C74424 60 000>mov dword ptr , 0
00402662 .3C 61 cmp al, 61
00402664 75 29 jnz short 0040268F ;这里不能跳,NOP掉
00402666 .0FBE05 865340>movsx eax, byte ptr
0040266D .0FBE0D 525340>movsx ecx, byte ptr
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
00402693 .C74424 60 FFF>mov dword ptr , -1
0040269B .E8 FA110000 call <jmp.&MFC42.#CPaintDC::~CPaintDC>
004026A0 .8B4C24 58 mov ecx, dword ptr
004026A4 .5E pop esi
004026A5 .64:890D 00000>mov dword ptr fs:, 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 ;eax=
00402415|.0FBE15 535340>movsx edx, byte ptr ;edx=
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 ;eax=
0040266D .0FBE0D 525340>movsx ecx, byte ptr ;ecx=
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: ;校验代码HASH值开始(此处的原理我就不分析了)
00401DDF .E8 2C140000 call 00403210 ;这个就是计算CM程序代码HASH值的CALL
00401DE4 .8D7C24 30 lea edi, dword ptr ;下断,F9执行后。查看一下13f5e0-13f5f0地址里的值
以下的二进制就是CrackMe_CR.exe文件代码的HASH值
0013F5E0AF FB 35 57 9F 37 8E B6 1B B6 5E 06 2C 90 82 1C?5W?幎禴,悅
0013F5F000 .
以下的二进制就是CrackMe.Atom文件里存放的HASH值
.
0013F6001F F5 35 57 9A 9E 8E B6 03 BC 5E E0 4B 77 F8 1B ?W殲幎糬郖w?
0013F61000 .
将13f5f0-13f5f0间的值替换CrackMe.Atom文件的值,保存即可. 到此此CM的爆破分析就完成了。谢谢观看!
[ 本帖最后由 hflywolf 于 2009-9-10 02:40 编辑 ] 占沙发学习 学习了 /:good 太强大了,这狼 膜拜老兄~~ 强人啊,支持一下 来看看,学习下,谢谢分享 :loveliness: 进来学习了,厉害 又一个属牛的狼 这个暴破点是够多的,狼真有耐心。
页:
[1]
2