Changeset 102
- Timestamp:
- 04/02/08 22:30:26 (17 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/regfi.h
r101 r102 86 86 #define REGFI_NK_MIN_LENGTH 0x4C 87 87 #define REGFI_VK_MIN_LENGTH 0x14 88 #define REGFI_SK_MIN_LENGTH 0x14 88 89 89 90 /* Flags for the vk records */ … … 188 189 uint32 hbin_off; /* offset from beginning of this hbin block */ 189 190 uint32 cell_size; /* ((start_offset - end_offset) & 0xfffffff8) */ 191 uint32 offset; /* Real file offset of this record */ 190 192 191 193 uint32 sk_off; /* offset parsed from NK record used as a key … … 196 198 uint32 next_sk_off; 197 199 uint32 ref_count; 198 uint32 size; 199 uint8 header[REC_HDR_SIZE]; 200 uint32 desc_size; /* size of security descriptor */ 201 uint16 unknown_tag; 202 uint8 magic[REC_HDR_SIZE]; 200 203 } REGF_SK_REC; 201 204 -
trunk/lib/regfi.c
r101 r102 426 426 427 427 /******************************************************************* 428 Input a rando noffset and receive the correpsonding HBIN428 Input a random offset and receive the correpsonding HBIN 429 429 block for it 430 430 *******************************************************************/ … … 548 548 549 549 550 550 551 /******************************************************************* 551 552 *******************************************************************/ 552 static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk ) 553 { 554 prs_struct *ps = &hbin->ps; 555 uint16 tag = 0xFFFF; 556 uint32 data_size, start_off, end_off; 557 558 559 depth++; 560 561 if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_MAGIC_SIZE - hbin->first_hbin_off ) ) 562 return false; 563 564 /* backup and get the data_size */ 565 566 if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) ) 567 return false; 568 start_off = hbin->ps.data_offset; 569 if ( !prs_uint32( "cell_size", &hbin->ps, depth, &sk->cell_size )) 570 return false; 571 572 if (!prs_uint8s("header", ps, depth, sk->header, sizeof(sk->header))) 573 return false; 574 if ( !prs_uint16( "tag", ps, depth, &tag)) 575 return false; 576 577 if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off)) 578 return false; 579 if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off)) 580 return false; 581 if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count)) 582 return false; 583 if ( !prs_uint32( "size", ps, depth, &sk->size)) 584 return false; 585 586 if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 587 return false; 588 589 end_off = hbin->ps.data_offset; 590 591 /* data_size must be divisible by 8 and large enough to hold the original record */ 592 593 data_size = ((start_off - end_off) & 0xfffffff8 ); 594 /* if ( data_size > sk->cell_size )*/ 595 /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->cell_size));*/ 596 597 return true; 553 REGF_SK_REC* regfi_parse_sk(REGF_FILE* file, uint32 offset, uint32 max_size, bool strict) 554 { 555 REGF_SK_REC* ret_val; 556 uint32 cell_length, length; 557 prs_struct ps; 558 uint8 sk_header[REGFI_SK_MIN_LENGTH]; 559 bool unalloc = false; 560 561 562 if(!regfi_parse_cell(file->fd, offset, sk_header, REGFI_SK_MIN_LENGTH, 563 &cell_length, &unalloc)) 564 return NULL; 565 566 if(sk_header[0] != 's' || sk_header[1] != 'k') 567 return NULL; 568 569 ret_val = (REGF_SK_REC*)zalloc(sizeof(REGF_SK_REC)); 570 if(ret_val == NULL) 571 return NULL; 572 573 ret_val->offset = offset; 574 ret_val->cell_size = cell_length; 575 576 if(ret_val->cell_size > max_size) 577 ret_val->cell_size = max_size & 0xFFFFFFF8; 578 if((ret_val->cell_size < REGFI_SK_MIN_LENGTH) 579 || (strict && ret_val->cell_size != (ret_val->cell_size & 0xFFFFFFF8))) 580 { 581 free(ret_val); 582 return NULL; 583 } 584 585 586 ret_val->magic[0] = sk_header[0]; 587 ret_val->magic[1] = sk_header[1]; 588 589 ret_val->unknown_tag = SVAL(sk_header, 0x2); 590 ret_val->prev_sk_off = IVAL(sk_header, 0x4); 591 ret_val->next_sk_off = IVAL(sk_header, 0x8); 592 ret_val->ref_count = IVAL(sk_header, 0xC); 593 ret_val->desc_size = IVAL(sk_header, 0x10); 594 595 if(ret_val->desc_size + REGFI_SK_MIN_LENGTH > ret_val->cell_size) 596 { 597 free(ret_val); 598 return NULL; 599 } 600 601 /* TODO: need to get rid of this, but currently the security descriptor 602 * code depends on the ps structure. 603 */ 604 if(!prs_init(&ps, ret_val->desc_size, NULL, UNMARSHALL)) 605 { 606 free(ret_val); 607 return NULL; 608 } 609 610 length = ret_val->desc_size; 611 if(regfi_read(file->fd, (uint8*)ps.data_p, &length) != 0 612 || length != ret_val->desc_size) 613 { 614 free(ret_val); 615 return NULL; 616 } 617 618 if (!sec_io_desc("sec_desc", &ret_val->sec_desc, &ps, 0)) 619 { 620 free(ret_val); 621 return NULL; 622 } 623 624 free(ps.data_p); 625 626 return ret_val; 598 627 } 599 628 … … 706 735 uint32 nk_cell_offset; 707 736 uint32 nk_max_length; 737 uint32 sk_max_length; 708 738 int depth = 0; 709 739 … … 757 787 } 758 788 759 /* get the to the security descriptor. First look if we have already parsed it */ 760 789 /* get the security descriptor. First look if we have already parsed it */ 761 790 if ((nk->sk_off!=REGF_OFFSET_NONE) 762 791 && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off ))) … … 775 804 } 776 805 777 if ( !(nk->sec_desc = (REGF_SK_REC*)zalloc(sizeof(REGF_SK_REC) )) ) 806 sk_max_length = sub_hbin->block_size - (nk->sk_off - sub_hbin->first_hbin_off); 807 nk->sec_desc = regfi_parse_sk(file, nk->sk_off + REGF_BLOCKSIZE, 808 sk_max_length, true); 809 if(nk->sec_desc == NULL) 778 810 return NULL; 779 811 nk->sec_desc->sk_off = nk->sk_off; 780 if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc ))781 return NULL;782 812 783 813 /* add to the list of security descriptors (ref_count has been read from the files) */ 784 785 nk->sec_desc->sk_off = nk->sk_off;786 814 /* XXX: this kind of caching needs to be re-evaluated */ 787 815 DLIST_ADD( file->sec_desc_list, nk->sec_desc ); … … 792 820 793 821 794 /******************************************************************* 795 *******************************************************************/ 796 static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob ) 797 { 798 uint8 header[REC_HDR_SIZE] = ""; 799 uint32 record_size; 800 uint32 curr_off, block_size; 822 /****************************************************************************** 823 824 ******************************************************************************/ 825 static bool regfi_find_root_nk(REGF_FILE* file, uint32 offset, uint32 hbin_size, 826 uint32* root_offset) 827 { 828 uint8 tmp[4]; 829 int32 record_size; 830 uint32 length, hbin_offset = 0; 831 REGF_NK_REC* nk = NULL; 801 832 bool found = false; 802 prs_struct *ps = &hbin->ps; 803 804 curr_off = ps->data_offset; 805 if ( curr_off == 0 ) 806 prs_set_offset( ps, HBIN_HEADER_REC_SIZE+4 ); 807 808 /* assume that the current offset is at the reacord header 809 and we need to backup to read the record size */ 810 curr_off -= sizeof(uint32); 811 812 block_size = ps->buffer_size; 813 record_size = 0; 814 while ( !found ) 815 { 816 curr_off = curr_off+record_size; 817 if ( curr_off >= block_size ) 818 break; 819 820 if ( !prs_set_offset( &hbin->ps, curr_off) ) 833 834 for(record_size=0; !found && (hbin_offset < hbin_size); ) 835 { 836 if(lseek(file->fd, offset+hbin_offset, SEEK_SET) == -1) 821 837 return false; 822 823 if ( !prs_uint32( "record_size", ps, 0, &record_size ) ) 838 839 length = 4; 840 if((regfi_read(file->fd, tmp, &length) != 0) || length != 4) 824 841 return false; 825 if ( !prs_uint8s("header", ps, 0, header, REC_HDR_SIZE ) ) 826 return false; 827 828 if ( record_size & 0x80000000 ) { 829 /* absolute_value(record_size) */ 830 record_size = (record_size ^ 0xffffffff) + 1; 842 record_size = IVALS(tmp, 0); 843 844 if(record_size < 0) 845 { 846 record_size = record_size*(-1); 847 nk = regfi_parse_nk(file, offset+hbin_offset, hbin_size-hbin_offset, true); 848 if(nk != NULL) 849 { 850 if(nk->key_type == NK_TYPE_ROOTKEY) 851 { 852 found = true; 853 *root_offset = nk->offset; 854 } 855 free(nk); 856 } 831 857 } 832 858 833 if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) { 834 found = true; 835 curr_off += sizeof(uint32); 836 } 837 } 838 839 /* mark prs_struct as done ( at end ) if no more SK records */ 840 /* mark end-of-block as true */ 841 if ( !found ) 842 { 843 prs_set_offset( &hbin->ps, hbin->ps.buffer_size ); 844 *eob = true; 845 return false; 846 } 847 848 if (!prs_set_offset(ps, curr_off)) 849 return false; 850 851 return true; 852 } 853 854 855 /******************************************************************* 856 *******************************************************************/ 857 static REGF_NK_REC* next_nk_record(REGF_FILE *file, REGF_HBIN *hbin, bool *eob) 858 { 859 REGF_NK_REC* ret_val; 860 if(next_record(hbin, "nk", eob) 861 && (ret_val = hbin_prs_key(file, hbin)) != NULL) 862 return ret_val; 863 864 fprintf(stderr, "ACK!"); 865 return NULL; 859 hbin_offset += record_size; 860 } 861 862 return found; 866 863 } 867 864 … … 930 927 * on my experience. --jerry 931 928 *****************************************************************************/ 932 REGF_NK_REC* regfi_rootkey( REGF_FILE *file ) 933 { 934 REGF_NK_REC *nk; 935 REGF_HBIN *hbin; 936 uint32 offset = REGF_BLOCKSIZE; 937 bool found = false; 938 bool eob; 929 REGF_NK_REC* regfi_rootkey(REGF_FILE *file) 930 { 931 REGF_NK_REC* nk = NULL; 932 REGF_HBIN* hbin; 933 uint32 offset = REGF_BLOCKSIZE; 934 uint32 root_offset; 939 935 940 936 if(!file) 941 937 return NULL; 942 938 943 /* scan through the file onHBIN block at a time looking939 /* Scan through the file one HBIN block at a time looking 944 940 for an NK record with a type == 0x002c. 945 941 Normally this is the first nk record in the first hbin 946 942 block (but I'm not assuming that for now) */ 947 943 948 944 while((hbin = regfi_parse_hbin(file, offset, true, false))) 949 945 { 950 eob = false; 951 952 while(!eob) 946 if(regfi_find_root_nk(file, hbin->file_off+HBIN_HEADER_REC_SIZE, 947 hbin->block_size-HBIN_HEADER_REC_SIZE, &root_offset)) 953 948 { 954 if((nk = next_nk_record(file, hbin, &eob)) != NULL) 955 { 956 if ( nk->key_type == NK_TYPE_ROOTKEY ) 957 { 958 found = true; 959 break; 960 } 961 } 962 if(hbin->ps.is_dynamic) 963 SAFE_FREE(hbin->ps.data_p); 964 hbin->ps.is_dynamic = false; 965 hbin->ps.buffer_size = 0; 966 hbin->ps.data_offset = 0; 949 if(!prs_set_offset(&hbin->ps, root_offset + 4 950 - hbin->first_hbin_off - REGF_BLOCKSIZE)) 951 return NULL; 952 953 nk = hbin_prs_key(file, hbin); 954 break; 967 955 } 968 969 if(found)970 break;971 956 972 957 offset += hbin->block_size; 973 958 } 974 975 if (!found) {976 /*DEBUG(0,("regfi_rootkey: corrupt registry file ? No root key record located\n"));*/977 return NULL;978 }979 980 /* XXX: this kind of caching needs to be re-evaluated */981 DLIST_ADD( file->block_list, hbin );982 959 983 960 return nk; … … 1374 1351 { 1375 1352 uint8 file_header[REGF_BLOCKSIZE]; 1376 uint32 ret,length;1353 uint32 length; 1377 1354 uint32 file_length; 1378 1355 struct stat sbuf; … … 1396 1373 1397 1374 length = REGF_BLOCKSIZE; 1398 if((re t = regfi_read(fd, file_header, &length)) != 01375 if((regfi_read(fd, file_header, &length)) != 0 1399 1376 || length != REGF_BLOCKSIZE) 1400 1377 { … … 1792 1769 uint8* ret_val; 1793 1770 uint32 read_length, cell_length; 1771 uint8 i; 1794 1772 bool unalloc; 1795 1773 1796 1774 /* The data is stored in the offset if the size <= 4 */ 1797 if (length & VK_DATA_IN_OFFSET) 1775 if (length & VK_DATA_IN_OFFSET) 1798 1776 { 1799 1777 length = length & ~VK_DATA_IN_OFFSET; … … 1803 1781 if((ret_val = (uint8*)zalloc(sizeof(uint8)*length)) == NULL) 1804 1782 return NULL; 1805 memcpy(ret_val, &offset, length); 1783 1784 offset = offset - REGF_BLOCKSIZE; 1785 for(i = 0; i < length; i++) 1786 ret_val[i] = (uint8)((offset >> i*8) & 0xFF); 1806 1787 } 1807 1788 else -
trunk/src/reglookup.c
r97 r102 248 248 249 249 snprintf(ascii, ascii_max, "0x%.2X%.2X%.2X%.2X", 250 datap[ 0], datap[1], datap[2], datap[3]);250 datap[3], datap[2], datap[1], datap[0]); 251 251 return ascii; 252 252 break; … … 259 259 260 260 snprintf(ascii, ascii_max, "0x%.2X%.2X%.2X%.2X", 261 datap[ 3], datap[2], datap[1], datap[0]);261 datap[0], datap[1], datap[2], datap[3]); 262 262 return ascii; 263 263 break; … … 277 277 278 278 /* XXX: this MULTI_SZ parser is pretty inefficient. Should be 279 * redone with fewer malloc calls and better string concatenation. 279 * redone with fewer malloc calls and better string concatenation. 280 * Also, gives lame output when "\0\0" is the string. 280 281 */ 281 282 case REG_MULTI_SZ: … … 532 533 const char* str_type = NULL; 533 534 uint32 size; 534 uint8 tmp_buf[4]; 535 536 /* Thanks Microsoft for making this process so straight-forward!!! */ 537 /* XXX: this logic should be abstracted and pushed into the regfi 538 * interface. This includes the size limits. 535 536 /* Microsoft's documentation indicates that "available memory" is 537 * the limit on value sizes. Annoying. We limit it to 1M which 538 * should rarely be exceeded, unless the file is corrupt or 539 * malicious. For more info, see: 540 * http://msdn2.microsoft.com/en-us/library/ms724872.aspx 539 541 */ 540 size = (vk->data_size & ~VK_DATA_IN_OFFSET); 541 if(vk->data_size & VK_DATA_IN_OFFSET) 542 { 543 tmp_buf[0] = (uint8)((vk->data_off >> 3) & 0xFF); 544 tmp_buf[1] = (uint8)((vk->data_off >> 2) & 0xFF); 545 tmp_buf[2] = (uint8)((vk->data_off >> 1) & 0xFF); 546 tmp_buf[3] = (uint8)(vk->data_off & 0xFF); 547 if(size > 4) 548 { 549 fprintf(stderr, "WARNING: value stored in offset larger than 4. " 550 "Truncating...\n"); 551 size = 4; 552 } 553 quoted_value = data_to_ascii(tmp_buf, 4, vk->type, &conv_error); 554 } 555 else 556 { 557 /* Microsoft's documentation indicates that "available memory" is 558 * the limit on value sizes. Annoying. We limit it to 1M which 559 * should rarely be exceeded, unless the file is corrupt or 560 * malicious. For more info, see: 561 * http://msdn2.microsoft.com/en-us/library/ms724872.aspx 562 */ 563 if(size > VK_MAX_DATA_LENGTH) 564 { 565 fprintf(stderr, "WARNING: value data size %d larger than " 566 "%d, truncating...\n", size, VK_MAX_DATA_LENGTH); 567 size = VK_MAX_DATA_LENGTH; 568 } 569 570 quoted_value = data_to_ascii(vk->data, vk->data_size, 571 vk->type, &conv_error); 572 } 542 if(size > VK_MAX_DATA_LENGTH) 543 { 544 fprintf(stderr, "WARNING: value data size %d larger than " 545 "%d, truncating...\n", size, VK_MAX_DATA_LENGTH); 546 size = VK_MAX_DATA_LENGTH; 547 } 548 549 quoted_value = data_to_ascii(vk->data, vk->data_size, 550 vk->type, &conv_error); 551 573 552 574 553 /* XXX: Sometimes value names can be NULL in registry. Need to
Note: See TracChangeset
for help on using the changeset viewer.