123456

 

驱动学习6----字符串系列函数

6.1.2 ANSI_STRING字符串和UNICOCE_STRING

用KdPrint表示分别%Z和%wZ表示

如:

extern "C" NTSTATUS DriverEntry (
			IN PDRIVER_OBJECT pDriverObject,
			IN PUNICODE_STRING pRegistryPath	) 
{
	NTSTATUS status;
	KdPrint(("Enter DriverEntryp RegistryPath:%wZ\n",pRegistryPath) );
要注意的是%wZ,w必须是小写,如果是%WZ,是不会打印的.


6.1.3字符串初始化

VOID 
  RtlInitAnsiString(
    IN OUT PANSI_STRING  DestinationString,
    IN PCSZ  SourceString
    );
这种方式有个坏处是,如果SourceString改变了,DestinationSting的Buff也会变,因为二者指针相同

以下代码用windbg调试:

	UNICODE_STRING symLinkName;
	WCHAR *wString = L"\\??\\HelloDDK";
	RtlInitUnicodeString(&symLinkName,wString);
如下图:

可以看到symLinkName的Buffer和wString的地址完全一样,所以二者会同时变化

另一种方式是程序员自己申请内存,并初始化内存,当不用字符串时,需要回收字符串占的内存。

注意的是UNICODE_STRING中的大小都是以字节来计算的,

自己写个小示例:

VOID CopyString()
{
	KdPrint(("CopyString start"));

	// 第一种方式
	WCHAR *wString = L"first copy";
	UNICODE_STRING Unicode_String;
	RtlInitUnicodeString(&Unicode_String, wString);
	KdPrint(("Unicode_String:%wZ\n", &Unicode_String));

	// 第二种方式
	UNICODE_STRING Second_String = {0};
	Second_String.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 1024);
	if (Second_String.Buffer)
	{
		Second_String.MaximumLength = 1024;
		Second_String.Length = 2*wcslen(wString);
		RtlCopyMemory(Second_String.Buffer, wString, Second_String.Length);
		KdPrint(("Second_String:%wZ\n", &Second_String));
		RtlFreeUnicodeString(&Second_String);
	}

	// 第三种方式
	UNICODE_STRING Third_String;
	Third_String.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 1024);
	if (Third_String.Buffer)
	{
		Third_String.MaximumLength = 1024;// length就不用初始化了,在copy中完成
		RtlCopyUnicodeString(&Third_String, &Unicode_String);
		KdPrint(("Third_String:%wZ, len:%d\n", &Third_String, Third_String.Length));
		RtlFreeUnicodeString(&Third_String);

	}

	KdPrint(("CopyString end"));
}

需要注意的是第二种第三种方式都需要自己分配、释放内存


6.1.5 字符串比较

LONG 
  RtlCompareUnicodeString(
    IN PUNICODE_STRING  String1,
    IN PUNICODE_STRING  String2,
    IN BOOLEAN  CaseInSensitive
    );
写了一段测试代码:

#pragma PAGEDCODE
VOID First_StringCompare()
{
	//第一种方式
	UNICODE_STRING First_String;
	RtlInitUnicodeString(&First_String, L"\\??\\First");
	KdPrint(("First_String.Length:%d, First_String.MaximumLength:%d, First_String.Buffer:%s\n",
		First_String.Length, First_String.MaximumLength, First_String.Buffer));
	UNICODE_STRING First_StringCompare = {0};
	First_StringCompare.MaximumLength = 1024;
	First_StringCompare.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 1024);
	if (First_StringCompare.Buffer)
	{
		RtlCopyUnicodeString(&First_StringCompare, &First_String);
		KdPrint(("First_StringCompare.Length:%d, First_StringCompare.MaximumLength:%d, First_StringCompare.Buffer:%s\n",
			First_StringCompare.Length, First_StringCompare.MaximumLength, First_StringCompare.Buffer));

		LONG bRet = RtlCompareUnicodeString(&First_StringCompare, &First_String, FALSE);
		KdPrint(("bRet:%d\n",bRet));
	}
}
结果bRet返回0,这两个打印的MaximunLength明显是不同的,只是比较buffer和length

