刘收获

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

注册表操作

0x01  简介

    注册表是windows操作系统、硬件设备以及客户应用程序得以正常运行和保存设置的核心“数据库”,也可以说是一个非常巨大的树状分层结构的数据库系统。
   注册表记录了用户安装在计算机上的软件和每个程序的相互关联信息,它包括了计算机的硬件配置,包括自动配置的即插即用的设备和已有的各种设备说明、状态属性以及各种状态信息和数据。利用一个功能强大的注册表数据库来统一集中地管理系统硬件设施、软件配置等信息,从而方便了管理,增强了系统的稳定性。

    (详细可参考:http://blog.sina.com.cn/s/blog_4d41e2690100q33v.html)

0x02  相关API

    (1)ZwOpenKey()  打开注册表键

1
2
3
4
5
6
7
NTSTATUS ZwOpenKey(
  _Out_  PHANDLE KeyHandle,
  _In_   ACCESS_MASK DesiredAccess,
  _In_   POBJECT_ATTRIBUTES ObjectAttributes,     //OBJECT_ATTRIBUTES结构的指针
);
 
     

  参数:

 

  KeyHandle [out]        指向一个HANDLE 变量的指针,此变量用于接收key的句柄。

 

  DesiredAccess [in]     指定一个ACCESS_MASK,以决定请求访问对象的方式。可以是中所有权限的任何组合:

    KEY_QUERY_VALUE:读取键下的值。

    KEY_SET_VALUE:设置键下的值。

    KEY_CREATE_SUB_KEY:生成子键。

    KEY_ENUMERATE_SUB_KEYS:枚举子键。

    也可以用KEY_READ来做为通用的读权限组合。这是一个组合宏。此外对应的有KEY_WRITE。如需获得全部的权限,可以使用KEY_ALL_ACCESS

 

  ObjectAttributes [in]   指向OBJECT_ATTRIBUTES 结构体的指针,它指定了对象名和其他属性。使用InitializeObjectAttributes 初始化这个结构。若调用者不是在一个系统线程的上下文中运行,必须在InitializeObjectAttributes时设置OBJ_KERNEL_HANDLE属性。

 

 

  返回值:

 

  ZwOpenKey 返回STATUS_SUCCESS 若打开了指定的键,否则返回一个如下的错误码:

  TATUS_INVALID_HANDLE

  STATUS_ACCESS_DENIED

 

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
UNICODE_STRING ustrRegString;
OBJECT_ATTRIBUTES obj_attrib;
RtlInitUnicodeString(&ustrRegString,L"\\Registry\\Machine\\SOFTWARE\\ODBC\\ODBC.INI");
InitializeObjectAttributes(&obj_attrib,
 
 &ustrRegString,
 
OBJ_CASE_INSENSITIVE,
 
NULL,
 
NULL);
 
 // 打开注册表
 
status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &obj_attrib);
 
if (NT_SUCCESS(status))
 
{
 
KdPrint(("[Test] ZwOpenKey %wZ Success!", ustrRegString));
 
}

  

 

 

    (2)ZwQueryValueKey() 读注册表

  

1
2
3
4
5
6
7
8
NTSTATUS ZwQueryValueKey(
  _In_       HANDLE KeyHandle,
  _In_       PUNICODE_STRING ValueName,
  _In_       KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
  _Out_opt_  PVOID KeyValueInformation,
  _In_       ULONG Length,
  _Out_      PULONG ResultLength
);

  

  参数:

  KeyHandle:这是用ZwCreateKey或者ZwOpenKey所打开的一个注册表键句柄。

  ValueName:要读取的值的名字。

  KeyValueInformationClass:本次查询所需要查询的信息类型。这有如下的三种可能。

  ①KeyValueBasicInformation:获得基础信息,包含值名和类型。

  ②KeyValueFullInformation:获得完整信息。包含值名、类型和值的数据。

  ③KeyValuePartialInformation:获得局部信息。包含类型和值数据

  使用KeyValuePartialInformation最常见。当采用KeyValuePartialInformation的时候,一个类型为KEY_VALUE_PARTIAL_INFORMATION的结构将被返回到参数KeyValueInformation所指向的内存中

  

1
2
3
4
5
6
typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
  ULONG TitleIndex;
  ULONG Type;
  ULONG DataLength;
  UCHAR Data[1];
} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;

    

  Length:用户传入的输出空间KeyValueInformation的长度。

    ResultLength:返回实际需要的长度。

 

    返回值:

    如果说实际需要的长度比Length要大,那么返回STATUS_BUFFER_OVERFLOW或者是STATUS_BUFFER_TOO_SMALL。如果成功读出了全部数据,那么返回STATUS_SUCCESS。其他的情况,返回一个错误码。

    

   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
UNICODE_STRING KeyName =
 
RTL_CONSTANT_STRING(L”SystemRoot”);
 
// 用来试探大小的key_infor
 
KEY_VALUE_PARTIAL_INFORMATION KeyInfor;
 
// 最后实际用到的key_infor指针。内存分配在堆中
 
PKEY_VALUE_PARTIAL_INFORMATION ActualKeyInfor;
 
ULONG Length;
 
……
 
// 前面已经打开了句柄my_key,下面如此来读取值:
 
status = ZwQueryValueKey(
 
    KeyHandle,
 
    &KeyName,
 
    KeyValuePartialInformation,
 
    &KeyInfor,
 
    sizeof(KEY_VALUE_PARTIAL_INFORMATION),
 
    &Length);
 
