#if 0

The windows NT registry has 2 different blocks, where one can occure many

times...

 

the "regf"-Block

================

 

"regf" is obviosly the abbreviation for "Registry file". "regf" is the

signature of the header-block which is always 4kb in size, although only

the first 64 bytes seem to be used and a checksum is calculated over

the first 0x200 bytes only!

 

Offset            Size      Contents

0x00000000      D-Word      ID: ASCII-"regf" = 0x66676572

0x00000004      D-Word      ???? //see struct REGF

0x00000008      D-Word      ???? Always the same value as at 0x00000004

0x0000000C      Q-Word      last modify date in WinNT date-format

0x00000014      D-Word      1

0x00000018      D-Word      3

0x0000001C      D-Word      0

0x00000020      D-Word      1

0x00000024      D-Word      Offset of 1st key record

0x00000028      D-Word      Size of the data-blocks (Filesize-4kb)

0x0000002C      D-Word      1

0x000001FC      D-Word      Sum of all D-Words from 0x00000000 to 0x000001FB  //XOR of all words. Nigel

 

I have analyzed more registry files (from multiple machines running

NT 4.0 german version) and could not find an explanation for the values

marked with ???? the rest of the first 4kb page is not important...

 

 

the "hbin"-Block

================

 

I don't know what "hbin" stands for, but this block is always a multiple

of 4kb in size.

 

Inside these hbin-blocks the different records are placed. The memory-

management looks like a C-compiler heap management to me...

 

 

hbin-Header

===========

 

Offset      Size      Contents

0x0000      D-Word      ID: ASCII-"hbin" = 0x6E696268

0x0004      D-Word      Offset from the 1st hbin-Block

0x0008      D-Word      Offset to the next hbin-Block

0x001C      D-Word      Block-size

 

The values in 0x0008 and 0x001C should be the same, so I don't know

if they are correct or swapped...

 

From offset 0x0020 inside a hbin-block data is stored with the following

format:

 

Offset      Size      Contents

0x0000      D-Word      Data-block size    //this size must be a multiple of 8. Nigel

0x0004      ????      Data

 

If the size field is negative (bit 31 set), the corresponding block

is free and has a size of -blocksize!

The data is stored as one record per block. Block size is a multiple

of 4 and the last block reaches the next hbin-block, leaving no room.

 

Records in the hbin-blocks

==========================

 

 

nk-Record

 

      The nk-record can be treated as a kombination of tree-record and

      key-record of the win 95 registry.

 

lf-Record

 

      The lf-record is the counterpart to the RGKN-record (the hash-function)

 

vk-Record

 

      The vk-record consists information to a single value.

 

sk-Record

 

      sk (? Security Key ?) is the ACL of the registry.

 

Value-Lists

 

      The value-lists contain information about which values are inside a

      sub-key and don't have a header.

 

Datas

 

      The datas of the registry are (like the value-list) stored without a

      header.

 

 

All offset-values are relative to the first hbin-block and point to the block-

size field of the record-entry. to get the file offset, you have to add

the header size (4kb) and the size field (4 bytes)...

 

the nk-Record

=============

 

Offset      Size      Contents

0x0000      Word      ID: ASCII-"nk" = 0x6B6E

0x0002      Word      for the root-key: 0x2C, otherwise 0x20  //key symbolic links 0x10. Nigel

0x0004      Q-Word      write-date/time in windows nt notation

0x0010      D-Word      Offset of Owner/Parent key

0x0014      D-Word      number of sub-Keys

0x001C      D-Word      Offset of the sub-key lf-Records

0x0024      D-Word      number of values

0x0028      D-Word      Offset of the Value-List

0x002C      D-Word      Offset of the sk-Record

0x0030      D-Word      Offset of the Class-Name

 

//see NK structure for the use of these fields. Nigel

 

0x0044      D-Word      Unused (data-trash)  //some kind of run time index. Does not appear to be important. Nigel

0x0048      Word      name-length

0x004A      Word      class-name length

0x004C      ????      key-name

 

the Value-List

==============

 

Offset      Size      Contents

0x0000      D-Word      Offset 1st Value

0x0004      D-Word      Offset 2nd Value

0x????      D-Word      Offset nth Value

 

To determine the number of values, you have to look at the

owner-nk-record!

 

Der vk-Record

=============

 

Offset      Size      Contents

0x0000      Word      ID: ASCII-"vk" = 0x6B76

0x0002      Word      name length

0x0004      D-Word      length of the data   //if top bit is set when offset contains data. Nigel

0x0008      D-Word      Offset of Data

0x000C      D-Word      Type of value

0x0010      Word      Flag

0x0012      Word      Unused (data-trash)

0x0014      ????      Name

 

If bit 0 of the flag-word is set, a name is present, otherwise the

value has no name (=default)

If the data-size is lower 5, the data-offset value is used to store

the data itself!

 

 

The data-types

==============

 

Wert      Beteutung

0x0001      RegSZ:             character string (in UNICODE!)

0x0002      ExpandSZ:   string with "%var%" expanding (UNICODE!)

0x0003      RegBin:           raw-binary value

0x0004      RegDWord:   Dword

0x0007      RegMultiSZ:      multiple strings, seperated with 0

                  (UNICODE!)

 

The "lf"-record

===============

 

Offset      Size      Contents

0x0000      Word      ID: ASCII-"lf" = 0x666C

0x0002      Word      number of keys

0x0004      ????      Hash-Records

 

Hash-Record

===========

 

Offset      Size      Contents

0x0000      D-Word      Offset of corresponding "nk"-Record

0x0004      D-Word      ASCII: the first 4 characters of the key-name,

            padded with 0's. Case sensitiv!

 

Keep in mind, that the value at 0x0004 is used for checking the

data-consistency! If you change the key-name you have to change the

hash-value too!

 

//These hashrecords must be sorted low to high within the lf record. Nigel.

 

The "sk"-block

==============

 

(due to the complexity of the SAM-info, not clear jet)

 

Offset      Size      Contents

0x0000      Word      ID: ASCII-"sk" = 0x6B73

0x0002      Word      Unused

0x0004      D-Word      Offset of previous "sk"-Record

0x0008      D-Word      Offset of next "sk"-Record

0x000C      D-Word      usage-counter

0x0010      D-Word      Size of "sk"-record in bytes

????                                             //standard self relative security desciptor. Nigel

????  ????      Security and auditing settings...

????

 

The usage counter counts the number of references to this

"sk"-record. You can use one "sk"-record for the entire registry!

 

Windows nt date/time format

===========================

 

The time-format is a 64-bit integer which is incremented every

