Changeset 123

Show
Ignore:
Timestamp:
12/17/06 15:39:43 (2 years ago)
Author:
kindlund
Message:

Completed alpha version of bug fix. Still have to test it out on our test VM network.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • honeyclient/branches/bug/42/bin/StartAgent.pl

    r122 r123  
    3737    print "Watchdog fault detected, recovering Agent daemon.\n"; 
    3838    # XXX: Reenable this, eventually. 
    39 #    Carp::carp __PACKAGE__ . "->_watchdogFaultHandler(): Error occurred during processing.\n" . $errMsg; 
     39    #Carp::carp __PACKAGE__ . "->_watchdogFaultHandler(): Error occurred during processing.\n" . $errMsg; 
    4040 
    4141 
  • honeyclient/branches/bug/42/bin/TestRegistry.pl

    r122 r123  
    2929my $registry = HoneyClient::Agent::Integrity::Registry->new(); 
    3030 
     31print "\n"; 
    3132print "Baseline check complete.  Perform normal allowable actions\n" . 
    3233      "on the system (i.e., browse benign web pages).\n\n" . 
     
    5758    $Data::Dumper::Indent = 1; 
    5859    print $fh Dumper($changes); 
    59     print "\nDone!\n"; 
     60    print "\n"; 
     61    print "Done!\n"; 
    6062    print "Detailed registry changes were written to: " . $file . "\n"; 
    6163} 
  • honeyclient/branches/bug/42/etc/honeyclient.xml

    r119 r123  
    4949    <!-- Note: This timeout should be long enough so that the Agent watchdog code will properly let the integrity checking code finish, before detecting a faulty timeout in processing. --> 
    5050    <timeout description="Default timeout used for all communications between each module (in seconds)." default="900"> 
    51         900 
     51        1800 
    5252    </timeout> 
    5353    <log_config description="The global Log4perl configuration file, used throughout all modules.  This setting should not need to be changed." default="etc/honeyclient_log.conf"> 
     
    121121            <!-- Files which are read in only. --> 
    122122            <!-- TODO: Update this. --> 
    123             <file_checklist description="The file containing the list of files and directories to check during filesystem checking."
    124                 ../../../etc/file_checklist.txt 
     123            <file_checklist description="The file containing the list of files and directories to check during filesystem checking." default="none"
     124                etc/file_checklist.txt 
    125125            </file_checklist> 
    126126            <!-- TODO: Update this. --> 
    127             <file_exclude description="The file containing the list of files or directories to exclude if found in subdirectories during filesystem checking."
     127            <file_exclude description="The file containing the list of files or directories to exclude if found in subdirectories during filesystem checking." default="none"
    128128                ../../../etc/file_exclude.txt 
    129129            </file_exclude> 
    130             <!-- TODO: Update this. --> 
    131             <reg_exclude_file description="The file containing the list of regular expressions specifying registry keys to exclude during registry checking."> 
    132                 ../../../etc/reg_exclude.txt 
    133             </reg_exclude_file> 
    134             <!-- TODO: Update this. --> 
    135             <reg_list_to_check description="The file containing the list of registry keys to check."> 
    136                 ../../../etc/reg_list_to_check.txt 
    137             </reg_list_to_check> 
    138130            <!-- Files which are written out only. --> 
    139131            <!-- TODO: Update this. --> 
     
    146138            </change_file> 
    147139            <!-- Files to read and write. --> 
    148             <!-- TODO: Update this. --> 
    149             <clean_reg description="Stores baseline for the registry.  Always appended with a number."> 
    150                 clean.reg 
    151             </clean_reg> 
    152             <!-- TODO: Update this. --> 
    153             <current_reg description="Stores the current state of the register to check against the clean state."> 
    154                 current.reg 
    155             </current_reg> 
    156             <!-- TODO: Update this. --> 
    157             <diffs description="The file for the diff command to redirect its output to.  Always appended with a number."> 
    158                 differences.out 
    159             </diffs> 
    160140            <!-- TODO: Update this. --> 
    161141            <test_dir description="If you're testing integrity checks, this is the directory that you can specify to minimize testing time. Only the files in this directory will be part of the integrity check."> 
  • honeyclient/branches/bug/42/lib/HoneyClient/Agent.pm

    r96 r123  
    210210# TODO: Update unit tests to include 'dclone' 
    211211use Storable qw(nfreeze thaw dclone); 
     212$Storable::Deparse = 1; 
     213$Storable::Eval = 1; 
    212214 
    213215# Include Base64 Libraries 
     
    366368 
    367369    # Perform initial integrity baseline check. 
    368     my $integrity = undef; 
    369     if ($PERFORM_INTEGRITY_CHECKS) { 
    370         print "Initializing Integrity Check...\n"; 
    371         # TODO: Initialize Integrity Checks 
    372         $integrity = HoneyClient::Agent::Integrity->new(); 
    373         $integrity->initAll(); 
    374    
    375     $integrityState = nfreeze($integrity); 
     370    #my $integrity = undef; 
     371    #if ($PERFORM_INTEGRITY_CHECKS) { 
     372    #    print "Initializing Integrity Check...\n"; 
     373    #    # TODO: Initialize Integrity Checks 
     374    #    $integrity = HoneyClient::Agent::Integrity->new(); 
     375    #    $integrity->initAll(); 
     376    #
     377    #$integrityState = $integrity->serialize(); 
    376378 
    377379    # Release data lock. 
     
    721723                    # As such, do NOT try to call integrity checks on multiple, simultaneous 
    722724                    # asynchronous threaded drivers. 
    723                     $integrity = thaw($integrityState); 
     725                    #$integrity = thaw($integrityState); 
     726                    # Perform initial integrity baseline check. 
     727                    print "Initializing Integrity Check...\n"; 
     728                    # TODO: Initialize Integrity Checks 
     729                    $integrity = HoneyClient::Agent::Integrity->new(); 
     730                    $integrity->initAll(); 
     731 
     732                    # TODO: Delete this. 
     733                    #$Data::Dumper::Indent = 1; 
     734                    #$Data::Dumper::Terse = 1; 
     735                    #print "Integrity: " . Dumper($integrity) . "\n"; 
    724736                } 
    725737 
  • honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity.pm

    r96 r123  
    104104can_ok('HoneyClient::Agent::Integrity', 'initFileSystem'); 
    105105can_ok('HoneyClient::Agent::Integrity', 'checkFileSystem'); 
    106 can_ok('HoneyClient::Agent::Integrity', 'initRegistry'); 
    107 can_ok('HoneyClient::Agent::Integrity', 'checkRegistry'); 
    108 use HoneyClient::Agent::Integrity qw(initAll checkAll initRegistry checkRegistry initFileSystem checkFileSystem); 
     106use HoneyClient::Agent::Integrity qw(initAll checkAll initFileSystem checkFileSystem); 
    109107 
    110108# Make sure HoneyClient::Util::Config loads. 
     
    133131 
    134132# Make sure Storable loads. 
    135 BEGIN { use_ok('Storable', qw(dclone)) or diag("Can't load Storable package.  Check to make sure the package library is correctly listed within the path."); } 
     133BEGIN { use_ok('Storable', qw(dclone nfreeze thaw)) or diag("Can't load Storable package.  Check to make sure the package library is correctly listed within the path."); } 
    136134require_ok('Storable'); 
    137135can_ok('Storable', 'dclone'); 
    138 use Storable qw(dclone); 
     136can_ok('Storable', 'nfreeze'); 
     137can_ok('Storable', 'thaw'); 
     138use Storable qw(dclone nfreeze thaw); 
    139139 
    140140###Testing Globals### 
     
    158158# Include Global Configuration Processing Library 
    159159use HoneyClient::Util::Config qw(getVar); 
     160use HoneyClient::Agent::Integrity::Registry; 
    160161use File::Find qw(find); 
    161162#use Win32::TieRegistry; 
    162163use Digest::MD5; 
    163164use MIME::Base64; 
    164 use Switch; 
    165 use Storable qw(dclone); 
     165use Storable qw(nfreeze thaw dclone); 
     166$Storable::Deparse = 1; 
     167$Storable::Eval = 1; 
    166168use Data::Dumper; 
    167169use File::Basename qw(dirname); 
     
    178180 
    179181    # Symbols to export on request 
    180     @EXPORT = qw(new initAll checkAll initRegistry checkRegistry initFileSystem checkFileSystem); 
     182    @EXPORT = qw(new initAll checkAll); 
    181183 
    182184    # Items to export into callers namespace by default. Note: do not export 
     
    208210#Used *for now* to signal whether any changes occured (if they == 1) 
    209211my $g_fs_changes = 0; 
    210 my $g_reg_changes = 0; 
    211  
    212 #Used to initialize a default registry space to check if they don't specify anything when creating the object 
    213 my @default_reg_check_array = ("HKEY_LOCAL_MACHINE", "HKEY_CLASSES_ROOT", "HKEY_CURRENT_USER", "HKEY_USERS", "HKEY_CURRENT_CONFIG"); 
    214  
    215 #I have no idea why slashes need to be triple-slashes since it's single quoted, but that's what works... 
    216 #also, of course [ and ] and any other special characters you find need to be escaped 
    217 my @default_reg_exclude_array = ( 
    218     '\[HKEY_LOCAL_MACHINE\\\SOFTWARE\\\Microsoft\\\Cryptography\\\RNG\]',  
    219     '\[HKEY_CURRENT_USER\\\SessionInformation\]', 
    220     '\[HKEY_USERS\\\.+\\\SessionInformation\]',  
    221     '\[HKEY_LOCAL_MACHINE\\\SOFTWARE\\\Microsoft\\\Windows\\\CurrentVersion\\\WindowsUpdate\\\Auto Update\]',  
    222     '\[HKEY_USERS\\\.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\UserAssist\\\.*\\\Count\]',  
    223     '\[HKEY_LOCAL_MACHINE\\\SYSTEM\\\CurrentControlSet\\\Services\\\.+\\\Parameters\\\Tcpip\]', 
    224     '\[HKEY_LOCAL_MACHINE\\\SYSTEM\\\CurrentControlSet\\\Services\\\Tcpip\\\Parameters\\\Interfaces\\\.+\]', 
    225     '\[HKEY_LOCAL_MACHINE\\\SYSTEM\\\CurrentControlSet\\\Services\\\Dhcp\\\Parameters\]', 
    226     '\[HKEY_LOCAL_MACHINE\\\SYSTEM\\\ControlSet.+\\\Services\\\.+\\\Parameters\\\Tcpip\]', 
    227     '\[HKEY_LOCAL_MACHINE\\\SYSTEM\\\ControlSet.+\\\Services\\\Tcpip\\\Parameters\\\Interfaces\\\.+\]', 
    228     '\[HKEY_LOCAL_MACHINE\\\SYSTEM\\\ControlSet.+\\\Services\\\Dhcp\\\Parameters\]', 
    229     '\[HKEY_LOCAL_MACHINE\\\SOFTWARE\\\Microsoft\\\Windows\\\CurrentVersion\\\BITS]', 
    230     '\[HKEY_USERS\\\.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\UserAssist\\\.+\\\Count\]', 
    231     '\[HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\UserAssist\\\.+\\\Count\]', 
    232     '\[HKEY_LOCAL_MACHINE\\\SOFTWARE\\\Microsoft\\\Windows\\\CurrentVersion\\\Group Policy\\\State\\\Machine\\\Extension-List\\\.+\]', 
    233     '\[HKEY_LOCAL_MACHINE\\\SOFTWARE\\\Microsoft\\\Windows\\\CurrentVersion\\\Group Policy\\\State\\\.+\\\Extension-List\\\.+\]', 
    234     '\[HKEY_USERS\\\.+\\\Software\\\Microsoft\\\Windows\\\ShellNoRoam\\\BagMRU\]', 
    235     '\[HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\ShellNoRoam\\\BagMRU\]', 
    236     '\[HKEY_CURRENT_USER\\\Volatile Environment\]', 
    237     '\[HKEY_USERS\\\.+\\\UNICODE Program Groups\]', 
    238     '\[HKEY_LOCAL_MACHINE\\\SYSTEM\\\ControlSet.+\\\Services\\\SharedAccess\\\Epoch\]', 
    239     '\[HKEY_LOCAL_MACHINE\\\SYSTEM\\\CurrentControlSet\\\Services\\\SharedAccess\\\Epoch\]', 
    240     '\[HKEY_LOCAL_MACHINE\\\SYSTEM\\\CurrentControlSet\\\Services\\\Eventlog\\\Application\\\ESENT\]', 
    241     '\[HKEY_LOCAL_MACHINE\\\SYSTEM\\\ControlSet001\\\Services\\\Eventlog\\\Application\\\ESENT\]', 
    242     '\[HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Internet Settings\\\Connections\]', 
    243     '\[HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Ext\\\Stats\\\.*\\\iexplore\]', 
    244     '\[HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MenuOrder\\\Favorites\\\Links\]', 
    245     '\[HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Internet Settings\\\Connections\]', 
    246     '\[HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Ext\\\Stats\\\.*\\\iexplore\]', 
    247     '\[HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MenuOrder\\\Favorites\\\Links\]', 
    248     '\[HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MenuOrder\\\Favorites\\\Links\]', 
    249     '\[HKEY_LOCAL_MACHINE\SOFTWARE\\\Microsoft\\\Windows\\\CurrentVersion\\\WindowsUpdate\\\.*\]', 
    250     '\[HKEY_LOCAL_MACHINE\SOFTWARE\\\Microsoft\\\Windows\\\CurrentVersion\\\WindowsUpdate\\\Reporting\\\.*\]', 
    251     '\[HKEY_LOCAL_MACHINE\SOFTWARE\\\Microsoft\\\Windows\\\CurrentVersion\\\WindowsUpdate\\\Reporting\\\EventCache\\\.*\]', 
    252     '\[HKEY_LOCAL_MACHINE\SOFTWARE\\\Microsoft\\\Windows\\\CurrentVersion\\\WindowsUpdate\\\Reporting\\\EventCache\\\.+\]', 
    253     '\[HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MountPoints2\\\CPC\\\Volume\]', 
    254     '\[HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MountPoints2\\\CPC\\\Volume\\\.*\]', 
    255     '\[HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MountPoints2\\\CPC\\\Volume\]', 
    256     '\[HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MountPoints2\\\CPC\\\Volume\\\.*\]', 
    257     '\[HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\ShellNoRoam\\\MUICache\]', 
    258     '\[HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Internet Settings\\\5.0\\\Cache\]', 
    259     '\[HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Internet Settings\\\5.0\\\Cache\\\.*\]', 
    260     '\[HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\ShellNoRoam\\\MUICache\]', 
    261     '\[HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Internet Settings\\\5.0\\\Cache\]', 
    262     '\[HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Internet Settings\\\5.0\\\Cache\\\.*\]', 
    263 ); 
    264212 
    265213# XXX: All dirs must NEVER end in a trailing slash. 
     
    290238    '/cygdrive/c/Program Files/Mozilla Firefox/updates.xml', 
    291239    '/cygdrive/c/WINDOWS/SoftwareDistribution/WuRedir', 
     240    '/cygdrive/c/WINDOWS/SYSTEM32/config/SecEvent.Evt', 
     241    '/cygdrive/c/WINDOWS/SYSTEM32/config/SysEvent.Evt', 
     242    '/cygdrive/c/WINDOWS/SYSTEM32/wbem/Repository/FS/INDEX.BTR', 
     243    '/cygdrive/c/WINDOWS/SYSTEM32/wbem/Repository/FS/INDEX.MAP', 
     244    '/cygdrive/c/WINDOWS/SYSTEM32/wbem/Repository/FS/MAPPING.VER', 
     245    '/cygdrive/c/WINDOWS/SYSTEM32/wbem/Repository/FS/MAPPING2.MAP', 
     246    '/cygdrive/c/WINDOWS/SYSTEM32/wbem/Repository/FS/OBJECTS.DATA', 
     247    '/cygdrive/c/WINDOWS/SYSTEM32/wbem/Repository/FS/OBJECTS.MAP', 
    292248); 
    293249 
     
    295251my %PARAMS = ( 
    296252 
    297     ### Files which are read in only ### 
    298     # List of files and directories to check during filesystem checking 
    299     file_checklist => getVar(name => "file_checklist", namespace => "HoneyClient::Agent::Integrity"), 
     253    # Contains the Registry object, once initialized. 
     254    _registry => undef, 
     255 
     256    # XXX: Clean the rest of these variables up. 
     257    ### Files which are read in only ### 
     258    # List of files and directories to check during filesystem checking 
     259    file_checklist => getVar(name => "file_checklist", namespace => "HoneyClient::Agent::Integrity"), 
    300260     
    301261    # List of files or directories to exclude if found in subdirs during 
    302262    # filesystem check. 
    303     file_exclude => getVar(name => "file_exclude", namespace => "HoneyClient::Agent::Integrity"), 
    304      
    305     # List of registry keys to check 
    306     reg_list_to_check   => getVar(name => "reg_list_to_check", namespace => "HoneyClient::Agent::Integrity"), 
    307  
    308     # List of registry keys to exclude 
    309     reg_exclude_file => getVar(name => "reg_exclude_file", namespace => "HoneyClient::Agent::Integrity"), 
     263    file_exclude => getVar(name => "file_exclude", namespace => "HoneyClient::Agent::Integrity"), 
    310264     
    311265    ### Files to write and read ### 
    312266    # File to store hashes for files selected during the baseline 
    313    clean_file => getVar(name => "clean_file", namespace => "HoneyClient::Agent::Integrity"), 
     267    clean_file => getVar(name => "clean_file", namespace => "HoneyClient::Agent::Integrity"), 
    314268     
    315269    # File to write any found changes to 
    316    change_file => getVar(name => "change_file", namespace => "HoneyClient::Agent::Integrity"), 
     270    change_file => getVar(name => "change_file", namespace => "HoneyClient::Agent::Integrity"), 
    317271     
    318     # Stores baseline for the registry. Always appended with a number 
    319     clean_reg => getVar(name => "clean_reg", namespace => "HoneyClient::Agent::Integrity"), 
     272    #vars 
     273    file_exclude_hash => undef, #hash, holds files to exclude 
     274    file_list => undef, #list, files to check when checking filesystem 
    320275     
    321     # Stores the current state of the registry to check against the 
    322     # clean state 
    323     current_reg => getVar(name => "current_reg", namespace => "HoneyClient::Agent::Integrity"), 
    324      
    325     # The file for the diff command to redirect it's output to. 
    326     # Always appended with a number. 
    327     diffs => getVar(name => "diffs", namespace => "HoneyClient::Agent::Integrity"), 
    328  
    329     #vars 
    330     file_exclude_hash => undef, #hash, holds files to exclude 
    331     file_list => undef, #list, files to check when checking filesystem 
    332     reg1 => undef,      #list,  holds entire contents of first file to diff 
    333     reg2 => undef,      #list, holds entire contents of second file to diff 
    334      
    335     #array that holds the locations in the registry to check 
    336     reg_check_array => undef, 
    337     #array that holds the registry locations that should be excluded from the detected changes 
    338     reg_exclude_array => undef,  
    339  
    340276    #works exactly like the reg_exclude_array, and is initialized in a similar way 
    341     file_exclude_array => undef, 
    342  
    343     changes => undef,   #multi-dimensional array used for holding individual instances of a diff output 
    344     g_count => -1,  #highest level index for, each $g_count will be a different instance of a diff grouping 
     277    file_exclude_array => undef, 
     278 
     279    changes => undef,   #multi-dimensional array used for holding individual instances of a diff output 
    345280); 
    346281 
     
    409344 
    410345sub initAll { 
    411 my $self = shift; 
     346    my $self = shift; 
    412347    # XXX: initRegistry() MUST be called before initFileSystem, since initRegistry 
    413348    # creates new files that must exist to be added to the exclusion list for 
    414349    # initFileSystem. 
    415     $self->initRegistry(); 
     350    $self->{'_registry'} = HoneyClient::Agent::Integrity::Registry->new(); 
    416351    $self->initFileSystem(); 
    417352} 
     
    428363 
    429364sub checkAll { 
    430 my $self = shift; 
    431 my $retval; 
    432  
    433     #Add any new created checks here 
    434   
    435     $self->startCheckProcesses();   #currently a dummy method that just returns 
     365    my $self = shift; 
     366    my $retval; 
     367 
    436368    # If at all possible we want the (faster) registry checks to short circut 
    437369    # the overall checks so we don't have to do the very slow filesystem checks. 
    438     $retval = $self->checkRegistry(); 
    439 # TODO: Re-enable this block. 
    440 #   if($retval){ 
    441 #       return $retval; 
    442 #   } 
    443     $retval = $self->checkFileSystem(); 
     370    my $changes = $self->{'_registry'}->check(); 
     371    if (scalar(@{$changes})) { 
     372        print "Registry has changed:\n"; 
     373        foreach my $change (@{$changes}) { 
     374            print $change->{'key'} . " (" . $change->{'status'} . ")\n"; 
     375        } 
     376        open CHANGES, ">>$self->{change_file}" or die "Cannot open $self->{change_file}: $!\n";      
     377        $Data::Dumper::Terse = 1; 
     378        $Data::Dumper::Indent = 1; 
     379        print CHANGES Dumper($changes); 
     380        close CHANGES; 
     381        return $changes; 
     382    } 
     383    print "No registry changes have occurred.\n"; 
     384    $retval = $self->checkFileSystem(); 
    444385 
    445386    return $retval; 
    446  
    447  
    448 
     387
     388 
     389# TODO: Comment this. 
     390sub serialize { 
     391    my $self = shift; 
     392 
     393    if (defined($self->{'_registry'})) { 
     394        $self->{'_registry'}->closeFiles(); 
     395    } 
     396 
     397    return nfreeze($self); 
     398
     399 
    449400################################################################################ 
    450401 
     
    513464    $g_hack = $self->{file_list}; 
    514465    $g_ex_hash = (); 
     466    my $file; 
    515467     
    516468    my @checkdirs = $self->_get_directories_to_check(); 
     
    528480    } 
    529481 
    530     foreach my $file (@{$self->{file_exclude_array}}){ 
     482    $/ = "\n"; 
     483    foreach $file (@{$self->{file_exclude_array}}){ 
    531484        chomp $file; 
    532485        if(-f $file){ 
     
    547500 
    548501    print "Finding Files in initFileSystem...Be Patient.\n"; 
    549     foreach my $checkdir(@checkdirs) { 
     502    foreach my $checkdir (@checkdirs) { 
    550503        find (\&_found, "$checkdir");   #this will populate @{$self->{file_list}} 
    551504    } 
     
    553506    $self->{file_list} = $g_hack; 
    554507    $self->{file_exclude_hash} = $g_ex_hash; 
    555 ###   print "file_exclude_hash in init\n" . Dumper($self->{file_exclude_hash}) . "\n"; 
     508##    print "file_exclude_hash in init\n" . Dumper($self->{file_exclude_hash}) . "\n"; 
    556509 
    557510    print "Hashing Files in initFileSystem...Be Patient\n"; 
    558511    open CLEANFILE, ">$self->{clean_file}" or die "Cannot open $self->{clean_file}: $!\n"; 
    559     foreach my $file (@{$self->{file_list}}) { 
     512    foreach $file (@{$self->{file_list}}) { 
    560513#       print "hashing $file\n"; 
    561514        if(open HASHFILE, "$file") { 
     
    638591sub checkFileSystem { 
    639592 
    640 my $self = shift;   #Object 
    641 %{$self->{clean_file_hash}} = (); 
    642 %{$self->{changed_file_hash}} = (); 
    643 my %current_file_hash = (); 
    644 my %new_file_hash = (); 
    645 my %del_file_hash = (); 
    646 my @checkdirs; 
    647 my $standalone_test = 0; 
     593    my $self = shift;   #Object 
     594    %{$self->{clean_file_hash}} = (); 
     595    %{$self->{changed_file_hash}} = (); 
     596    my %current_file_hash = (); 
     597    my %new_file_hash = (); 
     598    my %del_file_hash = (); 
     599    my @checkdirs; 
     600    my $standalone_test = 0; 
     601    my $file; 
     602    my $key; 
    648603 
    649604### print "file_exclude_hash in check\n" . Dumper($self->{file_exclude_hash}) . "\n"; 
     
    655610    #open file to create hash of values for clean files 
    656611    open CLEANFILE, "$self->{clean_file}" or die "Cannot open $self->{clean_file}: $!\n"; 
     612    $/ = "\n"; 
    657613    while(<CLEANFILE>) { 
    658614        my $line = $_; 
     
    691647        } 
    692648     
    693         foreach my $file (@{$self->{file_exclude_array}}){ 
     649        $/ = "\n"; 
     650        foreach $file (@{$self->{file_exclude_array}}){ 
    694651            chomp $file; 
    695652            if(-f $file){ 
     
    721678    #also detects new files 
    722679    print "Hashing Files in checkFileSystem...Be Patient\n"; 
    723     foreach my $file (@{$self->{file_list}}) { 
    724       if(open HASHFILE, "$file") { 
     680    foreach $file (@{$self->{file_list}}) { 
     681      if(open HASHFILE, "$file") { 
    725682            my $md5ctx = Digest::MD5->new(); 
    726683            # If this call fails, an exception will be generated. 
     
    739696 
    740697    #check for deleted files 
    741     foreach my $key (keys %{$self->{clean_file_hash}}) { 
     698    foreach $key (keys %{$self->{clean_file_hash}}) { 
    742699        if(!($current_file_hash{$key})) { 
    743700            $del_file_hash{$key} = $self->{clean_file_hash}->{$key}; 
     
    751708 
    752709        print CHANGES "Files deleted:\n"; 
    753         foreach my $key (sort keys %del_file_hash) { 
     710        foreach $key (sort keys %del_file_hash) { 
    754711            print CHANGES "$key\n"; 
    755712        } 
    756713        print CHANGES "\n\n"; 
    757714        print CHANGES "Files added:\n"; 
    758         foreach my $key (sort keys %new_file_hash) { 
     715        foreach $key (sort keys %new_file_hash) { 
    759716            print CHANGES "$key\n"; 
    760717        } 
    761718        print CHANGES "\n\n"; 
    762719        print CHANGES "Files modified:\n"; 
    763         foreach my $key (sort keys %{$self->{changed_file_hash}}) { 
     720        foreach $key (sort keys %{$self->{changed_file_hash}}) { 
    764721            print CHANGES "$key\n"; 
    765722        } 
     
    784741 
    785742    #Sets the VERY hardcoded default for now (late addition for ease of use, not clean code) 
    786    push @checkdirs, "/cygdrive/c/"; 
     743    push @checkdirs, "/cygdrive/c/"; 
    787744 
    788745    #Can override the default by creating this file (for now, eventually put directly into XML) 
     
    793750         "Please see the POD documentation for more information.\n"; 
    794751        @checkdirs = (); 
     752        $/ = "\n"; 
    795753        while(<CHECK>) { 
    796754            chomp; 
     
    814772         
    815773    my $foundfile = $File::Find::name; 
     774     
    816775    if (-f $foundfile) { 
    817776        if (exists($g_ex_hash->{$foundfile})) { 
     
    845804sub _recursive_exclude{ 
    846805     
    847    my $foundfile = $File::Find::name; 
     806   my $foundfile = $File::Find::name; 
    848807    if (-f $foundfile) { 
    849808        $g_ex_hash->{$foundfile} = 1; 
    850 #       print "\t _recursive_exclude()d $foundfile\n"; 
    851     } 
    852 
    853 ################################################################################ 
    854  
    855 =pod 
    856  
    857 =head1 
    858  
    859 initRegistry() : Takes no input. Optionally reads in a one-per-line list of  
    860 registry keys to check, as stored in $self->reg_list_to_check. If such a list is not 
    861 present, uses the values hardcoded in the @{$self->{reg_check_array}}. Uses a system() call to 
    862 have regedit export the keys and sub-keys beginning at the specified location.  
    863 Individual files are postfixed with their array index for uniqueness. Therefore 
    864 creates a number of files such as clean.reg0, clean.reg1, etc.  
    865  
    866 =begin testing 
    867  
    868  
    869 #Testing initRegistry() 
    870 my $ob = HoneyClient::Agent::Integrity->new(); 
    871  
    872 system("regedit.exe /s noTEST.reg"); 
    873 system("regedit.exe /s /c $test_dir/t1a.reg"); 
    874 $ob->initRegistry("HKEY_LOCAL_MACHINE\\HARDWARE\\TEST"); 
    875 open (DIFF, "diff $test_dir/t1a.reg clean.reg0 |") or die "Can't check the changes files\n"; 
    876 @result = <DIFF>; 
    877 close DIFF; 
    878 #Bad test because it will be empty in the case of an error anyway? 
    879 is(scalar(@result), 0, 'initRegistry: General Test'); 
    880  
    881 =end testing 
    882  
    883 =cut 
    884  
    885 sub initRegistry { 
    886 my $self = shift; 
    887  
    888     #If we're given function input, use it. 
    889     if(scalar(@_) > 0){ 
    890         print "given input for reg_check_array in the parameters\n"; 
    891         @{$self->{reg_check_array}} = @_; 
    892     } 
    893     else { 
    894         #otherwise, if we're given input via file, use it 
    895         if(-f "$self->{reg_list_to_check}"){ 
    896             open REGDIRS, "$self->{reg_list_to_check}" or die "Cannot open $self->{reg_list_to_check}: $!\n"; 
    897             #wipe out any hardcoded ones 
    898             @{$self->{reg_check_array}} = (); 
    899             while(<REGDIRS>){ 
    900                 push @{$self->{reg_check_array}}, $_; 
    901             } 
    902         } 
    903         #otherwise, it will use the default array. 
    904         else{ 
    905             $self->{reg_check_array} = \@default_reg_check_array; 
    906         } 
    907     } 
    908     my $tmp = $self->{clean_reg}; 
    909     print "clean_reg in initRegistry $tmp\n"; 
    910     print "reg_check_array in initRegistry @{$self->{reg_check_array}}\n"; 
    911     my $var = 0; 
    912     foreach my $key_to_check (@{$self->{reg_check_array}}){ 
    913         print "exporting $key_to_check to $self->{clean_reg}$var\n"; 
    914         print "regedit /a \"$self->{clean_reg}$var\" \"$key_to_check\" \n"; 
    915         system("regedit.exe /a \"$self->{clean_reg}$var\" \"$key_to_check\""); 
    916         # XXX: We touch the current and differences files first, even though they are empty. 
    917         # This is to make sure that these files get properly excluded during filesystem initialization, 
    918         # since they would not have existed otherwise, until after a registry check occurs. 
    919         system("touch \"$self->{current_reg}$var\""); 
    920         system("touch \"$self->{diffs}$var\""); 
    921         $var++; 
    922     } 
    923  
    924         if(-f $self->{reg_exclude_file}){ 
    925         open REGEXCLUDE, "$self->{reg_exclude_file}" or die "Cannot open $self->{reg_exclude_file}: $!\n"; 
    926         #wipe out any hardcoded ones 
    927         @{$self->{reg_exclude_file}} = (); 
    928         while(<REGEXCLUDE>){ 
    929             push @{$self->{reg_exclude_array}}, $_; 
    930         } 
    931     } 
    932     else{ 
    933         $self->{reg_exclude_array} = \@default_reg_exclude_array; 
    934     } 
    935 
    936 ################################################################################ 
    937  
    938 =pod 
    939  
    940 =head1 
    941  
    942 checkRegistry() : Takes no input. Responsible for dumping the current state of 
    943 each of the registry locations in @{$self->{reg_check_array}} and comparing it against that 
    944 which was exported to the filesystem in initRegistry() by using the command line 
    945 utility diff. If differences are detected it parses the diff file and consults 
    946 the original and new file as necessary to determine exactly what changed. 
    947  
    948 =begin testing 
    949  
    950  
    951 my $ob = HoneyClient::Agent::Integrity->new(); 
    952  
    953 reg_test($ob, 1, "checkRegistry: case 1 Multi-line addition changes."); 
    954 reg_test($ob, 2, "checkRegistry: case 2 Single-line addition changes."); 
    955 reg_test($ob, 3, "checkRegistry: case 3 Multi-line deletion changes."); 
    956 reg_test($ob, 4, "checkRegistry: case 4 Single-line deletion changes."); 
    957 reg_test($ob, 5, "checkRegistry: case 5 Simple multi-line to multi-line changes."); 
    958 is(6, 6, "checkRegistry: case 6 - SKIPPING (currently can't recreate conditions for test)"); 
    959 #reg_test($ob, 6, "checkRegistry: case 6 Complicated multi-line to multi-line changes."); 
    960 reg_test($ob, 7, "checkRegistry: case 7 Simple multi-line to single-line changes."); 
    961 reg_test($ob, 8, "checkRegistry: case 8 Complicated multi-line to single-line changes."); 
    962 reg_test($ob, 9, "checkRegistry: case 9 Simple single-line to multi-line changes."); 
    963 reg_test($ob, 10, "checkRegistry: case 10 Complicated single-line to multi-line changes."); 
    964 reg_test($ob, 11, "checkRegistry: case 11 Simple single-line to single-line changes."); 
    965 reg_test($ob, 12, "checkRegistry: case12 Complicated single-line to single-line changes."); 
    966  
    967 sub reg_test{ 
    968 my $ob = shift; 
    969 my $num = shift; 
    970 my $string = shift; 
    971  
    972     #for safety 
    973     if(-e "temp_reg_export.reg"){ 
    974         system("mv temp_reg_export.reg temp_reg_export.reg.CBL"); 
    975     } 
    976     system('regedit.exe /a temp_reg_export.reg "HKEY_LOCAL_MACHINE\HARDWARE\TEST"'); 
    977  
    978     system("regedit.exe /s noTEST.reg"); 
    979     system("regedit.exe /s /c $test_dir/t" . "$num" . "a.reg"); 
    980     $ob->initRegistry("HKEY_LOCAL_MACHINE\\HARDWARE"); 
    981     system("regedit.exe /s noTEST.reg"); 
    982     system("regedit.exe /s /c $test_dir/t" . "$num" . "b.reg"); 
    983     $ob->checkRegistry("HKEY_LOCAL_MACHINE\\HARDWARE"); 
    984     open (DIFF, "diff $test_dir/t" . "$num" . "changes.txt changes.txt |") or die "Can't check the changes files\n"; 
    985     @result = <DIFF>; 
    986     close DIFF; 
    987     #Bad test because it will be empty in the case of an error anyway? 
    988     is(scalar(@result), 0, "$string"); 
    989  
    990     #for safety/cleanup 
    991     if(-e "temp_reg_export.reg"){ 
    992         system("regedit.exe /s noTEST.reg"); 
    993         system("regedit.exe /s /c temp_reg_export.reg"); 
    994         system("rm temp_reg_export.reg"); 
    995         if(-e "temp_reg_export.reg.CBL"){ 
    996             system("mv temp_reg_export.reg.CBL temp_reg_export.reg"); 
    997         } 
    998     } 
    999      
    1000 
    1001  
    1002 =end testing 
    1003  
    1004 =cut 
    1005  
    1006 sub checkRegistry { 
    1007 my $self = shift; 
    1008  
    1009         #************************* 
    1010         #XXXY: delete me eventually 
    1011         #if(-f "$self->{change_file}") {system("rm $self->{change_file}");} 
    1012         #************************* 
    1013  
    1014  
    1015 #$var is used to create different files for different registry exports 
    1016 my $var = 0; 
    1017 #This foreach is what allows it to check multiple keys in the registry 
    1018 foreach my $key_to_check (@{$self->{reg_check_array}}){  
    1019  
    1020     #First we want @reg1 to hold the clean registry state 
    1021     print "reading in existing state for $key_to_check\n"; 
    1022     open REG, "$self->{clean_reg}$var"  or die "Cannot open $self->{clean_reg}$var: $!\n"; 
    1023     @{$self->{reg1}} = <REG>; 
    1024     close REG; 
    1025  
    1026     #Then we want @reg2 to hold the current registry state 
    1027     print "getting current state for $key_to_check\n"; 
    1028     system("regedit /a \"$self->{current_reg}$var\" \"$key_to_check\""); #More useful for debugging 
    1029     open REG2, "$self->{current_reg}$var" or die "Cannot open $self->{current_reg}$var: $!\n"; 
    1030 #   open REG2, "regedit /a \"$self->{current_reg}$var\" \"$key_to_check\" |"  or die "Problem with combo speed hack: $!\n"; #future speed hack 
    1031     @{$self->{reg2}} = <REG2>; 
    1032     close REG2; 
    1033  
    1034  
    1035  
    1036     print "diffing\n"; 
    1037     #Code to split the entries into chunks in a multi-dimensional array 
    1038     #This list is what everything else uses to differentiate different diffs ;) 
    1039     system("diff -a $self->{clean_reg}$var $self->{current_reg}$var > $self->{diffs}$var"); #More useful for debugging 
    1040     open DIFZ, "$self->{diffs}$var" or die "Cannot open $self->{diffs}$var: $!\n"; 
    1041 #   open DIFZ, "diff -a $self->{clean_reg}$var $self->{current_reg}$var |" or die "Problem with combo speed hack: $!\n"; #future speed hack 
    1042     my $inner_count=0; #inner index for the multi-dimensional array for holding diff entries 
    1043     @{$self->{changes}} = (); 
    1044     while(<DIFZ>){ 
    1045         #get rid of the nulls embedded by the export 
    1046         #NOTE: This will need to change when dealing with the  
    1047         # inaccessible special NULL registry key name case 
    1048         $_ =~ s/\0//g; 
    1049 #       print $_; 
    1050         #if the line starts with numbers then it's a new diff entry 
    1051         if($_ =~ /^[0-9]/){ 
    1052             $inner_count = 0; 
    1053             $self->{g_count}++; 
    1054             $self->{changes}->[$self->{g_count}][$inner_count] = $_; 
    1055         } 
    1056         else{ 
    1057             #otherwise it's just an entry in our current diff 
    1058             $inner_count++; 
    1059             $self->{changes}->[$self->{g_count}][$inner_count] = $_; 
    1060         } 
    1061     } 
    1062     close DIFZ; 
    1063     #Print the total number of individual diffs which will need to be parsed 
    1064     #NOTE: because "change" entries can include multiple events, this is an  
    1065     # underestimate of how many actual changes there will be 
    1066     #ALSO NOTE: The prefix ++ on the count. That's just an array index vs number 
    1067     # of elements off by one thing to make it print right. 
    1068     print ++$self->{g_count} . " diff blocks put into the changes list for parsing\n"; 
    1069     $self->{g_count}--; 
    1070  
    1071     #This while loop steps through each of the individual diffs in the multi-dimensional 
    1072     # list, parsing one at a time. 
    1073     while($self->{g_count} >= 0){ 
    1074         my $holder = $self->{changes}->[$self->{g_count}][0]; 
    1075     #   print $holder; 
    1076         my $first_start = 0; 
    1077         my $first_end = 0; 
    1078         my $second_start = 0; 
    1079         my $second_end = 0; 
    1080      
    1081         #XXX: NESTED SWITCHES CAUSE STRANGE PROBLEMS. Try to use the least nested switches as possible 
    1082         #$holder is always the first line of a diff, which is the line that contains the 
    1083         # line numbers for where in the two files the adds/deletes/changes are being made. 
    1084         #First it splits them into cases and subcases based on whether it's a an add, delete, or the 
    1085         # much more complicated change. 
    1086         switch($holder){ 
    1087             case /a/ { 
    1088      
    1089                 ############################################ 
    1090                 #Case of multi-line addition. 
    1091                 ############################################ 
    1092                  
    1093                 #TEST 1 
    1094                 if($holder =~ /([0-9]+)a([0-9]+),([0-9]+)/) { 
    1095                     $first_start = $1; 
    1096                     $second_start = $2; 
    1097                     $second_end = $3; 
    1098                     my $quick_count = $3-$2+1; 
    1099                     #We need an extra \ in the 2nd regex when used in a string 
    1100                     #The regexes tell it to only look at lines that start with 
    1101                     # the > because those are the lines represending added stuff 
    1102                     #Use parser because a multi-line addition can inlcude the addition 
    1103                     # of keys, not just name/data pairs. 
    1104                     _parser($self, "a", "(^> )(.*)", "^> \\[", $quick_count, $first_start, 1, undef); 
    1105                 } 
    1106                 else{ ############################################ 
    1107                     #Case of single name/data pair addition 
    1108                     ############################################ 
    1109                                  
    1110                     #TEST 2 
    1111                     if($holder =~ /([0-9]+)a([0-9]+)/) { 
    1112                         #In this case, there can not be any new keys because that would take 
    1113                         # at least 2 lines because diff inlcudes the blank line. But that does 
    1114                         # mean we have to go to the original file to find the name of the  
    1115                         # existing key. 
    1116                         _moonwalk_and_print($self, $first_start, "(^> )(.*)", "New values for existing key\n", 2, ($self->{changes}->[$self->{g_count}][1])); 
    1117                     } 
    1118                     else {print "WARNING: some strange case in add\n";} 
    1119                  
    1120                 }    
    1121             } 
    1122      
    1123                      
    1124             case /d/ { 
    1125                 ############################################ 
    1126                 #Case of multi-line deletion. 
    1127                 ############################################ 
    1128                              
    1129                 #TEST 3 
    1130                 if($holder =~ /([0-9]+),([0-9]+)d([0-9]+)/) { 
    1131                     $first_start = $1; 
    1132                     $first_end = $2; 
    1133                     $second_start = $3; 
    1134                     my $quick_count = $2-$1+1; 
    1135                     #need an extra \ in the 2nd regex when used in a string 
    1136                     #The regexes tell it to only look at lines that start with 
    1137                     # the < because those are the lines represending deleted stuff 
    1138                     #Use parser because a multi-line addition can inlcude the deletion 
    1139                     # of keys, not just name/data pairs. 
    1140                     _parser($self, "d", "(^< )(.*)", "^< \\[", $quick_count, $first_start, 1, undef); 
    1141      
    1142                 } 
    1143                 else {  ############################################ 
    1144                     #Case of single name/data pair deletion 
    1145                     ############################################ 
    1146                                  
    1147                     #TEST 4 
    1148                     if($holder =~ /([0-9]+)d([0-9]+)/) { 
    1149                         #We know that this can only be a name/data pair that was deleted because 
    1150                         # a deletion of a key takes at least 2 lines because diff includes the  
    1151                         # blank line separating it from the other keys 
    1152                         _moonwalk_and_print($self, $first_start, "(^< )(.*)", "Deletion of name/data from existing key\n", 1,($self->{changes}->[$self->{g_count}][1])); 
    1153                     } 
    1154                     else {print "WARNING: some strange case in delete\n";} 
    1155                 } 
    1156             } 
    1157              
    1158             case /c/ { 
    1159      
    1160                 #Note about the change case: 
    1161                 #First of all as mentioned elsewhere "change" diffs can (and do) include multiple 
    1162                 # actions into a single grouping of change instructions. If this was simply parsed  
    1163                 # and dealt with without going to either of the diffed files, this can easily 
    1164                 # be exploited to hide some registry entries (it would still show an entry, but 
    1165                 # for every entry added there can be an additional hidden one). Therefore as a 
    1166                 # tradeoff, generally I always check the *last* entry from both the top and  
    1167                 # bottom section (except where it can be proven to be a simple change) against. 
    1168                 # the first and second file respectively. While I have not found cases that  
    1169                 # necessitate this for every change subcase, it is currently done for safety 
    1170                 # and simplicity because it can be done by reusing the _top_half and _bottom_half 
    1171                 # code. 
    1172      
    1173                 switch($holder){ 
    1174                     #the cases have to be in this order ;) 
    1175                     case /([0-9]+),([0-9]+)c([0-9]+),([0-9]+)/ { 
    1176                         #XXX: BUG!!! need to do again (cause of nested switches?) 
    1177                         $holder =~ /([0-9]+),([0-9]+)c([0-9]+),([0-9]+)/; 
    1178                         $first_start = $1; 
    1179                         $first_end = $2; 
    1180                         $second_start = $3; 
    1181                         $second_end = $4; 
    1182      
    1183     #                   print "1234 = $1:$2:$3:$4\n"; 
    1184      
    1185                         ##first check to make sure there are no keys 
    1186                         my @full_diff = @{$self->{changes}->[$self->{g_count}]}; 
    1187                         my $simple = 1; 
    1188                         my @before; 
    1189                         my @after; 
    1190                         foreach (@full_diff){ 
    1191                             if(/^[<>] \[/){$simple = 0;} 
    1192                             if(/^< .*/){ 
    1193                                 push @before, $_; 
    1194                             } 
    1195                             if(/^> .*/){ 
    1196                                 push @after, $_; 
    1197                             } 
    1198                         } 
    1199      
    1200                         #TEST 5 
    1201                         ############################## 
    1202                         # simple multi-line to multi-line change 
    1203                         ############################## 
    1204                         if($simple){ 
    1205                             #case where it's only multi-line changes 
    1206                             my @fake_array = ("> Old Value:", @before, "> New Value:", @after); 
    1207                             _moonwalk_and_print($self, $first_start, "(^[<>] )(.*)", "Changed: \n", 1, @fake_array); 
    1208                         } 
    1209                         else{ 
    1210                             #TEST 6 
    1211                             ############################## 
    1212                             # the most complicated (multi-line to multi-line) changes ;) 
    1213                             ############################## 
    1214  
    1215                             #Haven't been able to recreate this case naturally... punting. 
    1216                             print("If you got here, please save the $self->{clean_reg}$var and $self->{current_reg}$var and send them to us\n"); 
    1217                             exit(); 
    1218      
    1219                             #parses the output of the diff before and after the "---"  
    1220                             # divider independently 
    1221                             _top_half($self,$first_start, $first_end, @before); 
    1222                             _bottom_half($self, $second_start, $second_end, @after); 
    1223                         } 
    1224                          
    1225                          
    1226                     } 
    1227                     case /([0-9]+),([0-9]+)c([0-9]+)/ {&nbs