Kmdtut 10---注册表
转自:http://www.gomb.cn/?uid-2-action-viewspace-itemid-1457
10.1 注册表的结构
10.2 在驱动程序中访问注册表
10.3 RegistryWorks驱动程序源代码
10.3.1 注册表键的创建与打开
10.3.2 创建注册表键值
10.3.3 访问注册表键值
10.3.4 删除注册表键
10.3.5 更新注册表键
源代码: KmdKit/examples/basic/RegistryWorks
10.1 注册表的结构
注册表(Registry)是基本数据的中心,在系统的设置和管理方面扮演着重要的角色。注册表的结构类似于磁盘的逻辑结构,但是注册表的内容不是磁盘数据的静态组合,而是随系统的工作进程而动态改变。注册表由keys构成,键就像磁盘的目录。最上层的keys叫做root keys。keys本身就是一个容器,装着其它的keys,装在里面的这些keys叫做subkeys或是values,就像磁盘上的文件。values保存着实际数据。对注册表的操作与管理是由Configuration Manager负责的。
root keys有六个:
HKEY_USER
包含所有注册信息;
HKEY_CURRENT_USER
保存着当前用户的注册信息;
HKEY_LOCAL_MACHINE
保存着系统配置信息:硬件设备支持记录,安全策略,用户口令,应用程序设置和服务及驱动程序配置。
HKEY_CURRENT_CONFIG
包含当前硬件配置信息;
HKEY_CLASSES_ROOT
保存着文件关联和COM类的注册数据;
HKEY_PERFORMANCE_DATA
包含着性能信息。
HKEY_PERFORMANCE_DATA 是一个特殊的键,未必会直接用到。在用户模式下,关于性能统计的信息是通过Performance Data Helper库来访问的,这个库实现在模块pdh.dll里。标准程序Performance Monitor正是利用了这个库。除性能统计之外这个键还包含着许多补充信息。例如,用于枚举进程、线程和模块等等的Process Status函数(在psapi.dll里实现)正是从HKEY_PERFORMANCE_DATA键中获得的信息。注册表编辑器Regedit和Regedt32并不能显示出这个键的内容,因此无法编辑。
根键HKEY_CURRENT_USER、HKEY_CURRENT_CONFIG和HKEY_CLASSES_ROOT并不包含什么信息。它们只是链接到注册表其它的子键。
HKEY_CURRENT_USER
链接到子键HKEY_USER/<SID_当前用户> 系统用户中对应于当前用户的注册信息。
HKEY_CURRENT_CONFIG
链接到子键HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Hardware Profiles/Current.
HKEY_CLASSES_ROOT
链接到子键HKEY_LOCAL_MACHINE/SOFTWARE/Classes和HKEY_CURRENT_USER/SOFTWARE/Classes.
10.2 在驱动程序中访问注册表
如何在内核模式下访问注册表?对注册表的访问和访问其它命名对象完全相同,即通过对象管理器的名字空间(详细方法见第三章)来访问。为了将注册表名字空间与对象管理器名字空间集成起来,配置管理器(Configuration Manager)在建立了一个名为“Registry”注册键类型的对象(key object)并将其放在对象管理器名字空间的根目录下。对于内核模式组件,有进入注册表的入口点。
所有的内核函数,对命名对象的访问要获得其名称,这个名称位于结构体OBJECT_ATRIBUTES的一个成员中,这个我们以前就知道了。如果对象类型为注册表键,则对象名字应该起始于“/Registry”。我要说的是,我不知道打开HKEY_PERFORMANCE_DATA根键要用什么名字,以及更一般的说,对某个键要用哪个名字。我在这方面作出过努力,但都是白费。如果您了解这方面的东西,还请您教我一下。有两个根键还算简单。
键 名称
HKEY_USER "/Registry/User"
HKEY_LOCAL_MACHINE "/Registry/Machine"
对于三个链接到其它地方的键还需要额外的操作。比如说,操作HKEY_CURRENT_CONFIG键需要知道它链接到了子键HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Hardware Profiles/Current上并用这个根键名字代替。这样就得到了/Registry/Machine/SYSTEM/CurrentControlSet/Hardware Profiles/Current这个名字。很可惜,我们不能使用CTW0和$CTW0宏来定义这个长长的unicode字符串,这个字符串超出了47个符号的限制。对此您可以用自己的方案来解决。
10.3 RegistryWorks驱动程序源代码
现在,当我们熟知根键名字的时候,理解它们就不会太困难。
;@echo off
;goto make
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
; RegistryWorks - Пример работы с реестром
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.386
.model flat, stdcall
option casemap:none
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; В К Л Ю Ч А Е М Ы Е Ф А Й Л Ы
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
include /masm32/include/w2k/ntstatus.inc
include /masm32/include/w2k/ntddk.inc
include /masm32/include/w2k/ntoskrnl.inc
includelib /masm32/lib/w2k/ntoskrnl.lib
include /masm32/Macros/Strings.mac
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; Н Е И З М Е Н Я Е М Ы Е Д А Н Н Ы Е
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.const
CCOUNTED_UNICODE_STRING "//Registry//Machine//Software//CoolApp", g_usMachineKeyName, 4
CCOUNTED_UNICODE_STRING "SomeData", g_usValueName, 4
CTW0 "It's just a string", g_wszStringData, 4
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; К О Д
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; CreateKey
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
CreateKey proc
local oa:OBJECT_ATTRIBUTES
local hKey:HANDLE
local dwDisposition:DWORD
invoke DbgPrint, $CTA0("/nRegistryWorks: *** Creating registry key/n")
lea ecx, oa
InitializeObjectAttributes ecx, offset g_usMachineKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL
invoke ZwCreateKey, addr hKey, KEY_WRITE, addr oa, 0, NULL, /
REG_OPTION_VOLATILE, addr dwDisposition
.if eax == STATUS_SUCCESS
.if dwDisposition == REG_CREATED_NEW_KEY
invoke DbgPrint, /
$CTA0("RegistryWorks: Registry key //Registry//Machine//Software//CoolApp created/n")
.elseif dwDisposition == REG_OPENED_EXISTING_KEY
invoke DbgPrint, /
$CTA0("RegistryWorks: Registry key //Registry//Machine//Software//CoolApp opened/n")
.endif
invoke ZwClose, hKey
invoke DbgPrint, $CTA0("RegistryWorks: Registry key handle closed/n")
.else
invoke DbgPrint, $CTA0("RegistryWorks: Can't create registry key. Status: %08X/n"), eax
.endif
ret
CreateKey endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; SetValueKey
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
SetValueKey proc
local oa:OBJECT_ATTRIBUTES
local hKey:HANDLE
invoke DbgPrint, $CTA0("/nRegistryWorks: *** Opening registry key to set new value/n")
lea ecx, oa
InitializeObjectAttributes ecx, offset g_usMachineKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL
invoke ZwOpenKey, addr hKey, KEY_SET_VALUE, ecx
.if eax == STATUS_SUCCESS
invoke DbgPrint, $CTA0("RegistryWorks: Registry key openeded/n")
invoke ZwSetValueKey, hKey, addr g_usValueName, 0, REG_SZ, /
addr g_wszStringData, sizeof g_wszStringData
.if eax == STATUS_SUCCESS
invoke DbgPrint, $CTA0("RegistryWorks: Registry key value added/n")
.else
invoke DbgPrint, /
$CTA0("RegistryWorks: Can't set registry key value. Status: %08X/n"), eax
.endif
invoke ZwClose, hKey
invoke DbgPrint, $CTA0("RegistryWorks: Registry key handle closed/n")
.else
invoke DbgPrint, $CTA0("RegistryWorks: Can't open registry key. Status: %08X/n"), eax
.endif
ret
SetValueKey endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; QueryValueKey
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
QueryValueKey proc
local oa:OBJECT_ATTRIBUTES
local hKey:HANDLE
local cb:DWORD
local ppi:PKEY_VALUE_PARTIAL_INFORMATION
local as:ANSI_STRING
local us:UNICODE_STRING
invoke DbgPrint, $CTA0("/nRegistryWorks: *** Opening registry key to read value/n")
lea ecx, oa
InitializeObjectAttributes ecx, offset g_usMachineKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL
invoke ZwOpenKey, addr hKey, KEY_QUERY_VALUE, ecx
.if eax == STATUS_SUCCESS
invoke DbgPrint, $CTA0("RegistryWorks: Registry key openeded/n")
invoke ZwQueryValueKey, hKey, addr g_usValueName, /
KeyValuePartialInformation, NULL, 0, addr cb
.if cb != 0
invoke ExAllocatePool, PagedPool, cb
.if eax != NULL
mov ppi, eax
invoke ZwQueryValueKey, hKey, addr g_usValueName, /
KeyValuePartialInformation, ppi, cb, addr cb
.if ( eax == STATUS_SUCCESS ) && ( cb != 0 )
mov eax, ppi
.if [KEY_VALUE_PARTIAL_INFORMATION PTR [eax]]._Type == REG_SZ
lea eax, (KEY_VALUE_PARTIAL_INFORMATION PTR [eax]).Data
invoke RtlInitUnicodeString, addr us, eax
invoke RtlUnicodeStringToAnsiString, addr as, addr us, TRUE
.if eax == STATUS_SUCCESS
invoke DbgPrint, /
$CTA0("RegistryWorks: Registry key value is: /=%s/=/n"), as.Buffer
invoke RtlFreeAnsiString, addr as
.endif
.endif
.else
invoke DbgPrint, /
$CTA0("RegistryWorks: Can't query registry key value. Status: %08X/n"), eax
.endif
invoke ExFreePool, ppi
.else
invoke DbgPrint, $CTA0("RegistryWorks: Can't allocate memory. Status: %08X/n"), eax
.endif
.else
invoke DbgPrint, /
$CTA0("RegistryWorks: Can't get bytes count needed for key partial information. Status: %08X/n"), eax
.endif
invoke ZwClose, hKey
invoke DbgPrint, $CTA0("RegistryWorks: Registry key handle closed/n")
.else
invoke DbgPrint, $CTA0("RegistryWorks: Can't open registry key. Status: %08X/n"), eax
.endif
ret
QueryValueKey endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; DeleteKey
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
DeleteKey proc
local oa:OBJECT_ATTRIBUTES
local hKey:HANDLE
invoke DbgPrint, $CTA0("/nRegistryWorks: *** Deleting registry key/n")
lea ecx, oa
InitializeObjectAttributes ecx, offset g_usMachineKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL
invoke ZwOpenKey, addr hKey, KEY_ALL_ACCESS, ecx
.if eax == STATUS_SUCCESS
invoke DbgPrint, $CTA0("RegistryWorks: Registry key opened/n")
invoke ZwDeleteKey, hKey
.if eax == STATUS_SUCCESS
invoke DbgPrint, $CTA0("RegistryWorks: Registry key deleted/n")
.else
invoke DbgPrint, $CTA0("RegistryWorks: Can't delete registry key. Status: %08X/n"), eax
.endif
invoke ZwClose, hKey
invoke DbgPrint, $CTA0("RegistryWorks: Registry key handle closed/n")
.else
invoke DbgPrint, $CTA0("RegistryWorks: Can't open registry key. Status: %08X/n"), eax
.endif
ret
DeleteKey endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; EnumerateKey
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
EnumerateKey proc
local oa:OBJECT_ATTRIBUTES
local hKey:HANDLE
local cb:DWORD
local pbi:PKEY_BASIC_INFORMATION
local pfi:PKEY_FULL_INFORMATION
local as:ANSI_STRING
local us:UNICODE_STRING
local dwSubKeys:DWORD
local pwszKeyName:PWCHAR
invoke DbgPrint, $CTA0("/nRegistryWorks: *** Opening //Registry//User key to enumerate/n")
CCOUNTED_UNICODE_STRING "//Registry//User", g_usUserKeyName, 4
lea ecx, oa
InitializeObjectAttributes ecx, offset g_usUserKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL
invoke ZwOpenKey, addr hKey, KEY_ENUMERATE_SUB_KEYS, ecx
.if eax == STATUS_SUCCESS
invoke DbgPrint, $CTA0("RegistryWorks: Registry key openeded/n")
invoke ZwQueryKey, hKey, KeyFullInformation, NULL, 0, addr cb
.if cb != 0
invoke ExAllocatePool, PagedPool, cb
.if eax != NULL
mov pfi, eax
invoke ZwQueryKey, hKey, KeyFullInformation, pfi, cb, addr cb
.if ( eax == STATUS_SUCCESS ) && ( cb != 0 )
mov eax, pfi
push (KEY_FULL_INFORMATION PTR [eax]).SubKeys
pop dwSubKeys
invoke DbgPrint, /
$CTA0("RegistryWorks: ---------- Starting enumerate subkeys ----------/n")
push ebx
xor ebx, ebx
.while ebx < dwSubKeys
invoke ZwEnumerateKey, hKey, ebx, KeyBasicInformation, NULL, 0, addr cb
.if cb != 0
invoke ExAllocatePool, PagedPool, cb
.if eax != NULL
mov pbi, eax
invoke ZwEnumerateKey, hKey, ebx, KeyBasicInformation, pbi, cb, addr cb
.if ( eax == STATUS_SUCCESS ) && ( cb != 0 )
mov eax, pbi
mov eax, (KEY_BASIC_INFORMATION PTR [eax]).NameLength
add eax, sizeof WCHAR
mov cb, eax
invoke ExAllocatePool, PagedPool, cb
.if eax != NULL
mov pwszKeyName, eax
invoke memset, pwszKeyName, 0, cb
mov ecx, pbi
mov eax, (KEY_BASIC_INFORMATION PTR [ecx]).NameLength
shr eax, 1
lea ecx, (KEY_BASIC_INFORMATION PTR [ecx])._Name
invoke wcsncpy, pwszKeyName, ecx, eax
invoke RtlInitUnicodeString, addr us, pwszKeyName
invoke RtlUnicodeStringToAnsiString, addr as, addr us, TRUE
.if eax == STATUS_SUCCESS
invoke DbgPrint, $CTA0("RegistryWorks: /=%s/=/n"), as.Buffer
invoke RtlFreeAnsiString, addr as
.endif
invoke ExFreePool, pwszKeyName
.endif
.else
invoke DbgPrint, /
$CTA0("RegistryWorks: Can't enumerate registry keys. Status: %08X/n"), eax
.endif
invoke ExFreePool, pbi
.endif
.endif
inc ebx
.endw
pop ebx
invoke DbgPrint, /
$CTA0("RegistryWorks: ------------------------------------------------/n")
.else
invoke DbgPrint, /
$CTA0("RegistryWorks: Can't query registry key information. Status: %08X/n"), eax
.endif
invoke ExFreePool, pfi
.else
invoke DbgPrint, $CTA0("RegistryWorks: Can't allocate memory. Status: %08X/n"), eax
.endif
.endif
invoke ZwClose, hKey
invoke DbgPrint, $CTA0("RegistryWorks: Registry key handle closed/n")
.else
invoke DbgPrint, $CTA0("RegistryWorks: Can't open registry key. Status: %08X/n"), eax
.endif
ret
EnumerateKey endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; DriverEntry
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
invoke DbgPrint, $CTA0("/nRegistryWorks: Entering DriverEntry/n")
;:::::::::::::::::::::::::::::::::::::::
; Создаём новый подраздел ;
;:::::::::::::::::::::::::::::::::::::::
invoke CreateKey
;:::::::::::::::::::::::::::::::::::::::
; Создаем в этом подразделе параметр ;
;:::::::::::::::::::::::::::::::::::::::
invoke SetValueKey
;:::::::::::::::::::::::::::::::::::::::
; Получаем значение параметра ;
;:::::::::::::::::::::::::::::::::::::::
invoke QueryValueKey
;:::::::::::::::::::::::::::::::::::::::
; Удаляем подраздел ;
;:::::::::::::::::::::::::::::::::::::::
invoke DeleteKey
;:::::::::::::::::::::::::::::::::::::::
; Перечисляем содержимое раздела ;
;:::::::::::::::::::::::::::::::::::::::
invoke EnumerateKey
invoke DbgPrint, $CTA0("/nRegistryWorks: Leaving DriverEntry/n")
mov eax, STATUS_DEVICE_CONFIGURATION_ERROR
ret
DriverEntry endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
end DriverEntry
:make
set drv=RegistryWorks
/masm32/bin/ml /nologo /c /coff %drv%.bat
/masm32/bin/link /nologo /driver /base:0x10000 /align:32 /out:%drv%.sys /subsystem:native %drv%.obj
del %drv%.obj
echo.
pause
驱动程序的代码由几个独立的函数构成:CreateKey、SetValueKey、QueryValueKey、DeleteKey和EnumerateKey,每一个都是“从零开始”操作注册表的,对于学习来说,例子总是最直观的。
10.3.1 注册表键的创建与打开
在CreateKey函数中调用了函数ZwCreateKey,建立新的Registry/Machine/Software/CoolApp键。
invoke ZwCreateKey, addr hKey, KEY_WRITE, addr oa, 0, NULL, REG_OPTION_VOLATILE, addr dwDisposition
标志REG_OPTION_VOLATILE不准将建立的子键写入hive——磁盘上的一个注册表文件。这样这个子键只存在到系统下一次加载。在本例中,并不一定非要使用这个标志,我们可以自己删除所有子键。如果想在注册表中较长时间注册这个子键,就不要用这个标志了。
.if eax == STATUS_SUCCESS
.if dwDisposition == REG_CREATED_NEW_KEY
.elseif dwDisposition == REG_OPENED_EXISTING_KEY
.endif
在成功调用ZwCreateKey后,变量dwDisposition的值定义了是否已创建新的子键(REG_CREATED_NEW_KEY),要是这个子键已在注册表中存在(REG_OPENED_EXISTING_KEY),就已被打开。
invoke ZwOpenKey, addr hKey, KEY_SET_VALUE, ecx
invoke ZwOpenKey, addr hKey, KEY_QUERY_VALUE, ecx
invoke ZwOpenKey, addr hKey, KEY_ALL_ACCESS, ecx
invoke ZwOpenKey, addr hKey, KEY_ENUMERATE_SUB_KEYS, ecx
在剩下的函数中,我们调用ZwOpenKey函数来打开已经存在的键,对相应的访问类型只使用相应的标志。
10.3.2 创建注册表键值
现在,我们来在我们的子键里创建一个字符串键值“SomeData”。
. . .
CCOUNTED_UNICODE_STRING "SomeData", g_usValueName, 4
CTW0 "It's just a string", g_wszStringData, 4
. . .
invoke ZwSetValueKey, hKey, addr g_usValueName, 0, REG_SZ, /
addr g_wszStringData, sizeof g_wszStringData
常量REG_SZ定义了所创建键值的类型:以零结尾的unicode字符串。系统还有许多其它的类型——DDK中有详细描述。
10.3.3 访问注册表键值
我们来获取我们的SomeData的值。
invoke ZwQueryValueKey, hKey, addr g_usValueName, /
KeyValuePartialInformation, NULL, 0, addr cb
函数ZwQueryValueKey的第三个参数定义了请求信息的类型。在DDK中定义了三种值:KeyValueBasicInformation、KeyValueFullInformation 和KeyValuePartialInformation,每一个值都有自己相应的结构体:KEY_VALUE_BASIC_INFORMATION、KEY_VALUE_FULL_INFORMATION和KEY_VALUE_PARTIAL_INFORMATION。在本例中,我们想获得键值的内容。对此KeyValuePartialInformation完全适合。
我们事先不知道所获取信息的大小,所以我们调用ZwQueryValueKey时,第四第五个参数分别使用NULL(缓冲区指针)和0(缓冲区大小)。函数ZwQueryValueKey计并算出缓冲区所需的大小并将这个值返回到变量cb中(很多但非全部的Zw*函数都是这个样子处理的)。
.if cb != 0
invoke ExAllocatePool, PagedPool, cb
.if eax != NULL
mov ppi, eax
invoke ZwQueryValueKey, hKey, addr g_usValueName, /
KeyValuePartialInformation, ppi, cb, addr cb
分配必需的内存空间,再次调用ZwQueryValueKey——现在已经有缓冲区指针了。
.if ( eax == STATUS_SUCCESS ) && ( cb != 0 )
mov eax, ppi
.if [KEY_VALUE_PARTIAL_INFORMATION PTR [eax]]._Type == REG_SZ
在任何情况下,我们都要检查键值类型。
lea eax, (KEY_VALUE_PARTIAL_INFORMATION PTR [eax]).Data
如果是REG_SZ类型的键值,则KEY_VALUE_PARTIAL_INFORMATION结构体的Data域就包含了以零结尾的unicode字符串。我们需要在调试信息中输出这个字符串,所以要将它转换为ansi字符串。
invoke RtlInitUnicodeString, addr us, eax
函数RtlInitUnicodeString初始化unicode字符串,其地址在第二个参数中,并填充UNICODE_STRING结构体,其地址在第一个参数中。
invoke RtlUnicodeStringToAnsiString, addr as, addr us, TRUE
函数RtlUnicodeStringToAnsiString将unicode字符串转换为ansi字符串。如果最后的参数设置为TRUE,则函数自己分配缓冲区,向那里写入转换的字符串并填充ANSI_STRING结构体(在我们这里是变量as)。ANSI_STRING的Buffer域将指向所分配的装有转换好的ansi字符串的缓冲区。如果最后一个参数为FALSE,则用于保存ansi字符串的缓冲区就需要事先分配好并将指针放在我们的ANSI_STRING结构体的Buffer域中。在本例中,我们让RtlUnicodeStringToAnsiString函数为我们分配缓冲区。
.if eax == STATUS_SUCCESS
invoke DbgPrint, /
$CTA0("RegistryWorks: Registry key value is: /=%s/=/n"), as.Buffer
invoke RtlFreeAnsiString, addr as
.endif
DDK描述了RtlUnicodeStringToAnsiString函数,而我却昏了头,说得模模糊糊的。IFS DDK更好的描述了这个函数的操作。为了处理“i上面的一点”我们来看个简单的例子。
wsz db 'a', 0, 'b', 0, 'c', 0, 0, 0
us UNICODE_STRING <>
as ANSI_STRING <>
变量us和as最初没有定义。wsz为unicode字符串,要被转换为ANSI格式。
us._Length = ?
us.MaximumLength = ?
us.Buffer = ?
as._Length = ?
as.MaximumLength = ?
as.Buffer = ?
RtlInitUnicodeString 用字符串wsz的大小填充变量us。
invoke RtlInitUnicodeString, addr us, addr wsz
us._Length = 6
us.MaximumLength = 8
us.Buffer = offset wsz
as._Length = ?
as.MaximumLength = ?
as.Buffer = ?
从RtlUnicodeStringToAnsiString的最后一个参数可以看到,它分配的缓冲区大小应该为us.MaximumLength / sizeof WCHAR。分配缓冲区并将指针放在域as.Buffer中后,函数RtlUnicodeStringToAnsiString开始真正转换字符串。如果这个操作成功完成,则变量as将包含转换好的字符串的完整的描述。
invoke RtlUnicodeStringToAnsiString, addr as, addr us, TRUE
us._Length = 6
us.MaximumLength = 8
us.Buffer = offset wsz
as._Length = 3
as.MaximumLength = 4
as.Buffer = -> 'a', 'b', 'c', 0 ; 指向RtlUnicodeStringToAnsiString,,,TRUE函数分配的缓冲区的指针
; 缓冲区包含有转换为ANCI格式的wsz字符串的
在使用了RtlUnicodeStringToAnsiString函数分配的缓冲区之后,还需要调用RtlFreeAnsiString释放掉它。而且充当其参数的不是指向函数自己缓冲区的指针,而是指向ANSI_STRING结构体的指针。
RtlFreeAnsiString释放掉缓冲区as.Buffer并清零变量as。
invoke RtlFreeAnsiString, addr as
us._Length = 6
us.MaximumLength = 8
us.Buffer = offset wsz
as._Length = 0
as.MaximumLength = 0
as.Buffer = NULL
现在应该全明白了吧。
10.3.4 删除注册表键
我想,这部分不用我讲您也能搞定。
10.3.5 更新注册表键
现在我们来看/Registry/User键下都有些什么。
invoke ZwQueryKey, hKey, KeyFullInformation, NULL, 0, addr cb
.if cb != 0
invoke ExAllocatePool, PagedPool, cb
.if eax != NULL
mov pfi, eax
invoke ZwQueryKey, hKey, KeyFullInformation, pfi, cb, addr cb
.if ( eax == STATUS_SUCCESS ) && ( cb != 0 )
mov eax, pfi
push (KEY_FULL_INFORMATION PTR [eax]).SubKeys
pop dwSubKeys
要组织键的内容就需要知道其下子键/键值的数量。对此我们要使用KeyFullInformation信息类。分配必需的内存并将它传给ZwQueryKey,我们就在变量dwSubKeys中得到了子键/键值的数量。
push ebx
xor ebx, ebx
.while ebx < dwSubKeys
invoke ZwEnumerateKey, hKey, ebx, KeyBasicInformation, NULL, 0, addr cb
.if cb != 0
invoke ExAllocatePool, PagedPool, cb
.if eax != NULL
mov pbi, eax
invoke ZwEnumerateKey, hKey, ebx, KeyBasicInformation, pbi, cb, addr cb
.if ( eax == STATUS_SUCCESS ) && ( cb != 0 )
我们在一个循环中使用KeyBasicInformation信息类来调用ZwEnumerateKey。就像前面那样,我们对其调用两次,第一次是为了得知信息的大小,第二次是为了获得这项信息本身。
mov eax, pbi
mov eax, (KEY_BASIC_INFORMATION PTR [eax]).NameLength
add eax, sizeof WCHAR
mov cb, eax
invoke ExAllocatePool, PagedPool, cb
在KEY_BASIC_INFORMATION结构体的_Name域返回的是子键/键值的名称,其形式为unicode字符串,但是这个字符串不是以零结尾的。为了在后面将其转换为ansi字符串(为了在调试信息中输出),我们应该将其完善——为其分配一个临时缓冲区。
.if eax != NULL
mov pwszKeyName, eax
invoke memset, pwszKeyName, 0, cb
mov ecx, pbi
mov eax, (KEY_BASIC_INFORMATION PTR [ecx]).NameLength
shr eax, 1
lea ecx, (KEY_BASIC_INFORMATION PTR [ecx])._Name
invoke wcsncpy, pwszKeyName, ecx, eax
将临时缓冲区清零,并向其中拷贝子键/键值的名称。
invoke RtlInitUnicodeString, addr us, pwszKeyName
invoke RtlUnicodeStringToAnsiString, addr as, addr us, TRUE
.if eax == STATUS_SUCCESS
invoke DbgPrint, $CTA0("RegistryWorks: /=%s/=/n"), as.Buffer
invoke RtlFreeAnsiString, addr as
.endif
我们来做必要的处理并在调试信息中输出子键/键值的名称。
invoke ExFreePool, pwszKeyName
.endif
.endif
invoke ExFreePool, pbi
.endif
.endif
inc ebx
.endw
pop ebx
.endif
invoke ExFreePool, pfi
.endif
.endif
进行必要的资源回收。
Kmdtut 10---注册表相关推荐
- Windows 10注册表
Windows 10注册表 一.注册表:记录系统和用户配置信息的文件 早期注册表:95以前版本为早期注册表,以ini 为扩展名的配置文件.(system.ini和win.ini) 注册表:由多个文件组 ...
- Windows 10注册表损坏怎么办?
注册表是一个复杂的数据库,如果不进行维护,它就会填充损坏的和孤立的注册表项.尤其是对Windows进行升级时,损坏或丢失的注册表项也会不断累积,从而影响您的系统性能.如果您的Windows 10系统正 ...
- win10误删的注册表能还原吗_Win10系统下恢复注册表项的技巧
如果需要还原或合并一个或多个注册表设置,可以使用以下步骤: --打开开始. --搜索regedit,右键单击最高结果,然后选择"以管理员身份运行"选项. --单击"文件& ...
- JCheckBox 默认选择_[注册表] 将Windows 10默认应用程序设置页面添加到桌面右键菜单中...
从Windows 10初始版本开始微软就已调整默认程序配置策略,即强制用户设置关联的默认程序不允许软件设置.这也是很多用户经常在通知栏里看到某某文件格式被重置的原因,因为软件安装后设置的会被微软重置默 ...
- 如果你不喜欢Windows 11开始菜单,还可以用注册表换回Windows 10样式
泄露的镜像表明微软将Windows 11开始菜单换成 Windows 10X 版的样式,即任务栏居中且开始菜单默认层叠. 蓝点网使用的体验就是感觉还可以,就是层叠后的菜单每次想要转到所有菜单列表必须再 ...
- 关闭惠普计算机通电启动注册表,惠普10代cpu电脑装win7卡logo(安装程序正在更新注册表设置)解决方法...
最近有很多网友问我惠普电脑10代cpu台式机安装win7卡在在更新注册表设置怎么办?出现这种情况一般情况是由于没有提前注入显卡驱动,现在很多新电脑都采用的集成显卡,10代以cpu采用的集显的话,在ue ...
- 注册表把html设置成桌面,[注册表] 将Windows 10默认应用程序设置页面添加到桌面右键菜单中...
从Windows 10初始版本开始微软就已调整默认程序配置策略,即强制用户设置关联的默认程序不允许软件设置. 这也是很多用户经常在通知栏里看到某某文件格式被重置的原因,因为软件安装后设置的会被微软重置 ...
- 10#Windows注册表的那些事儿
引言 用了多年的Windows系统,其实并没有对Windows系统进行过深入的了解,也正是由于Windows系统不用深入了解就可以简单上手所以才有这么多人去使用.笔者是做软件开发的,使用的基本都是Wi ...
- 组策略 计算机 用户账户控制,Windows 10 (用户帐户控制组策略和注册表) - Microsoft 365 Security | Microsoft Docs...
用户帐户控制组策略和注册表项设置 04/19/2017 本文内容 适用范围 Windows 10 Windows Server 2016 组策略设置 UAC 管理中心可以配置 10 个组策略 (用户帐 ...
- oracle一直在更新注册表,联想10代cpu电脑装win7后卡在正在更新注册表设置解决方法...
[文章导读]最近有很多网友问我联想电脑10代cpu台式机安装win7卡在在更新注册表设置怎么办?出现这种情况一般情况是由于没有提前注入显卡驱动,现在很多新电脑都采用的集成显卡,10代以cpu采用的集显 ...
最新文章
- poj 1981(单位圆覆盖点)
- OpenGL springmass弹簧质量模拟器的实例
- HDU4604(双端队列与DP)
- “SHOT NOTE”新文具,构建虚实之桥
- python制作远程桌面控制_Python 远程桌面协议RDPY简介
- mysql zpi版的如何配置_Mysql zip版 安装配置
- swoole php input,介绍swoole异步群发模板消息
- win10 家庭版系统,创建用户(users\account\ 中,文件的「所有者」属性)
- 【大数据】0001---使用SparkSQL关联两个表求和取前几行
- ansys2017安装教程_ANSYS Student
- (苹果Mac OSX系统)绿联USB无法连接网络解决方案
- 分享两个开源的成品项目,一个视频播放器,一个音乐播放器!
- 西门子802d数控立式加工中心智能调节参数
- CSS特效--图像悬停效果
- 修改 exchange服务器地址,绑定exchange邮箱服务器地址
- 用Visio画UML顺序图
- [vue学习笔记]数组+事件+v-model的使用
- 网络期刊(个人使用)
- C语言中task的用法,c – 在std :: packaged_task中使用成员函数
- BigDecimal 往左移动两位小数_移动信号灯