windbg跟进这个函数内部:

nt!RtlCompareUnicodeString:
805e2b0a 8bff            mov     edi,edi
805e2b0c 55              push    ebp
805e2b0d 8bec            mov     ebp,esp
805e2b0f 83ec0c          sub     esp,0Ch
805e2b12 8b4508          mov     eax,dword ptr [ebp+8]
805e2b15 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]
打印下,ecx和eax保存了比较双方

3: kd> r eax, ecx
eax=bad17c70 ecx=bad17c68
3: kd> dt bad17c70 UNICODE_STRING
HelloDDK!UNICODE_STRING
 "\??\First"
   +0x000 Length           : 0x12
   +0x002 MaximumLength    : 0x400
   +0x004 Buffer           : 0xe115c7f8  "\??\First"
3: kd> dt bad17c68 UNICODE_STRING
HelloDDK!UNICODE_STRING
 "\??\First"
   +0x000 Length           : 0x12
   +0x002 MaximumLength    : 0x14
   +0x004 Buffer           : 0xbac44920  "\??\First"
可以看到MaximunLength的大小的确不同

805e2b1b 0fb709          movzx   ecx,word ptr [ecx]
取得第一个比较数的length到ecx中

805e2b23 0fb700          movzx   eax,word ptr [eax]
取得第二个比较数的length到eax中

805e2b26 3bc1            cmp     eax,ecx
比较Length

805e2b2f 7e02            jle     nt!RtlCompareUnicodeString+0x29 (805e2b33)
805e2b31 8bc1            mov     eax,ecx
805e2b33 03c6            add     eax,esi
小或等于转移,所以上面的会直接跳转到805e2b33

05e2b33 03c6            add     eax,esi
其中eax是length,esi是buffer起始

3: kd> du esi
e115c7f8  "\??\First"
805e2b35 807d1000        cmp     byte ptr [ebp+10h],0
805e2b39 8945fc          mov     dword ptr [ebp-4],eax
805e2b3c 0f84fe000000    je      nt!RtlCompareUnicodeString+0x136 (805e2c40) [br=1]
比较buffer[Lengh]是否为0,为0则跳转到805e2c40

5e2c40 3bf0            cmp     esi,eax
最后是一个循环比较,直到esi=eax

3: kd> r eax, esi
eax=e115c80a esi=e115c80a

805e2c04 0f8246ffffff    jb      nt!RtlCompareUnicodeString+0x46 (805e2b50)
805e2c0a 8b45f8          mov     eax,dword ptr [ebp-8]
805e2c0d 2b45f4          sub     eax,dword ptr [ebp-0Ch]
805e2c10 5f              pop     edi
805e2c11 5e              pop     esi
805e2c12 5b              pop     ebx
805e2c13 c9              leave
805e2c14 c20c00          ret     0Ch
其中ebp-8的内存中保存了第一个len,ebp-0c保存了第二个len,两者相差,明显为0

整个过程和max大小没有关系.

另写了一段测试代码,同样ret为0,

#pragma PAGEDCODE
VOID First_StringCompare()
{
	//第二种方式
	UNICODE_STRING First_String = {0};
	First_String.MaximumLength = 100;
	First_String.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 100);
	if (First_String.Buffer)
	{
		First_String.Buffer[0] = 0x5c;
		First_String.Buffer[1] = 0x6c;
		First_String.Buffer[2] = 0x7c;
		First_String.Length = 4;
		KdPrint(("First_String.Length:%d, First_String.MaximumLength:%d, First_String.Buffer:%s\n",
			First_String.Length, First_String.MaximumLength, First_String.Buffer));
	}

	UNICODE_STRING First_StringCompare = {0};
	First_StringCompare.MaximumLength = 1024;
	First_StringCompare.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 1024);
	if (First_StringCompare.Buffer)
	{
		First_StringCompare.Buffer[0] = 0x5c;
		First_StringCompare.Buffer[1] = 0x6c;
		First_StringCompare.Buffer[2] = 0x8c;
		First_StringCompare.Length = 4;
		
		KdPrint(("First_StringCompare.Length:%d, First_StringCompare.MaximumLength:%d, First_StringCompare.Buffer:%s\n",
			First_StringCompare.Length, First_StringCompare.MaximumLength, First_StringCompare.Buffer));

		LONG bRet = RtlCompareUnicodeString(&First_StringCompare, &First_String, FALSE);
		KdPrint(("bRet:%d\n",bRet));
	}
}

