获取系统信息

DriverEntry

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
typedef NTSTATUS(NTAPI* LPFN_RTLGETVERSION)(
OUT PRTL_OSVERSIONINFOW OsVersionInfo);
typedef enum
{
UNKNOWN_VERSION = 0,
WIN2000_VERSION,
WINXP_VERSION,
WIN2003_VERSION,
WINVISTA_VERSION,
WIN7_VERSION,
WIN8_VERSION,
WIN8_VERSION_1,
WIN8_VERSION_1_9600,
WIN10_VERSION,
WIN10_VERSION_10240,
WIN10_VERSION_10586,
}OS_VERSION;
enum OS_VERSION __OsVersion = UNKNOWN_VERSION;

RTL_OSVERSIONINFOEXW __RtlOsVersionInfo = { 0 };// wdm.h中定义的,保存系统版本信息的结构体
UNICODE_STRING __RtlGetVersionU = RTL_CONSTANT_STRING(L"RtlGetVersion");

//系统导出的全局变量
extern PULONG InitSafeBootMode;

NTSTATUS DriverEntry(
DRIVER_OBJECT* DriverObject,
UNICODE_STRING* RegistryPath)
{
NTSTATUS Status = STATUS_ACCESS_DENIED;
/*
1: kd> dd InitSafeBootMode
849a4980 00000000 00000000 02080014 ffdf0030

*/
if (*InitSafeBootMode > 0)
{
return STATUS_ACCESS_DENIED;
}

// 一个全局结构体,代表系统版本信息
__RtlOsVersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
__RtlOsVersionInfo.dwMajorVersion = 0xFF; // 初始化一个无效的版本

// 从系统模块ntkrnlpa.exe的导出表中获取函数地址
__RtlGetVersion = (LPFN_RTLGETVERSION)MmGetSystemRoutineAddress(&__RtlGetVersionU);

if (__RtlGetVersion)
{
__RtlGetVersion((PRTL_OSVERSIONINFOW)&__RtlOsVersionInfo);
}

InitializeOsVersion(); //初始化系统版本信息
if (__OsVersion == UNKNOWN_VERSION)
{
return STATUS_ACCESS_DENIED;
}
//Ntos.exe
//Win32k.sys
//Ntdll.dll
//csrss.exe
Status = GetSystemInfo();

if (!NT_SUCCESS(Status)) {

return Status;
}

__DriverObject = DriverObject;
DriverObject->DriverUnload = DriverUnload;
}

获取系统版本

先判断MajorVersion,2003、 xp、 2000都是5,后面的都是6,win10是10。再判断MinorVersion,分辨win7、win8。对于win8、win10的一些小版本,通过BuildNumber来判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
ULONG __BuildNumber = 0;
void InitializeOsVersion()
{
ULONG BuildNumber = 0;
ULONG MajorVersion = 0;
ULONG MinorVersion = 0;
PsGetVersion(&MajorVersion, &MinorVersion, &BuildNumber, NULL);
__BuildNumber = BuildNumber;

// 2003, xp, 2000
if (MajorVersion == 5)
{
switch (MinorVersion)
{
case 0: // win2k

__OsVersion = WIN2000_VERSION;
return;

case 1: // winxp
__OsVersion = WINXP_VERSION;
//ReadOsServicePack();
return;

case 2: // win2003

__OsVersion = WIN2003_VERSION;
return;
}
}
else if (MajorVersion == 6)
{
switch (MinorVersion)
{
case 0:

__OsVersion = WINVISTA_VERSION;
return;

case 1:
__OsVersion = WIN7_VERSION;

return;

case 2:

__OsVersion = WIN8_VERSION;
return;

case 3:
if (__BuildNumber == 9431)
{
__OsVersion = WIN8_VERSION_1;
}
if (__BuildNumber == 9600)
{
__OsVersion = WIN8_VERSION_1_9600;
}
return;
case 4:
__OsVersion = WIN10_VERSION;
return;
}
}
else if (MajorVersion == 10)
{
if (__BuildNumber < 10240)
{
__OsVersion = WIN10_VERSION;
}
else if (__BuildNumber == 10240)
{
__OsVersion = WIN10_VERSION_10240;
}
else if (__BuildNumber == 10586)
{
__OsVersion = WIN10_VERSION_10586;
}
return;
}

__OsVersion = UNKNOWN_VERSION;
}

