註冊表
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
釋放一些必須的資源。