0,0000001 seconds by 1 (I don't know how accurate it realy is!)

It starts with 0 at the 1st of january 1601 0:00! All values are

stored in GMT time! The time-zone is important to get the real

time!

 

Common values for win95 and win-nt

==================================

 

Offset values marking an "end of list", are either 0 or -1 (0xFFFFFFFF).

If a value has no name (length=0, flag(bit 0)=0), it is treated as the

"Default" entry...

If a value has no data (length=0), it is displayed as empty.

 

simplyfied win-3.?? registry:

=============================

 

 

 

+-----------+

| next rec. |---+             +----->     +------------+

| first sub |   |             |      | Usage cnt. |

| name      |     |  +-->     +------------+      |      | length     |

| value     |     |  |      | next rec.  |      |      | text       |------->      +-------+

+-----------+     |  |      | name rec.  |--+      +------------+          | xxxxx |

   +------------+  |      | value rec. |-------->      +------------+          +-------+

   v           |     +------------+          | Usage cnt. |

+-----------+        |                    | length     |

| next rec. |        |                    | text       |------->      +-------+

| first sub |------+                      +------------+          | xxxxx |

| name      |                                               +-------+

| value     |

+-----------+    

 

 

 

Greatly simplyfied structure of the nt-registry:

================================================

 

 

    +-------------------------------------------------------------------------+

    v                                                                         |

+---------------+ +------------->      +-----------+  +------> +---------+   |

| "nk"            |      |           | lf-rec.   |  |      | nk-rec. |   |

| ID        |      |           | # of keys |  |      | parent  |---+

| Date            |      |           | 1st key   |--+      | ....    |

| parent      |      |           +-----------+           +---------+

| suk-keys      |-------+

| values      |---------------------> +----------+

| SK-rec.      |---------------+      | 1. value |--> +----------+

| class           |--+        |      +----------+      | vk-rec.  |

+---------------+  |          |                 | ....     |

               v           |                 | data     |--> +-------+

            +------------+      |                 +----------+      | xxxxx |

            | Class name |      |                             +-------+

            +------------+      |

                        v

            +---------+ +---------+

      +----->     | next sk |---> | Next sk |--+

      |   +---| prev sk | <---| prev sk |  |

      |   |      | ....    |     | ...     |  |

      |   |      +---------+ +---------+  |

      |   |             ^          |

      |   +--------------------+           |

      +------------------------------------+

 

--------------------------------------------------------------------------------

 

Hope this helps....  (Although it was "fun" for me to uncover this things,

                  it took me several sleepless nights ;)

 

            B.D.

#endif

 

 

 

 

 

#if DOS

      typedef wchar_t WCHAR;

#endif

 

#include <windows.h>

#include <assert.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <ctype.h>

 

#ifndef REG_NONE

 

#undef REG_SZ

 

#define REG_NONE                    ( 0 )   // No value type

#define REG_SZ                      ( 1 )   // Unicode nul terminated string

#define REG_EXPAND_SZ               ( 2 )   // Unicode nul terminated string

                                            // (with environment variable references)

#define REG_BINARY                  ( 3 )   // Free form binary

#define REG_DWORD                   ( 4 )   // 32-bit number

#define REG_DWORD_LITTLE_ENDIAN     ( 4 )   // 32-bit number (same as REG_DWORD)

#define REG_DWORD_BIG_ENDIAN        ( 5 )   // 32-bit number

#define REG_LINK                    ( 6 )   // Symbolic Link (unicode)

#define REG_MULTI_SZ                ( 7 )   // Multiple Unicode strings

#define REG_RESOURCE_LIST           ( 8 )   // Resource list in the resource map

#define REG_FULL_RESOURCE_DESCRIPTOR ( 9 )  // Resource list in the hardware description

#define REG_RESOURCE_REQUIREMENTS_LIST ( 10 )

 

#endif

 

#if !defined(READ_CONTROL)

 

typedef DWORD ACCESS_MASK;

typedef ACCESS_MASK *PACCESS_MASK;

 

#define DELETE                           (0x00010000L)

#define READ_CONTROL                     (0x00020000L)

#define WRITE_DAC                        (0x00040000L)

#define WRITE_OWNER                      (0x00080000L)

#define SYNCHRONIZE                      (0x00100000L)

 

#define STANDARD_RIGHTS_REQUIRED         (0x000F0000L)

 

#define STANDARD_RIGHTS_READ             (READ_CONTROL)

#define STANDARD_RIGHTS_WRITE            (READ_CONTROL)

#define STANDARD_RIGHTS_EXECUTE          (READ_CONTROL)

 

#define STANDARD_RIGHTS_ALL              (0x001F0000L)

 

#define SPECIFIC_RIGHTS_ALL              (0x0000FFFFL)

 

#define ACCESS_SYSTEM_SECURITY           (0x01000000L)

 

#define MAXIMUM_ALLOWED                  (0x02000000L)

 

#define GENERIC_READ                     (0x80000000L)

#define GENERIC_WRITE                    (0x40000000L)

#define GENERIC_EXECUTE                  (0x20000000L)

#define GENERIC_ALL                      (0x10000000L)

 

#endif

 

//this value is taken from those seen in practice.

 

#define STANDARD_SPECIFIC_RIGHTS_REQUIRED 0x0000003f

 

#if !defined(ACL_REVISION)

 

#define ACL_REVISION     (2)

#define ACL_REVISION_DS  (4)

 

#define ACL_REVISION1   (1)

#define MIN_ACL_REVISION ACL_REVISION2

#define ACL_REVISION2   (2)

#define ACL_REVISION3   (3)

#define ACL_REVISION4   (4)

#define MAX_ACL_REVISION ACL_REVISION4

 

typedef struct _ACL {

    BYTE  AclRevision;

    BYTE  Sbz1;

    WORD   AclSize;

    WORD   AceCount;

    WORD   Sbz2;

} ACL;

typedef ACL *PACL;

 

typedef struct _ACE_HEADER {

    BYTE  AceType;

    BYTE  AceFlags;

    WORD   AceSize;

} ACE_HEADER;

typedef ACE_HEADER *PACE_HEADER;

 

#define ACCESS_MIN_MS_ACE_TYPE                  (0x0)

#define ACCESS_ALLOWED_ACE_TYPE                 (0x0)

#define ACCESS_DENIED_ACE_TYPE                  (0x1)

#define SYSTEM_AUDIT_ACE_TYPE                   (0x2)

#define SYSTEM_ALARM_ACE_TYPE                   (0x3)

#define ACCESS_MAX_MS_V2_ACE_TYPE               (0x3)

 

#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE        (0x4)

#define ACCESS_MAX_MS_V3_ACE_TYPE               (0x4)

 

#define ACCESS_MIN_MS_OBJECT_ACE_TYPE           (0x5)

#define ACCESS_ALLOWED_OBJECT_ACE_TYPE          (0x5)

#define ACCESS_DENIED_OBJECT_ACE_TYPE           (0x6)

#define SYSTEM_AUDIT_OBJECT_ACE_TYPE            (0x7)

#define SYSTEM_ALARM_OBJECT_ACE_TYPE            (0x8)

#define ACCESS_MAX_MS_OBJECT_ACE_TYPE           (0x8)

 

#define ACCESS_MAX_MS_V4_ACE_TYPE               (0x8)

#define ACCESS_MAX_MS_ACE_TYPE                  (0x8)

 

#define OBJECT_INHERIT_ACE                (0x1)

#define CONTAINER_INHERIT_ACE             (0x2)

#define NO_PROPAGATE_INHERIT_ACE          (0x4)

#define INHERIT_ONLY_ACE                  (0x8)

#define INHERITED_ACE                     (0x10)

#define VALID_INHERIT_FLAGS               (0x1F)

 

#define SUCCESSFUL_ACCESS_ACE_FLAG       (0x40)

#define FAILED_ACCESS_ACE_FLAG           (0x80)

 

typedef struct _ACCESS_ALLOWED_ACE {

    ACE_HEADER Header;

    ACCESS_MASK Mask;

    DWORD SidStart;

} ACCESS_ALLOWED_ACE;

 

typedef ACCESS_ALLOWED_ACE *PACCESS_ALLOWED_ACE;

 

typedef struct _ACCESS_DENIED_ACE {

    ACE_HEADER Header;

    ACCESS_MASK Mask;

    DWORD SidStart;

} ACCESS_DENIED_ACE;

typedef ACCESS_DENIED_ACE *PACCESS_DENIED_ACE;

 

typedef struct _SYSTEM_AUDIT_ACE {

    ACE_HEADER Header;

    ACCESS_MASK Mask;

    DWORD SidStart;

} SYSTEM_AUDIT_ACE;

typedef SYSTEM_AUDIT_ACE *PSYSTEM_AUDIT_ACE;

 

typedef struct _SYSTEM_ALARM_ACE {

    ACE_HEADER Header;

    ACCESS_MASK Mask;

    DWORD SidStart;

} SYSTEM_ALARM_ACE;

typedef SYSTEM_ALARM_ACE *PSYSTEM_ALARM_ACE;

 

#endif

 

#if !defined(SID_REVISION)

 

typedef struct _SID_IDENTIFIER_AUTHORITY {

    BYTE  Value[6];

} SID_IDENTIFIER_AUTHORITY, *PSID_IDENTIFIER_AUTHORITY;

 

#if defined(DOS)

 

#define ANYSIZE_ARRAY (1)

 

#endif

 

typedef struct _SID {

   BYTE  Revision;

   BYTE  SubAuthorityCount;

   SID_IDENTIFIER_AUTHORITY IdentifierAuthority;

   DWORD SubAuthority[ANYSIZE_ARRAY];

} SID, *PISID;

 

#define SID_REVISION                     (1)    // Current revision level

#define SID_MAX_SUB_AUTHORITIES          (15)

#define SID_RECOMMENDED_SUB_AUTHORITIES  (1)    // Will change to around 6

                                                // in a future release.

 

#define SECURITY_NULL_SID_AUTHORITY       {0,0,0,0,0,0}

#define SECURITY_WORLD_SID_AUTHORITY      {0,0,0,0,0,1}

#define SECURITY_LOCAL_SID_AUTHORITY      {0,0,0,0,0,2}

#define SECURITY_CREATOR_SID_AUTHORITY    {0,0,0,0,0,3}

#define SECURITY_NON_UNIQUE_AUTHORITY     {0,0,0,0,0,4}

 

#define SECURITY_NULL_RID                 (0x00000000L)

#define SECURITY_WORLD_RID                (0x00000000L)

#define SECURITY_LOCAL_RID                (0X00000000L)

 

#define SECURITY_CREATOR_OWNER_RID        (0x00000000L)

#define SECURITY_CREATOR_GROUP_RID        (0x00000001L)

 

#define SECURITY_CREATOR_OWNER_SERVER_RID (0x00000002L)

#define SECURITY_CREATOR_GROUP_SERVER_RID (0x00000003L)

 

#define SECURITY_NT_AUTHORITY           {0,0,0,0,0,5}

 

#define SECURITY_DIALUP_RID             (0x00000001L)

#define SECURITY_NETWORK_RID            (0x00000002L)

#define SECURITY_BATCH_RID              (0x00000003L)

#define SECURITY_INTERACTIVE_RID        (0x00000004L)

#define SECURITY_SERVICE_RID            (0x00000006L)

#define SECURITY_ANONYMOUS_LOGON_RID    (0x00000007L)

#define SECURITY_PROXY_RID              (0x00000008L)

#define SECURITY_ENTERPRISE_CONTROLLERS_RID (0x00000009L)

#define SECURITY_SERVER_LOGON_RID       SECURITY_ENTERPRISE_CONTROLLERS_RID

#define SECURITY_PRINCIPAL_SELF_RID     (0x0000000AL)

#define SECURITY_AUTHENTICATED_USER_RID (0x0000000BL)

#define SECURITY_RESTRICTED_CODE_RID    (0x0000000CL)

 

#define SECURITY_LOGON_IDS_RID          (0x00000005L)

#define SECURITY_LOGON_IDS_RID_COUNT    (3L)

 

#define SECURITY_LOCAL_SYSTEM_RID       (0x00000012L)

 

#define SECURITY_NT_NON_UNIQUE          (0x00000015L)

 

#define SECURITY_BUILTIN_DOMAIN_RID     (0x00000020L)

 

#define DOMAIN_USER_RID_ADMIN          (0x000001F4L)

#define DOMAIN_USER_RID_GUEST          (0x000001F5L)

#define DOMAIN_USER_RID_KRBTGT         (0x000001F6L)

 

#define DOMAIN_GROUP_RID_ADMINS        (0x00000200L)

#define DOMAIN_GROUP_RID_USERS         (0x00000201L)

#define DOMAIN_GROUP_RID_GUESTS        (0x00000202L)

#define DOMAIN_GROUP_RID_COMPUTERS     (0x00000203L)

#define DOMAIN_GROUP_RID_CONTROLLERS   (0x00000204L)

#define DOMAIN_GROUP_RID_CERT_ADMINS   (0x00000205L)

#define DOMAIN_GROUP_RID_SCHEMA_ADMINS (0x00000206L)

 

#define DOMAIN_ALIAS_RID_ADMINS        (0x00000220L)

#define DOMAIN_ALIAS_RID_USERS         (0x00000221L)

#define DOMAIN_ALIAS_RID_GUESTS        (0x00000222L)

#define DOMAIN_ALIAS_RID_POWER_USERS   (0x00000223L)

 

#define DOMAIN_ALIAS_RID_ACCOUNT_OPS   (0x00000224L)

#define DOMAIN_ALIAS_RID_SYSTEM_OPS    (0x00000225L)

#define DOMAIN_ALIAS_RID_PRINT_OPS     (0x00000226L)

#define DOMAIN_ALIAS_RID_BACKUP_OPS    (0x00000227L)

 

#define DOMAIN_ALIAS_RID_REPLICATOR    (0x00000228L)

 

#endif

 

#if !defined(SECURITY_DESCRIPTOR_REVISION)

 

#define SECURITY_DESCRIPTOR_REVISION     (1)

#define SECURITY_DESCRIPTOR_REVISION1    (1)

 

#define SECURITY_DESCRIPTOR_MIN_LENGTH   (sizeof(SECURITY_DESCRIPTOR))

 

typedef WORD   SECURITY_DESCRIPTOR_CONTROL, *PSECURITY_DESCRIPTOR_CONTROL;

 

#define SE_OWNER_DEFAULTED               (0x0001)

#define SE_GROUP_DEFAULTED               (0x0002)

#define SE_DACL_PRESENT                  (0x0004)

#define SE_DACL_DEFAULTED                (0x0008)

#define SE_SACL_PRESENT                  (0x0010)

#define SE_SACL_DEFAULTED                (0x0020)

#define SE_DACL_AUTO_INHERIT_REQ         (0x0100)

#define SE_SACL_AUTO_INHERIT_REQ         (0x0200)

#define SE_DACL_AUTO_INHERITED           (0x0400)

#define SE_SACL_AUTO_INHERITED           (0x0800)

#define SE_DACL_PROTECTED                (0x1000)

#define SE_SACL_PROTECTED                (0x2000)

#define SE_SELF_RELATIVE                 (0x8000)

 

typedef struct _SECURITY_DESCRIPTOR_RELATIVE {

    BYTE  Revision;

    BYTE  Sbz1;

    SECURITY_DESCRIPTOR_CONTROL Control;

    DWORD Owner;

    DWORD Group;

    DWORD Sacl;

    DWORD Dacl;

} SECURITY_DESCRIPTOR_RELATIVE, *PISECURITY_DESCRIPTOR_RELATIVE;

 

#endif

 

 

void UpdateRegMM(long hOffset);

long OffsetToHBin(long offset);

 

void GetRegStruct(char *signature, unsigned long offset, unsigned char *uBuffer, long size);

void StripCharactersFromStart(char *ll, const char *characters);

 

const long blockSize=4*1024;

const long blockCount=2;

const long bufferSize=blockSize*blockCount;

 

typedef struct LONGLONGSTRUCT {

 

      unsigned long low, high;

} longlong;

 

#if DOS

int wcslen(WCHAR *p) {

   int l=0;

 

   while(*p++) l++;

 

   return l;

}

 

void PrintWideString(WCHAR *p, long nChars, FILE *fp) {

 

  while(nChars--) {

 

      if(*p)

            fprintf(fp, "%c", *p);

 

      p++;

  }

}

 

typedef longlong FILETIME;

 

bool FileTimeToDosDateTime(FILETIME *, unsigned short *dosDate, unsigned short *dosTime) {

 

      return true;

}

 

#endif

 

typedef

struct HBINDATA {

 

      long dataBlockSize;  //this must be a multiple of 8

} hbindata;

 

typedef

struct HBIN {

      char headerText[sizeof(long)];

      long offsetFromFirstHBinBlock;

      long offsetToNextHBinBlock;

      long pad0[4];

      long blockSize;

 

} hbin;

 

unsigned long OFFSET(unsigned long o) {

 

      hbindata hbd={0};

      return o+blockSize+sizeof(hbd.dataBlockSize);

}

 

typedef

struct NK {

 

      char  headerText[2];

      short rootOrOtherwise;  //0x2c=root 0x20 otherwise.  0x10 for symbolic links.

      longlong writeDate;

      long  pad0[1];          //0x0

      long  ownerParentKeyOffset;

      long  numberOFSubKeys;

      long  pad1[1];          //0x0

      long  offsetToSubKeyLFRecords;

      long  pad2[1];          //0xffffffff  almost always

      long  numberOfValues;

      long  offsetToValueList;

      long  offsetToSKrecord;

      long  offsetToClassName; //can be -1 when no classname is specified

      long  longestSubkeySizex2;

      long  longestClassSizex2;

      long  longestVNameSizex2;

      long  longestValueSizex2;

      long  unknownIndex;

      short nameLength;

      short classNameLength;   //0 if offset -1

      char keyname[1];

 

} nk;

 

void PrintNK(nk *nkp, FILE *fp) {

 

      assert(!strncmp(nkp->headerText, "nk", sizeof(nkp->headerText)));

 

      fprintf(fp, "key <%.*s>,cnl %d, cno %ld  0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",

            nkp->nameLength, nkp->keyname,

            nkp->classNameLength, nkp->offsetToClassName,

            nkp->pad0[0], nkp->pad1[0], nkp->pad2[0],

            nkp->longestSubkeySizex2, nkp->longestClassSizex2,

            nkp->longestVNameSizex2, nkp->longestValueSizex2,

            nkp->unknownIndex

            );

 

}

 

typedef

struct VALUELIST {

      long offsetToValue[1];  //actual number of records in nk record

 

} valueList;

 

 

typedef

struct VK {  //value record

 

      char headerText[2];

      short nameLength;

      long lengthOfData;  //top bit set indicates data in place in offsetToData

      long offsetToData;

      long typeOfValue;

      short flag;         //bit 0 indicates a name is present. Otherwise default

      short trash;

      char ValueName[1];

 

} vk;

 

void PrintVK( vk *vkp, char *data, FILE *fp ) {

 

      assert(!strncmp(vkp->headerText, "vk", sizeof(vkp->headerText)));

 

      assert((vkp->lengthOfData & ~0x80000000L)>4 || (vkp->lengthOfData & 0x80000000L) == 0x80000000L);

 

      if(vkp->flag & 1) {

 

            fprintf(fp, "value: <%.*s> ", vkp->nameLength, vkp->ValueName);

      } else {

 

            fprintf(fp, "value: <Default> ");

      }

 

      fprintf(fp, "type is %ld. ", vkp->typeOfValue);

 

      long dataLen=vkp->lengthOfData & ~0x80000000L;

 

      switch(vkp->typeOfValue) {

      case REG_SZ:

      case REG_EXPAND_SZ:

            fprintf(fp, "len=%ld, ", dataLen);

#if DOS

      PrintWideString((WCHAR*)data, dataLen/sizeof(WCHAR), fp);

#else

              fprintf(fp, "%.*ls.",dataLen/sizeof(WCHAR), data);

#endif

            break;

      case REG_DWORD:

 

            fprintf(fp, "0x%lx.", *(unsigned long *)data);

            break;

      case REG_MULTI_SZ:

            {

                  int len;

                  WCHAR *p=(WCHAR *)data;

                  while((len=wcslen(p))) {

               fprintf(fp, "<");

#if DOS

                  PrintWideString(p, len, fp);

#else

                        fprintf(fp, "%.*ls", len, p);

#endif

               fprintf(fp, ">");

                        p+=len+1;

                  }

            }

            break;

      default:

            break;

      }

 

 

      fprintf(fp, "\n");

}

 

typedef

struct HASHRECORD {

      long offsetToNKRec;

      char keyname[4];  //padded with zeros, CASE SENSITIVE

} hashrecord;

 

void PrintHashRecord( hashrecord *hr, FILE *fp ) {

 

 

}

 

typedef

struct LF {

      char headerText[2];

      short numberOfKeys;

      struct HASHRECORD hashRecords[1];

} lf;

 

void PrintLF(lf *lfp, FILE *fp) {

 

      assert(!strncmp(lfp->headerText, "lf", sizeof(lfp->headerText)));

 

 

}

 

typedef

struct SK {

      char headerText[2];

      short trash;

      long offsetOfPreviousSKRec;

      long offsetOfNextSKRec;

      long usageCounter;            //reference count

      long sizeOfSKRecInBytes;

 

      SECURITY_DESCRIPTOR_RELATIVE sd;

 

} sk;

 

void PrintSID(PISID sidp, long size, FILE *fp) {

     

      fprintf(fp, "S-%x-%x", sidp->Revision, sidp->IdentifierAuthority.Value[sizeof(sidp->IdentifierAuthority)-1]);

     

      size-=(sizeof(*sidp)-sizeof(sidp->SubAuthority[0])*ANYSIZE_ARRAY);

     

      assert(size>=0);

     

      if(size<sidp->SubAuthorityCount*sizeof(sidp->SubAuthority[0])) {

           

            fprintf(fp, "-!");

           

            assert(!(size%sizeof(sidp->SubAuthority[0])));

           

            sidp->SubAuthorityCount=size/sizeof(sidp->SubAuthority[0]);

      }

     

      assert(sidp->SubAuthorityCount<=SID_MAX_SUB_AUTHORITIES);

     

      for(int i=0; i<sidp->SubAuthorityCount; i++) {

           

            //assert((char*)(sidp->SubAuthority+i)-(char *)skap < skap->AceSize);

           

            fprintf(fp, "-%x", sidp->SubAuthority[i]);

      }

     

      assert(sidp->Revision==SID_REVISION);

     

#if 0

      assert(

            sidp->IdentifierAuthority == SECURITY_NULL_SID_AUTHORITY    ||

            sidp->IdentifierAuthority == SECURITY_WORLD_SID_AUTHORITY   ||

            sidp->IdentifierAuthority == SECURITY_LOCAL_SID_AUTHORITY   ||

            sidp->IdentifierAuthority == SECURITY_CREATOR_SID_AUTHORITY ||

            sidp->IdentifierAuthority == SECURITY_NON_UNIQUE_AUTHORITY  ||

            sidp->IdentifierAuthority == SECURITY_NT_AUTHORITY

            );

#endif

}

 

void PrintACE(ACE_HEADER *skap, unsigned long size, FILE *fp) {

 

      fprintf(fp, "SKACE: typ=0x%02x,flgs=0x%02x,sz=0x%04x,",

                  skap->AceType,

                  skap->AceFlags,

                  skap->AceSize);

 

      assert(size>=skap->AceSize);

 

      //assert(skap->AceType>=ACCESS_MIN_MS_ACE_TYPE && skap->AceType<=ACCESS_MAX_MS_ACE_TYPE);

 

      switch(skap->AceType) {

 

      case ACCESS_ALLOWED_ACE_TYPE:

      case ACCESS_DENIED_ACE_TYPE:

      case SYSTEM_AUDIT_ACE_TYPE:

      case SYSTEM_ALARM_ACE_TYPE:

            {

                  PACCESS_ALLOWED_ACE acep=(PACCESS_ALLOWED_ACE)skap;

 

                  fprintf(fp, "access=0x%08x,", *(unsigned long *)&acep->Mask);

 

                  PISID sidp=(PISID)&acep->SidStart;

 

                  PrintSID(sidp, size-sizeof(*acep)+sizeof(acep->SidStart), fp);

 

#if 0

                  //check if specific rights map consistently

 

                  assert((acep->Mask & 0xffff0000)!=READ_CONTROL             || (acep->Mask & 0x0000ffff) == 0x0019);

                  assert((acep->Mask & 0xffff0000)!=STANDARD_RIGHTS_REQUIRED || (acep->Mask & 0x0000ffff) == 0x003f);

                  assert((acep->Mask & 0xffff0000)!=(DELETE | READ_CONTROL)  || (acep->Mask & 0x0000ffff) == 0x001f);

#endif

 

            }

            break;

      default:

 

            fprintf(fp, "Unexpected ACE type %d found.\n", skap->AceType);

 

            assert(false);

      }

}

 

void PrintACL(PACL aclp, unsigned long size, FILE *fp) {

     

      fprintf(fp, "ACL: rev %d, size %d, ace count %d.\n",          

            aclp->AclRevision,

            aclp->AclSize,

            aclp->AceCount);

 

      assert(size>=aclp->AclSize);

     

      ACE_HEADER *skap=(ACE_HEADER*)(aclp+1);

 

      size-=sizeof(*aclp);

 

      for(int i=0; i<aclp->AceCount; i++) {

 

            fprintf(fp, "[%03d]", i);

 

            PrintACE(skap, size, fp);

     

            if(i+1!=aclp->AceCount) {

           

                  fprintf(fp, ".\n");

            }

           

            skap=(ACE_HEADER*)(((char *)skap)+skap->AceSize);

 

            size-=skap->AceSize;

 

            assert((char *)skap - (char *)aclp <= aclp->AclSize);

      }

 

      assert(aclp->AclRevision==ACL_REVISION);

}

 

void PrintSD(PISECURITY_DESCRIPTOR_RELATIVE sdp, unsigned long size, FILE *fp) {

 

      fprintf(fp, "SD: rev %d, control 0x%04x,", sdp->Revision, (unsigned short)sdp->Control);

 

      assert((sdp->Control & SE_SELF_RELATIVE) == SE_SELF_RELATIVE);

      assert(sdp->Revision==SECURITY_DESCRIPTOR_REVISION);

 

      fprintf(fp, "own[%ld]=", sdp->Owner);

 

      if(sdp->Owner && size>=sdp->Owner) {

 

            assert(size>=sdp->Owner);

 

            PrintSID((PISID)(((char *)sdp)+(int)sdp->Owner), size-sdp->Owner, fp);

      } else {

 

            fprintf(fp, "<null-SID>");

      }

 

      fprintf(fp, ". grp[%ld]=",sdp->Group);

 

      if(sdp->Group && size>=sdp->Group) {

 

            assert(size>=sdp->Group);

 

            PrintSID((PISID)(((char *)sdp)+(int)sdp->Group), size-sdp->Group, fp);

      } else {

 

            fprintf(fp, "<null-SID>");

      }

 

      if((sdp->Control & SE_SACL_PRESENT) == SE_SACL_PRESENT) {

     

            fprintf(fp, ".\n");

            fprintf(fp, "SACL=");  

 

            if(sdp->Sacl) {

 

                  assert(size>=sdp->Sacl);

 

                  PrintACL((PACL)(((char *)sdp)+(int)sdp->Sacl), size-sdp->Sacl, fp);

            } else {

                  fprintf(fp, "<null-ACL>");    

            }

      }

 

      if((sdp->Control & SE_DACL_PRESENT) == SE_DACL_PRESENT) {

     

            fprintf(fp, ".\n");    

            fprintf(fp, "DACL=");

           

            if(sdp->Dacl) {

 

                  assert(size>=sdp->Dacl);

 

                  PrintACL((PACL)(((char *)sdp)+(int)sdp->Dacl), size-sdp->Dacl, fp);

            } else {

                  fprintf(fp, "<null-ACL>");    

            }

      }

}

 

void PrintSK(sk *skp, FILE *fp) {

 

      fprintf(fp, "SK: prev %ld, next %ld, reference count %ld, size %ld.\n",

            skp->offsetOfPreviousSKRec,

            skp->offsetOfNextSKRec,

            skp->usageCounter,

            skp->sizeOfSKRecInBytes);

 

      PrintSD(&skp->sd, skp->sizeOfSKRecInBytes-sizeof(*skp)+sizeof(skp->sd), fp);

 

      fprintf(fp, ".\n");

}

 

//Note that this structure is reproduced almost exactly in the .log file associated with the registry file

//The only difference is in the first byte of the two long fields following the header text.  This byte appears

//to be one less in the .log file and hence the checksum field is also different.

 

typedef

struct REGF {

      char headerText[sizeof(long)];

      long  unknown1;                     //these two fields contain a number the first byte of which is the only difference

      long  asUnknown1;                  

      longlong lastModified;

      long  one, three, zero, oneAgain;

      long offsetToFirstKey;

      long sizeOfDataBlocks;

      long oneAgainAgain;

      WCHAR filename[(0x200-13*sizeof(long))/sizeof(WCHAR)];      //UNICODE filename terminated with FFFFFFFF

      long checksum;

 

} regf;

 

char *DosDateTimeString(short date, short time) {

 

      static char tString[20];

 

      sprintf(tString,

            "%d/%d/%d %d:%d:%d",

            (date & 0x1f),

            (date & 0x1e0) >> 5,

            ((date & 0xfe00) >> 9) + 1980,

            (time & 0xf800) >> 11,

            (time & 0x7e0) >> 5,

            (time & 0x1f));

 

      return tString;

}

 

unsigned long CheckSumULong(long required, unsigned long *m, long size) {

 

      unsigned long checkSum=0;

 

      for(int i=0; i<size; i++) {

 

            checkSum^=m[i];

 

            printf("dword[%d]=0x%08lx, required=0x08%lx, checksum=0x%08lx, diff=0x%08lx\n",

                  i, m[i], required, checkSum, checkSum-required);

      }

 

      if(checkSum==0xffffffffL) {

 

            checkSum=0xfffffffeL;

      } else if (checkSum==0) {

 

            checkSum=1;

      }

 

      return checkSum;

}

 

void PrintRegf(regf *s, FILE *fp) {

 

      unsigned short dosDate, dosTime;

 

      //s->lastModified.low=0;

      //s->lastModified.high=0;

 

      unsigned long calculatedChecksum=CheckSumULong(s->checksum, ((unsigned long *)s), ((unsigned long*)&s->checksum)-((unsigned long *)s));

 

      assert((unsigned long)s->checksum==calculatedChecksum);

 

      if(!FileTimeToDosDateTime((FILETIME *)&s->lastModified, &dosDate, &dosTime)) {

 

 

 

      }

 

      fprintf(

            fp,

            "REGF Block:h<%.*s>, unknown 0x%lx, unknown 0x%lx, last mod %s, "

            "%ld, %ld, %ld, %ld, k@%ld, data size %ld, %ld, csum 0x%lx/0x%lx.\n",

            sizeof(s->headerText),

            s->headerText,

            s->unknown1,

            s->asUnknown1,

            DosDateTimeString(dosDate, dosTime),

            s->one, s->three, s->zero, s->oneAgain,

            s->offsetToFirstKey,

            s->sizeOfDataBlocks,

            s->oneAgainAgain,

            s->checksum,

            calculatedChecksum

      );

}

 

FILE *fp;

 

int OpenRegFileRead(char *filename) {

 

      if(!(fp=fopen(filename, "rb"))) {

 

 

            return 1;

      }

 

      return 0;

}

 

int OpenRegFileWrite(char *filename) {

 

      if(!(fp=fopen(filename, "r+b"))) {

 

 

            return 1;

      }

 

      return 0;

}

 

static int initialised;

 

static unsigned long readOffset;

 

static char buffer[bufferSize];

 

void GetRegStruct(char *signature, unsigned long offset, unsigned char *uBuffer, long size) {

 

      //break the file into pages then map them into the buffer as required

      //use two for now so that structures that cross the page boundary can be retrieved

      //a full blown memory map can come later

 

      assert(size<=bufferSize);

 

      if(!initialised || offset < readOffset || offset+size > readOffset+bufferSize) {

 

            /*long bytesRead;*/

 

            readOffset=(offset/blockSize)*blockSize;      //round offset down to the nearest block boundary

 

            initialised=1;

 

            if(fseek(fp, readOffset, SEEK_SET)) {

                  //seek failure

                  bool seek_failure_in_get=true;

 

         assert(!seek_failure_in_get);

            }

 

            /*bytesRead=*/

      fread(buffer, 1, bufferSize, fp);

 

            //assert(bytesRead==bufferSize);

            //assert(!feof(fp));

      }

 

      memcpy(uBuffer, buffer+(int)(offset-readOffset), (int)size);

 

      assert(!memcmp(uBuffer, signature, strlen(signature)));

}

 

void PutRegStruct(char *signature, unsigned long offset, const unsigned char *uBuffer, long size) {

 

      assert(!memcmp(uBuffer, signature, strlen(signature)));

 

      if(initialised && offset+size >= readOffset && offset <= readOffset+bufferSize) {

 

            initialised=0;  //force reread from disk

      }

 

      if(fseek(fp, offset, SEEK_SET)) {

 

            //seek failure

            bool seek_failure_in_put=true;

 

            assert(!seek_failure_in_put);

      }

 

      long bytesWritten=fwrite(uBuffer, 1, size, fp);

 

      assert(bytesWritten==size);

 

      if(offset>=blockSize) {

            UpdateRegMM(OffsetToHBin(offset-blockSize));

      }

}

 

typedef struct HBINLIST {

 

      long offset;

      long size;

      long largestFreeBlock;

 

} hbinlist;

 

typedef struct HBINMANAGE {

 

      int hBinCount;

      long dataSize;

      hbinlist *hBinList;

 

} hbinmanage;

 

static hbinmanage hBinManage;

 

long UpdateMMEntry(long hOffset, hbinlist *hblp) {

 

      //hOffset must be the offset to the bin from the first bin

 

      hbin hb;

      hbindata hbd;

 

      GetRegStruct("hbin", blockSize+hOffset, (unsigned char *)&hb, sizeof(hb));

 

      assert(hOffset==hb.offsetFromFirstHBinBlock);

 

      //assert(!hOffset || (hb.blockSize==hb.offsetToNextHBinBlock));  //Often true but not always!

 

      hblp->offset=hOffset;

      hblp->size=hb.offsetToNextHBinBlock;

 

      long nextHBin=hOffset+hb.offsetToNextHBinBlock;

      long largestFreeBlock=0;

 

      hOffset+=sizeof(hb);

 

      while(hOffset<nextHBin) {

 

            GetRegStruct("", blockSize+hOffset, (unsigned char *)&hbd, sizeof(hbd));

 

            if(hbd.dataBlockSize<0) {

 

                  hbd.dataBlockSize=-hbd.dataBlockSize;

 

            } else if(hbd.dataBlockSize>largestFreeBlock) {

 

                  largestFreeBlock=hbd.dataBlockSize;

            }

 

            hOffset+=hbd.dataBlockSize;

      }

 

      assert(hOffset==nextHBin);

 

      hblp->largestFreeBlock=largestFreeBlock;

 

      return hOffset;

}

 

void InitRegMM() {

 

      free(hBinManage.hBinList);

 

      regf  regf1;

      hbin  hb;

 

      //The first hbin block is situated after the first 'regf' block.

 

      long hOffset=0;

 

      hBinManage.hBinCount=0;

 

      GetRegStruct("regf", 0, (unsigned char *)&regf1, sizeof(regf1));

 

      long dataSize=regf1.sizeOfDataBlocks;

 

      while(hOffset<dataSize) {

 

            hBinManage.hBinCount++;

 

            GetRegStruct("hbin", blockSize+hOffset, (unsigned char *)&hb, sizeof(hb));

 

            assert(hOffset==hb.offsetFromFirstHBinBlock);

 

            //assert(!hOffset || (hb.blockSize==hb.offsetToNextHBinBlock));  //Often true but not always!

 

            hOffset+=hb.offsetToNextHBinBlock;

      }

 

      assert(hOffset==dataSize);

 

      long manageSize=sizeof(*hBinManage.hBinList)*hBinManage.hBinCount;

 

      hBinManage.hBinList=(hbinlist*)malloc(manageSize);

 

      memset(hBinManage.hBinList, 0, manageSize);

 

      hOffset=0;

      hBinManage.hBinCount=0;

 

      while(hOffset<dataSize) {

 

            hOffset=UpdateMMEntry(hOffset, hBinManage.hBinList+hBinManage.hBinCount++);

      }

 

      hBinManage.dataSize=dataSize;

 

      assert(hOffset==dataSize);

}

 

void UpdateRegMM(long hOffset) {

 

      long hBinCount=hBinManage.hBinCount;

      hbinlist *p=hBinManage.hBinList;

 

      for(int i=0;i<hBinCount;i++) {

 

            if(hOffset==p[i].offset) {

 

                  UpdateMMEntry(hOffset, p+i);

 

                  return;

            }

      }

 

      assert(false);

}

 

void AddHBin(long size) {

 

      //add a new hbin to the end of the file that can accomodate a structure of the given size

 

      assert(hBinManage.hBinList!=NULL);

 

      hbin hb;

      hbindata hbd;

 

      size+=sizeof(hbd.dataBlockSize)+sizeof(hb);

 

      long hBinSize=(size+blockSize-1)/blockSize*blockSize;

 

      long finalHBinOffset=hBinManage.hBinList[hBinManage.hBinCount-1].offset;

 

      finalHBinOffset+=hBinManage.hBinList[hBinManage.hBinCount-1].size;

 

      strncpy(hb.headerText, "hbin", sizeof(hb.headerText));

      hb.blockSize=hBinSize;

      hb.offsetFromFirstHBinBlock=finalHBinOffset;

      hb.offsetToNextHBinBlock=hBinSize;

 

      memset(hb.pad0, 'x', sizeof(hb.pad0));

 

      PutRegStruct("hbin", blockSize+finalHBinOffset, (unsigned char *)&hb, sizeof(hb));

 

      hbd.dataBlockSize=hBinSize-sizeof(hb);

 

      PutRegStruct("", blockSize+finalHBinOffset+sizeof(hb), (unsigned char *)&hbd, sizeof(hbd));

 

      PutRegStruct("", blockSize+finalHBinOffset+hBinSize-1, (unsigned char *)" ", 1);   //extend file as required

 

      //modify size in regf structure

 

      //modify modified date in regf structure?

 

      //reset checksum

 

      regf regf1;

 

      GetRegStruct("regf", 0, (unsigned char *)&regf1, sizeof(regf1));

 

      regf1.sizeOfDataBlocks+=hBinSize;

 

    regf1.checksum=CheckSumULong(0, (unsigned long*)&regf1, ((unsigned long *)&regf1.checksum)-((unsigned long *)&regf1));

 

      PutRegStruct("regf", 0, (unsigned char *)&regf1, sizeof(regf1));

 

      GetRegStruct("hbin", blockSize+0, (unsigned char *)&hb, sizeof(hb));

 

      //modify size in first hbin structure

 

      hb.blockSize=regf1.sizeOfDataBlocks;

 

      PutRegStruct("hbin", blockSize+0, (unsigned char *)&hb, sizeof(hb));

 

      InitRegMM();

}

 

long OffsetToHBin(long offset) {

 

      long hBinCount=hBinManage.hBinCount;

      hbinlist *p=hBinManage.hBinList;

 

      for(int i=0;i<hBinCount;i++) {

 

            if(offset>=p[i].offset && offset<=p[i].offset+p[i].size) {

 

                  return p[i].offset;

            }

      }

 

      assert(false);

 

      return -1;

}

 

long SizeOfEnclosingDataBlock(long offset) {

 

      long size;

 

      GetRegStruct("", blockSize+offset, (unsigned char *)&size, sizeof(size));

 

      assert((size%sizeof(longlong))==0);

 

      return size>=0?size:-size;

}

 

long FindFreeBlockInHBin(long hOffset, long size) {

 

      //size must include the size of hbindata

 

      hbin hb;

      hbindata hbd;

 

      GetRegStruct("hbin", blockSize+hOffset, (unsigned char *)&hb, sizeof(hb));

 

      assert(hOffset==hb.offsetFromFirstHBinBlock);

 

      //assert(!hOffset || (hb.blockSize==hb.offsetToNextHBinBlock));  //Often true but not always!

 

      long offset=-1;

 

      long smallestFit=0x7fffffffL;

 

      long nextHBin=hOffset+hb.offsetToNextHBinBlock;

 

      hOffset+=sizeof(hb);

 

      while(hOffset<nextHBin) {

 

            GetRegStruct("", blockSize+hOffset, (unsigned char *)&hbd, sizeof(hbd));

 

            if(hbd.dataBlockSize<0) {

 

                  hbd.dataBlockSize=-hbd.dataBlockSize;

 

            } else if(hbd.dataBlockSize>=size && hbd.dataBlockSize<smallestFit) {

 

                  offset=hOffset;  //return offset of hbin data block

                  smallestFit=hbd.dataBlockSize;

            }

 

            hOffset+=hbd.dataBlockSize;

      }

 

      assert(hOffset==nextHBin);

 

      assert(offset>=0);

 

      return offset;

}

 

long FindFreeBlock(long size) {

 

      //size must include the size of hbindata

 

      long hBinCount=hBinManage.hBinCount;

      long dataBlockOffset=-1;

      long smallestLargestFreeBlock=0x7fffffffL;

 

      hbinlist *p=hBinManage.hBinList;

 

      for(int i=0;i<hBinCount;i++) {

 

            if(p[i].largestFreeBlock >= size && p[i].largestFreeBlock < smallestLargestFreeBlock) {

 

                  dataBlockOffset=p[i].offset;

                  smallestLargestFreeBlock=p[i].largestFreeBlock;

            }

      }

 

      if(dataBlockOffset>=0) {

 

            //find the smallest free block in the bin that is larger than size

 

            dataBlockOffset=FindFreeBlockInHBin(dataBlockOffset, size);

      }

 

      return dataBlockOffset;

}

 

void AllocateFreeBlock(long offset, long size) {

 

      //size must include the hbindata

      //take the +ve size entry and make -ve

 

      hbindata hbd;

 

      GetRegStruct("", blockSize+offset, (unsigned char *)&hbd, sizeof(hbd));

 

      long prevSize=hbd.dataBlockSize;

 

      assert(prevSize>=size);

 

      if(prevSize-size>sizeof(hbd.dataBlockSize) && (prevSize-size)%sizeof(longlong)==0) {

 

            hbd.dataBlockSize=prevSize-size;

 

            PutRegStruct("", blockSize+offset+size, (unsigned char *)&hbd, sizeof(hbd));

 

            hbd.dataBlockSize=-size;

 

      } else {

 

            hbd.dataBlockSize=-hbd.dataBlockSize;

      }

 

      PutRegStruct("", blockSize+offset, (unsigned char *)&hbd, sizeof(hbd));

}

 

void DeAllocateInUseBlock(long offset) {

 

      //take the -ve size entry and make +ve

 

      hbindata hbd;

 

      GetRegStruct("", blockSize+offset, (unsigned char *)&hbd, sizeof(hbd));

 

      assert(hbd.dataBlockSize<0);

 

      hbd.dataBlockSize=-hbd.dataBlockSize;

 

      PutRegStruct("", blockSize+offset, (unsigned char *)&hbd, sizeof(hbd));

}

 

void MergeFreeAreas(long hOffset) {

 

      //loop over all areas an hbin and merge any that are adjacent

 

      hbin hb;

      hbindata hbd, hbdSave;

 

      GetRegStruct("hbin", blockSize+hOffset, (unsigned char *)&hb, sizeof(hb));

 

      assert(hOffset==hb.offsetFromFirstHBinBlock);

 

      //assert(!hOffset || (hb.blockSize==hb.offsetToNextHBinBlock));  //Often true but not always!

 

      long nextHBin=hOffset+hb.offsetToNextHBinBlock;

 

      long lastFreeDataBlock=-1;

 

      hOffset+=sizeof(hb);

 

      while(hOffset<nextHBin) {

 

            GetRegStruct("", blockSize+hOffset, (unsigned char *)&hbd, sizeof(hbd));

 

            if(hbd.dataBlockSize<0) {

 

                  lastFreeDataBlock=-1;

                  hbd.dataBlockSize=-hbd.dataBlockSize;

 

            } else if(lastFreeDataBlock>=0) {

 

                  hbdSave.dataBlockSize+=hbd.dataBlockSize;

                  PutRegStruct("", blockSize+lastFreeDataBlock, (unsigned char *)&hbdSave, sizeof(hbdSave));

 

            } else {

 

                  hbdSave=hbd;

                  lastFreeDataBlock=hOffset;

            }

 

            hOffset+=hbd.dataBlockSize;

      }

 

      assert(hOffset==nextHBin);

 

}

 

long AllocateRegStruct(long size) {

 

      //look for existing unused space that is large enough

      //if there is none then add another hbin to the end of the heap

      //update regf (including checksum) and the first hbin which contains the total size in its

      //blockSize field.

      //allocate the space creating a new data block and adjusting the existing one.

      //return the offset to this structure

 

      hbindata hbd={0};

 

      size+=sizeof(hbd.dataBlockSize);

 

      size=(size+sizeof(longlong)-1)/sizeof(longlong)*sizeof(longlong);

 

      long offset;

 

      assert(hBinManage.hBinList!=NULL);

 

      if((offset=FindFreeBlock(size))<0) {

 

            AddHBin(size);

 

            assert((offset=FindFreeBlock(size))>=0);

      }

 

      AllocateFreeBlock(offset, size);

 

      UpdateRegMM(OffsetToHBin(offset));

 

      return offset;

}

 

void DeAllocateRegStruct(long offset) {

 

      //find bin containing this data

      //mark data block as free

      //merge block with adjacent blocks in the hbin

 

      assert(hBinManage.hBinList!=NULL);

 

      long hOffset=OffsetToHBin(offset);

 

      DeAllocateInUseBlock(offset);

 

      MergeFreeAreas(hOffset);

 

      UpdateRegMM(hOffset);

}

 

long ReAllocateRegStruct(long offset, long newSize) {

 

      //find the size of the structures enclosing data block

      //if that size is sufficient to enclose the newSize then return the

      //original offset

 

      //otherwise:

      //deallocate the structure

      //allocate a new one

 

      //newSize=(newSize+sizeof(unsigned long)-1)/sizeof(unsigned long)*sizeof(unsigned long);

 

      hbindata hbd={0};

 

      assert(hBinManage.hBinList!=NULL);

 

      long growSize=SizeOfEnclosingDataBlock(offset)-sizeof(hbd.dataBlockSize);

 

      if(growSize>=newSize) {

 

            return offset;

      }

 

      long newOffset=AllocateRegStruct(newSize);

 

      unsigned char *p=(unsigned char *)malloc(growSize);

 

      assert(p!=NULL);

 

      GetRegStruct("", OFFSET(offset), p, growSize);

 

      PutRegStruct("", OFFSET(newOffset), p, growSize);

 

      DeAllocateRegStruct(offset);

 

      free(p);

 

      return newOffset;

}

 

typedef

struct SIZEPAIR {

      unsigned long s1, s2;

} sizepair;

 

void EnumerateReg(long nkOffset, sizepair *ssSizes, FILE *fp);

 

void EnumerateRegSubKeys(long lfOffset, sizepair *sSizes, FILE *fp) {

 

      lf lf1;

      long sizeoflf;

 

      sSizes->s1=0;

      sSizes->s2=0;

 

      if(lfOffset<0) {

 

            return;

      }

 

      GetRegStruct("lf", OFFSET(lfOffset), (unsigned char *)&lf1, sizeof(lf1));

 

      sizeoflf=sizeof(lf1)+(lf1.numberOfKeys?lf1.numberOfKeys-1:0)*sizeof(lf1.hashRecords[0]);

 

      lf *lfp=(lf *)malloc(sizeoflf);

 

      GetRegStruct("lf", OFFSET(lfOffset), (unsigned char *)lfp, sizeoflf);

 

      PrintLF(lfp, fp);

 

      {

            int i;

            long nok=lfp->numberOfKeys;

 

            for(i=0;i<nok;i++) {

 

                  long offsetToNKRec = lfp->hashRecords[i].offsetToNKRec;

 

                  PrintHashRecord(lfp->hashRecords+i, fp);

 

                  fprintf(

                        fp,

                        "hash record key <%.*s>.\n",

                        sizeof(lfp->hashRecords[i].keyname),

                        lfp->hashRecords[i].keyname

                        );

 

                  if(i) {

 

                        //subkeys are sorted low to high

 

                        assert(sizeof(lfp->hashRecords[i].keyname)==4);

                        assert(strnicmp(lfp->hashRecords[i-1].keyname, lfp->hashRecords[i].keyname, sizeof(lfp->hashRecords[i].keyname))<=0);

                  }

 

                  free(lfp);  //don't leave it around hogging memory while we enumerate subtree

 

                  sizepair ssSizes;

 

                  EnumerateReg(offsetToNKRec, &ssSizes, fp);

 

                  if(ssSizes.s1>sSizes->s1) {

 

                        sSizes->s1=ssSizes.s1;

                  }

 

                  if(ssSizes.s2>sSizes->s2) {

 

                        sSizes->s2=ssSizes.s2;

                  }

 

                  lfp=(lf *)malloc(sizeoflf);

 

                  GetRegStruct("lf", OFFSET(lfOffset), (unsigned char *)lfp, sizeoflf);

            }

 

      }

 

      free(lfp);

}

 

void EnumerateValues(long valueListOffset, long numberOfValues, sizepair *vSizes, FILE *fp) {

 

      int i;

      long sizeofvl=sizeof(valueList)*numberOfValues;

      valueList *vlp;

 

      vSizes->s1=0;

      vSizes->s2=0;

 

      if(!numberOfValues) {

 

            return;

      }

 

      vlp=(valueList*)malloc(sizeofvl);

 

      GetRegStruct("", OFFSET(valueListOffset), (unsigned char *)vlp, sizeofvl);

 

      for(i=0; i<numberOfValues; i++) {

 

            long sizeofvk, sizeofvkd;

            vk vk1, *vkp;

 

            GetRegStruct("vk", OFFSET(vlp->offsetToValue[i]), (unsigned char *)&vk1, sizeof(vk1));

 

            if(vk1.nameLength*sizeof(WCHAR)>vSizes->s1) {

 

                  vSizes->s1=vk1.nameLength*sizeof(WCHAR);

            }

 

            bool dataInPlace=(vk1.lengthOfData & 0x80000000L) == 0x80000000L;

            unsigned long dataLen=vk1.lengthOfData & ~0x80000000L;

 

            if(dataLen>vSizes->s2) {

 

                  vSizes->s2=dataLen;

            }

 

            sizeofvk=sizeof(vk)+(vk1.nameLength>0?vk1.nameLength-1:0);

 

            if(dataInPlace) {  //REG_DWORD

 

                  vk1.lengthOfData=0;

            }

 

            sizeofvkd=sizeofvk+ (vk1.lengthOfData>0?vk1.lengthOfData:0);

 

            vkp=(vk*)malloc(sizeofvkd);

 

            GetRegStruct("vk", OFFSET(vlp->offsetToValue[i]), (unsigned char *)vkp, sizeofvk);

 

            if(dataInPlace) {  //REG_DWORD

 

                  PrintVK(vkp, (char *)&vkp->offsetToData, fp);

            } else {

 

                  GetRegStruct("", OFFSET(vkp->offsetToData), ((unsigned char *)vkp)+sizeofvk, (vkp->lengthOfData>0?vkp->lengthOfData:0));

 

                  PrintVK(vkp, ((char *)vkp)+sizeofvk, fp);

            }

 

            free(vkp);

      }

 

      free(vlp);

}

 

bool CheckSKLinkage(long skOffset, FILE *fp) {

 

      //check whether this record is in the list rooted at the root key

 

      regf regf1;

 

      nk nk1;

 

      sk sk1;

 

      GetRegStruct("regf", 0, (unsigned char *)&regf1, sizeof(regf1));

 

      GetRegStruct("nk", OFFSET(regf1.offsetToFirstKey), (unsigned char *)&nk1, sizeof(nk1));

 

      long skRoot=nk1.offsetToSKrecord;

      long ski=skRoot;

      bool found=false;

 

      do {

 

            GetRegStruct("sk", OFFSET(ski), (unsigned char *)&sk1, sizeof(sk1));

 

            sk *skp=(sk*)malloc(sk1.sizeOfSKRecInBytes);

 

            GetRegStruct("sk", OFFSET(ski), (unsigned char *)skp, sk1.sizeOfSKRecInBytes);

 

            free(skp);

 

            found=(ski==skOffset);

 

            ski=sk1.offsetOfNextSKRec;

 

      } while(!found && ski!=skRoot);

 

      return found;

}

 

void EnumerateSecurity(long skOffset, FILE *fp) {

 

      sk sk1;

 

      GetRegStruct("sk", OFFSET(skOffset), (unsigned char *)&sk1, sizeof(sk1));

 

      sk *skp=(sk*)malloc(sk1.sizeOfSKRecInBytes);

 

      GetRegStruct("sk", OFFSET(skOffset), (unsigned char *)skp, sk1.sizeOfSKRecInBytes);

 

      PrintSK(skp, fp);

 

      assert(CheckSKLinkage(skOffset, fp));

 

      free(skp);

}

 

void EnumerateReg(long nkOffset, sizepair *ssSizes, FILE *fp) {

 

      nk *nkp;

      nk nk1;

      long sizeofnk;

      long offsetToSubKeyLFRecords;

 

      sizepair vSizes, sSizes;

 

   ssSizes->s1=0;

   ssSizes->s2=0;

 

      if(nkOffset<0) {

 

            return;

      }

 

      GetRegStruct("nk", OFFSET(nkOffset), (unsigned char *)&nk1, sizeof(nk1));

 

      sizeofnk=sizeof(nk1)+(nk1.nameLength?nk1.nameLength-1:0);

 

      nkp=(nk *)malloc(sizeofnk);

 

      GetRegStruct("nk", OFFSET(nkOffset), (unsigned char *)nkp, sizeofnk);

 

      PrintNK(nkp, fp);

 

      ssSizes->s1=nkp->nameLength*sizeof(WCHAR);

      if(!ssSizes->s1) {

 

            ssSizes->s1=sizeof(WCHAR);

      }

 

      ssSizes->s2=nkp->classNameLength;

 

      EnumerateSecurity(nkp->offsetToSKrecord, fp);

 

      EnumerateValues(nkp->offsetToValueList, nkp->numberOfValues, &vSizes, fp);

 

   fprintf(fp, "value size 0x%lx/0x%lx 0x%lx/0x%lx\n",

      nkp->longestVNameSizex2,

      nkp->longestValueSizex2,

      vSizes.s1,

      vSizes.s2);

 

      assert(nkp->longestVNameSizex2 >= vSizes.s1);

      assert(nkp->longestValueSizex2 >= vSizes.s2);

 

      offsetToSubKeyLFRecords=nkp->offsetToSubKeyLFRecords;

 

      EnumerateRegSubKeys(offsetToSubKeyLFRecords, &sSizes, fp);

 

   fprintf(fp, "key size 0x%lx/0x%lx 0x%lx/0x%lx\n",

      nkp->longestSubkeySizex2,

      nkp->longestClassSizex2,

      sSizes.s1,

      sSizes.s2);

 

      assert(nkp->longestSubkeySizex2 >= sSizes.s1);

      assert(nkp->longestClassSizex2 >= sSizes.s2);

 

      free(nkp);

 

}

 

void EnumerateAvailableDataAreas(FILE *fp) {

 

      hbin  hb;

      hbindata hbd;

      regf     regf1;

 

      long largestBlockInUse=0, inUseBlockCount=0;

      long freeSpace=0, largestFreeBlock=0, freeBlockCount=0;

      long dataSize=0;

 

      //The first hbin block is situated after the first 'regf' block.

 

      long hOffset=0;

 

      GetRegStruct("regf", 0, (unsigned char *)&regf1, sizeof(regf));

 

      dataSize=regf1.sizeOfDataBlocks;

 

      fprintf(fp, "Data size %ld.\n", dataSize);

 

      while(hOffset<dataSize) {

 

            GetRegStruct("hbin", blockSize+hOffset, (unsigned char *)&hb, sizeof(hb));

 

            fprintf(fp, "HBIN: header <%.*s>, this %ld, first %ld, next %ld, %lx-%lx-%lx-%lx, size %ld.\n",

                  sizeof(hb.headerText),

                  hb.headerText,

                  hOffset,

                  hb.offsetFromFirstHBinBlock,

                  hb.offsetToNextHBinBlock,

                  hb.pad0[0], hb.pad0[1], hb.pad0[2], hb.pad0[3],

                  hb.blockSize

                  );

 

            assert(hOffset==hb.offsetFromFirstHBinBlock);

 

            //assert(!hOffset || (hb.blockSize==hb.offsetToNextHBinBlock));  //Often true but not always!

 

            long nextHBin=hOffset+hb.offsetToNextHBinBlock;

 

            hOffset+=sizeof(hb);

 

            while(hOffset < nextHBin) {

 

                  bool free=true;

 

                  GetRegStruct("", blockSize+hOffset, (unsigned char *)&hbd, sizeof(hbd));

 

                  if(hbd.dataBlockSize<0) {

 

                        inUseBlockCount++;

 

                        free=false;

                        hbd.dataBlockSize=-hbd.dataBlockSize;

 

                        if(hbd.dataBlockSize>largestBlockInUse) {

 

                              largestBlockInUse=hbd.dataBlockSize;

                        }

 

                  } else {

 

                        freeBlockCount++;

                        freeSpace+=hbd.dataBlockSize-sizeof(hbd.dataBlockSize);

 

                        if(hbd.dataBlockSize>largestFreeBlock) {

 

                              largestFreeBlock=hbd.dataBlockSize;

                        }

 

                        fprintf(fp, "%s block @%ld, size %ld\n", free?"   FREE":"NONFREE", hOffset, hbd.dataBlockSize);

                  }

 

                  hOffset+=hbd.dataBlockSize;

            }

 

      }

 

      assert(hOffset==dataSize);

 

      fprintf(fp,

                  "total data %ld, "

                  "free space %ld, "

                  "nfree blocks %ld, "

                  "lfree block %ld, "

                  "ninuse blocks %ld, "

                  "linuse block %ld\n",

                  dataSize,

                  freeSpace,

                  freeBlockCount,

                  largestFreeBlock,

                  inUseBlockCount,

                  largestBlockInUse

                  );

}

 

typedef struct _SDRDESC {

 

      unsigned long size;

      PISECURITY_DESCRIPTOR_RELATIVE sdp;

} SDRDESC, *PSDRDESC;

 

unsigned long GetACLAceCount(PACL pacl) {

 

      assert(pacl->AclRevision==ACL_REVISION);

 

      return pacl->AceCount;

}

 

PACE_HEADER GetACLNextAce(PACL pacl, unsigned long &context) {

 

      assert(pacl->AclRevision==ACL_REVISION);

 

      if(!context) {

 

            context+=sizeof(*pacl);

      }

 

      if(context>=pacl->AclSize) {

 

            return NULL;

      }

 

      PACE_HEADER pace=(PACE_HEADER)(((char *)pacl)+context);

 

      context+=pace->AceSize;

 

      return pace;

}

 

unsigned long GetSIDSize(PISID sidp) {

 

      assert(sidp->Revision==SID_REVISION);

 

      return       sizeof(*sidp)+(sidp->SubAuthorityCount-ANYSIZE_ARRAY)*sizeof(sidp->SubAuthority[0]);

}

 

typedef

struct _SIDDESC {

 

      PISID sidp;

      unsigned long size;

} SIDDESC;

 

SIDDESC GetSDOwner(PSDRDESC sddp) {

 

      SIDDESC sidd;

 

      sidd.sidp=NULL;

      sidd.size=0;

 

      unsigned long end=sddp->sdp->Group>sddp->sdp->Owner?sddp->sdp->Group:sddp->size;

 

      if(sddp->sdp->Owner && sddp->sdp->Owner<end) {

 

            sidd.sidp=(PISID)(((char *)sddp->sdp)+sddp->sdp->Owner);

 

            sidd.size=GetSIDSize(sidd.sidp);

 

            if(sddp->sdp->Owner+sidd.size>end) {

 

                  sidd.size=end-sddp->sdp->Owner;

            }

      }

 

      return sidd;

}

 

SIDDESC GetSDGroup(PSDRDESC sddp) {

 

      SIDDESC sidd;

 

      sidd.sidp=NULL;

      sidd.size=0;

 

      unsigned long end=sddp->size;

 

      if(sddp->sdp->Group && sddp->sdp->Group<end) {

 

            sidd.sidp=(PISID)(((char *)sddp->sdp)+sddp->sdp->Group);

 

            sidd.size=GetSIDSize(sidd.sidp);

 

            if(sddp->sdp->Group+sidd.size>end) {

 

                  sidd.size=end-sddp->sdp->Group;

            }

      }

 

      return sidd;

}

 

PACL GetSDDACL(PSDRDESC sddp) {

 

      if((sddp->sdp->Control & SE_DACL_PRESENT) != SE_DACL_PRESENT) {

 

            return NULL;

      }

 

      if(!sddp->sdp->Dacl) {

 

            return NULL;

      }

 

      PACL pacl=(PACL)(((char *)sddp->sdp)+sddp->sdp->Dacl);

 

      assert(pacl->AclRevision==ACL_REVISION);

 

      assert(sddp->sdp->Dacl+pacl->AclSize<=sddp->size);

 

      return pacl;

}

 

PACL GetSDSACL(PSDRDESC sddp) {

 

      if((sddp->sdp->Control & SE_SACL_PRESENT) != SE_SACL_PRESENT) {

 

            return NULL;

      }

 

      if(!sddp->sdp->Sacl) {

 

            return NULL;

      }

 

      PACL pacl=(PACL)(((char *)sddp->sdp)+sddp->sdp->Sacl);

 

      assert(pacl->AclRevision==ACL_REVISION);

 

      assert(sddp->sdp->Sacl+pacl->AclSize<=sddp->size);

 

      return pacl;

}

 

bool IsEqualSID(SIDDESC sidd1, SIDDESC sidd2) {

 

      return ((!sidd1.sidp && !sidd2.sidp) || (sidd1.sidp && sidd2.sidp && sidd1.size==sidd2.size && !memcmp(sidd1.sidp, sidd2.sidp, sidd1.size)));

}

 

unsigned long GetACLSize(PACL pacl) {

 

      assert(pacl->AclRevision==ACL_REVISION);

 

      unsigned long size=sizeof(*pacl);

 

      unsigned long context=0;

      unsigned long aceCount=GetACLAceCount(pacl);

 

      PACE_HEADER pace;

 

      while(aceCount-- && (pace=GetACLNextAce(pacl, context))) {

 

            size+=pace->AceSize;

      }

 

      return size;

}

 

bool IsEqualACL(PACL pacl1, PACL pacl2) {

 

      unsigned long s1=pacl1?GetACLSize(pacl1):0;

      unsigned long s2=pacl2?GetACLSize(pacl2):0;

 

      return ((!pacl1 && !pacl2) || (pacl1 && pacl2 && s1 == s2 && !memcmp(pacl1, pacl2, s1)));

}

 

bool IsEqualSDOwner(PSDRDESC sddp1, PSDRDESC sddp2) {

 

      return IsEqualSID(GetSDOwner(sddp1), GetSDOwner(sddp2));

}

bool IsEqualSDGroup(PSDRDESC sddp1, PSDRDESC sddp2) {

 

      return IsEqualSID(GetSDGroup(sddp1), GetSDGroup(sddp2));

}

bool IsEqualSDSACL(PSDRDESC sddp1, PSDRDESC sddp2) {

 

      return IsEqualACL(GetSDSACL(sddp1), GetSDSACL(sddp2));

}

bool IsEqualSDDACL(PSDRDESC sddp1, PSDRDESC sddp2) {

 

      return IsEqualACL(GetSDDACL(sddp1), GetSDDACL(sddp2));

}

 

bool IsEqualSD(PSDRDESC sddp1, PSDRDESC sddp2) {

 

      return IsEqualSDOwner(sddp1, sddp2) &&

               IsEqualSDGroup(sddp1, sddp2) &&

               IsEqualSDSACL(sddp1, sddp2) &&

               IsEqualSDDACL(sddp1, sddp2);

}

 

PACL InheritACL(PACL pacl) {

 

      //if an ace is inheritable then create two aces.

      //one inherit only and the other local

      //inherit a single copy of creator owner aces

      //add an all access allowed ace for the admin group

 

      PACL paclNew=NULL;

 

      assert(pacl->AclRevision==ACL_REVISION);

 

      unsigned long size=sizeof(*pacl);

 

      unsigned long context=0;

      unsigned long aceCount=GetACLAceCount(pacl);

 

      SID_IDENTIFIER_AUTHORITY creatorAuthority=SECURITY_CREATOR_SID_AUTHORITY;

      SID_IDENTIFIER_AUTHORITY ntAuthority     =SECURITY_NT_AUTHORITY;

 

      PISID sidp;

 

      unsigned long sizeOfAdministratorsAce=sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD)+sizeof(*sidp)+(2-ANYSIZE_ARRAY)*sizeof(sidp->SubAuthority[0]);

 

      PACE_HEADER pace;

 

      bool dacl=true;

      unsigned long inheritedAceCount=0;

 

      while(aceCount-- && (pace=GetACLNextAce(pacl, context))) {

 

            if((pace->AceFlags & CONTAINER_INHERIT_ACE) != CONTAINER_INHERIT_ACE) {

 

                  continue;

            }

 

            if((pace->AceFlags & NO_PROPAGATE_INHERIT_ACE) == NO_PROPAGATE_INHERIT_ACE) {

 

                  continue;

            }

 

            inheritedAceCount++;

            size+=pace->AceSize;

 

            assert(pace->AceType==ACCESS_ALLOWED_ACE_TYPE ||

                     pace->AceType==ACCESS_DENIED_ACE_TYPE ||

                     pace->AceType==SYSTEM_AUDIT_ACE_TYPE ||

                     pace->AceType==SYSTEM_ALARM_ACE_TYPE);

 

            if(pace->AceType==SYSTEM_AUDIT_ACE_TYPE ||      pace->AceType==SYSTEM_ALARM_ACE_TYPE) {

 

                  dacl=false;

            }

 

            sidp=(PISID)&((ACCESS_ALLOWED_ACE*)pace)->SidStart;

 

            if(!memcmp(&sidp->IdentifierAuthority, &creatorAuthority, sizeof(sidp->IdentifierAuthority))) {

 

                  if(dacl) {

                        size+=sizeOfAdministratorsAce; //make room for S-1-5-20-220

                        inheritedAceCount++;

                  }

 

                  continue;

            }

 

            //add another which is not iherited

 

            inheritedAceCount++;

            size+=pace->AceSize;

      }

 

      if(!inheritedAceCount) {

 

            return paclNew;

      }

 

      unsigned long requiredSize=size;

 

      size=(requiredSize+255)/256*256;

 

      paclNew=(PACL)malloc(size);

 

      *paclNew=*pacl;

 

      paclNew->AceCount=0;

      paclNew->AclSize=(unsigned short)size;

 

      context=0;

      aceCount=GetACLAceCount(pacl);

 

      size=sizeof(*pacl);

 

      PACE_HEADER lpace, creatorAce=NULL;

 

      while(aceCount-- && (pace=GetACLNextAce(pacl, context))) {

 

            if((pace->AceFlags & CONTAINER_INHERIT_ACE) != CONTAINER_INHERIT_ACE) {

 

                  continue;

            }

 

            if((pace->AceFlags & NO_PROPAGATE_INHERIT_ACE) == NO_PROPAGATE_INHERIT_ACE) {

 

                  continue;

            }

 

            assert(pace->AceType==ACCESS_ALLOWED_ACE_TYPE ||

                     pace->AceType==ACCESS_DENIED_ACE_TYPE ||

                     pace->AceType==SYSTEM_AUDIT_ACE_TYPE ||

                     pace->AceType==SYSTEM_ALARM_ACE_TYPE);

 

            sidp=(PISID)&((ACCESS_ALLOWED_ACE*)pace)->SidStart;

 

            if(!memcmp(&sidp->IdentifierAuthority, &creatorAuthority, sizeof(sidp->IdentifierAuthority))) {

 

                  creatorAce=pace;

                  continue;

            }

 

            //add copy of ace with AceFlags set to 00

 

            lpace=(PACE_HEADER)(((char *)paclNew)+size);

 

            memcpy(lpace, pace, pace->AceSize);

 

            lpace->AceFlags&=~VALID_INHERIT_FLAGS;

 

            paclNew->AceCount++;

            size+=lpace->AceSize;

 

            //add copy of ace with AceFlags set to 0a

 

            lpace=(PACE_HEADER)(((char *)paclNew)+size);

 

            memcpy(lpace, pace, pace->AceSize);

 

            lpace->AceFlags|=INHERIT_ONLY_ACE;

 

            paclNew->AceCount++;

            size+=lpace->AceSize;

      }

 

      if(creatorAce) {

 

            if(dacl) {

                  //add full access to S-1-5-20-220

 

                  ACCESS_ALLOWED_ACE *aaace=(ACCESS_ALLOWED_ACE *)(((char *)paclNew)+size);

 

                  aaace->Header.AceType =ACCESS_ALLOWED_ACE_TYPE;

                  aaace->Header.AceFlags=0;

                  aaace->Header.AceSize =(unsigned short)sizeOfAdministratorsAce;

 

                  //this mapping is taken from observation.

 

                  aaace->Mask=(STANDARD_RIGHTS_REQUIRED | STANDARD_SPECIFIC_RIGHTS_REQUIRED);

 

                  sidp=(PISID)&aaace->SidStart;

 

                  sidp->Revision=SID_REVISION;

                  sidp->IdentifierAuthority=ntAuthority;

                  sidp->SubAuthorityCount=2;

                  sidp->SubAuthority[0]=SECURITY_BUILTIN_DOMAIN_RID;

                  sidp->SubAuthority[1]=DOMAIN_ALIAS_RID_ADMINS;

 

                  paclNew->AceCount++;

                  size+=aaace->Header.AceSize;

            }

 

            //add creator if present

 

            lpace=(PACE_HEADER)(((char *)paclNew)+size);

 

            memcpy(lpace, creatorAce, creatorAce->AceSize);

 

            lpace->AceFlags|=INHERIT_ONLY_ACE;

 

            paclNew->AceCount++;

            size+=lpace->AceSize;

      }

 

      assert(size==requiredSize);

 

      return paclNew;

}

 