同样bRet为0,说明只是比较了buffer的length长度

6.1.6字符串转化为大写

VOID 
  RtlUpperString(
    IN OUT PSTRING  DestinationString,
    IN PSTRING  SourceString
    );
NTSTATUS 
  RtlUpcaseUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PCUNICODE_STRING  SourceString,
    IN BOOLEAN  AllocateDestinationString
    );
小示例

#pragma PAGEDCODE
VOID UpperCase()
{
	// ANSI_STRING转换成大写
	// 1.自己转换
	ANSI_STRING    Ansi_String = {0};
	RtlInitString(&Ansi_String, "Ansi_String");
	KdPrint(("Ansi_String.Length:%d, %d, %s", Ansi_String.Length, Ansi_String.MaximumLength,Ansi_String.Buffer));
	RtlUpperString(&Ansi_String, &Ansi_String);
	KdPrint(("Ansi_String.Length:%d, %d, %s", Ansi_String.Length, Ansi_String.MaximumLength,Ansi_String.Buffer));

这样会挂掉,跟进RtlUpperString后,可以看到:

kd> p
nt!RtlUpperString+0x36:
805e3cb6 8806            mov     byte ptr [esi],al
kd> r esi
esi=f892e770
kd> !vad f892e770 1

VAD @ f892e770
  Start VPN     69736e41  End VPN 7274535f  Control Area  43676e69
  FirstProtoPte 3a79706f  LastPte 0a5a7725  Commit Charge    4535f (283487.)
  Secured.Flink        0  Blink          0  Banked/Extend        0
  File Offset          0  
      ImageMap ViewUnmap NoChange LargePages AWE MemCommit EXECUTE           GUARD
因为这个内存是GUARD,所以会直接异常

当然,把属性改成#pragma INITCODE应该就OK,以下是改成INITCODE属性时这部分代码:

kd> !vad f8957230 1

VAD @ f8957230
  Start VPN     69736e41  End VPN 7274535f  Control Area  20797274
  FirstProtoPte 0a646e65  LastPte cccccc00  Commit Charge    57265 (356965.)
  Secured.Flink cccccccc  Blink   cccccccc  Banked/Extend        0
  File Offset     cccccc  
      ViewShare NoChange CopyOnWrite LargePages MemCommit EXECUTE_READWRITE NOCACHE
      MultipleSecured ReadOnly 
建议使用自己分配内存的字符串:

#pragma PAGEDCODE
VOID Upper()
{
	ANSI_STRING    Ansi_String = {0};
	RtlInitString(&Ansi_String, "Ansi_String");
	ANSI_STRING    Ansi_StringCopy = {0};
	Ansi_StringCopy.MaximumLength = 100;
	Ansi_StringCopy.Buffer = (PCHAR)ExAllocatePool(PagedPool, 100);
	if (Ansi_StringCopy.Buffer)
	{
		RtlCopyString(&Ansi_StringCopy, &Ansi_String);
		KdPrint(("Ansi_StringCopy:%Z\n", Ansi_StringCopy));
		RtlUpperString(&Ansi_StringCopy, &Ansi_StringCopy);
		KdPrint(("Ansi_StringCopy:%Z\n", Ansi_StringCopy));
		ExFreePool(Ansi_StringCopy.Buffer);
	}
}

肯定没问题

6.1.7 字符串和整型数字互换

NTSTATUS
  RtlUnicodeStringToInteger(
    IN PUNICODE_STRING  String,
    IN ULONG  Base  OPTIONAL,
    OUT PULONG  Value
    );

NTSTATUS 
  RtlIntegerToUnicodeString(
    IN ULONG  Value,
    IN ULONG  Base  OPTIONAL,
    IN OUT PUNICODE_STRING  String
    );
写了个小示例:

#pragma PAGEDCODE
VOID ConvertInteger()
{
	UNICODE_STRING Unicode_String = {0};
	RtlInitUnicodeString(&Unicode_String, L"10");
	ULONG lNumber = 0;
	NTSTATUS nStatus = RtlUnicodeStringToInteger(&Unicode_String, 16, &lNumber);

	UNICODE_STRING Unicode_String2 = {0};
	Unicode_String2.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 100);
	Unicode_String2.MaximumLength = 100;
	nStatus = RtlIntegerToUnicodeString(lNumber, 16, &Unicode_String2);
	RtlFreeUnicodeString(&Unicode_String2);
}
注意RtlIntegerToUnicodeString这个函数,字符串要先分配足够的大小,

