تحديد المسار إلى مفتاح التسجيل من مقبض HKEY في C ++

StackOverflow https://stackoverflow.com/questions/937044

  •  06-09-2019
  •  | 
  •  

سؤال

نظرا لمقبس تسجيل Windows، مثل تلك التي يتم تعيينها بواسطة :: RegoPenKeyex ()، هل من الممكن تحديد المسار الكامل لهذا المفتاح؟

أدرك أنه في تطبيق بسيط، كل ما عليك فعله هو البحث عن 5 أو 10 خطوط وقراءة ... ولكن في تطبيق معقد مثل تصحيح الأخطاء، يمكن فتح المفتاح الذي يهمني من سلسلة من المكالمات.

هل كانت مفيدة؟

المحلول

يستخدم LoadLibrary و NtQueryKey وظيفة تصدير كما في مقتطف التعليمات البرمجية التالية.

#include <windows.h>
#include <string>

typedef LONG NTSTATUS;

#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif

#ifndef STATUS_BUFFER_TOO_SMALL
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#endif

std::wstring GetKeyPathFromKKEY(HKEY key)
{
    std::wstring keyPath;
    if (key != NULL)
    {
        HMODULE dll = LoadLibrary(L"ntdll.dll");
        if (dll != NULL) {
            typedef DWORD (__stdcall *NtQueryKeyType)(
                HANDLE  KeyHandle,
                int KeyInformationClass,
                PVOID  KeyInformation,
                ULONG  Length,
                PULONG  ResultLength);

            NtQueryKeyType func = reinterpret_cast<NtQueryKeyType>(::GetProcAddress(dll, "NtQueryKey"));

            if (func != NULL) {
                DWORD size = 0;
                DWORD result = 0;
                result = func(key, 3, 0, 0, &size);
                if (result == STATUS_BUFFER_TOO_SMALL)
                {
                    size = size + 2;
                    wchar_t* buffer = new (std::nothrow) wchar_t[size/sizeof(wchar_t)]; // size is in bytes
                    if (buffer != NULL)
                    {
                        result = func(key, 3, buffer, size, &size);
                        if (result == STATUS_SUCCESS)
                        {
                            buffer[size / sizeof(wchar_t)] = L'\0';
                            keyPath = std::wstring(buffer + 2);
                        }

                        delete[] buffer;
                    }
                }
            }

            FreeLibrary(dll);
        }
    }
    return keyPath;
}

int _tmain(int argc, _TCHAR* argv[])
{
    HKEY key = NULL;
    LONG ret = ERROR_SUCCESS;

    ret = RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft", &key);
    if (ret == ERROR_SUCCESS)
    {
        wprintf_s(L"Key path for %p is '%s'.", key, GetKeyPathFromKKEY(key).c_str());    
        RegCloseKey(key);
    }

    return 0;
}

سيقوم هذا بطباعة المسار الرئيسي في وحدة التحكم:

المسار الرئيسي ل 00000fdc هو " السجل الجهاز البرمجيات Microsoft".

نصائح أخرى

اسميا لا لأنه مجرد مقبض ولا يوجد واجهة برمجة تطبيقات أعرفها أن ندعك في القيام بذلك في واجهة برمجة تطبيقات Windows العادية.

ومع ذلك، فإن API الأصلية لديها الكثير من الوظائف يمكن أن يمنحك بعض منها مقابض مفتوحة لملفات معينة وما شابه ذلك، لذلك ربما هناك شيء مشابه للسجل. هذا و Regmon بواسطة sysinternals قد يفعل شيئا مثل هذا ولكن سيكون لديك لجوجل أخشى: /

يمكنك استخدام regsavey. واكتبها إلى ملف، ثم انظر إلى الملف.

بدلا من ذلك، يمكنك الحفاظ على خريطة عالمية للميكزيئات إلى LPCWSTRS وإضافة إدخالات عند فتحها وتغيير البحث كلما.

قد تكون أيضا قادرة على القيام بشيء ما مع الأمر REG في WINDBG / NTSD، لكن لا يمكنك فقط إعطائها هيكل. عليك أن تفعل بعض الخداع الأخرى للحصول على المعلومات التي تريدها منه.

بالنسبة ntsd/windbg:

!handle yourhandle 4

كنت متحمسا للعثور على هذه المقالة وحلها المحتمل. حتى وجدت أن نظامي ntdll.dll لم يكن لديك ntquerykeytype.

بعد بعض الصيد حولها، ركضت عبر Zwquerykey في منتديات DDK.

في C #، ولكن هنا هو الحل الذي يعمل بالنسبة لي:

enum KEY_INFORMATION_CLASS
{
    KeyBasicInformation,            // A KEY_BASIC_INFORMATION structure is supplied.
    KeyNodeInformation,             // A KEY_NODE_INFORMATION structure is supplied.
    KeyFullInformation,             // A KEY_FULL_INFORMATION structure is supplied.
    KeyNameInformation,             // A KEY_NAME_INFORMATION structure is supplied.
    KeyCachedInformation,           // A KEY_CACHED_INFORMATION structure is supplied.
    KeyFlagsInformation,            // Reserved for system use.
    KeyVirtualizationInformation,   // A KEY_VIRTUALIZATION_INFORMATION structure is supplied.
    KeyHandleTagsInformation,       // Reserved for system use.
    MaxKeyInfoClass                 // The maximum value in this enumeration type.
}
[StructLayout(LayoutKind.Sequential)]
public struct KEY_NAME_INFORMATION
{
    public UInt32 NameLength;     // The size, in bytes, of the key name string in the Name array.
    public char[] Name;           // An array of wide characters that contains the name of the key.
                                  // This character string is not null-terminated.
                                  // Only the first element in this array is included in the
                                  //    KEY_NAME_INFORMATION structure definition.
                                  //    The storage for the remaining elements in the array immediately
                                  //    follows this element.
}

[DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern int ZwQueryKey(IntPtr hKey, KEY_INFORMATION_CLASS KeyInformationClass, IntPtr lpKeyInformation, int Length, out int ResultLength);

public static String GetHKeyName(IntPtr hKey)
{
    String result = String.Empty;
    IntPtr pKNI = IntPtr.Zero;

    int needed = 0;
    int status = ZwQueryKey(hKey, KEY_INFORMATION_CLASS.KeyNameInformation, IntPtr.Zero, 0, out needed);
    if ((UInt32)status == 0xC0000023)   // STATUS_BUFFER_TOO_SMALL
    {
        pKNI = Marshal.AllocHGlobal(sizeof(UInt32) + needed + 4 /*paranoia*/);
        status = ZwQueryKey(hKey, KEY_INFORMATION_CLASS.KeyNameInformation, pKNI, needed, out needed);
        if (status == 0)    // STATUS_SUCCESS
        {
            char[] bytes = new char[2 + needed + 2];
            Marshal.Copy(pKNI, bytes, 0, needed);
            // startIndex == 2  skips the NameLength field of the structure (2 chars == 4 bytes)
            // needed/2         reduces value from bytes to chars
            //  needed/2 - 2    reduces length to not include the NameLength
            result = new String(bytes, 2, (needed/2)-2);
        }
    }
    Marshal.FreeHGlobal(pKNI);
    return result;
}

لقد جربت ذلك فقط أثناء تشغيله كمسؤول، مما قد يكون مطلوبا.

والنتيجة هي تنسيق بعض الشيء: \REGISTRY\MACHINE\SOFTWARE\company\product على سبيل المثال، بدلا من HKEY_LOCAL_MACHINE\SOFTWARE\company\product.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top