64位內核開發第九講,註冊表編程.

一 註冊表編程

二 註冊表簡介

2.1 ring3註冊表

在內核中咱們的註冊表只有兩個 keyapi

內核 對應ring3
\\Registry\\Machine\\software HKEY_LOCAL_MACHINE
\\Registry\\User\\ HKEY_USERS

其它的三個是從這些內核中映射出來的。數組

2.2 重啓刪除原理

重啓刪除,其實信息是放在註冊表中的。網絡

以下:
內核:
\Registry\Machine\SYSTEM\CurrentControlSet\Control\Session Manager\pendingFileRenameOperations函數

對應Ring3
計算機\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\pendingFileRenameOperations
這個key裏面有個值是 REG_MULTI_SZ類型,這個類型存儲的是多個 \0結尾的路徑。code

使用 MoveFileEx(路徑,NULL,MOVEFILE_DELAY_UNTIL_REBOOT)這個函數進行重啓刪除。
參數2不爲空,就是替換,爲NULL就是刪除。 就是移動某個文件到某個目錄下,若是某個目錄存在就替換。orm

參數3: 參數3是很重要的。若是你替換的時候文件在使用則替換不了。給了這個參數。
那麼在重啓以後。會給你進行替換。也就是重啓刪除了。blog

此次重啓刪除則會放到上面那個註冊表中。ip

三丶註冊表API操做

3.1 Reg操做API

操做Key的函數內存

API 做用
ZwCreateKey 建立或者打開Key
ZwEnumerateKey 枚舉key
ZwQueryKey 查詢Key
ZwDeleteKey 刪除Key

操做Valuekey的函數.也就是key下面的值.

API 做用
ZwEnumerateValueKey 枚舉Valuekey 值
ZwQueryValueKey 查詢valuekey值
ZwSetValueKey 設置ValueKey的值
ZwDeleteValueKey 刪除Valuekey的值

四丶註冊表操做例子

4.1 ZwCreateKey建立key

建立key須要注意參數. 分別爲建立臨時key跟建立永久key

讀取共享文件夾下的路徑.
計算機\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares\你共享文件夾的名字
找到文件共享名字.尋找值取出路徑進行拼接.

對應內核:

registry\machine\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares\你的共享文件夾名

UNC路徑 = \\共享網絡名字\共享文件夾的名字\xxx文件

代碼以下

#include <ntddk.h>
#include <ntstrsafe.h>




DRIVER_UNLOAD DriverUnLoad;




//************************************
// Method:    ntIBinaryCreateKey
// FullName:  ntIBinaryCreateKey
// Access:    public 
// Returns:   NTSTATUS
// Qualifier: 建立註冊表鍵值
// Parameter: UNICODE_STRING uPathKeyName
//************************************


NTSTATUS ntIBinaryCreateKey(UNICODE_STRING uPathKeyName);
NTSTATUS ntIBinaryInit();


void DriverUnLoad (PDRIVER_OBJECT pDeviceObject)
{
    KdPrint(("驅動已卸載"));
}

NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT  pDriverObject,
    _In_ PUNICODE_STRING RegistryPath
    )
{
    NTSTATUS status = STATUS_SUCCESS;


    KdPrint(("驅動加載成功"));
    pDriverObject->DriverUnload = DriverUnLoad;
    
    return ntIBinaryInit();
}


NTSTATUS ntIBinaryInit()
{
    NTSTATUS status = STATUS_ERROR_PROCESS_NOT_IN_JOB;
    UNICODE_STRING uKeyPath;

    RtlUnicodeStringInit(&uKeyPath,L"\\registry\\machine\\SoftWare\\IBinary");
    status = ntIBinaryCreateKey(uKeyPath);
    if (!NT_SUCCESS(status))
    {
        
        KdPrint(("建立Key失敗"));
        return status;
    }

    return status;
}