void SDMemcpy(void *dst, unsigned long offset, void *src, unsigned long size) {

 

      memcpy(((char *)dst)+offset, src, size);

}

 

PSDRDESC InheritSD(PSDRDESC sddp) {

 

      //create a security descriptor

      //inheriting acls from the sd passed in sddp.

      //if an ace is inheritable then create two aces.

      //one inherit only and the other local

      //inherit a single copy of creator owner aces

      //add an all acc ess allowed ace for the admin group

 

      //add admin group + creator owner at end of acl

 

      //inherit owner/group also

 

      PACL psacl=GetSDSACL(sddp), psaclNew=NULL;

      PACL pdacl=GetSDDACL(sddp), pdaclNew=NULL;

 

      if(psacl) {

 

            psaclNew=InheritACL(psacl);

      }

 

      if(pdacl) {

 

            pdaclNew=InheritACL(pdacl);

      }

 

      SIDDESC OwnerSid=GetSDOwner(sddp);

      SIDDESC GroupSid=GetSDGroup(sddp);

 

      PSDRDESC sddp1=(PSDRDESC)malloc(sizeof(*sddp1));

 

      unsigned long requiredSize=

            sizeof(*sddp1->sdp)+

            (psaclNew?psaclNew->AclSize:0)+

            (pdaclNew?pdaclNew->AclSize:0)+

            OwnerSid.size+

            GroupSid.size;

 

      sddp1->size=requiredSize;

 

      sddp1->sdp=(PISECURITY_DESCRIPTOR_RELATIVE)malloc(sddp1->size);

 

      *sddp1->sdp = *sddp->sdp;

 

      unsigned long offset=sizeof(*sddp1->sdp), size;

 

      if(psaclNew) {

 

            size=psaclNew->AclSize;

            sddp1->sdp->Sacl=offset;

            SDMemcpy(sddp1->sdp, offset, psaclNew, size);

            offset+=size;

      } else {

 

            sddp1->sdp->Sacl=0;

      }

 

      if(pdaclNew) {

 

            size=pdaclNew->AclSize;

            sddp1->sdp->Dacl=offset;

            SDMemcpy(sddp1->sdp, offset, pdaclNew, size);

            offset+=size;

      } else {

 

            sddp1->sdp->Dacl=0;

      }

 

      if(OwnerSid.size) {

 

            size=OwnerSid.size;

            sddp1->sdp->Owner=offset;

            SDMemcpy(sddp1->sdp, offset, OwnerSid.sidp, size);

            offset+=size;

      } else {

 

            sddp1->sdp->Owner=0;

      }

 

      if(GroupSid.size) {

 

            size=GroupSid.size;

            sddp1->sdp->Group=offset;

            SDMemcpy(sddp1->sdp, offset, GroupSid.sidp, size);

            offset+=size;

      } else {

 

            sddp1->sdp->Group=0;

      }

 

      assert(offset==requiredSize);

 

      free(psaclNew);

      free(pdaclNew);

 

      return sddp1;

}

 

