接 xx学OD -- 内存断点(上)
0040140C /$ 60 PUSHAD
0040140D |. 6A 00 PUSH 0 ; /RootPathName = NULL
0040140F |. E8 B4000000 CALL <JMP.&KERNEL32.GetDriveTypeA> ; \
:调用GetDriveTypeA得到本程序所在的盘的类型 放入eax中这里是03
00401414 |. A2 EC334000 MOV BYTE PTR DS:[4033EC],Al 知道刚才的03怎么来的了
00401419 |. 6A 00 PUSH 0 ; /pFileSystemNameSize = NULL
0040141B |. 6A 00 PUSH 0 ; |pFileSystemNameBuffer = NULL
0040141D |. 6A 00 PUSH 0 ; |pFileSystemFlags = NULL
0040141F |. 6A 00 PUSH 0 ; |pMaxFilenameLength = NULL
00401421 |. 6A 00 PUSH 0 ; |pVolumeSerialNumber = NULL
00401423 |. 6A 0B PUSH 0B ; |MaxVolumeNameSize = B (11.)
00401425 |.689C334000PUSHCrackHea.0040339C |VolumeNameBuffer= CrackHea.0040339C
0040142A |. 6A 00 PUSH 0 ; |RootPathName = NULL
0040142C |. E8 A3000000 CALL <JMP.&KERNEL32.GetVolumeInformation>;
;调用GetVolumeInformationA函数获得该盘的卷标放入VolumeNameBuffer(40339C)中
00401431 |. 8D35 9C334000 LEAESI,DWORD PTR DS:[40339C]地址40339C送到ESI
00401437 |. 0FB60D EC3340> MOVZX ECX, BYTE PTR DS:[4033EC] 无符号扩展ECX=0000 0003
0040143E |. 33FF XOR EDI,EDI
00401440 |> 8BC1 MOV EAX,ECX
00401442 |. 8B1E MOV EBX, DWORD PTR DS:[ESI] 把卷标名作为数值送到EBX(584E4957)
00401444 |. F7E3 MUL EBX ; (EDX,EAX) = EAX*EBX
00401446 |. 03F8 ADD EDI,EAX 放到EDI中
00401448 |. 49 DEC ECX ;ECX-1
00401449 |. 83F9 00 CMP ECX,0 ;循环ECX(3次)
0040144C |.^ 75 F2 JNZ SHORT CrackHea.00401440
0040144E |. 893D 9C334000 MOV DWORD PTR DS:[40339C], EDI
把计算后值送回内存地址40339C, 这就是我们后来在ESI中看到的值
00401454 |. 61 POPAD
00401455 \. C3 RETN
分析到这可以得知基本算法是这样的:
先用GetDriveTypeA函数获取磁盘类型参数(参数为3),再用GetVolumeInformationA函数获取这个crackme程序所在分区的卷标。如这个Crackme程序放在桌面(C:\Documents and Settings\Administrator\桌面)而C盘设置的卷标是WINXP,则这里获取的就是 WINXP,
WINXP的ASCII码为“584E4957”。这里有一个问题,值得注意
原来在数据窗口中看到的地址40339C处的16进制代码是“57494E58”,即“WINXP”
但经过地址00401442处的那条MOV EBX, DWORD PTR DS:[ESI] 指令后,
却发现EBX中的值是“584E4957”,正好把我们上面那个“57494E58”反过来了。
指令MOV EBX,DWORD PTR DS:[ESI]等同于MOV EBX,DWORD PTR DS:[40339C]。
注意这里是DWORD,即“双字”,由4个连续的字节构成。而取地址为40339C的双字单元中的内容时,我们应该得到的是“584E4957”,即由高字节到低字节顺序的值。因此经过MOV EBX,DWORD PTR DS:[ESI]这条指令,就是把从地址40339C开始处的值送到EBX,所以我们得到了“584E4957”。
看算法:
取磁盘类型参数做循环次数,再取卷标值ASCII码的逆序作为数值,有了这两个值就开始计算了。现在我们把磁盘类型值作为n,卷标值ASCII码的逆序数值作为a,最后得出的结果作为b,有这样的计算过程:
第一次:b a * n
第二次:b a * (n - 1) + b
第三次:b a * (n - 2) + b
第n次:b a * 1 + b
可得出公式为b a * [n + (n - 1) + (n - 2) +…+ 1] a * [n * (n + 1) / 2]
记得在比较 0040132D |. 3BC6 CMP EAX, ESI 之前还有一句对ESI的操作。
00401405 |. 81F6 53757A79 XOR ESI, 797A7553即
这里算出来的b最后还要和797A7553H异或一下才是真正的注册码。
通过分析这个程序的算法,我们发现这个注册算法是有漏洞的。如果我的分区没有卷标的话,则卷标值为0,最后的注册码就是797A7553H,即十进制2038068563。而如果你的卷标和我一样,且磁盘类型一样的话,注册码也会一样,并不能真正做到一机一码。
内存断点简单加密算法 取硬盘信息去操作。。