获取系统信息

  1. csrss.exe是微软客户端、服务端运行时子系统,管理Windows图形相关任务,Hook SSSDT必须。SSSDT就是win32k.sys里面的函数,大多数都跟图形相关,比如什么NtUserGetDCEx或者NtUserCreateWindowEx等。所以要查看这些内核函数地址,光在驱动中进行和SSDT一样的访问会引发异常蓝屏的。所以有前辈就想出办法,在驱动程序里面调用KeAttachProces到csrss.exe中,获取这个系统进程的地址空间从而在驱动中获取SSSDT中的函数地址

  2. ZwQuerySystemInformation函数需要导出使用。配合枚举类型指示获取系统的什么信息。代码中获取了系统的所有模块,这个函数返回了首地址和大小。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(
    ULONG SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
    );
    typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemBasicInformation,
    SystemProcessorInformation, // obsolete...delete
    SystemPerformanceInformation,
    SystemTimeOfDayInformation,
    SystemPathInformation,
    SystemProcessInformation,
    SystemCallCountInformation,
    SystemDeviceInformation,
    SystemProcessorPerformanceInformation,
    SystemFlagsInformation,
    SystemCallTimeInformation,
    SystemModuleInformation,
    SystemLocksInformation,
    SystemStackTraceInformation,
    SystemPagedPoolInformation,
    SystemNonPagedPoolInformation,
    SystemHandleInformation,
    SystemObjectInformation,
    SystemPageFileInformation,
    SystemVdmInstemulInformation,
    SystemVdmBopInformation,
    SystemFileCacheInformation,
    SystemPoolTagInformation,
    SystemInterruptInformation,
    SystemDpcBehaviorInformation,
    SystemFullMemoryInformation,
    SystemLoadGdiDriverInformation,
    SystemUnloadGdiDriverInformation,
    SystemTimeAdjustmentInformation,
    SystemSummaryMemoryInformation,
    SystemMirrorMemoryInformation,
    SystemPerformanceTraceInformation,
    SystemObsolete0,
    SystemExceptionInformation,
    SystemCrashDumpStateInformation,
    SystemKernelDebuggerInformation,
    SystemContextSwitchInformation,
    SystemRegistryQuotaInformation,
    SystemExtendServiceTableInformation,
    SystemPrioritySeperation,
    SystemVerifierAddDriverInformation,
    SystemVerifierRemoveDriverInformation,
    SystemProcessorIdleInformation,
    SystemLegacyDriverInformation,
    SystemCurrentTimeZoneInformation,
    SystemLookasideInformation,
    SystemTimeSlipNotification,
    SystemSessionCreate,
    SystemSessionDetach,
    SystemSessionInformation,
    SystemRangeStartInformation,
    SystemVerifierInformation,
    SystemVerifierThunkExtend,
    SystemSessionProcessInformation,
    SystemLoadGdiDriverInSystemSpace,
    SystemNumaProcessorMap,
    SystemPrefetcherInformation,
    SystemExtendedProcessInformation,
    SystemRecommendedSharedDataAlignment,
    SystemComPlusPackage,
    SystemNumaAvailableMemory,
    SystemProcessorPowerInformation,
    SystemEmulationBasicInformation,
    SystemEmulationProcessorInformation,
    SystemExtendedHandleInformation,
    SystemLostDelayedWriteInformation,
    SystemBigPoolInformation,
    SystemSessionPoolTagInformation,
    SystemSessionMappedViewInformation,
    SystemHotpatchInformation,
    SystemObjectSecurityMode,
    SystemWatchdogTimerHandler,
    SystemWatchdogTimerInformation,
    SystemLogicalProcessorInformation,
    SystemWow64SharedInformation,
    SystemRegisterFirmwareTableInformationHandler,
    SystemFirmwareTableInformation,
    SystemModuleInformationEx,
    SystemVerifierTriageInformation,
    SystemSuperfetchInformation,
    SystemMemoryListInformation,
    SystemFileCacheInformationEx,
    MaxSystemInfoClass // MaxSystemInfoClass should always be the last enum
    } SYSTEM_INFORMATION_CLASS;
  3. strrchr用于从右查找字符数组第一次出现对应标识的地方,并返回指向这个被截断的数组的指针。RtlStringCchCatW连接两个字符串(Unicode),RtlStringCchCatNW限制连接的大小。

  4. win10下,win32k.sys变为了win32kfull.sys

  5. 内核有效地址从MmSystemRangeStart开始。模块枚举不到ntdll时,可以使用内存映射的方法获取ntdll信息。

  6. 注意比较csrss.exe的最大session id不能大于10。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
