手把手教你手撕HIVE文件

介绍

HIVE文件在HKLM\SYSTEM\CurrentControlSet\Control\hivelist下键值给出,这里以C:\Windows\System32\config\SOFTWARE为例。

常用数据结构

总长度为$4096$字节,重要信息:

偏移量 长度(字节) 描述
0x00 4 签名“regf”
0x0C 8 最后一次写入数据时间戳 UTC1601-1-1至今100纳秒间隔数
0x14 4 主版本号
0x18 4 次版本号
0x24 4 RootCell偏移量
0x28 4 HIVE文件长度 不包含表头和结尾附加数据
0x30 HIVE文件名 Unicode字符串

hbin cells

header后紧接着就是这个。重要信息:

偏移量 长度(字节) 描述
0x00 4 签名“hbin”
0x04 4 相对于第一个hbin偏移量
0x08 4 该hbin数据长度大小

node key(nk)

重要信息:

偏移量 长度(字节) 描述
0x00 4 大小 负数已被使用 整数未被使用
0x04 2 签名“nk”
0x06 2 属性 CompressedName0x20 HiveEntryRootKey0x4 HiveExit0x2 NoDelete0x8
0x08 8 最后一次写入数据时间戳
0x14 4 父nk索引
0x18 4 子nk数量
0x20 4 子nk索引
0x28 4 vk数量
0x2C 4 vk索引
0x30 4 sk索引
0x4C 4 nk名称长度
0x50 nk名称 ASCII字符串

value key(vk)

重要信息:

偏移量 长度(字节) 描述
0x00 4 大小 有符号
0x04 2 签名“vk”
0x06 2 vk名称长度
0x08 4 vk数据长度 大于0x80000000表示驻留数据 减去该数得真实大小
0x0C 4 vk数据 驻留数据就保存在这里 非驻留时保存数据节点偏移量
0x10 4 vk数据类型 REG_SZ0x1 REG_EXPAND_SZ0x2 REG_BINARY0x3 REG_DWORD0x4 REG_MULTI_SZ0x7
0x14 2 标识符 判断vk名称是否ASCII或Unicode格式储存
0x18 vk名称 ASCII编码

security key(sk)

重要信息:

偏移量 长度(字节) 描述
0x00 4 大小 有符号
0x04 2 签名“sk”
0x08 4 Flink 下一条sk偏移值
0x0C 4 Blink 上一条sk偏移值
0x10 4 引用计数 sk实际引用nk记录数量
0x1A 2 控制 SeDaclAutoInherited0x400 SeDaclDefaulted0x8 SeDaclPresent0x4 SeGroupDefaulted0x2 SeOwnerDefaulted0x1
0x1C 4 owner偏移量
0x20 4 group偏移量
0x24 4 SACL偏移量
0x28 4 DACL偏移量

list

列表结构。

lf与lh

lf和lh包含nk记录数据。

偏移量 长度(字节) 描述
0x00 4 大小 有符号
0x04 2 签名“lf”或“lh”
0x06 2 下面这俩的数量
0x08+0x08*n 4 nk记录偏移值
0x0C+0x08*n 4 nk记录HASH值

li与ri

列表记录数据,重要数据:

偏移量 长度(字节) 描述
0x00 4 大小 有符号
0x04 2 签名“li”或“ri”
0x06 2 下面这个的数量
0x08+0x04*n 4 列表记录的偏移量

db

记录vk数据,重要数据:

偏移量 长度(字节) 描述
0x00 4 大小 有符号
0x04 2 签名“db”
0x06 2 数量
0x08 4 vk记录偏移值

