Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/pxesploit/regeditor/ntreg.c
Views: 11780
/*1* ntreg.c - NT Registry Hive access library2*3* 2010-jun: Patches from Frediano Ziglio adding support for wide characters4* and some bugfixes. Thank you!5* 2008-mar: Type QWORD (XP/Vista and newer) now recognized6* 2008-mar: Most functions accepting a path now also have a parameter specifying if7* the search should be exact or on first match basis8* 2008-mar: Fixed bug which skipped first indirect index table when deleting keys,9* usually leading to endless loop when recursive deleting.10* 2008-mar: Export to .reg file by Leo von Klenze, expanded a bit by me.11* 2008-mar: 64 bit compatible patch by Mike Doty, via Alon Bar-Lev12* http://bugs.gentoo.org/show_bug.cgi?id=18541113* 2007-sep: Verbosity/debug messages minor changes14* 2007-apr: LGPL license.15* 2004-aug: Deep indirect index support. NT351 support. Recursive delete.16* Debugged a lot in allocation routines. Still no expansion.17* 2004-jan: Verbosity updates18* 2003-jan: Allocation of new data, supports adding/deleting keys & stuff.19* Missing is expanding the file.20* 2003-jan: Seems there may be garbage pages at end of file, not zero pages21* now stops enumerating at first non 'hbin' page.22*23* NOTE: The API is not frozen. It can and will change every release.24*25*****26*27* NTREG - Window registry file reader / writer library28* Copyright (c) 1997-2010 Petter Nordahl-Hagen.29*30* This library is free software; you can redistribute it and/or31* modify it under the terms of the GNU Lesser General Public32* License as published by the Free Software Foundation;33* version 2.1 of the License.34*35* This library is distributed in the hope that it will be useful,36* but WITHOUT ANY WARRANTY; without even the implied warranty of37* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU38* Lesser General Public License for more details.39* See file LGPL.txt for the full license.40*41*/4243#include <stdio.h>44#include <stdlib.h>45#include <ctype.h>46#include <sys/types.h>47#include <sys/stat.h>48#include <fcntl.h>49#include <errno.h>50#include <string.h>51#include <unistd.h>52#include <inttypes.h>5354#include "ntreg.h"5556/* Set to abort() and debug on more critical errors */57#define DOCORE 15859#define ZEROFILL 1 /* Fill blocks with zeroes when allocating and deallocating */60#define ZEROFILLONLOAD 0 /* Fill blocks marked as unused/deallocated with zeroes on load. FOR DEBUG */6162const char ntreg_version[] = "ntreg lib routines, v0.94.1 100627, (c) Petter N Hagen";6364const char *val_types[REG_MAX+1] = {65"REG_NONE", "REG_SZ", "REG_EXPAND_SZ", "REG_BINARY", "REG_DWORD", /* 0 - 4 */66"REG_DWORD_BIG_ENDIAN", "REG_LINK", /* 5 - 6 */67"REG_MULTI_SZ", "REG_RESOUCE_LIST", "REG_FULL_RES_DESC", "REG_RES_REQ", /* 7 - 10 */68"REG_QWORD", /* 11 */69};7071static char * string_regw2prog(void *string, int len);72static char * string_rega2prog(void *string, int len);73static char * string_prog2regw(void *string, int len, int* out_len);74static void string_prog2rega(char *string, int len);7576/* Utility routines */77char *str_dup( const char *str )78{79char *str_new;8081if (!str)82return 0 ;8384CREATE( str_new, char, strlen(str) + 1 );85strcpy( str_new, str );86return str_new;87}8889int fmyinput(char *prmpt, char *ibuf, int maxlen)90{9192printf("%s",prmpt);9394fgets(ibuf,maxlen+1,stdin);9596ibuf[strlen(ibuf)-1] = 0;9798return(strlen(ibuf));99}100101/* Print len number of hexbytes */102103void hexprnt(char *s, unsigned char *bytes, int len)104{105int i;106107printf("%s",s);108for (i = 0; i < len; i++) {109printf("%02x ",bytes[i]);110}111printf("\n");112}113114/* HexDump all or a part of some buffer */115116void hexdump(char *hbuf, int start, int stop, int ascii)117{118char c;119int diff,i;120121while (start < stop ) {122123diff = stop - start;124if (diff > 16) diff = 16;125126printf(":%05X ",start);127128for (i = 0; i < diff; i++) {129printf("%02X ",(unsigned char)*(hbuf+start+i));130}131if (ascii) {132for (i = diff; i < 16; i++) printf(" ");133for (i = 0; i < diff; i++) {134c = *(hbuf+start+i);135printf("%c", isprint(c) ? c : '.');136}137}138printf("\n");139start += 16;140}141}142143/* General search routine, find something in something else */144int find_in_buf(char *buf, char *what, int sz, int len, int start)145{146int i;147148for (; start < sz; start++) {149for (i = 0; i < len; i++) {150if (*(buf+start+i) != *(what+i)) break;151}152if (i == len) return(start);153}154return(0);155}156157/* Get INTEGER from memory. This is probably low-endian specific? */158int get_int( char *array )159{160return ((array[0]&0xff) + ((array[1]<<8)&0xff00) +161((array[2]<<16)&0xff0000) +162((array[3]<<24)&0xff000000));163}164165166/* Quick and dirty UNICODE to std. ascii */167168void cheap_uni2ascii(char *src, char *dest, int l)169{170171for (; l > 0; l -=2) {172*dest = *src;173dest++; src +=2;174}175*dest = 0;176}177178179/* Quick and dirty ascii to unicode */180181void cheap_ascii2uni(char *src, char *dest, int l)182{183for (; l > 0; l--) {184*dest++ = *src++;185*dest++ = 0;186187}188}189190void skipspace(char **c)191{192while( **c == ' ' ) (*c)++;193}194195int gethex(char **c)196{197int value;198199skipspace(c);200201if (!(**c)) return(0);202203sscanf(*c,"%x",&value);204205while( **c != ' ' && (**c)) (*c)++;206207return(value);208}209210/* Get a string of HEX bytes (space separated),211* or if first char is ' get an ASCII string instead.212*/213214int gethexorstr(char **c, char *wb)215{216int l = 0;217218skipspace(c);219220if ( **c == '\'') {221(*c)++;222while ( **c ) {223*(wb++) = *((*c)++);224l++;225}226} else {227do {228*(wb++) = gethex(c);229l++;230skipspace(c);231} while ( **c );232}233return(l);234}235236/* Simple buffer debugger, returns 1 if buffer dirty/edited */237238int debugit(char *buf, int sz)239{240241242char inbuf[100],whatbuf[100],*bp;243244int dirty=0,to,from,l,i,j,wlen,cofs = 0;245246printf("Buffer debugger. '?' for help.\n");247248while (1) {249l = fmyinput(".",inbuf,90);250bp = inbuf;251252skipspace(&bp);253254if (l > 0 && *bp) {255switch(*bp) {256case 'd' :257bp++;258if (*bp) {259from = gethex(&bp);260to = gethex(&bp);261} else {262from = cofs; to = 0;263}264if (to == 0) to = from + 0x100;265if (to > sz) to = sz;266hexdump(buf,from,to,1);267cofs = to;268break;269case 'a' :270bp++;271if (*bp) {272from = gethex(&bp);273to = gethex(&bp);274} else {275from = cofs; to = 0;276}277if (to == 0) to = from + 0x100;278if (to > sz) to = sz;279hexdump(buf,from,to,0);280cofs = to;281break;282#if 0283case 'k' :284bp++;285if (*bp) {286from = gethex(&bp);287} else {288from = cofs;289}290if (to > sz) to = sz;291parse_block(from,1);292cofs = to;293break;294#endif295#if 0296case 'l' :297bp++;298if (*bp) {299from = gethex(&bp);300} else {301from = cofs;302}303if (to > sz) to = sz;304nk_ls(from+4,0);305cofs = to;306break;307#endif308case 'q':309return(0);310break;311case 's':312if (!dirty) printf("Buffer has not changed, no need to write..\n");313return(dirty);314break;315case 'h':316bp++;317if (*bp == 'a') {318from = 0;319to = sz;320bp++;321} else {322from = gethex(&bp);323to = gethex(&bp);324}325wlen = gethexorstr(&bp,whatbuf);326if (to > sz) to = sz;327printf("from: %x, to: %x, wlen: %d\n",from,to,wlen);328for (i = from; i < to; i++) {329for (j = 0; j < wlen; j++) {330if ( *(buf+i+j) != *(whatbuf+j)) break;331}332if (j == wlen) printf("%06x ",i);333}334printf("\n");335break;336case ':':337bp++;338if (!*bp) break;339from = gethex(&bp);340wlen = gethexorstr(&bp,whatbuf);341342printf("from: %x, wlen: %d\n",from,wlen);343344memcpy(buf+from,whatbuf,wlen);345dirty = 1;346break;347#if 0348case 'p':349j = 0;350if (*(++bp) != 0) {351from = gethex(&bp);352}353if (*(++bp) != 0) {354j = gethex(&bp);355}356printf("from: %x, rid: %x\n",from,j);357seek_n_destroy(from,j,500,0);358break;359#endif360case '?':361printf("d [<from>] [<to>] - dump buffer within range\n");362printf("a [<from>] [<to>] - same as d, but without ascii-part (for cut'n'paste)\n");363printf(": <offset> <hexbyte> [<hexbyte> ...] - change bytes\n");364printf("h <from> <to> <hexbyte> [<hexbyte> ...] - hunt (search) for bytes\n");365printf("ha <hexbyte> [<hexbyte] - Hunt all (whole buffer)\n");366printf("s - save & quit\n");367printf("q - quit (no save)\n");368printf(" instead of <hexbyte> etc. you may give 'string to enter/search a string\n");369break;370default:371printf("?\n");372break;373}374}375}376}377378379/* ========================================================================= */380381/* The following routines are mostly for debugging, I used it382* much during discovery. the -t command line option uses it,383* also the 'st' and 's' from the editor & hexdebugger.384* All offsets shown in these are unadjusted (ie you must add385* headerpage (most often 0x1000) to get file offset)386*/387388/* Parse the nk datablock389* vofs = offset into struct (after size linkage)390*/391void parse_nk(struct hive *hdesc, int vofs, int blen)392{393394struct nk_key *key;395int i;396397printf("== nk at offset %0x\n",vofs);398399/* #define D_OFFS2(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs ) */400#define D_OFFS(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs )401402key = (struct nk_key *)(hdesc->buffer + vofs);403printf("%04lx type = 0x%02x %s\n", D_OFFS(type) ,key->type,404(key->type == KEY_ROOT ? "ROOT_KEY" : "") );405printf("%04lx timestamp skipped\n", D_OFFS(timestamp) );406printf("%04lx parent key offset = 0x%0x\n", D_OFFS(ofs_parent) ,key->ofs_parent);407printf("%04lx number of subkeys = %d\n", D_OFFS(no_subkeys),key->no_subkeys);408printf("%04lx lf-record offset = 0x%0x\n",D_OFFS(ofs_lf),key->ofs_lf);409printf("%04lx number of values = %d\n", D_OFFS(no_values),key->no_values);410printf("%04lx val-list offset = 0x%0x\n",D_OFFS(ofs_vallist),key->ofs_vallist);411printf("%04lx sk-record offset = 0x%0x\n",D_OFFS(ofs_sk),key->ofs_sk);412printf("%04lx classname offset = 0x%0x\n",D_OFFS(ofs_classnam),key->ofs_classnam);413printf("%04lx *unused?* = 0x%0x\n",D_OFFS(dummy4),key->dummy4);414printf("%04lx name length = %d\n", D_OFFS(len_name),key->len_name);415printf("%04lx classname length = %d\n", D_OFFS(len_classnam),key->len_classnam);416417printf("%04lx Key name: <",D_OFFS(keyname) );418for(i = 0; i < key->len_name; i++) putchar(key->keyname[i]);419printf(">\n== End of key info.\n");420421}422423/* Parse the vk datablock424* vofs = offset into struct (after size linkage)425*/426void parse_vk(struct hive *hdesc, int vofs, int blen)427{428struct vk_key *key;429int i;430431printf("== vk at offset %0x\n",vofs);432433434key = (struct vk_key *)(hdesc->buffer + vofs);435printf("%04lx name length = %d (0x%0x)\n", D_OFFS(len_name),436key->len_name, key->len_name );437printf("%04lx length of data = %d (0x%0x)\n", D_OFFS(len_data),438key->len_data, key->len_data );439printf("%04lx data offset = 0x%0x\n",D_OFFS(ofs_data),key->ofs_data);440printf("%04lx value type = 0x%0x %s\n", D_OFFS(val_type), key->val_type,441(key->val_type <= REG_MAX ? val_types[key->val_type] : "(unknown)") ) ;442443printf("%04lx flag = 0x%0x\n",D_OFFS(flag),key->flag);444printf("%04lx *unused?* = 0x%0x\n",D_OFFS(dummy1),key->dummy1);445446printf("%04lx Key name: <",D_OFFS(keyname) );447for(i = 0; i < key->len_name; i++) putchar(key->keyname[i]);448printf(">\n== End of key info.\n");449450}451452/* Parse the sk datablock453* Gee, this is the security info. Who cares? *evil grin*454* vofs = offset into struct (after size linkage)455*/456void parse_sk(struct hive *hdesc, int vofs, int blen)457{458struct sk_key *key;459/* int i; */460461printf("== sk at offset %0x\n",vofs);462463key = (struct sk_key *)(hdesc->buffer + vofs);464printf("%04lx *unused?* = %d\n" , D_OFFS(dummy1), key->dummy1 );465printf("%04lx Offset to prev sk = 0x%0x\n", D_OFFS(ofs_prevsk), key->ofs_prevsk);466printf("%04lx Offset to next sk = 0x%0x\n", D_OFFS(ofs_nextsk), key->ofs_nextsk);467printf("%04lx Usage counter = %d (0x%0x)\n", D_OFFS(no_usage),468key->no_usage,key->no_usage);469printf("%04lx Security data len = %d (0x%0x)\n", D_OFFS(len_sk),470key->len_sk,key->len_sk);471472printf("== End of key info.\n");473474}475476477/* Parse the lf datablock (>4.0 'nk' offsets lookuptable)478* vofs = offset into struct (after size linkage)479*/480void parse_lf(struct hive *hdesc, int vofs, int blen)481{482struct lf_key *key;483int i;484485printf("== lf at offset %0x\n",vofs);486487key = (struct lf_key *)(hdesc->buffer + vofs);488printf("%04lx number of keys = %d\n", D_OFFS(no_keys), key->no_keys );489490for(i = 0; i < key->no_keys; i++) {491printf("%04lx %3d Offset: 0x%0x - <%c%c%c%c>\n",492D_OFFS(hash[i].ofs_nk), i,493key->hash[i].ofs_nk,494key->hash[i].name[0],495key->hash[i].name[1],496key->hash[i].name[2],497key->hash[i].name[3] );498}499500printf("== End of key info.\n");501502}503504/* Parse the lh datablock (WinXP offsets lookuptable)505* vofs = offset into struct (after size linkage)506* The hash is most likely a base 37 conversion of the name string507*/508void parse_lh(struct hive *hdesc, int vofs, int blen)509{510struct lf_key *key;511int i;512513printf("== lh at offset %0x\n",vofs);514515key = (struct lf_key *)(hdesc->buffer + vofs);516printf("%04lx number of keys = %d\n", D_OFFS(no_keys), key->no_keys );517518for(i = 0; i < key->no_keys; i++) {519printf("%04lx %3d Offset: 0x%0x - <hash: %08x>\n",520D_OFFS(lh_hash[i].ofs_nk), i,521key->lh_hash[i].ofs_nk,522key->lh_hash[i].hash );523}524525printf("== End of key info.\n");526527}528529530/* Parse the li datablock (3.x 'nk' offsets list)531* vofs = offset into struct (after size linkage)532*/533void parse_li(struct hive *hdesc, int vofs, int blen)534{535struct li_key *key;536int i;537538printf("== li at offset %0x\n",vofs);539540/* #define D_OFFS(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs ) */541542key = (struct li_key *)(hdesc->buffer + vofs);543printf("%04lx number of keys = %d\n", D_OFFS(no_keys), key->no_keys );544545for(i = 0; i < key->no_keys; i++) {546printf("%04lx %3d Offset: 0x%0x\n",547D_OFFS(hash[i].ofs_nk), i,548key->hash[i].ofs_nk);549}550printf("== End of key info.\n");551552}553554/* Parse the ri subindex-datablock555* (Used to list li/lf/lh's when ~>500keys)556* vofs = offset into struct (after size linkage)557*/558void parse_ri(struct hive *hdesc, int vofs, int blen)559{560struct ri_key *key;561int i;562563printf("== ri at offset %0x\n",vofs);564565/* #define D_OFFS(o) ( (void *)&(key->o)-(void *)hdesc->buffer-vofs ) */566567key = (struct ri_key *)(hdesc->buffer + vofs);568printf("%04lx number of subindices = %d\n", D_OFFS(no_lis), key->no_lis );569570for(i = 0; i < key->no_lis; i++) {571printf("%04lx %3d Offset: 0x%0x\n",572D_OFFS(hash[i].ofs_li), i,573key->hash[i].ofs_li);574}575printf("== End of key info.\n");576577}578579580/* Parse the datablock581* vofs = offset into struct (after size linkage)582*/583584int parse_block(struct hive *hdesc, int vofs,int verbose)585{586unsigned short id;587int seglen;588589seglen = get_int(hdesc->buffer+vofs);590591if (verbose || seglen == 0) {592printf("** Block at offset %0x\n",vofs);593printf("seglen: %d, %u, 0x%0x\n",seglen,seglen,seglen);594}595if (seglen == 0) {596printf("Whoops! FATAL! Zero data block size! (not registry or corrupt file?)\n");597debugit(hdesc->buffer,hdesc->size);598return(0);599}600601if (seglen < 0) {602seglen = -seglen;603hdesc->usetot += seglen;604hdesc->useblk++;605if (verbose) {606printf("USED BLOCK: %d, 0x%0x\n",seglen,seglen);607/* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */608}609} else {610hdesc->unusetot += seglen;611hdesc->unuseblk++;612/* Useful to zero blocks we think are empty when debugging.. */613#if ZEROFILLONLOAD614bzero(hdesc->buffer+vofs+4,seglen-4);615#endif616617if (verbose) {618printf("FREE BLOCK!\n");619/* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */620}621}622623624/* printf("Seglen: 0x%02x\n",seglen & 0xff ); */625626vofs += 4;627id = (*(hdesc->buffer + vofs)<<8) + *(hdesc->buffer+vofs+1);628629if (verbose) {630switch (id) {631case 0x6e6b: /* nk */632parse_nk(hdesc, vofs, seglen);633break;634case 0x766b: /* vk */635parse_vk(hdesc, vofs, seglen);636break;637case 0x6c66: /* lf */638parse_lf(hdesc, vofs, seglen);639break;640case 0x6c68: /* lh */641parse_lh(hdesc, vofs, seglen);642break;643case 0x6c69: /* li */644parse_li(hdesc, vofs, seglen);645break;646case 0x736b: /* sk */647parse_sk(hdesc, vofs, seglen);648break;649case 0x7269: /* ri */650parse_ri(hdesc, vofs, seglen);651break;652default:653printf("value data, or not handeled yet!\n");654break;655}656}657return(seglen);658}659660/* ================================================================ */661/* Scan and allocation routines */662663/* Find start of page given a current pointer into the buffer664* hdesc = hive665* vofs = offset pointer into buffer666* returns: offset to start of page (and page header)667*/668669int find_page_start(struct hive *hdesc, int vofs)670{671int r,prev;672struct hbin_page *h;673674/* Again, assume start at 0x1000 */675676r = 0x1000;677while (r < hdesc->size) {678prev = r;679h = (struct hbin_page *)(hdesc->buffer + r);680if (h->id != 0x6E696268) return(0);681if (h->ofs_next == 0) {682printf("find_page_start: zero len or ofs_next found in page at 0x%x\n",r);683return(0);684}685r += h->ofs_next;686if (r > vofs) return (prev);687}688return(0);689}690691/* Find free space in page692* size = requested size in bytes693* pofs = offset to start of actual page header694* returns: offset to free block, or 0 for error695*/696697#define FB_DEBUG 0698699int find_free_blk(struct hive *hdesc, int pofs, int size)700{701int vofs = pofs + 0x20;702int seglen;703struct hbin_page *p;704705p = (struct hbin_page *)(hdesc->buffer + pofs);706707while (vofs-pofs < (p->ofs_next - HBIN_ENDFILL)) {708709seglen = get_int(hdesc->buffer+vofs);710711#if FB_DEBUG712printf("** Block at offset %0x\n",vofs);713printf("seglen: %d, %u, 0x%0x\n",seglen,seglen,seglen);714#endif715716if (seglen == 0) {717printf("find_free_blk: FATAL! Zero data block size! (not registry or corrupt file?)\n");718debugit(hdesc->buffer,hdesc->size);719return(0);720}721722if (seglen < 0) {723seglen = -seglen;724#if FB_DEBUG725printf("USED BLOCK: %d, 0x%0x\n",seglen,seglen);726#endif727/* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */728} else {729#if FB_DEBUG730printf("FREE BLOCK!\n");731#endif732/* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */733if (seglen >= size) {734#if FB_DEBUG735printf("find_free_blk: found size %d block at 0x%x\n",seglen,vofs);736#endif737#if 0738if (vofs == 0x19fb8) {739printf("find_free_blk: vofs = %x, seglen = %x\n",vofs,seglen);740debugit(hdesc->buffer,hdesc->size);741abort();742}743#endif744return(vofs);745}746}747vofs += seglen;748}749return(0);750751}752753#undef FB_DEBUG754755/* Search pages from start to find free block756* hdesc - hive757* size - space requested, in bytes758* returns: offset to free block, 0 if not found or error759*/760761int find_free(struct hive *hdesc, int size)762{763int r,blk;764struct hbin_page *h;765766/* Align to 8 byte boundary */767if (size & 7) size += (8 - (size & 7));768769/* Again, assume start at 0x1000 */770771r = 0x1000;772while (r < hdesc->size) {773h = (struct hbin_page *)(hdesc->buffer + r);774if (h->id != 0x6E696268) return(0);775if (h->ofs_next == 0) {776printf("find_free: zero len or ofs_next found in page at 0x%x\n",r);777return(0);778}779blk = find_free_blk(hdesc,r,size);780if (blk) return (blk);781r += h->ofs_next;782}783return(0);784}785786/* Allocate a block of requested size if possible787* hdesc - hive788* pofs - If >0 will try this page first (ptr may be inside page)789* size - number of bytes to allocate790* returns: 0 - failed, else pointer to allocated block.791* This function WILL CHANGE THE HIVE (change block linkage) if it792* succeeds.793*/794795int alloc_block(struct hive *hdesc, int ofs, int size)796{797int pofs = 0;798int blk = 0;799int trail, trailsize, oldsz;800801if (hdesc->state & HMODE_NOALLOC) {802printf("alloc_block: ERROR: Hive %s is in no allocation safe mode,"803"new space not allocated. Operation will fail!\n", hdesc->filename);804return(0);805}806807size += 4; /* Add linkage */808if (size & 7) size += (8 - (size & 7));809810/* Check current page first */811if (ofs) {812pofs = find_page_start(hdesc,ofs);813blk = find_free_blk(hdesc,pofs,size);814}815816/* Then check whole hive */817if (!blk) {818blk = find_free(hdesc,size);819}820821if (blk) { /* Got the space */822oldsz = get_int(hdesc->buffer+blk);823#if 0824printf("Block at : %x\n",blk);825printf("Old block size is: %x\n",oldsz);826printf("New block size is: %x\n",size);827#endif828trailsize = oldsz - size;829830if (trailsize == 4) {831trailsize = 0;832size += 4;833}834835#if 1836if (trailsize & 7) { /* Trail must be 8 aligned */837trailsize -= (8 - (trailsize & 7));838size += (8 - (trailsize & 7));839}840if (trailsize == 4) {841trailsize = 0;842size += 4;843}844#endif845846#if 0847printf("trail after comp: %x\n",trailsize);848printf("size after comp: %x\n",size);849#endif850851/* Now change pointers on this to reflect new size */852*(int *)((hdesc->buffer)+blk) = -(size);853/* If the fit was exact (unused block was same size as wee need)854* there is no need for more, else make free block after end855* of newly allocated one */856857hdesc->useblk++;858hdesc->unuseblk--;859hdesc->usetot += size;860hdesc->unusetot -= size;861862if (trailsize) {863trail = blk + size;864865*(int *)((hdesc->buffer)+trail) = (int)trailsize;866867hdesc->useblk++; /* This will keep blockcount */868hdesc->unuseblk--;869hdesc->usetot += 4; /* But account for more linkage bytes */870hdesc->unusetot -= 4;871872}873/* Clear the block data, makes it easier to debug */874#if ZEROFILL875bzero( (void *)(hdesc->buffer+blk+4), size-4);876#endif877878hdesc->state |= HMODE_DIRTY;879880return(blk);881} else {882printf("alloc_block: failed to alloc %d bytes, and hive expansion not implemented yet!\n",size);883}884return(0);885}886887/* Free a block in registry888* hdesc - hive889* blk - offset of block, MUST POINT TO THE LINKAGE!890* returns bytes freed (incl linkage bytes) or 0 if fail891* Will CHANGE HIVE IF SUCCESSFUL (changes linkage)892*/893894#define FB_DEBUG 0895896int free_block(struct hive *hdesc, int blk)897{898int pofs,vofs,seglen,prev,next,nextsz,prevsz,size;899struct hbin_page *p;900901if (hdesc->state & HMODE_NOALLOC) {902printf("free_block: ERROR: Hive %s is in no allocation safe mode,"903"space not freed. Operation will fail!\n", hdesc->filename);904return(0);905}906907size = get_int(hdesc->buffer+blk);908if (size >= 0) {909printf("free_block: trying to free already free block!\n");910#ifdef DOCORE911printf("blk = %x\n",blk);912debugit(hdesc->buffer,hdesc->size);913abort();914#endif915return(0);916}917size = -size;918919/* So, we must find start of the block BEFORE us */920pofs = find_page_start(hdesc,blk);921if (!pofs) return(0);922923p = (struct hbin_page *)(hdesc->buffer + pofs);924vofs = pofs + 0x20;925926prevsz = -32;927928if (vofs != blk) { /* Block is not at start of page? */929while (vofs-pofs < (p->ofs_next - HBIN_ENDFILL) ) {930931seglen = get_int(hdesc->buffer+vofs);932933if (seglen == 0) {934printf("free_block: EEEK! Zero data block size! (not registry or corrupt file?)\n");935debugit(hdesc->buffer,hdesc->size);936return(0);937}938939if (seglen < 0) {940seglen = -seglen;941/* hexdump(hdesc->buffer,vofs,vofs+seglen+4,1); */942}943prev = vofs;944vofs += seglen;945if (vofs == blk) break;946}947948if (vofs != blk) {949printf("free_block: ran off end of page!?!? Error in chains?\n");950#ifdef DOCORE951printf("vofs = %x, pofs = %x, blk = %x\n",vofs,pofs,blk);952debugit(hdesc->buffer,hdesc->size);953abort();954#endif955return(0);956}957958prevsz = get_int(hdesc->buffer+prev);959960}961962/* We also need details on next block (unless at end of page) */963next = blk + size;964965nextsz = 0;966if (next-pofs < (p->ofs_next - HBIN_ENDFILL) ) nextsz = get_int(hdesc->buffer+next);967968#if 0969printf("offset prev : %x , blk: %x , next: %x\n",prev,blk,next);970printf("size prev : %x , blk: %x , next: %x\n",prevsz,size,nextsz);971#endif972973/* Now check if next block is free, if so merge it with the one to be freed */974if ( nextsz > 0) {975#if 0976printf("Swallow next\n");977#endif978size += nextsz; /* Swallow it in current block */979hdesc->useblk--;980hdesc->usetot -= 4;981hdesc->unusetot -= 4; /* FIXME !??!?? */982}983984/* Now free the block (possibly with ajusted size as above) */985#if ZEROFILL986bzero( (void *)(hdesc->buffer+blk), size);987#endif988989*(int *)((hdesc->buffer)+blk) = (int)size;990hdesc->usetot -= size;991hdesc->unusetot -= size; /* FIXME !?!? */992hdesc->unuseblk--;993994hdesc->state |= HMODE_DIRTY;995996/* Check if previous block is also free, if so, merge.. */997if (prevsz > 0) {998#if 0999printf("Swallow prev\n");1000#endif1001hdesc->usetot -= prevsz;1002hdesc->unusetot += prevsz;1003prevsz += size;1004/* And swallow current.. */1005#if ZEROFILL1006bzero( (void *)(hdesc->buffer+prev), prevsz);1007#endif1008*(int *)((hdesc->buffer)+prev) = (int)prevsz;1009hdesc->useblk--;1010return(prevsz);1011}1012return(size);1013}101410151016101710181019/* ================================================================ */10201021/* ** Registry manipulation routines ** */1022102310241025/* "directory scan", return next name/pointer of a subkey on each call1026* nkofs = offset to directory to scan1027* lfofs = pointer to int to hold the current scan position,1028* set position to 0 to start.1029* sptr = pointer to struct to hold a single result1030* returns: -1 = error. 0 = end of key. 1 = more subkeys to scan1031* NOTE: caller must free the name-buffer (struct ex_data *name)1032*/1033int ex_next_n(struct hive *hdesc, int nkofs, int *count, int *countri, struct ex_data *sptr)1034{1035struct nk_key *key, *newnkkey;1036int newnkofs;1037struct lf_key *lfkey;1038struct li_key *likey;1039struct ri_key *rikey;104010411042if (!nkofs) return(-1);1043key = (struct nk_key *)(hdesc->buffer + nkofs);1044if (key->id != 0x6b6e) {1045printf("ex_next error: Not a 'nk' node at 0x%0x\n",nkofs);1046return(-1);1047}10481049#define EXNDEBUG 010501051lfkey = (struct lf_key *)(hdesc->buffer + key->ofs_lf + 0x1004);1052rikey = (struct ri_key *)(hdesc->buffer + key->ofs_lf + 0x1004);10531054if (rikey->id == 0x6972) { /* Is it extended 'ri'-block? */1055#if EXNDEBUG1056printf("%d , %d\n",*countri,*count);1057#endif1058if (*countri < 0 || *countri >= rikey->no_lis) { /* End of ri's? */1059return(0);1060}1061/* Get the li of lf-struct that's current based on countri */1062likey = (struct li_key *)( hdesc->buffer + rikey->hash[*countri].ofs_li + 0x1004 ) ;1063if (likey->id == 0x696c) {1064newnkofs = likey->hash[*count].ofs_nk + 0x1000;1065} else {1066lfkey = (struct lf_key *)( hdesc->buffer + rikey->hash[*countri].ofs_li + 0x1004 ) ;1067newnkofs = lfkey->hash[*count].ofs_nk + 0x1000;1068}10691070/* Check if current li/lf is exhausted */1071#if EXNDEBUG1072printf("likey->no_keys = %d\n",likey->no_keys);1073#endif1074if (*count >= likey->no_keys-1) { /* Last legal entry in li list? */1075(*countri)++; /* Bump up ri count so we take next ri entry next time */1076(*count) = -1; /* Reset li traverse counter for next round, not used later here */1077}1078} else { /* Plain handler */1079if (key->no_subkeys <= 0 || *count >= key->no_subkeys) {1080return(0);1081}1082if (lfkey->id == 0x696c) { /* Is it 3.x 'li' instead? */1083likey = (struct li_key *)(hdesc->buffer + key->ofs_lf + 0x1004);1084newnkofs = likey->hash[*count].ofs_nk + 0x1000;1085} else {1086newnkofs = lfkey->hash[*count].ofs_nk + 0x1000;1087}1088}10891090sptr->nkoffs = newnkofs;1091newnkkey = (struct nk_key *)(hdesc->buffer + newnkofs + 4);1092sptr->nk = newnkkey;10931094if (newnkkey->id != 0x6b6e) {1095printf("ex_next: ERROR: not 'nk' node at 0x%0x\n",newnkofs);10961097return(-1);1098} else {1099if (newnkkey->len_name <= 0) {1100printf("ex_next: nk at 0x%0x has no name!\n",newnkofs);1101} else if (newnkkey->type & 0x20) {1102#if 01103printf("dummy1 %x\n", *((int*)newnkkey->dummy1));1104printf("dummy2 %x\n", *((int*)newnkkey->dummy2));1105printf("type %x\n", newnkkey->type);1106printf("timestamp+8 %x\n", *((int*)(newnkkey->timestamp+8)));1107printf("dummy3+0 %x\n", *((int*)(newnkkey->dummy3+0)));1108printf("dummy3+4 %x\n", *((int*)(newnkkey->dummy3+4)));1109printf("dummy3+8 %x\n", *((int*)(newnkkey->dummy3+8)));1110printf("dummy3+12 %x\n", *((int*)(newnkkey->dummy3+12)));1111printf("dummy4 %x\n", *((int*)&newnkkey->dummy4));1112printf("len %d\n", newnkkey->len_name);1113printf("len class %d\n", newnkkey->len_classnam);1114fflush(stdout);1115#endif1116sptr->name = string_rega2prog(newnkkey->keyname, newnkkey->len_name);1117} else {1118sptr->name = string_regw2prog(newnkkey->keyname, newnkkey->len_name);1119}1120} /* if */1121(*count)++;1122return(1);1123/* return( *count <= key->no_subkeys); */1124}11251126/* "directory scan" for VALUES, return next name/pointer of a value on each call1127* nkofs = offset to directory to scan1128* lfofs = pointer to int to hold the current scan position,1129* set position to 0 to start.1130* sptr = pointer to struct to hold a single result1131* returns: -1 = error. 0 = end of key. 1 = more values to scan1132* NOTE: caller must free the name-buffer (struct vex_data *name)1133*/1134int ex_next_v(struct hive *hdesc, int nkofs, int *count, struct vex_data *sptr)1135{1136struct nk_key *key /* , *newnkkey */ ;1137int vkofs,vlistofs;1138int *vlistkey;1139struct vk_key *vkkey;114011411142if (!nkofs) return(-1);1143key = (struct nk_key *)(hdesc->buffer + nkofs);1144if (key->id != 0x6b6e) {1145printf("ex_next_v error: Not a 'nk' node at 0x%0x\n",nkofs);1146return(-1);1147}11481149if (key->no_values <= 0 || *count >= key->no_values) {1150return(0);1151}11521153vlistofs = key->ofs_vallist + 0x1004;1154vlistkey = (int *)(hdesc->buffer + vlistofs);11551156vkofs = vlistkey[*count] + 0x1004;1157vkkey = (struct vk_key *)(hdesc->buffer + vkofs);1158if (vkkey->id != 0x6b76) {1159printf("ex_next_v: hit non valuekey (vk) node during scan at offs 0x%0x\n",vkofs);1160return(-1);1161}11621163/* parse_vk(hdesc, vkofs, 4); */11641165sptr->vk = vkkey;1166sptr->vkoffs = vkofs;1167sptr->name = 0;1168sptr->size = (vkkey->len_data & 0x7fffffff);11691170if (vkkey->len_name >0) {1171if (vkkey->flag & 1) {1172sptr->name = string_rega2prog(vkkey->keyname, vkkey->len_name);1173} else {1174sptr->name = string_regw2prog(vkkey->keyname, vkkey->len_name);1175}1176} else {1177sptr->name = str_dup("");1178}11791180sptr->type = vkkey->val_type;1181if (sptr->size) {1182if (vkkey->val_type == REG_DWORD) {1183if (vkkey->len_data & 0x80000000) {1184sptr->val = (int)(vkkey->ofs_data);1185}1186}1187} else if (vkkey->len_data == 0x80000000) {1188/* Data SIZE is 0, high bit set: special inline case, data is DWORD and in TYPE field!! */1189/* Used a lot in SAM, and maybe in SECURITY I think */1190sptr->val = (int)(vkkey->val_type);1191sptr->size = 4;1192sptr->type = REG_DWORD;1193} else {1194sptr->val = 0;1195sptr->size = 0;1196}11971198(*count)++;1199return( *count <= key->no_values );1200}12011202/* traceback - trace nk's back to root,1203* building path string as we go.1204* nkofs = offset to nk-node1205* path = pointer to pathstring-buffer1206* maxlen = max length of path-buffer1207* return: length of path string1208*/12091210int get_abs_path(struct hive *hdesc, int nkofs, char *path, int maxlen)1211{1212/* int newnkofs; */1213struct nk_key *key;1214char tmp[ABSPATHLEN+1];1215char *keyname;1216int len_name;12171218maxlen = (maxlen < ABSPATHLEN ? maxlen : ABSPATHLEN);12191220key = (struct nk_key *)(hdesc->buffer + nkofs);12211222if (key->id != 0x6b6e) {1223printf("get_abs_path: Not a 'nk' node!\n");1224return(0);1225}12261227if (key->type == KEY_ROOT) { /* We're at the root */1228return(strlen(path));1229}12301231strncpy(tmp,path,ABSPATHLEN-1);12321233if (key->type & 0x20)1234keyname = string_rega2prog(key->keyname, key->len_name);1235else1236keyname = string_regw2prog(key->keyname, key->len_name);1237len_name = strlen(keyname);1238if ( (strlen(path) + len_name) >= maxlen-6) {1239free(keyname);1240snprintf(path,maxlen,"(...)%s",tmp);1241return(strlen(path)); /* Stop trace when string exhausted */1242}1243*path = '\\';1244memcpy(path+1,keyname,len_name);1245free(keyname);1246strncpy(path+len_name+1,tmp,maxlen-6-len_name);1247return(get_abs_path(hdesc, key->ofs_parent+0x1004, path, maxlen)); /* go back one more */1248}124912501251/* Value index table lookup1252* hdesc - hive as usual1253* vlistofs - offset of table1254* name - value name to look for1255* returns index into table or -1 if err1256*/12571258int vlist_find(struct hive *hdesc, int vlistofs, int numval, char *name, int type)1259{1260struct vk_key *vkkey;1261int i,vkofs,len;1262int32_t *vlistkey;12631264len = strlen(name);1265vlistkey = (int32_t *)(hdesc->buffer + vlistofs);12661267for (i = 0; i < numval; i++) {1268vkofs = vlistkey[i] + 0x1004;1269vkkey = (struct vk_key *)(hdesc->buffer + vkofs);1270if (vkkey->len_name == 0 && *name == '@') { /* @ is alias for nameless value */1271return(i);1272}1273if ( !(type & TPF_EXACT) || vkkey->len_name == len ) {1274if (!strncmp(name, vkkey->keyname, len)) { /* name match? */1275return(i);1276}1277}1278}1279return(-1);12801281}12821283/* Recursevely follow 'nk'-nodes based on a path-string,1284* returning offset of last 'nk' or 'vk'1285* vofs - offset to start node1286* path - null-terminated pathname (relative to vofs, \ is separator)1287* type - type to return TPF_??, see ntreg.h1288* return: offset to nk or vk (or NULL if not found)1289*/12901291int trav_path(struct hive *hdesc, int vofs, char *path, int type)1292{1293struct nk_key *key, *newnkkey;1294struct lf_key *lfkey;1295struct li_key *likey;1296struct ri_key *rikey;12971298int32_t *vlistkey;1299int newnkofs, plen, i, lfofs, vlistofs, adjust, r, ricnt, subs;1300char *buf;1301char part[ABSPATHLEN+1];1302char *partptr;13031304if (!hdesc) return(0);1305buf = hdesc->buffer;13061307if (!vofs) vofs = hdesc->rootofs+4; /* No current key given , so start at root */13081309if (*path == '\\' && *(path+1) != '\\') { /* Start from root if path starts with \ */1310path++;1311vofs = hdesc->rootofs+4;1312}13131314key = (struct nk_key *)(buf + vofs);1315/* printf("check of nk at offset: 0x%0x\n",vofs); */13161317if (key->id != 0x6b6e) {1318printf("trav_path: Error: Not a 'nk' node!\n");1319return(0);1320}13211322/* Find \ delimiter or end of string, copying to name part buffer as we go,1323rewriting double \\s */1324partptr = part;1325for(plen = 0; path[plen] && (path[plen] != '\\' || path[plen+1] == '\\'); plen++) {1326if (path[plen] == '\\' && path[plen+1] == '\\') plen++; /* Skip one if double */1327*partptr++ = path[plen];1328}1329*partptr = '\0';13301331/* printf("Name component: <%s>\n",part); */13321333adjust = (path[plen] == '\\' ) ? 1 : 0;1334/* printf("Checking for <%s> with len %d\n",path,plen); */1335if (!plen) return(vofs-4); /* Path has no lenght - we're there! */1336if ( (plen == 1) && (*path == '.') && !(type & TPF_EXACT)) { /* Handle '.' current dir */1337return(trav_path(hdesc,vofs,path+plen+adjust,type));1338}1339if ( !(type & TPF_EXACT) && (plen == 2) && !strncmp("..",path,2) ) { /* Get parent key */1340newnkofs = key->ofs_parent + 0x1004;1341/* Return parent (or only root if at the root) */1342return(trav_path(hdesc, (key->type == KEY_ROOT ? vofs : newnkofs), path+plen+adjust, type));1343}13441345/* at last name of path, and we want vk, and the nk has values */1346if (!path[plen] && (type & TPF_VK) && key->no_values) {1347/* printf("VK namematch for <%s>\n",part); */1348vlistofs = key->ofs_vallist + 0x1004;1349vlistkey = (int32_t *)(buf + vlistofs);1350i = vlist_find(hdesc, vlistofs, key->no_values, part, type);1351if (i != -1) {1352return(vlistkey[i] + 0x1000);1353}1354}13551356if (key->no_subkeys > 0) { /* If it has subkeys, loop through the hash */1357char *partw = NULL;1358int partw_len, part_len;13591360lfofs = key->ofs_lf + 0x1004; /* lf (hash) record */1361lfkey = (struct lf_key *)(buf + lfofs);13621363if (lfkey->id == 0x6972) { /* ri struct need special parsing */1364/* Prime loop state */13651366rikey = (struct ri_key *)lfkey;1367ricnt = rikey->no_lis;1368r = 0;1369likey = (struct li_key *)( hdesc->buffer + rikey->hash[r].ofs_li + 0x1004 ) ;1370subs = likey->no_keys;1371if (likey->id != 0x696c) { /* Bwah, not li anyway, XP uses lh usually which is actually smarter */1372lfkey = (struct lf_key *)( hdesc->buffer + rikey->hash[r].ofs_li + 0x1004 ) ;1373likey = NULL;1374}1375} else {1376if (lfkey->id == 0x696c) { /* li? */1377likey = (struct li_key *)(buf + lfofs);1378} else {1379likey = NULL;1380}1381rikey = NULL;1382ricnt = 0; r = 0; subs = key->no_subkeys;1383}13841385partw = string_prog2regw(part, partptr-part, &partw_len);1386string_prog2rega(part, partptr-part);1387part_len = strlen(part);1388do {1389for(i = 0; i < subs; i++) {1390if (likey) newnkofs = likey->hash[i].ofs_nk + 0x1004;1391else newnkofs = lfkey->hash[i].ofs_nk + 0x1004;1392newnkkey = (struct nk_key *)(buf + newnkofs);1393if (newnkkey->id != 0x6b6e) {1394printf("ERROR: not 'nk' node! (strange?)\n");1395} else {1396if (newnkkey->len_name <= 0) {1397printf("[No name]\n");1398} else {1399int cmp;1400if (newnkkey->type & 0x20)1401cmp = strncmp(part,newnkkey->keyname,part_len);1402else1403cmp = memcmp(partw, newnkkey->keyname, partw_len);1404if (!cmp) {1405/* printf("Key at 0x%0x matches! recursing!\n",newnkofs); */1406free(partw);1407return(trav_path(hdesc, newnkofs, path+plen+adjust, type));1408}1409}1410} /* if id OK */1411} /* hash loop */1412r++;1413if (ricnt && r < ricnt) {1414newnkofs = rikey->hash[r].ofs_li;1415likey = (struct li_key *)( hdesc->buffer + newnkofs + 0x1004 ) ;1416subs = likey->no_keys;1417if (likey->id != 0x696c) { /* Bwah, not li anyway, XP uses lh usually which is actually smarter */1418lfkey = (struct lf_key *)( hdesc->buffer + rikey->hash[r].ofs_li + 0x1004 ) ;1419likey = NULL;1420}1421}1422} while (r < ricnt && ricnt);1423free(partw);14241425} /* if subkeys */14261427/* Not found */1428return(0);1429}143014311432/* ls - list a 'nk' nodes subkeys and values1433* vofs - offset to start of data (skipping block linkage)1434* type - 0 = full, 1 = keys only. 2 = values only1435*/1436void nk_ls(struct hive *hdesc, char *path, int vofs, int type)1437{1438struct nk_key *key;1439int nkofs;1440struct ex_data ex;1441struct vex_data vex;1442int count = 0, countri = 0;144314441445nkofs = trav_path(hdesc, vofs, path, 0);14461447if(!nkofs) {1448printf("nk_ls: Key <%s> not found\n",path);1449return;1450}1451nkofs += 4;14521453key = (struct nk_key *)(hdesc->buffer + nkofs);1454VERBF(hdesc,"ls of node at offset 0x%0x\n",nkofs);14551456if (key->id != 0x6b6e) {1457printf("Error: Not a 'nk' node!\n");14581459debugit(hdesc->buffer,hdesc->size);14601461}14621463printf("Node has %d subkeys and %d values",key->no_subkeys,key->no_values);1464if (key->len_classnam) printf(", and class-data of %d bytes",key->len_classnam);1465printf("\n");14661467if (key->no_subkeys) {1468printf(" key name\n");1469while ((ex_next_n(hdesc, nkofs, &count, &countri, &ex) > 0)) {1470if (!(hdesc->state & HMODE_VERBOSE)) printf("%c <%s>\n", (ex.nk->len_classnam)?'*':' ',ex.name);1471else printf("[%6x] %c <%s>\n", ex.nkoffs, (ex.nk->len_classnam)?'*':' ',ex.name);1472FREE(ex.name);1473}1474}1475count = 0;1476if (key->no_values) {1477printf(" size type value name [value if type DWORD]\n");1478while ((ex_next_v(hdesc, nkofs, &count, &vex) > 0)) {1479if (hdesc->state & HMODE_VERBOSE) printf("[%6x] %6d %-16s <%s>", vex.vkoffs, vex.size,1480(vex.type < REG_MAX ? val_types[vex.type] : "(unknown)"), vex.name);1481else1482printf("%6d %-16s <%s>", vex.size,1483(vex.type < REG_MAX ? val_types[vex.type] : "(unknown)"), vex.name);14841485if (vex.type == REG_DWORD) printf(" %*d [0x%x]",25-(int)strlen(vex.name),vex.val , vex.val);1486printf("\n");1487FREE(vex.name);1488}1489}1490}14911492/* Get the type of a value */1493int get_val_type(struct hive *hdesc, int vofs, char *path, int exact)1494{1495struct vk_key *vkkey;1496int vkofs;14971498vkofs = trav_path(hdesc, vofs,path,exact | TPF_VK);1499if (!vkofs) {1500return -1;1501}1502vkofs +=4;1503vkkey = (struct vk_key *)(hdesc->buffer + vkofs);1504#if 01505if (vkkey->len_data & 0x80000000) return(REG_DWORD); /* Special case of INLINE storage */1506#endif1507return(vkkey->val_type);1508}150915101511/* Get len of a value, given current key + path */1512int get_val_len(struct hive *hdesc, int vofs, char *path, int exact)1513{1514struct vk_key *vkkey;1515int vkofs;1516int len;15171518vkofs = trav_path(hdesc, vofs,path,exact | TPF_VK);1519if (!vkofs) {1520return -1;1521}1522vkofs +=4;1523vkkey = (struct vk_key *)(hdesc->buffer + vkofs);15241525len = vkkey->len_data & 0x7fffffff;15261527if ( vkkey->len_data == 0x80000000 ) { /* Special inline case, return size of 4 (dword) */1528len = 4;1529}15301531return(len);1532}15331534/* Get void-pointer to value-data, also if inline.1535* If val_type != 0 a check for correct value type is done1536* Caller must keep track of value's length (call function above to get it)1537*/1538void *get_val_data(struct hive *hdesc, int vofs, char *path, int val_type, int exact)1539{1540struct vk_key *vkkey;1541int vkofs;15421543vkofs = trav_path(hdesc,vofs,path,exact | TPF_VK);1544if (!vkofs) {1545return NULL;1546}1547vkofs +=4;1548vkkey = (struct vk_key *)(hdesc->buffer + vkofs);154915501551if (vkkey->len_data == 0) return NULL;1552if (vkkey->len_data == 0x80000000) { /* Special inline case (len = 0x80000000) */1553return(&vkkey->val_type); /* Data (4 bytes?) in type field */1554}15551556if (val_type && vkkey->val_type && (vkkey->val_type) != val_type) {1557printf("Value <%s> is not of correct type!\n",path);1558#if DOCORE1559abort();1560#endif1561return NULL;1562}15631564/* Negative len is inline, return ptr to offset-field which in1565* this case contains the data itself1566*/1567if (vkkey->len_data & 0x80000000) return(&vkkey->ofs_data);1568/* Normal return, return data pointer */1569return(hdesc->buffer + vkkey->ofs_data + 0x1004);1570}157115721573/* Get and copy key data (if any) to buffer1574* if kv==NULL will allocate needed return struct & buffer1575* else will use buffer allocated for it (if it fits)1576* return len+data or NULL if not found (or other error)1577* NOTE: caller must deallocate buffer! a simple free(keyval) will suffice.1578*/1579struct keyval *get_val2buf(struct hive *hdesc, struct keyval *kv,1580int vofs, char *path, int type, int exact )1581{1582int l;1583struct keyval *kr;1584void *keydataptr;15851586l = get_val_len(hdesc, vofs, path, exact);1587if (l == -1) return(NULL); /* error */1588if (kv && (kv->len < l)) return(NULL); /* Check for overflow of supplied buffer */15891590keydataptr = get_val_data(hdesc, vofs, path, type, exact);1591/* if (!keydataptr) return(NULL); error */15921593/* Allocate space for data + header, or use supplied buffer */1594if (kv) {1595kr = kv;1596} else {1597ALLOC(kr,1,l+sizeof(int)+4);1598}15991600kr->len = l;1601memcpy(&(kr->data), keydataptr, l);16021603return(kr);1604}16051606/* DWORDs are so common that I make a small function to get it easily */16071608int get_dword(struct hive *hdesc, int vofs, char *path, int exact)1609{1610struct keyval *v;1611int dword;16121613v = get_val2buf(hdesc, NULL, vofs, path, REG_DWORD, exact | TPF_VK);1614if (!v) return(-1); /* well... -1 COULD BE THE STORED VALUE TOO */16151616dword = (int)v->data;16171618FREE(v);16191620return(dword);16211622}16231624/* Sanity checker when transferring data into a block1625* ofs = offset to data block, point to start of actual datablock linkage1626* data = data to copy1627* size = size of data to copy1628*/16291630int fill_block(struct hive *hdesc, int ofs, void *data, int size)1631{1632int blksize;16331634blksize = get_int(hdesc->buffer + ofs);1635blksize = -blksize;16361637#if 01638printf("fill_block: ofs = %x - %x, size = %x, blksize = %x\n",ofs,ofs+size,size,blksize);1639#endif1640/* if (blksize < size || ( (ofs & 0xfffff000) != ((ofs+size) & 0xfffff000) )) { */1641if (blksize < size) {1642printf("fill_block: ERROR: block to small for data: ofs = %x, size = %x, blksize = %x\n",ofs,size,blksize);1643debugit(hdesc->buffer,hdesc->size);1644abort();1645}16461647memcpy(hdesc->buffer + ofs + 4, data, size);1648return(0);1649}165016511652/* Free actual data of a value, and update value descriptor1653* hdesc - hive1654* vofs - current key1655* path - path to value1656* we return offset of vk1657*/16581659int free_val_data(struct hive *hdesc, int vofs, char *path, int exact)1660{1661struct vk_key *vkkey;1662int vkofs, inl;16631664vkofs = trav_path(hdesc,vofs,path,1);1665if (!vkofs) {1666return 0;1667}1668vkofs +=4;1669vkkey = (struct vk_key *)(hdesc->buffer + vkofs);16701671inl = (vkkey->len_data & 0x80000000);16721673if (!inl) {1674free_block(hdesc, vkkey->ofs_data + 0x1000);1675}1676vkkey->len_data = 0;1677vkkey->ofs_data = 0;16781679return(vkofs);16801681}16821683/* Allocate data for value, realloc if it already contains stuff1684* hdesc - hive1685* vofs - current key1686* path - path to value1687* size - size of data1688* Returns: 0 - error, >0 pointer to actual dataspace1689*/16901691int alloc_val_data(struct hive *hdesc, int vofs, char *path, int size,int exact)1692{1693struct vk_key *vkkey;1694int vkofs, len;1695int datablk;16961697vkofs = trav_path(hdesc,vofs,path,1);1698if (!vkofs) {1699return (0);1700}17011702vkofs +=4;1703vkkey = (struct vk_key *)(hdesc->buffer + vkofs);17041705/* Allocate space for new data */1706datablk = alloc_block(hdesc, vkofs, size);1707if (!datablk) return(0);17081709len = vkkey->len_data & 0x7fffffff;17101711/* Then we dealloc if something was there before */1712if (len) free_val_data(hdesc,vofs,path,exact);17131714/* Link in new datablock */1715vkkey->ofs_data = datablk - 0x1000;1716vkkey->len_data = size;17171718return(datablk + 4);1719}172017211722/* Add a value to a key.1723* Just add the metadata (empty value), to put data into it, use1724* put_buf2val afterwards1725* hdesc - hive1726* nkofs - current key1727* name - name of value1728* type - type of value1729* returns: 0 err, >0 offset to value metadata1730*/17311732struct vk_key *add_value(struct hive *hdesc, int nkofs, char *name, int type)1733{1734struct nk_key *nk;1735int oldvlist = 0, newvlist, newvkofs;1736struct vk_key *newvkkey;1737char *blank="";17381739if (!name || !*name) return(NULL);174017411742nk = (struct nk_key *)(hdesc->buffer + nkofs);1743if (nk->id != 0x6b6e) {1744printf("add_value: Key pointer not to 'nk' node!\n");1745return(NULL);1746}17471748if (trav_path(hdesc, nkofs, name, 1)) {1749printf("add_value: value %s already exists\n",name);1750return(NULL);1751}17521753if (!strcmp(name,"@")) name = blank;17541755if (nk->no_values) oldvlist = nk->ofs_vallist;17561757newvlist = alloc_block(hdesc, nkofs, nk->no_values * 4 + 4);1758if (!newvlist) {1759printf("add_value: failed to allocate new value list!\n");1760return(NULL);1761}1762if (oldvlist) { /* Copy old data if any */1763memcpy(hdesc->buffer + newvlist + 4, hdesc->buffer + oldvlist + 0x1004, nk->no_values * 4 + 4);1764}17651766/* Allocate value descriptor including its name */1767newvkofs = alloc_block(hdesc, newvlist, sizeof(struct vk_key) + strlen(name));1768if (!newvkofs) {1769printf("add_value: failed to allocate value descriptor\n");1770free_block(hdesc, newvlist);1771return(NULL);1772}17731774/* Success, now fill in the metadata */17751776newvkkey = (struct vk_key *)(hdesc->buffer + newvkofs + 4);17771778/* Add pointer in value list */1779*(int *)(hdesc->buffer + newvlist + 4 + (nk->no_values * 4)) = newvkofs - 0x1000;17801781/* Fill in vk struct */1782newvkkey->id = 0x6b76;1783newvkkey->len_name = strlen(name);1784if (type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN) {1785newvkkey->len_data = 0x80000004; /* Prime the DWORD inline stuff */1786} else {1787newvkkey->len_data = 0x00000000;1788}1789newvkkey->ofs_data = 0;1790newvkkey->val_type = type;1791newvkkey->flag = 1; /* Don't really know what this is */1792newvkkey->dummy1 = 0;1793strcpy((char *)&newvkkey->keyname, name); /* And copy name */17941795/* Finally update the key and free the old valuelist */1796nk->no_values++;1797nk->ofs_vallist = newvlist - 0x1000;1798if (oldvlist) free_block(hdesc,oldvlist + 0x1000);17991800return(newvkkey);18011802}18031804/* Remove a vk-struct incl dataspace if any1805* Mostly for use by higher level stuff1806* hdesc - hive1807* vkofs - offset to vk1808*/18091810void del_vk(struct hive *hdesc, int vkofs)1811{1812struct vk_key *vk;18131814vk = (struct vk_key *)(hdesc->buffer + vkofs);1815if (vk->id != 0x6b76) {1816printf("del_vk: Key pointer not to 'vk' node!\n");1817return;1818}18191820if ( !(vk->len_data & 0x80000000) && vk->ofs_data) {1821free_block(hdesc, vk->ofs_data + 0x1000);1822}18231824free_block(hdesc, vkofs - 4);1825}18261827/* Delete all values from key (used in recursive delete)1828* hdesc - yer usual hive1829* nkofs - current keyoffset1830*/18311832void del_allvalues(struct hive *hdesc, int nkofs)1833{1834int vlistofs, o, vkofs;1835int32_t *vlistkey;1836struct nk_key *nk;18371838nk = (struct nk_key *)(hdesc->buffer + nkofs);1839if (nk->id != 0x6b6e) {1840printf("del_allvalues: Key pointer not to 'nk' node!\n");1841return;1842}18431844if (!nk->no_values) {1845/* printf("del_avalues: Key has no values!\n"); */1846return;1847}18481849vlistofs = nk->ofs_vallist + 0x1004;1850vlistkey = (int32_t *)(hdesc->buffer + vlistofs);18511852/* Loop through index and delete all vk's */1853for (o = 0; o < nk->no_values; o++) {1854vkofs = vlistkey[o] + 0x1004;1855del_vk(hdesc, vkofs);1856}18571858/* Then zap the index, and update nk */1859free_block(hdesc, vlistofs-4);1860nk->ofs_vallist = -1;1861nk->no_values = 0;1862}186318641865/* Delete single value from key1866* hdesc - yer usual hive1867* nkofs - current keyoffset1868* name - name of value to delete1869* exact - NKF_EXACT to do exact match, else first match1870* returns: 0 - ok, 1 - failed1871*/18721873int del_value(struct hive *hdesc, int nkofs, char *name, int exact)1874{1875int vlistofs, slot, o, n, vkofs, newlistofs;1876int32_t *vlistkey, *tmplist, *newlistkey;1877struct nk_key *nk;1878char *blank="";18791880if (!name || !*name) return(1);18811882if (!strcmp(name,"@")) name = blank;18831884nk = (struct nk_key *)(hdesc->buffer + nkofs);1885if (nk->id != 0x6b6e) {1886printf("del_value: Key pointer not to 'nk' node!\n");1887return(1);1888}18891890if (!nk->no_values) {1891printf("del_value: Key has no values!\n");1892return(1);1893}18941895vlistofs = nk->ofs_vallist + 0x1004;1896vlistkey = (int32_t *)(hdesc->buffer + vlistofs);18971898slot = vlist_find(hdesc, vlistofs, nk->no_values, name, TPF_VK);18991900if (slot == -1) {1901printf("del_value: value %s not found!\n",name);1902return(1);1903}19041905/* Delete vk and data */1906vkofs = vlistkey[slot] + 0x1004;1907del_vk(hdesc, vkofs);19081909/* Copy out old index list */1910CREATE(tmplist,int32_t,nk->no_values);1911memcpy(tmplist, vlistkey, nk->no_values * sizeof(int32_t));19121913free_block(hdesc,vlistofs-4); /* Get rid of old list */19141915nk->no_values--;19161917if (nk->no_values) {1918newlistofs = alloc_block(hdesc, vlistofs, nk->no_values * sizeof(int32_t));1919if (!newlistofs) {1920printf("del_value: FATAL: Was not able to alloc new index list\n");1921abort();1922}1923/* Now copy over, omitting deleted entry */1924newlistkey = (int32_t *)(hdesc->buffer + newlistofs + 4);1925for (n = 0, o = 0; o < nk->no_values+1; o++, n++) {1926if (o == slot) o++;1927newlistkey[n] = tmplist[o];1928}1929nk->ofs_vallist = newlistofs - 0x1000;1930} else {1931nk->ofs_vallist = -1;1932}1933return(0);1934}19351936193719381939/* Add a subkey to a key1940* hdesc - usual..1941* nkofs - offset of current nk1942* name - name of key to add1943* return: ptr to new keystruct, or NULL1944*/19451946#define AKDEBUG 11947struct nk_key *add_key(struct hive *hdesc, int nkofs, char *name)1948{19491950int slot, newlfofs = 0, oldlfofs = 0, newliofs = 0;1951int oldliofs = 0;1952int o, n, i, onkofs, newnkofs, cmp;1953int rimax, rislot, riofs, namlen;1954struct ri_key *ri = NULL;1955struct lf_key *newlf = NULL, *oldlf;1956struct li_key *newli = NULL, *oldli;1957struct nk_key *key, *newnk, *onk;1958int32_t hash;19591960key = (struct nk_key *)(hdesc->buffer + nkofs);19611962if (key->id != 0x6b6e) {1963printf("add_key: current ptr not 'nk'\n");1964return(NULL);1965}19661967namlen = strlen(name);19681969slot = -1;1970if (key->no_subkeys) { /* It already has subkeys */19711972oldlfofs = key->ofs_lf;1973oldliofs = key->ofs_lf;19741975oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);1976if (oldlf->id != 0x666c && oldlf->id != 0x686c && oldlf->id != 0x696c && oldlf->id != 0x6972) {1977printf("add_key: index type not supported: 0x%04x\n",oldlf->id);1978return(NULL);1979}19801981rimax = 0; ri = NULL; riofs = 0; rislot = -1;1982if (oldlf->id == 0x6972) { /* Indirect index 'ri', init loop */1983riofs = key->ofs_lf;1984ri = (struct ri_key *)(hdesc->buffer + riofs + 0x1004);1985rimax = ri->no_lis-1;19861987#ifdef AKDEBUG1988printf("add_key: entering 'ri' traverse, rimax = %d\n",rimax);1989#endif19901991oldliofs = ri->hash[rislot+1].ofs_li;1992oldlfofs = ri->hash[rislot+1].ofs_li;19931994}19951996do { /* 'ri' loop, at least run once if no 'ri' deep index */19971998if (ri) { /* Do next 'ri' slot */1999rislot++;2000oldliofs = ri->hash[rislot].ofs_li;2001oldlfofs = ri->hash[rislot].ofs_li;2002oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);2003oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);2004}20052006oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);2007oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);20082009#ifdef AKDEBUG2010printf("add_key: top of ri-loop: rislot = %d, rimax = %d\n",rislot,rimax);2011#endif2012slot = -1;20132014if (oldli->id == 0x696c) { /* li */20152016#ifdef AKDEBUG2017printf("add_key: li slot allocate\n");2018#endif20192020FREE(newli);2021ALLOC(newli, 8 + 4*oldli->no_keys + 4, 1);2022newli->no_keys = oldli->no_keys;2023newli->id = oldli->id;20242025/* Now copy old, checking where to insert (alphabetically) */2026for (o = 0, n = 0; o < oldli->no_keys; o++,n++) {2027onkofs = oldli->hash[o].ofs_nk;2028onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);2029if (slot == -1) {2030#if 12031printf("add_key: cmp <%s> with <%s>\n",name,onk->keyname);2032#endif20332034cmp = strncasecmp(name, onk->keyname, (namlen > onk->len_name) ? namlen : onk->len_name);2035if (!cmp) {2036printf("add_key: key %s already exists!\n",name);2037FREE(newli);2038return(NULL);2039}2040if ( cmp < 0) {2041slot = o;2042rimax = rislot; /* Cause end of 'ri' search, too */2043n++;2044#ifdef AKDEBUG2045printf("add_key: li-match: slot = %d\n",o);2046#endif2047}2048}2049newli->hash[n].ofs_nk = oldli->hash[o].ofs_nk;2050}2051if (slot == -1) slot = oldli->no_keys;20522053} else { /* lf or lh */20542055oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);20562057FREE(newlf);2058ALLOC(newlf, 8 + 8*oldlf->no_keys + 8, 1);2059newlf->no_keys = oldlf->no_keys;2060newlf->id = oldlf->id;2061#ifdef AKDEBUG2062printf("add_key: new lf/lh no_keys: %d\n",newlf->no_keys);2063#endif20642065/* Now copy old, checking where to insert (alphabetically) */2066for (o = 0, n = 0; o < oldlf->no_keys; o++,n++) {2067onkofs = oldlf->hash[o].ofs_nk;2068onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);2069if (slot == -1) {20702071#if 02072printf("add_key: cmp <%s> with <%s>\n",name,onk->keyname);2073#endif2074cmp = strncasecmp(name, onk->keyname, (namlen > onk->len_name) ? namlen : onk->len_name);2075if (!cmp) {2076printf("add_key: key %s already exists!\n",name);2077FREE(newlf);2078return(NULL);2079}2080if ( cmp < 0 ) {2081slot = o;2082rimax = rislot; /* Cause end of 'ri' search, too */2083n++;2084#ifdef AKDEBUG2085printf("add_key: lf-match: slot = %d\n",o);2086#endif2087}2088}2089newlf->hash[n].ofs_nk = oldlf->hash[o].ofs_nk;2090newlf->hash[n].name[0] = oldlf->hash[o].name[0];2091newlf->hash[n].name[1] = oldlf->hash[o].name[1];2092newlf->hash[n].name[2] = oldlf->hash[o].name[2];2093newlf->hash[n].name[3] = oldlf->hash[o].name[3];2094}2095if (slot == -1) slot = oldlf->no_keys;2096} /* li else check */209720982099} while ( (rislot < rimax) && (rimax > 0)); /* 'ri' wrapper loop */21002101} else { /* Parent was empty, make new index block */2102#ifdef AKDEBUG2103printf("add_key: new index!\n");2104#endif2105ALLOC(newlf, 8 + 8, 1);2106newlf->no_keys = 1;2107/* Use ID (lf, lh or li) we fetched from root node, so we use same as rest of hive */2108newlf->id = hdesc->nkindextype;2109slot = 0;2110} /* if has keys before */211121122113/* Make and fill in new nk */2114newnkofs = alloc_block(hdesc, nkofs, sizeof(struct nk_key) + strlen(name));2115if (!newnkofs) {2116printf("add_key: unable to allocate space for new key descriptor for %s!\n",name);2117FREE(newlf);2118FREE(newli);2119return(NULL);2120}2121newnk = (struct nk_key *)(hdesc->buffer + newnkofs + 4);21222123newnk->id = 0x6b6e;2124newnk->type = KEY_NORMAL;2125newnk->ofs_parent = nkofs - 0x1004;2126newnk->no_subkeys = 0;2127newnk->ofs_lf = 0;2128newnk->no_values = 0;2129newnk->ofs_vallist = -1;2130newnk->ofs_sk = key->ofs_sk; /* Get parents for now. 0 or -1 here crashes XP */2131newnk->ofs_classnam = -1;2132newnk->len_name = strlen(name);2133newnk->len_classnam = 0;2134strcpy(newnk->keyname, name);21352136if (newli) { /* Handle li */21372138#if AKDEBUG2139printf("add_key: li fill at slot: %d\n",slot);2140#endif21412142/* And put its offset into parents index list */2143newli->hash[slot].ofs_nk = newnkofs - 0x1000;2144newli->no_keys++;21452146/* Allocate space for our new li list and copy it into reg */2147newliofs = alloc_block(hdesc, nkofs, 8 + 4*newli->no_keys);2148if (!newliofs) {2149printf("add_key: unable to allocate space for new index table for %s!\n",name);2150FREE(newli);2151free_block(hdesc,newnkofs);2152return(NULL);2153}2154/* memcpy(hdesc->buffer + newliofs + 4, newli, 8 + 4*newli->no_keys); */2155fill_block(hdesc, newliofs, newli, 8 + 4*newli->no_keys);215621572158} else { /* lh or lf */21592160#ifdef AKDEBUG2161printf("add_key: lf/lh fill at slot: %d, rislot: %d\n",slot,rislot);2162#endif2163/* And put its offset into parents index list */2164newlf->hash[slot].ofs_nk = newnkofs - 0x1000;2165newlf->no_keys++;2166if (newlf->id == 0x666c) { /* lf hash */2167newlf->hash[slot].name[0] = 0;2168newlf->hash[slot].name[1] = 0;2169newlf->hash[slot].name[2] = 0;2170newlf->hash[slot].name[3] = 0;2171strncpy(newlf->hash[slot].name, name, 4);2172} else if (newlf->id == 0x686c) { /* lh. XP uses this. hashes whole name */2173for (i = 0,hash = 0; i < strlen(name); i++) {2174hash *= 37;2175hash += toupper(name[i]);2176}2177newlf->lh_hash[slot].hash = hash;2178}21792180/* Allocate space for our new lf list and copy it into reg */2181newlfofs = alloc_block(hdesc, nkofs, 8 + 8*newlf->no_keys);2182if (!newlfofs) {2183printf("add_key: unable to allocate space for new index table for %s!\n",name);2184FREE(newlf);2185free_block(hdesc,newnkofs);2186return(NULL);2187}2188/* memcpy(hdesc->buffer + newlfofs + 4, newlf, 8 + 8*newlf->no_keys); */2189fill_block(hdesc, newlfofs, newlf, 8 + 8*newlf->no_keys);21902191} /* li else */219221932194/* Update parent, and free old lf list */2195key->no_subkeys++;2196if (ri) { /* ri index */2197ri->hash[rislot].ofs_li = (newlf ? newlfofs : newliofs) - 0x1000;2198} else { /* Parent key */2199key->ofs_lf = (newlf ? newlfofs : newliofs) - 0x1000;2200}22012202if (newlf && oldlfofs) free_block(hdesc,oldlfofs + 0x1000);2203if (newli && oldliofs) free_block(hdesc,oldliofs + 0x1000);22042205FREE(newlf);2206FREE(newli);2207return(newnk);220822092210}22112212/* Delete a subkey from a key2213* hdesc - usual..2214* nkofs - offset of current nk2215* name - name of key to delete (must match exactly, also case)2216* return: 1 - err, 0 - ok2217*/22182219#undef DKDEBUG22202221int del_key(struct hive *hdesc, int nkofs, char *name)2222{22232224int slot = 0, newlfofs = 0, oldlfofs = 0, o, n, onkofs, delnkofs;2225int oldliofs = 0, no_keys = 0, newriofs = 0;2226int namlen;2227int rimax, riofs, rislot;2228struct ri_key *ri, *newri = NULL;2229struct lf_key *newlf = NULL, *oldlf = NULL;2230struct li_key *newli = NULL, *oldli = NULL;2231struct nk_key *key, *onk, *delnk;2232char fullpath[501];22332234key = (struct nk_key *)(hdesc->buffer + nkofs);22352236namlen = strlen(name);22372238if (key->id != 0x6b6e) {2239printf("add_key: current ptr not nk\n");2240return(1);2241}22422243slot = -1;2244if (!key->no_subkeys) {2245printf("del_key: key has no subkeys!\n");2246return(1);2247}22482249oldlfofs = key->ofs_lf;2250oldliofs = key->ofs_lf;22512252oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);2253if (oldlf->id != 0x666c && oldlf->id != 0x686c && oldlf->id != 0x696c && oldlf->id != 0x6972) {2254printf("del_key: index other than 'lf', 'li' or 'lh' not supported yet. 0x%04x\n",oldlf->id);2255return(1);2256}22572258rimax = 0; ri = NULL; riofs = 0;2259rislot = 0;22602261if (oldlf->id == 0x6972) { /* Indirect index 'ri', init loop */2262riofs = key->ofs_lf;2263ri = (struct ri_key *)(hdesc->buffer + riofs + 0x1004);2264rimax = ri->no_lis-1;22652266#ifdef DKDEBUG2267printf("del_key: entering 'ri' traverse, rimax = %d\n",rimax);2268#endif22692270rislot = -1; /* Starts at slot 0 below */22712272}22732274do { /* 'ri' loop, at least run once if no 'ri' deep index */22752276if (ri) { /* Do next 'ri' slot */2277rislot++;2278oldliofs = ri->hash[rislot].ofs_li;2279oldlfofs = ri->hash[rislot].ofs_li;2280}22812282oldli = (struct li_key *)(hdesc->buffer + oldliofs + 0x1004);2283oldlf = (struct lf_key *)(hdesc->buffer + oldlfofs + 0x1004);22842285#ifdef DKDEBUG2286printf("del_key: top of ri-loop: rislot = %d\n",rislot);2287#endif2288slot = -1;22892290if (oldlf->id == 0x696c) { /* 'li' handler */2291#ifdef DKDEBUG2292printf("del_key: li handler\n");2293#endif22942295FREE(newli);2296ALLOC(newli, 8 + 4*oldli->no_keys - 4, 1);2297newli->no_keys = oldli->no_keys - 1; no_keys = newli->no_keys;2298newli->id = oldli->id;22992300/* Now copy old, checking where to delete */2301for (o = 0, n = 0; o < oldli->no_keys; o++,n++) {2302onkofs = oldli->hash[o].ofs_nk;2303onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);2304if (slot == -1 && onk->len_name == namlen && !strncmp(name, onk->keyname, (onk->len_name > namlen) ? onk->len_name : namlen)) {2305slot = o;2306delnkofs = onkofs; delnk = onk;2307rimax = rislot;2308o++;2309}2310newli->hash[n].ofs_nk = oldli->hash[o].ofs_nk;2311}231223132314} else { /* 'lf' or 'lh' are similar */23152316#ifdef DKDEBUG2317printf("del_key: lf or lh handler\n");2318#endif2319FREE(newlf);2320ALLOC(newlf, 8 + 8*oldlf->no_keys - 8, 1);2321newlf->no_keys = oldlf->no_keys - 1; no_keys = newlf->no_keys;2322newlf->id = oldlf->id;23232324/* Now copy old, checking where to delete */2325for (o = 0, n = 0; o < oldlf->no_keys; o++,n++) {2326onkofs = oldlf->hash[o].ofs_nk;2327onk = (struct nk_key *)(onkofs + hdesc->buffer + 0x1004);2328if (slot == -1 && (onk->len_name == namlen) && !strncmp(name, onk->keyname, onk->len_name)) {2329slot = o;2330delnkofs = onkofs; delnk = onk;2331rimax = rislot;2332o++;2333}2334newlf->hash[n].ofs_nk = oldlf->hash[o].ofs_nk;2335newlf->hash[n].name[0] = oldlf->hash[o].name[0];2336newlf->hash[n].name[1] = oldlf->hash[o].name[1];2337newlf->hash[n].name[2] = oldlf->hash[o].name[2];2338newlf->hash[n].name[3] = oldlf->hash[o].name[3];2339}2340} /* else lh or lf */23412342} while (rislot < rimax); /* ri traverse loop */23432344if (slot == -1) {2345printf("del_key: subkey %s not found!\n",name);2346FREE(newlf);2347FREE(newli);2348return(1);2349}23502351#ifdef DKDEBUG2352printf("del_key: key found at slot %d\n",slot);2353#endif23542355if (delnk->no_values || delnk->no_subkeys) {2356printf("del_key: subkey %s has subkeys or values. Not deleted.\n",name);2357FREE(newlf);2358FREE(newli);2359return(1);2360}23612362/* Allocate space for our new lf list and copy it into reg */2363if ( no_keys && (newlf || newli) ) {2364newlfofs = alloc_block(hdesc, nkofs, 8 + (newlf ? 8 : 4) * no_keys);2365#ifdef DKDEBUG2366printf("del_key: alloc_block for index returns: %x\n",newlfofs);2367#endif2368if (!newlfofs) {2369printf("del_key: WARNING: unable to allocate space for new key descriptor for %s! Not deleted\n",name);2370FREE(newlf);2371return(1);2372}23732374/* memcpy(hdesc->buffer + newlfofs + 4,2375((void *)newlf ? (void *)newlf : (void *)newli), 8 + (newlf ? 8 : 4) * no_keys);2376*/2377fill_block(hdesc, newlfofs,2378((void *)newlf ? (void *)newlf : (void *)newli), 8 + (newlf ? 8 : 4) * no_keys);237923802381} else { /* Last deleted, will throw away index */2382newlfofs = 0xfff; /* We subtract 0x1000 later */2383}23842385if (newlfofs < 0xfff) {2386printf("del_key: ERROR: newlfofs = %x\n",newlfofs);2387#if DOCORE2388debugit(hdesc->buffer,hdesc->size);2389abort();2390#endif2391}23922393/* Check for CLASS data, if so, deallocate it too */2394if (delnk->len_classnam) {2395free_block(hdesc, delnk->ofs_classnam + 0x1000);2396}2397/* Now it's safe to zap the nk */2398free_block(hdesc, delnkofs + 0x1000);2399/* And the old index list */2400free_block(hdesc, (oldlfofs ? oldlfofs : oldliofs) + 0x1000);24012402/* Update parent */2403key->no_subkeys--;24042405if (ri) {2406if (newlfofs == 0xfff) {24072408*fullpath = 0;2409get_abs_path(hdesc, nkofs, fullpath, 480);24102411VERBF(hdesc,"del_key: need to delete ri-slot %d for %x - %s\n", rislot,nkofs,fullpath );24122413if (ri->no_lis > 1) { /* We have subindiceblocks left? */2414/* Delete from array */2415ALLOC(newri, 8 + 4*ri->no_lis - 4, 1);2416newri->no_lis = ri->no_lis - 1;2417newri->id = ri->id;2418for (o = 0, n = 0; o < ri->no_lis; o++,n++) {2419if (n == rislot) o++;2420newri->hash[n].ofs_li = ri->hash[o].ofs_li;2421}2422newriofs = alloc_block(hdesc, nkofs, 8 + newri->no_lis*4 );2423if (!newriofs) {2424printf("del_key: WARNING: unable to allocate space for ri-index for %s! Not deleted\n",name);2425FREE(newlf);2426FREE(newri);2427return(1);2428}2429fill_block(hdesc, newriofs, newri, 8 + newri->no_lis * 4);2430free_block(hdesc, riofs + 0x1000);2431key->ofs_lf = newriofs - 0x1000;2432FREE(newri);2433} else { /* Last entry in ri was deleted, get rid of it, key is empty */2434VERB(hdesc,"del_key: .. and that was the last one. key now empty!\n");2435free_block(hdesc, riofs + 0x1000);2436key->ofs_lf = -1;2437}2438} else {2439ri->hash[rislot].ofs_li = newlfofs - 0x1000;2440}2441} else {2442key->ofs_lf = newlfofs - 0x1000;2443}24442445FREE(newlf);2446return(0);24472448}24492450/* Recursive delete keys2451* hdesc - usual..2452* nkofs - offset of current nk2453* name - name of key to delete2454* return: 0 - ok, 1 fail2455*/2456void rdel_keys(struct hive *hdesc, char *path, int vofs)2457{2458struct nk_key *key;2459int nkofs;2460struct ex_data ex;2461int count = 0, countri = 0;246224632464if (!path || !*path) return;24652466nkofs = trav_path(hdesc, vofs, path, TPF_NK_EXACT);24672468if(!nkofs) {2469printf("rdel_keys: Key <%s> not found\n",path);2470return;2471}2472nkofs += 4;24732474key = (struct nk_key *)(hdesc->buffer + nkofs);24752476/*2477VERBF(hdesc,"rdel of node at offset 0x%0x\n",nkofs);2478*/24792480if (key->id != 0x6b6e) {2481printf("Error: Not a 'nk' node!\n");24822483debugit(hdesc->buffer,hdesc->size);24842485}24862487#if 02488printf("Node has %d subkeys and %d values\n",key->no_subkeys,key->no_values);2489#endif2490if (key->no_subkeys) {2491while ((ex_next_n(hdesc, nkofs, &count, &countri, &ex) > 0)) {2492#if 02493printf("%s\n",ex.name);2494#endif2495rdel_keys(hdesc, ex.name, nkofs);2496count = 0;2497countri = 0;2498FREE(ex.name);2499}2500}25012502del_allvalues(hdesc, nkofs);2503del_key(hdesc, key->ofs_parent+0x1004, path);25042505}250625072508/* Get and copy keys CLASS-data (if any) to buffer2509* Returns a buffer with the data (first int32_t is size). see ntreg.h2510* NOTE: caller must deallocate buffer! a simple free(keyval) will suffice.2511*/2512struct keyval *get_class(struct hive *hdesc,2513int curnk, char *path)2514{2515int clen = 0, dofs = 0, nkofs;2516struct nk_key *key;2517struct keyval *data;2518void *classdata;25192520if (!path && !curnk) return(NULL);25212522nkofs = trav_path(hdesc, curnk, path, 0);25232524if(!nkofs) {2525printf("get_class: Key <%s> not found\n",path);2526return(NULL);2527}2528nkofs += 4;2529key = (struct nk_key *)(hdesc->buffer + nkofs);25302531clen = key->len_classnam;2532if (!clen) {2533printf("get_class: Key has no class data.\n");2534return(NULL);2535}25362537dofs = key->ofs_classnam;2538classdata = (void *)(hdesc->buffer + dofs + 0x1004);25392540#if 02541printf("get_class: len_classnam = %d\n",clen);2542printf("get_class: ofs_classnam = 0x%x\n",dofs);2543#endif25442545ALLOC(data, sizeof(struct keyval) + clen,1);2546data->len = clen;2547memcpy(&data->data, classdata, clen);2548return(data);2549}255025512552/* Write to registry value.2553* If same size as existing, copy back in place to avoid changing too much2554* otherwise allocate new dataspace, then free the old2555* Thus enough space to hold both new and old data is needed2556* Pass inn buffer with data len as first DWORD (as routines above)2557* returns: 0 - error, len - OK (len of data)2558*/25592560int put_buf2val(struct hive *hdesc, struct keyval *kv,2561int vofs, char *path, int type, int exact )2562{2563int l;2564void *keydataptr;25652566if (!kv) return(0);2567l = get_val_len(hdesc, vofs, path, exact);2568if (l == -1) return(0); /* error */2569if (kv->len != l) { /* Realloc data block if not same size as existing */2570if (!alloc_val_data(hdesc, vofs, path, kv->len, exact)) {2571printf("put_buf2val: %s : alloc_val_data failed!\n",path);2572return(0);2573}2574}25752576keydataptr = get_val_data(hdesc, vofs, path, type, exact);2577if (!keydataptr) return(0); /* error */25782579memcpy(keydataptr, &kv->data, kv->len);25802581hdesc->state |= HMODE_DIRTY;25822583return(kv->len);2584}25852586/* And, yer basic DWORD write */25872588int put_dword(struct hive *hdesc, int vofs, char *path, int exact, int dword)2589{2590struct keyval *kr;2591int r;25922593ALLOC(kr,1,sizeof(int)+sizeof(int));25942595kr->len = sizeof(int);2596kr->data = dword;25972598r = put_buf2val(hdesc, kr, vofs, path, REG_DWORD, exact);25992600FREE(kr);26012602return(r);2603}26042605/* ================================================================ */26062607/* Code to export registry entries to .reg file initiated by2608* Leo von Klenze2609* Then expanded a bit to handle more types etc.2610*/26112612/*2613* converts a value string from an registry entry into a c string. It does not2614* use any encoding functions.2615* It works very primitive by just taking every second char.2616* The caller must free the resulting string, that was allocated with malloc.2617*2618* string: string where every second char is \02619* len: length of the string2620* return: the converted string as char*2621*/2622static char *2623string_regw2prog(void *string, int len)2624{2625int i, k;2626char *cstring;26272628int out_len = 0;2629for(i = 0; i < len; i += 2)2630{2631unsigned v = ((unsigned char *)string)[i] + ((unsigned char *)string)[i+1] * 256u;2632if (v < 128)2633out_len += 1;2634else if(v < 0x800)2635out_len += 2;2636else2637out_len += 3;2638}2639cstring = (char *) malloc(out_len+1);2640if (!cstring) {2641printf("FATAL! ex_next: malloc() failed! Out of memory?\n");2642abort();2643}26442645for(i = 0, k = 0; i < len; i += 2)2646{2647unsigned v = ((unsigned char *)string)[i] + ((unsigned char *)string)[i+1] * 256u;2648if (v < 128)2649cstring[k++] = v;2650else if(v < 0x800) {2651cstring[k++] = 0xc0 | (v >> 6);2652cstring[k++] = 0x80 | (v & 0x3f);2653} else {2654cstring[k++] = 0xe0 | (v >> 12);2655cstring[k++] = 0x80 | ((v >> 6) & 0x3f);2656cstring[k++] = 0x80 | (v & 0x3f);2657}2658}2659cstring[out_len] = '\0';26602661return cstring;2662}26632664static char *2665string_rega2prog(void *string, int len)2666{2667int i, k;2668char *cstring;26692670int out_len = 0;2671for(i = 0; i < len; ++i)2672{2673unsigned v = ((unsigned char *)string)[i];2674if (v < 128)2675out_len += 1;2676else2677out_len += 2;2678}2679cstring = (char *) malloc(out_len+1);2680if (!cstring) {2681printf("FATAL! ex_next: malloc() failed! Out of memory?\n");2682abort();2683}26842685for(i = 0, k = 0; i < len; ++i)2686{2687unsigned v = ((unsigned char *)string)[i];2688if (v < 128)2689cstring[k++] = v;2690else {2691cstring[k++] = 0xc0 | (v >> 6);2692cstring[k++] = 0x80 | (v & 0x3f);2693}2694}2695cstring[out_len] = '\0';26962697return cstring;2698}26992700static void2701string_prog2rega(char *string, int len)2702{2703char *out = string;2704unsigned char *in = (unsigned char*) string;27052706for (;*in; ++in) {2707if (!(*in & 0x80)) {2708*out++ = *in;2709} else if ((in[0] & 0xe0) == 0xc0 && in[1]) {2710*out++ = (in[0] & 0x1f) << 6 | (in[1] & 0x3f);2711++in;2712} else if (in[1] && in[2]) {2713/* assume 3 byte*/2714*out++ = (in[1] & 0xf) << 6 | (in[2] & 0x3f);2715in += 2;2716}2717}2718*out = 0;2719}27202721static char *2722string_prog2regw(void *string, int len, int *out_len)2723{2724unsigned char *regw = (unsigned char*) malloc(len*2+2);2725unsigned char *out = regw;2726unsigned char *in = (unsigned char*) string;27272728for (;len>0; ++in, --len) {2729if (!(in[0] & 0x80)) {2730*out++ = *in;2731*out++ = 0;2732} else if ((in[0] & 0xe0) == 0xc0 && len >= 2) {2733*out++ = (in[0] & 0x1f) << 6 | (in[1] & 0x3f);2734*out++ = (in[0] & 0x1f) >> 2;2735++in, --len;2736} else if (len >= 3) {2737/* assume 3 byte*/2738*out++ = (in[1] & 0xf) << 6 | (in[2] & 0x3f);2739*out++ = (in[0] & 0xf) << 4 | ((in[1] & 0x3f) >> 2);2740in += 2;2741len -= 2;2742}2743}2744*out_len = out - regw;2745out[0] = out[1] = 0;2746return (char *) regw;2747}27482749static char *2750quote_string(const char *s)2751{2752int len = strlen(s);2753const char *p;2754char *dst, *out;27552756for (p = s; *p; ++p)2757if (*p == '\\' || *p == '\"')2758++len;27592760dst = out = (char*) malloc(len + 1);2761for (p = s; *p; ++p) {2762if (*p == '\\' || *p == '\"')2763*dst++ = '\\';2764*dst++ = *p;2765}2766*dst = 0;2767return out;2768}27692770static void2771export_bin(int type, char *value, int len, int col, FILE* file)2772{2773int byte;27742775if (type == REG_BINARY) {2776fprintf(file, "hex:");2777col += 4;2778} else {2779fprintf(file, "hex(%x):", type);2780col += 7;2781}2782byte = 0;2783int start = (col - 2) / 3;2784while (byte + 1 < len) { /* go byte by byte.. probably slow.. */2785fprintf(file, "%02x,", (unsigned char)value[byte]);2786byte++;2787if (!((byte + start) % 25)) fprintf(file, "\\\r\n ");2788}2789if (len)2790fprintf(file, "%02x\r\n", (unsigned char)value[len - 1]);2791}27922793/*2794* Exports the named subkey and its values to the given file.2795*2796* hdesc: registry hive2797* nkofs: offset of parent node2798* name: name of key to export2799* prefix: prefix for each key. This prefix is prepended to the keyname2800* file: file descriptor of destination file2801*/2802void export_subkey(struct hive *hdesc, int nkofs, char *name, char *prefix, FILE *file)2803{2804int newofs;2805int count = 0;2806int countri = 0;2807int len;2808char *path = (char*) malloc(1024);2809char *value;2810struct nk_key *key;2811struct ex_data ex;2812struct vex_data vex;281328142815// switch to key2816newofs = trav_path(hdesc, nkofs, name, TPF_NK_EXACT);2817if(!newofs)2818{2819printf("Key '%s' not found!\n", name);2820free(path);2821return;2822}2823nkofs = newofs + 4;28242825// get the key2826key = (struct nk_key *)(hdesc->buffer + nkofs);2827printf("Exporting key '%.*s' with %d subkeys and %d values...\n",2828key->len_name, key->keyname, key->no_subkeys, key->no_values);28292830*path = 0;2831get_abs_path(hdesc, nkofs, path, 1024);28322833// export the key2834fprintf(file, "\r\n");2835fprintf(file, "[%s\%s]\r\n", prefix, path);2836// export values2837if(key->no_values)2838{2839while ((ex_next_v(hdesc, nkofs, &count, &vex) > 0))2840{2841int col = 0;2842char *name = quote_string(vex.name);28432844/* print name */2845if (!name[0]) {2846fprintf(file, "@=");2847free(name);2848name = str_dup("@");2849col += 2;2850} else {2851fprintf(file, "\"%s\"=", name);2852col += strlen(name) + 3;2853}28542855if(vex.type == REG_DWORD)2856{2857fprintf(file, "dword:%08x\r\n", vex.val);2858}2859else if(vex.type == REG_SZ)2860{2861char *val, *quoted;2862value = (char *)get_val_data(hdesc, nkofs, name, vex.type, TPF_VK_EXACT);2863len = get_val_len(hdesc, nkofs, name, TPF_VK_EXACT);28642865val = string_regw2prog(value, len);2866/* dump as binary if invalid characters are embedded */2867if (strchr(val, 0xa) || strchr(val, 0xd))2868{2869free(val);2870//if (len >= 2 && value[len-2] == 0 && value[len-1] == 0) len -= 2;2871export_bin(vex.type, value, len, col, file);2872}2873else2874{2875quoted = quote_string(val);2876free(val);2877fprintf(file, "\"%s\"", quoted);2878free(quoted);2879fprintf(file, "\r\n");2880}2881}2882else2883{2884/* All other types seems to simply be hexdumped. Format is:2885"valuename"=hex(typenum):xx,xx,xx,xx,xx...2886for example:2887"qword64"=hex(b):4e,03,51,db,fa,04,00,002888this is type = 0xb = 11 = REG_QWORD2889"expandstring"=hex(2):46,00,6f,00,6f,00,62,00,61,00,72,00,20,00,25,00,73,00,20,\289000,42,00,61,00,7a,00,00,002891this is type 2 = REG_EXPAND_SZ and the line is continued with ,\<CR><LF><space><space>2892don't know how many bytes for each line. Around 18-24 seems to be it?? depends on name lenght??2893NOTE: Exception:2894type = REG_BINARY starts like this: "valuename"=hex:xx,xx,xx...2895*/2896value = (char *)get_val_data(hdesc, nkofs, name, vex.type, TPF_VK_EXACT);2897len = get_val_len(hdesc, nkofs, name, TPF_VK_EXACT);28982899export_bin(vex.type, value, len, col, file);2900}29012902FREE(vex.name);2903free(name);2904}2905}29062907// export subkeys2908if (key->no_subkeys)2909{2910count = 0;2911countri = 0;2912while ((ex_next_n(hdesc, nkofs, &count, &countri, &ex) > 0))2913{2914export_subkey(hdesc, nkofs, ex.name, prefix, file);2915FREE(ex.name);2916}2917}2918free(path);2919}29202921/*2922* Exports the given key to a windows .reg file that can be imported to the2923* windows registry.2924* The prefix is used to determine the destination hive in the windows2925* registry, set it to HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE or whatever you2926* want.2927*2928* hdesc: hive2929* nkofs: offset of parent node2930* name: name of subkey to export2931* filename: name of destination .reg file (will be overridden)2932* prefix: prefix for each exported key2933*/2934void export_key(struct hive *hdesc, int nkofs, char *name, char *filename, char *prefix)2935{2936FILE *file;29372938// open file2939file = fopen(filename, "w");2940if(!file)2941{2942printf("Cannot open file '%s'. %s (%d).\n", filename, strerror(errno),2943errno);2944return;2945}29462947printf("Exporting to file '%s'...\n", filename);2948fprintf(file, "Windows Registry Editor Version 5.00\r\n");2949export_subkey(hdesc, nkofs, name, prefix, file);29502951fclose(file);2952}295329542955/* ================================================================ */29562957/* Hive control (load/save/close) etc */29582959void closeHive(struct hive *hdesc)2960{29612962printf("closing hive %s\n",hdesc->filename);2963if (hdesc->state & HMODE_OPEN) {2964close(hdesc->filedesc);2965}2966FREE(hdesc->filename);2967FREE(hdesc->buffer);2968FREE(hdesc);29692970}29712972/* Write the hive back to disk (only if dirty & not readonly */2973int writeHive(struct hive *hdesc)2974{2975int len, i;2976struct regf_header *hdr;2977int32_t checksum;29782979if (hdesc->state & HMODE_RO) return(0);2980if ( !(hdesc->state & HMODE_DIRTY)) return(0);29812982if ( !(hdesc->state & HMODE_OPEN)) { /* File has been closed */2983if (!(hdesc->filedesc = open(hdesc->filename,O_RDWR))) {2984fprintf(stderr,"writeHive: open(%s) failed: %s, FILE NOT WRITTEN!\n",hdesc->filename,strerror(errno));2985return(1);2986}2987hdesc->state |= HMODE_OPEN;2988}2989/* Seek back to begginning of file (in case it's already open) */2990lseek(hdesc->filedesc, 0, SEEK_SET);29912992/* compute new checksum */2993hdr = (struct regf_header *) hdesc->buffer;2994checksum = 0;2995for (i = 0; i < 0x1fc/4; ++i)2996checksum ^= ((int32_t *) hdr)[i];2997hdr->checksum = checksum;29982999len = write(hdesc->filedesc, hdesc->buffer, hdesc->size);3000if (len != hdesc->size) {3001fprintf(stderr,"writeHive: write of %s failed: %s.\n",hdesc->filename,strerror(errno));3002return(1);3003}30043005hdesc->state &= (~HMODE_DIRTY);3006return(0);3007}30083009struct hive *openHive(char *filename, int mode)3010{30113012struct hive *hdesc;3013int fmode,r,vofs;3014struct stat sbuf;3015uint32_t pofs;3016/* off_t l; */3017char *c;3018struct hbin_page *p;3019struct regf_header *hdr;3020struct nk_key *nk;3021struct ri_key *rikey;3022int verbose = (mode & HMODE_VERBOSE);3023int trace = (mode & HMODE_TRACE);30243025CREATE(hdesc,struct hive,1);30263027hdesc->filename = str_dup(filename);3028hdesc->state = 0;3029hdesc->size = 0;3030hdesc->buffer = NULL;30313032if ( (mode & HMODE_RO) ) {3033fmode = O_RDONLY;3034} else {3035fmode = O_RDWR;3036}3037hdesc->filedesc = open(hdesc->filename,fmode);3038if (hdesc->filedesc < 0) {3039fprintf(stderr,"openHive(%s) failed: %s, trying read-only\n",hdesc->filename,strerror(errno));3040fmode = O_RDONLY;3041mode |= HMODE_RO;3042hdesc->filedesc = open(hdesc->filename,fmode);3043if (hdesc->filedesc < 0) {3044fprintf(stderr,"openHive(%s) in fallback RO-mode failed: %s\n",hdesc->filename,strerror(errno));3045closeHive(hdesc);3046return(NULL);3047}3048}304930503051if ( fstat(hdesc->filedesc,&sbuf) ) {3052perror("stat()");3053exit(1);3054}30553056hdesc->size = sbuf.st_size;3057hdesc->state = mode | HMODE_OPEN;3058/* fprintf(stderr,"hiveOpen(%s) successful\n",hdesc->filename); */30593060/* Read the whole file */30613062ALLOC(hdesc->buffer,1,hdesc->size);30633064r = read(hdesc->filedesc,hdesc->buffer,hdesc->size);3065if (r < hdesc->size) {3066fprintf(stderr,"Could not read file, got %d bytes while expecting %d\n",3067r, hdesc->size);3068closeHive(hdesc);3069return(NULL);3070}30713072/* Now run through file, tallying all pages */3073/* NOTE/KLUDGE: Assume first page starts at offset 0x1000 */30743075pofs = 0x1000;30763077hdr = (struct regf_header *)hdesc->buffer;3078if (hdr->id != 0x66676572) {3079printf("openHive(%s): File does not seem to be a registry hive!\n",filename);3080return(hdesc);3081}3082printf("Hive <%s> name (from header): <",filename);3083for (c = hdr->name; *c && (c < hdr->name + 64); c += 2) putchar(*c);30843085hdesc->rootofs = hdr->ofs_rootkey + 0x1000;3086printf(">\nROOT KEY at offset: 0x%06x * ",hdesc->rootofs);30873088/* Cache the roots subkey index type (li,lf,lh) so we can use the correct3089* one when creating the first subkey in a key */30903091nk = (struct nk_key *)(hdesc->buffer + hdesc->rootofs + 4);3092if (nk->id == 0x6b6e) {3093rikey = (struct ri_key *)(hdesc->buffer + nk->ofs_lf + 0x1004);3094hdesc->nkindextype = rikey->id;3095if (hdesc->nkindextype == 0x6972) { /* Gee, big root, must check indirectly */3096printf("load_hive: DEBUG: BIG ROOT!\n");3097rikey = (struct ri_key *)(hdesc->buffer + rikey->hash[0].ofs_li + 0x1004);3098hdesc->nkindextype = rikey->id;3099}3100if (hdesc->nkindextype != 0x666c &&3101hdesc->nkindextype != 0x686c &&3102hdesc->nkindextype != 0x696c) {3103hdesc->nkindextype = 0x666c;3104}31053106printf("Subkey indexing type is: %04x <%c%c>\n",3107hdesc->nkindextype,3108hdesc->nkindextype & 0xff,3109hdesc->nkindextype >> 8);3110} else {3111printf("load_hive: WARNING: ROOT key does not seem to be a key! (not type == nk)\n");3112}3113311431153116while (pofs < hdesc->size) {3117#ifdef LOAD_DEBUG3118if (trace) hexdump(hdesc->buffer,pofs,pofs+0x20,1);3119#endif3120p = (struct hbin_page *)(hdesc->buffer + pofs);3121if (p->id != 0x6E696268) {3122printf("Page at 0x%x is not 'hbin', assuming file contains garbage at end\n",pofs);3123break;3124}3125hdesc->pages++;3126#ifdef LOAD_DEBUG3127if (trace) printf("\n###### Page at 0x%0lx has size 0x%0lx, next at 0x%0lx ######\n",pofs,p->len_page,p->ofs_next);3128#endif3129if (p->ofs_next == 0) {3130#ifdef LOAD_DEBUG3131if (trace) printf("openhive debug: bailing out.. pagesize zero!\n");3132#endif3133return(hdesc);3134}3135#if 03136if (p->len_page != p->ofs_next) {3137#ifdef LOAD_DEBUG3138if (trace) printf("openhive debug: len & ofs not same. HASTA!\n");3139#endif3140exit(0);3141}3142#endif314331443145vofs = pofs + 0x20; /* Skip page header */3146#if 13147while (vofs-pofs < p->ofs_next && vofs < hdesc->size) {3148vofs += parse_block(hdesc,vofs,trace);31493150}3151#endif3152pofs += p->ofs_next;3153}3154printf("File size %d [%x] bytes, containing %d pages (+ 1 headerpage)\n",hdesc->size,hdesc->size, hdesc->pages);3155printf("Used for data: %d/%d blocks/bytes, unused: %d/%d blocks/bytes.\n\n",3156hdesc->useblk,hdesc->usetot,hdesc->unuseblk,hdesc->unusetot);315731583159/* So, let's guess what kind of hive this is, based on keys in its root */31603161hdesc->type = HTYPE_UNKNOWN;3162if (trav_path(hdesc, 0, "\\SAM", 0)) hdesc->type = HTYPE_SAM;3163else if (trav_path(hdesc, 0, "\\ControlSet", 0)) hdesc->type = HTYPE_SYSTEM;3164else if (trav_path(hdesc, 0, "\\Policy", 0)) hdesc->type = HTYPE_SECURITY;3165else if (trav_path(hdesc, 0, "\\Microsoft", 0)) hdesc->type = HTYPE_SOFTWARE;3166if (verbose) printf("Type of hive guessed to be: %d\n",hdesc->type);31673168return(hdesc);31693170}3171317231733174