【破文标题】对“经典的重启验证CrackMe”的分析
【下载地址】附件:StartupCrackMe.rar
【破解工具】OD、winhex、windows自带计算器
【保护方式】序号.重起验证
【任 务】练习硬件中断的使用,对sn多重内存复制的跟踪
【破文作者】mirrormask
【破解声明】我没什么经验,那位大虾有更好的方法请教育我!
【破解平台】 win2000 sp4
【时 间】2005-2-21
【破解过程】
原作地址:http://bbs.pediy.com/showthread.php?s=&threadid=10790
看到这个crackme有几天了,正如作者所说,真的是“经典的重启验证CrackMe”!!,
keyfile和读入过程没办法更简单了。可是,对于我来说以后的过程让人头晕,还是挺过来了,唉
通过这个练习可以熟练硬件中断的使用(内存断点也可以用,只不过不容易控制),希望大家
一起进步
打开随便填入sn : mht12345后,确定,退出,桌面出现CodeInfo.data文件,内容是
[CrackMe]
Code=mht12345
在od中载入程序,下readfile断点(ctr-n,找到readfile函数)。共三个,全部下断点。
f9运行中断
00420137 |. 6A 00 PUSH 0
00420139 |. 50 PUSH EAX
0042013A |. 8B07 MOV EAX,DWORD PTR DS:[EDI]
0042013C |. FF75 10 PUSH DWORD PTR SS:[EBP+10]
0042013F |. 52 PUSH EDX
00420140 |. FF3430 PUSH DWORD PTR DS:[EAX+ESI]
00420143 |. FF15 A0214400 CALL DWORD PTR DS:[<&KERNEL32.ReadFile>] ;ReadFile
注意buffer的内容(follow in dump),f8运行,buffer内容改变为
01187038 5B 43 72 61 63 6B 4D 65 [CrackMe
01187040 5D 0D 0A 43 6F 64 65 3D ]..Code=
01187048 6D 68 74 31 32 33 34 35 mht12345
CodeInfo.data注册文件的内容都在这。清除所有断点,
在‘m'位置(1187048)下硬件访问断点(byte)。f9运行,中断:
0041552D |. 0FB638 MOVZX EDI,BYTE PTR DS:[EAX]:
00415530 |. 40 INC EAX 断在这里,[1187038]-〉edi
00415531 |. 8906 MOV DWORD PTR DS:[ESI],EAX
00415533 |. EB 09 JMP SHORT 1.0041553E
00415535 |> 56 PUSH ESI
00415536 |. E8 8B6B0000 CALL 1.0041C0C6
0041553B |. 59 POP ECX
0041553C |. 8BF8 MOV EDI,EAX
0041553E |> 56 PUSH ESI
0041553F |. E8 60530000 CALL 1.0041A8A4 不要进入(我进去无数遍后,没用)
00415544 |. 59 POP ECX
00415545 |. 8BC7 MOV EAX,EDI ;’m'从edi-〉eax
00415547 |. 5F POP EDI
00415548 |. 5E POP ESI
edi中放着sn的第一个字母m,好的,看看edi要藏到哪里?
00415545 |. 8BC7 MOV EAX,EDI
狡猾~~接着跟踪eax,小可爱快出来~~~
f8,寻找语句对eax操作,不急,不急...很快
0040A589 . 8845 00 MOV BYTE PTR SS:[EBP],AL
出现了!!此时ebp==01185A20,在这句下f2断点,等sn一一复制进入ebp,
follow in dump:
01185A10 5B 43 72 61 63 6B 4D 65 [CrackMe
01185A18 5D 0D 0A 43 6F 64 65 3D ]..Code=
01185A20 6D 68 74 31 32 33 34 35 mht12345
清除硬件断点,清除所有断点,在1185a20‘m'位置下硬件断点。f9运行,中断
00404166 |. 8A1C02 |MOV BL,BYTE PTR DS:[EDX+EAX](停在下一个语句)
EDX+EAX==01185A20,把01185A20的那个字节放到bl。
bl又去哪里呢?慢慢看....,跟踪操作bl的语句
004041E6 |. 0FBEC3 |MOVSX EAX,BL 这句之后,eax存放着‘m'
004041E9 |. 03CA |ADD ECX,EDX
004041EB |. 8AE0 |MOV AH,AL 耍花招!!
004041ED |. 8801 |MOV BYTE PTR DS:[ECX],AL sn的去向!!下f2断点
ecx==11859ce,在4041ed下f2断点,f9,等sn全部拷入这段内存后,follow in dump:
011859C6 18 00 00 43 6F 64 65 3D ..Code=
011859CE 6D 68 74 31 32 33 34 35 mht12345
在搞什么药!!复制这么多做什么!!
清除所有断点,在11859ce(‘m')下硬件断点,f9,中断
0041535A |> \8B0A MOV ECX,DWORD PTR DS:[EDX]
0041535C |. 33CB |XOR ECX,EBX
0041535E |. BF FFFEFE7E |MOV EDI,7EFEFEFF
00415363 |. 03F9 |ADD EDI,ECX
00415365 |. 83F1 FF |XOR ECX,FFFFFFFF
00415368 |. 33CF |XOR ECX,EDI
0041536A |. 83C2 04 |ADD EDX,4
0041536D |. 81E1 00010181 |AND ECX,81010100
00415373 |.^ 74 E0 |JE SHORT 1.00415355
00415375 |. 8B4A FC |MOV ECX,DWORD PTR DS:[EDX-4]
00415378 |. 32CB |XOR CL,BL
0041537A |. 74 23 |JE SHORT 1.0041539F
0041537C |. 32EB |XOR CH,BL
0041537E |. 74 19 |JE SHORT 1.00415399
00415380 |. C1E9 10 |SHR ECX,10
00415383 |. 32CB |XOR CL,BL
00415385 |. 74 0C |JE SHORT 1.00415393
00415387 |. 32EB |XOR CH,BL
00415389 |. 74 02 |JE SHORT 1.0041538D
0041538B |.^ EB C8 \JMP SHORT 1.00415355
此处判断字符串是否到结尾,继续,第三次中断时,到这里
00401C24 |. F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
00401C26 |. 8BC8 MOV ECX,EAX
00401C28 |. 83E1 03 AND ECX,3
00401C2B |. F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
00401C2D |. 8B4D 04 MOV ECX,DWORD PTR SS:[EBP+4]
[edi]中存放复制进来的sn,执行到401c2d,edi-〉follow in dump,向上看
01185E2D 07 18 00 00 43 6F 64 65 ..Code
01185E35 3D 6D 68 74 31 32 33 34 =mht1234
01185E3D 35 5
清除所有断点,在1185e36下硬件断点,中断~~然后,谢谢你看到这里,跟飞了~~~~
看来sn在某一个地址被读取(访问)了多次,我们只跟踪了一次,因为清除了断点,
在该地址的第二次访问没有被断下
总结:找到sn存放地址后,下硬件中断,看看在程序领空被中断几次,然后分别进行跟踪
下面是跟踪结果:
内存中某一位置的sn被访问几次(提到的命令把sn在内存之间进行拷贝,按执行顺序排列):
命令地址 sn内存地址
readfile--〉01187048,只访问一次,
40a589--〉 01185A20,只访问一次,
4041ed-〉 011859CE ,访问两次
1、401c24->1185e5e 只一次
401c24――〉1185e36 跟飞了...~~~
2、401c24->1185dbe 只一次(下硬件访问断点后,f9继续 )
414734--〉 1185db9 只一次
405615--〉 1185fa9 只一次
4032b8--〉 12fba0 最后一次复制动作,以后所有比较都取此处的sn
在12fba0下内存断点,f9,中断:
004031AF . F2:AE REPNE SCAS BYTE PTR ES:[EDI] :中断在这里,求sn长度 ; 计算sn长度
004031B1 . F7D1 NOT ECX
004031B3 . 49 DEC ECX :ecx中是sn长度
004031B4 . 5F POP EDI
004031B5 . 83F9 02 CMP ECX,2 ; 比较字符串长度
004031B8 . 76 36 JBE SHORT StartupC.004031F0 :长度<=2 就跳走
004031BA . 807C24 00 30 CMP BYTE PTR SS:[ESP],30 ; sn 第一位是0?
004031BF . 75 2F JNZ SHORT StartupC.004031F0
004031C1 . 807C24 01 78 CMP BYTE PTR SS:[ESP+1],78 ; sn 第2位是x?
004031C6 . 75 28 JNZ SHORT StartupC.004031F0
这里有三个判断,都跳到004031F0。有点让人疑惑(一直都疑惑~~),经多次此实验,
不用理睬,可以跳过
硬件中断到这里:
00415273 |> /833D 280B4500>/CMP DWORD PTR DS:[450B28],1
0041527A |. |7E 0C |JLE SHORT StartupC.00415288
0041527C |. |6A 04 |PUSH 4
0041527E |. |56 |PUSH ESI
0041527F |. |E8 4D6B0000 |CALL StartupC.0041BDD1
00415284 |. |59 |POP ECX
00415285 |. |59 |POP ECX
00415286 |. |EB 0B |JMP SHORT StartupC.00415293
00415288 |> |A1 1C094500 |MOV EAX,DWORD PTR DS:[45091C] ;dump看一下
0041528D |. |8A0470 |MOV AL,BYTE PTR DS:[EAX+ESI*2] 中断在这里
00415290 |. |83E0 04 |AND EAX,4 sn第一位是0~9吗?
00415293 |> |85C0 |TEST EAX,EAX
00415295 |. |74 0D |JE SHORT StartupC.004152A4
00415297 |. |8D049B |LEA EAX,DWORD PTR DS:[EBX+EBX*4] ; ebx*5->eax
0041529A |. |8D5C46 D0 |LEA EBX,DWORD PTR DS:[ESI+EAX*2-30] ; eax*2+sn-30
0041529E |. |0FB637 |MOVZX ESI,BYTE PTR DS:[EDI] ; 下一位sn
004152A1 |. |47 |INC EDI
004152A2 |.^\EB CF \JMP SHORT StartupC.00415273 :循环
[45091C]==450926,下面是 450926的内容:
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00450920 20 00 20 00 20 00 20 00 20 00 .. . . . . .
00450930 20 00 20 00 20 00 20 00 28 00 28 00 28 00 28 00 . . . .(.(.(.(.
00450940 28 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 (. . . . . . . .
00450950 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 . . . . . . . .
00450960 20 00 20 00 20 00 48 00 10 00 10 00 10 00 10 00 . . .H.........
sn==20 21(!}
00450970 10 00 10 00 10 00 10 00 10 00 10 00 10 00 10 00 ................
00450980 10 00 10 00 10 00 84 00 84 00 84 00 84 00 84 00 ......?????
sn==30(0)
00450990 84 00 84 00 84 00 84 00 84 00 10 00 10 00 10 00 ?????......
39 3a (:)
004509A0 10 00 10 00 10 00 10 00 81 00 81 00 81 00 81 00 ........????
41(A)
004509B0 81 00 81 00 01 00 01 00 01 00 01 00 01 00 01 00 ??............
47(G)
004509C0 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 ................
004509D0 01 00 01 00 01 00 01 00 01 00 01 00 10 00 10 00 ................
Z 5b
004509E0 10 00 10 00 10 00 10 00 82 00 82 00 82 00 82 00 ........????
61(a)
004509F0 82 00 82 00 02 00 02 00 02 00 02 00 02 00 02 00 ??............
67(g)
00450A00 02 00 02 00 02 00 02 00 02 00 02 00 02 00 02 00 ................
00450A10 02 00 02 00 02 00 02 00 02 00 02 00 10 00 10 00 ................
z 7b
00450A20 10 00 10 00 20
7f
[EAX+ESI*2] 计算出sn的每一位*2之后落在上面那表的什么位置,
表中标示了几个明显分界点的sn的数值,可以看出,如果sn[0]是数字的话,
会落在[EAX+ESI*2]==84的位置。我们改变内存内容:
12fba0:"mht1"-――>"1231",不修改可能也行,少循环几次,不过以后跟踪标志不明显
然后进入循环,
ebx*5->eax
eax*2+sn-30――>ebx
sn计算后的结果sn’放入ebx
循环结束后到这里
004152A7 |. 8BC3 MOV EAX,EBX ; 计算结果sn’从ebx->eax
继续f8追踪eax的去向,没几次就到这里:
00403204 . 8901 MOV DWORD PTR DS:[ECX],EAX ; 计算结果sn’从eax->[ecx],
ecx==00454410,清除所有断点,在此处下硬件断点,f9,中断:
00402CCD . 8B07 MOV EAX,DWORD PTR DS:[EDI] ; sn’放入eax
00402CCF . 8B4C24 4C MOV ECX,DWORD PTR SS:[ESP+4C] 中断在这里
00402CD3 . 8D0440 LEA EAX,DWORD PTR DS:[EAX+EAX*2] ; sn’*3
00402CD6 . 8907 MOV DWORD PTR DS:[EDI],EAX ; sn’->[edi]
继续f9,中断:
00402BD0 . 8B41 18 MOV EAX,DWORD PTR DS:[ECX+18] ; 读sn’
00402BD3 . 33C9 XOR ECX,ECX ;
00402BD5 . 99 CDQ
00402BD6 . 2BC2 SUB EAX,EDX
00402BD8 . D1F8 SAR EAX,1 sn’算术右移1位
00402BDA . 3D C0810100 CMP EAX,181C0 sn’==181c0?
00402BDF . 0F94C1 SETE CL cl=1 if(zf==1)
00402BE2 . 8BC1 MOV EAX,ECX cl--》eax
00402BE4 . C3 RETN
好像要出结果!!!f8返回
00401918 . 85C0 TEST EAX,EAX ; 关键比较
0040191A . 74 07 JE SHORT StartupC.00401923 ; eax==0,转移
0040191C . 8BCE MOV ECX,ESI
0040191E . E8 0DFDFFFF CALL StartupC.00401630
00401923 > C705 D8434500>MOV DWORD PTR DS:[4543D8],1
0040192D > 5E POP ESI
0040192E . C3 RETN
此时把0040191A 语句nop掉,则注册成功!!
另一种情况:sn的前两位是0x的话(前面提到过)
12fba0中断后回到达:
0041BBE7 |> \A1 1C094500 ||MOV EAX,DWORD PTR DS:[45091C]
0041BBEC |. 8A0458 ||MOV AL,BYTE PTR DS:[EAX+EBX*2] ;sn[2]落在哪里
0041BBEF |. 25 80000000 ||AND EAX,80 ;eax第8位是否是一
0041BBF4 |> 85C0 ||TEST EAX,EAX
0041BBF6 |. 74 37 ||JE SHORT StartupC.0041BC2F
.....后面还有一系列计算,很容易
注册算法:
sal 181C0,1== 00030380或者30381
30381/3=1012b
30380/3有余数,放弃
1、sn是数字
ebx=ebx*10+sn[i]-30
一元i次方程,不会解!!穷举
2、sn是0x****的形式(见注册机)
注册机源码(c,穷举):
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int k,i,j;
long int r=0;
char sn[5];
for(k=100;k<99999;k++)
{
itoa(k, sn, 10);
for(i=0;i<6;i++)
{
if (sn[i]==0)break;
r=r*10+sn[i]-0x30;
}
if(r==0x1012b)printf("sn is: %s\n",sn);
r=0;
}
for(k=0x0;k<0xfffff;k++)
{
itoa(k, sn, 16);
for(i=0;i<6;i++)
{
if (sn[i]==0)break;
if((sn[i] >= 0x30) && (sn[i]<=0x39))
r=sn[i]-0x30+r*16;
else
r=(sn[i]-0x27-0x30)+r*16;
}
if(r==0x1012b)
{
printf("sn is: 0x%s\n",sn);
for (j=0; j<i; j++)
{
sn[j] = toupper(sn[j]);
}
printf("sn is: 0x%s\n",sn);
}
r=0;
}
return 0;
}
完毕,共耗时36小时以上
多谢看学学院:)
多谢观赏,跟贴指教:)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课