龙人在线
about me

Arron

抛砖只为引玉(QQ长期隐身在线)
不能富贵难成大器皆因懒,
胸无大志庸庸碌碌只为闲。

这里是我平时收集的和写的一些东西,希望和大家一起共同进步!

无聊看看电影 边听音乐边看 有空多交流
Google_search
Google
hot
latest
photos
还你真实的开幕式!震撼美图[转]【连载】 央行今日发行600万张面额10元奥运纪念钞(组图) 巧遇日本妹妹海滩拍片片 诱不可挡超级丰胸大美人
links
龙人在线 >> 学习资料 >> 破解教程 >> OllyDBG 入门系列(四)-内存断点(2)

OllyDBG 入门系列(四)-内存断点(2)

来源:看雪精华帖 作者:不详 日期:2010-06-23 热度:

0040140C /$ 60                 PUSHAD
0040140D |. 6A 00              PUSH                                      /RootPathName NULL
0040140F |. E8 B4000000        CALL <JMP.&KERNEL32.GetDriveTypeA>          \GetDriveTypeA
00401414 |. A2 EC334000        MOV BYTE PTR DS:[4033EC],AL                 磁盘类型参数送内存地址4033EC
00401419 |. 6A 00              PUSH                                      /pFileSystemNameSize NULL
0040141B |. 6A 00              PUSH                                      |pFileSystemNameBuffer NULL
0040141D |. 6A 00              PUSH                                      |pFileSystemFlags NULL
0040141F |. 6A 00              PUSH                                      |pMaxFilenameLength NULL
00401421 |. 6A 00              PUSH                                      |pVolumeSerialNumber NULL
00401423 |. 6A 0B              PUSH 0B                                     |MaxVolumeNameSize (11.)
00401425 |. 68 9C334000        PUSH CrackHea.0040339C                      |VolumeNameBuffer CrackHea.0040339C
0040142A |. 6A 00              PUSH                                      |RootPathName NULL
0040142C |. E8 A3000000        CALL <JMP.&KERNEL32.GetVolumeInformationA>  \GetVolumeInformationA
00401431 |. 8D35 9C334000      LEA ESI,DWORD PTR DS:[40339C]               把crackme程序所在分区的卷标名称送到ESI
00401437 |. 0FB60D EC334000    MOVZX ECX,BYTE PTR DS:[4033EC]              磁盘类型参数送ECX
0040143E |. 33FF               XOR EDI,EDI                                 把EDI清零
00401440 |> 8BC1               MOV EAX,ECX                                 磁盘类型参数送EAX
00401442 |. 8B1E               MOV EBX,DWORD PTR DS:[ESI]                  把卷标名作为数值送到 EBX
00401444 |. F7E3               MUL EBX                                     循环递减取磁盘类型参数值与卷标名值相乘
00401446 |. 03F8               ADD EDI,EAX                                 每次计算结果再加上上次计算结果保存在EDI中
00401448 |. 49                 DEC ECX                                     把磁盘类型参数作为循环次数,依次递减
00401449 |. 83F9 00            CMP ECX,0                                   判断是否计算完
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 函数获取磁盘类型参数,再用 GetVolumeInformationA 函数获取这个 crackme 程序所在分区的卷标。如我把这个 Crackme 程序放在 F:\OD教程\crackhead\ 目录下,而我 盘设置的卷标是 GAME,则这里获取的就是 GAME,ASCII 码为“47414D45”。但我们发现一个问题:假如原来我们在数据窗口中看到的地址 40339C 处的 16 进制代码是“47414D45”,即“GAME”,但经过地址 00401442 处的那条 MOV EBX,DWORD PTR DS:[ESI] 指令后,我们却发现 EBX 中的值是“454D4147”,正好把我们上面那个“47414D45”反过来了。为什么会这样呢?如果大家对 x86系列 CPU 的存储方式了解的话,这里就容易理解了。我们知道“GAME”有四个字节,即 ASCII 码为“47414D45”。我们看一下数据窗口中的情况:

0040339C     47 41 4D 45 00 00 00 00 00 00 00 00 00 00 00 00     GAME............

大家可以看出来内存地址 40339CH 到 40339FH 分别按顺序存放的是 47 41 4D 45。
如下图:
/up_files/image/Article/2010/06/23/34695171.gif  
系统存储的原则为“高高低低”,即低字节存放在地址较低的字节单元中,高字节存放在地址较高的字节单元中。比如一个字由两个字节组成,像这样:12 34 ,这里的高字节就是 12 ,低字节就是 34。上面的那条指令 MOV EBX,DWORD PTR DS:[ESI] 等同于 MOV EBX,DWORD PTR DS:[40339C]。注意这里是 DWORD,即“双字”,由 个连续的字节构成。而取地址为 40339C 的双字单元中的内容时,我们应该得到的是“454D4147”,即由高字节到低字节顺序的值。因此经过 MOV EBX,DWORD PTR DS:[ESI] 这条指令,就是把从地址 40339C 开始处的值送到 EBX,所以我们得到了“454D4147”。好了,这里弄清楚了,我们再接着谈这个程序的算法。前面我们已经说了取磁盘类型参数做循环次数,再取卷标值 ASCII 码的逆序作为数值,有了这两个值就开始计算了。现在我们把磁盘类型值作为 n,卷标值 ASCII 码的逆序数值作为 a,最后得出的结果作为 b,有这样的计算过程:
第一次:b n
第二次:b (n 1) b
第三次:b (n 2) b