unsigned long FindSK(unsigned long skOffset, PSDRDESC sddp1) {

 

      sk sk1, *skp;

 

      unsigned long ski=0xffffffffL;

 

      while(ski!=skOffset) {

 

            if(ski==0xffffffffL) {

 

                  ski=skOffset;

            }

 

            GetRegStruct("sk", OFFSET(ski), (unsigned char *)&sk1, sizeof(sk1));

 

            skp=(sk *)malloc(sk1.sizeOfSKRecInBytes);

           

            GetRegStruct("sk", OFFSET(ski), (unsigned char *)skp, sk1.sizeOfSKRecInBytes);

 

            SDRDESC sdd2;

 

            sdd2.sdp =&skp->sd;

            sdd2.size=skp->sizeOfSKRecInBytes-sizeof(*skp)+sizeof(skp->sd);

 

            if(IsEqualSD(sddp1, &sdd2)) {

 

                  free(skp);

                  return ski;

            }

 

            free(skp);

 

            ski=sk1.offsetOfNextSKRec;

      }

 

      return 0;

}

 

unsigned long GetSkRecord(unsigned long offsetToParentSK) {

 

      //look at parent's record. If this contains only records with the CONTAINER_INHERIT_ set

      //then look for an sk record which has each key inherited to a non-inheritable entry and an inheritable+inherit only entry

      //CREATOR-OWNER S-1-3-0 should only have  the inheritable+inherit only entry

      //Make sure there is full access to S-1-5-20-220

 

      //if one does not exist then create one

 

      //If parent contains inherit only entries then return offset to parent sk record

 

      unsigned long offsetToSK=0;

      sk sk1, *skp;

 

      GetRegStruct("sk", OFFSET(offsetToParentSK), (unsigned char *)&sk1, sizeof(sk1));

 

      skp=(sk*)malloc(sk1.sizeOfSKRecInBytes);

 

      GetRegStruct("sk", OFFSET(offsetToParentSK), (unsigned char *)skp, sk1.sizeOfSKRecInBytes);

 

      SDRDESC sdd;

 

      sdd.sdp=&skp->sd;

      sdd.size=skp->sizeOfSKRecInBytes-sizeof(*skp)+sizeof(skp->sd);

 

      PSDRDESC sddp=InheritSD(&sdd);

 

      if(IsEqualSD(&sdd, sddp)) {

 

            offsetToSK=offsetToParentSK;

      } else if(!(offsetToSK=FindSK(skp->offsetOfNextSKRec, sddp))) {

 

            //Create an sk record.

            //Attach the security descriptor and link into

            //circular list next to parents.

            //Set reference count to zero.  This will be incremented by calling routine

 

            unsigned long requiredSize=sddp->size+sizeof(*skp)-sizeof(skp->sd);

 

            skp=(sk*)realloc(skp, requiredSize);

 

            skp->usageCounter         =0;

            skp->offsetOfNextSKRec    =sk1.offsetOfNextSKRec;

            skp->offsetOfPreviousSKRec=offsetToParentSK;

            skp->sizeOfSKRecInBytes   =requiredSize;

 

            memcpy(&skp->sd, sddp->sdp, sddp->size);

 

            offsetToSK=AllocateRegStruct(requiredSize);

 

            PutRegStruct("sk", OFFSET(offsetToSK), (unsigned char *)skp, requiredSize);

 

            sk1.offsetOfNextSKRec=offsetToSK;

 

            PutRegStruct("sk", OFFSET(offsetToParentSK), (unsigned char *)&sk1, sizeof(sk1));

 

            GetRegStruct("sk", OFFSET(skp->offsetOfNextSKRec), (unsigned char *)&sk1, sizeof(sk1));

 

            sk1.offsetOfPreviousSKRec=offsetToSK;

 

            PutRegStruct("sk", OFFSET(skp->offsetOfNextSKRec), (unsigned char *)&sk1, sizeof(sk1));

      }

 

      free(sddp->sdp);

      free(sddp);

      free(skp);

 

      return offsetToSK;

}

 