RtlIntegerToUnicodeString returns an NTSTATUS value. Possible return values include :

STATUS_SUCCESS 
The routine successfully converted Value to a Unicode string. 
STATUS_BUFFER_OVERFLOW 
Value is too large to convert, or the UNICODE_STRING structure is too small to hold the result. 
STATUS_INVALID_PARAMETER 
The specified code base is not valid. The only valid values are 0, 2, 8, 10, and 16. 


6.18.ANSI和UNICODE字符串相互转换
NTSTATUS 
  RtlUnicodeStringToAnsiString(
    IN OUT PANSI_STRING  DestinationString,
    IN PUNICODE_STRING  SourceString,
    IN BOOLEAN  AllocateDestinationString
    );
一般当然是分配内存,第三个参数为true


6.2内核模式下的文件操作

NTSTATUS  
  ZwCreateFile(
    OUT PHANDLE  FileHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    IN PLARGE_INTEGER  AllocationSize  OPTIONAL,
    IN ULONG  FileAttributes,
    IN ULONG  ShareAccess,
    IN ULONG  CreateDisposition,
    IN ULONG  CreateOptions,
    IN PVOID  EaBuffer  OPTIONAL,
    IN ULONG  EaLength
    );
VOID 
  InitializeObjectAttributes(
    OUT POBJECT_ATTRIBUTES  InitializedAttributes,
    IN PUNICODE_STRING  ObjectName,
    IN ULONG  Attributes,
    IN HANDLE  RootDirectory,
    IN PSECURITY_DESCRIPTOR  SecurityDescriptor
    );

注意,初始化时文件名必须是符号链接或设备名,如"c:\1.log"应该写成"\??\c:\1.log“

测试小代码:

#pragma PAGEDCODE
VOID CreateFileTest()
{
	UNICODE_STRING objName;
	RtlInitUnicodeString(&objName, L"\\??\\c:\\yy.log");

	// 初始化obj
    OBJECT_ATTRIBUTES   objAttr;
	InitializeObjectAttributes(&objAttr, &objName, OBJ_CASE_INSENSITIVE,
		NULL, NULL);

	// 创建文件
	HANDLE hFile;
	IO_STATUS_BLOCK  iostatus;
	NTSTATUS ntStatus = ZwCreateFile
		(&hFile,
		 GENERIC_ALL,
		 &objAttr,
		 &iostatus,
		 NULL,
		 FILE_ATTRIBUTE_NORMAL,
		 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
		 FILE_OPEN_IF,
		 FILE_SYNCHRONOUS_IO_NONALERT,
		 NULL,
		 0);

	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[CreateFileTest]--ZwCreateFile sucess\n"));
	}
	else
	{
		KdPrint(("[CreateFileTest]--ZwCreateFile fail\n"));
	}

	//关闭文件句柄
	ZwClose(hFile);

	// 打开文件
	ntStatus = ZwCreateFile
		(&hFile,
		GENERIC_ALL,
		&objAttr,
		&iostatus,
		NULL,
		FILE_ATTRIBUTE_NORMAL,
		FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
		FILE_OPEN,//打开文件
		FILE_SYNCHRONOUS_IO_NONALERT,
		NULL,
		0);

	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[CreateFileTest]--[ZwCreateFile] open file sucess\n"));
	}
	else
	{
		KdPrint(("[CreateFileTest]--[ZwCreateFile] open file fail\n"));
	}

	//关闭文件句柄
	ZwClose(hFile);

	// 打开文件
	ntStatus = ZwOpenFile
		(&hFile, 
		GENERIC_ALL,
		&objAttr,
		&iostatus,
		FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
		FILE_SYNCHRONOUS_IO_NONALERT);

	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[CreateFileTest]--[ZwOpenFile] open file sucess\n"));
	}
	else
	{
		KdPrint(("[CreateFileTest]--[ZwOpenFile] open file fail\n"));
	}

	//关闭文件句柄
	ZwClose(hFile);
}