第 次:b b
可得出公式为 [n (n 1) (n 2) … 1] [n (n 1) 2]
还记得上一篇我们的分析吗?看这一句:

00401405 |. 81F6 53757A79     XOR ESI,797A7553                            把ESI中的值与797A7553H异或

这里算出来的 最后还要和 797A7553H 异或一下才是真正的注册码。只要你对编程有所了解,这个注册机就很好写了。如果用汇编来写这个注册机的话就更简单了,很多内容可以直接照抄。
到此已经差不多了,最后还有几个东西也说一下吧:
1、上面用到了两个 API 函数,一个是 GetDriveTypeA,还有一个是 GetVolumeInformationA,关于这两个函数的具体用法我就不多说了,大家可以查一下 MSDN。这里只要大家注意函数参数传递的次序,即调用约定。先看一下这里:

00401419 |. 6A 00              PUSH                                      /pFileSystemNameSize NULL
0040141B |. 6A 00              PUSH                                      |pFileSystemNameBuffer NULL
0040141D |. 6A 00              PUSH                                      |pFileSystemFlags NULL
0040141F |. 6A 00              PUSH                                      |pMaxFilenameLength NULL
00401421 |. 6A 00              PUSH                                      |pVolumeSerialNumber NULL
00401423 |. 6A 0B              PUSH 0B                                     |MaxVolumeNameSize (11.)
00401425 |. 68 9C334000        PUSH CrackHea.0040339C                      |VolumeNameBuffer CrackHea.0040339C
0040142A |. 6A 00              PUSH                                      |RootPathName NULL
0040142C |. E8 A3000000        CALL <JMP.&KERNEL32.GetVolumeInformationA>  \GetVolumeInformationA

把上面代码后的 OllyDBG 自动添加的注释与 MSDN 中的函数原型比较一下:
BOOL GetVolumeInformation(
LPCTSTR lpRootPathName,             // address of root directory of the file system
LPTSTR lpVolumeNameBuffer,          // address of name of the volume
DWORD nVolumeNameSize,              // length of lpVolumeNameBuffer
LPDWORD lpVolumeSerialNumber,       // address of volume serial number
LPDWORD lpMaximumComponentLength,   // address of system's maximum filename length
LPDWORD lpFileSystemFlags,          // address of file system flags
LPTSTR lpFileSystemNameBuffer,      // address of name of file system
DWORD nFileSystemNameSize           // length of lpFileSystemNameBuffer
);

大家应该看出来点什么了吧?函数调用是先把最后一个参数压栈,参数压栈顺序是从后往前。这就是一般比较常见的 stdcall 调用约定。
2、我在前面的 00401414 地址处的那条 MOV BYTE PTR DS:[4033EC],AL 指令后加的注释是“磁盘类型参数送内存地址4033EC”。为什么这样写?大家把前一句和这一句合起来看一下:

0040140F |. E8 B4000000        CALL <JMP.&KERNEL32.GetDriveTypeA>          \GetDriveTypeA
00401414 |. A2 EC334000        MOV BYTE PTR DS:[4033EC],AL                 磁盘类型参数送内存地址4033EC

地址 0040140F 处的那条指令是调用 GetDriveTypeA 函数,一般函数调用后的返回值都保存在 EAX 中,所以地址 00401414 处的那一句 MOV BYTE PTR DS:[4033EC],AL 就是传递返回值。查一下 MSDN 可以知道 GetDriveTypeA 函数的返回值有这几个:

Value                     Meaning                                        返回在EAX中的值
DRIVE_UNKNOWN             The drive type cannot be determined.               0
DRIVE_NO_ROOT_DIR         The root directory does not exist.                 1
DRIVE_REMOVABLE           The disk can be removed from the drive.            2
DRIVE_FIXED               The disk cannot be removed from the drive.         3
DRIVE_REMOTE              The drive is remote (network) drive.             4
DRIVE_CDROM               The drive is CD-ROM drive.                       5
DRIVE_RAMDISK             The drive is RAM disk.                           6

上面那个“返回在EAX中的值”是我加的,我这里返回的是 3,即磁盘不可从驱动器上删除。
3、通过分析这个程序的算法,我们发现这个注册算法是有漏洞的。如果我的分区没有卷标的话,则卷标值为 0,最后的注册码就是 797A7553H,即十进制 2038068563。而如果你的卷标和我一样,且磁盘类型一样的话,注册码也会一样,并不能真正做到一机一码。
 

Tags: AD
广告位招租,广告代号:gg468
search
站内
advertise
Copyright © www.jx19.Com All rights reserved.