int TrueLen(const char *s, int len) {

 

      while(len && s[len-1]=='\0')len--;

   return len;

}

 

int CompareUnterminatedStrings(const char *s1, int s1Len, const char *s2, int s2Len) {

 

      s1Len=TrueLen(s1, s1Len);

      s2Len=TrueLen(s2, s2Len);

 

      int len=s1Len;

   if(s2Len<s1Len) {

         len=s2Len;

   }

 

   int cmp=memicmp(s1, s2, len);

 

   if(!cmp && s1Len!=s2Len) {

 

         cmp=s1Len<s2Len?-1:1;

   }

 

#if 0

   printf("3 comparing[%s] %d <%.*s> to %d <%.*s>. result %d\n",

      s2,

      s1Len,

      s1Len,

      s1,

      s2Len,

      s2Len,

      s2,

      cmp);

#endif

 

   return cmp;

}

 

unsigned long DosCreateSubKey(unsigned long offsetToParentNK, char *keyName) {

 

      nk nk1;

 

      GetRegStruct("nk", OFFSET(offsetToParentNK), (unsigned char *)&nk1, sizeof(nk1));

 

      lf *lf1p=NULL;

 

      unsigned long lfSize=sizeof(*lf1p)+(nk1.numberOFSubKeys-1)*sizeof(lf1p->hashRecords[0]);

      unsigned long lfOffset=nk1.offsetToSubKeyLFRecords;

 

      char k[4];

 

      memset(k, 0, sizeof(k));

 

   long keyNameLength=strlen(keyName);

 

      long nCmp=sizeof(k)<keyNameLength?sizeof(k):keyNameLength;

 

      memcpy(k, keyName, nCmp);

 

      //find subkeys record if it exists

      //look for keyName in sub records

      //return address of nk record

 

      if(nk1.numberOFSubKeys>0) {

 

            lf1p=(lf *)malloc(lfSize);

 

            GetRegStruct("lf", OFFSET(nk1.offsetToSubKeyLFRecords), (unsigned char *)lf1p, lfSize);

 

            assert(nk1.numberOFSubKeys==lf1p->numberOfKeys);

      }

 

      int insertPosition=0;

 

      if(lf1p) {

 

            for(; insertPosition<lf1p->numberOfKeys; insertPosition++) {

 

                  assert(

                        !insertPosition ||

                        strnicmp(lf1p->hashRecords[insertPosition].keyname,

                        lf1p->hashRecords[insertPosition-1].keyname, sizeof(k))>0);

 

                  int cmp=strnicmp(lf1p->hashRecords[insertPosition].keyname, k, sizeof(k));

 

#if 0

                  printf("1 comparing[%s] %d <%.*s> to %d <%.*s>. result %d\n",

            keyName,

               sizeof(k),

            sizeof(k),

            lf1p->hashRecords[insertPosition].keyname,

            sizeof(k),

            sizeof(k),

            k,

            cmp);

#endif

 

                  if(cmp>0) {

 

                        break;

                  } else if(!cmp) {

 

                        nk nk2;

 

                        GetRegStruct("nk", OFFSET(lf1p->hashRecords[insertPosition].offsetToNKRec), (unsigned char *)&nk2, sizeof(nk2));

 

                        nk *nk2p=(nk*)malloc(sizeof(*nk2p)-1+nk2.nameLength);

 

                        assert(nk2p!=NULL);

 

                        GetRegStruct("nk", OFFSET(lf1p->hashRecords[insertPosition].offsetToNKRec), (unsigned char*)nk2p, sizeof(*nk2p)-1+nk2.nameLength);

 

                        cmp=CompareUnterminatedStrings(nk2p->keyname, nk2p->nameLength, keyName, keyNameLength);

 

#if 0

                        printf("cmp=%d\n", cmp);

                        printf("keyName=%s\n", keyName);

                        printf("nk key=%.*s\n", nk2p->nameLength, nk2p->keyname);

#if 0

 

                        printf("2 comparing[%s] %d <%.*s> to %d <%s>. result %d\n",

                              keyName,

                              nk2p->nameLength,

                              nk2p->nameLength,

                              nk2p->keyname,

                              keyNameLength,

                              keyNameLength,

                              keyName,

                              cmp);

 

#endif

#endif

 

                        if(cmp>0) {

 

                              break;

                        }else if(!cmp) {

 

                              //we should really reset the keyname in case the case has changed

 

                              unsigned long offsetToSubNK=lf1p->hashRecords[insertPosition].offsetToNKRec;

 

                              printf("found key @%ld\n", offsetToSubNK);

 

                              free(lf1p);

                              return offsetToSubNK;

                        }

                  }

            }

      }

 

      //allocate and create nk record for keyname

      //attach it to sk record of parent.  increase reference count of sk record

      //attach it to parent record

 

      long nkLen=sizeof(nk)+keyNameLength-1;

 

      nk *nk2p=(nk*)malloc(nkLen);

 

      memset(nk2p, 0, nkLen);

 

      nk2p->pad2[0]=0xffffffffL;

      nk2p->unknownIndex=0xb2b2b2b2L;

 

      strncpy(nk2p->headerText, "nk", sizeof(nk2p->headerText));

 

      nk2p->rootOrOtherwise=0x20;

      nk2p->writeDate=nk1.writeDate;

 

      nk2p->ownerParentKeyOffset=offsetToParentNK;

 

      nk2p->numberOFSubKeys=0;

      nk2p->offsetToSubKeyLFRecords=-1;

 

      nk2p->numberOfValues=0;

      nk2p->offsetToValueList=-1;

 

      sk sk1;

 

      nk2p->offsetToSKrecord=GetSkRecord(nk1.offsetToSKrecord);

 

      //update reference count

 

      GetRegStruct("sk", OFFSET(nk2p->offsetToSKrecord), (unsigned char *)&sk1, sizeof(sk1));

 

      sk1.usageCounter++;

 

      PutRegStruct("sk", OFFSET(nk2p->offsetToSKrecord), (unsigned char*)&sk1, sizeof(sk1));

 

      nk2p->nameLength=(short)keyNameLength;

 

      nk2p->offsetToClassName=nk1.offsetToClassName;  //can be -1

 

      nk2p->classNameLength=nk1.classNameLength;      //0 if offset -1

 

      strncpy(nk2p->keyname, keyName, keyNameLength);

 

      unsigned long newNkOffset=AllocateRegStruct(nkLen);

 

      PutRegStruct("nk", OFFSET(newNkOffset), (unsigned char *)nk2p, nkLen);

 

      //reallocate sub records

      //link parent to new record via sub records

      //return address of new nk record

 

      if(!lf1p) {

            //create new

 

            lfSize=sizeof(lf);

 

            lfOffset=AllocateRegStruct(lfSize);

 

            lf1p=(lf*)malloc(lfSize);

 

            memcpy(lf1p->headerText, "lf", sizeof(lf1p->headerText));

 

            memcpy(lf1p->hashRecords[insertPosition].keyname, k, sizeof(lf1p->hashRecords[insertPosition].keyname));

 

            lf1p->hashRecords[insertPosition].offsetToNKRec=newNkOffset;

            lf1p->numberOfKeys=1;

 

      } else {

            //reallocate

 

            lfSize+=sizeof(lf1p->hashRecords[0]);

 

            lfOffset=ReAllocateRegStruct(lfOffset, lfSize);

 

            lf1p=(lf*)realloc(lf1p, lfSize);

 

            assert(insertPosition>=0 && insertPosition<=lf1p->numberOfKeys);

 

            if(insertPosition<lf1p->numberOfKeys) {

 

                  memmove(lf1p->hashRecords+insertPosition+1, lf1p->hashRecords+insertPosition, (lf1p->numberOfKeys-insertPosition)*sizeof(lf1p->hashRecords[0]));

            }

 

            memcpy(lf1p->hashRecords[insertPosition].keyname, k, sizeof(lf1p->hashRecords[insertPosition].keyname));

 

            lf1p->hashRecords[insertPosition].offsetToNKRec=newNkOffset;

            lf1p->numberOfKeys++;

 

      }

 

      PutRegStruct("lf", OFFSET(lfOffset), (unsigned char*)lf1p, lfSize);

 

      nk1.numberOFSubKeys=lf1p->numberOfKeys;

      nk1.offsetToSubKeyLFRecords=lfOffset;

 

      if(nk2p->nameLength*sizeof(WCHAR)>nk1.longestSubkeySizex2) {

 

            nk1.longestSubkeySizex2=nk2p->nameLength*sizeof(WCHAR);

      }

 

      if(nk2p->classNameLength>nk1.longestClassSizex2) {

 

            nk1.longestClassSizex2=nk2p->classNameLength;

      }

 

      PutRegStruct("nk", OFFSET(offsetToParentNK), (unsigned char *)&nk1, sizeof(nk1));

 

      free(nk2p);

      free(lf1p);

 

      return newNkOffset;

}

 