注意每次创建或打开后都要调一下ZwCreateFile(hFile);,上面三次使用hFile,少一个关闭,外部打开yy.log就会提示文件被占用.

获取或修改文件属性



NTSTATUS 
  ZwSetInformationFile(
    IN HANDLE  FileHandle,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    IN PVOID  FileInformation,
    IN ULONG  Length,
    IN FILE_INFORMATION_CLASS  FileInformationClass
    );

NTSTATUS 
  ZwQueryInformationFile(
    IN HANDLE  FileHandle,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    OUT PVOID  FileInformation,
    IN ULONG  Length,
    IN FILE_INFORMATION_CLASS  FileInformationClass
    );
FileHandle:文件句柄

FileInformationClass可以理解为文件信息的类型,不同的类型有不同的Length,而FileInformation则依据前者类型不同而不同,

Set就是设置进去FileInformation,Query就是FileInformation返回

typedef struct FILE_STANDARD_INFORMATION {
  LARGE_INTEGER  AllocationSize;//为文件分配的大小(簇大小,非文件大小)
  LARGE_INTEGER  EndOfFile;//距文件结尾还有多少字节
  ULONG  NumberOfLinks;//有多少个链接文件
  BOOLEAN  DeletePending;//是否准备删除
  BOOLEAN  Directory;//是否为文件夹
} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
typedef struct FILE_BASIC_INFORMATION {
  LARGE_INTEGER  CreationTime;//文件创建时间
  LARGE_INTEGER  LastAccessTime;//最后访问时间
  LARGE_INTEGER  LastWriteTime;//最后写时间
  LARGE_INTEGER  ChangeTime;//最后修改时间
  ULONG  FileAttributes;//文件属性,如FILE_ATTRIBUTE_READONLY
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;

#pragma PAGEDCODE
VOID FileTest()
{
	UNICODE_STRING ObjName;
	RtlInitUnicodeString(&ObjName, L"\\??\\c:\\1234.log");
	OBJECT_ATTRIBUTES ObjAttr;
	InitializeObjectAttributes(&ObjAttr, &ObjName, OBJ_CASE_INSENSITIVE, NULL, NULL);
	HANDLE hFile;
	IO_STATUS_BLOCK  iostatus;
	NTSTATUS ntStatus = ZwCreateFile
		(&hFile,
		GENERIC_READ,
		&ObjAttr,
		&iostatus,
		NULL, 
		FILE_ATTRIBUTE_NORMAL,
		0,
		FILE_OPEN,
		FILE_SYNCHRONOUS_IO_NONALERT,
		NULL, 
		0);

	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[FileTest] -- open file success\n"));
	}

	//读取文件长度
	FILE_STANDARD_INFORMATION fsi;
	ntStatus = ZwQueryInformationFile
		(hFile,
		&iostatus,
		&fsi,
		sizeof(FILE_STANDARD_INFORMATION),
		FileStandardInformation
		);

	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[FileTest] -- len:%u\n", fsi.EndOfFile.QuadPart));
	}

	//读取文件的创建访问系列时间
	FILE_BASIC_INFORMATION fbi;
	ntStatus = ZwQueryInformationFile
		(hFile,
		&iostatus,
		&fbi,
		sizeof(FILE_BASIC_INFORMATION),
		FileBasicInformation
		);

	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[FileTest] -- time:%u\n", fbi.CreationTime.QuadPart));
	}

	//读取文件名
	FILE_NAME_INFORMATION  fni;
	PWCHAR pName = (PWCHAR)ExAllocatePool(PagedPool, 100);
	RtlZeroMemory(pName, 100);
	PFILE_NAME_INFORMATION pfni = (PFILE_NAME_INFORMATION)pName;
	pfni->FileNameLength = 95;
	ntStatus = ZwQueryInformationFile
		(hFile,
		&iostatus,
		pfni,
		sizeof(FILE_NAME_INFORMATION),
		FileNameInformation
		);

	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[FileTest] -- name:%s\n", fni.FileName));
		ExFreePool(pName);
	}

	KdPrint(("ntStatus:0x%08x\n", ntStatus));

	ZwClose(hFile);
}

