有许多方法,我比较喜欢使用的是:
NtQuerySystemInformation函数,其中SystemBasicInformation(0号功能)返回的结果是一个SYSTEM_BASIC_INFORMATION结构,其中的域bKeNumberProcessors将返回系统CPU的个数。
下面是该函数的具体说明:
/×-------------------------------------------------------------
NtQuerySystemInformation is used to check some system informations
avaiable only in KernelMode (above 0x80000000).
All avaiable (or all known) information classes are described
in SYSTEM_INFORMATION_CLASS.
Requirements
Client: Requires Windows XP or Windows 2000 Professional.
Server: Requires Windows 2000 Server.
Header: Declared in Winternl.h.
DLL: Requires Ntdll.dll.
[NtQuerySystemInformation is available for use in Windows 2000 and
Windows XP. It may be altered or unavailable in subsequent versions.
Applications should use the alternate functions listed in this topic.]
*/
注:NtQuerySystemInformation底层使用中写为ZwQuerySystemInformation,两个函数完全相同,只是入口不同。
NTSYSAPI
NTSTATUS
NTAPI
NtQuerySystemInformation(
//SystemInformationClass
//[in] One of the values enumerated in SYSTEM_INFORMATION_CLASS,
//indicating the kind of system information to be retrieved.
IN SYSTEMINFOCLASS SystemInformationClass,
// SystemInformation
// [in, out] Points to a buffer where the requested information is
// to be returned. The size and structure of this information varies
// depending on the value of the SystemInformationClass parameter:
OUT PVOID pSystemInformation,
// SystemInformationLength
// [in] Size of the buffer pointed to by the SystemInformation parameter,
// in bytes.
IN ULONG uSystemInformationLength,
// ReturnLength
// [out, optional] Optional pointer to a location where the function
// writes the actual size of the information requested.
// If that size is less than or equal to the SystemInformationLength
// parameter, the function copies the information into the
// SystemInformation buffer; otherwise, it returns an NTSTATUS error code
// and returns in ReturnLength the size of buffer required to receive
// the requested information.
OUT PULONG puReturnLength OPTIONAL
);
// Return Values
// Returns an NTSTATUS success or error code.
// The forms and significance of NTSTATUS error codes are listed
// in the Ntstatus.h header file available in the Windows Device
// Driver Kit (DDK), and are described in the DDK documentation
// under Kernel-Mode Driver Architecture / Design Guide / Driver
// Programming Techniques / Logging Errors.
typedef enum _SYSTEMINFOCLASS
{
SystemBasicInformation, //0
SystemProcessorInformation, // 1
SystemPerformanceInformation, //2
SystemTimeOfDayInformation, //3
SystemPathInformation, //4 SystemNotImplemented1
SystemProcessInformation, //5 per process SystemProcessesAndThreadsInformation
SystemCallCountInformation, //6 SystemCallInformation
SystemConfigurationInformation, //7 SystemDeviceInformation
SystemProcessorPerformanceInformation, //8 per cpu SystemProcessorCounters
SystemGlobalFlag, //SystemFlagsInformation
SystemCallTimeInformation, //10
SystemModuleInformation, //11
SystemLockInformation, //12
SystemStackTraceInformation, //13 SystemNotImplemented2
SystemPagedPoolInformation, //14 checked build only
SystemNonPagedPoolInformation, //15 checked build only
SystemHandleInformation, //16
SystemObjectInformation, //17 SystemObjectTypeInformation
SystemPageFileInformation, //18 per page file
SystemVdmInstemulInformation, //19 SystemVdmInstemulInformation
SystemVdmBopInformation, //20
SystemFileCacheInformation, //21
SystemPoolTagInformation, //22
SystemInterruptInformation, //23
SystemDpcBehaviorInformation, //24
SystemFullMemoryInformation, //25 checked build only
SystemLoadGdiDriverInformation, //26 set mode only
SystemUnloadGdiDriverInformation, //27 set mode only
SystemTimeAdjustmentInformation, //28 writeable
SystemSummaryMemoryInformation, //29 checked build only
SystemNextEventIdInformation, //30 checked build only
SystemEventIdsInformation, //31 checked build only
SystemCrashDumpInformation, //32
SystemExceptionInformation, //33
SystemCrashDumpStateInformation, //34
SystemKernelDebuggerInformation, //35
SystemContextSwitchInformation, //36
SystemRegistryQuotaInformation, //37
SystemExtendServiceTableInformation, //38 set mode only SystemAddDriver
SystemPrioritySeperation, //39 set mode only SystemPrioritySeparationInformation
SystemPlugPlayBusInformation, //40 not implemented
SystemDockInformation, //41 not implemented
SystemPowerInformation, //42 XP only
SystemProcessorSpeedInformation, //43 XP only
SystemCurrentTimeZoneInformation, //44
SystemLookasideInformation, //45
SystemSetTimeSlipEvent, //46
SystemCreateSession, // set mode only
SystemDeleteSession, // set mode only
SystemInvalidInfoClass1, // invalid info class
SystemRangeStartInformation, // 0x0004 (fails if size != 4)
SystemVerifierInformation,
SystemAddVerifier,
SystemSessionProcessesInformation, // checked build only
MaxSystemInfoClass
} SYSTEMINFOCLASS, *PSYSTEMINFOCLASS;
typedef struct _SYSTEM_BASIC_INFORMATION
{
DWORD dwUnknown1; // 0
ULONG uKeMaximumIncrement; // x86: 0x0002625A or 0x00018730
ULONG uPageSize; // bytes
ULONG uMmNumberOfPhysicalPages;
ULONG uMmLowestPhysicalPage;
ULONG uMmHighestPhysicalPage;
ULONG uAllocationGranularity; // bytes
PVOID pLowestUserAddress;
PVOID pMmHighestUserAddress;
KAFFINITY uKeActiveProcessors;
BYTE bKeNumberProcessors;
BYTE bUnknown2;
WORD wUnknown3;
} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;
typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
{
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER DpcTime;
LARGE_INTEGER InterruptTime;
DWORD InterruptCount;
DWORD dwUnknown1;
} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
typedef struct _SYSTEM_PERFORMANCE_INFORMATION
{
LARGE_INTEGER liIdleTime;
LARGE_INTEGER IoReadTransferCount;
LARGE_INTEGER IoWriteTransferCount;
LARGE_INTEGER IoOtherTransferCount;
ULONG IoReadOperationCount;
ULONG IoWriteOperationCount;
ULONG IoOtherOperationCount;
ULONG AvailablePages;
ULONG CommittedPages;
ULONG CommitLimit;
ULONG PeakCommitment;
ULONG PageFaultCount;
ULONG CopyOnWriteCount;
ULONG TransitionCount;
ULONG CacheTransitionCount;
ULONG DemandZeroCount;
ULONG PageReadCount;
ULONG PageReadIoCount;
ULONG CacheReadCount;
ULONG CacheIoCount;
ULONG DirtyPagesWriteCount;
ULONG DirtyWriteIoCount;
ULONG MappedPagesWriteCount;
ULONG MappedWriteIoCount;
ULONG PagedPoolPages;
ULONG NonPagedPoolPages;
ULONG PagedPoolAllocs;
ULONG PagedPoolFrees;
ULONG NonPagedPoolAllocs;
ULONG NonPagedPoolFrees;
ULONG FreeSystemPtes;
ULONG ResidentSystemCodePage;
ULONG TotalSystemDriverPages;
ULONG TotalSystemCodePages;
ULONG NonPagedPoolLookasideHits;
ULONG PagedPoolLookasideHits;
ULONG Spare3Count;
ULONG ResidentSystemCachePage;
ULONG ResidentPagedPoolPage;
ULONG ResidentSystemDriverPage;
ULONG CcFastReadNoWait;
ULONG CcFastReadWait;
ULONG CcFastReadResourceMiss;
ULONG CcFastReadNotPossible;
ULONG CcFastMdlReadNoWait;
ULONG CcFastMdlReadWait;
ULONG CcFastMdlReadResourceMiss;
ULONG CcFastMdlReadNotPossible;
ULONG CcMapDataNoWait;
ULONG CcMapDataWait;
ULONG CcMapDataNoWaitMiss;
ULONG CcMapDataWaitMiss;
ULONG CcPinMappedDataCount;
ULONG CcPinReadNoWait;
ULONG CcPinReadWait;
ULONG CcPinReadNoWaitMiss;
ULONG CcPinReadWaitMiss;
ULONG CcCopyReadNoWait;
ULONG CcCopyReadWait;
ULONG CcCopyReadNoWaitMiss;
ULONG CcCopyReadWaitMiss;
ULONG CcMdlReadNoWait;
ULONG CcMdlReadWait;
ULONG CcMdlReadNoWaitMiss;
ULONG CcMdlReadWaitMiss;
ULONG CcReadAheadIos;
ULONG CcLazyWriteIos;
ULONG CcLazyWritePages;
ULONG CcDataFlushes;
ULONG CcDataPages;
ULONG ContextSwitches;
ULONG FirstLevelTbFills;
ULONG SecondLevelTbFills;
ULONG SystemCalls;
}
我们在任务管理器中所见到的所有信息只使用了下面5个调用:
0 SystemBasicInformation
2 SystemPerformanceInformation
5 SystemProcessInformation
8 SystemProcessorPerformanceInformation
21 SystemFileCacheInformation
初始化部分使用了其中的3个调用(0、2、8),这里给出的是任务管理器的初始化部分:
010058D6 InitPerfInfo proc near
010058D6
010058D6 SYSPROCPERFINFO= SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ptr -76Ch
010058D6 SYSPERFINFO= SYSTEM_PERFORMANCE_INFORMATION ptr -16Ch
010058D6 SYSBASICINFO= SYSTEM_BASIC_INFORMATION ptr -34h
010058D6 pBuf= dword ptr -8
010058D6 i = dword ptr -4
010058D6
010058D6 push ebp
010058D7 mov ebp, esp
010058D9 sub esp, 76Ch
010058DF push ebx
010058E0 push esi
010058E1 xor ebx, ebx
010058E3 push edi
010058E4 push ebx ; puReturnLength
010058E5 lea eax, [ebp+SYSBASICINFO]
010058E8 push 2Ch ; SizeOf(SYSTEM_BASIC_INFORMATION)
010058EA push eax ; pSystemInformation
010058EB push ebx ; ebx = 0 SystemBasicInformation
010058EC call ds:NtQuerySystemInformation
010058F2 cmp eax, ebx
010058F4 jl Err_CpuNumAbove32
010058FA mov eax, [ebp+SYSBASICINFO.uPageSize]
010058FD mov g_PageSize, eax ; 页面大小
01005902 mov al, [ebp+SYSBASICINFO.bKeNumberProcessors]
01005905 cmp al, 32 ; 32位Windows操作系统最多允许系统有32个CPU
01005907 mov g_cProcessors, al ; CPU的个数
0100590C ja Err_CpuNumAbove32
01005912 mov esi, ds:LocalAlloc
01005918 mov edi, 1F40h
0100591D test al, al
0100591F jbe short CpuNumEquOne
01005921
01005921 Loop_for_AllocMem:
01005921 push edi
01005922 push LMEM_ZEROINIT
01005924 call esi ; LocalAlloc
01005926 test eax, eax
01005928 mov g_pCPUHistory[ebx*4], eax
0100592F jz Err_CpuNumAbove32
01005935 push edi
01005936 push LMEM_ZEROINIT
01005938 call esi ; LocalAlloc
0100593A test eax, eax
0100593C mov g_pKernelHistory[ebx*4], eax
01005943 jz Err_CpuNumAbove32
01005949 movzx eax, g_cProcessors
01005950 inc ebx
01005951 cmp ebx, eax
01005953 jl short Loop_for_AllocMem
01005955
01005955 CpuNumEquOne:
01005955 push edi
01005956 push LMEM_ZEROINIT
01005958 call esi ; LocalAlloc
0100595A test eax, eax
0100595C mov g_pMEMHistory, eax
01005961 jz Err_CpuNumAbove32
01005967 push 0 ; puReturnLength
01005969 lea eax, [ebp+SYSPROCPERFINFO]
0100596F push 600h ; 为32个CPU准备空间
0100596F ; SizeOf(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*32
01005974 push eax ; pSystemInformation
01005975 push SystemProcessorPerformanceInformation ; SystemInformationClass
01005977 call ds:NtQuerySystemInformation
0100597D test eax, eax
0100597F jl Err_CpuNumAbove32
01005985 movzx eax, g_cProcessors
0100598C and [ebp+i], 0
01005990 test eax, eax
01005992 jle short CpuNumEquOne_1
01005994 lea eax, [ebp+SYSPROCPERFINFO.KernelTime]
0100599A mov [ebp+pBuf], offset PreviousCPUKernelTime
010059A1
010059A1 Loop_IniCpuAllTime:
010059A1 mov ecx, [ebp+i]
010059A4 mov edx, [eax-8] ; edx = IdleTime.LowPart
010059A7 mov edi, [eax+8] ; edi = UserTime.LowPart
010059AA mov esi, [eax+4] ; esi = KernelTime.HighPart
010059AD shl ecx, 3 ; ecx = i X 8
010059B0 mov ebx, [eax+0Ch] ; ebx = UserTime.HighPart
010059B3 mov dword ptr PreviousCPUIdleTime.LowPart[ecx], edx
010059B9 mov edx, [eax-4] ; edx = IdleTime.HighPart
010059BC mov PreviousCPUIdleTime.HighPart[ecx], edx
010059C2 mov edx, [eax] ; KernelTime.LowPart
010059C4 add edi, edx ; edi = UserTime.LowPart + KernelTime.LowPart
010059C6 adc ebx, esi ; 带进位加
010059C6 ; ebx = UserTime.HighPart + KernelTime.HighPart
010059C8 add edx, [eax-8] ; edx = KernelTime.LowPart + IdleTime.LowPart
010059CB mov dword ptr PreviousCPUTotalTime.LowPart[ecx], edi
010059D1 mov PreviousCPUTotalTime.HighPart[ecx], ebx
010059D7 mov ecx, [ebp+pBuf] ; PreviousCPUKernelTime的指针
010059DA adc esi, [eax-4] ; 带进位加
010059DA ; esi = KernelTime.HighPart + IdleTime.HighPart
010059DD add eax, 30h ; 取下一个CPU的相关数据
010059DD ; SizeOf(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)
010059E0 inc [ebp+i]
010059E3 mov [ecx], edx ; PreviousCPUTotalTime.LowPart = KernelTime.LowPart + IdleTime.LowPart
010059E5 mov [ecx+4], esi ; PreviousCPUTotalTime.HighPart = KernelTime.HighPart + IdleTime.HighPart
010059E8 add ecx, 8 ; 移动PreviousCPUKernelTime的指针
010059EB mov [ebp+pBuf], ecx ; 保存PreviousCPUKernelTime的指针
010059EE movzx ecx, g_cProcessors
010059F5 cmp [ebp+i], ecx ; 和Cpu的个数比较
010059F8 jl short Loop_IniCpuAllTime
010059FA
010059FA CpuNumEquOne_1: ; puReturnLength
010059FA push 0
010059FC lea eax, [ebp+SYSPERFINFO]
01005A02 push 138h ; SizeOf(SYSTEM_PERFORMANCE_INFORMATION)
01005A07 push eax ; pSystemInformation
01005A08 push SystemPerformanceInformation ; SystemInformationClass
01005A0A call ds:NtQuerySystemInformation
01005A10 test eax, eax
01005A12 jge short Init_Exit
01005A14
01005A14 Err_CpuNumAbove32: ; 如果出错返回 0
01005A14 xor al, al
01005A16 jmp short Exit
01005A18
01005A18 Init_Exit:
01005A18 mov eax, g_PageSize
01005A1D shr eax, 10
01005A20 imul eax, [ebp+SYSPERFINFO.CommitLimit]
01005A27 mov g_MEMMax, eax
01005A2C mov al, g_cProcessors ; 返回Cpu的个数
01005A31
01005A31 Exit:
01005A31 pop edi
01005A32 pop esi
01005A33 pop ebx
01005A34 leave
01005A35 retn
01005A35 InitPerfInfo endp
01005A35
NtQuerySystemInformation非常复杂,其中的结构随着Windows的版本变化会发生变化,这里给出的结构是2K系统的。