if (!NT_SUCCESS(status) &&
 
    status != STATUS_BUFFER_OVERFLOW &&
 
    status != STATUS_BUFFER_TOO_SMALL)
 
{
 
    // 错误处理
 
    
 
}
 
// 如果没失败,那么分配足够的空间,再次读取
 
ActualKeyInfor = (PKEY_VALUE_PARTIAL_INFORMATION)
 
ExAllocatePoolWithTag(NonpagedPool, ac_length, MEM_TAG);
 
if (ac_key_infor == NULL)
 
{
 
    stauts = STATUS_INSUFFICIENT_RESOURCES;
 
    // 错误处理
 
    
 
}
 
status = ZwQueryValueKey(
 
    KeyHandle,
 
    &KeyName,
 
    KeyValuePartialInformation,
 
    ActualKeyInfor,
 
    Length,
 
    &Length);
 
// 如果status为STATUS_SUCCESS,则要读取的数据已经
// 在ac_key_infor->Data中。应转换为UNICODE_STRING
 
……

  

 

    (3)ZwSetValueKey()  写注册表

1
2
3
4
5
6
7
8
NTSTATUS ZwSetValueKey(
  _In_      HANDLE KeyHandle,
  _In_      PUNICODE_STRING ValueName,
  _In_opt_  ULONG TitleIndex,
  _In_      ULONG Type,
  _In_opt_  PVOID Data,
  _In_      ULONG DataSize
);

  

  参数:

  TileIndex参数填入0。KeyHandle、ValueName、Type这三个参数和ZwQueryValueKey中对应的参数相同。

  Data是要写入的数据的开始地址,而DataSize是要写入的数据的长度。

  如果该Value已经存在,那么其值会被这次写入覆盖。如果不存在,则会新建一个。

 

 

0x03  注册表注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// RegInject.cpp : 定义控制台应用程序的入口点。
//
 
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;
wstring GetExeDirectory();
wstring GetParent(const std::wstring& FullPath);
int main()
{
 
 
    LONG ReturnValue = 0;
    HKEY hKey;
    WCHAR  RegPath[] = L"SOFTWARE\\Microsoft\\Windows\ NT\\CurrentVersion\\Windows";
    const wchar_t* DllName = L"Dll.dll";
    wstring InjectFileFullPath;
    InjectFileFullPath = GetExeDirectory() +
        L"\\" + DllName;
    RegEnableReflectionKey(HKEY_LOCAL_MACHINE);
    //打开键值 
    ReturnValue = RegOpenKeyEx(
        HKEY_LOCAL_MACHINE,
        RegPath,
        0,
        KEY_ALL_ACCESS,
        &hKey);
 
    if (ReturnValue != ERROR_SUCCESS)
    {
        return 0;
    }
 
    //查询键值 
    DWORD dwReadType;
    DWORD dwReadCount;
    WCHAR szReadBuff[1000] = { 0 };
    ReturnValue = RegQueryValueEx(hKey,
        L"AppInit_DLLs",
        NULL,
        &dwReadType,
        (BYTE*)&szReadBuff,
        &dwReadCount);
 
    if (ReturnValue != ERROR_SUCCESS)
    {
        return 0;
    }
    //是否dll名称已经在内容中 
    wstring strCmpBuff(szReadBuff);
    //strCmpBuff = szReadBuff;
    int a = strCmpBuff.find(InjectFileFullPath);
    if (strCmpBuff.find(InjectFileFullPath))
    {
        MessageBox(NULL, TEXT("RegInject  Had  Been  Succeed"), TEXT("It's Done Before"), MB_OK);
        return 0;
    }
 
    //有字符串就加入空格 
    if (wcscmp(szReadBuff, L" ") != 0)
    {
        wcscat_s(szReadBuff, L" ");
    }
 
    wcscat_s(szReadBuff, InjectFileFullPath.c_str());
 
    //把dll路径设置到注册表中 
    ReturnValue = RegSetValueEx(hKey,
        L"AppInit_DLLs",
        0,
        REG_SZ,
        (CONST BYTE*)szReadBuff,
        (_tcslen(szReadBuff) + 1) * sizeof(TCHAR));
    DWORD v1 = 0;
    ReturnValue = RegSetValueEx(hKey,
        L"LoadAppInit_DLLs",
        0,
        REG_DWORD,
        (CONST BYTE*)&v1,
        sizeof(DWORD));
    if (ReturnValue != ERROR_SUCCESS)
    {
        MessageBox(NULL, TEXT("RegInject   Fail"), TEXT("NO NO NO"), MB_OK);
        RegCloseKey(hKey);
    }
    else
    {
        MessageBox(NULL, TEXT("RegInject   Succeed"), TEXT("LaLaLa"), MB_OK);
    }
    getchar();
    return 0;
}
 
wstring GetExeDirectory()
{
    wchar_t ProcessFullPath[MAX_PATH] = { 0 };
    DWORD ProcessFullPathLength = ARRAYSIZE(ProcessFullPath);
    GetModuleFileName(NULL, ProcessFullPath, ProcessFullPathLength);
 
    return GetParent(ProcessFullPath);
}
 
wstring GetParent(const std::wstring& FullPath)
{
    if (FullPath.empty())
    {
        return FullPath;
    }
    auto v1 = FullPath.rfind(L"\\");
    if (v1 == FullPath.npos)
    {
        v1 = FullPath.rfind(L'/');
    }
    if (v1 != FullPath.npos)
    {
        return FullPath.substr(0, v1);
    }
    else
    {
        return FullPath;
    }
}

  

posted on   沉疴  阅读(486)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示