Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/tools/winedump/reg.c
4388 views
1
/*
2
* Dump Windows NT Registry File (REGF)
3
*
4
* Copyright 2023 Piotr Caban for CodeWeavers
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
*/
20
21
#include "config.h"
22
#include "winedump.h"
23
24
#define BLOCK_SIZE 4096
25
26
#define SECSPERDAY 86400
27
/* 1601 to 1970 is 369 years plus 89 leap days */
28
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
29
#define TICKSPERSEC 10000000
30
31
enum file_type
32
{
33
REG_HIVE
34
};
35
36
typedef struct
37
{
38
unsigned int signature;
39
unsigned int seq_prim;
40
unsigned int seq_sec;
41
FILETIME modif_time;
42
unsigned int ver_major;
43
unsigned int ver_minor;
44
enum file_type file_type;
45
unsigned int unk1;
46
unsigned int root_key_off;
47
unsigned int hive_bins_size;
48
unsigned int unk2[116];
49
unsigned int checksum;
50
} header;
51
52
enum key_flags
53
{
54
KEY_IS_VOLATILE = 0x01,
55
KEY_HIVE_EXIT = 0x02,
56
KEY_HIVE_ENTRY = 0x04,
57
KEY_NO_DELETE = 0x08,
58
KEY_SYM_LINK = 0x10,
59
KEY_COMP_NAME = 0x20
60
};
61
62
typedef struct
63
{
64
unsigned int size;
65
short signature;
66
short flags;
67
FILETIME timestamp;
68
int unk1;
69
unsigned int parent_off;
70
unsigned int sub_keys;
71
unsigned int volatile_sub_keys;
72
unsigned int sub_keys_list_off;
73
unsigned int volatile_sub_keys_list_off;
74
unsigned int values;
75
unsigned int values_list_off;
76
unsigned int sec_key_off;
77
unsigned int class_off;
78
unsigned int max_name_size;
79
unsigned int max_class_size;
80
unsigned int max_val_name_size;
81
unsigned int max_val_size;
82
int unk2;
83
unsigned short name_size;
84
unsigned short class_size;
85
} named_key;
86
87
enum val_flags
88
{
89
VAL_COMP_NAME = 0x1
90
};
91
92
typedef struct
93
{
94
unsigned int size;
95
unsigned short signature;
96
unsigned short name_size;
97
unsigned int data_size;
98
unsigned int data_off;
99
unsigned int data_type;
100
unsigned short flags;
101
unsigned short padding;
102
} value_key;
103
104
typedef struct
105
{
106
unsigned int size;
107
unsigned short signature;
108
unsigned short count;
109
} key_list;
110
111
static unsigned int path_len;
112
static char path[512*256];
113
114
static BOOL dump_key(unsigned int hive_off, unsigned int off);
115
116
static time_t filetime_to_time_t(FILETIME ft)
117
{
118
ULONGLONG *ull = (ULONGLONG *)&ft;
119
time_t t = *ull / TICKSPERSEC - SECS_1601_TO_1970;
120
return *ull ? t : 0;
121
}
122
123
static const char *filetime_str(FILETIME ft)
124
{
125
return get_time_str(filetime_to_time_t(ft));
126
}
127
128
static unsigned int header_checksum(const header *h)
129
{
130
unsigned int i, checksum = 0;
131
132
for (i = 0; i < FIELD_OFFSET(header, checksum) / sizeof(int); i++)
133
checksum ^= ((unsigned int*)h)[i];
134
return checksum;
135
}
136
137
enum FileSig get_kind_reg(void)
138
{
139
const header *hdr;
140
141
hdr = PRD(0, BLOCK_SIZE);
142
if (hdr && !memcmp(&hdr->signature, "regf", sizeof(hdr->signature)))
143
return SIG_REG;
144
return SIG_UNKNOWN;
145
}
146
147
static BOOL dump_subkeys(unsigned int hive_off, unsigned int off)
148
{
149
const key_list *key_list = PRD(hive_off + off, sizeof(*key_list));
150
const unsigned int *offs;
151
unsigned int i;
152
153
if (!key_list)
154
return FALSE;
155
156
if (!memcmp(&key_list->signature, "lf", 2) ||
157
!memcmp(&key_list->signature, "lh", 2) ||
158
!memcmp(&key_list->signature, "li", 2))
159
{
160
unsigned int elem_size = memcmp(&key_list->signature, "li", 2) ? 2 : 1;
161
162
offs = PRD(hive_off + off + sizeof(*key_list),
163
key_list->count * elem_size * sizeof(*offs));
164
if (!offs)
165
return FALSE;
166
167
for (i = 0; i < key_list->count; i++)
168
{
169
if (!dump_key(hive_off, offs[elem_size * i]))
170
return FALSE;
171
}
172
}
173
else if (!memcmp(&key_list->signature, "ri", 2))
174
{
175
offs = PRD(hive_off + off + sizeof(*key_list), key_list->count * sizeof(*offs));
176
if (!offs)
177
return FALSE;
178
179
for (i = 0; i < key_list->count; i++)
180
{
181
if (!dump_subkeys(hive_off, offs[i]))
182
return FALSE;
183
}
184
}
185
else
186
{
187
return FALSE;
188
}
189
190
return TRUE;
191
}
192
193
static BOOL dump_value(unsigned int hive_off, unsigned int off)
194
{
195
unsigned int i, len, data_size;
196
const void *data = NULL;
197
const char *name, *str;
198
const value_key *val;
199
200
val = PRD(hive_off + off, sizeof(*val));
201
if (!val || memcmp(&val->signature, "vk", 2))
202
return FALSE;
203
204
if (!(val->data_size & 0x80000000) && val->data_size > 4 * BLOCK_SIZE)
205
{
206
printf("Warning: data blocks not supported\n");
207
return TRUE;
208
}
209
210
if (val->name_size && !(val->flags & VAL_COMP_NAME))
211
{
212
name = PRD(hive_off + off + sizeof(*val), val->name_size);
213
if (!name)
214
return FALSE;
215
name = get_unicode_str((WCHAR *)name, val->name_size / sizeof(WCHAR));
216
len = strlen(name) + 1;
217
218
printf("%s=", name);
219
}
220
else if (val->name_size)
221
{
222
name = PRD(hive_off + off + sizeof(*val), val->name_size);
223
if (!name)
224
return FALSE;
225
len = val->name_size + 3;
226
227
printf("\"%.*s\"=", val->name_size, name);
228
}
229
else
230
{
231
len = 2;
232
printf("@=");
233
}
234
235
data_size = val->data_size;
236
if (data_size & 0x80000000)
237
{
238
data = &val->data_off;
239
data_size &= ~0x80000000;
240
}
241
else if (data_size)
242
{
243
data = PRD(hive_off + val->data_off + sizeof(unsigned int), data_size);
244
if (!data)
245
return FALSE;
246
}
247
248
switch (val->data_type)
249
{
250
case REG_NONE:
251
/* TODO: dump as REG_NONE value. */
252
printf("hex:");
253
break;
254
case REG_EXPAND_SZ:
255
printf("str(2):");
256
/* fall through */
257
case REG_SZ:
258
printf("%s", !data ? "\"\"" :
259
get_unicode_str((const WCHAR *)data, data_size / sizeof(WCHAR)));
260
break;
261
case REG_QWORD:
262
case REG_BINARY:
263
printf("hex%s:", val->data_type == REG_QWORD ? "(b)" : "");
264
len += 4 + (val->data_type == REG_QWORD ? 3 : 0);
265
for (i = 0; i < data_size; i++)
266
{
267
if (i)
268
{
269
printf(",");
270
len += 1;
271
}
272
if (len > 76)
273
{
274
printf("\\\n ");
275
len = 2;
276
}
277
printf("%02x", ((BYTE *)data)[i]);
278
len += 2;
279
}
280
break;
281
case REG_DWORD:
282
assert(data_size == sizeof(DWORD) || !data_size);
283
if (data_size)
284
printf("dword:%08x", *(unsigned int *)data);
285
else
286
printf("hex(4):");
287
break;
288
case REG_MULTI_SZ:
289
printf("str(7):\"");
290
291
while(data_size > sizeof(WCHAR))
292
{
293
for (len = 0; len < data_size / sizeof(WCHAR); len++)
294
if (!((WCHAR *)data)[len])
295
break;
296
str = get_unicode_str(data, len);
297
298
printf("%.*s\\0", (unsigned int)strlen(str + 1) - 1, str + 1);
299
data = ((WCHAR *)data) + len + 1;
300
data_size -= (len + 1) * sizeof(WCHAR);
301
}
302
printf("\"");
303
break;
304
default:
305
printf("unhandled data type %d", val->data_type);
306
}
307
308
printf("\n");
309
return TRUE;
310
}
311
312
static BOOL dump_key(unsigned int hive_off, unsigned int off)
313
{
314
const named_key *key;
315
const char *name;
316
BOOL ret = TRUE;
317
318
key = PRD(hive_off + off, sizeof(*key));
319
if (!key || memcmp(&key->signature, "nk", 2))
320
return FALSE;
321
322
if (!(key->flags & KEY_COMP_NAME))
323
{
324
printf("unsupported key flags: %x\n", key->flags);
325
return FALSE;
326
}
327
328
name = PRD(hive_off + off + sizeof(*key), key->name_size);
329
if (!name)
330
return FALSE;
331
if (path_len)
332
path[path_len++] = '\\';
333
memcpy(path + path_len, name, key->name_size);
334
path_len += key->name_size;
335
path[path_len] = 0;
336
337
if ((!key->sub_keys && !key->volatile_sub_keys) || key->values)
338
{
339
printf("[%s] %u\n", path, (int)filetime_to_time_t(key->timestamp));
340
printf("#time=%x%08x\n", (int)key->timestamp.dwHighDateTime, (int)key->timestamp.dwLowDateTime);
341
342
if (key->values)
343
{
344
const unsigned int *offs = PRD(hive_off + key->values_list_off + sizeof(unsigned int),
345
key->values * sizeof(unsigned int));
346
unsigned int i;
347
348
if (!offs)
349
return FALSE;
350
351
for (i = 0; i < key->values; i++)
352
{
353
ret = dump_value(hive_off, offs[i]);
354
if (!ret)
355
return ret;
356
}
357
}
358
else
359
{
360
printf("@=\"\"\n");
361
}
362
if (!ret)
363
return FALSE;
364
365
printf("\n");
366
}
367
368
if (key->sub_keys)
369
ret = dump_subkeys(hive_off, key->sub_keys_list_off);
370
371
path_len -= key->name_size + 1;
372
path[path_len] = 0;
373
return ret;
374
}
375
376
void reg_dump(void)
377
{
378
const header *hdr;
379
380
hdr = PRD(0, sizeof(BLOCK_SIZE));
381
if (!hdr)
382
return;
383
384
printf("File Header\n");
385
printf(" %-20s %.4s\n", "signature:", (char*)&hdr->signature);
386
printf(" %-20s %u\n", "primary sequence:", hdr->seq_prim);
387
printf(" %-20s %u\n", "secondary sequence:", hdr->seq_sec);
388
printf(" %-20s %s\n", "modification time:", filetime_str(hdr->modif_time));
389
printf(" %-20s %u.%d\n", "version:", hdr->ver_major, hdr->ver_minor);
390
printf(" %-20s %u\n", "file type:", hdr->file_type);
391
printf(" %-20s %u\n", "root key offset:", hdr->root_key_off);
392
printf(" %-20s %u\n", "hive bins size:", hdr->hive_bins_size);
393
printf(" %-20s %x (%svalid)\n", "checksum:", hdr->checksum,
394
header_checksum(hdr) == hdr->checksum ? "" : "in");
395
printf("\n");
396
397
if (hdr->ver_major != 1 || hdr->ver_minor < 2 || hdr->ver_minor > 5 ||
398
hdr->file_type != REG_HIVE)
399
{
400
printf("unsupported format, exiting\n");
401
return;
402
}
403
404
path_len = 0;
405
path[0] = 0;
406
if (!dump_key(BLOCK_SIZE, hdr->root_key_off))
407
printf("error dumping file\n");
408
}
409
410