1 /*
2 * ntreg.c - Windows (NT and up) Registry Hive access library
3 * should be able to handle most basic functions:
4 * iterate, add&delete keys and values, read stuff, change stuff etc
5 * no rename of keys or values yet..
6 * also contains some minor utility functions (string handling etc) for now
7 *
8 * 2014-jan: openhive() now more compatible with build on non-unix?
9 * 2013-aug: Enter buil-in buffer debugger only if in trace mode, else return error or abort()
10 * 2013-may-aug: Fixed critical bug in del_value which could
11 * thrash the hive when removing value in bottom of key.
12 * And a pointer not reinitialized when buffer reallocated in some cases, fixed.
13 * Thanks to Jacky To for reporting those two.
14 * Some minor adjustments for compiler. A few more utility functions.
15 * 2012-oct: Added set_val_type. some minor changes.
16 * 2011-may: Seems like large values >16k or something like that is split
17 * into several blocks (db), have tried to implement that.
18 * Vista seems to accept it. Not tested on others yet.
19 * 2011-may: Expansion now seems to be working, have lot of test accepted by
20 * vista and win7. But no warranties..
21 * 2011-may: Found a couple of nasty bugs inn add_key(), making Vista and newer
22 * reject (remove) keys on hive load.
23 * May have been there for a long time according to reports.
24 * 2011-apr: Fixed some problems with the allocator when at the end of a hbin.
25 * 2011-apr: .reg file import. Ugly one, but it seems to work. Found
26 * quite a lot of bugs in other places while testing it.
27 * String handling when international characters or wide (UTF-16)
28 * is a pain, and very ugly. May not work in some cases.
29 * Will keep wide (16 bit) characters in strings when importing from
30 * .reg file that has it, like what regedit.exe generates for example.
31 * 2011-apr: Added routines for hive expansion. Will add new hbin at end of file
32 * when needed. If using library, please read ugly warnings in "alloc_block()".
33 * 2010-jun: Patches from Frediano Ziglio adding support for wide characters
34 * and some bugfixes. Thank you!
35 * 2008-mar: Type QWORD (XP/Vista and newer) now recognized
36 * 2008-mar: Most functions accepting a path now also have a parameter specifying if
37 * the search should be exact or on first match basis
38 * 2008-mar: Fixed bug which skipped first indirect index table when deleting keys,
39 * usually leading to endless loop when recursive deleting.
40 * 2008-mar: Export to .reg file by Leo von Klenze, expanded a bit by me.
41 * 2008-mar: 64 bit compatible patch by Mike Doty, via Alon Bar-Lev
42 * http://bugs.gentoo.org/show_bug.cgi?id=185411
43 * 2007-sep: Verbosity/debug messages minor changes
44 * 2007-apr: LGPL license.
45 * 2004-aug: Deep indirect index support. NT351 support. Recursive delete.
46 * Debugged a lot in allocation routines. Still no expansion.
47 * 2004-jan: Verbosity updates
48 * 2003-jan: Allocation of new data, supports adding/deleting keys & stuff.
49 * Missing is expanding the file.
50 * 2003-jan: Seems there may be garbage pages at end of file, not zero pages
51 * now stops enumerating at first non 'hbin' page.
52 *
53 * NOTE: The API is not frozen. It can and will change every release.
54 *
55 *****
56 *
57 * NTREG - Window registry file reader / writer library
58 * Copyright (c) 1997-2014 Petter Nordahl-Hagen.
59 *
60 * This library is free software; you can redistribute it and/or
61 * modify it under the terms of the GNU Lesser General Public
62 * License as published by the Free Software Foundation;
63 * version 2.1 of the License.
64 *
65 * This library is distributed in the hope that it will be useful,
66 * but WITHOUT ANY WARRANTY; without even the implied warranty of
67 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
68 * Lesser General Public License for more details.
69 * See file LGPL.txt for the full license.
70 *
71 */
72
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <ctype.h>
76 #include <sys/types.h>
77 #include <sys/stat.h>
78 #include <fcntl.h>
79 #include <errno.h>
80 #include <string.h>
81 #include <unistd.h>
82 #include <inttypes.h>
83 #include <stdarg.h>
84
85 #include "ntreg.h"
86
87 /* Set to abort() and debug on more critical errors */
88 #define DOCORE 1
89
90 #define ZEROFILL 1 /* Fill blocks with zeroes when allocating and deallocating */
91 #define ZEROFILLONLOAD 0 /* Fill blocks marked as unused/deallocated with zeroes on load. FOR DEBUG */
92
93 const char ntreg_version[] = "ntreg lib routines, v0.95 140201, (c) Petter N Hagen";
94
95 const char *val_types[REG_MAX+1] = {
96 "REG_NONE", "REG_SZ", "REG_EXPAND_SZ", "REG_BINARY", "REG_DWORD", /* 0 - 4 */
97 "REG_DWORD_BIG_ENDIAN", "REG_LINK", /* 5 - 6 */
98 "REG_MULTI_SZ", "REG_RESOUCE_LIST", "REG_FULL_RES_DESC", "REG_RES_REQ", /* 7 - 10 */
99 "REG_QWORD", /* 11 */
100 };
101
102 static char * string_prog2regw(void *string, int len, int* out_len);
103
104 /* Utility routines */
105
106 /* toupper() table for registry hashing functions, so we don't have to
107 * dependent upon external locale lib files
108 */
109
110 static const unsigned char reg_touppertable[] = {
111
112 /* ISO 8859-1 is probably not the one.. */
113
114 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
115 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
116 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
117 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
118 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
119 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
120 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
121 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
122 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
123 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
124 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
125 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
126 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */
127 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */
128 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
129 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
130
131 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
132 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
133 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
134 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
135 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
136 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
137 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */
138 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
139 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
140 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
141 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
142 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
143 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */
144 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */
145 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */
146 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xf8-0xff */
147
148 };
149
150
151 /* Use table above in strcasecmp else add_key may put names in wrong order
152 and windows actually verifies that on hive load!!
153 or at least it finds out in some cases..
154 */
155
156
strn_casecmp(const char * s1,const char * s2,size_t n)157 int strn_casecmp(const char *s1, const char *s2, size_t n)
158 {
159 char r;
160
161 while ( *s1 && *s2 && n ) {
162 r = (unsigned char)reg_touppertable[(unsigned char)*s1] - (unsigned char)reg_touppertable[(unsigned char)*s2];
163 if (r) return(r);
164 n--;
165 s1++;
166 s2++;
167 }
168 if ( (!*s1 && !*s2) || !n) return(0);
169 if ( !*s1 ) return(-1);
170 return(1);
171 }
172
173
str_dup(const char * str)174 char *str_dup( const char *str )
175 {
176 char *str_new;
177
178 if (!str) return(0);
179
180 CREATE( str_new, char, strlen(str) + 1 );
181 strcpy( str_new, str );
182 return str_new;
183 }
184
str_cat(char * str,char * add)185 char *str_cat(char *str, char *add)
186 {
187 if (!add) return(str);
188 str = (char *) realloc(str, strlen(str) + strlen(add) + 3);
189 strcat (str, add);
190 return (str);
191 }
192
str_catf(char * str,const char * format,...)193 char *str_catf(char *str, const char *format, ... )
194 {
195 va_list ap;
196 char add[640] ;
197
198 va_start(ap, format) ;
199 vsprintf(add, format, ap) ;
200 va_end(ap) ;
201
202 str = (char *) realloc(str, strlen(str) + strlen(add) + 3);
203 strcat (str, add );
204 return(str);
205 }
206
207
208
209
210 /* Copy non-terminated string to buffer we allocate and null terminate it
211 * Uses length only, does not check for nulls
212 */
213
mem_str(const char * str,int len)214 char *mem_str( const char *str, int len )
215 {
216 char *str_new;
217
218 if (!str)
219 return 0 ;
220
221 CREATE( str_new, char, len + 1 );
222 memcpy( str_new, str, len);
223 *(str_new+len) = 0;
224 return str_new;
225 }
226
227
fmyinput(char * prmpt,char * ibuf,int maxlen)228 int fmyinput(char *prmpt, char *ibuf, int maxlen)
229 {
230
231 printf("%s",prmpt);
232
233 fgets(ibuf,maxlen+1,stdin);
234
235 ibuf[strlen(ibuf)-1] = 0;
236
237 return(strlen(ibuf));
238 }
239
240 /* Print len number of hexbytes */
241
hexprnt(char * s,unsigned char * bytes,int len)242 void hexprnt(char *s, unsigned char *bytes, int len)
243 {
244 int i;
245
246 printf("%s",s);
247 for (i = 0; i < len; i++) {
248 printf("%02x ",bytes[i]);
249 }
250 printf("\n");
251 }
252
253 /* HexDump all or a part of some buffer */
254
hexdump(char * hbuf,int start,int stop,int ascii)255 void hexdump(char *hbuf, int start, int stop, int ascii)
256 {
257 char c;
258 int diff,i;
259
260 while (start < stop ) {
261
262 diff = stop - start;
263 if (diff > 16) diff = 16;
264
265 printf(":%05X ",start);
266
267 for (i = 0; i < diff; i++) {
268 printf("%02X ",(unsigned char)*(hbuf+start+i));
269 }
270 if (ascii) {
271 for (i = diff; i < 16; i++) printf(" ");
272 for (i = 0; i < diff; i++) {
273 c = *(hbuf+start+i);
274 printf("%c", isprint(c) ? c : '.');
275 }
276 }
277 printf("\n");
278 start += 16;
279 }
280 }
281
282 /* General search routine, find something in something else */
find_in_buf(char * buf,char * what,int sz,int len,int start)283 int find_in_buf(char *buf, char *what, int sz, int len, int start)
284 {
285 int i;
286
287 for (; start < sz; start++) {
288 for (i = 0; i < len; i++) {
289 if (*(buf+start+i) != *(what+i)) break;
290 }
291 if (i == len) return(start);
292 }
293 return(0);
294 }
295
296 /* Get INTEGER from memory. This is probably low-endian specific? */
get_int(char * array)297 int get_int( char *array )
298 {
299 return ((array[0]&0xff) + ((array[1]<<8)&0xff00) +
300 ((array[2]<<16)&0xff0000) +
301 ((array[3]<<24)&0xff000000));
302 }
303
304
305 /* Quick and dirty UNICODE to std. ascii */
306
cheap_uni2ascii(char * src,char * dest,int l)307 void cheap_uni2ascii(char *src, char *dest, int l)
308 {
309
310 for (; l > 0; l -=2) {
311 *dest = *src;
312 dest++; src +=2;
313 }
314 *dest = 0;
315 }
316
317
318 /* Quick and dirty ascii to unicode */
319
cheap_ascii2uni(char * src,char * dest,int l)320 void cheap_ascii2uni(char *src, char *dest, int l)
321 {
322 for (; l > 0; l--) {
323 *dest++ = *src++;
324 *dest++ = 0;
325
326 }
327 }
328
skipspace(char ** c)329 void skipspace(char **c)
330 {
331 while( **c == ' ' ) (*c)++;
332 }
333
gethex(char ** c)334 int gethex(char **c)
335 {
336 int value;
337
338 skipspace(c);
339
340 if (!(**c)) return(0);
341
342 sscanf(*c,"%x",&value);
343
344 while( **c != ' ' && (**c)) (*c)++;
345
346 return(value);
347 }
348
349 /* Get a string of HEX bytes (space separated),
350 * or if first char is ' get an ASCII string instead.
351 */
352
gethexorstr(char ** c,char * wb)353 int gethexorstr(char **c, char *wb)
354 {
355 int l = 0;
356
357 skipspace(c);
358
359 if ( **c == '\'') {
360 (*c)++;
361 while ( **c ) {
362 *(wb++) = *((*c)++);
363 l++;
364 }
365 } else {
366 do {
367 *(wb++) = gethex(c);
368 l++;
369 skipspace(c);
370 } while ( **c );
371 }
372 return(l);
373 }
374
375 /* Simple buffer debugger, returns 1 if buffer dirty/edited */
376
debugit(char * buf,int sz)377 int debugit(char *buf, int sz)
378 {
379
380
381 char inbuf[100],whatbuf[100],*bp;
382
383 int dirty=0,to,from,l,i,j,wlen,cofs = 0;
384
385 printf("Buffer debugger. '?' for help.\n");
386
387 while (1) {
388 l = fmyinput(".",inbuf,90);
389 bp = inbuf;
390
391 skipspace(&bp);
392
393 if (l > 0 && *bp) {
394 switch(*bp) {
395 case 'd' :
396 bp++;
397 if (*bp) {
398 from = gethex(&bp);
399 to = gethex(&bp);
400 } else {
401 from = cofs; to = 0;
402 }
403 if (to == 0) to = from + 0x100;
404 if (to > sz) to = sz;
405 hexdump(buf,from,to,1);
406 cofs = to;
407 break;
408 case 'a' :
409 bp++;
410 if (*bp) {
411 from = gethex(&bp);
412 to = gethex(&bp);
413 } else {
414 from = cofs; to = 0;
415 }
416 if (to == 0) to = from + 0x100;
417 if (to > sz) to = sz;
418 hexdump(buf,from,to,0);
419 cofs = to;
420 break;
421 case 'q':
422 return(0);
423 break;
424 case 's':
425 if (!dirty) printf("Buffer has not changed, no need to write..\n");
426 return(dirty);
427 break;
428 case 'h':
429 bp++;
430 if (*bp == 'a') {
431 from = 0;
432 to = sz;
433 bp++;
434 } else {
435 from = gethex(&bp);
436 to = gethex(&bp);
437 }
438 wlen = gethexorstr(&bp,whatbuf);
439 if (to > sz) to = sz;
440 printf("from: %x, to: %x, wlen: %d\n",from,to,wlen);
441 for (i = from; i < to; i++) {
442 for (j = 0; j < wlen; j++) {
443 if ( *(buf+i+j) != *(whatbuf+j)) break;
444 }
445 if (j == wlen) printf("%06x ",i);
446 }
447 printf("\n");
448 break;
449 case ':':
450 bp++;
451 if (!*bp) break;
452 from = gethex(&bp);
453 wlen = gethexorstr(&bp,whatbuf);
454
455 printf("from: %x, wlen: %d\n",from,wlen);
456
457 memcpy(buf+from,whatbuf,wlen);
458 dirty = 1;
459 break;
460
461 case '?':
462 printf("d [<from>] [<to>] - dump buffer within range\n");
463 printf("a [<from>] [<to>] - same as d, but without ascii-part (for cut'n'paste)\n");
464 printf(": <offset> <hexbyte> [<hexbyte> ...] - change bytes\n");
465 printf("h <from> <to> <hexbyte> [<hexbyte> ...] - hunt (search) for bytes\n");
466 printf("ha <hexbyte> [<hexbyte] - Hunt all (whole buffer)\n");
467 printf("s - save & quit\n");
468 printf("q - quit (no save)\n");
469 printf(" instead of <hexbyte> etc. you may give 'string to enter/search a string\n");
470 break;
471 default:
472 printf("?\n");
473 break;
474 }
475 }
476 }
477 }
478
479
480 /* Utility function to copy and append two values into a new one
481 * Will allocate new buffer, but not touch the input ones
482 */
483
reg_valcat(struct keyval * a,struct keyval * b)484 struct keyval *reg_valcat(struct keyval *a, struct keyval *b)
485 {
486 int newsize = 0;
487 int asize = 0;
488 int bsize = 0;
489 struct keyval *result = NULL;
490
491 if (!a && !b) return(NULL);
492
493 if (a) asize = a->len;
494 if (b) bsize = b->len;
495
496 newsize = asize + bsize;
497
498 // printf("asize = %d, bsize = %d, newsize = %d\n",asize,bsize,newsize);
499
500 ALLOC(result, sizeof(struct keyval) + newsize, 1);
501
502 if (asize) memcpy(&result->data, &a->data, asize);
503 if (bsize) memcpy(&result->data + asize / sizeof(int), &b->data, bsize);
504 result->len = newsize;
505
506 //printf("reg_valcat done\n");
507
508 return(result);
509
510 }
511
512
513
514
515
516
517
518 /* ========================================================================= */
519
520 /* The following routines are mostly for debugging, I used it
521 * much during discovery. the -t command line option uses it,
522 * also the 'st' and 's' from the editor & hexdebugger.
523 * All offsets shown in these are unadjusted (ie you must add
524 * headerpage (most often 0x1000) to get file offset)
525 */
526
527 /* Parse the nk datablock
528 * vofs = offset into struct (after size linkage)
529 */
parse_nk(struct hive * hdesc,int vofs,int blen)530 void parse_nk(struct hive *hdesc, int vofs, int blen)
531 {
532
533 struct nk_key *key;
534 int i;
535
536 printf("== nk at offset %0x\n",vofs);
537
538 /* #define D_OFFS2(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs ) */
539 #define D_OFFS(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs )
540
541 key = (struct nk_key *)(hdesc->buffer + vofs);
542 printf("%04x type = 0x%02x %s\n", D_OFFS(type) ,key->type,
543 (key->type == KEY_ROOT ? "ROOT_KEY" : "") );
544 printf("%04x timestamp skipped\n", D_OFFS(timestamp) );
545 printf("%04x parent key offset = 0x%0x\n", D_OFFS(ofs_parent) ,key->ofs_parent + 0x1000);
546 printf("%04x number of subkeys = %d\n", D_OFFS(no_subkeys),key->no_subkeys);
547 printf("%04x lf-record offset = 0x%0x\n",D_OFFS(ofs_lf),key->ofs_lf + 0x1000);
548 printf("%04x number of values = %d\n", D_OFFS(no_values),key->no_values);
549 printf("%04x val-list offset = 0x%0x\n",D_OFFS(ofs_vallist),key->ofs_vallist + 0x1000);
550 printf("%04x sk-record offset = 0x%0x\n",D_OFFS(ofs_sk),key->ofs_sk + 0x1000);
551 printf("%04x classname offset = 0x%0x\n",D_OFFS(ofs_classnam),key->ofs_classnam + 0x1000);
552
553 printf("%04x dummy3 = 0x%0x (%d)\n",D_OFFS(dummy3),key->dummy3,key->dummy3);
554 printf("%04x dummy4 = 0x%0x (%d)\n",D_OFFS(dummy4),key->dummy4,key->dummy4);
555 printf("%04x dummy5 = 0x%0x (%d)\n",D_OFFS(dummy5),key->dummy5,key->dummy5);
556 printf("%04x dummy6 = 0x%0x (%d)\n",D_OFFS(dummy6),key->dummy6,key->dummy6);
557 printf("%04x dummy7 = 0x%0x (%d)\n",D_OFFS(dummy7),key->dummy7,key->dummy7);
558
559 printf("%04x name length = %d\n", D_OFFS(len_name),key->len_name);
560 printf("%04x classname length = %d\n", D_OFFS(len_classnam),key->len_classnam);
561
562 printf("%04x Key name: <",D_OFFS(keyname) );
563 for(i = 0; i < key->len_name; i++) putchar(key->keyname[i]);
564 printf(">\n== End of key info.\n");
565
566 }
567
568 /* Parse the vk datablock
569 * vofs = offset into struct (after size linkage)
570 */
parse_vk(struct hive * hdesc,int vofs,int blen)571 void parse_vk(struct hive *hdesc, int vofs, int blen)
572 {
573 struct vk_key *key;
574 int i;
575
576 printf("== vk at offset %0x\n",vofs);
577
578
579 key = (struct vk_key *)(hdesc->buffer + vofs);
580 printf("%04x name length = %d (0x%0x)\n", D_OFFS(len_name),
581 key->len_name, key->len_name );
582 printf("%04x length of data = %d (0x%0x)\n", D_OFFS(len_data),
583 key->len_data, key->len_data );
584 printf("%04x data offset = 0x%0x\n",D_OFFS(ofs_data),key->ofs_data + 0x1000);
585 printf("%04x value type = 0x%0x %s\n", D_OFFS(val_type), key->val_type,
586 (key->val_type <= REG_MAX ? val_types[key->val_type] : "(unknown)") ) ;
587
588 printf("%04x flag = 0x%0x\n",D_OFFS(flag),key->flag);
589 printf("%04x *unused?* = 0x%0x\n",D_OFFS(dummy1),key->dummy1);
590
591 printf("%04x Key name: <",D_OFFS(keyname) );
592 for(i = 0; i < key->len_name; i++) putchar(key->keyname[i]);
593 printf(">\n== End of key info.\n");
594
595 }
596
597 /* Parse the sk datablock
598 * Gee, this is the security info. Who cares? *evil grin*
599 * vofs = offset into struct (after size linkage)
600 */
parse_sk(struct hive * hdesc,int vofs,int blen)601 void parse_sk(struct hive *hdesc, int vofs, int blen)
602 {
603 struct sk_key *key;
604 /* int i; */
605
606 printf("== sk at offset %0x\n",vofs);
607
608 key = (struct sk_key *)(hdesc->buffer + vofs);
609 printf("%04x *unused?* = %d\n" , D_OFFS(dummy1), key->dummy1 );
610 printf("%04x Offset to prev sk = 0x%0x\n", D_OFFS(ofs_prevsk), key->ofs_prevsk + 0x1000);
611 printf("%04x Offset to next sk = 0x%0x\n", D_OFFS(ofs_nextsk), key->ofs_nextsk + 0x1000);
612 printf("%04x Usage counter = %d (0x%0x)\n", D_OFFS(no_usage),
613 key->no_usage,key->no_usage);
614 printf("%04x Security data len = %d (0x%0x)\n", D_OFFS(len_sk),
615 key->len_sk,key->len_sk);
616
617 printf("== End of key info.\n");
618
619 }
620
621
622 /* Parse the lf datablock (>4.0 'nk' offsets lookuptable)
623 * vofs = offset into struct (after size linkage)
624 */
parse_lf(struct hive * hdesc,int vofs,int blen)625 void parse_lf(struct hive *hdesc, int vofs, int blen)
626 {
627 struct lf_key *key;
628 int i;
629
630 printf("== lf at offset %0x\n",vofs);
631
632 key = (struct lf_key *)(hdesc->buffer + vofs);
633 printf("%04x number of keys = %d\n", D_OFFS(no_keys), key->no_keys );
634
635 for(i = 0; i < key->no_keys; i++) {
636 printf("%04x %3d Offset: 0x%0x - <%c%c%c%c>\n",
637 D_OFFS(hash[i].ofs_nk), i,
638 key->hash[i].ofs_nk + 0x1000,
639 key->hash[i].name[0],
640 key->hash[i].name[1],
641 key->hash[i].name[2],
642 key->hash[i].name[3] );
643 }
644
645 printf("== End of key info.\n");
646
647 }
648
649 /* Parse the lh datablock (WinXP offsets lookuptable)
650 * vofs = offset into struct (after size linkage)
651 * The hash is most likely a base 37 conversion of the name string
652 */
parse_lh(struct hive * hdesc,int vofs,int blen)653 void parse_lh(struct hive *hdesc, int vofs, int blen)
654 {
655 struct lf_key *key;
656 int i;
657
658 printf("== lh at offset %0x\n",vofs);
659
660 key = (struct lf_key *)(hdesc->buffer + vofs);
661 printf("%04x number of keys = %d\n", D_OFFS(no_keys), key->no_keys );
662
663 for(i = 0; i < key->no_keys; i++) {
664 printf("%04x %3d Offset: 0x%0x - <hash: %08x>\n",
665 D_OFFS(lh_hash[i].ofs_nk), i,
666 key->lh_hash[i].ofs_nk + 0x1000,
667 key->lh_hash[i].hash );
668 }
669
670 printf("== End of key info.\n");
671
672 }
673
674
675 /* Parse the li datablock (3.x 'nk' offsets list)
676 * vofs = offset into struct (after size linkage)
677 */
parse_li(struct hive * hdesc,int vofs,int blen)678 void parse_li(struct hive *hdesc, int vofs, int blen)
679 {
680 struct li_key *key;
681 int i;
682
683 printf("== li at offset %0x\n",vofs);
684
685 /* #define D_OFFS(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs ) */
686
687 key = (struct li_key *)(hdesc->buffer + vofs);
688 printf("%04x number of keys = %d\n", D_OFFS(no_keys), key->no_keys );
689
690 for(i = 0; i < key->no_keys; i++) {
691 printf("%04x %3d Offset: 0x%0x\n",
692 D_OFFS(hash[i].ofs_nk), i,
693 key->hash[i].ofs_nk + 0x1000);
694 }
695 printf("== End of key info.\n");
696
697 }
698
699 /* Parse the ri subindex-datablock
700 * (Used to list li/lf/lh's when ~>500keys)
701 * vofs = offset into struct (after size linkage)
702 */
parse_ri(struct hive * hdesc,int vofs,int blen)703 void parse_ri(struct hive *hdesc, int vofs, int blen)
704 {
705 struct ri_key *key;
706 int i;
707
708 printf("== ri at offset %0x\n",vofs);
709
710 /* #define D_OFFS(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs ) */
711
712 key = (struct ri_key *)(hdesc->buffer + vofs);
713 printf("%04x number of subindices = %d\n", D_OFFS(no_lis), key->no_lis );
714
715 for(i = 0; i < key->no_lis; i++) {
716 printf("%04x %3d Offset: 0x%0x\n",
717 D_OFFS(hash[i].ofs_li), i,
718 key->hash[i].ofs_li + 0x1000);
719 }
720 printf("== End of key info.\n");
721
722 }
723
724
725 /* Parse the db block (used when value data >4k or something)
726 * vofs = offset into struct (after size linkage)
727 */
parse_db(struct hive * hdesc,int vofs,int blen)728 void parse_db(struct hive *hdesc, int vofs, int blen)
729 {
730 struct db_key *key;
731
732 printf("== db at offset %0x\n",vofs);
733
734 key = (struct db_key *)(hdesc->buffer + vofs);
735 printf("%04x number of parts = %d\n", D_OFFS(no_part), key->no_part );
736
737 printf("%04x Data list at offset: 0x%0x\n",
738 D_OFFS(ofs_data),
739 key->ofs_data + 0x1000);
740
741 printf("== End of key info.\n");
742
743 }
744
745
746
747 /* Parse the datablock
748 * vofs = offset into struct (after size linkage)
749 */
750
parse_block(struct hive * hdesc,int vofs,int verbose)751 int parse_block(struct hive *hdesc, int vofs,int verbose)
752 {
753 unsigned short id;
754 int seglen;
755
756 seglen = get_int(hdesc->buffer+vofs);
757
758 // if (vofs > 0xaef000) verbose = 1;
759
760 #if 0
761 if (verbose || seglen == 0) {
762 printf("** Block at offset %0x\n",vofs);
763 printf("seglen: %d, %u, 0x%0x\n",seglen,seglen,seglen);
764 }
765 #endif
766 if (seglen == 0) {
767 printf("parse_block: FATAL! Zero data block size! (not registry or corrupt file?)\n");
768 if (verbose) debugit(hdesc->buffer,hdesc->size);
769 return(0);
770 }
771
772 if (seglen < 0) {
773 seglen = -seglen;
774 hdesc->usetot += seglen;
775 hdesc->useblk++;
776 if (verbose) {
777 printf("USED BLOCK @ %06x to %06x : %d, 0x%0x\n",vofs,vofs+seglen,seglen,seglen);
778 /* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */
779 }
780 } else {
781 hdesc->unusetot += seglen;
782 hdesc->unuseblk++;
783 /* Useful to zero blocks we think are empty when debugging.. */
784 #if ZEROFILLONLOAD
785 bzero(hdesc->buffer+vofs+4,seglen-4);
786 #endif
787
788 if (verbose) {
789 printf("FREE BLOCK @ %06x to %06x : %d, 0x%0x\n",vofs,vofs+seglen,seglen,seglen);
790 /* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */
791 }
792 }
793
794
795 vofs += 4;
796 id = (*(hdesc->buffer + vofs)<<8) + *(hdesc->buffer+vofs+1);
797
798 if (verbose > 1) {
799 switch (id) {
800 case 0x6e6b: /* nk */
801 parse_nk(hdesc, vofs, seglen);
802 break;
803 case 0x766b: /* vk */
804 parse_vk(hdesc, vofs, seglen);
805 break;
806 case 0x6c66: /* lf */
807 parse_lf(hdesc, vofs, seglen);
808 break;
809 case 0x6c68: /* lh */
810 parse_lh(hdesc, vofs, seglen);
811 break;
812 case 0x6c69: /* li */
813 parse_li(hdesc, vofs, seglen);
814 break;
815 case 0x736b: /* sk */
816 parse_sk(hdesc, vofs, seglen);
817 break;
818 case 0x7269: /* ri */
819 parse_ri(hdesc, vofs, seglen);
820 break;
821 case 0x6462: /* db */
822 parse_db(hdesc, vofs, seglen);
823 break;
824 default:
825 printf("value data, or not handeled yet!\n");
826 break;
827 }
828 }
829 return(seglen);
830 }
831
832 /* ================================================================ */
833 /* Scan and allocation routines */
834
835 /* Find start of page given a current pointer into the buffer
836 * hdesc = hive
837 * vofs = offset pointer into buffer
838 * returns: offset to start of page (and page header)
839 */
840
find_page_start(struct hive * hdesc,int vofs)841 int find_page_start(struct hive *hdesc, int vofs)
842 {
843 int r,prev;
844 struct hbin_page *h;
845
846 /* Again, assume start at 0x1000 */
847
848 r = 0x1000;
849 while (r < hdesc->size) {
850 prev = r;
851 h = (struct hbin_page *)(hdesc->buffer + r);
852 if (h->id != 0x6E696268) return(0);
853 if (h->ofs_next == 0) {
854 printf("find_page_start: zero len or ofs_next found in page at 0x%x\n",r);
855 return(0);
856 }
857 r += h->ofs_next;
858 if (r > vofs) return (prev);
859 }
860 return(0);
861 }
862
863 /* Find free space in page
864 * size = requested size in bytes
865 * pofs = offset to start of actual page header
866 * returns: offset to free block, or 0 for error
867 */
868
869 #define FB_DEBUG 0
870
find_free_blk(struct hive * hdesc,int pofs,int size)871 int find_free_blk(struct hive *hdesc, int pofs, int size)
872 {
873 int vofs = pofs + 0x20;
874 int seglen;
875 struct hbin_page *p;
876
877 p = (struct hbin_page *)(hdesc->buffer + pofs);
878
879 while (vofs-pofs < (p->ofs_next - HBIN_ENDFILL)) {
880
881 seglen = get_int(hdesc->buffer+vofs);
882
883 #if FB_DEBUG
884 if (vofs > 0x400000) {
885 printf("** Block at offset %0x\n",vofs);
886 printf("seglen: %d, %u, 0x%0x\n",seglen,seglen,seglen);
887 }
888 #endif
889
890 if (seglen == 0) {
891 printf("find_free_blk: FATAL! Zero data block size! (not registry or corrupt file?)\n");
892 printf(" : Block at offset %0x\n",vofs);
893 if ( (vofs - pofs) == (p->ofs_next - 4) ) {
894 printf("find_free_blk: at exact end of hbin, do not care..\n");
895 return(0);
896 }
897 if (hdesc->state & HMODE_TRACE) debugit(hdesc->buffer,hdesc->size);
898 else abort();
899 return(0);
900 }
901
902 if (seglen < 0) {
903 seglen = -seglen;
904 #if FB_DEBUG
905 if (vofs >0x400000) printf("USED BLOCK: %d, 0x%0x\n",seglen,seglen);
906 #endif
907 /* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */
908 } else {
909 #if FB_DEBUG
910 if (vofs >0x400000) printf("FREE BLOCK!\n");
911 #endif
912 /* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */
913 if (seglen >= size) {
914 #if FB_DEBUG
915 if (vofs >0x400000) printf("find_free_blk: found size %d block at 0x%x\n",seglen,vofs);
916 #endif
917 #if 0
918 if (vofs == 0x19fb8) {
919 printf("find_free_blk: vofs = %x, seglen = %x\n",vofs,seglen);
920 debugit(hdesc->buffer,hdesc->size);
921 abort();
922 }
923 #endif
924 return(vofs);
925 }
926 }
927 vofs += seglen;
928 }
929 return(0);
930
931 }
932
933 #undef FB_DEBUG
934
935 /* Search pages from start to find free block
936 * hdesc - hive
937 * size - space requested, in bytes
938 * returns: offset to free block, 0 if not found or error
939 */
940
find_free(struct hive * hdesc,int size)941 int find_free(struct hive *hdesc, int size)
942 {
943 int r,blk;
944 struct hbin_page *h;
945
946 /* Align to 8 byte boundary */
947 if (size & 7) size += (8 - (size & 7));
948
949 /* Again, assume start at 0x1000 */
950
951 r = 0x1000;
952 while (r < hdesc->endofs) {
953 h = (struct hbin_page *)(hdesc->buffer + r);
954 if (h->id != 0x6E696268) return(0);
955 if (h->ofs_next == 0) {
956 printf("find_free: zero len or ofs_next found in page at 0x%x\n",r);
957 return(0);
958 }
959 blk = find_free_blk(hdesc,r,size);
960 if (blk) return (blk);
961 r += h->ofs_next;
962 }
963 return(0);
964 }
965
966 /* Add new hbin to end of file. If file contains data at end
967 * that is not in a hbin, include that too
968 * hdesc - hive as usual
969 * size - minimum size (will be rounded up to next 0x1000 alignment)
970 * returns offset to first block in new hbin
971 */
972
973 #define ADDBIN_DEBUG
add_bin(struct hive * hdesc,int size)974 int add_bin(struct hive *hdesc, int size)
975 {
976 int r,newsize,newbinofs;
977 struct hbin_page *newbin;
978 struct regf_header *hdr;
979
980 if (hdesc->state & HMODE_NOEXPAND) {
981 fprintf(stderr,"ERROR: Registry hive <%s> need to be expanded,\n"
982 "but that is not allowed according to selected options. Operations will fail.\n", hdesc->filename);
983 return(0);
984 }
985
986 r = ((size + 0x20 + 4) & ~0xfff) + HBIN_PAGESIZE; /* Add header and link, round up to page boundary, usually 0x1000 */
987
988 newbinofs = hdesc->endofs;
989
990
991 #ifdef ADDBIN_DEBUG
992 printf("add_bin: request size = %d [%x], rounded to %d [%x]\n",size,size,r,r);
993 printf("add_bin: old buffer size = %d [%x]\n",hdesc->size,hdesc->size);
994 printf("add_bin: firs nonbin off = %d [%x]\n",newbinofs,newbinofs);
995 printf("add_bin: free at end = %d [%x]\n",hdesc->size-newbinofs,hdesc->size-newbinofs);
996 #endif
997
998 if ( (newbinofs + r) >= hdesc->size) { /* We must allocate more buffer */
999 newsize = ( (newbinofs + r) & ~(REGF_FILEDIVISOR-1) ) + REGF_FILEDIVISOR; /* File normally multiple of 0x40000 bytes */
1000
1001 #ifdef ADDBIN_DEBUG
1002 printf("add_bin: new buffer size = %d [%x]\n",newsize,newsize);
1003 #endif
1004
1005 hdesc->buffer = realloc(hdesc->buffer, newsize);
1006 if (!hdesc->buffer) {
1007 perror("add_bin : realloc() ");
1008 abort();
1009 }
1010 hdesc->size = newsize;
1011
1012 }
1013
1014 /* At this point, we have large enough space at end of file */
1015
1016 newbin = (struct hbin_page *)(hdesc->buffer + newbinofs);
1017
1018 bzero((void *)newbin, r); /* zero out new hbin, easier to debug too */
1019
1020 newbin->id = 0x6E696268; /* 'hbin' */
1021 newbin->ofs_self = newbinofs - 0x1000; /* Point to ourselves minus regf. Seem to be that.. */
1022 newbin->ofs_next = r; /* size of this new bin */
1023
1024 /* Wonder if anything else in the hbin header matters? */
1025
1026 /* Set whole hbin to be one contious unused block */
1027 newbin->firstlink = (r - 0x20 - 0); /* Positive linkage = unused */
1028
1029 /* Update REGF header */
1030 hdr = (struct regf_header *) hdesc->buffer;
1031 hdr->filesize = newbinofs + r - 0x1000; /* Point header to new end of data */
1032
1033 #ifdef ADDBIN_DEBUG
1034 printf("add_bin: adjusting size field in REGF: %d [%x]\n",hdr->filesize,hdr->filesize);
1035 #endif
1036
1037 /* Update state */
1038
1039 hdesc->state |= HMODE_DIDEXPAND | HMODE_DIRTY;
1040 hdesc->lastbin = newbinofs; /* Last bin */
1041 hdesc->endofs = newbinofs + r; /* New data end */
1042
1043 return(newbinofs + 0x20);
1044
1045 }
1046
1047
1048
1049 /* Allocate a block of requested size if possible
1050 * hdesc - hive
1051 * pofs - If >0 will try this page first (ptr may be inside page)
1052 * size - number of bytes to allocate
1053 * returns: 0 - failed, else pointer to allocated block.
1054 * WARNING: Will realloc() buffer if it has to be expanded!
1055 * ALL POINTERS TO BUFFER IS INVALID AFTER THAT. (offsets are still correct)
1056 * Guess I'd better switch to mmap() one day..
1057 * This function WILL CHANGE THE HIVE (change block linkage) if it
1058 * succeeds.
1059 */
1060
alloc_block(struct hive * hdesc,int ofs,int size)1061 int alloc_block(struct hive *hdesc, int ofs, int size)
1062 {
1063 int pofs = 0;
1064 int blk = 0;
1065 int newbin;
1066 int trail, trailsize, oldsz;
1067
1068 if (hdesc->state & HMODE_NOALLOC) {
1069 printf("\nERROR: alloc_block: Hive <%s> is in no allocation safe mode,"
1070 "new space not allocated. Operation will fail!\n", hdesc->filename);
1071 return(0);
1072 }
1073
1074 size += 4; /* Add linkage */
1075 if (size & 7) size += (8 - (size & 7));
1076
1077 /* Check current page first */
1078 if (ofs) {
1079 pofs = find_page_start(hdesc,ofs);
1080 blk = find_free_blk(hdesc,pofs,size);
1081 }
1082
1083 /* Then check whole hive */
1084 if (!blk) {
1085 blk = find_free(hdesc,size);
1086 }
1087
1088 if (blk) { /* Got the space */
1089 oldsz = get_int(hdesc->buffer+blk);
1090 #if 0
1091 printf("Block at : %x\n",blk);
1092 printf("Old block size is: %x\n",oldsz);
1093 printf("New block size is: %x\n",size);
1094 #endif
1095 trailsize = oldsz - size;
1096
1097 if (trailsize == 4) {
1098 trailsize = 0;
1099 size += 4;
1100 }
1101
1102 #if 1
1103 if (trailsize & 7) { /* Trail must be 8 aligned */
1104 trailsize -= (8 - (trailsize & 7));
1105 size += (8 - (trailsize & 7));
1106 }
1107 if (trailsize == 4) {
1108 trailsize = 0;
1109 size += 4;
1110 }
1111 #endif
1112
1113 #if 0
1114 printf("trail after comp: %x\n",trailsize);
1115 printf("size after comp: %x\n",size);
1116 #endif
1117
1118 /* Now change pointers on this to reflect new size */
1119 *(int *)((hdesc->buffer)+blk) = -(size);
1120 /* If the fit was exact (unused block was same size as wee need)
1121 * there is no need for more, else make free block after end
1122 * of newly allocated one */
1123
1124 hdesc->useblk++;
1125 hdesc->unuseblk--;
1126 hdesc->usetot += size;
1127 hdesc->unusetot -= size;
1128
1129 if (trailsize) {
1130 trail = blk + size;
1131
1132 *(int *)((hdesc->buffer)+trail) = (int)trailsize;
1133
1134 hdesc->useblk++; /* This will keep blockcount */
1135 hdesc->unuseblk--;
1136 hdesc->usetot += 4; /* But account for more linkage bytes */
1137 hdesc->unusetot -= 4;
1138
1139 }
1140 /* Clear the block data, makes it easier to debug */
1141 #if ZEROFILL
1142 bzero( (void *)(hdesc->buffer+blk+4), size-4);
1143 #endif
1144
1145 hdesc->state |= HMODE_DIRTY;
1146
1147 #if 0
1148 printf("alloc_block: returning %x\n",blk);
1149 #endif
1150 return(blk);
1151 } else {
1152 printf("alloc_block: failed to alloc %d bytes, trying to expand hive..\n",size);
1153
1154 newbin = add_bin(hdesc,size);
1155 if (newbin) return(alloc_block(hdesc,newbin,size)); /* Nasty... recall ourselves. */
1156 /* Fallthrough to fail if add_bin fails */
1157 }
1158 return(0);
1159 }
1160
1161 /* Free a block in registry
1162 * hdesc - hive
1163 * blk - offset of block, MUST POINT TO THE LINKAGE!
1164 * returns bytes freed (incl linkage bytes) or 0 if fail
1165 * Will CHANGE HIVE IF SUCCESSFUL (changes linkage)
1166 */
1167
1168 #define FB_DEBUG 0
1169
free_block(struct hive * hdesc,int blk)1170 int free_block(struct hive *hdesc, int blk)
1171 {
1172 int pofs,vofs,seglen,prev,next,nextsz,prevsz,size;
1173 struct hbin_page *p;
1174
1175 if (hdesc->state & HMODE_NOALLOC) {
1176 printf("free_block: ERROR: Hive %s is in no allocation safe mode,"
1177 "space not freed. Operation will fail!\n", hdesc->filename);
1178 return(0);
1179 }
1180
1181 size = get_int(hdesc->buffer+blk);
1182 if (size >= 0) {
1183 printf("free_block: trying to free already free block!\n");
1184 #ifdef DOCORE
1185 printf("blk = %x\n",blk);
1186 if (hdesc->state & HMODE_TRACE) debugit(hdesc->buffer,hdesc->size);
1187 abort();
1188 #endif
1189 return(0);
1190 }
1191 size = -size;
1192
1193 /* So, we must find start of the block BEFORE us */
1194 pofs = find_page_start(hdesc,blk);
1195 if (!pofs) return(0);
1196
1197 p = (struct hbin_page *)(hdesc->buffer + pofs);
1198 vofs = pofs + 0x20;
1199
1200 prevsz = -32;
1201
1202 if (vofs != blk) { /* Block is not at start of page? */
1203 while (vofs-pofs < (p->ofs_next - HBIN_ENDFILL) ) {
1204
1205 seglen = get_int(hdesc->buffer+vofs);
1206
1207 if (seglen == 0) {
1208 printf("free_block: EEEK! Zero data block size! (not registry or corrupt file?)\n");
1209 debugit(hdesc->buffer,hdesc->size);
1210 return(0);
1211 }
1212
1213 if (seglen < 0) {
1214 seglen = -seglen;
1215 /* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */
1216 }
1217 prev = vofs;
1218 vofs += seglen;
1219 if (vofs == blk) break;
1220 }
1221
1222 if (vofs != blk) {
1223 printf("free_block: ran off end of page!?!? Error in chains?\n");
1224 #ifdef DOCORE
1225 printf("vofs = %x, pofs = %x, blk = %x\n",vofs,pofs,blk);
1226 if (hdesc->state & HMODE_TRACE) debugit(hdesc->buffer,hdesc->size);
1227 abort();
1228 #endif
1229 return(0);
1230 }
1231
1232 prevsz = get_int(hdesc->buffer+prev);
1233
1234 }
1235
1236 /* We also need details on next block (unless at end of page) */
1237 next = blk + size;
1238
1239 nextsz = 0;
1240 if (next-pofs < (p->ofs_next - HBIN_ENDFILL) ) nextsz = get_int(hdesc->buffer+next);
1241
1242 #if 0
1243 printf("offset prev : %x , blk: %x , next: %x\n",prev,blk,next);
1244 printf("size prev : %x , blk: %x , next: %x\n",prevsz,size,nextsz);
1245 #endif
1246
1247 /* Now check if next block is free, if so merge it with the one to be freed */
1248 if ( nextsz > 0) {
1249 #if 0
1250 printf("Swallow next\n");
1251 #endif
1252 size += nextsz; /* Swallow it in current block */
1253 hdesc->useblk--;
1254 hdesc->usetot -= 4;
1255 hdesc->unusetot -= 4; /* FIXME !??!?? */
1256 }
1257
1258 /* Now free the block (possibly with ajusted size as above) */
1259 #if ZEROFILL
1260 bzero( (void *)(hdesc->buffer+blk), size);
1261 #endif
1262
1263 *(int *)((hdesc->buffer)+blk) = (int)size;
1264 hdesc->usetot -= size;
1265 hdesc->unusetot -= size; /* FIXME !?!? */
1266 hdesc->unuseblk--;
1267
1268 hdesc->state |= HMODE_DIRTY;
1269
1270 /* Check if previous block is also free, if so, merge.. */
1271 if (prevsz > 0) {
1272 #if 0
1273 printf("Swallow prev\n");
1274 #endif
1275 hdesc->usetot -= prevsz;
1276 hdesc->unusetot += prevsz;
1277 prevsz += size;
1278 /* And swallow current.. */
1279 #if ZEROFILL
1280 bzero( (void *)(hdesc->buffer+prev), prevsz);
1281 #endif
1282 *(int *)((hdesc->buffer)+prev) = (int)prevsz;
1283 hdesc->useblk--;
1284 return(prevsz);
1285 }
1286 return(size);
1287 }
1288
1289
1290
1291
1292
1293 /* ================================================================ */
1294
1295 /* ** Registry manipulation routines ** */
1296
1297
1298
1299 /* "directory scan", return next name/pointer of a subkey on each call
1300 * nkofs = offset to directory to scan
1301 * lfofs = pointer to int to hold the current scan position,
1302 * set position to 0 to start.
1303 * sptr = pointer to struct to hold a single result
1304 * returns: -1 = error. 0 = end of key. 1 = more subkeys to scan
1305 * NOTE: caller must free the name-buffer (struct ex_data *name)
1306 */
ex_next_n(struct hive * hdesc,int nkofs,int * count,int * countri,struct ex_data * sptr)1307 int ex_next_n(struct hive *hdesc, int nkofs, int *count, int *countri, struct ex_data *sptr)
1308 {
1309 struct nk_key *key, *newnkkey;
1310 int newnkofs;
1311 struct lf_key *lfkey;
1312 struct li_key *likey;
1313 struct ri_key *rikey;
1314
1315
1316 if (!nkofs) return(-1);
1317 key = (struct nk_key *)(hdesc->buffer + nkofs);
1318 if (key->id != 0x6b6e) {
1319 printf("ex_next error: Not a 'nk' node at 0x%0x\n",nkofs);
1320 return(-1);
1321 }
1322
1323 #define EXNDEBUG 0
1324
1325 lfkey = (struct lf_key *)(hdesc->buffer + key->ofs_lf + 0x1004);
1326 rikey = (struct ri_key *)(hdesc->buffer + key->ofs_lf + 0x1004);
1327
1328 if (rikey->id == 0x6972) { /* Is it extended 'ri'-block? */
1329 #if EXNDEBUG
1330 printf("%d , %d\n",*countri,*count);
1331 #endif
1332 if (*countri < 0 || *countri >= rikey->no_lis) { /* End of ri's? */
1333 return(0);
1334 }
1335 /* Get the li of lf-struct that's current based on countri */
1336 likey = (struct li_key *)( hdesc->buffer + rikey->hash[*countri].ofs_li + 0x1004 ) ;
1337 if (likey->id == 0x696c) {
1338 newnkofs = likey->hash[*count].ofs_nk + 0x1000;
1339 } else {
1340 lfkey = (struct lf_key *)( hdesc->buffer + rikey->hash[*countri].ofs_li + 0x1004 ) ;
1341 newnkofs = lfkey->hash[*count].ofs_nk + 0x1000;
1342 }
1343
1344 /* Check if current li/lf is exhausted */
1345 #if EXNDEBUG
1346 printf("likey->no_keys = %d\n",likey->no_keys);
1347 #endif
1348 if (*count >= likey->no_keys-1) { /* Last legal entry in li list? */
1349 (*countri)++; /* Bump up ri count so we take next ri entry next time */
1350 (*count) = -1; /* Reset li traverse counter for next round, not used later here */
1351 }
1352 } else { /* Plain handler */
1353 if (key->no_subkeys <= 0 || *count >= key->no_subkeys) {
1354 return(0);
1355 }
1356 if (lfkey->id == 0x696c) { /* Is it 3.x 'li' instead? */
1357 likey = (struct li_key *)(hdesc->buffer + key->ofs_lf + 0x1004);
1358 newnkofs = likey->hash[*count].ofs_nk + 0x1000;
1359 } else {
1360 newnkofs = lfkey->hash[*count].ofs_nk + 0x1000;
1361 }
1362 }
1363
1364 sptr->nkoffs = newnkofs;
1365 newnkkey = (struct nk_key *)(hdesc->buffer + newnkofs + 4);
1366 sptr->nk = newnkkey;
1367
1368 if (newnkkey->id != 0x6b6e) {
1369 printf("ex_next: ERROR: not 'nk' node at 0x%0x\n",newnkofs);
1370
1371 return(-1);
1372 } else {
1373 if (newnkkey->len_name <= 0) {
1374 printf("ex_next: nk at 0x%0x has no name!\n",newnkofs);
1375 } else if (newnkkey->type & 0x20) {
1376 #if 0
1377 printf("dummy1 %x\n", *((int*)newnkkey->dummy1));
1378 printf("dummy2 %x\n", *((int*)newnkkey->dummy2));
1379 printf("type %x\n", newnkkey->type);
1380 printf("timestamp+8 %x\n", *((int*)(newnkkey->timestamp+8)));
1381 printf("dummy3+0 %x\n", *((int*)(newnkkey->dummy3+0)));
1382 printf("dummy3+4 %x\n", *((int*)(newnkkey->dummy3+4)));
1383 printf("dummy3+8 %x\n", *((int*)(newnkkey->dummy3+8)));
1384 printf("dummy3+12 %x\n", *((int*)(newnkkey->dummy3+12)));
1385 printf("dummy4 %x\n", *((int*)&newnkkey->dummy4));
1386 printf("len %d\n", newnkkey->len_name);
1387 printf("len class %d\n", newnkkey->len_classnam);
1388 fflush(stdout);
1389 #endif
1390
1391 sptr->name = mem_str(newnkkey->keyname,newnkkey->len_name);
1392 // sptr->name = string_rega2prog(newnkkey->keyname, newnkkey->len_name);
1393 } else {
1394 sptr->name = string_regw2prog(newnkkey->keyname, newnkkey->len_name);
1395 }
1396 } /* if */
1397 (*count)++;
1398 return(1);
1399 /* return( *count <= key->no_subkeys); */
1400 }
1401
1402 /* "directory scan" for VALUES, return next name/pointer of a value on each call
1403 * nkofs = offset to directory to scan
1404 * lfofs = pointer to int to hold the current scan position,
1405 * set position to 0 to start.
1406 * sptr = pointer to struct to hold a single result
1407 * returns: -1 = error. 0 = end of key. 1 = more values to scan
1408 * NOTE: caller must free the name-buffer (struct vex_data *name)
1409 */
ex_next_v(struct hive * hdesc,int nkofs,int * count,struct vex_data * sptr)1410 int ex_next_v(struct hive *hdesc, int nkofs, int *count, struct vex_data *sptr)
1411 {
1412 struct nk_key *key /* , *newnkkey */ ;
1413 int vkofs,vlistofs;
1414 int *vlistkey;
1415 struct vk_key *vkkey;
1416
1417
1418 if (!nkofs) return(-1);
1419 key = (struct nk_key *)(hdesc->buffer + nkofs);
1420 if (key->id != 0x6b6e) {
1421 printf("ex_next_v error: Not a 'nk' node at 0x%0x\n",nkofs);
1422 return(-1);
1423 }
1424
1425 if (key->no_values <= 0 || *count >= key->no_values) {
1426 return(0);
1427 }
1428
1429 vlistofs = key->ofs_vallist + 0x1004;
1430 vlistkey = (int *)(hdesc->buffer + vlistofs);
1431
1432 vkofs = vlistkey[*count] + 0x1004;
1433 vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1434 if (vkkey->id != 0x6b76) {
1435 printf("ex_next_v: hit non valuekey (vk) node during scan at offs 0x%0x\n",vkofs);
1436 return(-1);
1437 }
1438
1439 /* parse_vk(hdesc, vkofs, 4); */
1440
1441 sptr->vk = vkkey;
1442 sptr->vkoffs = vkofs;
1443 sptr->name = 0;
1444 sptr->size = (vkkey->len_data & 0x7fffffff);
1445
1446 if (vkkey->len_name >0) {
1447 if (vkkey->flag & 1) {
1448
1449 sptr->name = mem_str(vkkey->keyname, vkkey->len_name);
1450 // sptr->name = string_rega2prog(vkkey->keyname, vkkey->len_name);
1451 } else {
1452 sptr->name = string_regw2prog(vkkey->keyname, vkkey->len_name);
1453 }
1454 } else {
1455 sptr->name = str_dup("");
1456 }
1457
1458 sptr->type = vkkey->val_type;
1459
1460 if (sptr->size) {
1461 if (vkkey->val_type == REG_DWORD) {
1462 if (vkkey->len_data & 0x80000000) {
1463 sptr->val = (int)(vkkey->ofs_data);
1464 }
1465 }
1466 }
1467 #if 0
1468 else if (vkkey->len_data == 0x80000000) {
1469 /* Data SIZE is 0, high bit set: special inline case, data is DWORD and in TYPE field!! */
1470 /* Used a lot in SAM, and maybe in SECURITY I think */
1471 sptr->val = (int)(vkkey->val_type);
1472 sptr->size = 4;
1473 sptr->type = REG_DWORD;
1474 } else {
1475 sptr->val = 0;
1476 sptr->size = 0;
1477 }
1478 #endif
1479
1480 (*count)++;
1481 return( *count <= key->no_values );
1482 }
1483
1484 /* traceback - trace nk's back to root,
1485 * building path string as we go.
1486 * nkofs = offset to nk-node
1487 * path = pointer to pathstring-buffer
1488 * maxlen = max length of path-buffer
1489 * return: length of path string
1490 */
1491
get_abs_path(struct hive * hdesc,int nkofs,char * path,int maxlen)1492 int get_abs_path(struct hive *hdesc, int nkofs, char *path, int maxlen)
1493 {
1494 /* int newnkofs; */
1495 struct nk_key *key;
1496 char tmp[ABSPATHLEN+1];
1497 char *keyname;
1498 int len_name;
1499
1500 maxlen = (maxlen < ABSPATHLEN ? maxlen : ABSPATHLEN);
1501
1502 key = (struct nk_key *)(hdesc->buffer + nkofs);
1503
1504 if (key->id != 0x6b6e) {
1505 printf("get_abs_path: Not a 'nk' node!\n");
1506 return(0);
1507 }
1508
1509 if (key->type == KEY_ROOT) { /* We're at the root */
1510 return(strlen(path));
1511 }
1512
1513 strncpy(tmp,path,ABSPATHLEN-1);
1514
1515 if (key->type & 0x20)
1516 keyname = mem_str(key->keyname, key->len_name);
1517 // keyname = string_rega2prog(key->keyname, key->len_name);
1518 else
1519 keyname = string_regw2prog(key->keyname, key->len_name);
1520 len_name = strlen(keyname);
1521 if ( (strlen(path) + len_name) >= maxlen-6) {
1522 free(keyname);
1523 snprintf(path,maxlen,"(...)%s",tmp);
1524 return(strlen(path)); /* Stop trace when string exhausted */
1525 }
1526 *path = '\\';
1527 memcpy(path+1,keyname,len_name);
1528 free(keyname);
1529 strncpy(path+len_name+1,tmp,maxlen-6-len_name);
1530 return(get_abs_path(hdesc, key->ofs_parent+0x1004, path, maxlen)); /* go back one more */
1531 }
1532
1533
1534 /* Value index table lookup
1535 * hdesc - hive as usual
1536 * vlistofs - offset of table
1537 * name - value name to look for
1538 * returns index into table or -1 if err
1539 */
1540
vlist_find(struct hive * hdesc,int vlistofs,int numval,char * name,int type)1541 int vlist_find(struct hive *hdesc, int vlistofs, int numval, char *name, int type)
1542 {
1543 struct vk_key *vkkey;
1544 int i,vkofs,len;
1545 int32_t *vlistkey;
1546 int approx = -1;
1547
1548 len = strlen(name);
1549 vlistkey = (int32_t *)(hdesc->buffer + vlistofs);
1550
1551 // printf("vlist_find: <%s> len = %d\n",name,len);
1552
1553 for (i = 0; i < numval; i++) {
1554 vkofs = vlistkey[i] + 0x1004;
1555 vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1556 if (vkkey->len_name == 0 && *name == '@' && len == 1) { /* @ is alias for nameless value */
1557 return(i);
1558 }
1559
1560 // printf("vlist_find: matching against: <%s> len = %d\n",vkkey->keyname,vkkey->len_name);
1561
1562 if ( (type & TPF_EXACT) && vkkey->len_name != len ) continue; /* Skip if exact match and not exact size */
1563
1564 if ( vkkey->len_name >= len ) { /* Only check for names that are longer or equal than we seek */
1565 if ( !strncmp(name, vkkey->keyname, len) ) { /* Name match */
1566 if (vkkey->len_name == len) return(i); /* Exact match always best, returns */
1567 if (approx == -1) approx = i; /* Else remember first partial match */
1568 }
1569 }
1570
1571 }
1572 return(approx);
1573
1574 }
1575
1576 /* Recursevely follow 'nk'-nodes based on a path-string,
1577 * returning offset of last 'nk' or 'vk'
1578 * vofs - offset to start node
1579 * path - null-terminated pathname (relative to vofs, \ is separator)
1580 * type - type to return TPF_??, see ntreg.h
1581 * return: offset to nk or vk (or NULL if not found)
1582 */
1583
trav_path(struct hive * hdesc,int vofs,char * path,int type)1584 int trav_path(struct hive *hdesc, int vofs, char *path, int type)
1585 {
1586 struct nk_key *key, *newnkkey;
1587 struct lf_key *lfkey;
1588 struct li_key *likey;
1589 struct ri_key *rikey;
1590
1591 int32_t *vlistkey;
1592 int newnkofs, plen, i, lfofs, vlistofs, adjust, r, ricnt, subs;
1593 char *buf;
1594 char part[ABSPATHLEN+1];
1595 char *partptr;
1596
1597 if (!hdesc) return(0);
1598 buf = hdesc->buffer;
1599
1600 // printf("trav_path: called with vofs = %x, path = <%s>, type = %x\n",vofs, path, type);
1601
1602
1603 if (!vofs) vofs = hdesc->rootofs+4; /* No current key given , so start at root */
1604
1605 if ( !(type & TPF_ABS) && *path == '\\' && *(path+1) != '\\') { /* Start from root if path starts with \ */
1606 path++;
1607 vofs = hdesc->rootofs+4;
1608 }
1609
1610 key = (struct nk_key *)(buf + vofs);
1611 // printf("check of nk at offset: 0x%0x\n",vofs);
1612
1613 if (key->id != 0x6b6e) {
1614 printf("trav_path: Error: Not a 'nk' node!\n");
1615 return(0);
1616 }
1617
1618 if ( !(type & TPF_ABS)) { /* Only traverse path if not absolute literal value name passed */
1619
1620 /* TODO: Need to rethink this.. */
1621
1622 /* Find \ delimiter or end of string, copying to name part buffer as we go,
1623 rewriting double \\s */
1624 partptr = part;
1625 for(plen = 0; path[plen] && (path[plen] != '\\' || path[plen+1] == '\\'); plen++) {
1626 if (path[plen] == '\\' && path[plen+1] == '\\') plen++; /* Skip one if double */
1627 *partptr++ = path[plen];
1628 }
1629 *partptr = '\0';
1630
1631 #if 0
1632 printf("Name part: <%s>\n",part);
1633 printf("Name path: <%s>\n",path);
1634 #endif
1635
1636 adjust = (path[plen] == '\\' ) ? 1 : 0;
1637 // printf("Checking for <%s> with len %d\n",path,plen);
1638
1639 if (!plen) return(vofs-4); /* Path has no lenght - we're there! */
1640
1641 if ( (plen == 1) && (*(path+1) && *path == '.') && !(type & TPF_EXACT)) { /* Handle '.' current dir */
1642 // printf("** handle current\n");
1643 return(trav_path(hdesc,vofs,path+plen+adjust,type));
1644 }
1645 if ( !(type & TPF_EXACT) && (plen == 2) && !strncmp("..",path,2) ) { /* Get parent key */
1646 newnkofs = key->ofs_parent + 0x1004;
1647 /* Return parent (or only root if at the root) */
1648 return(trav_path(hdesc, (key->type == KEY_ROOT ? vofs : newnkofs), path+plen+adjust, type));
1649 }
1650
1651 }
1652
1653 /* at last name of path, and we want vk, and the nk has values */
1654 if ((type & TPF_VK_ABS) || (!path[plen] && (type & TPF_VK) && key->no_values) ) {
1655 // if ( (!path[plen] && (type & TPF_VK) && key->no_values) ) {
1656 if (type & TPF_ABS) {
1657 strcpy(part, path);
1658 plen = de_escape(part,0);
1659 partptr = part + plen;
1660 }
1661
1662 // printf("VK namematch for <%s>, type = %d\n",part,type);
1663 vlistofs = key->ofs_vallist + 0x1004;
1664 vlistkey = (int32_t *)(buf + vlistofs);
1665 i = vlist_find(hdesc, vlistofs, key->no_values, part, type);
1666 if (i != -1) {
1667 return(vlistkey[i] + 0x1000);
1668 }
1669 }
1670
1671 if (key->no_subkeys > 0) { /* If it has subkeys, loop through the hash */
1672 char *partw = NULL;
1673 int partw_len, part_len;
1674
1675 // printf("trav_path: subkey loop: path = %s, part = %s\n",path,part);
1676
1677 lfofs = key->ofs_lf + 0x1004; /* lf (hash) record */
1678 lfkey = (struct lf_key *)(buf + lfofs);
1679
1680 if (lfkey->id == 0x6972) { /* ri struct need special parsing */
1681 /* Prime loop state */
1682
1683 rikey = (struct ri_key *)lfkey;
1684 ricnt = rikey->no_lis;
1685 r = 0;
1686 likey = (struct li_key *)( hdesc->buffer + rikey->hash[r].ofs_li + 0x1004 ) ;
1687 subs = likey->no_keys;
1688 if (likey->id != 0x696c) { /* Bwah, not li anyway, XP uses lh usually which is actually smarter */
1689 lfkey = (struct lf_key *)( hdesc->buffer + rikey->hash[r].ofs_li + 0x1004 ) ;
1690 likey = NULL;
1691 }
1692 } else {
1693 if (lfkey->id == 0x696c) { /* li? */
1694 likey = (struct li_key *)(buf + lfofs);
1695 } else {
1696 likey = NULL;
1697 }
1698 rikey = NULL;
1699 ricnt = 0; r = 0; subs = key->no_subkeys;
1700 }
1701
1702 partw = string_prog2regw(part, partptr-part, &partw_len);
1703 // string_prog2rega(part, partptr-part);
1704 part_len = strlen(part);
1705 do {
1706 for(i = 0; i < subs; i++) {
1707 if (likey) newnkofs = likey->hash[i].ofs_nk + 0x1004;
1708 else newnkofs = lfkey->hash[i].ofs_nk + 0x1004;
1709 newnkkey = (struct nk_key *)(buf + newnkofs);
1710 if (newnkkey->id != 0x6b6e) {
1711 printf("ERROR: not 'nk' node! (strange?)\n");
1712 } else {
1713 if (newnkkey->len_name <= 0) {
1714 printf("[No name]\n");
1715 } else if (
1716 ( ( part_len <= newnkkey->len_name ) && !(type & TPF_EXACT) ) ||
1717 ( ( part_len == newnkkey->len_name ) && (type & TPF_EXACT) )
1718 ) {
1719 /* Can't match if name is shorter than we look for */
1720 int cmp;
1721 // printf("trav_path: part = <%s>, part_len = %d\n",part,part_len);
1722 if (newnkkey->type & 0x20)
1723 cmp = strncmp(part,newnkkey->keyname,part_len);
1724 else
1725 cmp = memcmp(partw, newnkkey->keyname, partw_len);
1726 if (!cmp) {
1727 // printf("Key at 0x%0x matches! recursing! new path = %s\n",newnkofs,path+plen+adjust);
1728 free(partw);
1729 return(trav_path(hdesc, newnkofs, path+plen+adjust, type));
1730 }
1731 }
1732 } /* if id OK */
1733 } /* hash loop */
1734 r++;
1735 if (ricnt && r < ricnt) {
1736 newnkofs = rikey->hash[r].ofs_li;
1737 likey = (struct li_key *)( hdesc->buffer + newnkofs + 0x1004 ) ;
1738 subs = likey->no_keys;
1739 if (likey->id != 0x696c) { /* Bwah, not li anyway, XP uses lh usually which is actually smarter */
1740 lfkey = (struct lf_key *)( hdesc->buffer + rikey->hash[r].ofs_li + 0x1004 ) ;
1741 likey = NULL;
1742 }
1743 }
1744 } while (r < ricnt && ricnt);
1745 free(partw);
1746
1747 } /* if subkeys */
1748
1749 /* Not found */
1750 return(0);
1751 }
1752
1753
1754 /* ls - list a 'nk' nodes subkeys and values
1755 * vofs - offset to start of data (skipping block linkage)
1756 * type - 0 = full, 1 = keys only. 2 = values only
1757 */
nk_ls(struct hive * hdesc,char * path,int vofs,int type)1758 void nk_ls(struct hive *hdesc, char *path, int vofs, int type)
1759 {
1760 struct nk_key *key;
1761 int nkofs;
1762 struct ex_data ex;
1763 struct vex_data vex;
1764 int count = 0, countri = 0;
1765
1766
1767 nkofs = trav_path(hdesc, vofs, path, 0);
1768
1769 if(!nkofs) {
1770 printf("nk_ls: Key <%s> not found\n",path);
1771 return;
1772 }
1773 nkofs += 4;
1774
1775 key = (struct nk_key *)(hdesc->buffer + nkofs);
1776 VERBF(hdesc,"ls of node at offset 0x%0x\n",nkofs);
1777
1778 if (key->id != 0x6b6e) {
1779 printf("Error: Not a 'nk' node at offset %x!\n",nkofs);
1780
1781 if (hdesc->state & HMODE_TRACE) debugit(hdesc->buffer,hdesc->size);
1782
1783 }
1784
1785 printf("Node has %d subkeys and %d values",key->no_subkeys,key->no_values);
1786 if (key->len_classnam) printf(", and class-data of %d bytes",key->len_classnam);
1787 printf("\n");
1788
1789 if (key->no_subkeys) {
1790 printf(" key name\n");
1791 while ((ex_next_n(hdesc, nkofs, &count, &countri, &ex) > 0)) {
1792 if (!(hdesc->state & HMODE_VERBOSE)) printf("%c <%s>\n", (ex.nk->len_classnam)?'*':' ',ex.name);
1793 else printf("[%6x] %c <%s>\n", ex.nkoffs, (ex.nk->len_classnam)?'*':' ',ex.name);
1794 FREE(ex.name);
1795 }
1796 }
1797 count = 0;
1798 if (key->no_values) {
1799 printf(" size type value name [value if type DWORD]\n");
1800 while ((ex_next_v(hdesc, nkofs, &count, &vex) > 0)) {
1801 if (hdesc->state & HMODE_VERBOSE) printf("[%6x] %6d %x %-16s <%s>", vex.vkoffs - 4, vex.size, vex.type,
1802 (vex.type < REG_MAX ? val_types[vex.type] : "(unknown)"), vex.name);
1803 else
1804 printf("%6d %x %-16s <%s>", vex.size, vex.type,
1805 (vex.type < REG_MAX ? val_types[vex.type] : "(unknown)"), vex.name);
1806
1807 if (vex.type == REG_DWORD) printf(" %*d [0x%x]",25-(int)strlen(vex.name),vex.val , vex.val);
1808 printf("\n");
1809 FREE(vex.name);
1810 }
1811 }
1812 }
1813
1814 /* Get the type of a value */
get_val_type(struct hive * hdesc,int vofs,char * path,int exact)1815 int get_val_type(struct hive *hdesc, int vofs, char *path, int exact)
1816 {
1817 struct vk_key *vkkey;
1818 int vkofs;
1819
1820 vkofs = trav_path(hdesc, vofs,path,exact | TPF_VK);
1821 if (!vkofs) {
1822 return -1;
1823 }
1824 vkofs +=4;
1825 vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1826
1827 return(vkkey->val_type);
1828 }
1829
1830 /* Set/change the type of a value. Strangely we need this in some situation in SAM
1831 * and delete + add value is a bit overkill */
1832
set_val_type(struct hive * hdesc,int vofs,char * path,int exact,int type)1833 int set_val_type(struct hive *hdesc, int vofs, char *path, int exact, int type)
1834 {
1835 struct vk_key *vkkey;
1836 int vkofs;
1837
1838 vkofs = trav_path(hdesc, vofs,path,exact | TPF_VK);
1839 if (!vkofs) {
1840 return -1;
1841 }
1842 vkofs +=4;
1843 vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1844
1845 vkkey->val_type = type;
1846
1847 return(vkkey->val_type);
1848 }
1849
1850
1851
1852 /* Get len of a value, given current key + path */
get_val_len(struct hive * hdesc,int vofs,char * path,int exact)1853 int get_val_len(struct hive *hdesc, int vofs, char *path, int exact)
1854 {
1855 struct vk_key *vkkey;
1856 int vkofs;
1857 int len;
1858
1859 vkofs = trav_path(hdesc, vofs,path,exact | TPF_VK);
1860 if (!vkofs) {
1861 return -1;
1862 }
1863 vkofs +=4;
1864 vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1865
1866 len = vkkey->len_data & 0x7fffffff;
1867
1868 if ( vkkey->len_data == 0x80000000 && (exact & TPF_VK_SHORT)) { /* Special inline case, return size of 4 (dword) */
1869 len = 4;
1870 }
1871
1872 return(len);
1873 }
1874
1875 /* Get void-pointer to value-data, also if inline.
1876 * If val_type != 0 a check for correct value type is done
1877 * Caller must keep track of value's length (call function above to get it)
1878 */
get_val_data(struct hive * hdesc,int vofs,char * path,int val_type,int exact)1879 void *get_val_data(struct hive *hdesc, int vofs, char *path, int val_type, int exact)
1880 {
1881 struct vk_key *vkkey;
1882 int vkofs;
1883
1884 // printf("get_val_data: path = %s\n",path);
1885
1886 vkofs = trav_path(hdesc,vofs,path,exact | TPF_VK);
1887 if (!vkofs) {
1888 printf("get_val_data: %s not found\n",path);
1889 abort();
1890 return NULL;
1891 }
1892 vkofs +=4;
1893 vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
1894
1895
1896 if (vkkey->len_data == 0) {
1897 return NULL;
1898 }
1899
1900 if (vkkey->len_data == 0x80000000 && (exact & TPF_VK_SHORT)) { /* Special inline case (len = 0x80000000) */
1901 return(&vkkey->val_type); /* Data (4 bytes?) in type field */
1902 }
1903
1904 if (val_type && vkkey->val_type && (vkkey->val_type) != val_type) {
1905 printf("Value <%s> is not of correct type!\n",path);
1906 #if DOCORE
1907 abort();
1908 #endif
1909 return NULL;
1910 }
1911
1912 /* Negative len is inline, return ptr to offset-field which in
1913 * this case contains the data itself
1914 */
1915 if (vkkey->len_data & 0x80000000) return(&vkkey->ofs_data);
1916 /* Normal return, return data pointer */
1917 return(hdesc->buffer + vkkey->ofs_data + 0x1004);
1918 }
1919
1920
1921 /* Get and copy key data (if any) to buffer
1922 * if kv==NULL will allocate needed return struct & buffer
1923 * else will use buffer allocated for it (if it fits)
1924 * return len+data or NULL if not found (or other error)
1925 * NOTE: caller must deallocate buffer! a simple free(keyval) will suffice.
1926 */
get_val2buf(struct hive * hdesc,struct keyval * kv,int vofs,char * path,int type,int exact)1927 struct keyval *get_val2buf(struct hive *hdesc, struct keyval *kv,
1928 int vofs, char *path, int type, int exact )
1929 {
1930 int l,i,parts,list,blockofs,blocksize,point,copylen,restlen;
1931 struct keyval *kr;
1932 void *keydataptr;
1933 struct db_key *db;
1934 void *addr;
1935
1936 l = get_val_len(hdesc, vofs, path, exact);
1937 if (l == -1) return(NULL); /* error */
1938 if (kv && (kv->len < l)) return(NULL); /* Check for overflow of supplied buffer */
1939
1940 keydataptr = get_val_data(hdesc, vofs, path, type, exact);
1941 // if (!keydataptr) return(NULL);
1942
1943 /* Allocate space for data + header, or use supplied buffer */
1944 if (kv) {
1945 kr = kv;
1946 } else {
1947 ALLOC(kr,1,l*sizeof(int)+4);
1948 }
1949
1950 kr->len = l;
1951
1952 // printf("get_val2buf: keydataprtr = %x, l = %x\n",keydataptr,l);
1953
1954
1955 if (l > VAL_DIRECT_LIMIT) { /* Where do the db indirects start? seems to be around 16k */
1956 db = (struct db_key *)keydataptr;
1957 if (db->id != 0x6264) abort();
1958 parts = db->no_part;
1959 list = db->ofs_data + 0x1004;
1960 printf("get_val2buf: Long value: parts = %d, list = %x\n",parts,list);
1961
1962 point = 0;
1963 restlen = l;
1964 for (i = 0; i < parts; i++) {
1965 blockofs = get_int(hdesc->buffer + list + (i << 2)) + 0x1000;
1966 blocksize = -get_int(hdesc->buffer + blockofs) - 8;
1967
1968 /* Copy this part, up to size of block or rest lenght in last block */
1969 copylen = (blocksize > restlen) ? restlen : blocksize;
1970
1971 printf("get_val2buf: Datablock %d offset %x, size %x (%d)\n",i,blockofs,blocksize,blocksize);
1972 printf(" : Point = %x, restlen = %x, copylen = %x\n",point,restlen,copylen);
1973
1974 addr = (void *)&(kr->data) + point;
1975 memcpy( addr, hdesc->buffer + blockofs + 4, copylen);
1976
1977 // debugit((char *)&(kr->data), l);
1978
1979 point += copylen;
1980 restlen -= copylen;
1981
1982 }
1983
1984
1985 } else {
1986 if (l && kr && keydataptr) memcpy(&(kr->data), keydataptr, l);
1987 }
1988
1989 return(kr);
1990 }
1991
1992 /* DWORDs are so common that I make a small function to get it easily */
1993
get_dword(struct hive * hdesc,int vofs,char * path,int exact)1994 int get_dword(struct hive *hdesc, int vofs, char *path, int exact)
1995 {
1996 struct keyval *v;
1997 int dword;
1998
1999 v = get_val2buf(hdesc, NULL, vofs, path, REG_DWORD, exact | TPF_VK);
2000 if (!v) return(-1); /* well... -1 COULD BE THE STORED VALUE TOO */
2001
2002 dword = (int)v->data;
2003
2004 FREE(v);
2005
2006 return(dword);
2007
2008 }
2009
2010 /* Sanity checker when transferring data into a block
2011 * ofs = offset to data block, point to start of actual datablock linkage
2012 * data = data to copy
2013 * size = size of data to copy
2014 */
2015
fill_block(struct hive * hdesc,int ofs,void * data,int size)2016 int fill_block(struct hive *hdesc, int ofs, void *data, int size)
2017 {
2018 int blksize;
2019
2020 blksize = get_int(hdesc->buffer + ofs);
2021 blksize = -blksize;
2022
2023 #if 0
2024 printf("fill_block: ofs = %x - %x, size = %x, blksize = %x\n",ofs,ofs+size,size,blksize);
2025 #endif
2026 /* if (blksize < size || ( (ofs & 0xfffff000) != ((ofs+size) & 0xfffff000) )) { */
2027 if (blksize < size) {
2028 printf("fill_block: ERROR: block to small for data: ofs = %x, size = %x, blksize = %x\n",ofs,size,blksize);
2029 if (hdesc->state & HMODE_TRACE) debugit(hdesc->buffer,hdesc->size);
2030 abort();
2031 }
2032
2033 memcpy(hdesc->buffer + ofs + 4, data, size);
2034 return(0);
2035 }
2036
2037
2038 /* Free actual data of a value, and update value descriptor
2039 * hdesc - hive
2040 * vofs - current value offset
2041 */
2042
free_val_data(struct hive * hdesc,int vkofs)2043 int free_val_data(struct hive *hdesc, int vkofs)
2044 {
2045 struct vk_key *vkkey;
2046 struct db_key *db;
2047 int len,i,blockofs,blocksize,parts,list;
2048
2049
2050 vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
2051
2052 len = vkkey->len_data;
2053
2054 if (!(len & 0x80000000)) { /* Check for inline, if so, skip it, nothing to do */
2055
2056 if (len > VAL_DIRECT_LIMIT) { /* Where do the db indirects start? seems to be around 16k */
2057
2058 db = (struct db_key *)(hdesc->buffer + vkkey->ofs_data + 0x1004);
2059
2060 if (db->id != 0x6264) abort();
2061
2062 parts = db->no_part;
2063 list = db->ofs_data + 0x1004;
2064
2065 printf("free_val_data: Long value: parts = %d, list = %x\n",parts,list);
2066
2067 for (i = 0; i < parts; i++) {
2068 blockofs = get_int(hdesc->buffer + list + (i << 2)) + 0x1000;
2069 blocksize = -get_int(hdesc->buffer + blockofs);
2070 printf("free_val_data: Freeing long datablock %d offset %x, size %x (%d)\n",i,blockofs,blocksize,blocksize);
2071 free_block(hdesc, blockofs);
2072 }
2073
2074 printf("free_val_data: Freeing indirect list at %x\n", list-4);
2075 free_block(hdesc, list - 4);
2076 printf("free_val_data: Freeing db structure at %x\n", vkkey->ofs_data + 0x1000);
2077 } /* Fall through to regular which deallocs data or db block ofs_data point to */
2078
2079 if (len) free_block(hdesc, vkkey->ofs_data + 0x1000);
2080
2081 } /* inline check */
2082
2083
2084 vkkey->len_data = 0;
2085 vkkey->ofs_data = 0;
2086
2087 return(vkofs);
2088
2089 }
2090
2091
2092 /* Allocate data for value. Frees old data (if any) which will be destroyed
2093 * hdesc - hive
2094 * vofs - current key
2095 * path - path to value
2096 * size - size of data
2097 * Returns: 0 - error, >0 pointer to actual dataspace
2098 */
2099
alloc_val_data(struct hive * hdesc,int vofs,char * path,int size,int exact)2100 int alloc_val_data(struct hive *hdesc, int vofs, char *path, int size,int exact)
2101 {
2102 struct vk_key *vkkey;
2103 struct db_key *db;
2104 int vkofs,dbofs,listofs,blockofs,blocksize,parts;
2105 int datablk,i;
2106 int *ptr;
2107
2108 vkofs = trav_path(hdesc,vofs,path,exact);
2109 if (!vkofs) {
2110 return (0);
2111 }
2112
2113 vkofs +=4;
2114 vkkey = (struct vk_key *)(hdesc->buffer + vkofs);
2115
2116
2117 free_val_data(hdesc, vkofs); /* Get rid of old data if any */
2118
2119 /* Allocate space for new data */
2120 if (size > 4) {
2121 if (size > VAL_DIRECT_LIMIT) { /* We must allocate indirect stuff *sigh* */
2122 parts = size / VAL_DIRECT_LIMIT + 1;
2123 printf("alloc_val_data: doing large key: size = %x (%d), parts = %d\n",size,size,parts);
2124
2125 dbofs = alloc_block(hdesc, vkofs, sizeof(struct db_key)); /* Alloc db structure */
2126 db = (struct db_key *)(hdesc->buffer + dbofs + 4);
2127 db->id = 0x6264;
2128 db->no_part = parts;
2129 listofs = alloc_block(hdesc, vkofs, 4 * parts); /* block offset list */
2130 db = (struct db_key *)(hdesc->buffer + dbofs + 4);
2131 db->ofs_data = listofs - 0x1000;
2132 printf("alloc_val_data: dbofs = %x, listofs = %x\n",dbofs,listofs);
2133
2134 for (i = 0; i < parts; i++) {
2135 blocksize = VAL_DIRECT_LIMIT; /* Windows seem to alway allocate the whole block */
2136 blockofs = alloc_block(hdesc, vkofs, blocksize);
2137 printf("alloc_val_data: block # %d, blockofs = %x\n",i,blockofs);
2138 ptr = (int *)(hdesc->buffer + listofs + 4 + (i << 2));
2139 *ptr = blockofs - 0x1000;
2140 }
2141 datablk = dbofs;
2142
2143 } else { /* Regular size < 16 k direct alloc */
2144 datablk = alloc_block(hdesc, vkofs, size);
2145 }
2146
2147
2148
2149 } else { /* 4 bytes or less are inlined */
2150 datablk = vkofs + (int32_t)&(vkkey->ofs_data) - (int32_t)vkkey;
2151 size |= 0x80000000;
2152 }
2153
2154 if (!datablk) return(0);
2155
2156 vkkey = (struct vk_key *)(hdesc->buffer + vkofs); /* alloc_block may move pointer, realloc() buf */
2157
2158 // printf("alloc_val_data: datablk = %x, size = %x, vkkey->len_data = %x\n",datablk, size, vkkey->len_data);
2159
2160
2161
2162 /* Link in new datablock */
2163 if ( !(size & 0x80000000)) vkkey->ofs_data = datablk - 0x1000;
2164 vkkey->len_data = size;
2165
2166 return(datablk + 4);
2167 }
2168
2169
2170 /* Add a value to a key.
2171 * Just add the metadata (empty value), to put data into it, use
2172 * put_buf2val afterwards
2173 * hdesc - hive
2174 * nkofs - current key
2175 * name - name of value
2176 * type - type of value
2177 * returns: 0 err, >0 offset to value metadata
2178 */
2179
add_value(struct hive * hdesc,int nkofs,char * name,int type)2180 struct vk_key *add_value(struct hive *hdesc, int nkofs, char *name, int type)
2181 {
2182 struct nk_key *nk;
2183 int oldvlist = 0, newvlist, newvkofs;
2184 struct vk_key *newvkkey;
2185 char *blank="";
2186
2187 if (!name || !*name) return(NULL);
2188
2189
2190 nk = (struct nk_key *)(hdesc->buffer + nkofs);
2191 if (nk->id != 0x6b6e) {
2192 printf("add_value: Key pointer not to 'nk' node!\n");
2193 return(NULL);
2194 }
2195
2196 if (vlist_find(hdesc, nk->ofs_vallist + 0x1004, nk->no_values, name, TPF_EXACT) != -1) {
2197 printf("add_value: value %s already exists\n",name);
2198 return(NULL);
2199 }
2200
2201 if (!strcmp(name,"@")) name = blank;
2202
2203 if (nk->no_values) oldvlist = nk->ofs_vallist;
2204
2205 newvlist = alloc_block(hdesc, nkofs, nk->no_values * 4 + 4);
2206 if (!newvlist) {
2207 printf("add_value: failed to allocate new value list!\n");
2208 return(NULL);
2209 }
2210
2211 nk = (struct nk_key *)(hdesc->buffer + nkofs); /* In case buffer was moved.. */
2212
2213 if (oldvlist) { /* Copy old data if any */
2214 memcpy(hdesc->buffer + newvlist + 4, hdesc->buffer + oldvlist + 0x1004, nk->no_values * 4 + 4);
2215 }
2216
2217 /* Allocate value descriptor including its name */
2218 newvkofs = alloc_block(hdesc, newvlist, sizeof(struct vk_key) + strlen(name));
2219 if (!newvkofs) {
2220 printf("add_value: failed to allocate value descriptor\n");
2221 free_block(hdesc, newvlist);
2222 return(NULL);
2223 }
2224
2225 nk = (struct nk_key *)(hdesc->buffer + nkofs); /* In case buffer was moved.. */
2226
2227
2228 /* Success, now fill in the metadata */
2229
2230 newvkkey = (struct vk_key *)(hdesc->buffer + newvkofs + 4);
2231
2232 /* Add pointer in value list */
2233 *(int *)(hdesc->buffer + newvlist + 4 + (nk->no_values * 4)) = newvkofs - 0x1000;
2234
2235 /* Fill in vk struct */
2236 newvkkey->id = 0x6b76;
2237 newvkkey->len_name = strlen(name);
2238 if (type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN) {
2239 newvkkey->len_data = 0x80000004; /* Prime the DWORD inline stuff */
2240 } else {
2241 newvkkey->len_data = 0x80000000; /* Default inline zero size */
2242 }
2243 newvkkey->ofs_data = 0;
2244 newvkkey->val_type = type;
2245 newvkkey->flag = newvkkey->len_name ? 1 : 0; /* Seems to be 1, but 0 for no name default value */
2246 newvkkey->dummy1 = 0;
2247 memcpy((char *)&newvkkey->keyname, name, newvkkey->len_name); /* And copy name */
2248
2249 /* Finally update the key and free the old valuelist */
2250 nk->no_values++;
2251 nk->ofs_vallist = newvlist - 0x1000;
2252 if (oldvlist) free_block(hdesc,oldvlist + 0x1000);
2253
2254 return(newvkkey);
2255
2256 }
2257
2258 /* Remove a vk-struct incl dataspace if any
2259 * Mostly for use by higher level stuff
2260 * hdesc - hive
2261 * vkofs - offset to vk
2262 */
2263
del_vk(struct hive * hdesc,int vkofs)2264 void del_vk(struct hive *hdesc, int vkofs)
2265 {
2266 struct vk_key *vk;
2267
2268 vk = (struct vk_key *)(hdesc->buffer + vkofs);
2269 if (vk->id != 0x6b76) {
2270 printf("del_vk: Key pointer not to 'vk' node!\n");
2271 return;
2272 }
2273
2274 if ( !(vk->len_data & 0x80000000) && vk->ofs_data) {
2275 free_val_data(hdesc, vkofs);
2276 }
2277
2278 free_block(hdesc, vkofs - 4);
2279 }
2280
2281 /* Delete all values from key (used in recursive delete)
2282 * hdesc - yer usual hive
2283 * nkofs - current keyoffset
2284 */
2285
del_allvalues(struct hive * hdesc,int nkofs)2286 void del_allvalues(struct hive *hdesc, int nkofs)
2287 {
2288 int vlistofs, o, vkofs;
2289 int32_t *vlistkey;
2290 struct nk_key *nk;
2291
2292 nk = (struct nk_key *)(hdesc->buffer + nkofs);
2293 if (nk->id != 0x6b6e) {
2294 printf("del_allvalues: Key pointer not to 'nk' node!\n");
2295 return;
2296 }
2297
2298 if (!nk->no_values) {
2299 /* printf("del_avalues: Key has no values!\n"); */
2300 return;
2301 }
2302
2303 vlistofs = nk->ofs_vallist + 0x1004;
2304 vlistkey = (int32_t *)(hdesc->buffer + vlistofs);
2305
2306 /* Loop through index and delete all vk's */
2307 for (o = 0; o < nk->no_values; o++) {
2308 vkofs = vlistkey[o] + 0x1004;
2309 del_vk(hdesc, vkofs);
2310 }
2311
2312 /* Then zap the index, and update nk */
2313 free_block(hdesc, vlistofs-4);
2314 nk->ofs_vallist = -1;
2315 nk->no_values = 0;
2316 }
2317
2318
2319 /* Delete single value from key
2320 * hdesc - yer usual hive
2321 * nkofs - current keyoffset
2322 * name - name of value to delete
2323 * exact - NKF_EXACT to do exact match, else first match
2324 * returns: 0 - ok, 1 - failed
2325 */
2326
del_value(struct hive * hdesc,int nkofs,char * name,int exact)2327 int del_value(struct hive *hdesc, int nkofs, char *name, int exact)
2328 {
2329 int vlistofs, slot, o, n, vkofs, newlistofs;
2330 int32_t *vlistkey, *tmplist, *newlistkey;
2331 struct nk_key *nk;
2332 char *blank="";
2333
2334 if (!name || !*name) return(1);
2335
2336 if (!strcmp(name,"@")) name = blank;
2337
2338 nk = (struct nk_key *)(hdesc->buffer + nkofs);
2339 if (nk->id != 0x6b6e) {
2340 printf("del_value: Key pointer not to 'nk' node!\n");
2341 return(1);
2342 }
2343
2344 if (!nk->no_values) {
2345 printf("del_value: Key has no values!\n");
2346 return(1);
2347 }
2348
2349 vlistofs = nk->ofs_vallist + 0x1004;
2350 vlistkey = (int32_t *)(hdesc->buffer + vlistofs);
2351
2352 slot = vlist_find(hdesc, vlistofs, nk->no_values, name, TPF_VK);
2353
2354 if (slot == -1) {
2355 printf("del_value: value %s not found!\n",name);
2356 return(1);
2357 }
2358
2359 /* Delete vk and data */
2360 vkofs = vlistkey[slot] + 0x1004;
2361 del_vk(hdesc, vkofs);
2362
2363 /* Copy out old index list */
2364 CREATE(tmplist,int32_t,nk->no_values);
2365 memcpy(tmplist, vlistkey, nk->no_values * sizeof(int32_t));
2366
2367 free_block(hdesc,vlistofs-4); /* Get rid of old list */
2368
2369 nk->no_values--;
2370
2371 if (nk->no_values) {
2372 newlistofs = alloc_block(hdesc, vlistofs, nk->no_values * sizeof(int32_t));
2373 if (!newlistofs) {
2374 printf("del_value: FATAL: Was not able to alloc new index list\n");
2375 abort();
2376 }
2377 nk = (struct nk_key *)(hdesc->buffer + nkofs); /* In case buffer was moved */
2378
2379 /* Now copy over, omitting deleted entry */
2380 newlistkey = (int32_t *)(hdesc->buffer + newlistofs + 4);
2381 for (n = 0, o = 0; n < nk->no_values; o++, n++) {
2382 if (o == slot) o++;
2383 newlistkey[n] = tmplist[o];
2384 }
2385 nk->ofs_vallist = newlistofs - 0x1000;
2386 } else {
2387 nk->ofs_vallist = -1;
2388 }
2389 return(0);
2390 }
2391
2392
2393
2394
2395 /* Add a subkey to a key
2396 * hdesc - usual..
2397 * nkofs - offset of current nk
2398 * name - name of key to add
2399 * return: ptr to new keystruct, or NULL
2400 */
2401
2402 #undef AKDEBUG
2403
add_key(struct hive * hdesc,int nkofs,char * name)2404 struct nk_key *add_key(struct hive *hdesc, int nkofs, char *name)
2405 {
2406
2407 int slot, newlfofs = 0, oldlfofs = 0, newliofs = 0;
2408 int oldliofs = 0;
2409 int o, n, i, onkofs, newnkofs, cmp;
2410 int rimax, rislot, riofs, namlen;
2411 struct ri_key *ri = NULL;
2412 struct lf_key *newlf = NULL, *oldlf;
2413 struct li_key *newli = NULL, *oldli;
2414 struct nk_key *key, *newnk, *onk;
2415 int32_t hash;
2416
2417 key = (struct nk_key *)(hdesc->buffer + nkofs);
2418
2419 if (key->id != 0x6b6e) {
2420 printf("add_key: current ptr not 'nk'\n");
2421 return(NULL);
2422 }
2423
2424 namlen = strlen(name);
2425
2426 slot = -1;
2427 if (key->no_subkeys) { /* It already has subkeys */
2428
2429 oldlfofs = key->ofs_lf;
2430 oldliofs = key->ofs_lf;
2431
2432 oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2433 if (oldlf->id != 0x666c && oldlf->id != 0x686c && oldlf->id != 0x696c && oldlf->id != 0x6972) {
2434 printf("add_key: index type not supported: 0x%04x\n",oldlf->id);
2435 return(NULL);
2436 }
2437
2438 rimax = 0; ri = NULL; riofs = 0; rislot = -1;
2439 if (oldlf->id == 0x6972) { /* Indirect index 'ri', init loop */
2440 riofs = key->ofs_lf;
2441 ri = (struct ri_key *)(hdesc->buffer + riofs + 0x1004);
2442 rimax = ri->no_lis-1;
2443
2444 #ifdef AKDEBUG
2445 printf("add_key: entering 'ri' traverse, rimax = %d\n",rimax);
2446 #endif
2447
2448 oldliofs = ri->hash[rislot+1].ofs_li;
2449 oldlfofs = ri->hash[rislot+1].ofs_li;
2450
2451 }
2452
2453 do { /* 'ri' loop, at least run once if no 'ri' deep index */
2454
2455 if (ri) { /* Do next 'ri' slot */
2456 rislot++;
2457 oldliofs = ri->hash[rislot].ofs_li;
2458 oldlfofs = ri->hash[rislot].ofs_li;
2459 oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);
2460 oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2461 }
2462
2463 oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);
2464 oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2465
2466 #ifdef AKDEBUG
2467 printf("add_key: top of ri-loop: rislot = %d, rimax = %d\n",rislot,rimax);
2468 #endif
2469 slot = -1;
2470
2471 if (oldli->id == 0x696c) { /* li */
2472
2473 #ifdef AKDEBUG
2474 printf("add_key: li slot allocate\n");
2475 #endif
2476
2477 FREE(newli);
2478 ALLOC(newli, 8 + 4*oldli->no_keys + 4, 1);
2479 newli->no_keys = oldli->no_keys;
2480 newli->id = oldli->id;
2481
2482 /* Now copy old, checking where to insert (alphabetically) */
2483 for (o = 0, n = 0; o < oldli->no_keys; o++,n++) {
2484 onkofs = oldli->hash[o].ofs_nk;
2485 onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
2486 if (slot == -1) {
2487 #if 1
2488 printf("add_key: cmp <%s> with <%s>\n",name,onk->keyname);
2489 #endif
2490
2491 cmp = strn_casecmp(name, onk->keyname, (namlen > onk->len_name) ? namlen : onk->len_name);
2492 if (!cmp) {
2493 printf("add_key: key %s already exists!\n",name);
2494 FREE(newli);
2495 return(NULL);
2496 }
2497 if ( cmp < 0) {
2498 slot = o;
2499 rimax = rislot; /* Cause end of 'ri' search, too */
2500 n++;
2501 #ifdef AKDEBUG
2502 printf("add_key: li-match: slot = %d\n",o);
2503 #endif
2504 }
2505 }
2506 newli->hash[n].ofs_nk = oldli->hash[o].ofs_nk;
2507 }
2508 if (slot == -1) slot = oldli->no_keys;
2509
2510 } else { /* lf or lh */
2511
2512 oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2513
2514 FREE(newlf);
2515 ALLOC(newlf, 8 + 8*oldlf->no_keys + 8, 1);
2516 newlf->no_keys = oldlf->no_keys;
2517 newlf->id = oldlf->id;
2518 #ifdef AKDEBUG
2519 printf("add_key: new lf/lh no_keys: %d\n",newlf->no_keys);
2520 #endif
2521
2522 /* Now copy old, checking where to insert (alphabetically) */
2523 for (o = 0, n = 0; o < oldlf->no_keys; o++,n++) {
2524 onkofs = oldlf->hash[o].ofs_nk;
2525 onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
2526 if (slot == -1) {
2527
2528 #if 0
2529 printf("add_key: cmp <%s> with <%s>\n",name,onk->keyname);
2530 #endif
2531 cmp = strn_casecmp(name, onk->keyname, (namlen > onk->len_name) ? namlen : onk->len_name);
2532 if (!cmp) {
2533 printf("add_key: key %s already exists!\n",name);
2534 FREE(newlf);
2535 return(NULL);
2536 }
2537 if ( cmp < 0 ) {
2538 slot = o;
2539 rimax = rislot; /* Cause end of 'ri' search, too */
2540 n++;
2541 #ifdef AKDEBUG
2542 printf("add_key: lf-match: slot = %d\n",o);
2543 #endif
2544 }
2545 }
2546 newlf->hash[n].ofs_nk = oldlf->hash[o].ofs_nk;
2547 newlf->hash[n].name[0] = oldlf->hash[o].name[0];
2548 newlf->hash[n].name[1] = oldlf->hash[o].name[1];
2549 newlf->hash[n].name[2] = oldlf->hash[o].name[2];
2550 newlf->hash[n].name[3] = oldlf->hash[o].name[3];
2551 }
2552 if (slot == -1) slot = oldlf->no_keys;
2553 } /* li else check */
2554
2555
2556 } while ( (rislot < rimax) && (rimax > 0)); /* 'ri' wrapper loop */
2557
2558 } else { /* Parent was empty, make new index block */
2559 #ifdef AKDEBUG
2560 printf("add_key: new index!\n");
2561 #endif
2562 ALLOC(newlf, 8 + 8, 1);
2563 newlf->no_keys = 0 ; /* Will increment to 1 when filling in the offset later */
2564 /* Use ID (lf, lh or li) we fetched from root node, so we use same as rest of hive */
2565 newlf->id = hdesc->nkindextype;
2566 slot = 0;
2567 } /* if has keys before */
2568
2569
2570 /* Make and fill in new nk */
2571 newnkofs = alloc_block(hdesc, nkofs, sizeof(struct nk_key) + strlen(name));
2572 if (!newnkofs) {
2573 printf("add_key: unable to allocate space for new key descriptor for %s!\n",name);
2574 FREE(newlf);
2575 FREE(newli);
2576 return(NULL);
2577 }
2578 key = (struct nk_key *)(hdesc->buffer + nkofs); /* In case buffer moved */
2579 newnk = (struct nk_key *)(hdesc->buffer + newnkofs + 4);
2580
2581 newnk->id = 0x6b6e;
2582 newnk->type = KEY_NORMAL; /* Some versions use 0x1020 a lot.. */
2583 newnk->ofs_parent = nkofs - 0x1004;
2584 newnk->no_subkeys = 0;
2585 newnk->ofs_lf = -1;
2586 newnk->no_values = 0;
2587 newnk->ofs_vallist = -1;
2588 newnk->ofs_sk = key->ofs_sk; /* Get parents for now. 0 or -1 here crashes XP */
2589 newnk->ofs_classnam = -1;
2590 newnk->len_name = strlen(name);
2591 newnk->len_classnam = 0;
2592 memcpy(newnk->keyname, name, newnk->len_name);
2593
2594 if (newli) { /* Handle li */
2595
2596 #if AKDEBUG
2597 printf("add_key: li fill at slot: %d\n",slot);
2598 #endif
2599
2600 /* And put its offset into parents index list */
2601 newli->hash[slot].ofs_nk = newnkofs - 0x1000;
2602 newli->no_keys++;
2603
2604 /* Allocate space for our new li list and copy it into reg */
2605 newliofs = alloc_block(hdesc, nkofs, 8 + 4*newli->no_keys);
2606 if (!newliofs) {
2607 printf("add_key: unable to allocate space for new index table for %s!\n",name);
2608 FREE(newli);
2609 free_block(hdesc,newnkofs);
2610 return(NULL);
2611 }
2612 key = (struct nk_key *)(hdesc->buffer + nkofs); /* In case buffer moved */
2613 newnk = (struct nk_key *)(hdesc->buffer + newnkofs + 4);
2614
2615 /* memcpy(hdesc->buffer + newliofs + 4, newli, 8 + 4*newli->no_keys); */
2616 fill_block(hdesc, newliofs, newli, 8 + 4*newli->no_keys);
2617
2618
2619 } else { /* lh or lf */
2620
2621 #ifdef AKDEBUG
2622 printf("add_key: lf/lh fill at slot: %d, rislot: %d\n",slot,rislot);
2623 #endif
2624 /* And put its offset into parents index list */
2625 newlf->hash[slot].ofs_nk = newnkofs - 0x1000;
2626 newlf->no_keys++;
2627 if (newlf->id == 0x666c) { /* lf hash */
2628 newlf->hash[slot].name[0] = 0;
2629 newlf->hash[slot].name[1] = 0;
2630 newlf->hash[slot].name[2] = 0;
2631 newlf->hash[slot].name[3] = 0;
2632 strncpy(newlf->hash[slot].name, name, 4);
2633 } else if (newlf->id == 0x686c) { /* lh. XP uses this. hashes whole name */
2634 for (i = 0,hash = 0; i < strlen(name); i++) {
2635 hash *= 37;
2636 hash += reg_touppertable[(unsigned char)name[i]];
2637 }
2638 newlf->lh_hash[slot].hash = hash;
2639 }
2640
2641 /* Allocate space for our new lf list and copy it into reg */
2642 newlfofs = alloc_block(hdesc, nkofs, 8 + 8*newlf->no_keys);
2643 if (!newlfofs) {
2644 printf("add_key: unable to allocate space for new index table for %s!\n",name);
2645 FREE(newlf);
2646 free_block(hdesc,newnkofs);
2647 return(NULL);
2648 }
2649
2650 key = (struct nk_key *)(hdesc->buffer + nkofs); /* In case buffer moved */
2651 newnk = (struct nk_key *)(hdesc->buffer + newnkofs + 4);
2652
2653 /* memcpy(hdesc->buffer + newlfofs + 4, newlf, 8 + 8*newlf->no_keys); */
2654 fill_block(hdesc, newlfofs, newlf, 8 + 8*newlf->no_keys);
2655
2656 } /* li else */
2657
2658
2659 /* Update parent, and free old lf list */
2660 key->no_subkeys++;
2661 if (ri) { /* ri index */
2662 ri->hash[rislot].ofs_li = (newlf ? newlfofs : newliofs) - 0x1000;
2663 } else { /* Parent key */
2664 key->ofs_lf = (newlf ? newlfofs : newliofs) - 0x1000;
2665 }
2666
2667 if (newlf && oldlfofs) free_block(hdesc,oldlfofs + 0x1000);
2668 if (newli && oldliofs) free_block(hdesc,oldliofs + 0x1000);
2669
2670 FREE(newlf);
2671 FREE(newli);
2672 return(newnk);
2673
2674 }
2675
2676 /* Delete a subkey from a key
2677 * hdesc - usual..
2678 * nkofs - offset of current nk
2679 * name - name of key to delete (must match exactly, also case)
2680 * return: 1 - err, 0 - ok
2681 */
2682
2683 #undef DKDEBUG
2684
del_key(struct hive * hdesc,int nkofs,char * name)2685 int del_key(struct hive *hdesc, int nkofs, char *name)
2686 {
2687
2688 int slot = 0, newlfofs = 0, oldlfofs = 0, o, n, onkofs, delnkofs;
2689 int oldliofs = 0, no_keys = 0, newriofs = 0;
2690 int namlen;
2691 int rimax, riofs, rislot;
2692 struct ri_key *ri, *newri = NULL;
2693 struct lf_key *newlf = NULL, *oldlf = NULL;
2694 struct li_key *newli = NULL, *oldli = NULL;
2695 struct nk_key *key, *onk, *delnk;
2696 char fullpath[501];
2697
2698 key = (struct nk_key *)(hdesc->buffer + nkofs);
2699
2700 namlen = strlen(name);
2701
2702 #ifdef DKDEBUG
2703 printf("del_key: deleting: <%s>\n",name);
2704 #endif
2705
2706
2707 if (key->id != 0x6b6e) {
2708 printf("del_key: current ptr not nk\n");
2709 return(1);
2710 }
2711
2712 slot = -1;
2713 if (!key->no_subkeys) {
2714 printf("del_key: key has no subkeys!\n");
2715 return(1);
2716 }
2717
2718 oldlfofs = key->ofs_lf;
2719 oldliofs = key->ofs_lf;
2720
2721 oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2722 if (oldlf->id != 0x666c && oldlf->id != 0x686c && oldlf->id != 0x696c && oldlf->id != 0x6972) {
2723 printf("del_key: index other than 'lf', 'li' or 'lh' not supported yet. 0x%04x\n",oldlf->id);
2724 return(1);
2725 }
2726
2727 rimax = 0; ri = NULL; riofs = 0;
2728 rislot = 0;
2729
2730 if (oldlf->id == 0x6972) { /* Indirect index 'ri', init loop */
2731 riofs = key->ofs_lf;
2732 ri = (struct ri_key *)(hdesc->buffer + riofs + 0x1004);
2733 rimax = ri->no_lis-1;
2734
2735 #ifdef DKDEBUG
2736 printf("del_key: entering 'ri' traverse, rimax = %d\n",rimax);
2737 #endif
2738
2739 rislot = -1; /* Starts at slot 0 below */
2740
2741 }
2742
2743 do { /* 'ri' loop, at least run once if no 'ri' deep index */
2744
2745 if (ri) { /* Do next 'ri' slot */
2746 rislot++;
2747 oldliofs = ri->hash[rislot].ofs_li;
2748 oldlfofs = ri->hash[rislot].ofs_li;
2749 }
2750
2751 oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);
2752 oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2753
2754 #ifdef DKDEBUG
2755 printf("del_key: top of ri-loop: rislot = %d\n",rislot);
2756 #endif
2757 slot = -1;
2758
2759 if (oldlf->id == 0x696c) { /* 'li' handler */
2760 #ifdef DKDEBUG
2761 printf("del_key: li handler\n");
2762 #endif
2763
2764 FREE(newli);
2765 ALLOC(newli, 8 + 4*oldli->no_keys - 4, 1);
2766 newli->no_keys = oldli->no_keys - 1; no_keys = newli->no_keys;
2767 newli->id = oldli->id;
2768
2769 /* Now copy old, checking where to delete */
2770 for (o = 0, n = 0; o < oldli->no_keys; o++,n++) {
2771 onkofs = oldli->hash[o].ofs_nk;
2772 onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
2773 if (slot == -1 && onk->len_name == namlen && !strncmp(name, onk->keyname, (onk->len_name > namlen) ? onk->len_name : namlen)) {
2774 slot = o;
2775 delnkofs = onkofs; delnk = onk;
2776 rimax = rislot;
2777 o++;
2778 }
2779 newli->hash[n].ofs_nk = oldli->hash[o].ofs_nk;
2780 }
2781
2782
2783 } else { /* 'lf' or 'lh' are similar */
2784
2785 #ifdef DKDEBUG
2786 printf("del_key: lf or lh handler\n");
2787 #endif
2788 FREE(newlf);
2789 ALLOC(newlf, 8 + 8*oldlf->no_keys - 8, 1);
2790 #ifdef DKDEBUG
2791 printf("alloc newlf: %x\n",newlf);
2792 #endif
2793 newlf->no_keys = oldlf->no_keys - 1; no_keys = newlf->no_keys;
2794 newlf->id = oldlf->id;
2795
2796 /* Now copy old, checking where to delete */
2797 for (o = 0, n = 0; o < oldlf->no_keys; o++,n++) {
2798
2799 onkofs = oldlf->hash[o].ofs_nk;
2800 onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);
2801
2802 if (slot == -1 && (onk->len_name == namlen) && !strncmp(name, onk->keyname, onk->len_name)) {
2803 slot = o;
2804 delnkofs = onkofs; delnk = onk;
2805 rimax = rislot;
2806 o++;
2807 }
2808
2809 if (n < newlf->no_keys) { /* Only store if not last index in old */
2810 #ifdef DKDEBUG
2811 printf("del_key: n = %d, o = %d\n",n,o);
2812 #endif
2813 newlf->hash[n].ofs_nk = oldlf->hash[o].ofs_nk;
2814 newlf->hash[n].name[0] = oldlf->hash[o].name[0];
2815 newlf->hash[n].name[1] = oldlf->hash[o].name[1];
2816 newlf->hash[n].name[2] = oldlf->hash[o].name[2];
2817 newlf->hash[n].name[3] = oldlf->hash[o].name[3];
2818 }
2819
2820 }
2821 } /* else lh or lf */
2822
2823 } while (rislot < rimax); /* ri traverse loop */
2824
2825 if (slot == -1) {
2826 printf("del_key: subkey %s not found!\n",name);
2827 FREE(newlf);
2828 FREE(newli);
2829 return(1);
2830 }
2831
2832 #ifdef DKDEBUG
2833 printf("del_key: key found at slot %d\n",slot);
2834 #endif
2835
2836 if (delnk->no_values || delnk->no_subkeys) {
2837 printf("del_key: subkey %s has subkeys or values. Not deleted.\n",name);
2838 FREE(newlf);
2839 FREE(newli);
2840 return(1);
2841 }
2842
2843 /* Allocate space for our new lf list and copy it into reg */
2844 if ( no_keys && (newlf || newli) ) {
2845 newlfofs = alloc_block(hdesc, nkofs, 8 + (newlf ? 8 : 4) * no_keys);
2846
2847 /* alloc_block may invalidate pointers if hive expanded. Recalculate this one.
2848 * Thanks to Jacky To for reporting it here, and suggesting a fix
2849 * (better would of course be for me to redesign stuff :)
2850 */
2851 if (delnkofs) delnk = (struct nk_key *)(delnkofs + hdesc->buffer + 0x1004);
2852
2853 #ifdef DKDEBUG
2854 printf("del_key: alloc_block for index returns: %x\n",newlfofs);
2855 #endif
2856 if (!newlfofs) {
2857 printf("del_key: WARNING: unable to allocate space for new key descriptor for %s! Not deleted\n",name);
2858 FREE(newlf);
2859 return(1);
2860 }
2861 key = (struct nk_key *)(hdesc->buffer + nkofs);
2862 oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);
2863 oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2864
2865
2866
2867 /* memcpy(hdesc->buffer + newlfofs + 4,
2868 ((void *)newlf ? (void *)newlf : (void *)newli), 8 + (newlf ? 8 : 4) * no_keys);
2869 */
2870 fill_block(hdesc, newlfofs,
2871 ((void *)newlf ? (void *)newlf : (void *)newli), 8 + (newlf ? 8 : 4) * no_keys);
2872
2873
2874 } else { /* Last deleted, will throw away index */
2875 newlfofs = 0xfff; /* We subtract 0x1000 later */
2876 }
2877
2878 if (newlfofs < 0xfff) {
2879 printf("del_key: ERROR: newlfofs = %x\n",newlfofs);
2880 #if DOCORE
2881 if (hdesc->state & HMODE_TRACE) debugit(hdesc->buffer,hdesc->size);
2882 abort();
2883 #endif
2884 }
2885
2886 /* Check for CLASS data, if so, deallocate it too */
2887 if (delnk->len_classnam) {
2888 free_block(hdesc, delnk->ofs_classnam + 0x1000);
2889 }
2890 /* Now it's safe to zap the nk */
2891 free_block(hdesc, delnkofs + 0x1000);
2892 /* And the old index list */
2893 free_block(hdesc, (oldlfofs ? oldlfofs : oldliofs) + 0x1000);
2894
2895 /* Update parent */
2896 key->no_subkeys--;
2897
2898 key = (struct nk_key *)(hdesc->buffer + nkofs);
2899 oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);
2900 oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2901
2902 if (ri) {
2903 ri = (struct ri_key *)(hdesc->buffer + riofs + 0x1004); /* In case realloc */
2904
2905 if (newlfofs == 0xfff) {
2906
2907 *fullpath = 0;
2908 get_abs_path(hdesc, nkofs, fullpath, 480);
2909
2910 VERBF(hdesc,"del_key: need to delete ri-slot %d for %x - %s\n", rislot,nkofs,fullpath );
2911
2912 if (ri->no_lis > 1) { /* We have subindiceblocks left? */
2913 /* Delete from array */
2914 ALLOC(newri, 8 + 4*ri->no_lis - 4, 1);
2915 newri->no_lis = ri->no_lis - 1;
2916 newri->id = ri->id;
2917 for (o = 0, n = 0; o < ri->no_lis; o++,n++) {
2918 if (n == rislot) o++;
2919 newri->hash[n].ofs_li = ri->hash[o].ofs_li;
2920 }
2921 newriofs = alloc_block(hdesc, nkofs, 8 + newri->no_lis*4 );
2922 if (!newriofs) {
2923 printf("del_key: WARNING: unable to allocate space for ri-index for %s! Not deleted\n",name);
2924 FREE(newlf);
2925 FREE(newri);
2926 return(1);
2927 }
2928 key = (struct nk_key *)(hdesc->buffer + nkofs);
2929 oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);
2930 oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);
2931
2932 fill_block(hdesc, newriofs, newri, 8 + newri->no_lis * 4);
2933 free_block(hdesc, riofs + 0x1000);
2934 key->ofs_lf = newriofs - 0x1000;
2935 FREE(newri);
2936 } else { /* Last entry in ri was deleted, get rid of it, key is empty */
2937 VERB(hdesc,"del_key: .. and that was the last one. key now empty!\n");
2938 free_block(hdesc, riofs + 0x1000);
2939 key->ofs_lf = -1;
2940 }
2941 } else {
2942 ri->hash[rislot].ofs_li = newlfofs - 0x1000;
2943 }
2944 } else {
2945 key->ofs_lf = newlfofs - 0x1000;
2946 }
2947
2948 FREE(newlf);
2949 return(0);
2950
2951 }
2952
2953 /* Recursive delete keys
2954 * hdesc - usual..
2955 * nkofs - offset of current nk
2956 * name - name of key to delete
2957 * return: 0 - ok, 1 fail
2958 */
rdel_keys(struct hive * hdesc,char * path,int vofs)2959 void rdel_keys(struct hive *hdesc, char *path, int vofs)
2960 {
2961 struct nk_key *key;
2962 int nkofs;
2963 struct ex_data ex;
2964 int count = 0, countri = 0;
2965
2966
2967 if (!path || !*path) return;
2968
2969 nkofs = trav_path(hdesc, vofs, path, TPF_NK_EXACT);
2970
2971 if(!nkofs) {
2972 printf("rdel_keys: Key <%s> not found\n",path);
2973 return;
2974 }
2975 nkofs += 4;
2976
2977 key = (struct nk_key *)(hdesc->buffer + nkofs);
2978
2979 /*
2980 VERBF(hdesc,"rdel of node at offset 0x%0x\n",nkofs);
2981 */
2982
2983 if (key->id != 0x6b6e) {
2984 printf("rdel_keys: ERROR: Not a 'nk' node!\n");
2985
2986 if (hdesc->state & HMODE_TRACE) debugit(hdesc->buffer,hdesc->size);
2987 return;
2988 }
2989
2990 #if 0
2991 printf("Node has %d subkeys and %d values\n",key->no_subkeys,key->no_values);
2992 #endif
2993 if (key->no_subkeys) {
2994 while ((ex_next_n(hdesc, nkofs, &count, &countri, &ex) > 0)) {
2995 #if 0
2996 printf("%s\n",ex.name);
2997 #endif
2998 rdel_keys(hdesc, ex.name, nkofs);
2999 count = 0;
3000 countri = 0;
3001 FREE(ex.name);
3002 }
3003 }
3004
3005 del_allvalues(hdesc, nkofs);
3006 key = (struct nk_key *)(hdesc->buffer + nkofs);
3007 del_key(hdesc, key->ofs_parent+0x1004, path);
3008
3009 }
3010
3011
3012 /* Get and copy keys CLASS-data (if any) to buffer
3013 * Returns a buffer with the data (first int32_t is size). see ntreg.h
3014 * NOTE: caller must deallocate buffer! a simple free(keyval) will suffice.
3015 */
get_class(struct hive * hdesc,int curnk,char * path)3016 struct keyval *get_class(struct hive *hdesc,
3017 int curnk, char *path)
3018 {
3019 int clen = 0, dofs = 0, nkofs;
3020 struct nk_key *key;
3021 struct keyval *data;
3022 void *classdata;
3023
3024 if (!path && !curnk) return(NULL);
3025
3026 nkofs = trav_path(hdesc, curnk, path, 0);
3027
3028 if(!nkofs) {
3029 printf("get_class: Key <%s> not found\n",path);
3030 return(NULL);
3031 }
3032 nkofs += 4;
3033 key = (struct nk_key *)(hdesc->buffer + nkofs);
3034
3035 clen = key->len_classnam;
3036 if (!clen) {
3037 printf("get_class: Key has no class data.\n");
3038 return(NULL);
3039 }
3040
3041 dofs = key->ofs_classnam;
3042 classdata = (void *)(hdesc->buffer + dofs + 0x1004);
3043
3044 #if 0
3045 printf("get_class: len_classnam = %d\n",clen);
3046 printf("get_class: ofs_classnam = 0x%x\n",dofs);
3047 #endif
3048
3049 ALLOC(data, sizeof(struct keyval) + clen,1);
3050 data->len = clen;
3051 memcpy(&data->data, classdata, clen);
3052 return(data);
3053 }
3054
3055
3056 /* Write to registry value.
3057 * If same size as existing, copy back in place to avoid changing too much
3058 * otherwise allocate new dataspace, then free the old
3059 * Thus enough space to hold both new and old data is needed
3060 * Pass inn buffer with data len as first DWORD (as routines above)
3061 * returns: 0 - error, len - OK (len of data)
3062 */
3063
put_buf2val(struct hive * hdesc,struct keyval * kv,int vofs,char * path,int type,int exact)3064 int put_buf2val(struct hive *hdesc, struct keyval *kv,
3065 int vofs, char *path, int type, int exact )
3066 {
3067 int l;
3068 void *keydataptr, *addr;
3069 struct db_key *db;
3070 int copylen, blockofs, blocksize, restlen, point, i, list, parts;
3071
3072 if (!kv) return(0);
3073
3074
3075 l = get_val_len(hdesc, vofs, path, exact);
3076 if (l == -1) return(0); /* error */
3077 // printf("put_buf2val: l = %d\n",l);
3078
3079 // printf("put_buf2val: %s, kv len = %d, l = %d\n",path,kv->len,l);
3080
3081
3082 if (kv->len != l) { /* Realloc data block if not same size as existing */
3083 if (!alloc_val_data(hdesc, vofs, path, kv->len, exact)) {
3084 printf("put_buf2val: %s : alloc_val_data failed!\n",path);
3085 return(0);
3086 }
3087 }
3088
3089 keydataptr = get_val_data(hdesc, vofs, path, type, exact);
3090 if (!keydataptr) {
3091 printf("put_buf2val: %s : get_val_data failed!\n",path);
3092 return(0); /* error */
3093 }
3094
3095
3096
3097 if (kv->len > VAL_DIRECT_LIMIT) { /* Where do the db indirects start? seems to be around 16k */
3098 db = (struct db_key *)keydataptr;
3099 if (db->id != 0x6264) abort();
3100 parts = db->no_part;
3101 list = db->ofs_data + 0x1004;
3102 printf("put_buf2val: Long value: parts = %d, list = %x\n",parts,list);
3103
3104 point = 0;
3105 restlen = kv->len;
3106 for (i = 0; i < parts; i++) {
3107 blockofs = get_int(hdesc->buffer + list + (i << 2)) + 0x1000;
3108 blocksize = -get_int(hdesc->buffer + blockofs) - 8;
3109
3110 /* Copy this part, up to size of block or rest lenght in last block */
3111 copylen = (blocksize > restlen) ? restlen : blocksize;
3112
3113 printf("put_buf2val: Datablock %d offset %x, size %x (%d)\n",i,blockofs,blocksize,blocksize);
3114 printf(" : Point = %x, restlen = %x, copylen = %x\n",point,restlen,copylen);
3115
3116 addr = (void *)&(kv->data) + point;
3117 fill_block( hdesc, blockofs, addr, copylen);
3118
3119 // debugit((char *)&(kr->data), l);
3120
3121 point += copylen;
3122 restlen -= copylen;
3123 }
3124 } else {
3125 memcpy(keydataptr, &kv->data, kv->len);
3126 }
3127
3128 hdesc->state |= HMODE_DIRTY;
3129
3130 return(kv->len);
3131 }
3132
3133 /* And, yer basic DWORD write */
3134
put_dword(struct hive * hdesc,int vofs,char * path,int exact,int dword)3135 int put_dword(struct hive *hdesc, int vofs, char *path, int exact, int dword)
3136 {
3137 struct keyval *kr;
3138 int r;
3139
3140 ALLOC(kr,1,sizeof(int)+sizeof(int));
3141
3142 kr->len = sizeof(int);
3143 kr->data = dword;
3144
3145 r = put_buf2val(hdesc, kr, vofs, path, REG_DWORD, exact);
3146
3147 FREE(kr);
3148
3149 return(r);
3150 }
3151
3152 /* ================================================================ */
3153
3154 /* Code to export registry entries to .reg file initiated by
3155 * Leo von Klenze
3156 * Then expanded a bit to handle more types etc.
3157 */
3158
3159 /*
3160 * converts a value string from an registry entry into a c string. It does not
3161 * use any encoding functions.
3162 * It works very primitive by just taking every second char.
3163 * The caller must free the resulting string, that was allocated with malloc.
3164 *
3165 * string: string where every second char is \0
3166 * len: length of the string
3167 * return: the converted string as char*
3168 */
3169 char *
string_regw2prog(void * string,int len)3170 string_regw2prog(void *string, int len)
3171 {
3172 int i, k;
3173 char *cstring;
3174
3175 int out_len = 0;
3176 for(i = 0; i < len; i += 2)
3177 {
3178 unsigned v = ((unsigned char *)string)[i] + ((unsigned char *)string)[i+1] * 256u;
3179 if (v < 128)
3180 out_len += 1;
3181 else if(v < 0x800)
3182 out_len += 2;
3183 else
3184 out_len += 3;
3185 }
3186 CREATE(cstring,char,out_len+1);
3187
3188 for(i = 0, k = 0; i < len; i += 2)
3189 {
3190 unsigned v = ((unsigned char *)string)[i] + ((unsigned char *)string)[i+1] * 256u;
3191 if (v < 128)
3192 cstring[k++] = v;
3193 else if(v < 0x800) {
3194 cstring[k++] = 0xc0 | (v >> 6);
3195 cstring[k++] = 0x80 | (v & 0x3f);
3196 } else {
3197 cstring[k++] = 0xe0 | (v >> 12);
3198 cstring[k++] = 0x80 | ((v >> 6) & 0x3f);
3199 cstring[k++] = 0x80 | (v & 0x3f);
3200 }
3201 }
3202 cstring[out_len] = '\0';
3203
3204 return cstring;
3205 }
3206
3207 #if 0 // Not used at the moment
3208 static char *
3209 string_rega2prog(void *string, int len)
3210 {
3211 int i, k;
3212 char *cstring;
3213
3214 int out_len = 0;
3215 for(i = 0; i < len; ++i)
3216 {
3217 unsigned v = ((unsigned char *)string)[i];
3218 if (v < 128)
3219 out_len += 1;
3220 else
3221 out_len += 2;
3222 }
3223 CREATE(cstring,char,out_len+1);
3224
3225 for(i = 0, k = 0; i < len; ++i)
3226 {
3227 unsigned v = ((unsigned char *)string)[i];
3228 if (v < 128)
3229 cstring[k++] = v;
3230 else {
3231 cstring[k++] = 0xc0 | (v >> 6);
3232 cstring[k++] = 0x80 | (v & 0x3f);
3233 }
3234 }
3235 cstring[out_len] = '\0';
3236
3237 return cstring;
3238 }
3239
3240 static void
3241 string_prog2rega(char *string, int len)
3242 {
3243 char *out = string;
3244 unsigned char *in = (unsigned char*) string;
3245
3246 for (;*in; ++in) {
3247 if (!(*in & 0x80)) {
3248 *out++ = *in;
3249 } else if ((in[0] & 0xe0) == 0xc0 && in[1]) {
3250 *out++ = (in[0] & 0x1f) << 6 | (in[1] & 0x3f);
3251 ++in;
3252 } else if (in[1] && in[2]) {
3253 /* assume 3 byte*/
3254 *out++ = (in[1] & 0xf) << 6 | (in[2] & 0x3f);
3255 in += 2;
3256 }
3257 }
3258 *out = 0;
3259 }
3260 #endif // Not used
3261
3262
3263 static char *
string_prog2regw(void * string,int len,int * out_len)3264 string_prog2regw(void *string, int len, int *out_len)
3265 {
3266 unsigned char *regw = (unsigned char*) malloc(len*2+2);
3267 unsigned char *out = regw;
3268 unsigned char *in = (unsigned char*) string;
3269
3270 for (;len>0; ++in, --len) {
3271 if (!(in[0] & 0x80)) {
3272 *out++ = *in;
3273 *out++ = 0;
3274 } else if ((in[0] & 0xe0) == 0xc0 && len >= 2) {
3275 *out++ = (in[0] & 0x1f) << 6 | (in[1] & 0x3f);
3276 *out++ = (in[0] & 0x1f) >> 2;
3277 ++in, --len;
3278 } else if (len >= 3) {
3279 /* assume 3 byte*/
3280 *out++ = (in[1] & 0xf) << 6 | (in[2] & 0x3f);
3281 *out++ = (in[0] & 0xf) << 4 | ((in[1] & 0x3f) >> 2);
3282 in += 2;
3283 len -= 2;
3284 }
3285 }
3286 *out_len = out - regw;
3287 out[0] = out[1] = 0;
3288 return (char *) regw;
3289 }
3290
3291 static char *
quote_string(const char * s)3292 quote_string(const char *s)
3293 {
3294 int len = strlen(s);
3295 const char *p;
3296 char *dst, *out;
3297
3298 for (p = s; *p; ++p)
3299 if (*p == '\\' || *p == '\"')
3300 ++len;
3301
3302 dst = out = (char*) malloc(len + 1);
3303 for (p = s; *p; ++p) {
3304 if (*p == '\\' || *p == '\"')
3305 *dst++ = '\\';
3306 *dst++ = *p;
3307 }
3308 *dst = 0;
3309 return out;
3310 }
3311
3312 static void
export_bin(int type,char * value,int len,int col,FILE * file)3313 export_bin(int type, char *value, int len, int col, FILE* file)
3314 {
3315 int byte;
3316
3317 if (type == REG_BINARY) {
3318 fprintf(file, "hex:");
3319 col += 4;
3320 } else {
3321 fprintf(file, "hex(%x):", type);
3322 col += 7;
3323 }
3324 byte = 0;
3325 int start = (col - 2) / 3;
3326 while (byte + 1 < len) { /* go byte by byte.. probably slow.. */
3327 fprintf(file, "%02x,", (unsigned char)value[byte]);
3328 byte++;
3329 if (!((byte + start) % 25)) fprintf(file, "\\\r\n ");
3330 }
3331 if (len)
3332 fprintf(file, "%02x\r\n", (unsigned char)value[len - 1]);
3333 }
3334
3335 /*
3336 * Exports the named subkey and its values to the given file.
3337 *
3338 * hdesc: registry hive
3339 * nkofs: offset of parent node
3340 * name: name of key to export
3341 * prefix: prefix for each key. This prefix is prepended to the keyname
3342 * file: file descriptor of destination file
3343 */
export_subkey(struct hive * hdesc,int nkofs,char * name,char * prefix,FILE * file)3344 void export_subkey(struct hive *hdesc, int nkofs, char *name, char *prefix, FILE *file)
3345 {
3346 int newofs;
3347 int count = 0;
3348 int countri = 0;
3349 int len;
3350 char *path = (char*) malloc(1024);
3351 char *value;
3352 struct nk_key *key;
3353 struct ex_data ex;
3354 struct vex_data vex;
3355
3356
3357 // switch to key
3358 newofs = trav_path(hdesc, nkofs, name, TPF_NK_EXACT);
3359 if(!newofs)
3360 {
3361 printf("export_subkey: Key '%s' not found!\n", name);
3362 free(path);
3363 return;
3364 }
3365 nkofs = newofs + 4;
3366
3367 // get the key
3368 key = (struct nk_key *)(hdesc->buffer + nkofs);
3369 printf("Exporting key '%.*s' with %d subkeys and %d values...\n",
3370 key->len_name, key->keyname, key->no_subkeys, key->no_values);
3371
3372 *path = 0;
3373 get_abs_path(hdesc, nkofs, path, 1024);
3374
3375 // export the key
3376 fprintf(file, "\r\n");
3377 fprintf(file, "[%s\%s]\r\n", prefix, path);
3378 // export values
3379 if(key->no_values)
3380 {
3381 while ((ex_next_v(hdesc, nkofs, &count, &vex) > 0))
3382 {
3383 int col = 0;
3384 char *name = quote_string(vex.name);
3385
3386 /* print name */
3387 if (!name[0]) {
3388 fprintf(file, "@=");
3389 free(name);
3390 name = str_dup("@");
3391 col += 2;
3392 } else {
3393 fprintf(file, "\"%s\"=", name);
3394 col += strlen(name) + 3;
3395 }
3396
3397 if(vex.type == REG_DWORD)
3398 {
3399 fprintf(file, "dword:%08x\r\n", vex.val);
3400 }
3401 else if(vex.type == REG_SZ)
3402 {
3403 char *val, *quoted;
3404 value = (char *)get_val_data(hdesc, nkofs, name, vex.type, TPF_VK_EXACT|TPF_ABS);
3405 len = get_val_len(hdesc, nkofs, name, TPF_VK_EXACT|TPF_ABS);
3406
3407 val = string_regw2prog(value, len);
3408 /* dump as binary if invalid characters are embedded */
3409 if (strchr(val, 0xa) || strchr(val, 0xd))
3410 {
3411 free(val);
3412 //if (len >= 2 && value[len-2] == 0 && value[len-1] == 0) len -= 2;
3413 export_bin(vex.type, value, len, col, file);
3414 }
3415 else
3416 {
3417 quoted = quote_string(val);
3418 free(val);
3419 fprintf(file, "\"%s\"", quoted);
3420 free(quoted);
3421 fprintf(file, "\r\n");
3422 }
3423 }
3424 else
3425 {
3426 /* All other types seems to simply be hexdumped. Format is:
3427 "valuename"=hex(typenum):xx,xx,xx,xx,xx...
3428 for example:
3429 "qword64"=hex(b):4e,03,51,db,fa,04,00,00
3430 this is type = 0xb = 11 = REG_QWORD
3431 "expandstring"=hex(2):46,00,6f,00,6f,00,62,00,61,00,72,00,20,00,25,00,73,00,20,\
3432 00,42,00,61,00,7a,00,00,00
3433 this is type 2 = REG_EXPAND_SZ and the line is continued with ,\<CR><LF><space><space>
3434 don't know how many bytes for each line. Around 18-24 seems to be it?? depends on name lenght??
3435 NOTE: Exception:
3436 type = REG_BINARY starts like this: "valuename"=hex:xx,xx,xx...
3437 */
3438 value = (char *)get_val_data(hdesc, nkofs, name, vex.type, TPF_VK_EXACT|TPF_ABS);
3439 len = get_val_len(hdesc, nkofs, name, TPF_VK_EXACT|TPF_ABS);
3440
3441 export_bin(vex.type, value, len, col, file);
3442 }
3443
3444 FREE(vex.name);
3445 free(name);
3446 }
3447 }
3448
3449 // export subkeys
3450 if (key->no_subkeys)
3451 {
3452 count = 0;
3453 countri = 0;
3454 while ((ex_next_n(hdesc, nkofs, &count, &countri, &ex) > 0))
3455 {
3456 export_subkey(hdesc, nkofs, ex.name, prefix, file);
3457 FREE(ex.name);
3458 }
3459 }
3460 free(path);
3461 }
3462
3463 /*
3464 * Exports the given key to a windows .reg file that can be imported to the
3465 * windows registry.
3466 * The prefix is used to determine the destination hive in the windows
3467 * registry, set it to HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE or whatever you
3468 * want.
3469 *
3470 * hdesc: hive
3471 * nkofs: offset of parent node
3472 * name: name of subkey to export
3473 * filename: name of destination .reg file (will be overridden)
3474 * prefix: prefix for each exported key
3475 */
export_key(struct hive * hdesc,int nkofs,char * name,char * filename,char * prefix)3476 void export_key(struct hive *hdesc, int nkofs, char *name, char *filename, char *prefix)
3477 {
3478 FILE *file;
3479
3480 // open file
3481 file = fopen(filename, "w");
3482 if(!file)
3483 {
3484 printf("export: Cannot open file '%s'. %s (%d).\n", filename, strerror(errno),
3485 errno);
3486 return;
3487 }
3488
3489 printf("Exporting to file '%s'...\n", filename);
3490 fprintf(file, "Windows Registry Editor Version 5.00\r\n");
3491 export_subkey(hdesc, nkofs, name, prefix, file);
3492
3493 fprintf(file,"\r\n"); /* Must end file with an empty line, windows does that */
3494
3495 fclose(file);
3496 }
3497
3498 /* ================================================================ */
3499
3500 /* Import from .reg file routines */
3501
3502 #define MAXLINE 20000
3503
3504 /* Wide character fgetsw() may not be available on all small libraries..
3505 * so.. roll our own fgets() that handles wide if needed
3506 */
3507
my_fgets(char * s,char * w,int max,FILE * file,int wide)3508 char *my_fgets(char *s, char *w, int max, FILE *file, int wide)
3509 {
3510
3511 int i = 0;
3512 char prev = 1;
3513 char c = 1;
3514
3515
3516 while (c != '\n' && !feof(file) && max) {
3517 c = (char)fgetc(file);
3518 /* printf("char = %c\n",c); */
3519 if (!c && (!prev && !wide) ) break; /* Stop on 1 (or 2 if wide) null */
3520 prev = c;
3521 if (c != '\r') {
3522 *(s+i) = c;
3523 *(w+i) = c;
3524 i++;
3525 }
3526 max--;
3527 }
3528 *(s+i) = 0;
3529 *(s+i+1) = 0;
3530 *(w+i) = 0;
3531 *(w+i+1) = 0;
3532
3533 if (wide) { /* Convert to C string, de widing it.. */
3534 cheap_uni2ascii(w, s, i);
3535 // printf("cheap returns len = %d : %s\n",strlen(s), s);
3536
3537 fgetc(file); /* Skip second byte of CR/LF termination */
3538 }
3539
3540 // printf("my_fgets returning :\n");
3541 //hexdump(w, 0, i, 1);
3542 //printf("====== hexdump end\n");
3543 return(s);
3544
3545 }
3546
3547
3548 /* Read one line, while skipping blank lines, also checks for =
3549 * line = line buffer
3550 * file = you know..
3551 * assigner - left part of value assignemt (before =)
3552 * value - right part of assignment (after =)
3553 * value = NULL if [KEY] line.
3554 * assigner = NULL if value continuation line
3555 * Returns total lenght of line
3556 */
3557
3558
3559 #undef GETLINE_DEBUG
3560
get_line(char s[],char w[],FILE * file,char ** assigner,char ** value,int wide)3561 int get_line(char s[], char w[], FILE *file, char **assigner, char **value, int wide)
3562 {
3563 int l,q;
3564 char *b; /* Start of line after spaces */
3565 char *c;
3566
3567 *assigner = NULL;
3568 *value = NULL;
3569
3570 do {
3571
3572 s[0] = 0;
3573 my_fgets(s, w, MAXLINE, file, wide);
3574 s[MAXLINE] = 0;
3575 b = s;
3576
3577 l = strlen(s);
3578
3579 #ifdef GETLINE_DEBUG
3580 printf("get_line: read line len %d : %s\n",l,s);
3581 #endif
3582
3583 if (l == 0) {
3584 if (feof(file)) return 0;
3585 break;
3586 }
3587
3588 while (isspace(*b)) b++;
3589 c = b;
3590 while (*c && *c != '\n' && *c != '\r') c++;
3591 *c = 0; /* Terminate with null not cr/lf */
3592
3593
3594 if (!*b) continue; /* Blank line */
3595
3596 l = strlen(s);
3597
3598 #ifdef GETLINE_DEBUG
3599 printf("get_line: stripped line len %d : %s\n",l,s);
3600 #endif
3601
3602
3603 c = b;
3604
3605 if (*b == '[') { /* Key line starts with [ */
3606 #ifdef GETLINE_DEBUG
3607 printf("get_line: key line..\n");
3608 #endif
3609 while (*c && (*c != ']')) c++;
3610 if (!*c) {
3611 printf("get_line: WARNING: un-terminated key line..\n");
3612 }
3613 *c = 0;
3614 *assigner = b+1;
3615 *value = NULL;
3616 return(l);
3617 }
3618
3619 q = 0;
3620 while (*c) {
3621 /* printf(" char = %c : q = %d\n",*c,q); */
3622 if (*c == '"') q ^= 1; /* Flip quote indicator */
3623 if (*c == '=' && !q) { /* Found = outside quotes */
3624 *c = 0;
3625 *assigner = b;
3626 *value = c + 1;
3627 #ifdef GETLINE_DEBUG
3628 printf("get_line: value line\n");
3629 #endif
3630 return(l);
3631 }
3632 c++;
3633 }
3634 /* At this point we don't have a = outside quotes, so probably a value cont line */
3635 *assigner = NULL;
3636 *value = b;
3637 #ifdef GETLINE_DEBUG
3638 printf("get_line: cont line\n");
3639 #endif
3640 return(l);
3641
3642 } while (!feof(file));
3643
3644 return(l);
3645 }
3646
3647
3648 /* Wide strlen */
wide_strlen(char * s)3649 int wide_strlen(char *s)
3650 {
3651
3652 int l = 0;
3653
3654 while ( *(s+l) || *(s+l+1) ) l += 2;
3655
3656 return(l);
3657
3658 }
3659
3660
3661
3662 /* De-quote a string (removing quotes first and last)
3663 * Does nothing if no quoutes
3664 * String MUST be null-terminated
3665 */
3666
dequote(char * s)3667 char *dequote(char *s)
3668 {
3669 int l;
3670
3671 if (*s != '"') return(s); /* No first quote, then don't change anything, even at end */
3672
3673 l = strlen(s);
3674
3675 if ( *(s+l-1) == '"' ) {
3676 *(s+l-1) = 0;
3677 }
3678
3679 return(s+1);
3680 }
3681
3682 /* de-escape a string, handling \ backslash
3683 * s = string buffer, WILL BE CHANGED
3684 * wide = true to make it handle wide characters
3685 * returns new lenght
3686 */
3687
de_escape(char * s,int wide)3688 int de_escape(char *s, int wide)
3689 {
3690 int src = 0;
3691 int dst = 0;
3692
3693 if (wide) {
3694 while ( *(s + src) || *(s + src +1)) {
3695 if ( *(s + src) == '\\' && *(s + src + 1) == 0) src += 2; /* Skip over backslash */
3696 *(s + dst) = *(s + src);
3697 *(s + dst + 1) = *(s + src + 1);
3698 dst += 2;
3699 src += 2;
3700 }
3701 *(s + dst) = 0;
3702 *(s + dst + 1) = 0;
3703 dst += 2;
3704 } else {
3705 while ( *(s + src) ) {
3706 if ( *(s + src) == '\\' ) src++;
3707 *(s + dst) = *(s + src);
3708 dst++;
3709 src++;
3710 }
3711 *(s + dst) = 0;
3712 dst++;
3713 }
3714
3715 return(dst);
3716 }
3717
3718
3719
3720
3721 /* Parse the value to be assigned
3722 * s = string to parse
3723 * bufptr = pointer to buffer pointer for binary data (will be allocated).
3724 * First byte of buffer is value type.
3725 * returns lenght
3726 *
3727 "stringvalue"="this is a string"
3728 "binaryvalue"=hex:11,22,33,aa,bb,cc,12,34,01,02,ab,cd,ef,be,ef
3729 "dwordvalue"=dword:12345678
3730 "qwordvalue"=hex(b):ef,cd,ab,89,67,45,23,01
3731 "multistringvalue"=hex(7):73,00,74,00,72,00,69,00,6e,00,67,00,20,00,31,00,00,\
3732 00,73,00,74,00,72,00,69,00,6e,00,67,00,20,00,32,00,00,00,73,00,74,00,72,00,\
3733 69,00,6e,00,67,00,20,00,33,00,00,00,00,00
3734 "expstringvalue"=hex(2):73,00,74,00,72,00,69,00,6e,00,67,00,20,00,77,00,69,00,\
3735 74,00,68,00,20,00,25,00,73,00,20,00,65,00,78,00,70,00,61,00,6e,00,73,00,69,\
3736 00,6f,00,6e,00,00,00
3737 *
3738 */
3739
parse_valuestring(char * s,char * w,int len,int wide,struct keyval ** kvptr)3740 int parse_valuestring(char *s, char *w, int len, int wide, struct keyval **kvptr)
3741 {
3742 unsigned int dword;
3743 int type = -1;
3744 int i;
3745 int quote;
3746 int strstart;
3747 uint8_t byte;
3748 uint8_t *array;
3749 char *widebuf = NULL;
3750 struct keyval *kv = NULL;
3751
3752
3753 // printf("parse_val: input string: <%s>\n",s);
3754
3755 if (!strncmp(s,"dword",4)) { /* DWORD */
3756 sscanf(s,"dword:%x",&dword);
3757 // printf("parse_vals: dword is %x\n",dword);
3758 type = REG_DWORD;
3759 len = 4;
3760 ALLOC(kv,1,len + 8);
3761 kv->data = dword;
3762
3763 } else if (!strncmp(s,"hex",3)) { /* Hex string */
3764 if (!sscanf(s,"hex(%x):",&type)) type = REG_BINARY;
3765
3766 // printf("parse_vals: hex type is %d\n",type);
3767
3768 while (*s && *s != ':') s++; /* Move up to : */
3769 s++;
3770 len = strlen(s);
3771 if (len > 0) len = len / 3 + 1; /* 3 characters per byte */
3772
3773 // printf("parse_vals: hex byte count %d\n", len);
3774
3775 ALLOC(kv,1,len + 8);
3776 array = (uint8_t *)&kv->data;
3777
3778 for (i = 0; i < len; i++) {
3779 if (!sscanf(s,"%hhx",&byte)) {
3780 fprintf(stderr,"parse_values: hex string parse error: %s\n",s);
3781 abort();
3782 }
3783 // printf("parse_vals: adding byte: %02x\n",byte);
3784 *(array+i) = byte;
3785 s += 3;
3786 }
3787
3788 } else { /* Assume it simply is a string */
3789 type = REG_SZ;
3790
3791 if (wide) { /* File is wide, find string limits and de-escape it, then copy in as wide */
3792
3793 quote = 0;
3794 i = 0;
3795 strstart = 0;
3796 while ( *(w+i) ) {
3797 if ( *(w+i) == '"' && *(w+i+1) == 0) quote ^= 1;
3798 if (!quote && !strstart && ( *(w+i) == '=' && *(w+i+1) == 0) ) {
3799 strstart = i + 4; /* Skip past start quote */
3800 }
3801 i += 2;
3802 }
3803 if ( *(w+i-2) == '"' && *(w+i-1) == 0) { /* Remove end quoute */
3804 *(w+i-2) = 0;
3805 *(w+i-1) = 0;
3806 i -= 2;
3807 }
3808 i += 2;
3809
3810
3811 // hexdump(w+strstart,0,i-strstart,1);
3812
3813 len = de_escape(w + strstart, wide);
3814
3815 // hexdump(w+strstart,0,len,1);
3816
3817 // printf("wide string: i = %d, strstart = %d, len = %d\n",i,strstart,len);
3818
3819 ALLOC(kv,1,len + 8);
3820
3821 memcpy(&kv->data,w + strstart, len);
3822
3823 } else { /* File is not wide, so we must widen string before putting into registry */
3824
3825 len = strlen(s);
3826 // printf("parse_vals: len %d string <%s>\n",len,s);
3827 len = de_escape(s, 0);
3828 // printf("parse_vals: after de-escape len %d string <%s>\n",len,s);
3829
3830 widebuf = string_prog2regw(s, strlen(s), &len);
3831 len += 2; /* Also store the terminating NULLs */
3832 // printf("parse_vals: len after wide expansion: %d\n",len);
3833
3834 ALLOC(kv,1,len + 8);
3835 memcpy(&kv->data,widebuf,len);
3836
3837 FREE(widebuf);
3838 }
3839
3840
3841 }
3842
3843 if (kv) {
3844 kv->len = len;
3845 *kvptr = kv;
3846 }
3847
3848 return(type);
3849
3850 }
3851
3852
3853
3854
3855 /* Main import routine
3856 * Only reading into one hive at a time supported.
3857 * Will support 8 bit or 16 bit (wide) character .reg file.
3858 * Windows regedit.exe usually generates 16 bit.
3859 * NOTE: Not a lot of sanity checking, a broken input file may end in strange behaviour or corrupt registry!
3860 * hdesc - Loaded hive
3861 * filename - (path)name of .reg file to read
3862 * prefix - HKEY_
3863 */
3864
import_reg(struct hive * hdesc,char * filename,char * prefix)3865 void import_reg(struct hive *hdesc, char *filename, char *prefix)
3866 {
3867
3868 FILE *file;
3869 char line[MAXLINE+2];
3870 char wline[MAXLINE+2]; /* Wide buffer */
3871 int l, plen;
3872 char *assigner = NULL;
3873 char *value = NULL;
3874 int wide = 0;
3875 int c,wl;
3876 // void *valbuf;
3877 char *valname = NULL;
3878 char *plainname = NULL;
3879 char *valstr, *key, *walstr = NULL;
3880 int nk, prevnk; /* offsets to nk */
3881 int type,oldtype;
3882 struct keyval *valbinbuf = NULL;
3883 int numkeys = 0;
3884 int numkeyadd = 0;
3885 int numtotvals = 0;
3886 int numkeyvals = 0;
3887 int bailout = 0;
3888
3889 plen = strlen(prefix);
3890
3891 file = fopen(filename, "r");
3892 if(!file)
3893 {
3894 fprintf(stderr,"import_reg: Cannot open file '%s'. %s (%d).\n", filename, strerror(errno),
3895 errno);
3896 return;
3897 }
3898
3899 c = fgetc(file);
3900
3901 if (c == 0xff) { /* Wide characters file */
3902 fprintf(stderr,"import_reg: WARNING: Wide character (16 bit) file..\n"
3903 "import_reg: WARNING: Implementation is not 100%% accurate, some things may not import correctly!\n");
3904 c = fgetc(file); /* Get second wide indicator character */
3905 wide = 1;
3906 } else {
3907 ungetc(c, file);
3908 }
3909
3910 line[0] = 0;
3911 my_fgets(line, wline, MAXLINE, file, wide);
3912 line[MAXLINE] = 0;
3913
3914
3915 if (strncmp("Windows Registry Editor",line,23)) {
3916 fprintf(stderr,"import_reg: ERROR: Windows Registry Editor signature missing on first line\n");
3917 fclose(file);
3918 return;
3919 }
3920
3921 do {
3922
3923 l = get_line(line, wline, file, &assigner, &value, wide);
3924
3925 if (!feof(file) && !assigner && value) {
3926 // printf("import_reg: value continuation line: %s\n",value);
3927 l = strlen(value);
3928 if ( *(value+l-1) == '\\' ) { /* Strip off cont character */
3929 *(value+l-1) = 0;
3930 l--;
3931 }
3932 value = dequote(value);
3933 l = strlen(value);
3934 valstr = realloc(valstr, strlen(valstr) + l + 3);
3935 if (valstr == NULL) {
3936 perror("import_reg: realloc(valstr)");
3937 abort();
3938 }
3939 strcat(valstr, value);
3940 // printf("import_reg: build value string: %s\n",valstr);
3941 if (wide) {
3942 wl = wide_strlen(wline);
3943 walstr = realloc(walstr, wide_strlen(walstr) + wl + 4);
3944 if (walstr == NULL) {
3945 perror("import_reg: realloc(valstr)");
3946 abort();
3947 }
3948 memcpy(walstr + wl, wline, wl);
3949 }
3950
3951
3952
3953 } else { /* End continuation, store built up value */
3954 if (valname) {
3955 // printf("import_reg: end of value %s, result string: %s\n\n",valname,valstr);
3956
3957 type = parse_valuestring(valstr, walstr, l, wide, &valbinbuf);
3958
3959 // printf("import_reg: got value type = %d\n",type);
3960 // printf("import_reg: data lenght = %d\n",(*valbinbuf).len);
3961
3962 VERBF(hdesc," Value <%s> of type %d length %d",valname,type,(*valbinbuf).len);
3963
3964 oldtype = get_val_type(hdesc, nk + 4, valname, TPF_VK_ABS|TPF_EXACT);
3965
3966
3967 if (oldtype == -1) {
3968 // printf("Value <%s> not found, creating it new\n",valname);
3969 plainname = str_dup(valname);
3970 de_escape(plainname,0);
3971 // printf("de-escaped to <%s> creating it new\n",plainname);
3972 add_value(hdesc, nk + 4, plainname, type);
3973 oldtype = get_val_type(hdesc, nk + 4, valname, TPF_VK_ABS|TPF_EXACT);
3974 FREE(plainname);
3975 VERB(hdesc," [CREATED]");
3976
3977 }
3978
3979 if (oldtype != type) {
3980 fprintf(stderr,"ERROR: import_reg: unable to change value <%s>, new type is %d while old is %d\n",valname,type,oldtype);
3981 bailout = 1;
3982 } else {
3983
3984 VERB(hdesc,"\n");
3985 put_buf2val(hdesc, valbinbuf, nk + 4, valname, type, TPF_VK_ABS|TPF_EXACT);
3986
3987 numkeyvals++;
3988 numtotvals++;
3989
3990 FREE(valbinbuf);
3991 FREE(valstr);
3992 FREE(valname);
3993 FREE(walstr);
3994 }
3995 }
3996 }
3997
3998
3999 if (assigner && !value) { /* Its a key line */
4000 //printf("import_reg: read key name: %s\n",assigner);
4001 if ( !strncmp(assigner,prefix,plen)) { /* Check and strip of prefix of key name */
4002 assigner += plen;
4003 } else {
4004 fprintf(stderr,"import_reg: WARNING: found key <%s> not matching prefix <%s>\n",assigner,prefix);
4005 abort();
4006 }
4007
4008 if (numkeys) {
4009 if (hdesc->state & HMODE_VERBOSE)
4010 printf("--- END of key, with %d values\n",numkeyvals);
4011 else
4012 printf(" with %d values.\n",numkeyvals);
4013 numkeyvals = 0;
4014 }
4015
4016 printf("--- Import KEY <%s> ",assigner);
4017 numkeys++;
4018
4019 key = strtok(assigner,"\\");
4020 prevnk = hdesc->rootofs;
4021 while (key) {
4022 nk = trav_path(hdesc, prevnk + 4, key, TPF_NK_EXACT);
4023 if (!nk) {
4024 if (!add_key(hdesc, prevnk + 4, key)) {
4025 fprintf(stderr,"\nERROR: import_reg: failed to add (sub)key <%s>\n",key);
4026 bailout = 1;
4027 } else {
4028 printf(" [added <%s>] ",key);
4029 nk = trav_path(hdesc, prevnk + 4, key, TPF_NK_EXACT);
4030 numkeyadd++;
4031 }
4032 }
4033 prevnk = nk;
4034 key = strtok(NULL,"\\");
4035 }
4036 fflush(stdout);
4037 VERB(hdesc,"\n");
4038 }
4039
4040
4041 if (assigner && value) {
4042 // printf("import_reg: value assignment line: %s = %s\n",assigner,value);
4043 valname = str_dup(dequote(assigner));
4044 if (wide) {
4045 FREE(walstr);
4046 ALLOC(walstr, 1, wide_strlen(wline));
4047 memcpy(walstr, wline, wide_strlen(wline));
4048 }
4049
4050 l = strlen(value);
4051 if ( *(value+l-1) == '\\' ) { /* Strip off cont character */
4052 *(value+l-1) = 0;
4053 l--;
4054 }
4055 value = dequote(value);
4056 valstr = str_dup(value);
4057 // valbuf = NULL;
4058 //printf("import_reg: val name = %s\n",valname);
4059 //printf("import_reg: val str = %s\n",valstr);
4060
4061 }
4062
4063
4064 } while (!feof(file) && !bailout);
4065
4066
4067 printf("\nEND OF IMPORT, file <%s>, operation %s!\n", filename, (bailout ? "FAILED" : "SUCCEEDED"));
4068 printf("%d keys\n",numkeys);
4069 printf("%d new keys added\n",numkeyadd);
4070 printf("%d values total\n\n",numtotvals);
4071 fclose(file);
4072
4073 if (bailout) hdesc->state &= ~HMODE_DIRTY; /* Don't save if error. Or should we? */
4074
4075 }
4076
4077
4078
4079
4080
4081
4082
4083
4084 /* ================================================================ */
4085
4086 /* Hive control (load/save/close) etc */
4087
closeHive(struct hive * hdesc)4088 void closeHive(struct hive *hdesc)
4089 {
4090
4091 // printf("closing hive %s\n",hdesc->filename);
4092 if (hdesc->state & HMODE_OPEN) {
4093 close(hdesc->filedesc);
4094 }
4095 FREE(hdesc->filename);
4096 FREE(hdesc->buffer);
4097 FREE(hdesc);
4098
4099 }
4100
4101
4102 /* Compute checksum of REGF header page
4103 * hdesc = hive
4104 * returns checksum value, 32 bit int
4105 */
4106
calc_regfsum(struct hive * hdesc)4107 int32_t calc_regfsum(struct hive *hdesc)
4108 {
4109 int32_t checksum = 0;
4110 struct regf_header *hdr;
4111 int i;
4112
4113 hdr = (struct regf_header *) hdesc->buffer;
4114
4115 for (i = 0; i < 0x1fc/4; ++i)
4116 checksum ^= ((int32_t *) hdr)[i];
4117
4118 return(checksum);
4119
4120 }
4121
4122
4123
4124 /* Write the hive back to disk (only if dirty & not readonly) */
4125
writeHive(struct hive * hdesc)4126 int writeHive(struct hive *hdesc)
4127 {
4128 int len;
4129 struct regf_header *hdr;
4130
4131 if (hdesc->state & HMODE_RO) return(0);
4132 if ( !(hdesc->state & HMODE_DIRTY)) return(0);
4133
4134 if ( !(hdesc->state & HMODE_OPEN)) { /* File has been closed */
4135 if (!(hdesc->filedesc = open(hdesc->filename,O_RDWR))) {
4136 fprintf(stderr,"writeHive: open(%s) failed: %s, FILE NOT WRITTEN!\n",hdesc->filename,strerror(errno));
4137 return(1);
4138 }
4139 hdesc->state |= HMODE_OPEN;
4140 }
4141 /* Seek back to begginning of file (in case it's already open) */
4142 lseek(hdesc->filedesc, 0, SEEK_SET);
4143
4144 /* compute new checksum */
4145
4146 hdr = (struct regf_header *) hdesc->buffer;
4147
4148 hdr->checksum = calc_regfsum(hdesc);
4149
4150
4151 len = write(hdesc->filedesc, hdesc->buffer, hdesc->size);
4152 if (len != hdesc->size) {
4153 fprintf(stderr,"writeHive: write of %s failed: %s.\n",hdesc->filename,strerror(errno));
4154 return(1);
4155 }
4156
4157 hdesc->state &= (~HMODE_DIRTY);
4158 return(0);
4159 }
4160
4161 #undef LOAD_DEBUG
4162
openHive(char * filename,int mode)4163 struct hive *openHive(char *filename, int mode)
4164 {
4165
4166 struct hive *hdesc;
4167 int fmode,r,vofs;
4168 struct stat sbuf;
4169 uint32_t pofs;
4170 int32_t checksum;
4171 char *c;
4172 int rt;
4173 struct hbin_page *p;
4174 struct regf_header *hdr;
4175 struct nk_key *nk;
4176 struct ri_key *rikey;
4177
4178 int verbose = (mode & HMODE_VERBOSE);
4179 int trace = (mode & HMODE_TRACE) ? 1 : 0;
4180 int info = (mode & HMODE_INFO);
4181
4182 if (!filename || !*filename) return(NULL);
4183
4184 CREATE(hdesc,struct hive,1);
4185
4186 hdesc->filename = str_dup(filename);
4187 hdesc->state = 0;
4188 hdesc->size = 0;
4189 hdesc->buffer = NULL;
4190
4191 if ( (mode & HMODE_RO) ) {
4192 fmode = O_RDONLY;
4193 } else {
4194 fmode = O_RDWR;
4195 }
4196
4197 /* Some non-unix platforms may need this. Thanks to Dan Schmidt */
4198 #ifdef O_BINARY
4199 fmode |= O_BINARY;
4200 #endif
4201
4202 hdesc->filedesc = open(hdesc->filename,fmode);
4203 if (hdesc->filedesc < 0) {
4204 fprintf(stderr,"openHive(%s) failed: %s, trying read-only\n",hdesc->filename,strerror(errno));
4205 fmode = O_RDONLY;
4206 mode |= HMODE_RO;
4207 hdesc->filedesc = open(hdesc->filename,fmode);
4208 if (hdesc->filedesc < 0) {
4209 fprintf(stderr,"openHive(%s) in fallback RO-mode failed: %s\n",hdesc->filename,strerror(errno));
4210 closeHive(hdesc);
4211 return(NULL);
4212 }
4213 }
4214
4215
4216 if ( fstat(hdesc->filedesc,&sbuf) ) {
4217 perror("stat()");
4218 exit(1);
4219 }
4220
4221 hdesc->size = sbuf.st_size;
4222 hdesc->state = mode | HMODE_OPEN;
4223
4224 /* Read the whole file */
4225
4226 ALLOC(hdesc->buffer,1,hdesc->size);
4227
4228 rt = 0;
4229 do { /* On some platforms read may not block, and read in chunks. handle that */
4230 r = read(hdesc->filedesc, hdesc->buffer + rt, hdesc->size - rt);
4231 rt += r;
4232 } while ( !errno && (rt < hdesc->size) );
4233
4234 if (errno) {
4235 perror("openHive(): read error: ");
4236 closeHive(hdesc);
4237 return(NULL);
4238 }
4239 if (rt < hdesc->size) {
4240 fprintf(stderr,"Could not read file, got %d bytes while expecting %d\n",
4241 r, hdesc->size);
4242 closeHive(hdesc);
4243 return(NULL);
4244 }
4245
4246 /* Now run through file, tallying all pages */
4247 /* NOTE/KLUDGE: Assume first page starts at offset 0x1000 */
4248
4249 pofs = 0x1000;
4250
4251 hdr = (struct regf_header *)hdesc->buffer;
4252 if (hdr->id != 0x66676572) {
4253 fprintf(stderr,"openHive(%s): File does not seem to be a registry hive!\n",filename);
4254 return(hdesc);
4255 }
4256
4257 checksum = calc_regfsum(hdesc);
4258
4259 #ifdef LOAD_DEBUG
4260 printf("openhive: calculated checksum: %08x\n",checksum);
4261 printf("openhive: file REGF checksum: %08x\n",hdr->checksum);
4262 #endif
4263 if (checksum != hdr->checksum) {
4264 fprintf(stderr,"openHive(%s): WARNING: REGF header checksum mismatch! calc: 0x%08x != file: 0x%08x\n",filename,checksum,hdr->checksum);
4265 }
4266
4267 hdesc->rootofs = hdr->ofs_rootkey + 0x1000;
4268
4269 if (info) {
4270 printf("Hive <%s> name (from header): <",filename);
4271 for (c = hdr->name; *c && (c < hdr->name + 64); c += 2) putchar(*c);
4272 printf(">\nROOT KEY at offset: 0x%06x * ",hdesc->rootofs);
4273 }
4274
4275 /* Cache the roots subkey index type (li,lf,lh) so we can use the correct
4276 * one when creating the first subkey in a key */
4277
4278 nk = (struct nk_key *)(hdesc->buffer + hdesc->rootofs + 4);
4279 if (nk->id == 0x6b6e) {
4280 rikey = (struct ri_key *)(hdesc->buffer + nk->ofs_lf + 0x1004);
4281 hdesc->nkindextype = rikey->id;
4282 if (hdesc->nkindextype == 0x6972) { /* Gee, big root, must check indirectly */
4283 fprintf(stderr,"openHive: DEBUG: BIG ROOT!\n");
4284 rikey = (struct ri_key *)(hdesc->buffer + rikey->hash[0].ofs_li + 0x1004);
4285 hdesc->nkindextype = rikey->id;
4286 }
4287 if (hdesc->nkindextype != 0x666c &&
4288 hdesc->nkindextype != 0x686c &&
4289 hdesc->nkindextype != 0x696c) {
4290 hdesc->nkindextype = 0x666c;
4291 }
4292
4293 if (info) printf("Subkey indexing type is: %04x <%c%c>\n",
4294 hdesc->nkindextype,
4295 hdesc->nkindextype & 0xff,
4296 hdesc->nkindextype >> 8);
4297 } else {
4298 fprintf(stderr,"openHive: WARNING: ROOT key does not seem to be a key! (not type == nk)\n");
4299 }
4300
4301
4302 while (pofs < hdr->filesize + 0x1000) { /* Loop through hbins until end according to regf header */
4303 #ifdef LOAD_DEBUG
4304 int htrace = 1;
4305 // if (htrace) hexdump(hdesc->buffer,pofs,pofs+0x20,1);
4306 #endif
4307 p = (struct hbin_page *)(hdesc->buffer + pofs);
4308 if (p->id != 0x6E696268) {
4309 if (info) printf("Page at 0x%x is not 'hbin', assuming file contains garbage at end\n",pofs);
4310 break;
4311 }
4312 hdesc->pages++;
4313
4314 if (verbose) printf("###### Page at 0x%0x ofs_self 0x%0x, size (delta ofs_next) 0x%0x ######\n",
4315 pofs,p->ofs_self,p->ofs_next);
4316
4317 if (p->ofs_next == 0) {
4318 fprintf(stderr,"openHive: ERROR: Page at 0x%x has size zero! File may be corrupt, or program has a bug\n",pofs);
4319 return(hdesc);
4320 }
4321
4322
4323 vofs = pofs + 0x20; /* Skip page header, and run through blocks in hbin */
4324
4325 while (vofs-pofs < p->ofs_next && vofs < hdesc->size) {
4326 vofs += parse_block(hdesc,vofs,trace);
4327
4328 }
4329
4330 pofs += p->ofs_next;
4331
4332 } /* hbin loop */
4333
4334
4335 hdesc->endofs = hdr->filesize + 0x1000;
4336 hdesc->lastbin = pofs - p->ofs_next; /* Compensate for loop that added at end above */
4337
4338 if (verbose) {
4339 printf("Last HBIN at offset : 0x%x\n",hdesc->lastbin);
4340 printf("First non-HBIN page offset: 0x%x\n",hdesc->endofs);
4341 printf("hdr->unknown4 (version?) : 0x%x\n",hdr->unknown4);
4342 }
4343
4344 if (info || verbose) {
4345 printf("File size %d [%x] bytes, containing %d pages (+ 1 headerpage)\n",hdesc->size,hdesc->size, hdesc->pages);
4346 printf("Used for data: %d/%d blocks/bytes, unused: %d/%d blocks/bytes.\n\n",
4347 hdesc->useblk,hdesc->usetot,hdesc->unuseblk,hdesc->unusetot);
4348 }
4349
4350 /* So, let's guess what kind of hive this is, based on keys in its root */
4351
4352 hdesc->type = HTYPE_UNKNOWN;
4353
4354 if (trav_path(hdesc, 0, "\\SAM", 0)) hdesc->type = HTYPE_SAM;
4355 else if (trav_path(hdesc, 0, "\\ControlSet", 0)) hdesc->type = HTYPE_SYSTEM;
4356 else if (trav_path(hdesc, 0, "\\Policy", 0)) hdesc->type = HTYPE_SECURITY;
4357 else if (trav_path(hdesc, 0, "\\Microsoft", 0)) hdesc->type = HTYPE_SOFTWARE;
4358 if (verbose) printf("Type of hive guessed to be: %d\n",hdesc->type);
4359
4360 return(hdesc);
4361
4362 }
4363
4364