6.2.4  文件的写操作

NTSTATUS 
  ZwWriteFile(
    IN HANDLE  FileHandle,//文件打开句柄
    IN HANDLE  Event  OPTIONAL,//设为NULL
    IN PIO_APC_ROUTINE  ApcRoutine  OPTIONAL,//设为NULL
    IN PVOID  ApcContext  OPTIONAL,//设为NULL
    OUT PIO_STATUS_BLOCK  IoStatusBlock,//写操作的状态
    IN PVOID  Buffer,
    IN ULONG  Length,
    IN PLARGE_INTEGER  ByteOffset  OPTIONAL,//从文件的多少偏移地址开始写
    IN PULONG  Key  OPTIONAL//设为NULL
	)
小示例

#pragma PAGEDCODE
VOID FileTest()
{
	UNICODE_STRING ObjName;
	RtlInitUnicodeString(&ObjName, L"\\??\\c:\\1234.log");
	OBJECT_ATTRIBUTES ObjAttr;
	InitializeObjectAttributes(&ObjAttr, &ObjName, OBJ_CASE_INSENSITIVE, NULL, NULL);
	HANDLE hFile;
	IO_STATUS_BLOCK  iostatus;
	NTSTATUS ntStatus = ZwCreateFile
		(&hFile,
		GENERIC_WRITE,//请求写权限
		&ObjAttr,
		&iostatus,
		NULL, 
		FILE_ATTRIBUTE_NORMAL,
		0,
		FILE_OPEN,
		FILE_SYNCHRONOUS_IO_NONALERT,
		NULL, 
		0);

	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[FileTest] -- open file success\n"));
	}

	PCHAR pBuffer = (PCHAR)ExAllocatePool(PagedPool, 100);
	RtlFillMemory(pBuffer, 100, 0xAA);

	//写文件
	LARGE_INTEGER  Offset;
	Offset.QuadPart = 2;
	ntStatus = ZwWriteFile
		(hFile,
		NULL, NULL, NULL,
		&iostatus,
		pBuffer, 100,
		&Offset, NULL
		);
	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[FileTest] --  write file success\n"));
	}
	KdPrint(("ntStatus :0x%08x\n", ntStatus));

	ZwClose(hFile);
}
注意打开时文件句柄要获得写权限,写完后用UE在16进制下观看


NTSTATUS 
  ZwReadFile(
    IN HANDLE  FileHandle,
    IN HANDLE  Event  OPTIONAL,//设为NULL
    IN PIO_APC_ROUTINE  ApcRoutine  OPTIONAL,//设为NULL
    IN PVOID  ApcContext  OPTIONAL,//设为NULL
    OUT PIO_STATUS_BLOCK  IoStatusBlock,//状态,Information 成员记录读了多少
    OUT PVOID  Buffer,//指向调用者已分配的内存
    IN ULONG  Length,//buffer的长度
    IN PLARGE_INTEGER  ByteOffset  OPTIONAL,//文件指针的偏移
    IN PULONG  Key  OPTIONAL//设为NULL
    );


6.3内核模式下注册表操作

应用编程中对应的子键    驱动编程中的路径写法
HKEY_LOCAL_MACHINE    \Registry\Machine
HKEY_USERS        \Registry\User
HKEY_CLASSES_ROOT    没有对应的路径
HKEY_CURRENT_USER    没有简单的对应路径,但是可以求得

#pragma PAGEDCODE
VOID RegeditTest()
{
	UNICODE_STRING KeyPath;
	RtlInitUnicodeString(&KeyPath, L"\\Registry\\Machine\\system\\hgy413");
	OBJECT_ATTRIBUTES ObjAttr;
	InitializeObjectAttributes(&ObjAttr, &KeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL);

	//创建注册表
	HANDLE hKey;
	ULONG ulResult;
	NTSTATUS ntStatus = ZwCreateKey
		(&hKey,
		KEY_ALL_ACCESS,
		&ObjAttr,
		0,
		NULL,
		REG_OPTION_NON_VOLATILE,
		&ulResult
		);

	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[RegeditTest]--ulResult:%d\n", ulResult));
	}
	KdPrint(("ntStatus:0x%08x", ntStatus));
	ZwClose(hKey);
	hKey = NULL;

	//打开注册表
	ntStatus = ZwOpenKey
		(&hKey,
		KEY_ALL_ACCESS,
		&ObjAttr
		);
	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[RegeditTest]--ZwOpenKey  success\n"));
	}

	UNICODE_STRING ValueName;
	RtlInitUnicodeString(&ValueName, L"REG_SZ value");

	UNICODE_STRING Value;
	RtlInitUnicodeString(&Value, L"Reg_sz");

	//设置子键
	ntStatus = 
		ZwSetValueKey
		(
		hKey,
		&ValueName,
		0,
		REG_SZ,
		Value.Buffer,
		Value.MaximumLength
		);
	KdPrint(("ntStatus:0x%08x", ntStatus));
	if (NT_SUCCESS(ntStatus))
	{
		KdPrint(("[RegeditTest]--ZwSetValueKey  success\n"));
	}
	KdPrint(("ntStatus:0x%08x", ntStatus));

	//查询子键内容大小
	ULONG ulSize;
	ntStatus = ZwQueryValueKey
		(
		hKey,
		&ValueName,
		KeyValuePartialInformation,
		NULL, 
		0, 
		&ulSize
		);
	KdPrint(("ntStatus:0x%08x", ntStatus));
	if (STATUS_BUFFER_TOO_SMALL == ntStatus)
	{
		PKEY_VALUE_PARTIAL_INFORMATION pVaule = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(PagedPool, ulSize);
		//查询子键内容
		ntStatus = ZwQueryValueKey
			(
			hKey,
			&ValueName,
			KeyValuePartialInformation,
			pVaule, 
			ulSize, 
			&ulSize
			);
		KdPrint(("ntStatus:0x%08x", ntStatus));
	}

	ZwClose(hKey);
	hKey = NULL;
}

也可以使用Rtl系列封装函数来实现:

#pragma PAGEDCODE
VOID RtlRegeditTest()
{

	// 创建子项
	NTSTATUS ntStatus = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\Machine\\system\\hgy413");
	KdPrint(("ntStatus:0x%08x", ntStatus));

	// 确认子项是否存在
	ntStatus = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,  L"\\Registry\\Machine\\system\\hgy413");
	KdPrint(("ntStatus:0x%08x", ntStatus));

	// 写注册表
	PWCHAR szString = L"sz_Reg";
	ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\Machine\\system\\hgy413",
		L"sz_Value", REG_SZ, szString, wcslen(szString)*2+2);
	KdPrint(("ntStatus:0x%08x", ntStatus));
	
}


























posted on 2014-02-07 22:48  hgy413  阅读(467)  评论(0编辑  收藏  举报

导航