zoukankan      html  css  js  c++  java
  • 64位内核开发第九讲,注册表编程.

    一 注册表编程

    二 注册表简介

    2.1 ring3注册表

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

    内核 对应ring3
    \Registry\Machine\software HKEY_LOCAL_MACHINE
    \Registry\User\ HKEY_USERS

    其它的三个是从这些内核中映射出来的。

    2.2 重启删除原理

    重启删除,其实信息是放在注册表中的。

    如下:
    内核:
    RegistryMachineSYSTEMCurrentControlSetControlSession ManagerpendingFileRenameOperations

    对应Ring3
    计算机HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerpendingFileRenameOperations
    这个key里面有个值是 REG_MULTI_SZ类型,这个类型存储的是多个 结尾的路径。

    使用 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_MACHINESYSTEMCurrentControlSetServicesLanmanServerShares你共享文件夹的名字
    找到文件共享名字.寻找值取出路径进行拼接.

    对应内核:

    registrymachineSYSTEMCurrentControlSetServicesLanmanServerShares你的共享文件夹名

    **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;
    }
    
    

    代码演示.

  • 相关阅读:
    2019-2020-2-20175332 张苗 -《网络对抗技术》Exp5 信息搜集与漏洞扫描
    2019-2020-2-20175332 张苗-《网络对抗技术》-exp4 恶意代码分析
    2019-2020-2 网络对抗技术-20175332 张苗-exp3 免杀原理与实践
    2019-2020-2-《网络攻防技术》-20175332 张苗-exp2 后门原理与实践
    2019-2020-2-《网络对抗技术》-20175332 张苗-exp1 PC平台逆向破解
    2019-2020-1-20175332-实验五通讯协议设计
    2018-2019-2 20165204《网络对抗技术》 Exp9 Web安全基础
    2018-2019-2 20165204《网络对抗技术》 Exp8 Web基础
    2018-2019-2 20165204《网络对抗技术》 Exp7 网络欺诈防范
    2018-2019-2 20165204《网络对抗技术》 Exp6 信息搜集与漏洞扫描
  • 原文地址:https://www.cnblogs.com/iBinary/p/10990686.html
Copyright © 2011-2022 走看看