📄 regfio.c
字号:
/* * Unix SMB/CIFS implementation. * Windows NT registry I/O library * Copyright (c) Gerald (Jerry) Carter 2005 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "includes.h"#include "regfio.h"/******************************************************************* * * TODO : Right now this code basically ignores classnames. * ******************************************************************//**************************************************************************************************************************************/static int write_block( REGF_FILE *file, prs_struct *ps, uint32 offset ){ int bytes_written, returned; char *buffer = prs_data_p( ps ); uint32 buffer_size = prs_data_size( ps ); SMB_STRUCT_STAT sbuf; if ( file->fd == -1 ) return -1; /* check for end of file */ if ( sys_fstat( file->fd, &sbuf ) ) { DEBUG(0,("write_block: stat() failed! (%s)\n", strerror(errno))); return -1; } if ( lseek( file->fd, offset, SEEK_SET ) == -1 ) { DEBUG(0,("write_block: lseek() failed! (%s)\n", strerror(errno) )); return -1; } bytes_written = returned = 0; while ( bytes_written < buffer_size ) { if ( (returned = write( file->fd, buffer+bytes_written, buffer_size-bytes_written )) == -1 ) { DEBUG(0,("write_block: write() failed! (%s)\n", strerror(errno) )); return False; } bytes_written += returned; } return bytes_written;}/**************************************************************************************************************************************/static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, uint32 block_size ){ int bytes_read, returned; char *buffer; SMB_STRUCT_STAT sbuf; /* check for end of file */ if ( sys_fstat( file->fd, &sbuf ) ) { DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno))); return -1; } if ( (size_t)file_offset >= sbuf.st_size ) return -1; /* if block_size == 0, we are parsing HBIN records and need to read some of the header to get the block_size from there */ if ( block_size == 0 ) { char hdr[0x20]; if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) { DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) )); return -1; } returned = read( file->fd, hdr, 0x20 ); if ( (returned == -1) || (returned < 0x20) ) { DEBUG(0,("read_block: failed to read in HBIN header. Is the file corrupt?\n")); return -1; } /* make sure this is an hbin header */ if ( strncmp( hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) { DEBUG(0,("read_block: invalid block header!\n")); return -1; } block_size = IVAL( hdr, 0x08 ); } DEBUG(10,("read_block: block_size == 0x%x\n", block_size )); /* set the offset, initialize the buffer, and read the block from disk */ if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) { DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) )); return -1; } prs_init( ps, block_size, file->mem_ctx, UNMARSHALL ); buffer = prs_data_p( ps ); bytes_read = returned = 0; while ( bytes_read < block_size ) { if ( (returned = read( file->fd, buffer+bytes_read, block_size-bytes_read )) == -1 ) { DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) )); return False; } if ( (returned == 0) && (bytes_read < block_size) ) { DEBUG(0,("read_block: not a vald registry file ?\n" )); return False; } bytes_read += returned; } return bytes_read;}/**************************************************************************************************************************************/static BOOL write_hbin_block( REGF_FILE *file, REGF_HBIN *hbin ){ if ( !hbin->dirty ) return True; /* write free space record if any is available */ if ( hbin->free_off != REGF_OFFSET_NONE ) { uint32 header = 0xffffffff; if ( !prs_set_offset( &hbin->ps, hbin->free_off-sizeof(uint32) ) ) return False; if ( !prs_uint32( "free_size", &hbin->ps, 0, &hbin->free_size ) ) return False; if ( !prs_uint32( "free_header", &hbin->ps, 0, &header ) ) return False; } hbin->dirty = (write_block( file, &hbin->ps, hbin->file_off ) != -1); return hbin->dirty;}/**************************************************************************************************************************************/static BOOL hbin_block_close( REGF_FILE *file, REGF_HBIN *hbin ){ REGF_HBIN *p; /* remove the block from the open list and flush it to disk */ for ( p=file->block_list; p && p!=hbin; p=p->next ) ;; if ( p == hbin ) { DLIST_REMOVE( file->block_list, hbin ); } else DEBUG(0,("hbin_block_close: block not in open list!\n")); if ( !write_hbin_block( file, hbin ) ) return False; return True;}/**************************************************************************************************************************************/static BOOL prs_regf_block( const char *desc, prs_struct *ps, int depth, REGF_FILE *file ){ prs_debug(ps, depth, desc, "prs_regf_block"); depth++; if ( !prs_uint8s( True, "header", ps, depth, (uint8*)file->header, sizeof( file->header )) ) return False; /* yes, these values are always identical so store them only once */ if ( !prs_uint32( "unknown1", ps, depth, &file->unknown1 )) return False; if ( !prs_uint32( "unknown1 (again)", ps, depth, &file->unknown1 )) return False; /* get the modtime */ if ( !prs_set_offset( ps, 0x0c ) ) return False; if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) ) return False; /* constants */ if ( !prs_uint32( "unknown2", ps, depth, &file->unknown2 )) return False; if ( !prs_uint32( "unknown3", ps, depth, &file->unknown3 )) return False; if ( !prs_uint32( "unknown4", ps, depth, &file->unknown4 )) return False; if ( !prs_uint32( "unknown5", ps, depth, &file->unknown5 )) return False; /* get file offsets */ if ( !prs_set_offset( ps, 0x24 ) ) return False; if ( !prs_uint32( "data_offset", ps, depth, &file->data_offset )) return False; if ( !prs_uint32( "last_block", ps, depth, &file->last_block )) return False; /* one more constant */ if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 )) return False; /* get the checksum */ if ( !prs_set_offset( ps, 0x01fc ) ) return False; if ( !prs_uint32( "checksum", ps, depth, &file->checksum )) return False; return True;}/**************************************************************************************************************************************/static BOOL prs_hbin_block( const char *desc, prs_struct *ps, int depth, REGF_HBIN *hbin ){ uint32 block_size2; prs_debug(ps, depth, desc, "prs_regf_block"); depth++; if ( !prs_uint8s( True, "header", ps, depth, (uint8*)hbin->header, sizeof( hbin->header )) ) return False; if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off )) return False; /* The dosreg.cpp comments say that the block size is at 0x1c. According to a WINXP NTUSER.dat file, this is wrong. The block_size is at 0x08 */ if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size )) return False; block_size2 = hbin->block_size; prs_set_offset( ps, 0x1c ); if ( !prs_uint32( "block_size2", ps, depth, &block_size2 )) return False; if ( MARSHALLING(ps) ) hbin->dirty = True; return True;}/**************************************************************************************************************************************/static BOOL prs_nk_rec( const char *desc, prs_struct *ps, int depth, REGF_NK_REC *nk ){ uint16 class_length, name_length; uint32 start; uint32 data_size, start_off, end_off; uint32 unknown_off = REGF_OFFSET_NONE; nk->hbin_off = prs_offset( ps ); start = nk->hbin_off; prs_debug(ps, depth, desc, "prs_nk_rec"); depth++; /* back up and get the data_size */ if ( !prs_set_offset( ps, prs_offset(ps)-sizeof(uint32)) ) return False; start_off = prs_offset( ps ); if ( !prs_uint32( "rec_size", ps, depth, &nk->rec_size )) return False; if ( !prs_uint8s( True, "header", ps, depth, (uint8*)nk->header, sizeof( nk->header )) ) return False; if ( !prs_uint16( "key_type", ps, depth, &nk->key_type )) return False; if ( !smb_io_time( "mtime", &nk->mtime, ps, depth )) return False; if ( !prs_set_offset( ps, start+0x0010 ) ) return False; if ( !prs_uint32( "parent_off", ps, depth, &nk->parent_off )) return False; if ( !prs_uint32( "num_subkeys", ps, depth, &nk->num_subkeys )) return False; if ( !prs_set_offset( ps, start+0x001c ) ) return False; if ( !prs_uint32( "subkeys_off", ps, depth, &nk->subkeys_off )) return False; if ( !prs_uint32( "unknown_off", ps, depth, &unknown_off) ) return False; if ( !prs_set_offset( ps, start+0x0024 ) ) return False; if ( !prs_uint32( "num_values", ps, depth, &nk->num_values )) return False; if ( !prs_uint32( "values_off", ps, depth, &nk->values_off )) return False; if ( !prs_uint32( "sk_off", ps, depth, &nk->sk_off )) return False; if ( !prs_uint32( "classname_off", ps, depth, &nk->classname_off )) return False; if ( !prs_uint32( "max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname)) return False; if ( !prs_uint32( "max_bytes_subkeyclassname", ps, depth, &nk->max_bytes_subkeyclassname)) return False; if ( !prs_uint32( "max_bytes_valuename", ps, depth, &nk->max_bytes_valuename)) return False; if ( !prs_uint32( "max_bytes_value", ps, depth, &nk->max_bytes_value)) return False; if ( !prs_uint32( "unknown index", ps, depth, &nk->unk_index)) return False; name_length = nk->keyname ? strlen(nk->keyname) : 0 ; class_length = nk->classname ? strlen(nk->classname) : 0 ; if ( !prs_uint16( "name_length", ps, depth, &name_length )) return False; if ( !prs_uint16( "class_length", ps, depth, &class_length )) return False; if ( class_length ) { ;; } if ( name_length ) { if ( UNMARSHALLING(ps) ) { if ( !(nk->keyname = PRS_ALLOC_MEM( ps, char, name_length+1 )) ) return False; } if ( !prs_uint8s( True, "name", ps, depth, (uint8*)nk->keyname, name_length) ) return False; if ( UNMARSHALLING(ps) ) nk->keyname[name_length] = '\0'; } end_off = prs_offset( ps ); /* data_size must be divisible by 8 and large enough to hold the original record */ data_size = ((start_off - end_off) & 0xfffffff8 ); if ( data_size > nk->rec_size ) DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size)); if ( MARSHALLING(ps) ) nk->hbin->dirty = True; return True;}/**************************************************************************************************************************************/static uint32 regf_block_checksum( prs_struct *ps ){ char *buffer = prs_data_p( ps ); uint32 checksum, x; int i; /* XOR of all bytes 0x0000 - 0x01FB */ checksum = x = 0; for ( i=0; i<0x01FB; i+=4 ) { x = IVAL(buffer, i ); checksum ^= x; } return checksum;}/**************************************************************************************************************************************/static BOOL read_regf_block( REGF_FILE *file ){ prs_struct ps; uint32 checksum; /* grab the first block from the file */ if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 ) return False; /* parse the block and verify the checksum */ if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) return False; checksum = regf_block_checksum( &ps ); prs_mem_free( &ps ); if ( file->checksum != checksum ) { DEBUG(0,("read_regf_block: invalid checksum\n" )); return False; } return True;}/**************************************************************************************************************************************/static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset ){ REGF_HBIN *hbin; uint32 record_size, curr_off, block_size, header; if ( !(hbin = TALLOC_ZERO_P(file->mem_ctx, REGF_HBIN)) ) return NULL; hbin->file_off = offset; hbin->free_off = -1; if ( read_block( file, &hbin->ps, offset, 0 ) == -1 ) return NULL; if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) ) return NULL; /* this should be the same thing as hbin->block_size but just in case */ block_size = prs_data_size( &hbin->ps ); /* Find the available free space offset. Always at the end, so walk the record list and stop when you get to the end. The end is defined by a record header of 0xffffffff. The
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -