Nếu bạn đã thực hiện chế độ người dùng truy cập chương trình liên quan đến đăng ký, bạn có thể có thể đoán như thế nào để sử dụng các chức năng trong một driver.. Nếu bạn đang chạy trong
Trang 1Kỹ thuật lập trình hỗn hợp (Miscellaneous Programming
Techniques )
Bởi:
Khoa CNTT ĐHSP KT Hưng Yên
Truy cập vào Registry
Windows XP và Windows 98/Me ghi lại cấu hình và các thông tin quan trọng trong một
cơ sở dữ liệu gọi là đăng ký WDM trình điều khiển có thể gọi các chức năng được liệt
kê trong bảng 3-10 để truy cập các đăng ký Nếu bạn đã thực hiện chế độ người dùng truy cập chương trình liên quan đến đăng ký, bạn có thể có thể đoán như thế nào để sử dụng các chức năng trong một driver Tôi được tìm thấy hạt nhân-chế độ hỗ trợ đầy đủ các chức năng khác nhau, tuy nhiên, tôi nghĩ rằng giá trị của nó mô tả cách nào bạn có thể sử dụng chúng
Trang 2Trong phần này, tôi sẽ thảo luận, trong số những thứ khác, các gia đình của ZwXxx thói quen và RtlDeleteRegistryValue, mà cung cấp các chức năng cơ bản đăng ký rằng suffices cho hầu hết các trình điều khiển WDM
Mở ra một registry key
Trước khi bạn có thể interrogate giá trị trong việc đăng ký, bạn cần phải mở các khoá
có chứa chúng Bạn sử dụng vào ZwOpenKey mở một chìa khóa hiện tại ZwCreateKey bạn sử dụng để mở hoặc một trọng điểm hiện tại hoặc để tạo ra một khoá mới Hoặc chức năng cần thiết bạn đầu tiên khởi tạo một OBJECT_ATTRIBUTES cơ cấu với tên của chủ chốt và (có lẽ) các thông tin khác OBJECT_ATTRIBUTES các cấu trúc đã công bố sau đây:
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
Trang 3PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
Hơn là khởi tạo một dụ của cấu trúc này bằng tay, nó dễ để sử dụng InitializeObjectAttributes vĩ mô, mà tôi tin về bạn để hiển thị
Giả, ví dụ, rằng chúng tôi muốn mở các dịch vụ chủ chốt cho các driver của chúng tôi The I / O Trưởng đại diện cho chúng tôi tên của khoá này như là một tham số để DriverEntry Vì vậy, chúng tôi có thể viết mã như sau:
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
{
OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, RegistryPath, OBJ_KERNEL_HANDLE │
OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE hkey;
status = ZwOpenKey(&hkey, KEY_READ, &oa);
if (NT_SUCCESS(status))
{
ZwClose(hkey);
}
}
Trang 41 Chúng tôi đang bắt đầu các đối tượng thuộc tính cơ cấu pathname đăng ký với chúng tôi bằng cách cung cấp cho các I / O Trưởng đại diện và bảo mật với một NULL descriptor ZwOpenKey sẽ bỏ qua các an ninh descriptor anyway-bạn có thể xác định thuộc tính bảo mật chỉ khi bạn tạo một chìa khóa cho lần đầu tiên
2 ZwOpenKey sẽ mở khoá cho đọc và lưu trữ các kết quả xử lý của chúng tôi trong hkey biến
3 ZwClose là một thói quen chung cho đóng một để xử lý một hạt nhân-chế độ đối tượng Đây, chúng tôi sử dụng nó để đóng trình xử lý chúng tôi đã đăng ký vào chìa khóa
Các OBJ_KERNEL_HANDLE cờ, hiển thị trong mẫu mã trước, là rất quan trọng cho các hệ thống tích hợp Nếu bạn đang chạy trong bối cảnh của một người dùng sợi khi bạn gọi ZwOpenKey, và nếu bạn không cung cấp này bit, cờ, các bạn sẽ có được xử lý
sẽ được sẵn sàng cho người sử dụng chế độ xử lý Nó thậm chí có thể xảy ra rằng người
sử dụng chế độ-mã sẽ đóng trình xử lý mới và mở ra một đối tượng, lại nhận được cùng một số giá trị All of a sudden, các cuộc gọi của bạn để đăng ký chức năng sẽ được giao
dịch với các sai loại xử lý Những cách khác để mở registry phím
Ngoài ra vào ZwOpenKey, Windows XP cung cấp hai chức năng cho các phím mở đăng ký
IoOpenDeviceRegistryKey cho phép bạn mở một trong những phím đặc biệt đăng ký liên kết với một đối tượng điện thoại:
HANDLE hkey;
Status = IoOpenDeviceRegistryKey(pdo, flag, access, &hkey);
nơi pdo là địa chỉ của các đối tượng vật lý điện thoại (PDO) ở dưới cùng của trình điều khiển đặc biệt của bạn stack, cờ là một chỉ cho các khoá đặc biệt mà bạn muốn mở (xem
B ng 3-11), và truy cập là một ví dụ như mặt nạ truy cập KEY_READ
Tôi sử dụng IoOpenDeviceRegistryKey với PLUGPLAY_REGKEY_DEVICE cờ rất thường xuyên trong các trình điều khiển của riêng tôi Trong Windows XP, chức năng
Trang 5này sẽ mở ra những thiết bị subkey Các thông số của phần cứng, chìa khóa cho điện thoại Trong Windows 98/Me, nó sẽ mở ra phần cứng, chìa khóa riêng của mình Các phím được đúng nơi để lưu trữ tham số thông tin về phần cứng Tôi sẽ thảo luận này phím đầy đủ chi tiết trong Chương 15 trong kết nối với các cài đặt và phân phối một driver
IoOpenDeviceInterfaceRegistryKey sẽ mở ra các phím kết hợp với một dụ của một thiết
bị giao diện đăng ký:
HANDLE hkey;
status = IoOpenDeviceInterfaceRegistryKey(linkname, access,
&hkey);
nơi linkname là liên kết tượng trưng tên của đăng ký và truy cập vào giao diện truy cập
là một mặt nạ như KEY_READ
Bắt và cài đặt các giá trị
Thông thường, bạn mở một chìa khóa vì đăng ký mà bạn muốn, để lấy một giá trị từ cơ
sở dữ liệu Các chức năng cơ bản mà bạn sử dụng cho mục đích là ZwQueryValueKey
Ví dụ, để lấy lại giá trị trong imagePath bằng driver dịch vụ chủ chốt-Tôi thật sự không biết lý do tại sao bạn muốn biết này, nhưng đó không phải là bộ phận của tôi-bạn có thể
sử dụng các mã sau đây:
UNICODE_STRING valname;
RtlInitUnicodeString(&valname, L"ImagePath");
size = 0;
status = ZwQueryValueKey(hkey, &valname, KeyValuePartialInformation,
NULL, 0, &size);
if (status == STATUS_OBJECT_NAME_NOT_FOUND ││ size == 0)
<handle error>;
size = min(size, PAGE_SIZE);
PKEY_VALUE_PARTIAL_INFORMATION vpip =
Trang 6PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool(PagedPool, size);
if (!vpip)
<handle error>;
status = ZwQueryValueKey(hkey, &valname, KeyValuePartialInformation,
vpip, size, &size);
if (!NT_SUCCESS(status))
<handle error>;
<do something with vpip->Data>ExFreePool(vpip);
Đây, chúng tôi thực hiện hai cuộc gọi để ZwQueryValueKey Mục đích của cuộc gọi đầu tiên là để xác định bao nhiêu không gian, chúng tôi cần phải phân bổ cho các cơ cấu KEY_VALUE_PARTIAL_INFORMATION chúng tôi đang cố gắng để lấy Thứ hai, gọi truy thông tin Tôi còn lại kiểm tra các lỗi trong mã này fragment lỗi vì đã không làm việc trong thực tế ra con đường cho chúng tôi mong đợi Đặc biệt, tôi đoán rằng các bước đầu tiên để gọi ZwQueryValueKey sẽ trở lại STATUS_BUFFER_TOO_SMALL (kể từ khi tôi qua nó không-một chiều dài đệm) Nó không làm điều đó, mặc dù Quan trọng là STATUS_OBJECT_NAME_NOT_FOUND mã không thành công, cho thấy giá trị thực
sự không tồn tại Vì vậy, tôi kiểm tra cho rằng chỉ có giá trị Nếu có một số lỗi khác ngăn cản ZwQueryValueKey từ làm việc, các cuộc gọi thứ hai sẽ uncover nó
Cái được gọi là "một phần" thông tin trong cơ cấu bạn lấy bằng cách này chứa các giá trị của dữ liệu và một mô tả về một loạt các dữ liệu dạng:
typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
ULONG TitleIndex;
ULONG Type;
ULONG DataLength;
UCHAR Data[1];
} KEY_VALUE_PARTIAL_INFORMATION,
*PKEY_VALUE_PARTIAL_INFORMATION;
Trang 7Loại hình là một trong những loại dữ liệu đăng ký liệt kê trong bảng 3-12 (Các loại dữ liệu là có thể có nhưng không quan tâm đến trình điều khiển thiết bị.) DataLength là chiều dài của dữ liệu giá trị, và dữ liệu là dữ liệu riêng của mình TitleIndex không có liên quan đến trình điều khiển Dưới đây là một số dữ kiện hữu ích để biết về các loại
dữ liệu khác nhau:
• REG_DWORD là 32-bit unsigned integer ở định dạng nào (về cuối lớn hay nhỏ cuối)
là nền tảng cho tự nhiên
• REG_SZ mô tả một null-Unicode chấm dứt chuỗi giá trị The Terminator null được bao gồm trong DataLength truy cập
• Để mở rộng một REG_EXPAND_SZ có giá trị bằng cách thay biến môi trường, quý
vị nên RtlQueryRegistryValues như của bạn sử dụng phương pháp hỏi các đăng ký Nội
bộ cho các thói quen truy cập các biến môi trường không phải là tài liệu hoặc xúc cho
sử dụng bởi trình điều khiển
• RtlQueryRegistryValues cũng là một cách tốt để interrogate REG_MULTI_SZ giá trị trong đó nó sẽ gọi của bạn được xem thường gọi một lần cho mỗi phòng trong số có tiềm năng rất nhiều những dây
Chú thích:
Mặc dù, rõ ràng ích của RtlQuery ¬ RegistryValues, tôi đã được tránh bằng cách sử dụng nó bao giờ hết, vì nó sẽ gây ra vụ đụng xe trong một trong các trình điều khiển của tôi Tất nhiên, giá trị tôi đã đọc các chức năng cần thiết để gọi giúp đỡ một chức năng
đã được đặt trong sở khởi phần của hạt nhân và đã được, do đó, hiện nay không còn
Để thiết lập một giá trị đăng ký, bạn phải có KEY_SET_VALUE truy cập vào cha mẹ chìa khóa Tôi đã sử dụng KEY_READ sớm hơn, đó sẽ không cho bạn truy cập như
Trang 8vậy Bạn có thể sử dụng KEY_WRITE hay KEY_ALL_ACCESS, mặc dù bạn thu được nhiều hơn do đó cần thiết cho phép Sau đó, gọi ZwSetValueKey Ví dụ:
RtlInitUnicodeString(&valname, L"TheAnswer");
ULONG value = 42;
ZwSetValueKey(hkey, &valname, 0, REG_DWORD, &value,
sizeof(value));
Subkeys xóa hoặc giá trị
Để xóa một giá trị trong một chìa khóa mở ra, bạn có thể sử dụng RtlDeleteRegistryValue trong cách đặc biệt sau đây:
RtlDeleteRegistryValue(RTL_REGISTRY_HANDLE, (PCWSTR) hkey,
L"TheAnswer");
RtlDeleteRegistryValue nói chung là một dịch vụ có chức năng đầu tiên đối số có thể chỉ định một trong một số nơi đặc biệt trong các đăng ký Khi bạn sử dụng RTL_REGISTRY_HANDLE, như tôi đã làm trong ví dụ này, bạn chỉ ra rằng bạn đã có một mở khoá để xử lý trong vòng mà bạn muốn xóa một giá trị Bạn chỉ rõ trọng điểm (với một ném biên để làm cho hạnh phúc) như là đối số thứ hai Thứ ba, và cuối cùng là đối số-null chấm dứt Unicode tên của giá trị mà bạn muốn xóa Đây là một trong những thời gian khi bạn không có để tạo ra một cơ cấu UNICODE_STRING để mô tả chuỗi
Trong Windows 2000 và sau này, bạn có thể sử dụng ZwDeleteValueKey để xóa một giá trị (nó là một giám sát rằng chức năng này không phải là tài liệu trong DDK):
UNICODE_STRING valname;
RtlInitUnicodeString(&valname, L"TheAnswer");
RtlDeleteValueKey(hkey, &valname);
Bạn có thể xoá chỉ những phím mà bạn đã mở ra với ít nhất là cho phép XOÁ (mà bạn nhận được với KEY_ALL_ACCESS) Gọi ZwDeleteKey bạn:
ZwDeleteKey(hkey);
Chìa khóa cho đến khi cuộc sống trên tất cả các xử lý đang đóng cửa, nhưng các nỗ lực
để mở một cửa hàng mới để xử lý các phím hoặc để truy cập vào các phím bằng cách sử
Trang 9dụng bất cứ hiện đang mở xử lý sẽ không thành công với STATUS_KEY_DELETED.
Kể từ khi bạn có một mở xử lý tại điểm này, bạn cần phải chắc chắn sẽ được gọi ZwClose sometime (The DDK tài liệu hướng dẫn cho các mục nhập ZwDeleteKey nói những xử lý sẽ trở thành không hợp lệ It doesnt-bạn vẫn phải đóng nó bằng cách gọi điện thoại ZwClose.)
Enumerating Subkeys hoặc các giá trị
Một hoạt động phức tạp, bạn có thể thực hiện với một ký mở là chìa khóa để enumerate các yếu tố (subkeys và giá trị) mà có chứa chìa khóa Để làm được điều này, bạn sẽ thấy đầu tiên gọi ZwQueryKey để xác định một vài thực tế về các subkeys và các giá trị, chẳng hạn như số điện thoại của người, độ dài của tên lớn nhất, và như vậy trên ZwQueryKey có một đối số cho biết rằng đó của ba loại thông tin bạn muốn tải về các phím Các loại được đặt tên cơ bản, node, và đầy đủ Để chuẩn bị cho một Enumeration, bạn muốn được quan tâm đầu tiên trong đầy đủ thông tin:
typedef struct _KEY_FULL_INFORMATION {
LARGE_INTEGER LastWriteTime;
ULONG TitleIndex;
ULONG ClassOffset;
ULONG ClassLength;
ULONG SubKeys;
ULONG MaxNameLen;
ULONG MaxClassLen;
ULONG Values;
ULONG MaxValueNameLen;
ULONG MaxValueDataLen;
WCHAR Class[1];
} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION;
Trang 10Đây thực sự là cơ cấu của biến chiều dài từ Lớp [0] chỉ là những ký tự đầu tiên của tên lớp học It's phong tục để thực hiện một cuộc gọi để tìm hiểu cách thức lớn, một buffer bạn cần phải phân bổ và một cuộc gọi thứ hai để có được những dữ liệu, như sau: ULONG size;
ZwQueryKey(hkey, KeyFullInformation, NULL, 0, &size);
size = min(size, PAGE_SIZE);
PKEY_FULL_INFORMATION fip = (PKEY_FULL_INFORMATION)
ExAllocatePool(PagedPool, size);
ZwQueryKey(hkey, KeyFullInformation, fip, size, &size);
Bây giờ bạn đã được quan tâm trong subkeys đăng ky của bạn, bạn có thể thực hiện trong vòng lặp sau đây gọi ZwEnumerateKey:
for (ULONG i = 0; i < fip->SubKeys; ++i)
{
ZwEnumerateKey(hkey, i, KeyBasicInformation, NULL, 0, &size);
size = min(size, PAGE_SIZE);
PKEY_BASIC_INFORMATION bip = (PKEY_BASIC_INFORMATION)
ExAllocatePool(PagedPool, size);
ZwEnumerateKey(hkey, i, KeyBasicInformation, bip, size, &size);
<do something with bip->Name>
ExFreePool(bip);
}
Chìa khóa thực tế, bạn khám phá về mỗi subkey là tên của nó, mà cho thấy tính lên như
là một chuỗi Unicode trong cơ cấu KEY_BASIC_INFORMATION bạn lấy bên trong vòng lặp:
typedef struct _KEY_BASIC_INFORMATION {
Trang 11LARGE_INTEGER LastWriteTime;
ULONG Type;
ULONG NameLength;
WCHAR Name[1];
} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION
Không phải là tên null-chấm dứt, bạn phải sử dụng các NameLength thành thành viên
của các cơ cấu để xác định chiều dài của nó Đừng quên rằng trong chiều dài là byte!
Tên là không đầy đủ hoặc đường dẫn đăng ký; điều đó chỉ cần tên của subkey nào trong
vòng chìa khóa chứa nó Đây thật sự là may mắn, bởi vì bạn có thể dễ dàng mở một
subkey của nó cho một tên và xử lý để mở các bậc cha mẹ chìa khóa
Để một Enumeration của các giá trị trong một không gian mở chìa khóa, nhân viên của
các phương pháp sau đây:
ULONG maxlen = fip->MaxValueNameLen +
sizeof(KEY_VALUE_BASIC_INFORMATION);
maxlen = min(maxlen, PAGE_SIZE);
PKEY_VALUE_BASIC_INFORMATION vip = (PKEY_VALUE_BASIC_INFORMATION) ExAllocatePool(PagedPool, maxlen);
for (ULONG i = 0; i < fip->Values; ++i)
{
ZwEnumerateValueKey(hkey, i, KeyValueBasicInformation, vip,
maxlen, &size);
<do something with vip->Name>
}
ExFreePool(vip);
Trang 12Cấp cho không gian lớn nhất có thể có cấu trúc
MaxValueNameLen dựa trên các thành viên của KEY_FULL_INFORMATION cơ cấu Bên trong vòng tròn, bạn sẽ thấy muốn làm cái gì với tên của giá trị, mà sẽ đến với bạn như là một chuỗi Unicode tính trong cấu trúc này:
typedef struct _KEY_VALUE_BASIC_INFORMATION {
ULONG TitleIndex;
ULONG Type;
ULONG NameLength;
WCHAR Name[1];
} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;
Một lần nữa, có tên của một giá trị và mở để xử lý các phụ huynh là chìa khóa chỉ cần những gì bạn cần để lấy lại giá trị, như được hiển thị trong phần trước
Hiện có các biến thể trên ZwQueryKey và trên hai Enumeration chức năng mà tôi đã không được thảo luận Bạn có thể, ví dụ, có được đầy đủ thông tin về một subkey khi bạn gọi ZwEnumerateKey Tôi chỉ cho bạn làm thế nào để có được những thông tin cơ bản bao gồm các tên Bạn có thể tải dữ liệu chỉ có giá trị, hoặc tên cộng với dữ liệu giá trị, từ ZwEnumerateValueKey Tôi chỉ cho bạn làm thế nào để có được tên của một giá trị
Truy cập tập tin
It's đôi khi hữu ích để có thể đọc và viết thường xuyên đĩa file từ bên trong một trình điều khiển WDM Có lẽ bạn cần phải tải về một số tiền lớn của microcode với phần cứng của bạn, hoặc có lẽ bạn cần phải tạo riêng của bạn rộng lớn của thông tin đăng nhập cho một số mục đích Có bộ ZwXxx thói quen để giúp bạn làm được những điều đó
Kích truy cập thông qua các thói quen ZwXxx yêu cầu bạn chạy được tại PAS ¬ SIVE_LEVEL (xem chương kế tiếp) trong một sợi mà có thể an toàn bị treo Trong thực tế, các yêu cầu sau có nghĩa là bạn phải không có khuyết tật Asynchronous Thủ tục cuộc gọi (APCs) bằng cách gọi điện thoại KeEnterCriticalRegion Bạn sẽ đọc trong chương kế tiếp rằng một số đồng bộ hóa primitives yêu cầu bạn đến IRQL nâng cao trên PASSIVE_LEVEL hay để vô hiệu hoá APCs Gấu chỉ cần ghi nhớ rằng những primitives và đồng bộ hóa tập tin không tương đang truy cập