NTSTATUS ntIBinaryCreateKey(UNICODE_STRING uPathKeyName)
{
    
    NTSTATUS status = STATUS_ERROR_PROCESS_NOT_IN_JOB;
    OBJECT_ATTRIBUTES objAttri;
    HANDLE hKeyHandle;

    UNICODE_STRING uSubKey;
    HANDLE hSubKey;
    OBJECT_ATTRIBUTES objSubAttri;
    ULONG isRegStatus;  //註冊表的狀態,傳出.
    InitializeObjectAttributes(
        &objAttri,
        &uPathKeyName,
        OBJ_CASE_INSENSITIVE, //句柄只能內核訪問,並且只能一個打開.
        NULL, NULL);

    status = ZwCreateKey(&hKeyHandle,
        KEY_ALL_ACCESS,
        &objAttri,
        0,
        NULL,
        REG_OPTION_BACKUP_RESTORE,
        (PULONG)(&isRegStatus)
    );
    if (!NT_SUCCESS(status))
    {
        ZwClose(hKeyHandle);
        return status;
    }

    //建立子Key
    RtlUnicodeStringInit(&uSubKey, L"MyReg");
    
/*
    InitializeObjectAttributes(p, n, a, r, s) {
        \
            (p)->Length = sizeof(OBJECT_ATTRIBUTES);          \
            (p)->RootDirectory = r;                             \
            (p)->Attributes = a;                                \
            (p)->ObjectName = n;                                \
            (p)->SecurityDescriptor = s;                        \
            (p)->SecurityQualityOfService = NULL;               \
    }
    */
    //InitializeObjectAttributes(&objAttri, &uSubKey, OBJ_CASE_INSENSITIVE, hKeyHandle, NULL);
    //不使用宏,手工進行賦值.
    objSubAttri.Length = sizeof(OBJECT_ATTRIBUTES);
    objSubAttri.Attributes = OBJ_CASE_INSENSITIVE;
    objSubAttri.ObjectName = &uSubKey;
    objSubAttri.SecurityDescriptor = NULL;
    objSubAttri.SecurityQualityOfService = NULL;
    objSubAttri.RootDirectory = hKeyHandle;  //注意這裏.父目錄設置爲咱們上面建立的key


    status = ZwCreateKey(&hSubKey,  //傳出建立的Key
        KEY_ALL_ACCESS,             //權限
        &objSubAttri,               //路徑
        0,
        NULL,
        REG_OPTION_NON_VOLATILE,   //建立的Key重啓是否存在仍是臨時的
        &isRegStatus);             //保存key的狀態,建立成功仍是打開

    if (!NT_SUCCESS(status))
    {
        ZwClose(hSubKey);
        ZwClose(hKeyHandle);
        return status;
    }
    ZwClose(hSubKey);
    ZwClose(hKeyHandle);
    KdPrint(("建立Key成功"));
    return status;
}

ZwCreateKey 來建立Key. 建立子Key也是用這個函數.只不過你須要在初始化子類的路徑的時候.傳入父類的Key便可.

2.刪除Key

刪除Key很簡單了.使用 ZwOpenKey打開key ZwDeleteKey刪除key

NTSTATUS ntIBinaryDeleteKey(UNICODE_STRING uPathKeyName)
{
    NTSTATUS ntStatus;
    HANDLE hKey;
    OBJECT_ATTRIBUTES ObjAttr;
    ULONG isRegStatus;

    ObjAttr.Length = sizeof(OBJECT_ATTRIBUTES);
    ObjAttr.Attributes = OBJ_CASE_INSENSITIVE;
    ObjAttr.ObjectName = &uPathKeyName;
    ObjAttr.RootDirectory = NULL;
    ObjAttr.SecurityDescriptor = NULL;
    ObjAttr.SecurityQualityOfService = NULL;
    __try
    {

        
        ntStatus = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &ObjAttr);//打開Key在進行刪除

        if (!NT_SUCCESS(ntStatus))
        {
            ZwClose(hKey);
            return ntStatus;
        }
        ntStatus = ZwDeleteKey(hKey);

        if (!NT_SUCCESS(ntStatus))
        {
            ZwClose(hKey);
            return ntStatus;
        }
        KdPrint(("刪除Key成功"));
    }
    __except (GetExceptionCode())
    {
        KdPrint(("刪除Key出現異常"));
    }
    return ntStatus;
}

3.查詢遍歷Key

查詢遍歷Key也很簡單.
1.使用函數 ZwOpenKey打開你想遍歷的Key
2.兩次調用 ZwQueryKey* ,第一次獲取你想遍歷Key的緩衝區大小.第二次.得到緩衝區大小了.爲這個結構體申請內存.傳入這個結構體.繼續遍歷.關於結構體能夠查看MSDN介紹.

3.經過結構體成員.拿到子key數量.創建for循環遍歷子key
4.遍歷過程當中.調用兩次 ZwEnumerateKey 第一次調用.
拿到你遍歷當前key的基本信息結構體的大小.而後爲結構體申請內存.
第二次調用傳入結構體.獲得當前key的基本信息.這個基本信息是放在這個結構體中.

最後初始化UNICODE_STRING字符串.進行打印便可.

代碼:

NTSTATUS ntIBinaryQueryKey(UNICODE_STRING uPathKeyName) //查詢Key
{
    NTSTATUS ntStatus;
    HANDLE hKey;
    OBJECT_ATTRIBUTES objAttri = { 0 };
    PKEY_FULL_INFORMATION pkfinfo = NULL;
    ULONG uSize = 0;
    ULONG iteratorValue = 0; //遍歷的變量
    PKEY_BASIC_INFORMATION pBaseinfo = NULL;
    UNICODE_STRING uDbgValue = { 0 };//遍歷出來的信息保存到UNICODE_STRING結構體中
    //首先打開Key,而後遍歷Key

    
    __try
    {

        InitializeObjectAttributes(
            &objAttri,
            &uPathKeyName,
            OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
            NULL,
            NULL);

        ntStatus = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &objAttri);
        if (!NT_SUCCESS(ntStatus))
        {

            return ntStatus;
        }


        //遍歷Key.須要兩次調用.第一次調用得出數據大小.第二次調用則是填充數據
        ntStatus = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &uSize);
        //得出KEY_FUN_INFOMATION 結構的大小.進行內存申請便可.
        //查詢MSDN得出,ZwQuery當數據不足會返回兩個狀態.因此判斷一下便可.

        //STATUS_BUFFER_OVERFLOW或STATUS_BUFFER_TOO_SMALL
        if (ntStatus != STATUS_BUFFER_OVERFLOW && ntStatus != STATUS_BUFFER_TOO_SMALL)
        {
            ZwClose(hKey);
            return ntStatus;
        }


        pkfinfo = (PKEY_FULL_INFORMATION)ExAllocatePoolWithTag(PagedPool, uSize, 'niBI');
        if (NULL == pkfinfo)
        {
            ZwClose(hKey);
            return ntStatus;
        }


        //申請了KEY_FULL_INFOMATION結構數組大小.而後進行獲取大小

        ntStatus = ZwQueryKey(hKey, KeyFullInformation, pkfinfo, uSize, &uSize);
        if (!NT_SUCCESS(ntStatus))
        {
            ExFreePoolWithTag(pkfinfo, 'niBI');
            ZwClose(hKey);
            return ntStatus;
        }


        for (iteratorValue = 0; iteratorValue < pkfinfo->SubKeys; iteratorValue++)
        {
            //遍歷出Key就要進行枚舉出Key的詳細信息.使用ZwEnumerateKey便可.也是枚舉一個結構.
            ntStatus = ZwEnumerateKey(hKey,
                0,
                KeyBasicInformation,
                NULL,
                0,
                &uSize);

            if (ntStatus != STATUS_BUFFER_OVERFLOW && ntStatus != STATUS_BUFFER_TOO_SMALL)
            {
                ZwClose(hKey);
                return ntStatus;
            }


            pBaseinfo = (PKEY_BASIC_INFORMATION)ExAllocatePoolWithTag(PagedPool, uSize, 'niBI');
            if (NULL == pkfinfo)
            {
                ZwClose(hKey);
                return ntStatus;
            }

            //繼續申請一次得出須要的
            ntStatus = ZwEnumerateKey(hKey,
                0,
                KeyBasicInformation,
                pBaseinfo,
                uSize,
                &uSize);

            if (!NT_SUCCESS(ntStatus))
            {
                if (NULL != pBaseinfo)
                    ExFreePoolWithTag(pBaseinfo, 'niBI');
                if (NULL != pkfinfo)
                    ExFreePoolWithTag(pkfinfo, 'niBI');
                ZwClose(hKey);
                return ntStatus;
            }

            //得出信息則能夠進行進一步操做了.

            //初始化UNICODE結構.進行打印輸出便可.

            uDbgValue.Length = (USHORT)pBaseinfo->NameLength;
            uDbgValue.MaximumLength = (USHORT)pBaseinfo->NameLength;
            uDbgValue.Buffer = pBaseinfo->Name;

            KdPrint(("得出的key 名字 = %wZ", &uDbgValue));

            ExFreePool(pBaseinfo); //同上釋放內存
        }

        //釋放資源
        if (NULL != pkfinfo)
            ExFreePool(pkfinfo);
        ZwClose(hKey);
    }
    __except (GetExceptionCode())
    {
        KdPrint(("出現異常,異常代碼爲: %ld", GetExceptionCode()));
    }
    return ntStatus;
}

結果

4.建立而且設置Value的值.

上面說的只是建立key.下面則是怎麼設置對應的Value

代碼也很簡單.
原理以下下:
1.打開Key
2.使用函數 ZwSetValueKey建立而且設置Value便可.

代碼以下

NTSTATUS ntIBinarySetKeyValue(UNICODE_STRING uPathKeyName)
{
    NTSTATUS ntStatus;
    OBJECT_ATTRIBUTES objAttri;
    HANDLE hKey;
    UNICODE_STRING uSetValueKeyName;
    ULONG Value = 10;

    InitializeObjectAttributes(&objAttri,
        &uPathKeyName, 
        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
        NULL, 
        NULL);

    ntStatus = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &objAttri);
    if (!NT_SUCCESS(ntStatus))
    {
        return ntStatus;
    }
        

    //設置KEY value的值
    RtlUnicodeStringInit(&uSetValueKeyName, L"IBinaryFrist");
    ntStatus = ZwSetValueKey(hKey,
        &uSetValueKeyName,
        0,
        REG_DWORD,
        &Value,
        sizeof(ULONG));
    if (!NT_SUCCESS(ntStatus))
    {
        ZwClose(hKey);
        return ntStatus;
    }

    KdPrint(("設置Key成功"));
    ZwClose(hKey);

    return ntStatus;
}

代碼演示.

相關文章
相關標籤/搜索