实战

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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
BOOL AnalysisHiveFile(PTCHAR pszHiveFileName) {
BOOL bRet = FALSE;
HANDLE hFile = NULL, hFileMap = NULL;
LPVOID pMemory = NULL;
do {
// 内存映射文件
hFile = ::CreateFile(pszHiveFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
if (INVALID_HANDLE_VALUE == hFile)
break;
hFileMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (NULL == hFileMap)
break;
pMemory = MapViewOfFile(hFileMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
if (NULL == pMemory)
break;
// 分析HIVE文件头
bRet = AnalysisHiveHeader((PUCHAR)pMemory);
} while (FALSE);
// 释放
if (pMemory)
UnmapViewOfFile(pMemory);
if (hFileMap)
::CloseHandle(hFileMap);
if (hFile)
::CloseHandle(hFile);
return bRet;
};
// 分析HIVE文件头
BOOL AnalysisHiveHeader(PUCHAR pMemory) {
BOOL bRet = FALSE;
DWORD dwMajor = 0, dwMinor = 0;
DWORD dwRootCellOffset = 0;
DWORD dwLength = 0;
WCHAR* pwszHiveName = NULL;
PUCHAR pHBIN = NULL;
// 获取HIVE文件主版本号
dwMajor = *(DWORD*)(pMemory + 0x14);
// 获取HIVE文件次版本号
dwMinor = *(DWORD*)(pMemory + 0x18);
// 获取RootCellOffset
dwRootCellOffset = *(DWORD*)(pMemory + 0x24);
// 获取HIVE文件总长度
dwLength = *(DWORD*)(pMemory + 0x28);
// HIVE文件名称
pwszHiveName = (WCHAR*)(pMemory + 0x30);
// 显示
printf("-----------------------------------------------------------------------\n");
printf("dwMajor=%d, dwMinor=%d\n", dwMajor, dwMinor);
printf("RootCellOffset=0x%X, dwLength=0x%X\n", dwRootCellOffset, dwLength);
printf("szHiveName=%S\n", pwszHiveName);
printf("-----------------------------------------------------------------------\n\n");
// 分析hbin
pHBIN = pMemory + 0x1000;
// 分析NK
bRet = HiveNK(pHBIN, (pHBIN + dwRootCellOffset));
return bRet;
};
// 分析NK
BOOL HiveNK(PUCHAR pHBIN, PUCHAR pNode) {
char* pszNodeName = NULL;
USHORT usSignature = 0;
DWORD dwSubNodeCount = 0;
DWORD dwSubNodeOffset = 0;
DWORD dwValueCount = 0;
DWORD dwValueOffset = 0;
DWORD dwNodeNameLength = 0;
DWORD dwValueOffsetList = NULL;
DWORD i = 0;
// 获取 签名
usSignature = *(USHORT*)(pNode + 0x4);
if (0x6B6E != usSignature) // nk
return FALSE;
// 获取 子键数量
dwSubNodeCount = *(DWORD*)(pNode + 0x18);
// 获取 子键索引
dwSubNodeOffset = *(DWORD*)(pNode + 0x20);
// 获取 键值数量
dwValueCount = *(DWORD*)(pNode + 0x28);
// 获取 键值索引
dwValueOffset = *(DWORD*)(pNode + 0x2C);
// 获取 键名长度
dwNodeNameLength = *(DWORD*)(pNode + 0x4C);
// 获取 键名
pszNodeName = (char*)(pNode + 0x50);
// 显示
for (i = 0; i < dwNodeNameLength; i++)
printf("%c", pszNodeName[i]);
printf("\n");
// 遍历键值
for (i = 0; i < dwValueCount; i++) {
// 分析VK
DWORD dwOffset = *(DWORD*)(pHBIN + dwValueOffset + 4 * (1 + i));
HiveVK(pHBIN, (pHBIN + dwOffset));
};
// 遍历子键
for (i = 0; i < dwSubNodeCount; i++)
// 分析LIST
HiveList(pHBIN, (pHBIN + dwSubNodeOffset));
return TRUE;
};
// 分析VK
BOOL HiveVK(PUCHAR pHBIN, PUCHAR pValue) {
char* pszValueName = NULL;
USHORT usSignature = 0;
USHORT usValueNameLength = 0;
DWORD dwValueDataLength = 0;
DWORD dwValueData = 0;
DWORD dwValueType = 0;
DWORD i = 0;
// 获取 签名
usSignature = *(USHORT*)(pValue + 0x4);
if (0x6B76 != usSignature) //vk
return FALSE;
// 获取 键值名称长度
usValueNameLength = *(USHORT*)(pValue + 0x6);
// 获取 键值数据长度
dwValueDataLength = *(DWORD*)(pValue + 0x8);
// 获取 键值数据
dwValueData = *(DWORD*)(pValue + 0xC);
// 获取 键值数据类型
dwValueType = *(DWORD*)(pValue + 0x10);
// 获取 键值名称
pszValueName = (char*)(pValue + 0x18);
// 显示
// 键值数据名称
for (i = 0; i < usValueNameLength; i++)
printf("%c", pszValueName[i]);
// 键值数据类型
printf(", %d\n", dwValueType);
/*
printf(", %d, ", dwValueType);
// 键值数据
// 判断是否是驻留数据
if (0x80000000 < dwValueDataLength) {
// 驻留数据
dwValueDataLength = dwValueDataLength - 0x80000000;
switch (dwValueDataLength) {
case 1: {
dwValueData = dwValueData & 0x000000FF;
break;
};
case 2: {
dwValueData = dwValueData & 0x0000FFFF;
break;
};
case 3: {
dwValueData = dwValueData & 0x00FFFFFF;
break;
};
case 4: {
dwValueData = dwValueData & 0xFFFFFFFF;
break;
};
default:
break;
};
printf("%X\n", dwValueData);
}
else {
// 非驻留数据
for (i = 0; i < dwValueDataLength; i++)
printf("0x%X ", *(UCHAR*)(pHBIN + dwValueData + 0x4 + i));
printf("\n");
};
*/
return TRUE;
};
// 分析LIST
BOOL HiveList(PUCHAR pHBIN, PUCHAR pList) {
USHORT usSignature = 0;
USHORT usCount = 0;
DWORD dwOffset = 0;
USHORT i = 0;
// 获取 签名
usSignature = *(USHORT*)(pList + 0x4);
// 获取 数量
usCount = *(USHORT*)(pList + 0x6);
// 判断
if (0x666C == usSignature || 0x686C == usSignature) { // lf lh
// 获取偏移量
for (i = 0; i < usCount; i++) {
dwOffset = *(DWORD*)(pList + 0x8 + 8 * i);
HiveNK(pHBIN, (pHBIN + dwOffset));
};
}
else if (0x696C == usSignature || 0x6972 == usSignature) { // li ri
// 获取偏移量
for (i = 0; i < usCount; i++) {
dwOffset = *(DWORD*)(pList + 0x8 + 4 * i);
HiveList(pHBIN, (pHBIN + dwOffset));
};
}
else if (0x6264 == usSignature) { // db
// 获取偏移量
dwOffset = *(DWORD*)(pList + 0x8);
HiveVK(pHBIN, (pHBIN + dwOffset));
};
return TRUE;
};