NTSTATUS GetSystemInfo()
{
#define SYSTEM_PROCESS_IDENTITY ((HANDLE)0x4)
#define CSRSS_IMAGE_NAME L"csrss.exe" //微软客户端、服务端运行时子系统,管理Windows图形相关任务,Hook Sssdt必须

NTSTATUS Status = STATUS_UNSUCCESSFUL;
ULONG ViewSize = 100 * 1024;//100K
ULONG NumberOfModules;
LONG i;
PCHAR ModuleName = NULL;
PVOID VirtualAddress = NULL;
PRTL_PROCESS_MODULES RtlProcessModules = NULL;
PRTL_PROCESS_MODULE_INFORMATION RtlProcessModuleInfo = NULL;
PSYSTEM_PROCESS_INFORMATION SystemProcessInfo = NULL; //系统对所有进程的记录结构
LPCSTR v1;
ANSI_STRING v2;
UNICODE_STRING v3;

do
{
VirtualAddress = AllocateMemory1(ViewSize);
if (VirtualAddress == NULL)
{
return STATUS_NO_MEMORY;
}

//获取系统所有模块
Status = ZwQuerySystemInformation(SystemModuleInformation, (PVOID)VirtualAddress, ViewSize, NULL);
if (Status == STATUS_INFO_LENGTH_MISMATCH) //内存不足
{
FreeMemory1(VirtualAddress);
VirtualAddress = NULL;
ViewSize *= 2;
}
else if (!NT_SUCCESS(Status))
{
FreeMemory1(VirtualAddress);
return Status;
}
} while (Status == STATUS_INFO_LENGTH_MISMATCH);


//游历内存
RtlProcessModules = (PRTL_PROCESS_MODULES)VirtualAddress;
NumberOfModules = (RtlProcessModules->NumberOfModules);

RtlProcessModuleInfo = (PRTL_PROCESS_MODULE_INFORMATION)(RtlProcessModules->Modules); //获取到第一个模块信息

v1 = strrchr(RtlProcessModuleInfo->FullPathName, '\\'); //右边第一次出现的字符
if (v1)
{
v1++;
RtlInitAnsiString(&v2, v1); //char数组转换成Ansi
Status = RtlAnsiStringToUnicodeString(&v3, &v2, TRUE); //Ansi转换成Unicode
if (NT_SUCCESS(Status)) {

RtlStringCchCatW(__NtosFilePath, sizeof(__NtosFilePath) / sizeof(WCHAR), L"\\SystemRoot\\system32\\");
RtlStringCchCatNW(__NtosFilePath, sizeof(__NtosFilePath) / sizeof(WCHAR), v3.Buffer, v3.Length / sizeof(WCHAR));
RtlFreeUnicodeString(&v3); //TRUE
}

//v3 struct _UNICODE_STRING "ntkrnlpa.exe"
}

//ntoskrnl.exe Ntdll.dll Ssdt

//获取系统第一个模块信息 ntoskrnl.exe
__NtosImageBase = RtlProcessModuleInfo[0].ImageBase;
__NtosImageSize = RtlProcessModuleInfo[0].ImageSize;

// 枚举系统模块信息
//win32k.sys / WIN32KFULL.SYS User32.dll Sssdt
for (i = (LONG)NumberOfModules - 1; i >= 0; i--)
{
//c:\windows\system\win32k.sys
ModuleName = (RtlProcessModuleInfo[i].FullPathName + RtlProcessModuleInfo[i].OffsetToFileName);
if (!_stricmp(ModuleName, WIN32K_SYS))
{
__Win32kImageBase = RtlProcessModuleInfo[i].ImageBase; //0x87e5a31d "win32k.sys"
}

if (__OsVersion == WIN10_VERSION_10240)
{
if (!_stricmp(ModuleName, "win32kfull.sys"))
{
__Win32kFullImageBase = RtlProcessModuleInfo[i].ImageBase;
}
}
}

//ntdll.dll
for (i = (LONG)NumberOfModules - 1; i >= 0; i--)
{
//判断地址是否在Ring3层的范围内
//0: kd> dd MmSystemRangeStart
//849a584c 80000000 7fff0000 80741000 000fffff

if ((ULONG_PTR)RtlProcessModuleInfo[i].ImageBase > (ULONG_PTR)MmSystemRangeStart)
{
continue;
}

ModuleName = (RtlProcessModuleInfo[i].FullPathName + RtlProcessModuleInfo[i].OffsetToFileName);

if (!_stricmp(ModuleName, NTDLL_DLL))
{
__NtdllImageBase = RtlProcessModuleInfo[i].ImageBase;
__NtdllImageSize = RtlProcessModuleInfo[i].ImageSize;
}
}

if (NULL == __NtdllImageBase)
{

__NtdllImageBase = MappingModuleInfo(L"\\SystemRoot\\System32\\ntdll.dll", NULL, NULL);
}

///< ntdll


if (!__NtosImageBase || !__Win32kImageBase || !__NtdllImageBase)
{
FreeMemory1(VirtualAddress);
return STATUS_NOT_FOUND;
}

//获取Csrss进程的方法
do
{
if (NULL == VirtualAddress)
{
VirtualAddress = AllocateMemory1(ViewSize);
if (VirtualAddress == NULL)
{
return STATUS_NO_MEMORY;
}
}

Status = ZwQuerySystemInformation(SystemProcessInformation, VirtualAddress, ViewSize, NULL);
if (Status == STATUS_INFO_LENGTH_MISMATCH)
{
FreeMemory1(VirtualAddress);
VirtualAddress = NULL;
ViewSize *= 2;
}
else if (!NT_SUCCESS(Status))
{
FreeMemory1(VirtualAddress);
return Status;
}
} while (Status == STATUS_INFO_LENGTH_MISMATCH);

Status = STATUS_NOT_FOUND;

SystemProcessInfo = (PSYSTEM_PROCESS_INFORMATION)VirtualAddress;

while (TRUE)
{
if (SystemProcessInfo->ImageName.Length == sizeof(CSRSS_IMAGE_NAME) - sizeof(WCHAR))
{
if (!_wcsnicmp(SystemProcessInfo->ImageName.Buffer,
CSRSS_IMAGE_NAME,
(sizeof(CSRSS_IMAGE_NAME) - sizeof(WCHAR)) / sizeof(WCHAR)))
{
//插入到数据结构中
if (InsertCsrssProcessIdentity(SystemProcessInfo->UniqueProcessId, SystemProcessInfo->SessionId))
{
Status = STATUS_SUCCESS;
}
break;
}
}

if (SystemProcessInfo->NextEntryOffset == 0)
{
break; //下一个信息如果不存在
}

(ULONG_PTR)SystemProcessInfo += SystemProcessInfo->NextEntryOffset; //定位到下一条信息上
}

FreeMemory1(VirtualAddress);

return Status;
}