unsigned long DosCreateKey(unsigned long offsetToParentNK, char *path) {

 

      nk nk1;

 

      GetRegStruct("nk", OFFSET(offsetToParentNK), (unsigned char *)&nk1, sizeof(nk1));

 

      StripCharactersFromStart(path, "\\");

 

      if(!*path) {

 

            //we are there!

 

            return offsetToParentNK;

      }

 

      //get the key to lookup

 

      char *p=strchr(path, '\\');

      char *nextKey;

 

      if(p) {

 

            nextKey=(char*)malloc(p-path+1);

 

            *nextKey='\0';

 

            strncat(nextKey, path, p-path);

 

            path=p;

      } else {

 

 

            nextKey=strdup(path);

 

            path=path+strlen(path);

      }

 

      unsigned long offsetToNextNK=DosCreateSubKey(offsetToParentNK, nextKey);

 

      free(nextKey);

 

      return DosCreateKey(offsetToNextNK, path);

}

 

unsigned long DosCreateAndSetKey(char *path) {

 

      //Create the path if required

      //Set the default path to <path> so that future DosSetValueEx calls will add values to this key

 

      regf regf1;

 

      GetRegStruct("regf", 0, (unsigned char *)&regf1, sizeof(regf1));

 

      return DosCreateKey(regf1.offsetToFirstKey, path);

}

 

