CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/pxesploit/regeditor/ntreg.c
Views: 11780
1
/*
2
* ntreg.c - NT Registry Hive access library
3
*
4
* 2010-jun: Patches from Frediano Ziglio adding support for wide characters
5
* and some bugfixes. Thank you!
6
* 2008-mar: Type QWORD (XP/Vista and newer) now recognized
7
* 2008-mar: Most functions accepting a path now also have a parameter specifying if
8
* the search should be exact or on first match basis
9
* 2008-mar: Fixed bug which skipped first indirect index table when deleting keys,
10
* usually leading to endless loop when recursive deleting.
11
* 2008-mar: Export to .reg file by Leo von Klenze, expanded a bit by me.
12
* 2008-mar: 64 bit compatible patch by Mike Doty, via Alon Bar-Lev
13
* http://bugs.gentoo.org/show_bug.cgi?id=185411
14
* 2007-sep: Verbosity/debug messages minor changes
15
* 2007-apr: LGPL license.
16
* 2004-aug: Deep indirect index support. NT351 support. Recursive delete.
17
* Debugged a lot in allocation routines. Still no expansion.
18
* 2004-jan: Verbosity updates
19
* 2003-jan: Allocation of new data, supports adding/deleting keys & stuff.
20
* Missing is expanding the file.
21
* 2003-jan: Seems there may be garbage pages at end of file, not zero pages
22
* now stops enumerating at first non 'hbin' page.
23
*
24
* NOTE: The API is not frozen. It can and will change every release.
25
*
26
*****
27
*
28
* NTREG - Window registry file reader / writer library
29
* Copyright (c) 1997-2010 Petter Nordahl-Hagen.
30
*
31
* This library is free software; you can redistribute it and/or
32
* modify it under the terms of the GNU Lesser General Public
33
* License as published by the Free Software Foundation;
34
* version 2.1 of the License.
35
*
36
* This library is distributed in the hope that it will be useful,
37
* but WITHOUT ANY WARRANTY; without even the implied warranty of
38
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39
* Lesser General Public License for more details.
40
* See file LGPL.txt for the full license.
41
*
42
*/
43
44
#include <stdio.h>
45
#include <stdlib.h>
46
#include <ctype.h>
47
#include <sys/types.h>
48
#include <sys/stat.h>
49
#include <fcntl.h>
50
#include <errno.h>
51
#include <string.h>
52
#include <unistd.h>
53
#include <inttypes.h>
54
55
#include "ntreg.h"
56
57
/* Set to abort() and debug on more critical errors */
58
#define DOCORE 1
59
60
#define ZEROFILL 1 /* Fill blocks with zeroes when allocating and deallocating */
61
#define ZEROFILLONLOAD 0 /* Fill blocks marked as unused/deallocated with zeroes on load. FOR DEBUG */
62
63
const char ntreg_version[] = "ntreg lib routines, v0.94.1 100627, (c) Petter N Hagen";
64
65
const char *val_types[REG_MAX+1] = {
66
"REG_NONE", "REG_SZ", "REG_EXPAND_SZ", "REG_BINARY", "REG_DWORD", /* 0 - 4 */
67
"REG_DWORD_BIG_ENDIAN", "REG_LINK", /* 5 - 6 */
68
"REG_MULTI_SZ", "REG_RESOUCE_LIST", "REG_FULL_RES_DESC", "REG_RES_REQ", /* 7 - 10 */
69
"REG_QWORD", /* 11 */
70
};
71
72
static char * string_regw2prog(void *string, int len);
73
static char * string_rega2prog(void *string, int len);
74
static char * string_prog2regw(void *string, int len, int* out_len);
75
static void string_prog2rega(char *string, int len);
76
77
/* Utility routines */
78
char *str_dup( const char *str )
79
{
80
char *str_new;
81
82
if (!str)
83
return 0 ;
84
85
CREATE( str_new, char, strlen(str) + 1 );
86
strcpy( str_new, str );
87
return str_new;
88
}
89
90
int fmyinput(char *prmpt, char *ibuf, int maxlen)
91
{
92
93
printf("%s",prmpt);
94
95
fgets(ibuf,maxlen+1,stdin);
96
97
ibuf[strlen(ibuf)-1] = 0;
98
99
return(strlen(ibuf));
100
}
101
102
/* Print len number of hexbytes */
103
104
void hexprnt(char *s, unsigned char *bytes, int len)
105
{
106
int i;
107
108
printf("%s",s);
109
for (i = 0; i < len; i++) {
110
printf("%02x ",bytes[i]);
111
}
112
printf("\n");
113
}
114
115
/* HexDump all or a part of some buffer */
116
117
void hexdump(char *hbuf, int start, int stop, int ascii)
118
{
119
char c;
120
int diff,i;
121
122
while (start < stop ) {
123
124
diff = stop - start;
125
if (diff > 16) diff = 16;
126
127
printf(":%05X ",start);
128
129
for (i = 0; i < diff; i++) {
130
printf("%02X ",(unsigned char)*(hbuf+start+i));
131
}
132
if (ascii) {
133
for (i = diff; i < 16; i++) printf(" ");
134
for (i = 0; i < diff; i++) {
135
c = *(hbuf+start+i);
136
printf("%c", isprint(c) ? c : '.');
137
}
138
}
139
printf("\n");
140
start += 16;
141
}
142
}
143
144
/* General search routine, find something in something else */
145
int find_in_buf(char *buf, char *what, int sz, int len, int start)
146
{
147
int i;
148
149
for (; start < sz; start++) {
150
for (i = 0; i < len; i++) {
151
if (*(buf+start+i) != *(what+i)) break;
152
}
153
if (i == len) return(start);
154
}
155
return(0);
156
}
157
158
/* Get INTEGER from memory. This is probably low-endian specific? */
159
int get_int( char *array )
160
{
161
return ((array[0]&0xff) + ((array[1]<<8)&0xff00) +
162
((array[2]<<16)&0xff0000) +
163
((array[3]<<24)&0xff000000));
164
}
165
166
167
/* Quick and dirty UNICODE to std. ascii */
168
169
void cheap_uni2ascii(char *src, char *dest, int l)
170
{
171
172
for (; l > 0; l -=2) {
173
*dest = *src;
174
dest++; src +=2;
175
}
176
*dest = 0;
177
}
178
179
180
/* Quick and dirty ascii to unicode */
181
182
void cheap_ascii2uni(char *src, char *dest, int l)
183
{
184
for (; l > 0; l--) {
185
*dest++ = *src++;
186
*dest++ = 0;
187
188
}
189
}
190
191
void skipspace(char **c)
192
{
193
while( **c == ' ' ) (*c)++;
194
}
195
196
int gethex(char **c)
197
{
198
int value;
199
200
skipspace(c);
201
202
if (!(**c)) return(0);
203
204
sscanf(*c,"%x",&value);
205
206
while( **c != ' ' && (**c)) (*c)++;
207
208
return(value);
209
}
210
211
/* Get a string of HEX bytes (space separated),
212
* or if first char is ' get an ASCII string instead.
213
*/
214
215
int gethexorstr(char **c, char *wb)
216
{
217
int l = 0;
218
219
skipspace(c);
220
221
if ( **c == '\'') {
222
(*c)++;
223
while ( **c ) {
224
*(wb++) = *((*c)++);
225
l++;
226
}
227
} else {
228
do {
229
*(wb++) = gethex(c);
230
l++;
231
skipspace(c);
232
} while ( **c );
233
}
234
return(l);
235
}
236
237
/* Simple buffer debugger, returns 1 if buffer dirty/edited */
238
239
int debugit(char *buf, int sz)
240
{
241
242
243
char inbuf[100],whatbuf[100],*bp;
244
245
int dirty=0,to,from,l,i,j,wlen,cofs = 0;
246
247
printf("Buffer debugger. '?' for help.\n");
248
249
while (1) {
250
l = fmyinput(".",inbuf,90);
251
bp = inbuf;
252
253
skipspace(&bp);
254
255
if (l > 0 && *bp) {
256
switch(*bp) {
257
case 'd' :
258
bp++;
259
if (*bp) {
260
from = gethex(&bp);
261
to = gethex(&bp);
262
} else {
263
from = cofs; to = 0;
264
}
265
if (to == 0) to = from + 0x100;
266
if (to > sz) to = sz;
267
hexdump(buf,from,to,1);
268
cofs = to;
269
break;
270
case 'a' :
271
bp++;
272
if (*bp) {
273
from = gethex(&bp);
274
to = gethex(&bp);
275
} else {
276
from = cofs; to = 0;
277
}
278
if (to == 0) to = from + 0x100;
279
if (to > sz) to = sz;
280
hexdump(buf,from,to,0);
281
cofs = to;
282
break;
283
#if 0
284
case 'k' :
285
bp++;
286
if (*bp) {
287
from = gethex(&bp);
288
} else {
289
from = cofs;
290
}
291
if (to > sz) to = sz;
292
parse_block(from,1);
293
cofs = to;
294
break;
295
#endif
296
#if 0
297
case 'l' :
298
bp++;
299
if (*bp) {
300
from = gethex(&bp);
301
} else {
302
from = cofs;
303
}
304
if (to > sz) to = sz;
305
nk_ls(from+4,0);
306
cofs = to;
307
break;
308
#endif
309
case 'q':
310
return(0);
311
break;
312
case 's':
313
if (!dirty) printf("Buffer has not changed, no need to write..\n");
314
return(dirty);
315
break;
316
case 'h':
317
bp++;
318
if (*bp == 'a') {
319
from = 0;
320
to = sz;
321
bp++;
322
} else {
323
from = gethex(&bp);
324
to = gethex(&bp);
325
}
326
wlen = gethexorstr(&bp,whatbuf);
327
if (to > sz) to = sz;
328
printf("from: %x, to: %x, wlen: %d\n",from,to,wlen);
329
for (i = from; i < to; i++) {
330
for (j = 0; j < wlen; j++) {
331
if ( *(buf+i+j) != *(whatbuf+j)) break;
332
}
333
if (j == wlen) printf("%06x ",i);
334
}
335
printf("\n");
336
break;
337
case ':':
338
bp++;
339
if (!*bp) break;
340
from = gethex(&bp);
341
wlen = gethexorstr(&bp,whatbuf);
342
343
printf("from: %x, wlen: %d\n",from,wlen);
344
345
memcpy(buf+from,whatbuf,wlen);
346
dirty = 1;
347
break;
348
#if 0
349
case 'p':
350
j = 0;
351
if (*(++bp) != 0) {
352
from = gethex(&bp);
353
}
354
if (*(++bp) != 0) {
355
j = gethex(&bp);
356
}
357
printf("from: %x, rid: %x\n",from,j);
358
seek_n_destroy(from,j,500,0);
359
break;
360
#endif
361
case '?':
362
printf("d [<from>] [<to>] - dump buffer within range\n");
363
printf("a [<from>] [<to>] - same as d, but without ascii-part (for cut'n'paste)\n");
364
printf(": <offset> <hexbyte> [<hexbyte> ...] - change bytes\n");
365
printf("h <from> <to> <hexbyte> [<hexbyte> ...] - hunt (search) for bytes\n");
366
printf("ha <hexbyte> [<hexbyte] - Hunt all (whole buffer)\n");
367
printf("s - save & quit\n");
368
printf("q - quit (no save)\n");
369
printf(" instead of <hexbyte> etc. you may give 'string to enter/search a string\n");
370
break;
371
default:
372
printf("?\n");
373
break;
374
}
375
}
376
}
377
}
378
379
380
/* ========================================================================= */
381
382
/* The following routines are mostly for debugging, I used it
383
* much during discovery. the -t command line option uses it,
384
* also the 'st' and 's' from the editor & hexdebugger.
385
* All offsets shown in these are unadjusted (ie you must add
386
* headerpage (most often 0x1000) to get file offset)
387
*/
388
389
/* Parse the nk datablock
390
* vofs = offset into struct (after size linkage)
391
*/
392
void parse_nk(struct hive *hdesc, int vofs, int blen)
393
{
394
395
struct nk_key *key;
396
int i;
397
398
printf("== nk at offset %0x\n",vofs);
399
400
/* #define D_OFFS2(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs ) */
401
#define D_OFFS(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs )
402
403
key = (struct nk_key *)(hdesc->buffer + vofs);
404
printf("%04lx type = 0x%02x %s\n", D_OFFS(type) ,key->type,
405
(key->type == KEY_ROOT ? "ROOT_KEY" : "") );
406
printf("%04lx timestamp skipped\n", D_OFFS(timestamp) );
407
printf("%04lx parent key offset = 0x%0x\n", D_OFFS(ofs_parent) ,key->ofs_parent);
408
printf("%04lx number of subkeys = %d\n", D_OFFS(no_subkeys),key->no_subkeys);
409
printf("%04lx lf-record offset = 0x%0x\n",D_OFFS(ofs_lf),key->ofs_lf);
410
printf("%04lx number of values = %d\n", D_OFFS(no_values),key->no_values);
411
printf("%04lx val-list offset = 0x%0x\n",D_OFFS(ofs_vallist),key->ofs_vallist);
412
printf("%04lx sk-record offset = 0x%0x\n",D_OFFS(ofs_sk),key->ofs_sk);
413
printf("%04lx classname offset = 0x%0x\n",D_OFFS(ofs_classnam),key->ofs_classnam);
414
printf("%04lx *unused?* = 0x%0x\n",D_OFFS(dummy4),key->dummy4);
415
printf("%04lx name length = %d\n", D_OFFS(len_name),key->len_name);
416
printf("%04lx classname length = %d\n", D_OFFS(len_classnam),key->len_classnam);
417
418
printf("%04lx Key name: <",D_OFFS(keyname) );
419
for(i = 0; i < key->len_name; i++) putchar(key->keyname[i]);
420
printf(">\n== End of key info.\n");
421
422
}
423
424
/* Parse the vk datablock
425
* vofs = offset into struct (after size linkage)
426
*/
427
void parse_vk(struct hive *hdesc, int vofs, int blen)
428
{
429
struct vk_key *key;
430
int i;
431
432
printf("== vk at offset %0x\n",vofs);
433
434
435
key = (struct vk_key *)(hdesc->buffer + vofs);
436
printf("%04lx name length = %d (0x%0x)\n", D_OFFS(len_name),
437
key->len_name, key->len_name );
438
printf("%04lx length of data = %d (0x%0x)\n", D_OFFS(len_data),
439
key->len_data, key->len_data );
440
printf("%04lx data offset = 0x%0x\n",D_OFFS(ofs_data),key->ofs_data);
441
printf("%04lx value type = 0x%0x %s\n", D_OFFS(val_type), key->val_type,
442
(key->val_type <= REG_MAX ? val_types[key->val_type] : "(unknown)") ) ;
443
444
printf("%04lx flag = 0x%0x\n",D_OFFS(flag),key->flag);
445
printf("%04lx *unused?* = 0x%0x\n",D_OFFS(dummy1),key->dummy1);
446
447
printf("%04lx Key name: <",D_OFFS(keyname) );
448
for(i = 0; i < key->len_name; i++) putchar(key->keyname[i]);
449
printf(">\n== End of key info.\n");
450
451
}
452
453
/* Parse the sk datablock
454
* Gee, this is the security info. Who cares? *evil grin*
455
* vofs = offset into struct (after size linkage)
456
*/
457
void parse_sk(struct hive *hdesc, int vofs, int blen)
458
{
459
struct sk_key *key;
460
/* int i; */
461
462
printf("== sk at offset %0x\n",vofs);
463
464
key = (struct sk_key *)(hdesc->buffer + vofs);
465
printf("%04lx *unused?* = %d\n" , D_OFFS(dummy1), key->dummy1 );
466
printf("%04lx Offset to prev sk = 0x%0x\n", D_OFFS(ofs_prevsk), key->ofs_prevsk);
467
printf("%04lx Offset to next sk = 0x%0x\n", D_OFFS(ofs_nextsk), key->ofs_nextsk);
468
printf("%04lx Usage counter = %d (0x%0x)\n", D_OFFS(no_usage),
469
key->no_usage,key->no_usage);
470
printf("%04lx Security data len = %d (0x%0x)\n", D_OFFS(len_sk),
471
key->len_sk,key->len_sk);
472
473
printf("== End of key info.\n");
474
475
}
476
477
478
/* Parse the lf datablock (>4.0 'nk' offsets lookuptable)
479
* vofs = offset into struct (after size linkage)
480
*/
481
void parse_lf(struct hive *hdesc, int vofs, int blen)
482
{
483
struct lf_key *key;
484
int i;
485
486
printf("== lf at offset %0x\n",vofs);
487
488
key = (struct lf_key *)(hdesc->buffer + vofs);
489
printf("%04lx number of keys = %d\n", D_OFFS(no_keys), key->no_keys );
490
491
for(i = 0; i < key->no_keys; i++) {
492
printf("%04lx %3d Offset: 0x%0x - <%c%c%c%c>\n",
493
D_OFFS(hash[i].ofs_nk), i,
494
key->hash[i].ofs_nk,
495
key->hash[i].name[0],
496
key->hash[i].name[1],
497
key->hash[i].name[2],
498
key->hash[i].name[3] );
499
}
500
501
printf("== End of key info.\n");
502
503
}
504
505
/* Parse the lh datablock (WinXP offsets lookuptable)
506
* vofs = offset into struct (after size linkage)
507
* The hash is most likely a base 37 conversion of the name string
508
*/
509
void parse_lh(struct hive *hdesc, int vofs, int blen)
510
{
511
struct lf_key *key;
512
int i;
513
514
printf("== lh at offset %0x\n",vofs);
515
516
key = (struct lf_key *)(hdesc->buffer + vofs);
517
printf("%04lx number of keys = %d\n", D_OFFS(no_keys), key->no_keys );
518
519
for(i = 0; i < key->no_keys; i++) {
520
printf("%04lx %3d Offset: 0x%0x - <hash: %08x>\n",
521
D_OFFS(lh_hash[i].ofs_nk), i,
522
key->lh_hash[i].ofs_nk,
523
key->lh_hash[i].hash );
524
}
525
526
printf("== End of key info.\n");
527
528
}
529
530
531
/* Parse the li datablock (3.x 'nk' offsets list)
532
* vofs = offset into struct (after size linkage)
533
*/
534
void parse_li(struct hive *hdesc, int vofs, int blen)
535
{
536
struct li_key *key;
537
int i;
538
539
printf("== li at offset %0x\n",vofs);
540
541
/* #define D_OFFS(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs ) */
542
543
key = (struct li_key *)(hdesc->buffer + vofs);
544
printf("%04lx number of keys = %d\n", D_OFFS(no_keys), key->no_keys );
545
546
for(i = 0; i < key->no_keys; i++) {
547
printf("%04lx %3d Offset: 0x%0x\n",
548
D_OFFS(hash[i].ofs_nk), i,
549
key->hash[i].ofs_nk);
550
}
551
printf("== End of key info.\n");
552
553
}
554
555
/* Parse the ri subindex-datablock
556
* (Used to list li/lf/lh's when ~>500keys)
557
* vofs = offset into struct (after size linkage)
558
*/
559
void parse_ri(struct hive *hdesc, int vofs, int blen)
560
{
561
struct ri_key *key;
562
int i;
563
564
printf("== ri at offset %0x\n",vofs);
565
566
/* #define D_OFFS(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs ) */
567
568
key = (struct ri_key *)(hdesc->buffer + vofs);
569
printf("%04lx number of subindices = %d\n", D_OFFS(no_lis), key->no_lis );
570
571
for(i = 0; i < key->no_lis; i++) {
572
printf("%04lx %3d Offset: 0x%0x\n",
573
D_OFFS(hash[i].ofs_li), i,
574
key->hash[i].ofs_li);
575
}
576
printf("== End of key info.\n");
577
578
}
579
580
581
/* Parse the datablock
582
* vofs = offset into struct (after size linkage)
583
*/
584
585
int parse_block(struct hive *hdesc, int vofs,int verbose)
586
{
587
unsigned short id;
588
int seglen;
589
590
seglen = get_int(hdesc->buffer+vofs);
591
592
if (verbose || seglen == 0) {
593
printf("** Block at offset %0x\n",vofs);
594
printf("seglen: %d, %u, 0x%0x\n",seglen,seglen,seglen);
595
}
596
if (seglen == 0) {
597
printf("Whoops! FATAL! Zero data block size! (not registry or corrupt file?)\n");
598
debugit(hdesc->buffer,hdesc->size);
599
return(0);
600
}
601
602
if (seglen < 0) {
603
seglen = -seglen;
604
hdesc->usetot += seglen;
605
hdesc->useblk++;
606
if (verbose) {
607
printf("USED BLOCK: %d, 0x%0x\n",seglen,seglen);
608
/* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */
609
}
610
} else {
611
hdesc->unusetot += seglen;
612
hdesc->unuseblk++;
613
/* Useful to zero blocks we think are empty when debugging.. */
614
#if ZEROFILLONLOAD
615
bzero(hdesc->buffer+vofs+4,seglen-4);
616
#endif
617
618
if (verbose) {
619
printf("FREE BLOCK!\n");
620
/* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */
621
}
622
}
623
624
625
/* printf("Seglen: 0x%02x\n",seglen & 0xff ); */
626
627
vofs += 4;
628
id = (*(hdesc->buffer + vofs)<<8) + *(hdesc->buffer+vofs+1);
629
630
if (verbose) {
631
switch (id) {
632
case 0x6e6b: /* nk */
633
parse_nk(hdesc, vofs, seglen);
634
break;
635
case 0x766b: /* vk */
636
parse_vk(hdesc, vofs, seglen);
637
break;
638
case 0x6c66: /* lf */
639
parse_lf(hdesc, vofs, seglen);
640
break;
641
case 0x6c68: /* lh */
642
parse_lh(hdesc, vofs, seglen);
643
break;
644
case 0x6c69: /* li */
645
parse_li(hdesc, vofs, seglen);
646
break;
647
case 0x736b: /* sk */
648
parse_sk(hdesc, vofs, seglen);
649
break;
650
case 0x7269: /* ri */
651
parse_ri(hdesc, vofs, seglen);
652
break;
653
default:
654
printf("value data, or not handeled yet!\n");
655
break;
656
}
657
}
658
return(seglen);
659
}
660
661
/* ================================================================ */
662
/* Scan and allocation routines */
663
664
/* Find start of page given a current pointer into the buffer
665
* hdesc = hive
666
* vofs = offset pointer into buffer
667
* returns: offset to start of page (and page header)
668
*/
669
670
int find_page_start(struct hive *hdesc, int vofs)
671
{
672
int r,prev;
673
struct hbin_page *h;
674
675
/* Again, assume start at 0x1000 */
676
677
r = 0x1000;
678
while (r < hdesc->size) {
679
prev = r;
680
h = (struct hbin_page *)(hdesc->buffer + r);
681
if (h->id != 0x6E696268) return(0);
682
if (h->ofs_next == 0) {
683
printf("find_page_start: zero len or ofs_next found in page at 0x%x\n",r);
684
return(0);
685
}
686
r += h->ofs_next;
687
if (r > vofs) return (prev);
688
}
689
return(0);
690
}
691
692
/* Find free space in page
693
* size = requested size in bytes
694
* pofs = offset to start of actual page header
695
* returns: offset to free block, or 0 for error
696
*/
697
698
#define FB_DEBUG 0
699
700
int find_free_blk(struct hive *hdesc, int pofs, int size)
701
{
702
int vofs = pofs + 0x20;
703
int seglen;
704
struct hbin_page *p;
705
706
p = (struct hbin_page *)(hdesc->buffer + pofs);
707
708
while (vofs-pofs < (p->ofs_next - HBIN_ENDFILL)) {
709
710
seglen = get_int(hdesc->buffer+vofs);
711
712
#if FB_DEBUG
713
printf("** Block at offset %0x\n",vofs);
714
printf("seglen: %d, %u, 0x%0x\n",seglen,seglen,seglen);
715
#endif
716
717
if (seglen == 0) {
718
printf("find_free_blk: FATAL! Zero data block size! (not registry or corrupt file?)\n");
719
debugit(hdesc->buffer,hdesc->size);
720
return(0);
721
}
722
723
if (seglen < 0) {
724
seglen = -seglen;
725
#if FB_DEBUG
726
printf("USED BLOCK: %d, 0x%0x\n",seglen,seglen);
727
#endif
728
/* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */
729
} else {
730
#if FB_DEBUG
731
printf("FREE BLOCK!\n");
732
#endif
733
/* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */
734
if (seglen >= size) {
735
#if FB_DEBUG
736
printf("find_free_blk: found size %d block at 0x%x\n",seglen,vofs);
737
#endif
738
#if 0
739
if (vofs == 0x19fb8) {
740
printf("find_free_blk: vofs = %x, seglen = %x\n",vofs,seglen);
741
debugit(hdesc->buffer,hdesc->size);
742
abort();
743
}
744
#endif
745
return(vofs);
746
}
747
}
748
vofs += seglen;
749
}
750
return(0);
751
752
}
753
754
#undef FB_DEBUG
755
756
/* Search pages from start to find free block
757
* hdesc - hive
758
* size - space requested, in bytes
759
* returns: offset to free block, 0 if not found or error
760
*/
761
762
int find_free(struct hive *hdesc, int size)
763
{
764
int r,blk;
765
struct hbin_page *h;
766
767
/* Align to 8 byte boundary */
768
if (size & 7) size += (8 - (size & 7));
769
770
/* Again, assume start at 0x1000 */
771
772
r = 0x1000;
773
while (r < hdesc->size) {
774
h = (struct hbin_page *)(hdesc->buffer + r);
775
if (h->id != 0x6E696268) return(0);
776
if (h->ofs_next == 0) {
777
printf("find_free: zero len or ofs_next found in page at 0x%x\n",r);
778
return(0);
779
}
780
blk = find_free_blk(hdesc,r,size);
781
if (blk) return (blk);
782
r += h->ofs_next;
783
}
784
return(0);
785
}
786
787
/* Allocate a block of requested size if possible
788
* hdesc - hive
789
* pofs - If >0 will try this page first (ptr may be inside page)
790
* size - number of bytes to allocate
791
* returns: 0 - failed, else pointer to allocated block.
792
* This function WILL CHANGE THE HIVE (change block linkage) if it
793
* succeeds.
794
*/
795
796
int alloc_block(struct hive *hdesc, int ofs, int size)
797
{
798
int pofs = 0;
799
int blk = 0;
800
int trail, trailsize, oldsz;
801
802
if (hdesc->state & HMODE_NOALLOC) {
803
printf("alloc_block: ERROR: Hive %s is in no allocation safe mode,"
804
"new space not allocated. Operation will fail!\n", hdesc->filename);
805
return(0);
806
}
807
808
size += 4; /* Add linkage */
809
if (size & 7) size += (8 - (size & 7));
810
811
/* Check current page first */
812
if (ofs) {
813
pofs = find_page_start(hdesc,ofs);
814
blk = find_free_blk(hdesc,pofs,size);
815
}
816
817
/* Then check whole hive */
818
if (!blk) {
819
blk = find_free(hdesc,size);
820
}
821
822
if (blk) { /* Got the space */
823
oldsz = get_int(hdesc->buffer+blk);
824
#if 0
825
printf("Block at : %x\n",blk);
826
printf("Old block size is: %x\n",oldsz);
827
printf("New block size is: %x\n",size);
828
#endif
829
trailsize = oldsz - size;
830
831
if (trailsize == 4) {
832
trailsize = 0;
833
size += 4;
834
}
835
836
#if 1
837
if (trailsize & 7) { /* Trail must be 8 aligned */
838
trailsize -= (8 - (trailsize & 7));
839
size += (8 - (trailsize & 7));
840
}
841
if (trailsize == 4) {
842
trailsize = 0;
843
size += 4;
844
}
845
#endif
846
847
#if 0
848
printf("trail after comp: %x\n",trailsize);
849
printf("size after comp: %x\n",size);
850
#endif
851
852
/* Now change pointers on this to reflect new size */
853
*(int *)((hdesc->buffer)+blk) = -(size);
854
/* If the fit was exact (unused block was same size as wee need)
855
* there is no need for more, else make free block after end
856
* of newly allocated one */
857
858
hdesc->useblk++;
859
hdesc->unuseblk--;
860
hdesc->usetot += size;
861
hdesc->unusetot -= size;
862
863
if (trailsize) {
864
trail = blk + size;
865
866
*(int *)((hdesc->buffer)+trail) = (int)trailsize;
867
868
hdesc->useblk++; /* This will keep blockcount */
869
hdesc->unuseblk--;
870
hdesc->usetot += 4; /* But account for more linkage bytes */
871
hdesc->unusetot -= 4;
872
873
}
874
/* Clear the block data, makes it easier to debug */
875
#if ZEROFILL
876
bzero( (void *)(hdesc->buffer+blk+4), size-4);
877
#endif
878
879
hdesc->state |= HMODE_DIRTY;
880
881
return(blk);
882
} else {
883
printf("alloc_block: failed to alloc %d bytes, and hive expansion not implemented yet!\n",size);
884
}
885
return(0);
886
}
887
888
/* Free a block in registry
889
* hdesc - hive
890
* blk - offset of block, MUST POINT TO THE LINKAGE!
891
* returns bytes freed (incl linkage bytes) or 0 if fail
892
* Will CHANGE HIVE IF SUCCESSFUL (changes linkage)
893
*/
894
895
#define FB_DEBUG 0
896
897
int free_block(struct hive *hdesc, int blk)
898
{
899
int pofs,vofs,seglen,prev,next,nextsz,prevsz,size;
900
struct hbin_page *p;
901
902
if (hdesc->state & HMODE_NOALLOC) {
903
printf("free_block: ERROR: Hive %s is in no allocation safe mode,"
904
"space not freed. Operation will fail!\n", hdesc->filename);
905
return(0);
906
}
907
908
size = get_int(hdesc->buffer+blk);
909
if (size >= 0) {
910
printf("free_block: trying to free already free block!\n");
911
#ifdef DOCORE
912
printf("blk = %x\n",blk);
913
debugit(hdesc->buffer,hdesc->size);
914
abort();
915
#endif
916
return(0);
917
}
918
size = -size;
919
920
/* So, we must find start of the block BEFORE us */
921
pofs = find_page_start(hdesc,blk);
922
if (!pofs) return(0);
923
924
p = (struct hbin_page *)(hdesc->buffer + pofs);
925
vofs = pofs + 0x20;
926
927
prevsz = -32;
928
929
if (vofs != blk) { /* Block is not at start of page? */
930
while (vofs-pofs < (p->ofs_next - HBIN_ENDFILL) ) {
931
932
seglen = get_int(hdesc->buffer+vofs);
933
934
if (seglen == 0) {
935
printf("free_block: EEEK! Zero data block size! (not registry or corrupt file?)\n");
936
debugit(hdesc->buffer,hdesc->size);
937
return(0);
938
}
939
940
if (seglen < 0) {
941
seglen = -seglen;
942
/* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */
943
}
944
prev = vofs;
945
vofs += seglen;
946
if (vofs == blk) break;
947
}
948
949
if (vofs != blk) {
950
printf("free_block: ran off end of page!?!? Error in chains?\n");
951
#ifdef DOCORE
952
printf("vofs = %x, pofs = %x, blk = %x\n",vofs,pofs,blk);
953
debugit(hdesc->buffer,hdesc->size);
954
abort();
955
#endif
956
return(0);
957
}
958
959
prevsz = get_int(hdesc->buffer+prev);
960
961
}
962
963
/* We also need details on next block (unless at end of page) */
964
next = blk + size;
965
966
nextsz = 0;
967
if (next-pofs < (p->ofs_next - HBIN_ENDFILL) ) nextsz = get_int(hdesc->buffer+next);
968
969
#if 0
970
printf("offset prev : %x , blk: %x , next: %x\n",prev,blk,next);
971
printf("size prev : %x , blk: %x , next: %x\n",prevsz,size,nextsz);
972
#endif
973
974
/* Now check if next block is free, if so merge it with the one to be freed */
975
if ( nextsz > 0) {
976
#if 0
977
printf("Swallow next\n");
978
#endif
979
size += nextsz; /* Swallow it in current block */
980
hdesc->useblk--;
981
hdesc->usetot -= 4;
982
hdesc->unusetot -= 4; /* FIXME !??!?? */
983
}
984
985
/* Now free the block (possibly with ajusted size as above) */
986
#if ZEROFILL
987
bzero( (void *)(hdesc->buffer+blk), size);
988
#endif
989
990
*(int *)((hdesc->buffer)+blk) = (int)size;
991
hdesc->usetot -= size;
992
hdesc->unusetot -= size; /* FIXME !?!? */
993
hdesc->unuseblk--;
994
995
hdesc->state |= HMODE_DIRTY;
996
997
/* Check if previous block is also free, if so, merge.. */
998
if (prevsz > 0) {
999
#if 0
1000
printf("Swallow prev\n");
1001
#endif
1002
hdesc->usetot -= prevsz;
1003
hdesc->unusetot += prevsz;
1004
prevsz += size;
1005
/* And swallow current.. */
1006
#if ZEROFILL
1007
bzero( (void *)(hdesc->buffer+prev), prevsz);
1008
#endif
1009
*(int *)((hdesc->buffer)+prev) = (int)prevsz;
1010
hdesc->useblk--;
1011
return(prevsz);
1012
}
1013
return(size);
1014
}
1015
1016
1017
1018
1019
1020
/* ================================================================ */
1021
1022
/* ** Registry manipulation routines ** */
1023
1024
1025
1026
/* "directory scan", return next name/pointer of a subkey on each call
1027
* nkofs = offset to directory to scan
1028
* lfofs = pointer to int to hold the current scan position,
1029
* set position to 0 to start.
1030
* sptr = pointer to struct to hold a single result
1031
* returns: -1 = error. 0 = end of key. 1 = more subkeys to scan
1032
* NOTE: caller must free the name-buffer (struct ex_data *name)
1033
*/
1034
int ex_next_n(struct hive *hdesc, int nkofs, int *count, int *countri, struct ex_data *sptr)
1035
{
1036
struct nk_key *key, *newnkkey;
1037
int newnkofs;
1038
struct lf_key *lfkey;
1039
struct li_key *likey;
1040
struct ri_key *rikey;
1041
1042
1043
if (!nkofs) return(-1);
1044
key = (struct nk_key *)(hdesc->buffer + nkofs);
1045
if (key->id != 0x6b6e) {
1046
printf("ex_next error: Not a 'nk' node at 0x%0x\n",nkofs);
1047
return(-1);
1048
}
1049
1050
#define EXNDEBUG 0
1051
1052
lfkey = (struct lf_key *)(hdesc->buffer + key->ofs_lf + 0x1004);
1053
rikey = (struct ri_key *)(hdesc->buffer + key->ofs_lf + 0x1004);
1054
1055
if (rikey->id == 0x6972) { /* Is it extended 'ri'-block? */
1056
#if EXNDEBUG
1057
printf("%d , %d\n",*countri,*count);
1058
#endif
1059
if (*countri < 0 || *countri >= rikey->no_lis) { /* End of ri's? */
1060
return(0);
1061
}
1062
/* Get the li of lf-struct that's current based on countri */
1063
likey = (struct li_key *)( hdesc->buffer + rikey->hash[*countri].ofs_li + 0x1004 ) ;
1064
if (likey->id == 0x696c) {
1065
newnkofs = likey->hash[*count].ofs_nk + 0x1000;
1066
} else {
1067
lfkey = (struct lf_key *)( hdesc->buffer + rikey->hash[*countri].ofs_li + 0x1004 ) ;
1068
newnkofs = lfkey->hash[*count].ofs_nk + 0x1000;
1069
}
1070
1071
/* Check if current li/lf is exhausted */
1072
#if EXNDEBUG
1073
printf("likey->no_keys = %d\n",likey->no_keys);
1074
#endif
1075
if (*count >= likey->no_keys-1) { /* Last legal entry in li list? */
1076
(*countri)++; /* Bump up ri count so we take next ri entry next time */
1077
(*count) = -1; /* Reset li traverse counter for next round, not used later here */
1078
}
1079
} else { /* Plain handler */
1080
if (key->no_subkeys <= 0 || *count >= key->no_subkeys) {
1081
return(0);
1082
}
1083
if (lfkey->id == 0x696c) { /* Is it 3.x 'li' instead? */
1084
likey = (struct li_key *)(hdesc->buffer + key->ofs_lf + 0x1004);
1085
newnkofs = likey->hash[*count].ofs_nk + 0x1000;
1086
} else {
1087
newnkofs = lfkey->hash[*count].ofs_nk + 0x1000;
1088
}
1089
}
1090
1091
sptr->nkoffs = newnkofs;
1092
newnkkey = (struct nk_key *)(hdesc->buffer + newnkofs + 4);
1093
sptr->nk = newnkkey;
1094
1095
if (newnkkey->id != 0x6b6e) {
1096
printf("ex_next: ERROR: not 'nk' node at 0x%0x\n",newnkofs);
1097
1098
return(-1);
1099
} else {
1100
if (newnkkey->len_name <= 0) {
1101
printf("ex_next: nk at 0x%0x has no name!\n",newnkofs);
1102
} else if (newnkkey->type & 0x20) {
1103
#if 0
1104
printf("dummy1 %x\n", *((int*)newnkkey->dummy1));
1105
printf("dummy2 %x\n", *((int*)newnkkey->dummy2));
1106
printf("type %x\n", newnkkey->type);
1107
printf("timestamp+8 %x\n", *((int*)(newnkkey->timestamp+8)));
1108
printf("dummy3+0 %x\n", *((int*)(newnkkey->dummy3+0)));
1109
printf("dummy3+4 %x\n", *((int*)(newnkkey->dummy3+4)));
1110
printf("dummy3+8 %x\n", *((int*)(newnkkey->dummy3+8)));
1111
printf("dummy3+12 %x\n", *((int*)(newnkkey->dummy3+12)));
1112
printf("dummy4 %x\n", *((int*)&newnkkey->dummy4));
1113
printf("len %d\n", newnkkey->len_name);
1114
printf("len class %d\n", newnkkey->len_classnam);
1115
fflush(stdout);
1116
#endif
1117
sptr->name = string_rega2prog(newnkkey->keyname, newnkkey->len_name);
1118
} else {
1119
sptr->name = string_regw2prog(newnkkey->keyname, newnkkey->len_name);
1120
}
1121
} /* if */
1122
(*count)++;
1123
return(1);
1124
/* return( *count <= key->no_subkeys); */
1125
}
1126
1127
/* "directory scan" for VALUES, return next name/pointer of a value on each call
1128
* nkofs = offset to directory to scan
1129
* lfofs = pointer to int to hold the current scan position,
1130
* set position to 0 to start.
1131
* sptr = pointer to struct to hold a single result
1132
* returns: -1 = error. 0 = end of key. 1 = more values to scan
1133
* NOTE: caller must free the name-buffer (struct vex_data *name)
1134
*/
1135
int ex_next_v(struct hive *hdesc, int nkofs, int *count, struct vex_data *sptr)
1136
{
1137
struct nk_key *key /* , *newnkkey */ ;
1138
int vkofs,vlistofs;
1139
int *vlistkey;
1140
struct vk_key *vkkey;
1141
1142
1143
if (!nkofs) return(-1);
1144
key = (struct nk_key *)(hdesc->buffer + nkofs);
1145
if (key->id != 0x6b6e) {
1146
printf("ex_next_v error: Not a 'nk' node at 0x%0x\n",nkofs);
1147
return(-1);
1148
}
1149
1150
if (key->no_values <= 0 || *count >= key->no_values) {
1151
return(0);
1152
}
1153
1154
vlistofs = key->ofs_vallist + 0x1004;
1155
vlistkey = (int *)(hdesc->buffer + vlistofs);
1156
1157
vkofs = vlistkey[*count] + 0x1004;
1158
vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1159
if (vkkey->id != 0x6b76) {
1160
printf("ex_next_v: hit non valuekey (vk) node during scan at offs 0x%0x\n",vkofs);
1161
return(-1);
1162
}
1163
1164
/* parse_vk(hdesc, vkofs, 4); */
1165
1166
sptr->vk = vkkey;
1167
sptr->vkoffs = vkofs;
1168
sptr->name = 0;
1169
sptr->size = (vkkey->len_data & 0x7fffffff);
1170
1171
if (vkkey->len_name >0) {
1172
if (vkkey->flag & 1) {
1173
sptr->name = string_rega2prog(vkkey->keyname, vkkey->len_name);
1174
} else {
1175
sptr->name = string_regw2prog(vkkey->keyname, vkkey->len_name);
1176
}
1177
} else {
1178
sptr->name = str_dup("");
1179
}
1180
1181
sptr->type = vkkey->val_type;
1182
if (sptr->size) {
1183
if (vkkey->val_type == REG_DWORD) {
1184
if (vkkey->len_data & 0x80000000) {
1185
sptr->val = (int)(vkkey->ofs_data);
1186
}
1187
}
1188
} else if (vkkey->len_data == 0x80000000) {
1189
/* Data SIZE is 0, high bit set: special inline case, data is DWORD and in TYPE field!! */
1190
/* Used a lot in SAM, and maybe in SECURITY I think */
1191
sptr->val = (int)(vkkey->val_type);
1192
sptr->size = 4;
1193
sptr->type = REG_DWORD;
1194
} else {
1195
sptr->val = 0;
1196
sptr->size = 0;
1197
}
1198
1199
(*count)++;
1200
return( *count <= key->no_values );
1201
}
1202
1203
/* traceback - trace nk's back to root,
1204
* building path string as we go.
1205
* nkofs = offset to nk-node
1206
* path = pointer to pathstring-buffer
1207
* maxlen = max length of path-buffer
1208
* return: length of path string
1209
*/
1210
1211
int get_abs_path(struct hive *hdesc, int nkofs, char *path, int maxlen)
1212
{
1213
/* int newnkofs; */
1214
struct nk_key *key;
1215
char tmp[ABSPATHLEN+1];
1216
char *keyname;
1217
int len_name;
1218
1219
maxlen = (maxlen < ABSPATHLEN ? maxlen : ABSPATHLEN);
1220
1221
key = (struct nk_key *)(hdesc->buffer + nkofs);
1222
1223
if (key->id != 0x6b6e) {
1224
printf("get_abs_path: Not a 'nk' node!\n");
1225
return(0);
1226
}
1227
1228
if (key->type == KEY_ROOT) { /* We're at the root */
1229
return(strlen(path));
1230
}
1231
1232
strncpy(tmp,path,ABSPATHLEN-1);
1233
1234
if (key->type & 0x20)
1235
keyname = string_rega2prog(key->keyname, key->len_name);
1236
else
1237
keyname = string_regw2prog(key->keyname, key->len_name);
1238
len_name = strlen(keyname);
1239
if ( (strlen(path) + len_name) >= maxlen-6) {
1240
free(keyname);
1241
snprintf(path,maxlen,"(...)%s",tmp);
1242
return(strlen(path)); /* Stop trace when string exhausted */
1243
}
1244
*path = '\\';
1245
memcpy(path+1,keyname,len_name);
1246
free(keyname);
1247
strncpy(path+len_name+1,tmp,maxlen-6-len_name);
1248
return(get_abs_path(hdesc, key->ofs_parent+0x1004, path, maxlen)); /* go back one more */
1249
}
1250
1251
1252
/* Value index table lookup
1253
* hdesc - hive as usual
1254
* vlistofs - offset of table
1255
* name - value name to look for
1256
* returns index into table or -1 if err
1257
*/
1258
1259
int vlist_find(struct hive *hdesc, int vlistofs, int numval, char *name, int type)
1260
{
1261
struct vk_key *vkkey;
1262
int i,vkofs,len;
1263
int32_t *vlistkey;
1264
1265
len = strlen(name);
1266
vlistkey = (int32_t *)(hdesc->buffer + vlistofs);
1267
1268
for (i = 0; i < numval; i++) {
1269
vkofs = vlistkey[i] + 0x1004;
1270
vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1271
if (vkkey->len_name == 0 && *name == '@') { /* @ is alias for nameless value */
1272
return(i);
1273
}
1274
if ( !(type & TPF_EXACT) || vkkey->len_name == len ) {
1275
if (!strncmp(name, vkkey->keyname, len)) { /* name match? */
1276
return(i);
1277
}
1278
}
1279
}
1280
return(-1);
1281
1282
}
1283
1284
/* Recursevely follow 'nk'-nodes based on a path-string,
1285
* returning offset of last 'nk' or 'vk'
1286
* vofs - offset to start node
1287
* path - null-terminated pathname (relative to vofs, \ is separator)
1288
* type - type to return TPF_??, see ntreg.h
1289
* return: offset to nk or vk (or NULL if not found)
1290
*/
1291
1292
int trav_path(struct hive *hdesc, int vofs, char *path, int type)
1293
{
1294
struct nk_key *key, *newnkkey;
1295
struct lf_key *lfkey;
1296
struct li_key *likey;
1297
struct ri_key *rikey;
1298
1299
int32_t *vlistkey;
1300
int newnkofs, plen, i, lfofs, vlistofs, adjust, r, ricnt, subs;
1301
char *buf;
1302
char part[ABSPATHLEN+1];
1303
char *partptr;
1304
1305
if (!hdesc) return(0);
1306
buf = hdesc->buffer;
1307
1308
if (!vofs) vofs = hdesc->rootofs+4; /* No current key given , so start at root */
1309
1310
if (*path == '\\' && *(path+1) != '\\') { /* Start from root if path starts with \ */
1311
path++;
1312
vofs = hdesc->rootofs+4;
1313
}
1314
1315
key = (struct nk_key *)(buf + vofs);
1316
/* printf("check of nk at offset: 0x%0x\n",vofs); */
1317
1318
if (key->id != 0x6b6e) {
1319
printf("trav_path: Error: Not a 'nk' node!\n");
1320
return(0);
1321
}
1322
1323
/* Find \ delimiter or end of string, copying to name part buffer as we go,
1324
rewriting double \\s */
1325
partptr = part;
1326
for(plen = 0; path[plen] && (path[plen] != '\\' || path[plen+1] == '\\'); plen++) {
1327
if (path[plen] == '\\' && path[plen+1] == '\\') plen++; /* Skip one if double */
1328
*partptr++ = path[plen];
1329
}
1330
*partptr = '\0';
1331
1332
/* printf("Name component: <%s>\n",part); */
1333
1334
adjust = (path[plen] == '\\' ) ? 1 : 0;
1335
/* printf("Checking for <%s> with len %d\n",path,plen); */
1336
if (!plen) return(vofs-4); /* Path has no lenght - we're there! */
1337
if ( (plen == 1) && (*path == '.') && !(type & TPF_EXACT)) { /* Handle '.' current dir */
1338
return(trav_path(hdesc,vofs,path+plen+adjust,type));
1339
}
1340
if ( !(type & TPF_EXACT) && (plen == 2) && !strncmp("..",path,2) ) { /* Get parent key */
1341
newnkofs = key->ofs_parent + 0x1004;
1342
/* Return parent (or only root if at the root) */
1343
return(trav_path(hdesc, (key->type == KEY_ROOT ? vofs : newnkofs), path+plen+adjust, type));
1344
}
1345
1346
/* at last name of path, and we want vk, and the nk has values */
1347
if (!path[plen] && (type & TPF_VK) && key->no_values) {
1348
/* printf("VK namematch for <%s>\n",part); */
1349
vlistofs = key->ofs_vallist + 0x1004;
1350
vlistkey = (int32_t *)(buf + vlistofs);
1351
i = vlist_find(hdesc, vlistofs, key->no_values, part, type);
1352
if (i != -1) {
1353
return(vlistkey[i] + 0x1000);
1354
}
1355
}
1356
1357
if (key->no_subkeys > 0) { /* If it has subkeys, loop through the hash */
1358
char *partw = NULL;
1359
int partw_len, part_len;
1360
1361
lfofs = key->ofs_lf + 0x1004; /* lf (hash) record */
1362
lfkey = (struct lf_key *)(buf + lfofs);
1363
1364
if (lfkey->id == 0x6972) { /* ri struct need special parsing */
1365
/* Prime loop state */
1366
1367
rikey = (struct ri_key *)lfkey;
1368
ricnt = rikey->no_lis;
1369
r = 0;
1370
likey = (struct li_key *)( hdesc->buffer + rikey->hash[r].ofs_li + 0x1004 ) ;
1371
subs = likey->no_keys;
1372
if (likey->id != 0x696c) { /* Bwah, not li anyway, XP uses lh usually which is actually smarter */
1373
lfkey = (struct lf_key *)( hdesc->buffer + rikey->hash[r].ofs_li + 0x1004 ) ;
1374
likey = NULL;
1375
}
1376
} else {
1377
if (lfkey->id == 0x696c) { /* li? */
1378
likey = (struct li_key *)(buf + lfofs);
1379
} else {
1380
likey = NULL;
1381
}
1382
rikey = NULL;
1383
ricnt = 0; r = 0; subs = key->no_subkeys;
1384
}
1385
1386
partw = string_prog2regw(part, partptr-part, &partw_len);
1387
string_prog2rega(part, partptr-part);
1388
part_len = strlen(part);
1389
do {
1390
for(i = 0; i < subs; i++) {
1391
if (likey) newnkofs = likey->hash[i].ofs_nk + 0x1004;
1392
else newnkofs = lfkey->hash[i].ofs_nk + 0x1004;
1393
newnkkey = (struct nk_key *)(buf + newnkofs);
1394
if (newnkkey->id != 0x6b6e) {
1395
printf("ERROR: not 'nk' node! (strange?)\n");
1396
} else {
1397
if (newnkkey->len_name <= 0) {
1398
printf("[No name]\n");
1399
} else {
1400
int cmp;
1401
if (newnkkey->type & 0x20)
1402
cmp = strncmp(part,newnkkey->keyname,part_len);
1403
else
1404
cmp = memcmp(partw, newnkkey->keyname, partw_len);
1405
if (!cmp) {
1406
/* printf("Key at 0x%0x matches! recursing!\n",newnkofs); */
1407
free(partw);
1408
return(trav_path(hdesc, newnkofs, path+plen+adjust, type));
1409
}
1410
}
1411
} /* if id OK */
1412
} /* hash loop */
1413
r++;
1414
if (ricnt && r < ricnt) {
1415
newnkofs = rikey->hash[r].ofs_li;
1416
likey = (struct li_key *)( hdesc->buffer + newnkofs + 0x1004 ) ;
1417
subs = likey->no_keys;
1418
if (likey->id != 0x696c) { /* Bwah, not li anyway, XP uses lh usually which is actually smarter */
1419
lfkey = (struct lf_key *)( hdesc->buffer + rikey->hash[r].ofs_li + 0x1004 ) ;
1420
likey = NULL;
1421
}
1422
}
1423
} while (r < ricnt && ricnt);
1424
free(partw);
1425
1426
} /* if subkeys */
1427
1428
/* Not found */
1429
return(0);
1430
}
1431
1432
1433
/* ls - list a 'nk' nodes subkeys and values
1434
* vofs - offset to start of data (skipping block linkage)
1435
* type - 0 = full, 1 = keys only. 2 = values only
1436
*/
1437
void nk_ls(struct hive *hdesc, char *path, int vofs, int type)
1438
{
1439
struct nk_key *key;
1440
int nkofs;
1441
struct ex_data ex;
1442
struct vex_data vex;
1443
int count = 0, countri = 0;
1444
1445
1446
nkofs = trav_path(hdesc, vofs, path, 0);
1447
1448
if(!nkofs) {
1449
printf("nk_ls: Key <%s> not found\n",path);
1450
return;
1451
}
1452
nkofs += 4;
1453
1454
key = (struct nk_key *)(hdesc->buffer + nkofs);
1455
VERBF(hdesc,"ls of node at offset 0x%0x\n",nkofs);
1456
1457
if (key->id != 0x6b6e) {
1458
printf("Error: Not a 'nk' node!\n");
1459
1460
debugit(hdesc->buffer,hdesc->size);
1461
1462
}
1463
1464
printf("Node has %d subkeys and %d values",key->no_subkeys,key->no_values);
1465
if (key->len_classnam) printf(", and class-data of %d bytes",key->len_classnam);
1466
printf("\n");
1467
1468
if (key->no_subkeys) {
1469
printf(" key name\n");
1470
while ((ex_next_n(hdesc, nkofs, &count, &countri, &ex) > 0)) {
1471
if (!(hdesc->state & HMODE_VERBOSE)) printf("%c <%s>\n", (ex.nk->len_classnam)?'*':' ',ex.name);
1472
else printf("[%6x] %c <%s>\n", ex.nkoffs, (ex.nk->len_classnam)?'*':' ',ex.name);
1473
FREE(ex.name);
1474
}
1475
}
1476
count = 0;
1477
if (key->no_values) {
1478
printf(" size type value name [value if type DWORD]\n");
1479
while ((ex_next_v(hdesc, nkofs, &count, &vex) > 0)) {
1480
if (hdesc->state & HMODE_VERBOSE) printf("[%6x] %6d %-16s <%s>", vex.vkoffs, vex.size,
1481
(vex.type < REG_MAX ? val_types[vex.type] : "(unknown)"), vex.name);
1482
else
1483
printf("%6d %-16s <%s>", vex.size,
1484
(vex.type < REG_MAX ? val_types[vex.type] : "(unknown)"), vex.name);
1485
1486
if (vex.type == REG_DWORD) printf(" %*d [0x%x]",25-(int)strlen(vex.name),vex.val , vex.val);
1487
printf("\n");
1488
FREE(vex.name);
1489
}
1490
}
1491
}
1492
1493
/* Get the type of a value */
1494
int get_val_type(struct hive *hdesc, int vofs, char *path, int exact)
1495
{
1496
struct vk_key *vkkey;
1497
int vkofs;
1498
1499
vkofs = trav_path(hdesc, vofs,path,exact | TPF_VK);
1500
if (!vkofs) {
1501
return -1;
1502
}
1503
vkofs +=4;
1504
vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1505
#if 0
1506
if (vkkey->len_data & 0x80000000) return(REG_DWORD); /* Special case of INLINE storage */
1507
#endif
1508
return(vkkey->val_type);
1509
}
1510
1511
1512
/* Get len of a value, given current key + path */
1513
int get_val_len(struct hive *hdesc, int vofs, char *path, int exact)
1514
{
1515
struct vk_key *vkkey;
1516
int vkofs;
1517
int len;
1518
1519
vkofs = trav_path(hdesc, vofs,path,exact | TPF_VK);
1520
if (!vkofs) {
1521
return -1;
1522
}
1523
vkofs +=4;
1524
vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1525
1526
len = vkkey->len_data & 0x7fffffff;
1527
1528
if ( vkkey->len_data == 0x80000000 ) { /* Special inline case, return size of 4 (dword) */
1529
len = 4;
1530
}
1531
1532
return(len);
1533
}
1534
1535
/* Get void-pointer to value-data, also if inline.
1536
* If val_type != 0 a check for correct value type is done
1537
* Caller must keep track of value's length (call function above to get it)
1538
*/
1539
void *get_val_data(struct hive *hdesc, int vofs, char *path, int val_type, int exact)
1540
{
1541
struct vk_key *vkkey;
1542
int vkofs;
1543
1544
vkofs = trav_path(hdesc,vofs,path,exact | TPF_VK);
1545
if (!vkofs) {
1546
return NULL;
1547
}
1548
vkofs +=4;
1549
vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1550
1551
1552
if (vkkey->len_data == 0) return NULL;
1553
if (vkkey->len_data == 0x80000000) { /* Special inline case (len = 0x80000000) */
1554
return(&vkkey->val_type); /* Data (4 bytes?) in type field */
1555
}
1556
1557
if (val_type && vkkey->val_type && (vkkey->val_type) != val_type) {
1558
printf("Value <%s> is not of correct type!\n",path);
1559
#if DOCORE
1560
abort();
1561
#endif
1562
return NULL;
1563
}
1564
1565
/* Negative len is inline, return ptr to offset-field which in
1566
* this case contains the data itself
1567
*/
1568
if (vkkey->len_data & 0x80000000) return(&vkkey->ofs_data);
1569
/* Normal return, return data pointer */
1570
return(hdesc->buffer + vkkey->ofs_data + 0x1004);
1571
}
1572
1573
1574
/* Get and copy key data (if any) to buffer
1575
* if kv==NULL will allocate needed return struct & buffer
1576
* else will use buffer allocated for it (if it fits)
1577
* return len+data or NULL if not found (or other error)
1578
* NOTE: caller must deallocate buffer! a simple free(keyval) will suffice.
1579
*/
1580
struct keyval *get_val2buf(struct hive *hdesc, struct keyval *kv,
1581
int vofs, char *path, int type, int exact )
1582
{
1583
int l;
1584
struct keyval *kr;
1585
void *keydataptr;
1586
1587
l = get_val_len(hdesc, vofs, path, exact);
1588
if (l == -1) return(NULL); /* error */
1589
if (kv && (kv->len < l)) return(NULL); /* Check for overflow of supplied buffer */
1590
1591
keydataptr = get_val_data(hdesc, vofs, path, type, exact);
1592
/* if (!keydataptr) return(NULL); error */
1593
1594
/* Allocate space for data + header, or use supplied buffer */
1595
if (kv) {
1596
kr = kv;
1597
} else {
1598
ALLOC(kr,1,l+sizeof(int)+4);
1599
}
1600
1601
kr->len = l;
1602
memcpy(&(kr->data), keydataptr, l);
1603
1604
return(kr);
1605
}
1606
1607
/* DWORDs are so common that I make a small function to get it easily */
1608
1609
int get_dword(struct hive *hdesc, int vofs, char *path, int exact)
1610
{
1611
struct keyval *v;
1612
int dword;
1613
1614
v = get_val2buf(hdesc, NULL, vofs, path, REG_DWORD, exact | TPF_VK);
1615
if (!v) return(-1); /* well... -1 COULD BE THE STORED VALUE TOO */
1616
1617
dword = (int)v->data;
1618
1619
FREE(v);
1620
1621
return(dword);
1622
1623
}
1624
1625
/* Sanity checker when transferring data into a block
1626
* ofs = offset to data block, point to start of actual datablock linkage
1627
* data = data to copy
1628
* size = size of data to copy
1629
*/
1630
1631
int fill_block(struct hive *hdesc, int ofs, void *data, int size)
1632
{
1633
int blksize;
1634
1635
blksize = get_int(hdesc->buffer + ofs);
1636
blksize = -blksize;
1637
1638
#if 0
1639
printf("fill_block: ofs = %x - %x, size = %x, blksize = %x\n",ofs,ofs+size,size,blksize);
1640
#endif
1641
/* if (blksize < size || ( (ofs & 0xfffff000) != ((ofs+size) & 0xfffff000) )) { */
1642
if (blksize < size) {
1643
printf("fill_block: ERROR: block to small for data: ofs = %x, size = %x, blksize = %x\n",ofs,size,blksize);
1644
debugit(hdesc->buffer,hdesc->size);
1645
abort();
1646
}
1647
1648
memcpy(hdesc->buffer + ofs + 4, data, size);
1649
return(0);
1650
}
1651
1652
1653
/* Free actual data of a value, and update value descriptor
1654
* hdesc - hive
1655
* vofs - current key
1656
* path - path to value
1657
* we return offset of vk
1658
*/
1659
1660
int free_val_data(struct hive *hdesc, int vofs, char *path, int exact)
1661
{
1662
struct vk_key *vkkey;
1663
int vkofs, inl;
1664
1665
vkofs = trav_path(hdesc,vofs,path,1);
1666
if (!vkofs) {
1667
return 0;
1668
}
1669
vkofs +=4;
1670
vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1671
1672
inl = (vkkey->len_data & 0x80000000);
1673
1674
if (!inl) {
1675
free_block(hdesc, vkkey->ofs_data + 0x1000);
1676
}
1677
vkkey->len_data = 0;
1678
vkkey->ofs_data = 0;
1679
1680
return(vkofs);
1681
1682
}
1683
1684
/* Allocate data for value, realloc if it already contains stuff
1685
* hdesc - hive
1686
* vofs - current key
1687
* path - path to value
1688
* size - size of data
1689
* Returns: 0 - error, >0 pointer to actual dataspace
1690
*/
1691
1692
int alloc_val_data(struct hive *hdesc, int vofs, char *path, int size,int exact)
1693
{
1694
struct vk_key *vkkey;
1695
int vkofs, len;
1696
int datablk;
1697
1698
vkofs = trav_path(hdesc,vofs,path,1);
1699
if (!vkofs) {
1700
return (0);
1701
}
1702
1703
vkofs +=4;
1704
vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1705
1706
/* Allocate space for new data */
1707
datablk = alloc_block(hdesc, vkofs, size);
1708
if (!datablk) return(0);
1709
1710
len = vkkey->len_data & 0x7fffffff;
1711
1712
/* Then we dealloc if something was there before */
1713
if (len) free_val_data(hdesc,vofs,path,exact);
1714
1715
/* Link in new datablock */
1716
vkkey->ofs_data = datablk - 0x1000;
1717
vkkey->len_data = size;
1718
1719
return(datablk + 4);
1720
}
1721
1722
1723
/* Add a value to a key.
1724
* Just add the metadata (empty value), to put data into it, use
1725
* put_buf2val afterwards
1726
* hdesc - hive
1727
* nkofs - current key
1728
* name - name of value
1729
* type - type of value
1730
* returns: 0 err, >0 offset to value metadata
1731
*/
1732
1733
struct vk_key *add_value(struct hive *hdesc, int nkofs, char *name, int type)
1734
{
1735
struct nk_key *nk;
1736
int oldvlist = 0, newvlist, newvkofs;
1737
struct vk_key *newvkkey;
1738
char *blank="";
1739
1740
if (!name || !*name) return(NULL);
1741
1742
1743
nk = (struct nk_key *)(hdesc->buffer + nkofs);
1744
if (nk->id != 0x6b6e) {
1745
printf("add_value: Key pointer not to 'nk' node!\n");
1746
return(NULL);
1747
}
1748
1749
if (trav_path(hdesc, nkofs, name, 1)) {
1750
printf("add_value: value %s already exists\n",name);
1751
return(NULL);
1752
}
1753
1754
if (!strcmp(name,"@")) name = blank;
1755
1756
if (nk->no_values) oldvlist = nk->ofs_vallist;
1757
1758
newvlist = alloc_block(hdesc, nkofs, nk->no_values * 4 + 4);
1759
if (!newvlist) {
1760
printf("add_value: failed to allocate new value list!\n");
1761
return(NULL);
1762
}
1763
if (oldvlist) { /* Copy old data if any */
1764
memcpy(hdesc->buffer + newvlist + 4, hdesc->buffer + oldvlist + 0x1004, nk->no_values * 4 + 4);
1765
}
1766
1767
/* Allocate value descriptor including its name */
1768
newvkofs = alloc_block(hdesc, newvlist, sizeof(struct vk_key) + strlen(name));
1769
if (!newvkofs) {
1770
printf("add_value: failed to allocate value descriptor\n");
1771
free_block(hdesc, newvlist);
1772
return(NULL);
1773
}
1774
1775
/* Success, now fill in the metadata */
1776
1777
newvkkey = (struct vk_key *)(hdesc->buffer + newvkofs + 4);
1778
1779
/* Add pointer in value list */
1780
*(int *)(hdesc->buffer + newvlist + 4 + (nk->no_values * 4)) = newvkofs - 0x1000;
1781
1782
/* Fill in vk struct */
1783
newvkkey->id = 0x6b76;
1784
newvkkey->len_name = strlen(name);
1785
if (type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN) {
1786
newvkkey->len_data = 0x80000004; /* Prime the DWORD inline stuff */
1787
} else {
1788
newvkkey->len_data = 0x00000000;
1789
}
1790
newvkkey->ofs_data = 0;
1791
newvkkey->val_type = type;
1792
newvkkey->flag = 1; /* Don't really know what this is */
1793
newvkkey->dummy1 = 0;
1794
strcpy((char *)&newvkkey->keyname, name); /* And copy name */
1795
1796
/* Finally update the key and free the old valuelist */
1797
nk->no_values++;
1798
nk->ofs_vallist = newvlist - 0x1000;
1799
if (oldvlist) free_block(hdesc,oldvlist + 0x1000);
1800
1801
return(newvkkey);
1802
1803
}
1804
1805
/* Remove a vk-struct incl dataspace if any
1806
* Mostly for use by higher level stuff
1807
* hdesc - hive
1808
* vkofs - offset to vk
1809
*/
1810
1811
void del_vk(struct hive *hdesc, int vkofs)
1812
{
1813
struct vk_key *vk;
1814
1815
vk = (struct vk_key *)(hdesc->buffer + vkofs);
1816
if (vk->id != 0x6b76) {
1817
printf("del_vk: Key pointer not to 'vk' node!\n");
1818
return;
1819
}
1820
1821
if ( !(vk->len_data & 0x80000000) && vk->ofs_data) {
1822
free_block(hdesc, vk->ofs_data + 0x1000);
1823
}
1824
1825
free_block(hdesc, vkofs - 4);
1826
}
1827
1828
/* Delete all values from key (used in recursive delete)
1829
* hdesc - yer usual hive
1830
* nkofs - current keyoffset
1831
*/
1832
1833
void del_allvalues(struct hive *hdesc, int nkofs)
1834
{
1835
int vlistofs, o, vkofs;
1836
int32_t *vlistkey;
1837
struct nk_key *nk;
1838
1839
nk = (struct nk_key *)(hdesc->buffer + nkofs);
1840
if (nk->id != 0x6b6e) {
1841
printf("del_allvalues: Key pointer not to 'nk' node!\n");
1842
return;
1843
}
1844
1845
if (!nk->no_values) {
1846
/* printf("del_avalues: Key has no values!\n"); */
1847
return;
1848
}
1849
1850
vlistofs = nk->ofs_vallist + 0x1004;
1851
vlistkey = (int32_t *)(hdesc->buffer + vlistofs);
1852
1853
/* Loop through index and delete all vk's */
1854
for (o = 0; o < nk->no_values; o++) {
1855
vkofs = vlistkey[o] + 0x1004;
1856
del_vk(hdesc, vkofs);
1857
}
1858
1859
/* Then zap the index, and update nk */
1860
free_block(hdesc, vlistofs-4);
1861
nk->ofs_vallist = -1;
1862
nk->no_values = 0;
1863
}
1864
1865
1866
/* Delete single value from key
1867
* hdesc - yer usual hive
1868
* nkofs - current keyoffset
1869
* name - name of value to delete
1870
* exact - NKF_EXACT to do exact match, else first match
1871
* returns: 0 - ok, 1 - failed
1872
*/
1873
1874
int del_value(struct hive *hdesc, int nkofs, char *name, int exact)
1875
{
1876
int vlistofs, slot, o, n, vkofs, newlistofs;
1877
int32_t *vlistkey, *tmplist, *newlistkey;
1878
struct nk_key *nk;
1879
char *blank="";
1880
1881
if (!name || !*name) return(1);
1882
1883
if (!strcmp(name,"@")) name = blank;
1884
1885
nk = (struct nk_key *)(hdesc->buffer + nkofs);
1886
if (nk->id != 0x6b6e) {
1887
printf("del_value: Key pointer not to 'nk' node!\n");
1888
return(1);
1889
}
1890
1891
if (!nk->no_values) {
1892
printf("del_value: Key has no values!\n");
1893
return(1);
1894
}
1895
1896
vlistofs = nk->ofs_vallist + 0x1004;
1897
vlistkey = (int32_t *)(hdesc->buffer + vlistofs);
1898
1899
slot = vlist_find(hdesc, vlistofs, nk->no_values, name, TPF_VK);
1900
1901
if (slot == -1) {
1902
printf("del_value: value %s not found!\n",name);
1903
return(1);
1904
}
1905
1906
/* Delete vk and data */
1907
vkofs = vlistkey[slot] + 0x1004;
1908
del_vk(hdesc, vkofs);
1909
1910
/* Copy out old index list */
1911
CREATE(tmplist,int32_t,nk->no_values);
1912
memcpy(tmplist, vlistkey, nk->no_values * sizeof(int32_t));
1913
1914
free_block(hdesc,vlistofs-4); /* Get rid of old list */
1915
1916
nk->no_values--;
1917
1918
if (nk->no_values) {
1919
newlistofs = alloc_block(hdesc, vlistofs, nk->no_values * sizeof(int32_t));
1920
if (!newlistofs) {
1921
printf("del_value: FATAL: Was not able to alloc new index list\n");
1922
abort();
1923
}
1924
/* Now copy over, omitting deleted entry */
1925
newlistkey = (int32_t *)(hdesc->buffer + newlistofs + 4);
1926
for (n = 0, o = 0; o < nk->no_values+1; o++, n++) {
1927
if (o == slot) o++;
1928
newlistkey[n] = tmplist[o];
1929
}
1930
nk->ofs_vallist = newlistofs - 0x1000;
1931
} else {
1932
nk->ofs_vallist = -1;
1933
}
1934
return(0);
1935
}
1936
1937
1938
1939
1940
/* Add a subkey to a key
1941
* hdesc - usual..
1942
* nkofs - offset of current nk
1943
* name - name of key to add
1944
* return: ptr to new keystruct, or NULL
1945
*/
1946
1947
#define AKDEBUG 1
1948
struct nk_key *add_key(struct hive *hdesc, int nkofs, char *name)
1949
{
1950
1951
int slot, newlfofs = 0, oldlfofs = 0, newliofs = 0;
1952
int oldliofs = 0;
1953
int o, n, i, onkofs, newnkofs, cmp;
1954
int rimax, rislot, riofs, namlen;
1955
struct ri_key *ri = NULL;
1956
struct lf_key *newlf = NULL, *oldlf;
1957
struct li_key *newli = NULL, *oldli;
1958
struct nk_key *key, *newnk, *onk;
1959
int32_t hash;
1960
1961
key = (struct nk_key *)(hdesc->buffer + nkofs);
1962
1963
if (key->id != 0x6b6e) {
1964
printf("add_key: current ptr not 'nk'\n");
1965
return(NULL);
1966
}
1967
1968
namlen = strlen(name);
1969
1970
slot = -1;
1971
if (key->no_subkeys) { /* It already has subkeys */
1972
1973
oldlfofs = key->ofs_lf;
1974
oldliofs = key->ofs_lf;
1975
1976
oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
1977
if (oldlf->id != 0x666c && oldlf->id != 0x686c && oldlf->id != 0x696c && oldlf->id != 0x6972) {
1978
printf("add_key: index type not supported: 0x%04x\n",oldlf->id);
1979
return(NULL);
1980
}
1981
1982
rimax = 0; ri = NULL; riofs = 0; rislot = -1;
1983
if (oldlf->id == 0x6972) { /* Indirect index 'ri', init loop */
1984
riofs = key->ofs_lf;
1985
ri = (struct ri_key *)(hdesc->buffer + riofs + 0x1004);
1986
rimax = ri->no_lis-1;
1987
1988
#ifdef AKDEBUG
1989
printf("add_key: entering 'ri' traverse, rimax = %d\n",rimax);
1990
#endif
1991
1992
oldliofs = ri->hash[rislot+1].ofs_li;
1993
oldlfofs = ri->hash[rislot+1].ofs_li;
1994
1995
}
1996
1997
do { /* 'ri' loop, at least run once if no 'ri' deep index */
1998
1999
if (ri) { /* Do next 'ri' slot */
2000
rislot++;
2001
oldliofs = ri->hash[rislot].ofs_li;
2002
oldlfofs = ri->hash[rislot].ofs_li;
2003
oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);
2004
oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2005
}
2006
2007
oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);
2008
oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2009
2010
#ifdef AKDEBUG
2011
printf("add_key: top of ri-loop: rislot = %d, rimax = %d\n",rislot,rimax);
2012
#endif
2013
slot = -1;
2014
2015
if (oldli->id == 0x696c) { /* li */
2016
2017
#ifdef AKDEBUG
2018
printf("add_key: li slot allocate\n");
2019
#endif
2020
2021
FREE(newli);
2022
ALLOC(newli, 8 + 4*oldli->no_keys + 4, 1);
2023
newli->no_keys = oldli->no_keys;
2024
newli->id = oldli->id;
2025
2026
/* Now copy old, checking where to insert (alphabetically) */
2027
for (o = 0, n = 0; o < oldli->no_keys; o++,n++) {
2028
onkofs = oldli->hash[o].ofs_nk;
2029
onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
2030
if (slot == -1) {
2031
#if 1
2032
printf("add_key: cmp <%s> with <%s>\n",name,onk->keyname);
2033
#endif
2034
2035
cmp = strncasecmp(name, onk->keyname, (namlen > onk->len_name) ? namlen : onk->len_name);
2036
if (!cmp) {
2037
printf("add_key: key %s already exists!\n",name);
2038
FREE(newli);
2039
return(NULL);
2040
}
2041
if ( cmp < 0) {
2042
slot = o;
2043
rimax = rislot; /* Cause end of 'ri' search, too */
2044
n++;
2045
#ifdef AKDEBUG
2046
printf("add_key: li-match: slot = %d\n",o);
2047
#endif
2048
}
2049
}
2050
newli->hash[n].ofs_nk = oldli->hash[o].ofs_nk;
2051
}
2052
if (slot == -1) slot = oldli->no_keys;
2053
2054
} else { /* lf or lh */
2055
2056
oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2057
2058
FREE(newlf);
2059
ALLOC(newlf, 8 + 8*oldlf->no_keys + 8, 1);
2060
newlf->no_keys = oldlf->no_keys;
2061
newlf->id = oldlf->id;
2062
#ifdef AKDEBUG
2063
printf("add_key: new lf/lh no_keys: %d\n",newlf->no_keys);
2064
#endif
2065
2066
/* Now copy old, checking where to insert (alphabetically) */
2067
for (o = 0, n = 0; o < oldlf->no_keys; o++,n++) {
2068
onkofs = oldlf->hash[o].ofs_nk;
2069
onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
2070
if (slot == -1) {
2071
2072
#if 0
2073
printf("add_key: cmp <%s> with <%s>\n",name,onk->keyname);
2074
#endif
2075
cmp = strncasecmp(name, onk->keyname, (namlen > onk->len_name) ? namlen : onk->len_name);
2076
if (!cmp) {
2077
printf("add_key: key %s already exists!\n",name);
2078
FREE(newlf);
2079
return(NULL);
2080
}
2081
if ( cmp < 0 ) {
2082
slot = o;
2083
rimax = rislot; /* Cause end of 'ri' search, too */
2084
n++;
2085
#ifdef AKDEBUG
2086
printf("add_key: lf-match: slot = %d\n",o);
2087
#endif
2088
}
2089
}
2090
newlf->hash[n].ofs_nk = oldlf->hash[o].ofs_nk;
2091
newlf->hash[n].name[0] = oldlf->hash[o].name[0];
2092
newlf->hash[n].name[1] = oldlf->hash[o].name[1];
2093
newlf->hash[n].name[2] = oldlf->hash[o].name[2];
2094
newlf->hash[n].name[3] = oldlf->hash[o].name[3];
2095
}
2096
if (slot == -1) slot = oldlf->no_keys;
2097
} /* li else check */
2098
2099
2100
} while ( (rislot < rimax) && (rimax > 0)); /* 'ri' wrapper loop */
2101
2102
} else { /* Parent was empty, make new index block */
2103
#ifdef AKDEBUG
2104
printf("add_key: new index!\n");
2105
#endif
2106
ALLOC(newlf, 8 + 8, 1);
2107
newlf->no_keys = 1;
2108
/* Use ID (lf, lh or li) we fetched from root node, so we use same as rest of hive */
2109
newlf->id = hdesc->nkindextype;
2110
slot = 0;
2111
} /* if has keys before */
2112
2113
2114
/* Make and fill in new nk */
2115
newnkofs = alloc_block(hdesc, nkofs, sizeof(struct nk_key) + strlen(name));
2116
if (!newnkofs) {
2117
printf("add_key: unable to allocate space for new key descriptor for %s!\n",name);
2118
FREE(newlf);
2119
FREE(newli);
2120
return(NULL);
2121
}
2122
newnk = (struct nk_key *)(hdesc->buffer + newnkofs + 4);
2123
2124
newnk->id = 0x6b6e;
2125
newnk->type = KEY_NORMAL;
2126
newnk->ofs_parent = nkofs - 0x1004;
2127
newnk->no_subkeys = 0;
2128
newnk->ofs_lf = 0;
2129
newnk->no_values = 0;
2130
newnk->ofs_vallist = -1;
2131
newnk->ofs_sk = key->ofs_sk; /* Get parents for now. 0 or -1 here crashes XP */
2132
newnk->ofs_classnam = -1;
2133
newnk->len_name = strlen(name);
2134
newnk->len_classnam = 0;
2135
strcpy(newnk->keyname, name);
2136
2137
if (newli) { /* Handle li */
2138
2139
#if AKDEBUG
2140
printf("add_key: li fill at slot: %d\n",slot);
2141
#endif
2142
2143
/* And put its offset into parents index list */
2144
newli->hash[slot].ofs_nk = newnkofs - 0x1000;
2145
newli->no_keys++;
2146
2147
/* Allocate space for our new li list and copy it into reg */
2148
newliofs = alloc_block(hdesc, nkofs, 8 + 4*newli->no_keys);
2149
if (!newliofs) {
2150
printf("add_key: unable to allocate space for new index table for %s!\n",name);
2151
FREE(newli);
2152
free_block(hdesc,newnkofs);
2153
return(NULL);
2154
}
2155
/* memcpy(hdesc->buffer + newliofs + 4, newli, 8 + 4*newli->no_keys); */
2156
fill_block(hdesc, newliofs, newli, 8 + 4*newli->no_keys);
2157
2158
2159
} else { /* lh or lf */
2160
2161
#ifdef AKDEBUG
2162
printf("add_key: lf/lh fill at slot: %d, rislot: %d\n",slot,rislot);
2163
#endif
2164
/* And put its offset into parents index list */
2165
newlf->hash[slot].ofs_nk = newnkofs - 0x1000;
2166
newlf->no_keys++;
2167
if (newlf->id == 0x666c) { /* lf hash */
2168
newlf->hash[slot].name[0] = 0;
2169
newlf->hash[slot].name[1] = 0;
2170
newlf->hash[slot].name[2] = 0;
2171
newlf->hash[slot].name[3] = 0;
2172
strncpy(newlf->hash[slot].name, name, 4);
2173
} else if (newlf->id == 0x686c) { /* lh. XP uses this. hashes whole name */
2174
for (i = 0,hash = 0; i < strlen(name); i++) {
2175
hash *= 37;
2176
hash += toupper(name[i]);
2177
}
2178
newlf->lh_hash[slot].hash = hash;
2179
}
2180
2181
/* Allocate space for our new lf list and copy it into reg */
2182
newlfofs = alloc_block(hdesc, nkofs, 8 + 8*newlf->no_keys);
2183
if (!newlfofs) {
2184
printf("add_key: unable to allocate space for new index table for %s!\n",name);
2185
FREE(newlf);
2186
free_block(hdesc,newnkofs);
2187
return(NULL);
2188
}
2189
/* memcpy(hdesc->buffer + newlfofs + 4, newlf, 8 + 8*newlf->no_keys); */
2190
fill_block(hdesc, newlfofs, newlf, 8 + 8*newlf->no_keys);
2191
2192
} /* li else */
2193
2194
2195
/* Update parent, and free old lf list */
2196
key->no_subkeys++;
2197
if (ri) { /* ri index */
2198
ri->hash[rislot].ofs_li = (newlf ? newlfofs : newliofs) - 0x1000;
2199
} else { /* Parent key */
2200
key->ofs_lf = (newlf ? newlfofs : newliofs) - 0x1000;
2201
}
2202
2203
if (newlf && oldlfofs) free_block(hdesc,oldlfofs + 0x1000);
2204
if (newli && oldliofs) free_block(hdesc,oldliofs + 0x1000);
2205
2206
FREE(newlf);
2207
FREE(newli);
2208
return(newnk);
2209
2210
2211
}
2212
2213
/* Delete a subkey from a key
2214
* hdesc - usual..
2215
* nkofs - offset of current nk
2216
* name - name of key to delete (must match exactly, also case)
2217
* return: 1 - err, 0 - ok
2218
*/
2219
2220
#undef DKDEBUG
2221
2222
int del_key(struct hive *hdesc, int nkofs, char *name)
2223
{
2224
2225
int slot = 0, newlfofs = 0, oldlfofs = 0, o, n, onkofs, delnkofs;
2226
int oldliofs = 0, no_keys = 0, newriofs = 0;
2227
int namlen;
2228
int rimax, riofs, rislot;
2229
struct ri_key *ri, *newri = NULL;
2230
struct lf_key *newlf = NULL, *oldlf = NULL;
2231
struct li_key *newli = NULL, *oldli = NULL;
2232
struct nk_key *key, *onk, *delnk;
2233
char fullpath[501];
2234
2235
key = (struct nk_key *)(hdesc->buffer + nkofs);
2236
2237
namlen = strlen(name);
2238
2239
if (key->id != 0x6b6e) {
2240
printf("add_key: current ptr not nk\n");
2241
return(1);
2242
}
2243
2244
slot = -1;
2245
if (!key->no_subkeys) {
2246
printf("del_key: key has no subkeys!\n");
2247
return(1);
2248
}
2249
2250
oldlfofs = key->ofs_lf;
2251
oldliofs = key->ofs_lf;
2252
2253
oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2254
if (oldlf->id != 0x666c && oldlf->id != 0x686c && oldlf->id != 0x696c && oldlf->id != 0x6972) {
2255
printf("del_key: index other than 'lf', 'li' or 'lh' not supported yet. 0x%04x\n",oldlf->id);
2256
return(1);
2257
}
2258
2259
rimax = 0; ri = NULL; riofs = 0;
2260
rislot = 0;
2261
2262
if (oldlf->id == 0x6972) { /* Indirect index 'ri', init loop */
2263
riofs = key->ofs_lf;
2264
ri = (struct ri_key *)(hdesc->buffer + riofs + 0x1004);
2265
rimax = ri->no_lis-1;
2266
2267
#ifdef DKDEBUG
2268
printf("del_key: entering 'ri' traverse, rimax = %d\n",rimax);
2269
#endif
2270
2271
rislot = -1; /* Starts at slot 0 below */
2272
2273
}
2274
2275
do { /* 'ri' loop, at least run once if no 'ri' deep index */
2276
2277
if (ri) { /* Do next 'ri' slot */
2278
rislot++;
2279
oldliofs = ri->hash[rislot].ofs_li;
2280
oldlfofs = ri->hash[rislot].ofs_li;
2281
}
2282
2283
oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);
2284
oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2285
2286
#ifdef DKDEBUG
2287
printf("del_key: top of ri-loop: rislot = %d\n",rislot);
2288
#endif
2289
slot = -1;
2290
2291
if (oldlf->id == 0x696c) { /* 'li' handler */
2292
#ifdef DKDEBUG
2293
printf("del_key: li handler\n");
2294
#endif
2295
2296
FREE(newli);
2297
ALLOC(newli, 8 + 4*oldli->no_keys - 4, 1);
2298
newli->no_keys = oldli->no_keys - 1; no_keys = newli->no_keys;
2299
newli->id = oldli->id;
2300
2301
/* Now copy old, checking where to delete */
2302
for (o = 0, n = 0; o < oldli->no_keys; o++,n++) {
2303
onkofs = oldli->hash[o].ofs_nk;
2304
onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
2305
if (slot == -1 && onk->len_name == namlen && !strncmp(name, onk->keyname, (onk->len_name > namlen) ? onk->len_name : namlen)) {
2306
slot = o;
2307
delnkofs = onkofs; delnk = onk;
2308
rimax = rislot;
2309
o++;
2310
}
2311
newli->hash[n].ofs_nk = oldli->hash[o].ofs_nk;
2312
}
2313
2314
2315
} else { /* 'lf' or 'lh' are similar */
2316
2317
#ifdef DKDEBUG
2318
printf("del_key: lf or lh handler\n");
2319
#endif
2320
FREE(newlf);
2321
ALLOC(newlf, 8 + 8*oldlf->no_keys - 8, 1);
2322
newlf->no_keys = oldlf->no_keys - 1; no_keys = newlf->no_keys;
2323
newlf->id = oldlf->id;
2324
2325
/* Now copy old, checking where to delete */
2326
for (o = 0, n = 0; o < oldlf->no_keys; o++,n++) {
2327
onkofs = oldlf->hash[o].ofs_nk;
2328
onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
2329
if (slot == -1 && (onk->len_name == namlen) && !strncmp(name, onk->keyname, onk->len_name)) {
2330
slot = o;
2331
delnkofs = onkofs; delnk = onk;
2332
rimax = rislot;
2333
o++;
2334
}
2335
newlf->hash[n].ofs_nk = oldlf->hash[o].ofs_nk;
2336
newlf->hash[n].name[0] = oldlf->hash[o].name[0];
2337
newlf->hash[n].name[1] = oldlf->hash[o].name[1];
2338
newlf->hash[n].name[2] = oldlf->hash[o].name[2];
2339
newlf->hash[n].name[3] = oldlf->hash[o].name[3];
2340
}
2341
} /* else lh or lf */
2342
2343
} while (rislot < rimax); /* ri traverse loop */
2344
2345
if (slot == -1) {
2346
printf("del_key: subkey %s not found!\n",name);
2347
FREE(newlf);
2348
FREE(newli);
2349
return(1);
2350
}
2351
2352
#ifdef DKDEBUG
2353
printf("del_key: key found at slot %d\n",slot);
2354
#endif
2355
2356
if (delnk->no_values || delnk->no_subkeys) {
2357
printf("del_key: subkey %s has subkeys or values. Not deleted.\n",name);
2358
FREE(newlf);
2359
FREE(newli);
2360
return(1);
2361
}
2362
2363
/* Allocate space for our new lf list and copy it into reg */
2364
if ( no_keys && (newlf || newli) ) {
2365
newlfofs = alloc_block(hdesc, nkofs, 8 + (newlf ? 8 : 4) * no_keys);
2366
#ifdef DKDEBUG
2367
printf("del_key: alloc_block for index returns: %x\n",newlfofs);
2368
#endif
2369
if (!newlfofs) {
2370
printf("del_key: WARNING: unable to allocate space for new key descriptor for %s! Not deleted\n",name);
2371
FREE(newlf);
2372
return(1);
2373
}
2374
2375
/* memcpy(hdesc->buffer + newlfofs + 4,
2376
((void *)newlf ? (void *)newlf : (void *)newli), 8 + (newlf ? 8 : 4) * no_keys);
2377
*/
2378
fill_block(hdesc, newlfofs,
2379
((void *)newlf ? (void *)newlf : (void *)newli), 8 + (newlf ? 8 : 4) * no_keys);
2380
2381
2382
} else { /* Last deleted, will throw away index */
2383
newlfofs = 0xfff; /* We subtract 0x1000 later */
2384
}
2385
2386
if (newlfofs < 0xfff) {
2387
printf("del_key: ERROR: newlfofs = %x\n",newlfofs);
2388
#if DOCORE
2389
debugit(hdesc->buffer,hdesc->size);
2390
abort();
2391
#endif
2392
}
2393
2394
/* Check for CLASS data, if so, deallocate it too */
2395
if (delnk->len_classnam) {
2396
free_block(hdesc, delnk->ofs_classnam + 0x1000);
2397
}
2398
/* Now it's safe to zap the nk */
2399
free_block(hdesc, delnkofs + 0x1000);
2400
/* And the old index list */
2401
free_block(hdesc, (oldlfofs ? oldlfofs : oldliofs) + 0x1000);
2402
2403
/* Update parent */
2404
key->no_subkeys--;
2405
2406
if (ri) {
2407
if (newlfofs == 0xfff) {
2408
2409
*fullpath = 0;
2410
get_abs_path(hdesc, nkofs, fullpath, 480);
2411
2412
VERBF(hdesc,"del_key: need to delete ri-slot %d for %x - %s\n", rislot,nkofs,fullpath );
2413
2414
if (ri->no_lis > 1) { /* We have subindiceblocks left? */
2415
/* Delete from array */
2416
ALLOC(newri, 8 + 4*ri->no_lis - 4, 1);
2417
newri->no_lis = ri->no_lis - 1;
2418
newri->id = ri->id;
2419
for (o = 0, n = 0; o < ri->no_lis; o++,n++) {
2420
if (n == rislot) o++;
2421
newri->hash[n].ofs_li = ri->hash[o].ofs_li;
2422
}
2423
newriofs = alloc_block(hdesc, nkofs, 8 + newri->no_lis*4 );
2424
if (!newriofs) {
2425
printf("del_key: WARNING: unable to allocate space for ri-index for %s! Not deleted\n",name);
2426
FREE(newlf);
2427
FREE(newri);
2428
return(1);
2429
}
2430
fill_block(hdesc, newriofs, newri, 8 + newri->no_lis * 4);
2431
free_block(hdesc, riofs + 0x1000);
2432
key->ofs_lf = newriofs - 0x1000;
2433
FREE(newri);
2434
} else { /* Last entry in ri was deleted, get rid of it, key is empty */
2435
VERB(hdesc,"del_key: .. and that was the last one. key now empty!\n");
2436
free_block(hdesc, riofs + 0x1000);
2437
key->ofs_lf = -1;
2438
}
2439
} else {
2440
ri->hash[rislot].ofs_li = newlfofs - 0x1000;
2441
}
2442
} else {
2443
key->ofs_lf = newlfofs - 0x1000;
2444
}
2445
2446
FREE(newlf);
2447
return(0);
2448
2449
}
2450
2451
/* Recursive delete keys
2452
* hdesc - usual..
2453
* nkofs - offset of current nk
2454
* name - name of key to delete
2455
* return: 0 - ok, 1 fail
2456
*/
2457
void rdel_keys(struct hive *hdesc, char *path, int vofs)
2458
{
2459
struct nk_key *key;
2460
int nkofs;
2461
struct ex_data ex;
2462
int count = 0, countri = 0;
2463
2464
2465
if (!path || !*path) return;
2466
2467
nkofs = trav_path(hdesc, vofs, path, TPF_NK_EXACT);
2468
2469
if(!nkofs) {
2470
printf("rdel_keys: Key <%s> not found\n",path);
2471
return;
2472
}
2473
nkofs += 4;
2474
2475
key = (struct nk_key *)(hdesc->buffer + nkofs);
2476
2477
/*
2478
VERBF(hdesc,"rdel of node at offset 0x%0x\n",nkofs);
2479
*/
2480
2481
if (key->id != 0x6b6e) {
2482
printf("Error: Not a 'nk' node!\n");
2483
2484
debugit(hdesc->buffer,hdesc->size);
2485
2486
}
2487
2488
#if 0
2489
printf("Node has %d subkeys and %d values\n",key->no_subkeys,key->no_values);
2490
#endif
2491
if (key->no_subkeys) {
2492
while ((ex_next_n(hdesc, nkofs, &count, &countri, &ex) > 0)) {
2493
#if 0
2494
printf("%s\n",ex.name);
2495
#endif
2496
rdel_keys(hdesc, ex.name, nkofs);
2497
count = 0;
2498
countri = 0;
2499
FREE(ex.name);
2500
}
2501
}
2502
2503
del_allvalues(hdesc, nkofs);
2504
del_key(hdesc, key->ofs_parent+0x1004, path);
2505
2506
}
2507
2508
2509
/* Get and copy keys CLASS-data (if any) to buffer
2510
* Returns a buffer with the data (first int32_t is size). see ntreg.h
2511
* NOTE: caller must deallocate buffer! a simple free(keyval) will suffice.
2512
*/
2513
struct keyval *get_class(struct hive *hdesc,
2514
int curnk, char *path)
2515
{
2516
int clen = 0, dofs = 0, nkofs;
2517
struct nk_key *key;
2518
struct keyval *data;
2519
void *classdata;
2520
2521
if (!path && !curnk) return(NULL);
2522
2523
nkofs = trav_path(hdesc, curnk, path, 0);
2524
2525
if(!nkofs) {
2526
printf("get_class: Key <%s> not found\n",path);
2527
return(NULL);
2528
}
2529
nkofs += 4;
2530
key = (struct nk_key *)(hdesc->buffer + nkofs);
2531
2532
clen = key->len_classnam;
2533
if (!clen) {
2534
printf("get_class: Key has no class data.\n");
2535
return(NULL);
2536
}
2537
2538
dofs = key->ofs_classnam;
2539
classdata = (void *)(hdesc->buffer + dofs + 0x1004);
2540
2541
#if 0
2542
printf("get_class: len_classnam = %d\n",clen);
2543
printf("get_class: ofs_classnam = 0x%x\n",dofs);
2544
#endif
2545
2546
ALLOC(data, sizeof(struct keyval) + clen,1);
2547
data->len = clen;
2548
memcpy(&data->data, classdata, clen);
2549
return(data);
2550
}
2551
2552
2553
/* Write to registry value.
2554
* If same size as existing, copy back in place to avoid changing too much
2555
* otherwise allocate new dataspace, then free the old
2556
* Thus enough space to hold both new and old data is needed
2557
* Pass inn buffer with data len as first DWORD (as routines above)
2558
* returns: 0 - error, len - OK (len of data)
2559
*/
2560
2561
int put_buf2val(struct hive *hdesc, struct keyval *kv,
2562
int vofs, char *path, int type, int exact )
2563
{
2564
int l;
2565
void *keydataptr;
2566
2567
if (!kv) return(0);
2568
l = get_val_len(hdesc, vofs, path, exact);
2569
if (l == -1) return(0); /* error */
2570
if (kv->len != l) { /* Realloc data block if not same size as existing */
2571
if (!alloc_val_data(hdesc, vofs, path, kv->len, exact)) {
2572
printf("put_buf2val: %s : alloc_val_data failed!\n",path);
2573
return(0);
2574
}
2575
}
2576
2577
keydataptr = get_val_data(hdesc, vofs, path, type, exact);
2578
if (!keydataptr) return(0); /* error */
2579
2580
memcpy(keydataptr, &kv->data, kv->len);
2581
2582
hdesc->state |= HMODE_DIRTY;
2583
2584
return(kv->len);
2585
}
2586
2587
/* And, yer basic DWORD write */
2588
2589
int put_dword(struct hive *hdesc, int vofs, char *path, int exact, int dword)
2590
{
2591
struct keyval *kr;
2592
int r;
2593
2594
ALLOC(kr,1,sizeof(int)+sizeof(int));
2595
2596
kr->len = sizeof(int);
2597
kr->data = dword;
2598
2599
r = put_buf2val(hdesc, kr, vofs, path, REG_DWORD, exact);
2600
2601
FREE(kr);
2602
2603
return(r);
2604
}
2605
2606
/* ================================================================ */
2607
2608
/* Code to export registry entries to .reg file initiated by
2609
* Leo von Klenze
2610
* Then expanded a bit to handle more types etc.
2611
*/
2612
2613
/*
2614
* converts a value string from an registry entry into a c string. It does not
2615
* use any encoding functions.
2616
* It works very primitive by just taking every second char.
2617
* The caller must free the resulting string, that was allocated with malloc.
2618
*
2619
* string: string where every second char is \0
2620
* len: length of the string
2621
* return: the converted string as char*
2622
*/
2623
static char *
2624
string_regw2prog(void *string, int len)
2625
{
2626
int i, k;
2627
char *cstring;
2628
2629
int out_len = 0;
2630
for(i = 0; i < len; i += 2)
2631
{
2632
unsigned v = ((unsigned char *)string)[i] + ((unsigned char *)string)[i+1] * 256u;
2633
if (v < 128)
2634
out_len += 1;
2635
else if(v < 0x800)
2636
out_len += 2;
2637
else
2638
out_len += 3;
2639
}
2640
cstring = (char *) malloc(out_len+1);
2641
if (!cstring) {
2642
printf("FATAL! ex_next: malloc() failed! Out of memory?\n");
2643
abort();
2644
}
2645
2646
for(i = 0, k = 0; i < len; i += 2)
2647
{
2648
unsigned v = ((unsigned char *)string)[i] + ((unsigned char *)string)[i+1] * 256u;
2649
if (v < 128)
2650
cstring[k++] = v;
2651
else if(v < 0x800) {
2652
cstring[k++] = 0xc0 | (v >> 6);
2653
cstring[k++] = 0x80 | (v & 0x3f);
2654
} else {
2655
cstring[k++] = 0xe0 | (v >> 12);
2656
cstring[k++] = 0x80 | ((v >> 6) & 0x3f);
2657
cstring[k++] = 0x80 | (v & 0x3f);
2658
}
2659
}
2660
cstring[out_len] = '\0';
2661
2662
return cstring;
2663
}
2664
2665
static char *
2666
string_rega2prog(void *string, int len)
2667
{
2668
int i, k;
2669
char *cstring;
2670
2671
int out_len = 0;
2672
for(i = 0; i < len; ++i)
2673
{
2674
unsigned v = ((unsigned char *)string)[i];
2675
if (v < 128)
2676
out_len += 1;
2677
else
2678
out_len += 2;
2679
}
2680
cstring = (char *) malloc(out_len+1);
2681
if (!cstring) {
2682
printf("FATAL! ex_next: malloc() failed! Out of memory?\n");
2683
abort();
2684
}
2685
2686
for(i = 0, k = 0; i < len; ++i)
2687
{
2688
unsigned v = ((unsigned char *)string)[i];
2689
if (v < 128)
2690
cstring[k++] = v;
2691
else {
2692
cstring[k++] = 0xc0 | (v >> 6);
2693
cstring[k++] = 0x80 | (v & 0x3f);
2694
}
2695
}
2696
cstring[out_len] = '\0';
2697
2698
return cstring;
2699
}
2700
2701
static void
2702
string_prog2rega(char *string, int len)
2703
{
2704
char *out = string;
2705
unsigned char *in = (unsigned char*) string;
2706
2707
for (;*in; ++in) {
2708
if (!(*in & 0x80)) {
2709
*out++ = *in;
2710
} else if ((in[0] & 0xe0) == 0xc0 && in[1]) {
2711
*out++ = (in[0] & 0x1f) << 6 | (in[1] & 0x3f);
2712
++in;
2713
} else if (in[1] && in[2]) {
2714
/* assume 3 byte*/
2715
*out++ = (in[1] & 0xf) << 6 | (in[2] & 0x3f);
2716
in += 2;
2717
}
2718
}
2719
*out = 0;
2720
}
2721
2722
static char *
2723
string_prog2regw(void *string, int len, int *out_len)
2724
{
2725
unsigned char *regw = (unsigned char*) malloc(len*2+2);
2726
unsigned char *out = regw;
2727
unsigned char *in = (unsigned char*) string;
2728
2729
for (;len>0; ++in, --len) {
2730
if (!(in[0] & 0x80)) {
2731
*out++ = *in;
2732
*out++ = 0;
2733
} else if ((in[0] & 0xe0) == 0xc0 && len >= 2) {
2734
*out++ = (in[0] & 0x1f) << 6 | (in[1] & 0x3f);
2735
*out++ = (in[0] & 0x1f) >> 2;
2736
++in, --len;
2737
} else if (len >= 3) {
2738
/* assume 3 byte*/
2739
*out++ = (in[1] & 0xf) << 6 | (in[2] & 0x3f);
2740
*out++ = (in[0] & 0xf) << 4 | ((in[1] & 0x3f) >> 2);
2741
in += 2;
2742
len -= 2;
2743
}
2744
}
2745
*out_len = out - regw;
2746
out[0] = out[1] = 0;
2747
return (char *) regw;
2748
}
2749
2750
static char *
2751
quote_string(const char *s)
2752
{
2753
int len = strlen(s);
2754
const char *p;
2755
char *dst, *out;
2756
2757
for (p = s; *p; ++p)
2758
if (*p == '\\' || *p == '\"')
2759
++len;
2760
2761
dst = out = (char*) malloc(len + 1);
2762
for (p = s; *p; ++p) {
2763
if (*p == '\\' || *p == '\"')
2764
*dst++ = '\\';
2765
*dst++ = *p;
2766
}
2767
*dst = 0;
2768
return out;
2769
}
2770
2771
static void
2772
export_bin(int type, char *value, int len, int col, FILE* file)
2773
{
2774
int byte;
2775
2776
if (type == REG_BINARY) {
2777
fprintf(file, "hex:");
2778
col += 4;
2779
} else {
2780
fprintf(file, "hex(%x):", type);
2781
col += 7;
2782
}
2783
byte = 0;
2784
int start = (col - 2) / 3;
2785
while (byte + 1 < len) { /* go byte by byte.. probably slow.. */
2786
fprintf(file, "%02x,", (unsigned char)value[byte]);
2787
byte++;
2788
if (!((byte + start) % 25)) fprintf(file, "\\\r\n ");
2789
}
2790
if (len)
2791
fprintf(file, "%02x\r\n", (unsigned char)value[len - 1]);
2792
}
2793
2794
/*
2795
* Exports the named subkey and its values to the given file.
2796
*
2797
* hdesc: registry hive
2798
* nkofs: offset of parent node
2799
* name: name of key to export
2800
* prefix: prefix for each key. This prefix is prepended to the keyname
2801
* file: file descriptor of destination file
2802
*/
2803
void export_subkey(struct hive *hdesc, int nkofs, char *name, char *prefix, FILE *file)
2804
{
2805
int newofs;
2806
int count = 0;
2807
int countri = 0;
2808
int len;
2809
char *path = (char*) malloc(1024);
2810
char *value;
2811
struct nk_key *key;
2812
struct ex_data ex;
2813
struct vex_data vex;
2814
2815
2816
// switch to key
2817
newofs = trav_path(hdesc, nkofs, name, TPF_NK_EXACT);
2818
if(!newofs)
2819
{
2820
printf("Key '%s' not found!\n", name);
2821
free(path);
2822
return;
2823
}
2824
nkofs = newofs + 4;
2825
2826
// get the key
2827
key = (struct nk_key *)(hdesc->buffer + nkofs);
2828
printf("Exporting key '%.*s' with %d subkeys and %d values...\n",
2829
key->len_name, key->keyname, key->no_subkeys, key->no_values);
2830
2831
*path = 0;
2832
get_abs_path(hdesc, nkofs, path, 1024);
2833
2834
// export the key
2835
fprintf(file, "\r\n");
2836
fprintf(file, "[%s\%s]\r\n", prefix, path);
2837
// export values
2838
if(key->no_values)
2839
{
2840
while ((ex_next_v(hdesc, nkofs, &count, &vex) > 0))
2841
{
2842
int col = 0;
2843
char *name = quote_string(vex.name);
2844
2845
/* print name */
2846
if (!name[0]) {
2847
fprintf(file, "@=");
2848
free(name);
2849
name = str_dup("@");
2850
col += 2;
2851
} else {
2852
fprintf(file, "\"%s\"=", name);
2853
col += strlen(name) + 3;
2854
}
2855
2856
if(vex.type == REG_DWORD)
2857
{
2858
fprintf(file, "dword:%08x\r\n", vex.val);
2859
}
2860
else if(vex.type == REG_SZ)
2861
{
2862
char *val, *quoted;
2863
value = (char *)get_val_data(hdesc, nkofs, name, vex.type, TPF_VK_EXACT);
2864
len = get_val_len(hdesc, nkofs, name, TPF_VK_EXACT);
2865
2866
val = string_regw2prog(value, len);
2867
/* dump as binary if invalid characters are embedded */
2868
if (strchr(val, 0xa) || strchr(val, 0xd))
2869
{
2870
free(val);
2871
//if (len >= 2 && value[len-2] == 0 && value[len-1] == 0) len -= 2;
2872
export_bin(vex.type, value, len, col, file);
2873
}
2874
else
2875
{
2876
quoted = quote_string(val);
2877
free(val);
2878
fprintf(file, "\"%s\"", quoted);
2879
free(quoted);
2880
fprintf(file, "\r\n");
2881
}
2882
}
2883
else
2884
{
2885
/* All other types seems to simply be hexdumped. Format is:
2886
"valuename"=hex(typenum):xx,xx,xx,xx,xx...
2887
for example:
2888
"qword64"=hex(b):4e,03,51,db,fa,04,00,00
2889
this is type = 0xb = 11 = REG_QWORD
2890
"expandstring"=hex(2):46,00,6f,00,6f,00,62,00,61,00,72,00,20,00,25,00,73,00,20,\
2891
00,42,00,61,00,7a,00,00,00
2892
this is type 2 = REG_EXPAND_SZ and the line is continued with ,\<CR><LF><space><space>
2893
don't know how many bytes for each line. Around 18-24 seems to be it?? depends on name lenght??
2894
NOTE: Exception:
2895
type = REG_BINARY starts like this: "valuename"=hex:xx,xx,xx...
2896
*/
2897
value = (char *)get_val_data(hdesc, nkofs, name, vex.type, TPF_VK_EXACT);
2898
len = get_val_len(hdesc, nkofs, name, TPF_VK_EXACT);
2899
2900
export_bin(vex.type, value, len, col, file);
2901
}
2902
2903
FREE(vex.name);
2904
free(name);
2905
}
2906
}
2907
2908
// export subkeys
2909
if (key->no_subkeys)
2910
{
2911
count = 0;
2912
countri = 0;
2913
while ((ex_next_n(hdesc, nkofs, &count, &countri, &ex) > 0))
2914
{
2915
export_subkey(hdesc, nkofs, ex.name, prefix, file);
2916
FREE(ex.name);
2917
}
2918
}
2919
free(path);
2920
}
2921
2922
/*
2923
* Exports the given key to a windows .reg file that can be imported to the
2924
* windows registry.
2925
* The prefix is used to determine the destination hive in the windows
2926
* registry, set it to HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE or whatever you
2927
* want.
2928
*
2929
* hdesc: hive
2930
* nkofs: offset of parent node
2931
* name: name of subkey to export
2932
* filename: name of destination .reg file (will be overridden)
2933
* prefix: prefix for each exported key
2934
*/
2935
void export_key(struct hive *hdesc, int nkofs, char *name, char *filename, char *prefix)
2936
{
2937
FILE *file;
2938
2939
// open file
2940
file = fopen(filename, "w");
2941
if(!file)
2942
{
2943
printf("Cannot open file '%s'. %s (%d).\n", filename, strerror(errno),
2944
errno);
2945
return;
2946
}
2947
2948
printf("Exporting to file '%s'...\n", filename);
2949
fprintf(file, "Windows Registry Editor Version 5.00\r\n");
2950
export_subkey(hdesc, nkofs, name, prefix, file);
2951
2952
fclose(file);
2953
}
2954
2955
2956
/* ================================================================ */
2957
2958
/* Hive control (load/save/close) etc */
2959
2960
void closeHive(struct hive *hdesc)
2961
{
2962
2963
printf("closing hive %s\n",hdesc->filename);
2964
if (hdesc->state & HMODE_OPEN) {
2965
close(hdesc->filedesc);
2966
}
2967
FREE(hdesc->filename);
2968
FREE(hdesc->buffer);
2969
FREE(hdesc);
2970
2971
}
2972
2973
/* Write the hive back to disk (only if dirty & not readonly */
2974
int writeHive(struct hive *hdesc)
2975
{
2976
int len, i;
2977
struct regf_header *hdr;
2978
int32_t checksum;
2979
2980
if (hdesc->state & HMODE_RO) return(0);
2981
if ( !(hdesc->state & HMODE_DIRTY)) return(0);
2982
2983
if ( !(hdesc->state & HMODE_OPEN)) { /* File has been closed */
2984
if (!(hdesc->filedesc = open(hdesc->filename,O_RDWR))) {
2985
fprintf(stderr,"writeHive: open(%s) failed: %s, FILE NOT WRITTEN!\n",hdesc->filename,strerror(errno));
2986
return(1);
2987
}
2988
hdesc->state |= HMODE_OPEN;
2989
}
2990
/* Seek back to begginning of file (in case it's already open) */
2991
lseek(hdesc->filedesc, 0, SEEK_SET);
2992
2993
/* compute new checksum */
2994
hdr = (struct regf_header *) hdesc->buffer;
2995
checksum = 0;
2996
for (i = 0; i < 0x1fc/4; ++i)
2997
checksum ^= ((int32_t *) hdr)[i];
2998
hdr->checksum = checksum;
2999
3000
len = write(hdesc->filedesc, hdesc->buffer, hdesc->size);
3001
if (len != hdesc->size) {
3002
fprintf(stderr,"writeHive: write of %s failed: %s.\n",hdesc->filename,strerror(errno));
3003
return(1);
3004
}
3005
3006
hdesc->state &= (~HMODE_DIRTY);
3007
return(0);
3008
}
3009
3010
struct hive *openHive(char *filename, int mode)
3011
{
3012
3013
struct hive *hdesc;
3014
int fmode,r,vofs;
3015
struct stat sbuf;
3016
uint32_t pofs;
3017
/* off_t l; */
3018
char *c;
3019
struct hbin_page *p;
3020
struct regf_header *hdr;
3021
struct nk_key *nk;
3022
struct ri_key *rikey;
3023
int verbose = (mode & HMODE_VERBOSE);
3024
int trace = (mode & HMODE_TRACE);
3025
3026
CREATE(hdesc,struct hive,1);
3027
3028
hdesc->filename = str_dup(filename);
3029
hdesc->state = 0;
3030
hdesc->size = 0;
3031
hdesc->buffer = NULL;
3032
3033
if ( (mode & HMODE_RO) ) {
3034
fmode = O_RDONLY;
3035
} else {
3036
fmode = O_RDWR;
3037
}
3038
hdesc->filedesc = open(hdesc->filename,fmode);
3039
if (hdesc->filedesc < 0) {
3040
fprintf(stderr,"openHive(%s) failed: %s, trying read-only\n",hdesc->filename,strerror(errno));
3041
fmode = O_RDONLY;
3042
mode |= HMODE_RO;
3043
hdesc->filedesc = open(hdesc->filename,fmode);
3044
if (hdesc->filedesc < 0) {
3045
fprintf(stderr,"openHive(%s) in fallback RO-mode failed: %s\n",hdesc->filename,strerror(errno));
3046
closeHive(hdesc);
3047
return(NULL);
3048
}
3049
}
3050
3051
3052
if ( fstat(hdesc->filedesc,&sbuf) ) {
3053
perror("stat()");
3054
exit(1);
3055
}
3056
3057
hdesc->size = sbuf.st_size;
3058
hdesc->state = mode | HMODE_OPEN;
3059
/* fprintf(stderr,"hiveOpen(%s) successful\n",hdesc->filename); */
3060
3061
/* Read the whole file */
3062
3063
ALLOC(hdesc->buffer,1,hdesc->size);
3064
3065
r = read(hdesc->filedesc,hdesc->buffer,hdesc->size);
3066
if (r < hdesc->size) {
3067
fprintf(stderr,"Could not read file, got %d bytes while expecting %d\n",
3068
r, hdesc->size);
3069
closeHive(hdesc);
3070
return(NULL);
3071
}
3072
3073
/* Now run through file, tallying all pages */
3074
/* NOTE/KLUDGE: Assume first page starts at offset 0x1000 */
3075
3076
pofs = 0x1000;
3077
3078
hdr = (struct regf_header *)hdesc->buffer;
3079
if (hdr->id != 0x66676572) {
3080
printf("openHive(%s): File does not seem to be a registry hive!\n",filename);
3081
return(hdesc);
3082
}
3083
printf("Hive <%s> name (from header): <",filename);
3084
for (c = hdr->name; *c && (c < hdr->name + 64); c += 2) putchar(*c);
3085
3086
hdesc->rootofs = hdr->ofs_rootkey + 0x1000;
3087
printf(">\nROOT KEY at offset: 0x%06x * ",hdesc->rootofs);
3088
3089
/* Cache the roots subkey index type (li,lf,lh) so we can use the correct
3090
* one when creating the first subkey in a key */
3091
3092
nk = (struct nk_key *)(hdesc->buffer + hdesc->rootofs + 4);
3093
if (nk->id == 0x6b6e) {
3094
rikey = (struct ri_key *)(hdesc->buffer + nk->ofs_lf + 0x1004);
3095
hdesc->nkindextype = rikey->id;
3096
if (hdesc->nkindextype == 0x6972) { /* Gee, big root, must check indirectly */
3097
printf("load_hive: DEBUG: BIG ROOT!\n");
3098
rikey = (struct ri_key *)(hdesc->buffer + rikey->hash[0].ofs_li + 0x1004);
3099
hdesc->nkindextype = rikey->id;
3100
}
3101
if (hdesc->nkindextype != 0x666c &&
3102
hdesc->nkindextype != 0x686c &&
3103
hdesc->nkindextype != 0x696c) {
3104
hdesc->nkindextype = 0x666c;
3105
}
3106
3107
printf("Subkey indexing type is: %04x <%c%c>\n",
3108
hdesc->nkindextype,
3109
hdesc->nkindextype & 0xff,
3110
hdesc->nkindextype >> 8);
3111
} else {
3112
printf("load_hive: WARNING: ROOT key does not seem to be a key! (not type == nk)\n");
3113
}
3114
3115
3116
3117
while (pofs < hdesc->size) {
3118
#ifdef LOAD_DEBUG
3119
if (trace) hexdump(hdesc->buffer,pofs,pofs+0x20,1);
3120
#endif
3121
p = (struct hbin_page *)(hdesc->buffer + pofs);
3122
if (p->id != 0x6E696268) {
3123
printf("Page at 0x%x is not 'hbin', assuming file contains garbage at end\n",pofs);
3124
break;
3125
}
3126
hdesc->pages++;
3127
#ifdef LOAD_DEBUG
3128
if (trace) printf("\n###### Page at 0x%0lx has size 0x%0lx, next at 0x%0lx ######\n",pofs,p->len_page,p->ofs_next);
3129
#endif
3130
if (p->ofs_next == 0) {
3131
#ifdef LOAD_DEBUG
3132
if (trace) printf("openhive debug: bailing out.. pagesize zero!\n");
3133
#endif
3134
return(hdesc);
3135
}
3136
#if 0
3137
if (p->len_page != p->ofs_next) {
3138
#ifdef LOAD_DEBUG
3139
if (trace) printf("openhive debug: len & ofs not same. HASTA!\n");
3140
#endif
3141
exit(0);
3142
}
3143
#endif
3144
3145
3146
vofs = pofs + 0x20; /* Skip page header */
3147
#if 1
3148
while (vofs-pofs < p->ofs_next && vofs < hdesc->size) {
3149
vofs += parse_block(hdesc,vofs,trace);
3150
3151
}
3152
#endif
3153
pofs += p->ofs_next;
3154
}
3155
printf("File size %d [%x] bytes, containing %d pages (+ 1 headerpage)\n",hdesc->size,hdesc->size, hdesc->pages);
3156
printf("Used for data: %d/%d blocks/bytes, unused: %d/%d blocks/bytes.\n\n",
3157
hdesc->useblk,hdesc->usetot,hdesc->unuseblk,hdesc->unusetot);
3158
3159
3160
/* So, let's guess what kind of hive this is, based on keys in its root */
3161
3162
hdesc->type = HTYPE_UNKNOWN;
3163
if (trav_path(hdesc, 0, "\\SAM", 0)) hdesc->type = HTYPE_SAM;
3164
else if (trav_path(hdesc, 0, "\\ControlSet", 0)) hdesc->type = HTYPE_SYSTEM;
3165
else if (trav_path(hdesc, 0, "\\Policy", 0)) hdesc->type = HTYPE_SECURITY;
3166
else if (trav_path(hdesc, 0, "\\Microsoft", 0)) hdesc->type = HTYPE_SOFTWARE;
3167
if (verbose) printf("Type of hive guessed to be: %d\n",hdesc->type);
3168
3169
return(hdesc);
3170
3171
}
3172
3173
3174