使用内存映射方法获取ntdll模块信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
PVOID MappingModuleInfo(LPCWSTR FilePath, PULONG ImageFileSize, PULONG ImageSize)
{
#define SEC_IMAGE 0x1000000 //内存粒度对齐

PVOID ImageBase = NULL;
HANDLE FileHandle = NULL;
HANDLE SectionHandle = NULL;
UNICODE_STRING FilePathU;
IO_STATUS_BLOCK IoStatusBlock = { 0 };
NTSTATUS Status;
SIZE_T ViewSize = 0;
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
//LARGE_INTEGER SectionOffset;
SECTION_IMAGE_INFORMATION SectionImageInfo;

RtlInitUnicodeString(&FilePathU, FilePath);

//内核句柄
InitializeObjectAttributes(&ObjectAttributes, &FilePathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);

//通过文件路径获取文件句柄
Status = ZwOpenFile(&FileHandle,
SYNCHRONIZE | GENERIC_READ | FILE_EXECUTE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);

if (!NT_SUCCESS(Status))
{
goto Exit;
}

ObjectAttributes.ObjectName = NULL;

//通过文件句柄获取内存映射句柄
Status = ZwCreateSection(&SectionHandle,
SECTION_MAP_READ | SECTION_QUERY | SECTION_MAP_EXECUTE,
&ObjectAttributes,
0,
PAGE_READONLY,
SEC_IMAGE,
FileHandle);
if (!NT_SUCCESS(Status))
{
goto Exit;
}

//获取内存对象中的数据
Status = ZwQuerySection(SectionHandle,
SectionImageInformation,
&SectionImageInfo,
sizeof(SectionImageInfo),
NULL
);
if (!NT_SUCCESS(Status)) {
goto Exit;
}

if (ImageFileSize) {
*ImageFileSize = SectionImageInfo.ImageFileSize;
}

//通过Section句柄获取虚拟地址
Status = ZwMapViewOfSection(
SectionHandle,
NtCurrentProcess(),
&ImageBase,
0,
0,
NULL,
&ViewSize,
ViewShare,
0,
PAGE_READONLY);
if (!NT_SUCCESS(Status)) {
goto Exit;
}

if (ImageSize) {
*ImageSize = ViewSize;
}

Exit:

if (NULL != FileHandle) {
ZwClose(FileHandle);
}
if (NULL != SectionHandle) {
ZwClose(SectionHandle);
}
return ImageBase;
}