zoukankan      html  css  js  c++  java
  • 自己调用NTDLL函数

    一、概述

    在DLL初始化的时候有时不能调用其它系统DLL的函数,以免导致问题,但有时候又必须要调用怎么办?一种办法就是自己直接调用NTDLL接口,这样肯定没有问题。

    下面我写个自己调用Registry的封装类,用来代替原本系统注册表API。

    二、申明NTDLL导出函数

    在自己工程中需要调用NTDLL导出函数,可以通GetProcessAddr来获取函数地址再调用,也可以通过导入库的方式(这种需要ntdll.lib文件,在DDK中有),我这里采用第二种方式。

    函数和类型声明:

    NTDllDecl.h

    #pragma once
    #include <windows.h>
    #include <winternl.h>
    
    namespace NT {
        extern "C" {
    
    // macro definition
    #ifndef NTSTATUS
    #define NTSTATUS    LONG                                
    #endif
    
    #ifndef NTAPI
    #define NTAPI        __stdcall                                
    #endif
    
    #ifndef NTSYSAPI 
    #define NTSYSAPI    __declspec(dllimport)
    #endif
    
    #ifndef STATUS_BUFFER_OVERFLOW
    #define STATUS_BUFFER_OVERFLOW           ((NTSTATUS)0x80000005L)
    #endif
    
    typedef enum _KEY_INFORMATION_CLASS {
        KeyBasicInformation,
        KeyNodeInformation,
        KeyFullInformation,
        KeyNameInformation,
        KeyCachedInformation,
        KeyFlagsInformation,
        KeyVirtualizationInformation,
        KeyHandleTagsInformation,
        MaxKeyInfoClass  // MaxKeyInfoClass should always be the last enum
    } KEY_INFORMATION_CLASS;
    
    typedef enum _KEY_VALUE_INFORMATION_CLASS {
        KeyValueBasicInformation,
        KeyValueFullInformation,
        KeyValuePartialInformation,
        KeyValueFullInformationAlign64,
        KeyValuePartialInformationAlign64,
        MaxKeyValueInfoClass  // MaxKeyValueInfoClass should always be the last enum
    } KEY_VALUE_INFORMATION_CLASS;
    
    typedef struct _KEY_BASIC_INFORMATION {
        LARGE_INTEGER LastWriteTime;
        ULONG   TitleIndex;
        ULONG   NameLength;
        WCHAR   Name[1];            // Variable length string
    } KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION;
    
    typedef struct _KEY_NODE_INFORMATION {
        LARGE_INTEGER LastWriteTime;
        ULONG   TitleIndex;
        ULONG   ClassOffset;
        ULONG   ClassLength;
        ULONG   NameLength;
        WCHAR   Name[1];            // Variable length string
    //          Class[1];           // Variable length string not declared
    } KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION;
    
    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];           // Variable length
    } KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION;
    
    typedef struct _KEY_VALUE_BASIC_INFORMATION {
        ULONG   TitleIndex;
        ULONG   Type;
        ULONG   NameLength;
        WCHAR   Name[1];            // Variable size
    } KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;
    
    typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
        ULONG   TitleIndex;
        ULONG   Type;
        ULONG   DataLength;
        UCHAR   Data[1];            // Variable size
    } KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;
    
    // Registry
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwCreateKey(
        OUT PHANDLE KeyHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes,
        IN ULONG TitleIndex,
        IN PUNICODE_STRING Class,
        IN ULONG CreateOptions,
        OUT PULONG Disposition
        );
    
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwOpenKey(
        OUT PHANDLE KeyHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes
        );
    
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwQueryKey(
        IN HANDLE KeyHandle,
        IN KEY_INFORMATION_CLASS KeyInformationClass,
        OUT PVOID KeyInformation,
        IN ULONG KeyInformationLength,
        OUT PULONG ResultLength
        );
    
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwSetValueKey(
        IN HANDLE KeyHandle,
        IN PUNICODE_STRING ValueName,
        IN ULONG TitleIndex,
        IN ULONG Type,
        IN PVOID Data,
        IN ULONG DataSize
        );
    
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwQueryValueKey(
        IN HANDLE KeyHandle,
        IN PUNICODE_STRING ValueName,
        IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
        OUT PVOID KeyValueInformation,
        IN ULONG KeyValueInformationLength,
        OUT PULONG ResultLength
        );
    
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwEnumerateKey(
        IN HANDLE KeyHandle,
        IN ULONG Index,
        IN KEY_INFORMATION_CLASS KeyInformationClass,
        OUT PVOID KeyInformation,
        IN ULONG KeyInformationLength,
        OUT PULONG ResultLength
        );
    
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwClose(
        IN HANDLE Handle
        );
    
    NTSYSAPI
    NTSTATUS 
    NTAPI
    RtlFormatCurrentUserKeyPath( 
        OUT PUNICODE_STRING RegistryPath 
        );
    
    
        }
    };

    三、封装自己注册表函数

    自己定义一个类用来封装注册表函数,我这里只封装了几个需要用的注册表函数(参考ReatOS和Windows代码),其余的可以后续再添加。

    注册封装类声明:

    NTRegistry.h

    //********************************************************************  
    //    文件名:        NTRegistry.h
    //    文件描述:      Ntdll导出注册表函数定义头文件
    //    作者:           
    //    版本:          1.0
    // 
    //    修改历史:      
    //    备注:          
    //*********************************************************************
    #pragma once
    
    #ifndef STATIC
    #define STATIC        static
    #endif
    
    #ifndef NTSTATUS
    #define NTSTATUS    LONG
    #endif
    
    
    class NTRegistry
    {
    public:
        
        STATIC LONG RegCreateKey(
                    HKEY hKey,
                    LPCWSTR lpSubKey,
                    DWORD Reserved,
                    LPWSTR lpClass,
                    DWORD dwOptions,
                    REGSAM samDesired,
                    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
                    PHKEY phkResult,
                    LPDWORD lpdwDisposition);
    
        STATIC LONG RegOpenKey(
                    HKEY hKey,
                    LPCWSTR lpSubKey,
                    DWORD ulOptions,
                    REGSAM samDesired,
                    PHKEY phkResult);
    
        STATIC LONG RegQueryInfoKey(
                    HKEY hKey,
                    LPWSTR lpClass,
                    LPDWORD lpcbClass,
                    LPDWORD lpReserved,
                    LPDWORD lpcSubKeys,
                    LPDWORD lpcbMaxSubKeyLen,
                    LPDWORD lpcbMaxClassLen,
                    LPDWORD lpcValues,
                    LPDWORD lpcbMaxValueNameLen,
                    LPDWORD lpcbMaxValueLen,
                    LPDWORD lpcbSecurityDescriptor,
                    PFILETIME lpftLastWriteTime
                    );
    
        STATIC LONG RegSetValue( 
                    HKEY hKey,
                    LPCWSTR lpValueName,
                    DWORD Reserved,
                    DWORD dwType,
                    CONST BYTE* lpData,
                    DWORD cbData);
    
        STATIC LONG RegQueryValue(
                    HKEY hKey,
                    LPCWSTR lpValueName,
                    LPDWORD lpReserved,
                    LPDWORD lpType,
                    LPBYTE lpData,
                    LPDWORD lpcbData
                    );
    
        STATIC LONG RegEnumKey(
                    HKEY hKey,
                    DWORD dwIndex,
                    LPWSTR lpName,
                    LPDWORD lpcbName,
                    LPDWORD lpReserved,
                    LPWSTR lpClass,
                    LPDWORD lpcbClass,
                    PFILETIME lpftLastWriteTime);
    
        STATIC LONG RegCloseKey(HKEY hKey);
    
    private:
    
        STATIC NTSTATUS OpenCurrentUser(
                    IN ACCESS_MASK DesiredAccess,
                    OUT PHANDLE KeyHandle);
    
        STATIC NTSTATUS OpenLocalMachineKey(
                    OUT PHANDLE KeyHandle);
    
        STATIC NTSTATUS OpenCurrentConfigKey (PHANDLE KeyHandle);
    
        STATIC NTSTATUS OpenUsersKey(PHANDLE KeyHandle);
    
        STATIC NTSTATUS OpenClassesRootKey(PHANDLE KeyHandle);
    
        STATIC NTSTATUS MapDefaultKey(
                    OUT PHANDLE RealKey, 
                    IN HKEY Key);
    };

    注册封装类定义:

    NTRegistry.cpp

    #include "StdAfx.h"
    #include "NTRegistry.h"
    #include "NTDllDecl.h"
    
    #define ARGUMENT_PRESENT( arg )                                            
        ((( PVOID ) arg ) != (( PVOID ) NULL ))
    
    #define DEFAULT_KEY_NAME_SIZE                    128
    #define DEFAULT_CLASS_SIZE                        128
    #define DEFAULT_VALUE_SIZE                        128
    
    #define REG_MAX_NAME_SIZE                        256
    #define REG_MAX_DATA_SIZE                        2048
    
    #ifndef STATUS_SUCCESS
    #define STATUS_SUCCESS                          ((NTSTATUS)0x00000000L) 
    #endif
    
    #define RTL_CONSTANT_STRING(__SOURCE_STRING__)                            
    {                                                                        
        sizeof(__SOURCE_STRING__) - sizeof((__SOURCE_STRING__)[0]),            
        sizeof(__SOURCE_STRING__),                                            
        (__SOURCE_STRING__)                                                    
    }
    
    #define IsPredefKey(HKey)                                               
        (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
    
    #define ClosePredefKey(Handle)                                          
        if ((ULONG_PTR)Handle & 0x1) {                                      
            NT::ZwClose(Handle);                                            
        }
    
    NTSTATUS
    NTRegistry::OpenCurrentUser(
        IN ACCESS_MASK DesiredAccess,
        OUT PHANDLE KeyHandle)
    {
        OBJECT_ATTRIBUTES ObjectAttributes;
        UNICODE_STRING KeyPath;
        NTSTATUS Status;
    
        /* Get the user key */
        Status = NT::RtlFormatCurrentUserKeyPath(&KeyPath);
        if (NT_SUCCESS(Status))
        {
            /* Initialize the attributes and open it */
            InitializeObjectAttributes(&ObjectAttributes,
                                       &KeyPath,
                                       OBJ_CASE_INSENSITIVE,
                                       NULL,
                                       NULL);
            Status = NT::ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
    
            /* Free the path and return success if it worked */
            RtlFreeUnicodeString(&KeyPath);        
        }
    
        return Status;
    }
    
    NTSTATUS 
    NTRegistry::OpenLocalMachineKey(
        OUT PHANDLE KeyHandle)
    {
        OBJECT_ATTRIBUTES Attributes;
        UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\Registry\Machine");
        NTSTATUS Status;
    
        InitializeObjectAttributes(
            &Attributes,
            &KeyName,
            OBJ_CASE_INSENSITIVE,
            NULL,
            NULL);
        Status = NT::ZwOpenKey(KeyHandle, MAXIMUM_ALLOWED, &Attributes);
    
        return Status;
    }
    
    NTSTATUS
    NTRegistry::OpenClassesRootKey(PHANDLE KeyHandle)
    {
        OBJECT_ATTRIBUTES Attributes;
        UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\Registry\Machine\Software\CLASSES");
    
        InitializeObjectAttributes(
            &Attributes,
            &KeyName,
            OBJ_CASE_INSENSITIVE,
            NULL,
            NULL);
    
        return NT::ZwOpenKey(KeyHandle,
                         MAXIMUM_ALLOWED,
                         &Attributes);
    }
    
    NTSTATUS
    NTRegistry::OpenUsersKey(PHANDLE KeyHandle)
    {
        OBJECT_ATTRIBUTES Attributes;
        UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\Registry\User");
       
        InitializeObjectAttributes(&Attributes,
                                   &KeyName,
                                   OBJ_CASE_INSENSITIVE,
                                   NULL,
                                   NULL);
        return NT::ZwOpenKey(KeyHandle,
                         MAXIMUM_ALLOWED,
                         &Attributes);
    }
    
    NTSTATUS
    NTRegistry::OpenCurrentConfigKey (PHANDLE KeyHandle)
    {
        OBJECT_ATTRIBUTES Attributes;
        UNICODE_STRING KeyName =
            RTL_CONSTANT_STRING(L"\Registry\Machine\System\CurrentControlSet\Hardware Profiles\Current");
    
        InitializeObjectAttributes(&Attributes,
                                   &KeyName,
                                   OBJ_CASE_INSENSITIVE,
                                   NULL,
                                   NULL);
        return NT::ZwOpenKey(KeyHandle,
                         MAXIMUM_ALLOWED,
                         &Attributes);
    }
    
    NTSTATUS
    NTRegistry::MapDefaultKey(
        OUT PHANDLE RealKey,
        IN HKEY Key)
    {
        NTSTATUS Status;
        if (!IsPredefKey(Key))
        {
            *RealKey = (HANDLE)((ULONG_PTR)Key & ~0x1);
            return STATUS_SUCCESS;
        }
    
        switch ((LONG)Key)
        {
        case HKEY_CURRENT_USER:
            {
                Status = OpenCurrentUser(MAXIMUM_ALLOWED, RealKey);
            }
            break;
    
        case HKEY_LOCAL_MACHINE:
            {
                Status = OpenLocalMachineKey(RealKey);
            }
            break;
    
        case HKEY_CLASSES_ROOT:
            {
                Status = OpenClassesRootKey(RealKey);
            }
            break;
    
        case HKEY_USERS:
            {
                Status = OpenUsersKey(RealKey);
            }
            break;
    
        case HKEY_CURRENT_CONFIG:
            {
                Status = OpenCurrentConfigKey(RealKey);
            }
            break;
    
        default:
            Status = STATUS_INVALID_PARAMETER;
            break;
        }
    
        return Status;
    }
    
    LONG 
    NTRegistry::RegCreateKey(
        HKEY hKey,
        LPCWSTR lpSubKey,
        DWORD Reserved,
        LPWSTR lpClass,
        DWORD dwOptions,
        REGSAM samDesired,
        LPSECURITY_ATTRIBUTES lpSecurityAttributes,
        PHKEY phkResult,
        LPDWORD lpdwDisposition)
    {
        UNICODE_STRING SubKeyString;
        UNICODE_STRING ClassString;
        OBJECT_ATTRIBUTES ObjectAttributes;
        HANDLE ParentKey = NULL;
        NTSTATUS Status;
    
        if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES))
        {
            return ERROR_INVALID_USER_BUFFER;
        }
    
        /* get the real parent key */
        Status = MapDefaultKey(&ParentKey,
                               hKey);
        if (!NT_SUCCESS(Status))
        {
            return RtlNtStatusToDosError(Status);
        }
    
        if (!phkResult)  
        {  
            return ERROR_INVALID_PARAMETER;  
        }
    
        RtlInitUnicodeString(&ClassString, lpClass);
        RtlInitUnicodeString(&SubKeyString, lpSubKey);
    
        InitializeObjectAttributes(
            &ObjectAttributes,
            &SubKeyString,
            OBJ_CASE_INSENSITIVE,
            (HANDLE)ParentKey,
            lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
    
        Status = NT::ZwCreateKey(
            (PHANDLE)phkResult,
            samDesired,
            &ObjectAttributes,
            0,
            (lpClass == NULL) ? NULL : &ClassString,                    /* optional*/
            dwOptions,
            lpdwDisposition
            );         
    
        ClosePredefKey(ParentKey);    
    
        return RtlNtStatusToDosError( Status );
    }
    
    LONG NTRegistry::RegOpenKey(
        HKEY hKey,
        LPCWSTR lpSubKey,
        DWORD ulOptions,
        REGSAM samDesired,
        PHKEY phkResult)
    {
        OBJECT_ATTRIBUTES ObjectAttributes;
        UNICODE_STRING SubKeyString;
        HANDLE KeyHandle;
        NTSTATUS Status;
    
        if (!phkResult)
        {
            return ERROR_INVALID_PARAMETER;
        }
    
        Status = MapDefaultKey(&KeyHandle, hKey);
        if (!NT_SUCCESS(Status))
        {
            return RtlNtStatusToDosError(Status);
        }
    
        if (lpSubKey != NULL)
            RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
        else
            RtlInitUnicodeString(&SubKeyString, (LPWSTR)L"");
            
        InitializeObjectAttributes(
            &ObjectAttributes,
            &SubKeyString,
            OBJ_CASE_INSENSITIVE,
            KeyHandle,
            NULL
            );
    
        Status = NT::ZwOpenKey(
            (PHANDLE)phkResult,
            samDesired,
            &ObjectAttributes
            );
    
        ClosePredefKey(KeyHandle);
    
        return RtlNtStatusToDosError( Status );
    }
    
    LONG NTRegistry::RegQueryInfoKey(
        HKEY hKey,
        LPWSTR lpClass,
        LPDWORD lpcbClass,
        LPDWORD lpReserved,
        LPDWORD lpcSubKeys,
        LPDWORD lpcbMaxSubKeyLen,
        LPDWORD lpcbMaxClassLen,
        LPDWORD lpcValues,
        LPDWORD lpcbMaxValueNameLen,
        LPDWORD lpcbMaxValueLen,
        LPDWORD lpcbSecurityDescriptor,
        PFILETIME lpftLastWriteTime
        )
    {
        NT::KEY_FULL_INFORMATION FullInfoBuffer;
        NT::PKEY_FULL_INFORMATION FullInfo;
        ULONG FullInfoSize;
        ULONG ClassLength = 0;
        HANDLE KeyHandle;
        NTSTATUS Status;
        ULONG Length;
        LONG ErrorCode = ERROR_SUCCESS;
    
        if ((lpClass) && (!lpcbClass))
        {
            return ERROR_INVALID_PARAMETER;
        }
    
        Status = MapDefaultKey(&KeyHandle,
                               hKey);
        if (!NT_SUCCESS(Status))
        {
            return RtlNtStatusToDosError(Status);
        }
    
        if (lpClass != NULL)
        {
            if (*lpcbClass > 0)
            {
                ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
            }
            else
            {
                ClassLength = 0;
            }
    
            FullInfoSize = sizeof(NT::KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
            FullInfo = (NT::PKEY_FULL_INFORMATION)HeapAlloc(GetProcessHeap(),
                                 0,
                                 FullInfoSize);
            if (FullInfo == NULL)
            {
                ErrorCode = ERROR_OUTOFMEMORY;
                goto Cleanup;
            }
    
            FullInfo->ClassLength = ClassLength;
        }
        else
        {
            FullInfoSize = sizeof(NT::KEY_FULL_INFORMATION);
            FullInfo = &FullInfoBuffer;
            FullInfo->ClassLength = 0;
        }
        FullInfo->ClassOffset = FIELD_OFFSET(NT::KEY_FULL_INFORMATION, Class);
    
        Status = NT::ZwQueryKey(KeyHandle,
                            NT::KeyFullInformation,
                            FullInfo,
                            FullInfoSize,
                            &Length);
        if (!NT_SUCCESS(Status))
        {
            if (lpClass != NULL)
            {
                HeapFree(GetProcessHeap(),
                            0,
                            FullInfo);
            }
    
            ErrorCode = RtlNtStatusToDosError(Status);
            goto Cleanup;
        }
    
        if (lpcSubKeys != NULL)
        {
            *lpcSubKeys = FullInfo->SubKeys;
        }
    
        if (lpcbMaxSubKeyLen != NULL)
        {
            *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
        }
    
        if (lpcbMaxClassLen != NULL)
        {
            *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
        }
    
        if (lpcValues != NULL)
        {
            *lpcValues = FullInfo->Values;
        }
    
        if (lpcbMaxValueNameLen != NULL)
        {
            *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
        }
    
        if (lpcbMaxValueLen != NULL)
        {
            *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
        }
    
        if (lpftLastWriteTime != NULL)
        {
            lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
            lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
        }
    
        if (lpClass != NULL)
        {
            if (FullInfo->ClassLength > ClassLength)
            {
                ErrorCode = ERROR_BUFFER_OVERFLOW;
            }
            else
            {
                RtlCopyMemory(lpClass,
                                FullInfo->Class,
                                FullInfo->ClassLength);
                *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
                lpClass[*lpcbClass] = 0;
            }
    
            HeapFree(GetProcessHeap(),
                        0,
                        FullInfo);
        }
    
    Cleanup:
    
        ClosePredefKey(KeyHandle);
    
        return ErrorCode;
    }
    
    LONG NTRegistry::RegSetValue(
        HKEY hKey,
        LPCWSTR lpValueName,
        DWORD Reserved,
        DWORD dwType,
        CONST BYTE* lpData,
        DWORD cbData)
    {
        UNICODE_STRING ValueName;
        PUNICODE_STRING pValueName;
        HANDLE KeyHandle;
        NTSTATUS Status;
    
        Status = MapDefaultKey(&KeyHandle,
                               hKey);
        if (!NT_SUCCESS(Status))
        {
            return RtlNtStatusToDosError(Status);
        }
    
        RtlInitUnicodeString(&ValueName, lpValueName);
        pValueName = &ValueName;
    
        if ((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ) || (dwType == REG_MULTI_SZ) && (cbData != 0))
        {
            PWSTR pwsData = (PWSTR)lpData;
    
            if((pwsData[cbData / sizeof(WCHAR) - 1] != L'') &&
                (pwsData[cbData / sizeof(WCHAR)] == L''))
            {
                /* Increment length if last character is not zero and next is zero */
                cbData += sizeof(WCHAR);
            }
        }
    
        Status = NT::ZwSetValueKey(
            hKey,
            &ValueName,
            0,
            dwType,
            (PVOID)lpData,
            cbData);
    
        ClosePredefKey(KeyHandle);
    
        return RtlNtStatusToDosError( Status );
    }
    
    LONG NTRegistry::RegQueryValue(
        HKEY hKey,
        LPCWSTR lpValueName,
        LPDWORD lpReserved,
        LPDWORD lpType,
        LPBYTE lpData,
        LPDWORD lpcbData
        )
    {
        NTSTATUS Status;
        UNICODE_STRING ValueName;
        ULONG    BufferLength;
        NT::KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass;
        PVOID    KeyValueInformation;
        ULONG    ResultLength;
        HANDLE    KeyHandle;
        BYTE    PrivateKeyValueInformation[ sizeof( NT::KEY_VALUE_PARTIAL_INFORMATION ) +
                                            DEFAULT_VALUE_SIZE ];
    
        //
        // Validate dependency between lpData and lpcbData parameters.
        //
    
        if( ARGUMENT_PRESENT( lpReserved ) ||
            (ARGUMENT_PRESENT( lpData ) && ( ! ARGUMENT_PRESENT( lpcbData )))) {
            return ERROR_INVALID_PARAMETER;
        }
    
        Status = MapDefaultKey(&KeyHandle,
                               hKey);
        if (!NT_SUCCESS(Status))
        {
            return RtlNtStatusToDosError(Status);
        }
    
        //
        // Convert the value name to a counted Unicode string.
        //
    
        RtlInitUnicodeString( &ValueName, lpValueName );
        
        //
        //  First we assume that the information we want will fit on
        //  PrivateKeyValueInformattion
        //
    
        KeyValueInformationClass = ( ARGUMENT_PRESENT( lpcbData ))?
                                   NT::KeyValuePartialInformation :
                                   NT::KeyValueBasicInformation;
    
        KeyValueInformation = PrivateKeyValueInformation;
        BufferLength = sizeof( PrivateKeyValueInformation );    
    
        Status = NT::ZwQueryValueKey(
                    KeyHandle,
                    &ValueName,
                    KeyValueInformationClass,
                    KeyValueInformation,
                    BufferLength,
                    &ResultLength);
    
        if( ( Status == STATUS_BUFFER_OVERFLOW ) &&
            ( !ARGUMENT_PRESENT( lpData ) ) ) 
        {
            
            Status = STATUS_SUCCESS;
        }
    
        if( Status == STATUS_BUFFER_OVERFLOW ) 
        {
            //
            //  The buffer defined in the stack wasn't big enough to hold
            //  the Value information.
            //  If the caller's buffer is big enough to hold the value data
            //  then allocate a new buffer, and call the NT API again.
            //
            if( ( ( KeyValueInformationClass == NT::KeyValuePartialInformation ) &&
                  ( ARGUMENT_PRESENT( lpData ) ) &&
                  ( *lpcbData >= (( NT::PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->DataLength)) ) 
            {
                BufferLength = ResultLength;
    
                KeyValueInformation = HeapAlloc( GetProcessHeap( ), 0, BufferLength);
                //
                // If the memory allocation fails, return a Registry error.
                //
    
                if( ! KeyValueInformation ) 
                {
                    return ERROR_OUTOFMEMORY;
                }
    
                //
                // Query for the necessary information about the supplied value.
                //
    
                Status = NT::ZwQueryValueKey( 
                                KeyHandle,
                                &ValueName,
                                KeyValueInformationClass,
                                KeyValueInformation,
                                BufferLength,
                                &ResultLength
                                );
            }
        }
    
        if( NT_SUCCESS( Status ) &&
            ARGUMENT_PRESENT( lpData ) ) 
        {
            //
            //  If requested, copy the value data
            //
            if( *lpcbData >= (( NT::PKEY_VALUE_PARTIAL_INFORMATION )
                                KeyValueInformation )->DataLength ) 
            {
    
                RtlMoveMemory( lpData, (( NT::PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->Data,
                               (( NT::PKEY_VALUE_PARTIAL_INFORMATION )KeyValueInformation )->DataLength);
    
            } 
            else 
            {
                Status = STATUS_BUFFER_OVERFLOW;
            }
        }
    
        //
        // Certain information is returned on success or in the case of
        // NtQueryValueKey returning STATUS_BUFFER_OVERFLOW.  This information
        // is always available because we always pass the minimum size required for
        // the NtQueryValueKey API.
        //
    
        if( NT_SUCCESS( Status ) ||
            ( Status == STATUS_BUFFER_OVERFLOW ) ) {
    
            if( KeyValueInformationClass == NT::KeyValueBasicInformation ) {
    
                //
                // If requested, return the value type.
                //
    
                if( ARGUMENT_PRESENT( lpType )) {
    
                    *lpType = (( NT::PKEY_VALUE_BASIC_INFORMATION )
                                KeyValueInformation )->Type;
                }
    
            } else {
    
                //
                // If requested, return the value type.
                //
    
                if( ARGUMENT_PRESENT( lpType )) {
    
                    *lpType = (( NT::PKEY_VALUE_PARTIAL_INFORMATION )
                                KeyValueInformation )->Type;
                }
    
                //
                // Return the value data size
                //
                *lpcbData = (( NT::PKEY_VALUE_PARTIAL_INFORMATION )
                                KeyValueInformation )->DataLength;
            }
        }
    
        //
        // Transmit all of the data back to the client.
        //
    
        if( ARGUMENT_PRESENT( lpcbData ) ) {
            if( NT_SUCCESS( Status ) &&
                ARGUMENT_PRESENT( lpData ) ) {
                *lpcbData = (( NT::PKEY_VALUE_PARTIAL_INFORMATION )
                            KeyValueInformation )->DataLength;
            } else {
                //
                // The API failed, so make sure that no data is transmitted back
                // to the client. This ensures that the client stub will not
                // attempt to unmarshall data that doesn't exist.
                //
    
                *lpcbData = 0;
            }
        }
    
        //
        //  If memory was allocated, then free it
        //
        if( KeyValueInformation != PrivateKeyValueInformation ) {
    
            HeapFree( GetProcessHeap( ), 0, KeyValueInformation );
        }
        
        return RtlNtStatusToDosError( Status );
    }
    
    LONG NTRegistry::RegEnumKey(
        HKEY hKey,
        DWORD dwIndex,
        LPWSTR lpName,
        LPDWORD lpcName,
        LPDWORD lpReserved,
        LPWSTR lpClass,
        LPDWORD lpcClass,
        PFILETIME lpftLastWriteTime)
    {
        NTSTATUS Status;
        NT::KEY_INFORMATION_CLASS  KeyInformationClass;
        UNICODE_STRING NameString;
        UNICODE_STRING ClassString;
        PVOID  KeyInformation;
        ULONG  BufferLength;
        ULONG  ResultLength;
        HANDLE KeyHandle;
        BYTE   PrivateKeyInformation[ sizeof( NT::KEY_NODE_INFORMATION ) +
                                            DEFAULT_KEY_NAME_SIZE +
                                            DEFAULT_CLASS_SIZE ];
    
    
        if( !ARGUMENT_PRESENT( lpName ) ||
            (ARGUMENT_PRESENT( lpClass ) && ( ! ARGUMENT_PRESENT( lpcClass )))) {
            return ERROR_INVALID_PARAMETER;
        }
    
        //
        // Use the supplied name string buffer as the buffer in a counted
        // Unicode string.
        //
        NameString.Length           = 0;
        if ((*lpcName << 1) > 0xFFFE) {
            NameString.MaximumLength    = ( USHORT ) 0xFFFE;
        } else {
            NameString.MaximumLength    = ( USHORT )( *lpcName << 1 );
        }    
        NameString.Buffer           = lpName;
    
        //
        // If supplied use the supplied name string buffer as the buffer in a
        // counted Unicode string.
        //
        if (ARGUMENT_PRESENT( lpClass ))
            RtlInitUnicodeString(&ClassString, (LPWSTR)lpClass);
        else
            RtlInitUnicodeString(&ClassString, (LPWSTR)L"");    
    
        //
        //  First we assume that the information we want will fit on
        //  PrivateKeyValueInformattion
        //
    
        KeyInformationClass = (ARGUMENT_PRESENT( lpClass )) ?  NT::KeyNodeInformation : NT::KeyBasicInformation;
    
        KeyInformation = PrivateKeyInformation;
        BufferLength = sizeof( PrivateKeyInformation );
    
        Status = MapDefaultKey(&KeyHandle,
                               hKey);
        if (!NT_SUCCESS(Status))
        {
            return RtlNtStatusToDosError(Status);
        }
    
        Status = NT::ZwEnumerateKey(
            KeyHandle, 
            dwIndex,
            KeyInformationClass,
            KeyInformation,
            BufferLength,
            &ResultLength);
    
        if( Status == STATUS_BUFFER_OVERFLOW ) {
            //
            //  The buffer defined in the stack wasn't big enough to hold
            //  the Key information.
            //  If the caller's buffer are big enough to hold the key name
            //  and key class, then allocate a new buffer, and call the
            //  NT API again.
            //
            if( ( ( KeyInformationClass == NT::KeyBasicInformation ) &&
                  ( (ULONG)(NameString.MaximumLength) >= (( NT::PKEY_BASIC_INFORMATION )KeyInformation )->NameLength + sizeof(UNICODE_NULL)) ) ||
                ( ( KeyInformationClass == NT::KeyNodeInformation ) &&
                  ( (ULONG)(NameString.MaximumLength) >= (( NT::PKEY_NODE_INFORMATION )KeyInformation )->NameLength + sizeof(UNICODE_NULL)) &&
                  ( ARGUMENT_PRESENT( lpClass )) && 
                  ( (ULONG)(ClassString.MaximumLength) >= (( NT::PKEY_NODE_INFORMATION )KeyInformation )->ClassLength + sizeof(UNICODE_NULL))
                ) ) 
            {
                BufferLength = ResultLength;
    
                KeyInformation = HeapAlloc( GetProcessHeap( ), 0, BufferLength);
                //
                // If the memory allocation fails, return a Registry error.
                //
    
                if( ! KeyInformation ) {
                    return ERROR_OUTOFMEMORY;
                }
    
                //
                // Query for the necessary information about the supplied key.
                // This may or may not include the class depending on lpClass->Buffer
                // as determined above.
                //
    
                {
                    Status = NT::ZwEnumerateKey(
                                KeyHandle, dwIndex,
                                KeyInformationClass,
                                KeyInformation,
                                BufferLength,
                                &ResultLength);
                }
    
            }
        }
    
        if( NT_SUCCESS( Status ) ) 
        {
    
            if( KeyInformationClass == NT::KeyBasicInformation ) 
            {
                //
                // Return the name length and the name of the key.
                // Note that the NUL byte is included so that RPC copies the
                // correct number of bytes. It is decremented on the client
                // side.
                //
    
                if( (ULONG)(NameString.MaximumLength) >=
                     (( NT::PKEY_BASIC_INFORMATION )KeyInformation )->NameLength + sizeof( UNICODE_NULL ) ) 
                {
    
                    NameString.Length = ( USHORT )(( NT::PKEY_BASIC_INFORMATION )KeyInformation )->NameLength;
    
                    RtlMoveMemory( NameString.Buffer, 
                        (( NT::PKEY_BASIC_INFORMATION )KeyInformation )->Name,  
                        NameString.Length);
    
                    //
                    // NUL terminate the value name.
                    //
    
                    NameString.Buffer[ NameString.Length >> 1 ] = UNICODE_NULL;
                    if( ARGUMENT_PRESENT( lpcName )) {
    
                        *lpcName = NameString.Length >> 1;
                    }
    
                } else {
    
                    Status = STATUS_BUFFER_OVERFLOW;
                }
    
                //
                // If requested, return the last write time.
                //
    
                if( ARGUMENT_PRESENT( lpftLastWriteTime )) {
    
                    *lpftLastWriteTime = *( PFILETIME )&(( NT::PKEY_BASIC_INFORMATION ) KeyInformation )->LastWriteTime;
                }
    
            } else {
                //
                // Return the name length and the name of the key.
                // Note that the NUL byte is included so that RPC copies the
                // correct number of bytes. It is decremented on the client
                // side.
                //
    
                if( ( (ULONG)(NameString.MaximumLength) >=
                      (( NT::PKEY_NODE_INFORMATION )
                       KeyInformation )->NameLength + sizeof( UNICODE_NULL ) ) &&
                    ( (ULONG)(ClassString.MaximumLength) >=
                      (( NT::PKEY_NODE_INFORMATION )
                       KeyInformation )->ClassLength + sizeof( UNICODE_NULL) )
                  ) {
                    //
                    //  Copy the key name
                    //
                    NameString.Length = ( USHORT )
                                     (( NT::PKEY_NODE_INFORMATION )
                                     KeyInformation )->NameLength;
                    
                    RtlMoveMemory( NameString.Buffer,
                                   (( NT::PKEY_NODE_INFORMATION )KeyInformation )->Name,
                                   NameString.Length
                                 );
    
                    //
                    // NUL terminate the key name.
                    //
    
                    NameString.Buffer[ NameString.Length >> 1 ] = UNICODE_NULL;                
                    if( ARGUMENT_PRESENT( lpcName )) {
    
                        *lpcName = NameString.Length >> 1;
                    }
    
    
                    //
                    //  Copy the key class
                    //
    
                    ClassString.Length = (USHORT)
                        ((( NT::PKEY_NODE_INFORMATION ) KeyInformation )->ClassLength );
    
                    RtlMoveMemory(
                        ClassString.Buffer,
                        ( PBYTE ) KeyInformation
                        + (( NT::PKEY_NODE_INFORMATION ) KeyInformation )->ClassOffset,
                        ClassString.Length
                        );
    
                    //
                    // NUL terminate the class.
                    //
    
                    ClassString.Buffer[ ClassString.Length >> 1 ] = UNICODE_NULL;
                    if( ARGUMENT_PRESENT( lpcClass )) {
    
                        *lpcClass = ClassString.Length >> 1;
                    }
    
                } else {
                    Status = STATUS_BUFFER_OVERFLOW;
                }
    
                //
                // If requested, return the last write time.
                //
    
                if( ARGUMENT_PRESENT( lpftLastWriteTime )) {
    
                    *lpftLastWriteTime
                    = *( PFILETIME )
                    &(( NT::PKEY_NODE_INFORMATION ) KeyInformation )
                    ->LastWriteTime;
                }
            }
        }
        
        if( KeyInformation != PrivateKeyInformation ) {
            //
            // Free the buffer allocated.
            //
    
            HeapFree( GetProcessHeap( ), 0, KeyInformation );
        }
    
        return RtlNtStatusToDosError( Status );
    }
    
    LONG NTRegistry::RegCloseKey(HKEY hKey)
    {
        NTSTATUS Status;
        /* don't close null handle or a pseudo handle */
        if ((!hKey) || (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000))
        {
            return ERROR_INVALID_HANDLE;
        }
    
        Status = NT::ZwClose( hKey );
    
        return RtlNtStatusToDosError( Status );
    }

    四、项目设置

    为了使用NTDLL导出函数,我们这里还需要用到ntdll.lib,需要在工程属性中添加导入ntdll.lib,只需要把ntdll.lib从DDK中拷贝出来放到你自己第三方库位置。

    五、测试程序

    测试了个获取Adobe安装目录的程序

    NtFunctionTest.cpp

    #include "stdafx.h"
    #include <gtest/gtest.h>
    #include <string>
    #include <NT/NtRegistry.h>
    
    TEST(GsKernelTest, tRegistryKey)
    {
    
        HKEY hKey = NULL;
        LONG RetVal    = NTRegistry::RegOpenKey(
                        HKEY_LOCAL_MACHINE, 
                        L"SOFTWARE\Adobe\Acrobat Reader",         
                        REG_OPTION_NON_VOLATILE,
                        KEY_READ,        
                        &hKey);
        ASSERT_TRUE(RetVal==ERROR_SUCCESS);
        if ( ERROR_SUCCESS != RetVal )
        {
            return;
        }
    
        DWORD cSubKeys = 0;
        RetVal = NTRegistry::RegQueryInfoKey(hKey, NULL, NULL, NULL, &cSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
        ASSERT_TRUE(RetVal==ERROR_SUCCESS);
        if ( ERROR_SUCCESS != RetVal )
        {
            NTRegistry::RegCloseKey(hKey);
            return;
        }
    
        TCHAR szKeyName[MAX_PATH];
        for ( DWORD i=0; i < cSubKeys; ++i )
        {
            DWORD dwKeyNameLength = sizeof(szKeyName)/sizeof(szKeyName[0]);
            RetVal = NTRegistry::RegEnumKey( hKey, i, szKeyName, &dwKeyNameLength, NULL, NULL, NULL,NULL);
            if ( ERROR_SUCCESS != RetVal )
            {
                continue;
            }
    
            double fVersion = _tstof(szKeyName);
            DWORD dwVesion = (DWORD)(fVersion*10);
    
            if ( dwVesion > 120 || dwVesion < 60  )
            {
                continue;
            }        
    
            /// 拷贝文件
            TCHAR szAdobePath[MAX_PATH];
            _tcscat_s(szKeyName,_countof(szKeyName), TEXT("\InstallPath"));
            HKEY hChildKey = NULL;
            RetVal = NTRegistry::RegOpenKey(hKey, szKeyName, 0, KEY_READ, &hChildKey);
            if ( ERROR_SUCCESS != RetVal )
            {
                continue;
            }
    
            DWORD cKey = sizeof(szAdobePath);
            RetVal = NTRegistry::RegQueryValue(hChildKey, NULL, 0, NULL, (LPBYTE)szAdobePath, &cKey );
            if ( ERROR_SUCCESS == RetVal )
            {
                wcout << L"InstallPath: " << szAdobePath << endl;            
            }
            
            NTRegistry::RegCloseKey(hChildKey);
    
        }
    
        NTRegistry::RegCloseKey(hKey);
    }

    我的测试代码都是放到测试工程中的,采用的是gTest框架。

    不采用导入ntdll.lib库方式的我后面再补充,只要通过GetProcessAddr获取函数地址就可以了。

    Book16  看书、学习、写代码
  • 相关阅读:
    WIN10 UBUNTU 异常:sleep: cannot read realtime clock: Invalid argument
    Mysql表名大小写忽略
    Spring boot自定义配置文件并映射到指定类中
    list addAll产生异常java.lang.UnsupportedOperationException
    Oracle extract函数提取时分秒的问题
    JOOQ默认schema
    Druid数据库连接失败,无限尝试问题
    Mysql安装后root无法登陆(Access denied for user 'root'@'localhost')
    JavaSE第17篇:集合之Map集合
    JavaSE第16篇:集合之Collection集合下篇
  • 原文地址:https://www.cnblogs.com/Quincy/p/4838600.html
Copyright © 2011-2022 走看看