之前(1)篇中大致介绍了mainCRTStartup,但是其中一些调用到的函数并未深究,现打算逐一剖析它们。
GetVersion函数是kernel32.dll中提供的API,用于获取当前Win平台的版本。准确的说,GetVersion可以获得3个信息:
1. OSPlatformId
2. OSBuildNumber
3. OSMinorVersion
4. OSMajorVersion
其中比较诡异的是OSPlatformId,在GetVersion的过程当中它被获得过,但是返回的时候又没了...所以只剩下2、3、4
可以用OD来跟进GetVersion:
mov eax, dword ptr fs:[18] mov ecx, dword ptr [eax+30] mov eax, dword ptr [ecx+B0] // 获取 OSPlatformId movzx edx, word ptr [ecx+AC] // 获取 OSBuildNumber xor eax, FFFFFFFE shl eax, 0E // 几次左移,把OSPlatformId的信息给移没了... or eax, edx shl eax, 8 or eax, dword ptr [ecx+A8] // 获取 OSMinorVersion shl eax, 8 or eax, dword ptr [ecx+A4] // 获取 OSMajorVersion retn
GetVersion主要是去PEB(Process Environment Block)结构中访问当前的OS信息,每个进程都会有自己独立的PEB。想要获取当前进程的PEB地址,首先要先访问TEB(Thread Environment Block )结构。因为TEB结构的30偏移量处中存放了PEB结构的指针。FS 寄存器指向了当前活动线程的TEB结构,其中偏移位置18表示了FS 段寄存器在内存中的镜像地址。
因此
mov eax, dword ptr fs:[18]
mov ecx, dword ptr [eax+30]
两句表示根据TEB获取PEB的指针,并且存放在ECX中。拿到PEB的指针后,就可以去PEB中拿OS的信息。
PEB结构中关于OS信息的偏移量如下:
如果是XP用户,那么GetVersion最终的返回值应该是:0A280105 。
其中 0A28表示XP build版本是2600,01表示OSMinorVersion,05表示OSMajorVersion 。
中间被忽略掉的 OSPlatformId 信息可以为:
VER_PLATFORM_WIN32s 或 0x0000,用于指定 Microsoft Windows 3.1。
VER_PLATFORM_WIN32_WINDOWS 或 0x0001,用于指定 Windows 95、Windows 98 或从其继承的操作系统。
VER_PLATFORM_WIN32_NT 或 0x0010,用于指定 Windows NT 或从其继承的操作系统。
另外,还有一些补充的OS信息如下:
(摘录自 http://msdn.microsoft.com/zh-cn/library/ms724833%28v=VS.85%29.aspx )
Operating system | Version number | dwMajorVersion | dwMinorVersion |
Windows 7 | 6.1 | 6 | 1 |
Windows Server 2008 R2 | 6.1 | 6 | 1 |
Windows Server 2008 | 6.0 | 6 | 0 |
Windows Vista | 6.0 | 6 | 0 |
Windows Server 2003 R2 | 5.2 | 5 | 2 |
Windows Home Server | 5.2 | 5 | 2 |
Windows Server 2003 | 5.2 | 5 | 2 |
Windows XP Professional x64 Edition | 5.2 | 5 | 2 |
Windows XP | 5.1 | 5 | 1 |
Windows 2000 | 5.0 | 5 | 0 |