Changeset 4


Ignore:
Timestamp:
02/19/05 22:19:23 (19 years ago)
Author:
tim
Message:

Now handling MULTI_SZ types by printing a list of converted strings, rather
than a hex dump. (Still needs testing.)

Moved header comments of reglookup.c to doc/winntreg.txt.

Added copy of GPL2 as LICENSE.

Files:
2 added
1 edited

Legend:

Unmodified
Added
Removed
  • src/reglookup.c

    r2 r4  
    11/*
    2  * $Id: $
     2 * $Id$
     3 *
     4 * A utility to edit a Windows NT/2K etc registry file.
    35 *
    46 * This code was taken from Richard Sharpe''s editreg utility, in the
     
    1113 * This program is free software; you can redistribute it and/or modify
    1214 * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 2 of the License, or
    14  * (at your option) any later version.
     15 * the Free Software Foundation; version 2 of the License.
    1516 *
    1617 * This program is distributed in the hope that it will be useful,
     
    2526 
    2627/*************************************************************************
    27                                                    
    28  A utility to edit a Windows NT/2K etc registry file.
    29                                      
    30  Many of the ideas in here come from other people and software.
    31  I first looked in Wine in misc/registry.c and was also influenced by
    32  http://www.wednesday.demon.co.uk/dosreg.html
    33 
    34  Which seems to contain comments from someone else. I reproduce them here
    35  incase the site above disappears. It actually comes from
    36  http://home.eunet.no/~pnordahl/ntpasswd/WinReg.txt.
    37 
    38  The goal here is to read the registry into memory, manipulate it, and then
    39  write it out if it was changed by any actions of the user.
    40 
    41 The windows NT registry has 2 different blocks, where one can occur many
    42 times...
    43 
    44 the "regf"-Block
    45 ================
     28
     29 A note from Richard Sharpe:
     30  Many of the ideas in here come from other people and software.
     31  I first looked in Wine in misc/registry.c and was also influenced by
     32  http://www.wednesday.demon.co.uk/dosreg.html
     33
     34  Which seems to contain comments from someone else. I reproduce them here
     35  incase the site above disappears. It actually comes from
     36  http://home.eunet.no/~pnordahl/ntpasswd/WinReg.txt.
    4637 
    47 "regf" is obviosly the abbreviation for "Registry file". "regf" is the
    48 signature of the header-block which is always 4kb in size, although only
    49 the first 64 bytes seem to be used and a checksum is calculated over
    50 the first 0x200 bytes only!
    51 
    52 Offset            Size      Contents
    53 0x00000000      D-Word      ID: ASCII-"regf" = 0x66676572
    54 0x00000004      D-Word      ???? //see struct REGF
    55 0x00000008      D-Word      ???? Always the same value as at 0x00000004
    56 0x0000000C      Q-Word      last modify date in WinNT date-format
    57 0x00000014      D-Word      1
    58 0x00000018      D-Word      3
    59 0x0000001C      D-Word      0
    60 0x00000020      D-Word      1
    61 0x00000024      D-Word      Offset of 1st key record
    62 0x00000028      D-Word      Size of the data-blocks (Filesize-4kb)
    63 0x0000002C      D-Word      1
    64 0x000001FC      D-Word      Sum of all D-Words from 0x00000000 to
    65 0x000001FB  //XOR of all words. Nigel
    66 
    67 I have analyzed more registry files (from multiple machines running
    68 NT 4.0 german version) and could not find an explanation for the values
    69 marked with ???? the rest of the first 4kb page is not important...
    70 
    71 the "hbin"-Block
    72 ================
    73 I dont know what "hbin" stands for, but this block is always a multiple
    74 of 4kb in size.
    75 
    76 Inside these hbin-blocks the different records are placed. The memory-
    77 management looks like a C-compiler heap management to me...
    78 
    79 hbin-Header
    80 ===========
    81 Offset      Size      Contents
    82 0x0000      D-Word      ID: ASCII-"hbin" = 0x6E696268
    83 0x0004      D-Word      Offset from the 1st hbin-Block
    84 0x0008      D-Word      Offset to the next hbin-Block
    85 0x001C      D-Word      Block-size
    86 
    87 The values in 0x0008 and 0x001C should be the same, so I dont know
    88 if they are correct or swapped...
    89 
    90 From offset 0x0020 inside a hbin-block data is stored with the following
    91 format:
    92 
    93 Offset      Size      Contents
    94 0x0000      D-Word      Data-block size    //this size must be a
    95 multiple of 8. Nigel
    96 0x0004      ????      Data
    97  
    98 If the size field is negative (bit 31 set), the corresponding block
    99 is free and has a size of -blocksize!
    100 
    101 That does not seem to be true. All block lengths seem to be negative!
    102 (Richard Sharpe)
    103 
    104 The data is stored as one record per block. Block size is a multiple
    105 of 4 and the last block reaches the next hbin-block, leaving no room.
    106 
    107 (That also seems incorrect, in that the block size if a multiple of 8.
    108 That is, the block, including the 4 byte header, is always a multiple of
    109 8 bytes. Richard Sharpe.)
    110 
    111 Records in the hbin-blocks
    112 ==========================
    113 
    114 nk-Record
    115 
    116       The nk-record can be treated as a kombination of tree-record and
    117       key-record of the win 95 registry.
    118 
    119 lf-Record
    120 
    121       The lf-record is the counterpart to the RGKN-record (the
    122       hash-function)
    123 
    124 vk-Record
    125 
    126       The vk-record consists information to a single value.
    127 
    128 sk-Record
    129 
    130       sk (? Security Key ?) is the ACL of the registry.
    131 
    132 Value-Lists
    133 
    134       The value-lists contain information about which values are inside a
    135       sub-key and dont have a header.
    136 
    137 Datas
    138 
    139       The datas of the registry are (like the value-list) stored without a
    140       header.
    141 
    142 All offset-values are relative to the first hbin-block and point to the
    143 block-size field of the record-entry. to get the file offset, you have to add
    144 the header size (4kb) and the size field (4 bytes)...
    145 
    146 the nk-Record
    147 =============
    148 Offset      Size      Contents
    149 0x0000      Word      ID: ASCII-"nk" = 0x6B6E
    150 0x0002      Word      for the root-key: 0x2C, otherwise 0x20  //key symbolic links 0x10. Nigel
    151 0x0004      Q-Word      write-date/time in windows nt notation
    152 0x0010      D-Word      Offset of Owner/Parent key
    153 0x0014      D-Word      number of sub-Keys
    154 0x001C      D-Word      Offset of the sub-key lf-Records
    155 0x0024      D-Word      number of values
    156 0x0028      D-Word      Offset of the Value-List
    157 0x002C      D-Word      Offset of the sk-Record
    158 
    159 0x0030      D-Word      Offset of the Class-Name //see NK structure for the use of these fields. Nigel
    160 0x0044      D-Word      Unused (data-trash)  //some kind of run time index. Does not appear to be important. Nigel
    161 0x0048      Word      name-length
    162 0x004A      Word      class-name length
    163 0x004C      ????      key-name
    164 
    165 the Value-List
    166 ==============
    167 Offset      Size      Contents
    168 0x0000      D-Word      Offset 1st Value
    169 0x0004      D-Word      Offset 2nd Value
    170 0x????      D-Word      Offset nth Value
    171 
    172 To determine the number of values, you have to look at the owner-nk-record!
    173 
    174 Der vk-Record
    175 =============
    176 Offset      Size      Contents
    177 0x0000      Word      ID: ASCII-"vk" = 0x6B76
    178 0x0002      Word      name length
    179 0x0004      D-Word      length of the data   //if top bit is set when offset contains data. Nigel
    180 0x0008      D-Word      Offset of Data
    181 0x000C      D-Word      Type of value
    182 0x0010      Word      Flag
    183 0x0012      Word      Unused (data-trash)
    184 0x0014      ????      Name
    185 
    186 If bit 0 of the flag-word is set, a name is present, otherwise the value has no name (=default)
    187 
    188 If the data-size is lower 5, the data-offset value is used to store the data itself!
    189 
    190 The data-types
    191 ==============
    192 Wert      Beteutung
    193 0x0001      RegSZ:             character string (in UNICODE!)
    194 0x0002      ExpandSZ:   string with "%var%" expanding (UNICODE!)
    195 0x0003      RegBin:           raw-binary value
    196 0x0004      RegDWord:   Dword
    197 0x0007      RegMultiSZ:      multiple strings, seperated with 0
    198                   (UNICODE!)
    199 
    200 The "lf"-record
    201 ===============
    202 Offset      Size      Contents
    203 0x0000      Word      ID: ASCII-"lf" = 0x666C
    204 0x0002      Word      number of keys
    205 0x0004      ????      Hash-Records
    206 
    207 Hash-Record
    208 ===========
    209 Offset      Size      Contents
    210 0x0000      D-Word      Offset of corresponding "nk"-Record
    211 0x0004      D-Word      ASCII: the first 4 characters of the key-name, padded with 0-s. Case sensitiv!
    212 
    213 Keep in mind, that the value at 0x0004 is used for checking the data-consistency! If you change the
    214 key-name you have to change the hash-value too!
    215 
    216 //These hashrecords must be sorted low to high within the lf record. Nigel.
    217 
    218 The "sk"-block
    219 ==============
    220 (due to the complexity of the SAM-info, not clear jet)
    221 (This is just a self-relative security descriptor in the data. R Sharpe.)
    222 
    223 
    224 Offset      Size      Contents
    225 0x0000      Word      ID: ASCII-"sk" = 0x6B73
    226 0x0002      Word      Unused
    227 0x0004      D-Word      Offset of previous "sk"-Record
    228 0x0008      D-Word      Offset of next "sk"-Record
    229 0x000C      D-Word      usage-counter
    230 0x0010      D-Word      Size of "sk"-record in bytes
    231 ????                                             //standard self
    232 relative security desciptor. Nigel
    233 ????  ????      Security and auditing settings...
    234 ????
    235 
    236 The usage counter counts the number of references to this
    237 "sk"-record. You can use one "sk"-record for the entire registry!
    238 
    239 Windows nt date/time format
    240 ===========================
    241 The time-format is a 64-bit integer which is incremented every
    242 0,0000001 seconds by 1 (I dont know how accurate it really is!)
    243 It starts with 0 at the 1st of january 1601 0:00! All values are
    244 stored in GMT time! The time-zone is important to get the real
    245 time!
    246 
    247 Common values for win95 and win-nt
    248 ==================================
    249 Offset values marking an "end of list", are either 0 or -1 (0xFFFFFFFF).
    250 If a value has no name (length=0, flag(bit 0)=0), it is treated as the
    251 "Default" entry...
    252 If a value has no data (length=0), it is displayed as empty.
    253 
    254 simplyfied win-3.?? registry:
    255 =============================
    256 
    257 +-----------+
    258 | next rec. |---+                      +----->+------------+
    259 | first sub |   |                      |      | Usage cnt. |
    260 | name      |   |  +-->+------------+  |      | length     |
    261 | value     |   |  |   | next rec.  |  |      | text       |------->+-------+
    262 +-----------+   |  |   | name rec.  |--+      +------------+        | xxxxx |
    263    +------------+  |   | value rec. |-------->+------------+        +-------+
    264    v               |   +------------+         | Usage cnt. |
    265 +-----------+      |                          | length     |
    266 | next rec. |      |                          | text       |------->+-------+
    267 | first sub |------+                          +------------+        | xxxxx |
    268 | name      |                                                       +-------+
    269 | value     |
    270 +-----------+   
    271 
    272 Greatly simplyfied structure of the nt-registry:
    273 ================================================
    274    
    275 +---------------------------------------------------------------+
    276 |                                                               |
    277 v                                                               |
    278 +---------+     +---------->+-----------+  +----->+---------+   |
    279 | "nk"    |     |           | lf-rec.   |  |      | nk-rec. |   |
    280 | ID      |     |           | # of keys |  |      | parent  |---+
    281 | Date    |     |           | 1st key   |--+      | ....    |
    282 | parent  |     |           +-----------+         +---------+
    283 | suk-keys|-----+
    284 | values  |--------------------->+----------+
    285 | SK-rec. |---------------+      | 1. value |--> +----------+
    286 | class   |--+            |      +----------+    | vk-rec.  |
    287 +---------+  |            |                      | ....     |
    288              v            |                      | data     |--> +-------+
    289       +------------+      |                      +----------+    | xxxxx |
    290       | Class name |      |                                      +-------+
    291       +------------+      |
    292                           v
    293           +---------+    +---------+
    294    +----->| next sk |--->| Next sk |--+
    295    |  +---| prev sk |<---| prev sk |  |
    296    |  |   | ....    |    | ...     |  |
    297    |  |   +---------+    +---------+  |
    298    |  |                    ^          |
    299    |  |                    |          |
    300    |  +--------------------+          |
    301    +----------------------------------+
    302 
    303 ---------------------------------------------------------------------------
    304 
    305 Hope this helps....  (Although it was *fun* for me to uncover this things,
    306                   it took me several sleepless nights ;)
    307 
    308             B.D.
    309 
    310 *************************************************************************/
     38 NOTE: the comments he refers to have been moved to doc/winntreg.txt
     39
     40**************************************************************************/
     41
    31142
    31243#include <stdio.h>
     
    1154885  unsigned short num_nulls;
    1155886  unsigned char* ascii;
    1156   unsigned int ascii_max;
    1157   int str_rem;
     887  unsigned char* cur_str;
     888  unsigned int cur_str_len;
     889  unsigned int ascii_max, cur_str_max;
     890  unsigned int str_rem, cur_str_rem, alen;
    1158891
    1159892  switch (type)
     
    1216949  case REG_TYPE_MULTISZ:
    1217950    ascii_max = sizeof(char)*len*4;
     951    cur_str_max = sizeof(char)*len+1;
     952    cur_str = malloc(cur_str_max);
    1218953    ascii = malloc(ascii_max+4);
    1219954    if(ascii == NULL)
     
    1228963    num_nulls = 0;
    1229964    str_rem = ascii_max;
    1230     for(i=0; (i < len) && (num_nulls < 4) && str_rem > 0; i++)
     965    cur_str_rem = cur_str_max;
     966    cur_str_len = 0;
     967
     968    *asciip = '"';
     969    asciip +=1;
     970   
     971    for(i=0; (i < len) && str_rem > 0; i++)
    1231972    {
    1232       asciip += snprintf((char*)asciip, str_rem, "%02x ",
    1233                          *(unsigned char *)(datap+i));
    1234       str_rem -= 3;
    1235       if(*(datap+i) == 0)
     973      *(cur_str+cur_str_len) = *(datap+i);
     974      if(*(cur_str+cur_str_len) == 0)
    1236975        num_nulls++;
    1237976      else
    1238977        num_nulls = 0;
    1239     }
    1240     *asciip = '\0';
     978      cur_str_len++;
     979
     980      if(num_nulls == 2)
     981      {
     982        uni_to_ascii(cur_str, asciip, str_rem, 0);
     983        alen = strlen((char*)asciip);
     984        asciip += alen;
     985        str_rem -= alen;
     986        if(*(datap+i+1) == 0 && *(datap+i+2) == 0)
     987          break;
     988        else
     989        {
     990          alen = snprintf((char*)asciip, str_rem, "%s", "\" \"");
     991          asciip += alen;
     992          str_rem -= alen;
     993          memset(cur_str, 0, cur_str_max);
     994          cur_str_len = 0;
     995          num_nulls = 0;
     996          /* To eliminate leading nulls in subsequent strings. */
     997          i++;
     998        }
     999      }
     1000    }
     1001    snprintf((char*)asciip, str_rem, "%s", "\"");
    12411002    return ascii;
    12421003    break;
     
    23112072  fprintf(stderr, "\n\t-v\t sets verbose mode");
    23122073  fprintf(stderr, "\n\t-f\t a simple prefix filter.");
    2313   fprintf(stderr, "\n\t-p\t prints the registry");
    23142074  fprintf(stderr, "\n\t-s\t prints security descriptors");
    23152075  fprintf(stderr, "\n");
     
    24082168  nt_key_iterator(regf, regf->root, 0, "", filter_prefix);
    24092169
    2410   /* XXX: debugging; remove me. */
    2411   printf("%d,%d,%d\n",
    2412          str_is_prefix("foo", "foobar"),
    2413          str_is_prefix("", "xyz"),
    2414          str_is_prefix("foo", "foo"));
    2415 
    24162170  return 0;
    24172171}
Note: See TracChangeset for help on using the changeset viewer.