前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >64位内核开发第九讲,注册表编程.

64位内核开发第九讲,注册表编程.

作者头像
IBinary
发布2019-06-14 14:25:50
1K0
发布2019-06-14 14:25:50
举报
文章被收录于专栏:逆向技术

一 注册表编程

二 注册表简介

2.1 ring3注册表

在内核中我们的注册表只有两个 key

内核

对应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结尾的路径。

使用 MoveFileEx(路径,NULL,MOVEFILE_DELAY_UNTIL_REBOOT)这个函数进行重启删除。 参数2不为空,就是替换,为NULL就是删除。 就是移动某个文件到某个目录下,如果某个目录存在就替换。

参数3: 参数3是很重要的。如果你替换的时候文件在使用则替换不了。给了这个参数。 那么在重启之后。会给你进行替换。也就是重启删除了。

这次重启删除则会放到上面那个注册表中。

三丶注册表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文件

代码如下

代码语言:javascript
复制
#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

代码语言:javascript
复制
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字符串.进行打印即可.

代码:

代码语言:javascript
复制
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即可.

代码如下

代码语言:javascript
复制
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;
}

代码演示.

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-06-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一 注册表编程
    • 二 注册表简介
      • 2.1 ring3注册表
      • 2.2 重启删除原理
    • 三丶注册表API操作
      • 3.1 Reg操作API
    • 四丶注册表操作例子
      • 4.1 ZwCreateKey创建key
      • 2.删除Key
      • 3.查询遍历Key
      • 4.创建并且设置Value的值.
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档