注册表
10.1
注册表结构
注册表(
Registry
)——系统配置和管理中起重要作用的一个中心数据库。他的结构与注册驱动的结构是类似的,但是注册表不是静态存储在硬盘上而是在系统中动态改变的。注册表是由键组成的,存储在硬盘目录中。最高层的键被称为根键或主键。根键是一个包含其他子键
(subkeys)
或值
(values)
的容器。类似于硬盘上的文件。值用来保存合适的数据。配置管理器用来执行和管理注册表。
注册表一共有六个根键:
HKEY_USER
|
存储所有帐户的信息
;
|
HKEY_CURRENT_USER
|
存储当前登录用户的信息
;
|
HKEY_LOCAL_MACHINE
|
存储系统配置信息:硬件描述,安全策略,用户密码,系统设置,应用程序,以及服务和驱动等信息
;
|
HKEY_CURRENT_CONFIG
|
存储当前硬件配置信息
;
|
HKEY_CLASSES_ROOT
|
存储文件扩展名和组件对象模型(
COM
)的对象注册信息
;
|
HKEY_PERFORMANCE_DATA
|
存储性能相关信息
|
HKEY_PERFORMANCE_DATA
是一个特别的键,直接访问需要的信息。可以通过性能数据帮助器(
PDH, Performance Data Helper
)库,
Pdh.dll
模块来访问性能计数器信息。除了性能计数之外,这个键还包括许多其他额外信息。例如,进程功能状态(
psapi.dll
),进程列表,流操作,模块等等。这些信息都来自于键
HKEY_PERFORMANCE_DATA
。注册表编辑器regedit和regedit32没有显示这个键的内容,对他的编辑没有作用。
HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG HKEY_CLASSES_ROOT
这三个根键不包含任何的信息。实际上是与其他子键相关联的。
HKEY_CURRENT_USER
|
是
HKEY_USER
的一个子键与当前系统登录用户相关的一个子键
HKEY_CURRENT_USER,HKEY_CURRENT_CONFIG HKEY_CLASSES_ROOT
这三个根键不包含任何的信息。实际上是与其他子键相关联的。
|
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
访问注册表的驱动
下面通过内核访问注册表,访问注册表的方式跟访问其他命名对象的方式相同,或者通过命名空间控制对象(第三部分有关于这个的详细说明)。为了使命名空间注册表和控制对象配置管理器相关联,必须在注册表名下创建一个键类型对象(
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 - Creates, sets/reads and deletes registry key
;
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.386
.model flat, stdcall
option casemap:none
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; I N C L U D E F I L E S
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
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
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; R E A D O N L Y D A T A
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.const
;CCOUNTED_UNICODE_STRING "//Registry//User", g_usKeyName, 4
;CCOUNTED_UNICODE_STRING "//Registry//Machine", g_usKeyName, 4
;CCOUNTED_UNICODE_STRING "//Registry//CurrentConfig", g_usKeyName, 4
;"//Registry//User//.Default"
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
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; C O D E
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; CreateKey
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
CreateKey proc
local oa:OBJECT_ATTRIBUTES
local hKey:HANDLE
local dwDisposition:DWORD
invoke DbgPrint, $CTA0("/nRegistryWorks: *** Creating registry key/n")
; Pay attention at OBJ_KERNEL_HANDLE flag.
; It's not necessary to specify it here because we call CreateKey and other routines from DriverEntry
; running in system process context. So the handle will belong to the kernel anyway.
; But if you
抮
e running in the context of a user-mode process the OBJ_KERNEL_HANDLE must be set.
; This restricts the use of the handle to processes running only in kernel mode.
; Otherwise, the handle can be accessed by the process in whose context the driver is running.
; A process-specific handle will go away if the process terminates.
; A kernel handle doesn
抰
disappear until the operating system shuts down
; and can be used without ambiguity in any process.
InitializeObjectAttributes addr oa, addr g_usMachineKeyName, OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE, NULL, NULL
; REG_OPTION_VOLATILE means that key is not to be stored across boots.
; We don't have to specify this flag here since we'll delete the key right after it will be created
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
; A new key object was created.
invoke DbgPrint, $CTA0("RegistryWorks: Registry key //Registry//Machine//Software//CoolApp created/n")
.elseif dwDisposition == REG_OPENED_EXISTING_KEY
; An existing key object was opened.
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")
InitializeObjectAttributes addr oa, addr g_usMachineKeyName, OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE, 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")
InitializeObjectAttributes addr oa, addr g_usMachineKeyName, OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE, 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")
InitializeObjectAttributes addr oa, addr g_usMachineKeyName, OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE, 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
InitializeObjectAttributes addr oa, addr g_usUserKeyName, OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE, NULL, NULL
; Open key to enumerate subkeys
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 )
; Allocate memory for subkey name
mov eax, pbi
mov eax, (KEY_BASIC_INFORMATION PTR [eax]).NameLength
add eax, sizeof WCHAR ; place for terminating zero
mov cb, eax
invoke ExAllocatePool, PagedPool, cb
.if eax != NULL
mov pwszKeyName, eax
; Zero buffer
invoke memset, pwszKeyName, 0, cb
; The unicode-string pointed by KEY_BASIC_INFORMATION._Name
; is not null-terminated. To avoid BSOD copy it into zeroed temporary buffer.
mov ecx, pbi
mov eax, (KEY_BASIC_INFORMATION PTR [ecx]).NameLength
shr eax, 1 ; / sizeof WCHAR. NumOfBytes -> NumOfChars
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 ; next subkey
.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")
;:::::::::::::::::::::::::::::::::::::::
; Create new registry key ;
;:::::::::::::::::::::::::::::::::::::::
invoke CreateKey
;:::::::::::::::::::::::::::::::::::::::
; Set registry key value ;
;:::::::::::::::::::::::::::::::::::::::
invoke SetValueKey
;:::::::::::::::::::::::::::::::::::::::
; Query registry key value ;
;:::::::::::::::::::::::::::::::::::::::
invoke QueryValueKey
;:::::::::::::::::::::::::::::::::::::::
; Delete registry key ;
;:::::::::::::::::::::::::::::::::::::::
invoke DeleteKey
;:::::::::::::::::::::::::::::::::::::::
; Enumerating registry keys ;
;:::::::::::::::::::::::::::::::::::::::
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 and 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
禁止标志,记录已经建立的子键——硬盘上的注册表文件。这些子键在重启后清除。在这个例子中,这个标志不是必须的因为我们要删除整个子键。如果你想让这个子键永久保存,就不应该用这个标志。
.if eax == STATUS_SUCCESS
.if dwDisposition == REG_CREATED_NEW_KEY
.elseif dwDisposition == REG_OPENED_EXISTING_KEY
.endif
通过对这个函数
ZwCreateKey
的成功调用,通过这个变量
dwDisposition
是否等于
REG_CREATED_NEW_KEY
表示创建一个新建
,
或等于
REG_CREATED_NEW_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
包含
unicode
零字符串行,我们用这个行来存储调试信息,因此要转换为
ansi
。
invoke RtlInitUnicodeString, addr us, eax
这个函数
RtlInitUnicodeString
的第二个参数指向一个
unicode
字符串地址,并且填充第一个参数指向的
UNICODE_STRING
结构。
invoke RtlUnicodeStringToAnsiString, addr as, addr us, TRUE
这个函数
RtlUnicodeStringToAnsiString
将
unicode
字符串行转为
ansi
。如果最后一个参数是
TRUE
,函数自己会提供一个缓冲区。函数会写这行并填充
ANSI_STRING
结构(在这个例子中作为一个变量)。
ANSI_STRING
结构缓冲区在被选折的缓冲区中列出转换后的
ansi
行。如果最后一个参数设置为
FALSE
指向当前选折的
ansi
行缓冲区并把这个地址赋值给
ANSI_STRING
结构中的缓冲区。在这个例子中我们要求这个函数分配一个缓冲区为我们。
.if eax == STATUS_SUCCESS
invoke DbgPrint, /
$CTA0("RegistryWorks: Registry key value is: /=%s/=/n"), as.Buffer
invoke RtlFreeAnsiString, addr as
.endif
在
DDK
中(至少在
2000
的
DDK
中)
RtlUnicodeStringToAnsiString
函数的描述是非常模糊的,我甚至说是不明确的。如果
DDK
描述的更好。让我们看一个简单的例子。
wsz db 'a', 0, 'b', 0, 'c', 0, 0, 0
us UNICODE_STRING <>
as ANSI_STRING <>
初始化我们的变量,
wsz
是
unicode
字符串行,将会被转化为
ANSI
格式。
us._Length = ?
us.MaximumLength = ?
us.Buffer = ?
as._Length = ?
as.MaximumLength = ?
as.Buffer = ?
RtlInitUnicodeString
填充
us
变量根据
wsz
行的大小。
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
开始转换这行。如果这个操作成功,这个变量将要包转换字符串的所有的描述。
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
; pointer to the selected feature RtlUnicodeStringToAnsiString,,,TRUE
; buffer, which contains the converted string wsz in ANSI format.
RtlUnicodeStringToAnsiString
函数分配的缓冲区利用后必须调用
RtlFreeAnsiString
释放,作为指向
ANSI_STRING
结构的指针不能传递指针指向自己的缓冲区。
RtlFreeAnsiString
释放缓冲区
as.Buffer
。
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 )
ZwEnumerateKey
函数用
KeyBasicInformation
类型信息。跟以前一样调用两次:第一次获得数量,第二次获得具体的信息。
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
结构中,值的类型
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
释放一些必须的资源。