Changeset 116

Show
Ignore:
Timestamp:
12/16/06 22:25:09 (2 years ago)
Author:
kindlund
Message:

Still finishing up registry parser; ran into issues where the registry group blocks were NOT properly alphabetically sorted. As such, I'm having to rely more upon the diff.exe output, in order to determine if each diff block is an add, delete, or change. Updated unit tests across both Registry and Parser modules.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry.pm

    r112 r116  
    538538 
    539539# Helper function, designed to perform a binary diff on two files, 
    540 # providing two arrays of offsets, corresponding to where changes 
    541 # have occurred in either source or target registry hive dumps. 
     540# providing two arrays of line numbers, corresponding to where changes 
     541# have occurred in either source or target registry hive dumps, along 
     542# with an array of corresponding characters ('a', 'c', or 'd'), 
     543# signifying what type of change was made. 
    542544# 
    543545# Inputs: HoneyClient::Agent::Integrity::Registry object,  
    544546#         source parser, target parser 
    545547# 
    546 # Outputs: source offset array ref, target offset array ref 
     548# Outputs: source line number array ref, target line number array ref, 
     549#          diff type char array ref 
    547550sub _diff { 
    548551    # Extract arguments. 
    549552    my ($self, $src_parser, $tgt_parser) = @_; 
    550553 
    551     my $src_offsets = []; 
    552     my $tgt_offsets = []; 
     554    my $src_linenums = []; 
     555    my $tgt_linenums = []; 
     556    my $diff_types = []; 
    553557 
    554558    # Get the corresponding file names. 
     
    580584            $LOG->info("No changes detected in specified data."); 
    581585            _cleanup($fname_tmp); 
    582             return ($src_offsets, $tgt_offsets); 
     586            return ($src_linenums, $tgt_linenums); 
    583587        } 
    584588        if ($_ eq "FAILURE\n") { 
     
    591595 
    592596    do { 
    593         if (/([0-9]+)(?:|,[0-9]+)[a-z]([0-9]+)/) { 
    594             push (@{$src_offsets}, $1); 
    595             push (@{$tgt_offsets}, $2); 
     597        if (/([0-9]+)(?:|,[0-9]+)([a-z])([0-9]+)/) { 
     598            push (@{$src_linenums}, $1); 
     599            push (@{$diff_types}, $2); 
     600            push (@{$tgt_linenums}, $3); 
    596601        } 
    597602    } while (<$fh>); 
    598603 
    599604    _cleanup($fname_tmp); 
    600     return ($src_offsets, $tgt_offsets); 
     605    return ($src_linenums, $tgt_linenums, $diff_types); 
    601606} 
    602607 
     
    623628    my $after_parser  = $args{'after_parser'}; 
    624629 
     630    # A hashtable reference, containing the latest change found. 
     631    my $currentChange = { }; 
     632 
     633    # Indicates if the $currentChange hashtable is not empty. 
     634    my $currentChangeExists = 0; 
     635 
    625636    # Array reference, containing hashtables, where each 
    626637    # hashtable represents a change between the before and 
     
    628639    my $changes = [];  
    629640 
    630     # Array references, reflecting collection of offsets 
     641    # State variable: 
     642    # - Positive value: Keep comparing groups, linearly. 
     643    # - Negative value: Stop comparing groups, seek to next diff. 
     644    # 
     645    # Note: When a comparison is different, then this variable's 
     646    # value remains the same.  When a comparison is the same, then 
     647    # this variable's value is decremented by 1. 
     648    my $changeState = 1; 
     649     
     650    # Array references, reflecting collection of line numbers 
    631651    # found, where differences occur between before and 
    632     # after the specified files. 
    633     my ($before_offsets, $after_offsets) = $self->_diff($before_parser, $after_parser); 
    634  
    635     # Get first offsets. 
    636     my $before_offset = shift(@{$before_offsets}); 
    637     my $after_offset = shift(@{$after_offsets}); 
    638  
    639     # Return early, if no changes were found. 
    640     if (!defined($before_offset) && !defined($after_offset)) { 
    641         return $changes; 
    642     } 
    643  
    644     # Seek to nearest common group. 
    645     $before_parser->seekToNearestGroup(absolute_offset => $before_offset); 
    646 #    $after_parser->seekToNearestGroup(absolute_offset => $after_offset); 
    647  
    648     # Start with the first registry group from both files. 
    649     my $before_group = $self->_nextGroup($before_parser); 
    650     my $after_group  = $self->_nextGroup($after_parser); 
    651  
    652     # A hashtable reference, containing the latest change found. 
    653     my $change = { }; 
    654  
    655     # While we are able to read the next key from either file... 
    656     while (defined($before_group) || defined($after_group)) { 
    657  
    658         # Reset the change hashref. 
    659         $change = { }; 
    660  
    661         # If the next group name extracted from both files is identical...  
    662         if (defined($before_group) && defined($after_group) && 
    663             ($self->_cmpGroup($before_group, $after_group) == 0)) { 
    664  
    665             # Extract the next key/value pair corresponding to this group from 
    666             # both files. 
    667             my ($before_entry_name, $before_entry_value) = $self->_nextVal($before_parser); 
    668             my ($after_entry_name, $after_entry_value)   = $self->_nextVal($after_parser); 
    669  
    670             # While this key name exists in either file... 
    671             while (defined($before_entry_name) || defined($after_entry_name)) { 
    672  
    673                 # If the key name matches in both files... 
    674                 if (defined($before_entry_name) && defined($after_entry_name) && 
    675                     $self->_cmpEntryName($before_entry_name, $after_entry_name) == 0) { 
    676  
    677                     # If the corresponding values in both files are 
    678                     # DIFFERENT... 
    679                     if ($before_entry_value ne $after_entry_value) { 
    680  
    681                         # Scenario: 
    682                         # Same directory name, same entry key name, 
    683                         # but different entry values. 
    684  
    685                         # Save the change. 
    686                         $change->{'key'} = $before_group; 
    687                         $change->{'status'} = "changed"; 
    688                         $change->{'entries'}->{$before_entry_name} = { 
    689                             old_value => $before_entry_value, 
    690                             new_value => $after_entry_value, 
    691                         }; 
    692                     } 
    693  
    694                     # Get the next corresponding key/value pair from this group. 
    695                     ($before_entry_name, $before_entry_value) = $self->_nextVal($before_parser); 
    696                     ($after_entry_name, $after_entry_value)   = $self->_nextVal($after_parser); 
    697  
    698                 # Else, the key names are different in both files... 
     652    # after the specified files, along with an array reference of 
     653    # characters ('a', 'd', or 'c') indicating the type of diffs. 
     654    my ($before_linenums, $after_linenums, $diff_types) = $self->_diff($before_parser, $after_parser); 
     655 
     656    # Helper variables, to extract the latest line number from the diff 
     657    # operation, along with the latest diff type. 
     658    my $before_linenum = undef; 
     659    my $after_linenum = undef; 
     660    my $diff_type = undef; 
     661 
     662    # Helper variables, to contain the latest parsed group. 
     663    my $before_group = undef; 
     664    my $after_group = undef; 
     665 
     666    # Helper variables, to contain the latest parsed key/value pair. 
     667    my ($before_entry_name, $before_entry_value) = (undef, undef); 
     668    my ($after_entry_name, $after_entry_value)   = (undef, undef); 
     669 
     670    # Helper variables, to keep track of how many total lines 
     671    # that the parser has actually parsed. 
     672    my $before_total_linenums = $before_parser->getCurrentLineCount(); 
     673    my $after_total_linenums = $after_parser->getCurrentLineCount(); 
     674 
     675    # Helper variables, to indicate whether the before or after group parser 
     676    # needs to go back more than by more than one group (if the diff type 
     677    # was an addition or deletion). 
     678    my $before_adjust_index = 0; 
     679    my $after_adjust_index = 0; 
     680 
     681    while (1) { 
     682 
     683        if (($changeState <= 0) || 
     684            (!defined($before_group) && !defined($after_group))) { 
     685 
     686            # Get the next set of offsets and type. 
     687            $before_linenum = shift(@{$before_linenums}); 
     688            $after_linenum  = shift(@{$after_linenums}); 
     689            $diff_type      = shift(@{$diff_types}); 
     690 
     691 print("Before: ", Dumper($before_linenum) . "\n"); 
     692 print("After: ", Dumper($after_linenum) . "\n"); 
     693 
     694            # Return early, if no changes were found. 
     695            if (!defined($before_linenum) && !defined($after_linenum)) { 
     696                # TODO: delete this, eventually. 
     697                #$Data::Dumper::Terse = 1; 
     698                #$Data::Dumper::Indent = 1; 
     699                #print "Complete list: " . Dumper($changes) . "\n"; 
     700 
     701                return $changes; 
     702            } 
     703 
     704            # Figure out how many lines we've parsed so far.  
     705            $before_total_linenums += $before_parser->getCurrentLineCount(); 
     706            $after_total_linenums += $after_parser->getCurrentLineCount(); 
     707print("Before Total Linenums: ", Dumper($before_total_linenums) . "\n"); 
     708print("After Total Linenums: ", Dumper($after_total_linenums) . "\n"); 
     709 
     710            # Seek to nearest common group, that we haven't already parsed. 
     711            # TODO: Check to make sure that linking them is okay. 
     712            if (($before_linenum > $before_total_linenums) && 
     713                ($after_linenum > $after_total_linenums)) { 
     714 
     715                $before_adjust_index = 0; 
     716                $after_adjust_index = 0; 
     717                if ($diff_type eq 'a') { 
     718                    $after_adjust_index = -1; 
     719                    # Be sure to perform comparisons before (-1), during (0), and after (-1) the diff block. 
     720                    $changeState = 2; 
     721                } elsif ($diff_type eq 'd') { 
     722                    $before_adjust_index = -1; 
     723                    # Be sure to perform comparisons before (-1), during (0), and after (-1) the diff block. 
     724                    $changeState = 2; 
    699725                } else { 
    700  
    701                     # Scenario: 
    702                     # Same directory name, different entry key names. 
    703  
    704                     # Save the change. 
    705                     $change->{'key'} = $before_group; 
    706                     $change->{'status'} = "changed"; 
    707  
    708                     # If the after key name doesn't exist, or if the before key  
    709                     # name exists and the before name is alphabetically earlier 
    710                     # than the after key name... 
    711                     if (!defined($after_entry_name) || defined($before_entry_name) && 
    712                         $self->_cmpEntryName($before_entry_name, $after_entry_name) < 0) { 
    713  
    714                         # Then we know that the before key name got deleted 
    715                         # in the after file. 
    716                         # Check to see if some of this change data already exists... 
    717                         if (exists($change->{'entries'}->{$before_entry_name})) { 
    718  
    719                             # Sanity check: Looks like an earlier iteration populated 
    720                             # this change entry with a 'new_value'.  Let's make sure 
    721                             # the our 'old_value' and 'new_value' are truly different. 
    722                             if (defined($change->{'entries'}->{$before_entry_name}->{'new_value'}) && 
    723                                 ($change->{'entries'}->{$before_entry_name}->{'new_value'} ne 
    724                                  $before_entry_value)) { 
    725  
    726                                 # Okay, looks like they're different, so only update the old_value. 
    727                                 $change->{'entries'}->{$before_entry_name}->{'old_value'} = $before_entry_value; 
    728                             } else { 
    729                                 # Looks like they're the same value, so delete the entry completely. 
    730                                 delete($change->{'entries'}->{$before_entry_name}); 
    731                             } 
    732                         } else { 
    733                             # If not, then update both old_value and new_value. 
    734                             $change->{'entries'}->{$before_entry_name} = { 
     726                    # Be sure to perform comparisons during (0) and after (-1) the diff block. 
     727                    $changeState = 1; 
     728                } 
     729 
     730                $before_total_linenums = $before_parser->seekToNearestGroup(absolute_linenum => $before_linenum, 
     731                                                                            adjust_index => $before_adjust_index); 
     732                $after_total_linenums = $after_parser->seekToNearestGroup(absolute_linenum => $after_linenum, 
     733                                                                          adjust_index => $after_adjust_index); 
     734            } 
     735 
     736        } 
     737 
     738        # Get the next registry group from both files. 
     739        $before_group = $self->_nextGroup($before_parser); 
     740        $after_group  = $self->_nextGroup($after_parser); 
     741 
     742        # While we are able to read the next key from either file... 
     743        while (($changeState > 0) && (defined($before_group) || defined($after_group))) { 
     744 
     745            # Update the total line count. 
     746            $before_total_linenums += $before_parser->getCurrentLineCount(); 
     747            $after_total_linenums += $after_parser->getCurrentLineCount(); 
     748 
     749print("Before Current Linenums: ", Dumper($before_total_linenums) . "\n"); 
     750print("After Current Linenums: ", Dumper($after_total_linenums) . "\n"); 
     751 
     752print "Before Group: " . Dumper($before_group) . "\n"; 
     753print "After Group: " . Dumper($after_group) . "\n"; 
     754 
     755            # Reset the current change hashref. 
     756            $currentChange = { }; 
     757 
     758            # If the next group name extracted from both files is identical...  
     759            if (defined($before_group) && defined($after_group) && 
     760                ($self->_cmpGroup($before_group, $after_group) == 0)) { 
     761 
     762                # Extract the next key/value pair corresponding to this group from 
     763                # both files. 
     764                ($before_entry_name, $before_entry_value) = $self->_nextVal($before_parser); 
     765                ($after_entry_name, $after_entry_value)   = $self->_nextVal($after_parser); 
     766 
     767                # While this key name exists in either file... 
     768                while (defined($before_entry_name) || defined($after_entry_name)) { 
     769 
     770                    # If the key name matches in both files... 
     771                    if (defined($before_entry_name) && defined($after_entry_name) && 
     772                        $self->_cmpEntryName($before_entry_name, $after_entry_name) == 0) { 
     773 
     774                        # If the corresponding values in both files are 
     775                        # DIFFERENT... 
     776                        if ($before_entry_value ne $after_entry_value) { 
     777 
     778                            # Scenario: 
     779                            # Same directory name, same entry key name, 
     780                            # but different entry values. 
     781 
     782                            # Save the change. 
     783                            $currentChange->{'key'} = $before_group; 
     784                            $currentChange->{'status'} = "changed"; 
     785                            $currentChange->{'entries'}->{$before_entry_name} = { 
    735786                                old_value => $before_entry_value, 
    736                                 new_value => undef, 
    737                             }; 
    738                         } 
    739  
    740                         # And get the next corresponding key/value pair from the before group. 
    741                         ($before_entry_name, $before_entry_value) = $self->_nextVal($before_parser); 
    742  
    743                     # Else, the after key name exists but the corresponding before key name  
    744                     # did not exist -- which means that this is a new key/value pair. 
    745                     } else { 
    746  
    747                         # Check to see if some of this change data already exists... 
    748                         if (exists($change->{'entries'}->{$after_entry_name})) { 
    749                             # Sanity check: Looks like an earlier iteration populated 
    750                             # this change entry with an 'old_value'.  Let's make sure 
    751                             # the our 'old_value' and 'new_value' are truly different. 
    752                             if (defined($change->{'entries'}->{$after_entry_name}->{'old_value'}) && 
    753                                 ($change->{'entries'}->{$after_entry_name}->{'old_value'} ne 
    754                                  $after_entry_value)) { 
    755  
    756                                 # Okay, looks like they're different, so only update the new_value. 
    757                                 $change->{'entries'}->{$after_entry_name}->{'new_value'} = $after_entry_value; 
    758                             } else { 
    759                                 # Looks like they're the same value, so delete the entry completely. 
    760                                 delete($change->{'entries'}->{$after_entry_name}); 
    761                             } 
    762                         } else { 
    763                             # If not, then update both old_value and new_value. 
    764                             $change->{'entries'}->{$after_entry_name} = { 
    765                                 old_value => undef, 
    766787                                new_value => $after_entry_value, 
    767788                            }; 
    768789                        } 
    769790 
    770                         # And get the next corresponding key/value pair from the after group. 
    771                         ($after_entry_name, $after_entry_value) = $self->_nextVal($after_parser); 
     791                        # Get the next corresponding key/value pair from this group. 
     792                        ($before_entry_name, $before_entry_value) = $self->_nextVal($before_parser); 
     793                        ($after_entry_name, $after_entry_value)   = $self->_nextVal($after_parser); 
     794 
     795                        # Else, the key names are different in both files... 
     796                    } else { 
     797 
     798                        # Scenario: 
     799                        # Same directory name, different entry key names. 
     800 
     801                        # Save the change. 
     802                        $currentChange->{'key'} = $before_group; 
     803                        $currentChange->{'status'} = "changed"; 
     804 
     805                        # If the after key name doesn't exist, or if the before key  
     806                        # name exists and the before name is alphabetically earlier 
     807                        # than the after key name... 
     808                        if (!defined($after_entry_name) || defined($before_entry_name) && 
     809                            $self->_cmpEntryName($before_entry_name, $after_entry_name) < 0) { 
     810 
     811                            # Then we know that the before key name got deleted 
     812                            # in the after file. 
     813                            # Check to see if some of this change data already exists... 
     814                            if (exists($currentChange->{'entries'}->{$before_entry_name})) { 
     815 
     816                                # Sanity check: Looks like an earlier iteration populated 
     817                                # this change entry with a 'new_value'.  Let's make sure 
     818                                # the our 'old_value' and 'new_value' are truly different. 
     819                                if (defined($currentChange->{'entries'}->{$before_entry_name}->{'new_value'}) && 
     820                                    ($currentChange->{'entries'}->{$before_entry_name}->{'new_value'} ne 
     821                                        $before_entry_value)) { 
     822 
     823                                    # Okay, looks like they're different, so only update the old_value. 
     824                                    $currentChange->{'entries'}->{$before_entry_name}->{'old_value'} = $before_entry_value; 
     825                                } else { 
     826                                    # Looks like they're the same value, so delete the entry completely. 
     827                                    delete($currentChange->{'entries'}->{$before_entry_name}); 
     828                                } 
     829                            } else { 
     830                                # If not, then update both old_value and new_value. 
     831                                $currentChange->{'entries'}->{$before_entry_name} = { 
     832                                    old_value => $before_entry_value, 
     833                                    new_value => undef, 
     834                                }; 
     835                            } 
     836 
     837                            # And get the next corresponding key/value pair from the before group. 
     838                            ($before_entry_name, $before_entry_value) = $self->_nextVal($before_parser); 
     839 
     840                            # Else, the after key name exists but the corresponding before key name  
     841                            # did not exist -- which means that this is a new key/value pair. 
     842                        } else { 
     843 
     844                            # Check to see if some of this change data already exists... 
     845                            if (exists($currentChange->{'entries'}->{$after_entry_name})) { 
     846                                # Sanity check: Looks like an earlier iteration populated 
     847                                # this change entry with an 'old_value'.  Let's make sure 
     848                                # the our 'old_value' and 'new_value' are truly different. 
     849                                if (defined($currentChange->{'entries'}->{$after_entry_name}->{'old_value'}) && 
     850                                    ($currentChange->{'entries'}->{$after_entry_name}->{'old_value'} ne 
     851                                        $after_entry_value)) { 
     852 
     853                                    # Okay, looks like they're different, so only update the new_value. 
     854                                    $currentChange->{'entries'}->{$after_entry_name}->{'new_value'} = $after_entry_value; 
     855                                } else { 
     856                                    # Looks like they're the same value, so delete the entry completely. 
     857                                    delete($currentChange->{'entries'}->{$after_entry_name}); 
     858                                } 
     859                            } else { 
     860                                # If not, then update both old_value and new_value. 
     861                                $currentChange->{'entries'}->{$after_entry_name} = { 
     862                                    old_value => undef, 
     863                                    new_value => $after_entry_value, 
     864                                }; 
     865                            } 
     866 
     867                            # And get the next corresponding key/value pair from the after group. 
     868                            ($after_entry_name, $after_entry_value) = $self->_nextVal($after_parser); 
     869                        } 
    772870                    } 
    773871                } 
     872 
     873                # Once we're out of the previous loop, then we are finished enumerating 
     874                # all key/value pairs corresponding to the identical group in either files. 
     875 
     876                # And get the next group to compare from both files. 
     877                $before_group = $self->_nextGroup($before_parser); 
     878                $after_group  = $self->_nextGroup($after_parser); 
     879 
     880                # Else, if the after group doesn't exist, or if the before group exists and the 
     881                # before group name is alphabetically earlier than the after group name... 
     882                # but verify that our $diff_type signifies a deletion (otherwise, the groups 
     883                # may not be sorted alphabetically). 
     884            } elsif (!defined($after_group) || defined($before_group) && 
     885                     (($diff_type eq 'd') && 
     886                      ($self->_cmpGroup($before_group, $after_group) < 0))) { 
     887 
     888                # Scenario: 
     889                # Directory was deleted. 
     890 
     891                # Save the change. 
     892                $currentChange->{'key'} = $before_group; 
     893                $currentChange->{'status'} = "deleted"; 
     894                $currentChange->{'entries'} = { }; 
     895 
     896                # Get the first key/value pair from this before group. 
     897                ($before_entry_name, $before_entry_value) = $self->_nextVal($before_parser); 
     898 
     899                # While there are key/values within this before group. 
     900                while (defined($before_entry_name)) { 
     901                    $currentChange->{'entries'}->{$before_entry_name} = { 
     902                        old_value => $before_entry_value, 
     903                        new_value => undef, 
     904                    }; 
     905 
     906                    # And get the next corresponding key/value pair from the before group. 
     907                    ($before_entry_name, $before_entry_value) = $self->_nextVal($before_parser); 
     908                } 
     909 
     910                # Get the next group from the before file. 
     911                $before_group = $self->_nextGroup($before_parser); 
     912 
     913                # Else, the after group exists but the corresponding before group 
     914                # did not exist -- which means that this is a new group. 
     915            } else { 
     916                # Scenario: 
     917                # Directory was added. 
     918 
     919                # Save the change. 
     920                $currentChange->{'key'} = $after_group; 
     921                $currentChange->{'status'} = "added"; 
     922                $currentChange->{'entries'} = { }; 
     923 
     924                # Get the first key/value pair from this after group. 
     925                ($after_entry_name, $after_entry_value) = $self->_nextVal($after_parser); 
     926 
     927                # While there are key/values within this after group. 
     928                while (defined($after_entry_name)) { 
     929 
     930                    $currentChange->{'entries'}->{$after_entry_name} = { 
     931                        old_value => undef, 
     932                        new_value => $after_entry_value, 
     933                    }; 
     934 
     935                    # Get the next key/value pair from the after group. 
     936                    ($after_entry_name, $after_entry_value) = $self->_nextVal($after_parser); 
     937                } 
     938 
     939                # Get the next group from the after file. 
     940                $after_group = $self->_nextGroup($after_parser); 
    774941            } 
    775942 
    776             # Once we're out of the previous loop, then we are finished enumerating 
    777             # all key/value pairs corresponding to the identical group in either files. 
    778  
    779             # And get the next group to compare from both files. 
    780             $before_group = $self->_nextGroup($before_parser); 
    781             $after_group  = $self->_nextGroup($after_parser); 
    782  
    783         # Else, if the after group doesn't exist, or if the before group exists and the 
    784         # before group name is alphabetically earlier than the after group name... 
    785         } elsif (!defined($after_group) || defined($before_group) && 
    786                  $self->_cmpGroup($before_group, $after_group) < 0) { 
    787  
    788             # Get the length of the before group. 
    789             my $before_group_length = length($before_group); 
    790  
    791             # Scenario: 
    792             # Directory was deleted. 
    793  
    794             # Save the change. 
    795             $change->{'key'} = $before_group; 
    796             $change->{'status'} = "deleted"; 
    797             $change->{'entries'} = { }; 
    798  
    799             # Get the first key/value pair from this before group. 
    800             my ($before_entry_name, $before_entry_value) = $self->_nextVal($before_parser); 
    801  
    802             # While there are key/values within this before group. 
    803             while (defined($before_entry_name)) { 
    804                 $change->{'entries'}->{$before_entry_name} = { 
    805                     old_value => $before_entry_value, 
    806                     new_value => undef, 
    807                 }; 
    808  
    809                 # And get the next corresponding key/value pair from the before group. 
    810                 ($before_entry_name, $before_entry_value) = $self->_nextVal($before_parser); 
     943            # Transform the 'entries' sub-key from a nested hash structure, 
     944            # into an array of separate hashtables. 
     945            if (exists($currentChange->{'entries'})) { 
     946                my $entries = [ ]; 
     947                while (my ($key, $value) = each(%{$currentChange->{'entries'}})) { 
     948                    push (@{$entries}, { 
     949                            name      => $key, 
     950                            old_value => $value->{'old_value'}, 
     951                            new_value => $value->{'new_value'}, 
     952                        }); 
     953                } 
     954                $currentChange->{'entries'} = $entries; 
    811955            } 
    812956 
    813             # Get the next group from the before file. 
    814             $before_group = $self->_nextGroup($before_parser); 
    815  
    816         # Else, the after group exists but the corresponding before group 
    817         # did not exist -- which means that this is a new group. 
    818         } else { 
    819             # Scenario: 
    820             # Directory was added. 
    821  
    822             # Save the change. 
    823             $change->{'key'} = $after_group; 
    824             $change->{'status'} = "added"; 
    825             $change->{'entries'} = { }; 
    826  
    827             # Get the first key/value pair from this after group. 
    828             my ($after_entry_name, $after_entry_value) = $self->_nextVal($after_parser); 
    829  
    830             # While there are key/values within this after group. 
    831             while (defined($after_entry_name)) { 
    832  
    833                 $change->{'entries'}->{$after_entry_name} = { 
    834                     old_value => undef, 
    835                     new_value => $after_entry_value, 
    836                 }; 
    837  
    838                 # Get the next key/value pair from the after group. 
    839                 ($after_entry_name, $after_entry_value) = $self->_nextVal($after_parser); 
     957            # Determine if $currentChange is empty. 
     958            $currentChangeExists = scalar(keys(%{$currentChange})); 
     959 
     960            # Push the change onto our array of changes. 
     961            if ($currentChangeExists) { 
     962                push(@{$changes}, $currentChange); 
     963            } else { 
     964                $changeState--; 
    840965            } 
    841  
    842             # Get the next group from the after file. 
    843             $after_group = $self->_nextGroup($after_parser); 
     966# TODO: delete. 
     967#$Data::Dumper::Terse = 1; 
     968#$Data::Dumper::Indent = 1; 
     969#print "Current Change: " . Dumper($currentChange) . "\n"; 
    844970        } 
    845971 
    846         # Transform the 'entries' sub-key from a nested hash structure, 
    847         # into an array of separate hashtables. 
    848         if (exists($change->{'entries'})) { 
    849             my $entries = [ ]; 
    850             while (my ($key, $value) = each(%{$change->{'entries'}})) { 
    851                 push (@{$entries}, { 
    852                         name      => $key, 
    853                         old_value => $value->{'old_value'}, 
    854                         new_value => $value->{'new_value'}, 
    855                 }); 
    856             } 
    857             $change->{'entries'} = $entries; 
    858         } 
    859  
    860         # Push the change onto our array of changes. 
    861         if (scalar(keys(%{$change}))) { 
    862             push(@{$changes}, $change); 
    863         } 
    864972    } 
    865973 
    866     # TODO: delete this, eventually. 
    867     $Data::Dumper::Terse = 1; 
    868     $Data::Dumper::Indent = 1; 
    869     #print "Complete list: " . Dumper($changes) . "\n"; 
    870     return $changes; 
     974    # TODO: delete. 
     975    #return $changes; 
    871976} 
    872977 
  • honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Makefile

    r98 r116  
    66clean: 
    77    rm -f Parser.pm 
     8    rm -f Parser.3pm 
    89 
    910all: Parser 
  • honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Parser.pm

    r112 r116  
    490490        $_[0]->YYData->{'in_group'} = 0; 
    491491        $LOG->debug("Found NEWLINE token ending at offset (" . pos($_[0]->YYData->{DATA}) . ")."); 
     492        $_[0]->YYData->{'line_count'}++; 
    492493        return ("NEWLINE", "\n"); 
    493494    } 
     
    513514            $_[0]->YYData->{'in_group'} = 1; 
    514515            $LOG->debug("Found DIR_NAME token ending at offset (" . pos($_[0]->YYData->{DATA}) . ")."); 
     516            $_[0]->YYData->{'last_group_line_number'} = $_[0]->YYData->{'line_count'}; 
     517            $_[0]->YYData->{'line_count'}++; 
    515518            return ("DIR_NAME", $1); 
    516519        } 
     
    519522        if ($_[0]->YYData->{DATA} =~ m/\GREGEDIT4\n/cg) { 
    520523            $LOG->debug("Found HEADER token ending at offset (" . pos($_[0]->YYData->{DATA}) . ")."); 
     524            $_[0]->YYData->{'line_count'}++; 
    521525            return ("HEADER", "REGEDIT4\n"); 
    522526        } 
     
    547551                $_[0]->YYData->{'in_value'} = 0; 
    548552                $LOG->debug("Found KEY_VALUE token ending at offset (" . pos($_[0]->YYData->{DATA}) . ")."); 
     553                $_[0]->YYData->{'line_count'} += 1 + @{[$1 =~ /\n/g]}; 
    549554                return ("KEY_VALUE", $1); 
    550555            } 
     
    554559                $_[0]->YYData->{'in_value'} = 0; 
    555560                $LOG->debug("Found KEY_VALUE token ending at offset (" . pos($_[0]->YYData->{DATA}) . ")."); 
     561                $_[0]->YYData->{'line_count'} += 1 + @{[$1 =~ /\n/g]}; 
    556562                return ("KEY_VALUE", $1); 
    557563            } 
     
    631637    # Total number of key/value pairs parsed. 
    632638    $self->YYData->{'entry_count'} = 0; 
     639 
     640    # Total number of lines parsed. 
     641    $self->YYData->{'line_count'} = 0; 
     642 
     643    # Last line number that corresponded to a group separation point. 
     644    $self->YYData->{'last_group_line_number'} = 0; 
    633645 
    634646    # Progress bar information. 
     
    656668    $LOG->debug("Starting group index process."); 
    657669 
    658     $self->YYData->{'group_index'} = [0, ]; 
     670    $self->YYData->{'group_index_offsets'} = [0, ]; 
     671    $self->YYData->{'group_index_linenums'} = [0, ]; 
    659672 
    660673    my $registryGroup = $self->nextGroup(); 
    661674    while(scalar(keys(%{$registryGroup}))) { 
     675        push (@{$self->YYData->{'group_index_offsets'}}, $self->YYData->{'input_pos'}); 
     676        push (@{$self->YYData->{'group_index_linenums'}}, $self->YYData->{'last_group_line_number'}); 
    662677        $registryGroup = $self->nextGroup(); 
    663         push (@{$self->YYData->{'group_index'}}, $self->YYData->{'input_pos'}); 
    664678    } 
    665679 
     
    678692# see the Search::Binary POD documentation. 
    679693# 
    680 # Inputs: parser, value_to_compare, current_array_index 
     694# Inputs: arrayref, value_to_compare, current_array_index 
    681695# Outputs: comparison, last_valid_array_index 
    682696sub _search { 
     
    692706 
    693707    # Perform a comparison, if the array entry is defined. 
    694     if (defined(@{$parser->YYData->{'group_index'}}[$parser->YYData->{'last_search_index'}])) { 
    695         return($value_to_compare <=> @{$parser->YYData->{'group_index'}}[$parser->YYData->{'last_search_index'}], 
    696                $parser->YYData->{'last_search_index'}); 
     708    # Check to see if the search is for line numbers or offsets. 
     709    if ($parser->YYData->{'search_is_linenum'}) { 
     710        if (defined(@{$parser->YYData->{'group_index_linenums'}}[$parser->YYData->{'last_search_index'}])) { 
     711            return($value_to_compare <=> @{$parser->YYData->{'group_index_linenums'}}[$parser->YYData->{'last_search_index'}], 
     712                   $parser->YYData->{'last_search_index'}); 
     713        } 
     714    } else { 
     715        if (defined(@{$parser->YYData->{'group_index_offsets'}}[$parser->YYData->{'last_search_index'}])) { 
     716            return($value_to_compare <=> @{$parser->YYData->{'group_index_offsets'}}[$parser->YYData->{'last_search_index'}], 
     717                   $parser->YYData->{'last_search_index'}); 
     718        } 
    697719    } 
    698720 
     
    797819        $parser->_index(); 
    798820    } else { 
    799         $parser->YYData->{'group_index'} = [0, ]; 
     821        $parser->YYData->{'group_index_offsets'} = [0, ]; 
     822        $parser->YYData->{'group_index_linenums'} = [0, ]; 
    800823    } 
    801824 
     
    11431166=pod 
    11441167 
    1145 =head2 $object->seekToNearestGroup(absolute_offset => $offset
     1168=head2 $object->getCurrentLineCount(
    11461169 
    11471170=over 4 
    11481171 
    1149 Given an absolute offset within the file, this function 
     1172Returns the number of lines parsed by the Parser B<$object>  
     1173within the specified file and resets the counter back to 
     1174zero. 
     1175 
     1176I<Output>: Returns the current line count of the parser. 
     1177 
     1178B<Note>: Calling this function will reset the parser's 
     1179line count. 
     1180 
     1181=back 
     1182 
     1183=begin testing 
     1184 
     1185my ($handle); 
     1186my $test_registry_file = $ENV{PWD} . "/" . getVar(name      => "registry_file", 
     1187                                                  namespace => "HoneyClient::Agent::Integrity::Registry::Parser::Test"); 
     1188 
     1189# Create a generic Parser object, with test state data. 
     1190my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file, index_groups => 1); 
     1191 
     1192$parser->seekToNearestGroup(absolute_offset => 84); 
     1193my $nextGroup = $parser->nextGroup(); 
     1194 
     1195is($parser->getCurrentLineCount(), 9, "getCurrentLineCount()") or diag("The getCurrentLineCount() call failed."); 
     1196 
     1197=end testing 
     1198 
     1199=cut 
     1200 
     1201sub getCurrentLineCount { 
     1202    # Extract arguments. 
     1203    my ($self, %args) = @_; 
     1204 
     1205    # Log resolved arguments. 
     1206    # Make Dumper format more terse. 
     1207    $Data::Dumper::Terse = 1; 
     1208    $Data::Dumper::Indent = 0; 
     1209    $LOG->debug(Dumper(\%args)); 
     1210 
     1211    my $ret = $self->YYData->{'line_count'}; 
     1212    $self->YYData->{'line_count'} = 0; 
     1213    return $ret; 
     1214
     1215 
     1216=pod 
     1217 
     1218=head2 $object->seekToNearestGroup(absolute_offset => $offset, absolute_linenum => $linenum, adjust_index => $index) 
     1219 
     1220=over 4 
     1221 
     1222Given an absolute offset or line number within the file, this function 
    11501223will seek the parser to the nearest group found B<before> 
    11511224the specified offset. 
     
    11541227 B<$offset> is an required parameter, specifying the absolute offset 
    11551228within the file to seek to. 
     1229 B<$linenum> is a required parameter, specifying the absolute line 
     1230number within the file to seek to. 
     1231 B<$index> is an optional parameter, specifying to seek to a group 
     1232before or after the target group.  If unspecified, $index = 0. 
    11561233 
    11571234I<Outputs>: None. 
     1235 
     1236B<Notes>: Either B<$offset> or B<$linnum> must be specified.  To seek to the 
     1237target group, specify $index = 0 or leave undefined.  To seek to the previous 
     1238group before the target group, specify $index = -1.  To seek to the next 
     1239group after the target group, specify $index = 1. 
     1240 
     1241Once called, B<all> corresponding statistical counters will be reset.  This means, 
     1242that the output from $object->dirsParsed() and $object->entriesParsed() will be 
     1243zero, if called immediately after this function. 
    11581244 
    11591245=back 
     
    11681254my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file, index_groups => 1); 
    11691255 
    1170 $parser->seekToNearestGroup(absolute_offset => 84); 
    1171  
    11721256# Verify Test Group #2 
    1173 $nextGroup = $parser->nextGroup(); 
    11741257$expectedGroup = { 
    11751258    key     => 'HKEY_CURRENT_USER\Testing Group 2', 
     
    11911274    }, ], 
    11921275}; 
    1193 is_deeply($nextGroup, $expectedGroup, "seekToNearestGroup()") or diag("The seekToNearestGroup() call failed."); 
     1276is($parser->seekToNearestGroup(absolute_offset => 84), 73, "seekToNearestGroup(absolute_offset => 84)") or diag("The seekToNearestGroup() call failed."); 
     1277$nextGroup = $parser->nextGroup(); 
     1278is_deeply($nextGroup, $expectedGroup, "seekToNearestGroup(absolute_offset => 84)") or diag("The seekToNearestGroup() call failed."); 
     1279 
     1280is($parser->seekToNearestGroup(absolute_linenum => 7), 6, "seekToNearestGroup(absolute_linenum => 7)") or diag("The seekToNearestGroup() call failed."); 
     1281$nextGroup = $parser->nextGroup(); 
     1282is_deeply($nextGroup, $expectedGroup, "seekToNearestGroup(absolute_linenum => 7)") or diag("The seekToNearestGroup() call failed."); 
     1283 
     1284# Verify Test Group #3 
     1285$expectedGroup = { 
     1286    key     => 'HKEY_CURRENT_USER\Testing Group 3', 
     1287    entries => [ { 
     1288        name  => 'Test_Bin_1', 
     1289        value => 'hex:f4,ff,ff,ff,00,00,00,00,00,00,00,00,00,00,00,00,bc,02,00,00,00,\ 
     1290  00,00,00,00,00,00,00,54,00,61,00,68,00,6f,00,6d,00,61,00,00,00,f0,77,3f,00,\ 
     1291  3f,00,3f,00,3f,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,78,00,1c,10,fc,\ 
     1292  7f,22,14,fc,7f,b0,fe,12,00,00,00,00,00,00,00,00,00,98,23,eb,77' 
     1293    }, { 
     1294        name  => 'Test_Bin_2', 
     1295        value => 'hex:f5,ff,ff,ff,00,00,00,00,00,00,00,00,00,00,00,00,90,01,00,00,00,\ 
     1296  00,00,00,00,00,00,00,4d,00,69,00,63,00,72,00,6f,00,73,00,6f,00,66,00,74,00,\ 
     1297  20,00,53,00,61,00,6e,00,73,00,20,00,53,00,65,00,72,00,69,00,66,00,00,00,f0,\ 
     1298  77,00,20,14,00,00,00,00,10,80,05,14,00,f0,1f,14,00,00,00,14,00' 
     1299