bool DosSetValueEx(unsigned long nkOffset, char *name, unsigned long reserved, unsigned long type, unsigned char *value, unsigned long valueLength) {

 

      unsigned long newNameLength=strlen(name);

 

      reserved=0; //stop unused variable warning

 

      //Set a value at the current path

 

      nk nk1;

 

      GetRegStruct("nk", OFFSET(nkOffset), (unsigned char *)&nk1, sizeof(nk1));

 

      //look for existing entry with this name

 

      vk vk1, *vkp=NULL;

      unsigned long sizeofvk;

      unsigned long existingValueOffset;

 

      valueList *vp=NULL;

      unsigned long vSize=nk1.numberOfValues*sizeof(*vp);

      unsigned long vOffset=nk1.offsetToValueList;

 

      if(nk1.numberOfValues>0) {

 

            vp=(valueList*)malloc(vSize);

      }

 

      if(vp) {

 

            bool found=false;

 

            GetRegStruct("", OFFSET(vOffset), (unsigned char *)vp, vSize);

 

            for(int i=0;i<nk1.numberOfValues;i++) {

 

                  GetRegStruct("vk", OFFSET(vp->offsetToValue[i]), (unsigned char *)&vk1, sizeof(vk1));

 

                  unsigned long nameLength=(vk1.nameLength>0?vk1.nameLength:0);

 

                  if(!newNameLength && (vk1.flag==0) || newNameLength && nameLength==newNameLength) {

 

                        sizeofvk=sizeof(*vkp)+nameLength;

 

                        vkp=(vk*)malloc(sizeofvk);

 

                        GetRegStruct("vk", OFFSET(vp->offsetToValue[i]), (unsigned char*)vkp, sizeofvk);

 

                        if(!newNameLength && (vk1.flag==0) || !strncmp(name, vkp->ValueName, nameLength)) {

 

                              existingValueOffset=vp->offsetToValue[i];

 

                              found=true;

                              break;

                        }

 

                        free(vkp);

                  }

 

            }

 

            if(found) {

 

                  //modify data

 

                  vkp->typeOfValue=type;

 

                  vkp->lengthOfData=valueLength;

 

                  if(vkp->lengthOfData<=sizeof(vkp->offsetToData)) {

 

                        vkp->offsetToData=0;

 

                        memcpy(&vkp->offsetToData, value, valueLength);

 

                        vkp->lengthOfData |= 0x80000000L;

 

                  } else {

 

                        vkp->offsetToData=ReAllocateRegStruct(vkp->offsetToData, vkp->lengthOfData);

 

                        PutRegStruct("", OFFSET(vkp->offsetToData), (unsigned char*)value, vkp->lengthOfData);

                  }

 

                  PutRegStruct("vk", OFFSET(existingValueOffset), (unsigned char *)vkp, sizeofvk);

 

                  if((vkp->lengthOfData & ~0x80000000L) > nk1.longestValueSizex2) {

 

                        nk1.longestValueSizex2=vkp->lengthOfData & ~0x80000000L;

                  }

 

                  PutRegStruct("nk", OFFSET(nkOffset), (unsigned char *)&nk1, sizeof(nk1));

 

                  free(vkp);

                  free(vp);

 

                  return true;

            }

 

      }

 

      sizeofvk=sizeof(*vkp)+newNameLength-1;

 

      vkp=(vk*)malloc(sizeofvk);

 

      vkp->flag=newNameLength?1:0;

      strncpy(vkp->headerText, "vk", sizeof(vkp->headerText));

      vkp->nameLength=(short)newNameLength;

      vkp->typeOfValue=type;

 

      vkp->lengthOfData=valueLength;

 

      if(vkp->lengthOfData<=sizeof(vkp->offsetToData)) {

 

            vkp->offsetToData=0;

 

            memcpy(&vkp->offsetToData, value, valueLength);

 

            vkp->lengthOfData|=0x80000000L;

 

      } else {

 

            vkp->offsetToData=AllocateRegStruct(valueLength);

 

            PutRegStruct("", OFFSET(vkp->offsetToData), value, valueLength);

      }

 

      strncpy(vkp->ValueName, name, newNameLength);

 

      if(!vp) {

 

            nk1.numberOfValues=0;

 

            vSize=sizeof(*vp);

            vp=(valueList*)malloc(vSize);

      } else {

 

            vSize+=sizeof(*vp);

            vp=(valueList*)realloc(vp, vSize);

      }

 

      vp->offsetToValue[nk1.numberOfValues]=AllocateRegStruct(sizeofvk);

 

      PutRegStruct("vk", OFFSET(vp->offsetToValue[nk1.numberOfValues]), (unsigned char *)vkp, sizeofvk);

 

      nk1.offsetToValueList=AllocateRegStruct(vSize);

 

      PutRegStruct("", OFFSET(nk1.offsetToValueList), (unsigned char *)vp, vSize);

 

      nk1.numberOfValues++;

 

      if((vkp->lengthOfData & ~0x80000000L) > nk1.longestValueSizex2) {

 

            nk1.longestValueSizex2=vkp->lengthOfData & ~0x80000000L;

      }

 

      if(newNameLength*sizeof(WCHAR) > nk1.longestVNameSizex2) {

 

            nk1.longestVNameSizex2=newNameLength*sizeof(WCHAR);

      }

 

      PutRegStruct("nk", OFFSET(nkOffset), (unsigned char *)&nk1, sizeof(nk1));

 

      free(vkp);

      free(vp);

 

      return true;

}

 

void StripCharactersFromEnd(char *ll, const char *characters) {

 

      char *e=ll+strlen(ll)-1;

 

      while(e>=ll && strchr(characters, *e)) {

 

            *e--='\0';

      }

}

 

void StripCharactersFromStart(char *ll, const char *characters) {

 

      char *s=ll;

 

      while(*s && strchr(characters, *s)) {

 

            s++;

      }

 

      memmove(ll, s, strlen(s)+1);

}

 

char *AppendString(char *s1, const char *s2) {

 

      long len=strlen(s1)+strlen(s2)+1;

 

      char *p=(char*)malloc(len);

 

      *p='\0';

 

      strcat(strcat(p, s1), s2);

 

      return p;

}

 

char *FindEndOfString(char *p) {

 

      if(*p++!='\"') {

 

            return NULL;

      }

 

      while(*p && *p!='\"') {

 

 

            if(*p=='\\') {

 

                  //take next character

 

                  p++;

            }

 

            p++;

      }

 

      return p;

}

 

unsigned char *cEvalString(const char *p) {

 

      if(*p++!='\"') {

           

            return NULL;

      }

     

      unsigned char *r=(unsigned char*)malloc(strlen(p)+1), *q=r;   

 

      long c;

     

      while((c=*p++)!=0 && c!='\"') {

           

            long i = 0;

           

            if (c == '\\') {

                 

                  switch ((c = *p++)) {

                  case 'a': c =    7; break;

                  case 'b': c = '\b'; break;

                  case 'e': c =   27; break;

                  case 'f': c = '\f'; break;

                  case 'n': c = '\n'; break;

                  case 'r': c = '\r'; break;

                  case 't': c = '\t'; break;

                  case 'v': c = '\v'; break;

                       

                  case '0': case '1': case '2': case '3':

                  case '4': case '5': case '6': case '7':

                        c -= '0';

                        while (i++ < 2 && isdigit(*p) && *p != '8' && *p != '9') {

                              c = c * 8 + *p++ - '0';

                        }

                        break;

 

                  case 'x':

                        c = 0;

                        while (i++ < 2 && isxdigit(*p)) {

                              c = c * 16 + tolower(*p) - ((isdigit(*p))? '0' : 'W');

                              p++;

                        }

                        break;

                       

                  case 0:   /* Allows for an empty line */

                        p--;

                        continue;

                       

                  default:

                        break;

                  }

            }

            *q++= (char)c;

      }

      *q++='\0';

 

      return r;

}

 

const long maxLineLength=4096;

 

void UpdReg(const char *regfile) {

 

      char buf[maxLineLength];

 

      FILE *fp=fopen(regfile, "rt");

 

      if(!fp) {

 

 

 

      }

 

      unsigned long nkOffset=-1;

 

      long ln=0;

      char *section=0;

      char *line=0;

      char *ll=0;

      char *name=0;

 

      while(fgets(buf, sizeof(buf), fp)) {

 

            if(ll) {

                  free(ll);

            }

 

            ll=strdup(buf);

 

            StripCharactersFromEnd(ll, "\n\r");

            StripCharactersFromStart(ll, " ");

 

            ln++;

 

            if(!strlen(ll) || ll[0]==';') {

 

                  continue;

            }

 

            if(ll[0]=='[' && ll[strlen(ll)-1]==']') {

 

                  //new section start

 

                  ll[strlen(ll)-1]='\0';

 

                  if(section) {

 

                        free(section);

                  }

 

                  section=strdup(ll+1);

 

                  if((nkOffset=DosCreateAndSetKey(section))<0) {

 

                        //failed

 

 

 

                  }

 

                  if(line && strlen(line)) {

 

                        //unterminated line

 

                        free(line);

                        line=NULL;

                  }

 

                  continue;

            }

 

            if(line && strlen(line)) {

 

                  char *p=AppendString(line, ll);

 

                  free(line);

 

                  line=p;

 

            } else {

 

                  if(line) {

 

                        free(line);

                  }

 

                  line=strdup(ll);

            }

 

            if(line[strlen(line)-1]=='\\') {

 

                  //line is continued

 

                  continue;

            }

 

 

            if(!section) {

 

                  //should have a section at this stage

                  //error in regedit file formay

 

 

            }

 

            //should have just

            //@=<val>

            //"string"=<val>

            //

            //Where: <val> = "string", dword:00000000, hex:00,00..., hex(2):00,00,00, hex(7):00,00,00

 

            //look for structure @=value or "string"=value

 

            if(name) {

 

                  free(name);

                  name=NULL;

            }

 

            char *valueStart;

 

            if(line[0]=='@' && line[1]=='=') {

 

                  valueStart=line+2;

 

                  name=strdup("");

 

            } else if(line[0]=='\"') {

 

                  char *p=line;

 

                  p=FindEndOfString(p);

 

                  if(p[1]!='=') {

 

                        //don't understand this format

 

 

                  }

 

                  valueStart=p+2;

 

                  name=(char *)cEvalString(line);

 

            } else {

 

                  //don't understand this name/value format

 

 

 

            }

 

            if(*valueStart=='"') {

 

                  //value is a string

 

                  unsigned char *data=cEvalString(valueStart);

 

                  long len=strlen((const char *)data)+1;

                  long wLen=len*sizeof(WCHAR);

 

                  WCHAR *wData=(WCHAR *)malloc(wLen);

 

#if DOS

                  mbstowcs(wData, data, len);

#else

                  swprintf(wData, L"%hs", data);

#endif

                  DosSetValueEx(nkOffset, name, NULL, REG_SZ, (unsigned char *)wData, wLen);

 

                  free(data);

                  free(wData);

 

            } else if(!strnicmp(valueStart, "dword:", strlen("dword:"))) {

 

                  unsigned long data;

 

                  sscanf(valueStart+strlen("dword:"), "%lx", &data);

 

                  DosSetValueEx(nkOffset, name, NULL, REG_DWORD, (unsigned char *)&data, sizeof(data));

 

            } else if(*valueStart=='h' || *valueStart=='H') {

 

                  unsigned long vOffset=0;

                  unsigned long type=0;

 

                  if(strnicmp(valueStart, "hex:", strlen("hex:"))) {

 

                        //REG_BINARY

 

                        type=REG_BINARY;

                        vOffset=strlen("hex:");

 

                  } else if(strnicmp(valueStart, "hex(2):", strlen("hex(2):"))) {

 

                        //REG_EXPAND_SZ

 

                        type=REG_EXPAND_SZ;

                        vOffset=strlen("hex(2):");

 

                  } else if(strnicmp(valueStart, "hex(7):", strlen("hex(7):"))) {

 

                        //REG_MULTI_SZ

 

                        type=REG_MULTI_SZ;

                        vOffset=strlen("hex(7):");

 

                  } else {

 

                        //don't understand value format

 

 

                  }

 

                  //read pairs of hex digits separated by commas.

 

                  //count the number of commas

 

                  char *p=valueStart+vOffset;

 

                  unsigned long values=1;

 

                  while((p=strchr(p, ','))) {

 

                        p++;

                        values++;

                  }

 

                  unsigned char *data=(unsigned char *)malloc(sizeof(char)*values);

 

                  p=valueStart+vOffset;

 

                  int i=0;

 

                  for(i=0;i<values;i++) {

 

                        unsigned long v;

 

                        sscanf(p, "%02lx", &v);

 

                        data[i]=(unsigned char) v;

 

                        p+=3;

                  }

 

                  DosSetValueEx(nkOffset, name, NULL, type, data, values);

 

                  free(data);

 

            } else {

 

                  //don't understand this data format

 

 

 

            }

 

            if(line) {

                  free(line);

                  line=NULL;

            }

 

      } //while fgets

 

      if(section) {

 

            free(section);

      }

 

      if(line) {

 

            free(line);

      }

 

      if(ll) {

 

            free(ll);

      }

 

      if(name) {

 

            free(name);

      }

 

}

 

void main(int argc, char *argv[]) {

 

      regf regf1;

 

      if(argc>2) {

            if(!OpenRegFileWrite(argv[1])) {

 

 

            }

            InitRegMM();

            UpdReg(argv[2]);

            fclose(fp);

      }

 

      if(!OpenRegFileRead(argv[1])) {

 

 

 

      }

 

      //don't forget to create/update log file

      //Is the log file a copy of the header before updating or

      //a cop[y of the modified header with the version number unmodified?

 

      GetRegStruct("regf", 0, (unsigned char *)&regf1, sizeof(regf1));

 

      PrintRegf(&regf1, stdout);

 

      EnumerateAvailableDataAreas(stdout);

 

      sizepair ssSizes;

 

      EnumerateReg(regf1.offsetToFirstKey, &ssSizes, stdout);

 

      fclose(fp);

 

      if(argc>2) {

 

            char *logFile=AppendString(argv[1], ".log");

 

            if(!OpenRegFileWrite(logFile)) {

 

 

            }

 

            regf1.unknown1=--regf1.asUnknown1;

 

            regf1.checksum=CheckSumULong(0, (unsigned long*)&regf1, ((unsigned long *)&regf1.checksum)-((unsigned long *)&regf1));

 

            PutRegStruct("regf", 0, (unsigned char *)&regf1, sizeof(regf1));

 

            fclose(fp);

      }

 

}