Changeset 123
- Timestamp:
- 12/17/06 15:39:43 (4 years ago)
- Files:
-
- honeyclient/branches/bug/42/bin/StartAgent.pl (modified) (1 diff)
- honeyclient/branches/bug/42/bin/TestRegistry.pl (modified) (2 diffs)
- honeyclient/branches/bug/42/etc/file_checklist.txt (added)
- honeyclient/branches/bug/42/etc/honeyclient.xml (modified) (3 diffs)
- honeyclient/branches/bug/42/lib/HoneyClient/Agent.pm (modified) (3 diffs)
- honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity.pm (modified) (24 diffs)
- honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry.pm (modified) (7 diffs)
- honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Parser.pm (modified) (4 diffs)
- honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Parser.yp (modified) (4 diffs)
- honeyclient/branches/bug/42/t/honeyclient_agent_integrity.t (modified) (3 diffs)
- honeyclient/branches/bug/42/t/honeyclient_agent_integrity_registry.t (modified) (1 diff)
- honeyclient/branches/bug/42/t/honeyclient_agent_integrity_registry_parser.t (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
honeyclient/branches/bug/42/bin/StartAgent.pl
r122 r123 37 37 print "Watchdog fault detected, recovering Agent daemon.\n"; 38 38 # 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; 40 40 41 41 honeyclient/branches/bug/42/bin/TestRegistry.pl
r122 r123 29 29 my $registry = HoneyClient::Agent::Integrity::Registry->new(); 30 30 31 print "\n"; 31 32 print "Baseline check complete. Perform normal allowable actions\n" . 32 33 "on the system (i.e., browse benign web pages).\n\n" . … … 57 58 $Data::Dumper::Indent = 1; 58 59 print $fh Dumper($changes); 59 print "\nDone!\n"; 60 print "\n"; 61 print "Done!\n"; 60 62 print "Detailed registry changes were written to: " . $file . "\n"; 61 63 } honeyclient/branches/bug/42/etc/honeyclient.xml
r119 r123 49 49 <!-- 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. --> 50 50 <timeout description="Default timeout used for all communications between each module (in seconds)." default="900"> 51 90051 1800 52 52 </timeout> 53 53 <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"> … … 121 121 <!-- Files which are read in only. --> 122 122 <!-- 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.txt123 <file_checklist description="The file containing the list of files and directories to check during filesystem checking." default="none"> 124 etc/file_checklist.txt 125 125 </file_checklist> 126 126 <!-- 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"> 128 128 ../../../etc/file_exclude.txt 129 129 </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.txt133 </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.txt137 </reg_list_to_check>138 130 <!-- Files which are written out only. --> 139 131 <!-- TODO: Update this. --> … … 146 138 </change_file> 147 139 <!-- 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.reg151 </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.reg155 </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.out159 </diffs>160 140 <!-- TODO: Update this. --> 161 141 <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 210 210 # TODO: Update unit tests to include 'dclone' 211 211 use Storable qw(nfreeze thaw dclone); 212 $Storable::Deparse = 1; 213 $Storable::Eval = 1; 212 214 213 215 # Include Base64 Libraries … … 366 368 367 369 # Perform initial integrity baseline check. 368 my $integrity = undef;369 if ($PERFORM_INTEGRITY_CHECKS) {370 print "Initializing Integrity Check...\n";371 # TODO: Initialize Integrity Checks372 $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(); 376 378 377 379 # Release data lock. … … 721 723 # As such, do NOT try to call integrity checks on multiple, simultaneous 722 724 # 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"; 724 736 } 725 737 honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity.pm
r96 r123 104 104 can_ok('HoneyClient::Agent::Integrity', 'initFileSystem'); 105 105 can_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); 106 use HoneyClient::Agent::Integrity qw(initAll checkAll initFileSystem checkFileSystem); 109 107 110 108 # Make sure HoneyClient::Util::Config loads. … … 133 131 134 132 # 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."); }133 BEGIN { 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."); } 136 134 require_ok('Storable'); 137 135 can_ok('Storable', 'dclone'); 138 use Storable qw(dclone); 136 can_ok('Storable', 'nfreeze'); 137 can_ok('Storable', 'thaw'); 138 use Storable qw(dclone nfreeze thaw); 139 139 140 140 ###Testing Globals### … … 158 158 # Include Global Configuration Processing Library 159 159 use HoneyClient::Util::Config qw(getVar); 160 use HoneyClient::Agent::Integrity::Registry; 160 161 use File::Find qw(find); 161 162 #use Win32::TieRegistry; 162 163 use Digest::MD5; 163 164 use MIME::Base64; 164 use Switch; 165 use Storable qw(dclone); 165 use Storable qw(nfreeze thaw dclone); 166 $Storable::Deparse = 1; 167 $Storable::Eval = 1; 166 168 use Data::Dumper; 167 169 use File::Basename qw(dirname); … … 178 180 179 181 # Symbols to export on request 180 @EXPORT = qw(new initAll checkAll initRegistry checkRegistry initFileSystem checkFileSystem);182 @EXPORT = qw(new initAll checkAll); 181 183 182 184 # Items to export into callers namespace by default. Note: do not export … … 208 210 #Used *for now* to signal whether any changes occured (if they == 1) 209 211 my $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 object213 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 escaped217 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 );264 212 265 213 # XXX: All dirs must NEVER end in a trailing slash. … … 290 238 '/cygdrive/c/Program Files/Mozilla Firefox/updates.xml', 291 239 '/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', 292 248 ); 293 249 … … 295 251 my %PARAMS = ( 296 252 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"), 300 260 301 261 # List of files or directories to exclude if found in subdirs during 302 262 # 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"), 310 264 311 265 ### Files to write and read ### 312 266 # 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"), 314 268 315 269 # 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"), 317 271 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 320 275 321 # Stores the current state of the registry to check against the322 # clean state323 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 #vars330 file_exclude_hash => undef, #hash, holds files to exclude331 file_list => undef, #list, files to check when checking filesystem332 reg1 => undef, #list, holds entire contents of first file to diff333 reg2 => undef, #list, holds entire contents of second file to diff334 335 #array that holds the locations in the registry to check336 reg_check_array => undef,337 #array that holds the registry locations that should be excluded from the detected changes338 reg_exclude_array => undef,339 340 276 #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 345 280 ); 346 281 … … 409 344 410 345 sub initAll { 411 my $self = shift;346 my $self = shift; 412 347 # XXX: initRegistry() MUST be called before initFileSystem, since initRegistry 413 348 # creates new files that must exist to be added to the exclusion list for 414 349 # initFileSystem. 415 $self-> initRegistry();350 $self->{'_registry'} = HoneyClient::Agent::Integrity::Registry->new(); 416 351 $self->initFileSystem(); 417 352 } … … 428 363 429 364 sub 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 436 368 # If at all possible we want the (faster) registry checks to short circut 437 369 # 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(); 444 385 445 386 return $retval; 446 447 448 } 387 } 388 389 # TODO: Comment this. 390 sub serialize { 391 my $self = shift; 392 393 if (defined($self->{'_registry'})) { 394 $self->{'_registry'}->closeFiles(); 395 } 396 397 return nfreeze($self); 398 } 399 449 400 ################################################################################ 450 401 … … 513 464 $g_hack = $self->{file_list}; 514 465 $g_ex_hash = (); 466 my $file; 515 467 516 468 my @checkdirs = $self->_get_directories_to_check(); … … 528 480 } 529 481 530 foreach my $file (@{$self->{file_exclude_array}}){ 482 $/ = "\n"; 483 foreach $file (@{$self->{file_exclude_array}}){ 531 484 chomp $file; 532 485 if(-f $file){ … … 547 500 548 501 print "Finding Files in initFileSystem...Be Patient.\n"; 549 foreach my $checkdir (@checkdirs) {502 foreach my $checkdir (@checkdirs) { 550 503 find (\&_found, "$checkdir"); #this will populate @{$self->{file_list}} 551 504 } … … 553 506 $self->{file_list} = $g_hack; 554 507 $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"; 556 509 557 510 print "Hashing Files in initFileSystem...Be Patient\n"; 558 511 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}}) { 560 513 # print "hashing $file\n"; 561 514 if(open HASHFILE, "$file") { … … 638 591 sub checkFileSystem { 639 592 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; 648 603 649 604 ### print "file_exclude_hash in check\n" . Dumper($self->{file_exclude_hash}) . "\n"; … … 655 610 #open file to create hash of values for clean files 656 611 open CLEANFILE, "$self->{clean_file}" or die "Cannot open $self->{clean_file}: $!\n"; 612 $/ = "\n"; 657 613 while(<CLEANFILE>) { 658 614 my $line = $_; … … 691 647 } 692 648 693 foreach my $file (@{$self->{file_exclude_array}}){ 649 $/ = "\n"; 650 foreach $file (@{$self->{file_exclude_array}}){ 694 651 chomp $file; 695 652 if(-f $file){ … … 721 678 #also detects new files 722 679 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") { 725 682 my $md5ctx = Digest::MD5->new(); 726 683 # If this call fails, an exception will be generated. … … 739 696 740 697 #check for deleted files 741 foreach my$key (keys %{$self->{clean_file_hash}}) {698 foreach $key (keys %{$self->{clean_file_hash}}) { 742 699 if(!($current_file_hash{$key})) { 743 700 $del_file_hash{$key} = $self->{clean_file_hash}->{$key}; … … 751 708 752 709 print CHANGES "Files deleted:\n"; 753 foreach my$key (sort keys %del_file_hash) {710 foreach $key (sort keys %del_file_hash) { 754 711 print CHANGES "$key\n"; 755 712 } 756 713 print CHANGES "\n\n"; 757 714 print CHANGES "Files added:\n"; 758 foreach my$key (sort keys %new_file_hash) {715 foreach $key (sort keys %new_file_hash) { 759 716 print CHANGES "$key\n"; 760 717 } 761 718 print CHANGES "\n\n"; 762 719 print CHANGES "Files modified:\n"; 763 foreach my$key (sort keys %{$self->{changed_file_hash}}) {720 foreach $key (sort keys %{$self->{changed_file_hash}}) { 764 721 print CHANGES "$key\n"; 765 722 } … … 784 741 785 742 #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/"; 787 744 788 745 #Can override the default by creating this file (for now, eventually put directly into XML) … … 793 750 "Please see the POD documentation for more information.\n"; 794 751 @checkdirs = (); 752 $/ = "\n"; 795 753 while(<CHECK>) { 796 754 chomp; … … 814 772 815 773 my $foundfile = $File::Find::name; 774 816 775 if (-f $foundfile) { 817 776 if (exists($g_ex_hash->{$foundfile})) { … … 845 804 sub _recursive_exclude{ 846 805 847 my $foundfile = $File::Find::name;806 my $foundfile = $File::Find::name; 848 807 if (-f $foundfile) { 849 808 $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]+)/ { 1228 #XXX: BUG!!! need to do again (cause of nested switches?) 1229 $holder =~ /([0-9]+),([0-9]+)c([0-9]+)/; 1230 $first_start = $1; 1231 $first_end = $2; 1232 $second_start = $3; 1233 my $quick_count = $2-$1+1; 1234 1235 # print "123 = $1:$2:$3\n"; 1236 1237 #first check to see if it is the trivial case of 1238 # ONLY changing name/data pairs (i.e. should not 1239 # find any keys (i.e. lines starting with "> [" 1240 # or "< [") 1241 my @full_diff = @{$self->{changes}->[$self->{g_count}]}; 1242 my $simple = 1; 1243 my @before; 1244 my @after; 1245 foreach (@full_diff){ 1246 if(/^[<>] \[/){$simple = 0;} 1247 if(/^< .*/){ 1248 push @before, $_; 1249 } 1250 if(/^> .*/){ 1251 push @after, $_; 1252 } 1253 } 1254 1255 #TEST 7 1256 ############################## 1257 # simple multi-line to single-line change 1258 ############################## 1259 if($simple){ 1260 #case where it's only multi-line changes 1261 my @fake_array = ("> Old Value:", @before, "> New Value:", @after); 1262 _moonwalk_and_print($self, $first_start, "(^[<>] )(.*)", "Changed: \n", 1, @fake_array); 1263 } 1264 1265 else{ 1266 #TEST 8 1267 ############################## 1268 # complicated multi-line to single-line change 1269 ############################## 1270 _top_half($self, $first_start, $first_end, @before); 1271 _bottom_half($self, $second_start, $second_start, @after); 1272 1273 } 1274 1275 1276 } 1277 case /([0-9]+)c([0-9]+),([0-9]+)/ { 1278 #XXX: BUG!!! need to do again (cause of nested switches?) 1279 $holder =~ /([0-9]+)c([0-9]+),([0-9]+)/; 1280 $first_start = $1; 1281 $second_start = $2; 1282 $second_end = $3; 1283 1284 my $quick_count = $3-$2+3; 1285 1286 # print "123 = $1:$2:$3\n"; 1287 1288 ##first check to make sure there are no keys 1289 my @full_diff = @{$self->{changes}->[$self->{g_count}]}; 1290 my $simple = 1; 1291 my @before; 1292 my @after; 1293 foreach (@full_diff){ 1294 if(/^[<>] \[/){$simple = 0;} 1295 if(/^< .*/){ 1296 push @before, $_; 1297 } 1298 if(/^> .*/){ 1299 push @after, $_; 1300 } 1301 } 1302 1303 #TEST 9 1304 ############################## 1305 # simple single-line to multi-line change 1306 ############################## 1307 if($simple){ 1308 my @fake_array = ("> Old Value:", @before,"> New Value:", @after); 1309 _moonwalk_and_print($self, $first_start, "(^[<>] )(.*)", "Changed: \n", 1, @fake_array); 1310 } 1311 1312 1313 else{ 1314 #TEST 10 1315 ############################## 1316 # complicated single-line to multi-line change 1317 ############################## 1318 _top_half($self, $first_start, $first_start, @before); 1319 _bottom_half($self, $second_start, $second_end, @after); 1320 } 1321 1322 } 1323 case /([0-9]+)c([0-9]+)/ { 1324 #XXX: BUG!!! need to do again (cause of nested switches?) 1325 $holder =~ /([0-9]+)c([0-9]+)/; 1326 $first_start = $1; 1327 $second_start = $2; 1328 1329 my @full_diff = @{$self->{changes}->[$self->{g_count}]}; 1330 my $simple = 1; 1331 my @before; 1332 my @after; 1333 foreach (@full_diff){ 1334 if(/^[<>] \[/){$simple = 0;} 1335 if(/^< .*/){ 1336 push @before, $_; 1337 } 1338 if(/^> .*/){ 1339 push @after, $_; 1340 } 1341 } 1342 1343 #TEST 11 1344 ############################## 1345 # simple single-line to single-line change 1346 ############################## 1347 if($simple){ 1348 my @fake_array = ("> Old Value:", @before,"> New Value:", @after); 1349 _moonwalk_and_print($self, $first_start, "(^[<>] )(.*)", "Changed: \n", 1, @fake_array); 1350 } 1351 else{ 1352 #TEST 12 1353 ############################## 1354 # complicated single-line to single-line change 1355 ############################## 1356 _top_half($self, $first_start, $first_start, @before); 1357 _bottom_half($self, $second_start, $second_start, @after); 1358 } 1359 } 1360 } 1361 } 1362 else { 1363 print "holder = $holder matched none of the cases, serious problem!\n"; 1364 } 1365 }#end switch 1366 1367 $self->{g_count}--; 1368 } #end big while 1369 1370 $var++; 1371 } #end big foreach 1372 return $g_reg_changes; 1373 1374 } #end checkRegistry 1375 ################################################################################ 1376 1377 1378 # A very important function which is responsible for looping through a list which 1379 # is given to it, and treating extra registry keys as adds or deletes with 1380 # possible adds, deletes, or changes as the "leftover" elements which get passed 1381 # to _moonwalk_and_print. Originally this function only operated on a chunk of 1382 # the @{$self->{changes}} array, therefore to maintain compatibility for now, if no array 1383 # is given, it will instead use the @{$self->{changes}} array. 1384 1385 # The general logic is that if it finds something in an array it pushes it into 1386 # a temporary one. At such time as it pushes a line starting with > [ or < [ 1387 # that means that there was a registry key included in the array and therefore 1388 # we know which key the name/data pairs belong to and therefore we won't need 1389 # to consult the disk because we have everything we need to know about that 1390 # event. If there are still things in the temporary array when we finish looping 1391 # through the given/changes array then that is something leftover which we will 1392 # have to consult either the current or clean registry state about, to determine 1393 # which key the name/data pair belongs to. That's _moonwalk_and_print()'s job. 1394 1395 # TODO: Check to make sure the function generates appriopriate exceptions, when failures 1396 # occur. 1397 sub _parser{ 1398 my $self = shift; 1399 my $type = shift; 1400 my $regex = shift; 1401 my $regex2 = shift; 1402 my $quick_count = shift; 1403 my $start_line = shift; 1404 my $offset = shift; 1405 my @custom_array = @_; 1406 my @holding_array; 1407 1408 open CHANGES, ">>$self->{change_file}" or die "Cannot open $self->{change_file} (1): $!\n"; 1409 1410 #start to step (backwards) through the output of the diff 1411 my $tmp; 1412 while($quick_count >= $offset){ 1413 if (defined $custom_array[$quick_count]){ 1414 $tmp = $custom_array[$quick_count]; 1415 } 1416 else{ 1417 $tmp = $self->{changes}->[$self->{g_count}][$quick_count]; 1418 } 1419 1420 #If the line starts with '> [' it's a registry key 1421 #If this case is detected it means it's a new key 1422 # (possibly with name/data pairs, possibly without) and it 1423 # will just dump this to the CHANGES file because 1424 # it doesn't have to consult the original registry 1425 # dump in order to know which key/names/values is added. 1426 if($tmp =~ /$regex2/){ 1427 push @holding_array, $tmp; 1428 @holding_array = reverse (@holding_array); 1429 switch($type){ 1430 case /a/ { 1431 if(scalar(@holding_array) > 1){ 1432 print CHANGES "\nAdded key and name/data: \n" or die "Can't write to changefile!\n"; 1433 } 1434 else { 1435 print CHANGES "\nAdded empty key: \n" or die "Can't write to changefile!\n"; 1436 } 1437 } 1438 case /d/ { 1439 if(scalar(@holding_array) > 1){ 1440 print CHANGES "\nDeleted key and name/data: \n" or die "Can't write to changefile!\n"; 1441 } 1442 else { 1443 print CHANGES "\nDeleted empty key: \n" or die "Can't write to changefile!\n"; 1444 } 1445 } 1446 else{die "Unknown type in _parser() switch\n";} 1447 } 1448 1449 foreach my $line (@holding_array){ 1450 $line =~ /$regex/; 1451 #discard $1 which is formatting from diff 1452 print CHANGES "$2\n" or die "Can't write to changefile!\n"; 1453 } 1454 print CHANGES "\n" or die "Can't write to changefile!\n"; 1455 @holding_array = (); 1456 1457 } 1458 else{ 1459 #Push anything else (except empty line), as it will be included 1460 # in whatever key it was found in 1461 if($tmp !~ /^[<>] \r\n/){ 1462 push @holding_array, $tmp; 1463 } 1464 } 1465 $quick_count--; 1466 } 1467 $g_reg_changes = 1; 1468 close CHANGES or warn "Can't close changefile!\n"; 1469 1470 #Anything left over in @holding_array after that loop 1471 # is a name/data pair which did not have a new key 1472 # being created, and therefore is the modification of 1473 # an existing key. Thus we must consult the original 1474 # file to clean up stragglers if any. 1475 if(scalar(@holding_array) > 0){ 1476 @holding_array = reverse (@holding_array); 1477 my $string; 1478 my $case; 1479 switch($type){ 1480 case "a" { 1481 $string = "Added name/data for existing key\n"; 1482 $case = 2; 1483 } 1484 case "d" { 1485 $string = "Deleted name/data for existing key\n"; 1486 $case = 1; 1487 } 1488 case /c/ { 1489 #$string = "Changed name/data for existing key\n"; 1490 return @holding_array; 1491 $case = 1; 1492 } 1493 else{die "Unknown type in 2nd _parser() switch\n";} 1494 } 1495 1496 _moonwalk_and_print($self, $start_line, $regex, $string, $case, @holding_array); 1497 } 1498 1499 } 1500 ################################################################################ 1501 1502 # Given a line number to start at in $moonwalk, this 1503 # function walks backwards trying to find the enclosing 1504 # registry key, and then prints the results to the 1505 # CHANGES file. 1506 # NOTE that most of this functionality has been passed off to _find_enclosing_key() 1507 # such that this primarily just prints now. It has been left in place for now 1508 # simply to maintain current code. 1509 1510 # TODO: Check to make sure the function generates appriopriate exceptions, when failures 1511 # occur. 1512 sub _moonwalk_and_print { 1513 my $self = shift; #Object 1514 my $start_line = shift; #The line to start walking backwards from 1515 my $regex = shift; #regular expression to use to get rid of diff formatting on lines 1516 my $string = shift; #String to print when 1517 my $case = shift; #Add/delete/change case (1 for delete/change, 2 for add) 1518 my @holding_array = @_; 1519 1520 #walk backwards looking for the registry key 1521 # which contains us. 1522 my $enclosing_key = _find_enclosing_key($self, $start_line, $case); 1523 1524 print "Searching for excludes matching: $enclosing_key\n"; 1525 foreach my $exclude_key (@{$self->{reg_exclude_array}}){ 1526 ### print "trying to match $enclosing_key against exclude key $exclude_key\n"; 1527 if($enclosing_key =~ /$exclude_key/){ 1528 print "SUCCESS! I'm outta here!\n"; 1529 print "Exclude: $exclude_key\n"; 1530 return $start_line; 1531 } 1532 } 1533 1534 open CHANGES, ">>$self->{change_file}" or die "Cannot open $self->{change_file} (2): $!\n"; 1535 print CHANGES "\n$string" or die "Can't write to changefile!\n"; 1536 print CHANGES $enclosing_key or die "Can't write to changefile!\n"; 1537 foreach my $line (@holding_array){ 1538 $line =~ /$regex/; 1539 #discard $1 which is formatting from diff 1540 print CHANGES "$2\n" or die "Can't write to changefile!\n"; 1541 } 1542 $g_reg_changes = 1; 1543 close CHANGES or warn "Error closing changefile!\n"; 1544 #for use by changed case to avoid another walk 1545 return $start_line; 1546 } 1547 ################################################################################ 1548 1549 1550 #This is now what's actually doing the moonwalking due to some code rearrangement ;) 1551 #Steps backwards from the passed in line number in the passed in case 1552 # representing an array (representing a file) you want to use. @{$self->{reg1}} is the first 1553 # file given to the diff (should be the clean file) and @{$self->{reg2}} is therefore the 1554 # second file (the current state). 1555 1556 # TODO: Check to make sure the function generates appriopriate exceptions, when failures 1557 # occur. 1558 sub _find_enclosing_key{ 1559 my $self = shift; #Object 1560 my $start_line = shift; # 1561 my $case = shift; 1562 1563 #This is the delete or change case so it checks the clean registry file (reg1) 1564 # (because a key which is deleted for instance can only be found in the orignal 1565 # not the current) 1566 if($case == 1){ 1567 while($self->{reg1}->[$start_line] !~ /^\[/){ 1568 $start_line--; 1569 } 1570 return $self->{reg1}->[$start_line]; 1571 } 1572 else{ 1573 #This is the add case so it checks the current registry file (reg2) 1574 # (because a key which is deleted for instance can only be found in 1575 #the orignal not the clean) 1576 if($case == 2){ 1577 while($self->{reg2}->[$start_line] !~ /^\[/){ 1578 $start_line--; 1579 } 1580 return $self->{reg2}->[$start_line]; 1581 } 1582 else{ 1583 die "Invalid value for case in _find_enclosing_key\n"; 1584 } 1585 } 1586 } 1587 1588 ################################################################################ 1589 1590 # Because changes can be ambiguous this function (and _bottom_half) were created 1591 # to first deal with the ambigious case and then pass the rest into _parser(). 1592 # Based on the way that diff works and testing, it seems that ambiguous cases 1593 # can only manifest themselves in the last entry in the top half (the stuff 1594 # immediately before the "---" line when reading from top to bottom). Similarly 1595 # it can only manifest in the last entry of the bottom half. Therefore if it is 1596 # deal with in this code, the remainder of the array representing changes in the 1597 # top or bottom half should be safe to parse with _parser(). 1598 1599 sub _top_half{ 1600 my $self = shift; 1601 my $first_start = shift; 1602 my $first_end = shift; 1603 my @before = @_; 1604 my $num_lines = scalar(@before)-1; 1605 my @tmp_array; 1606 my $walk = $first_end; 1607 1608 ############################## 1609 # treat the top half like *deletes* 1610 # BUT first go to file for the last one and check its contents! 1611 ############################## 1612 1613 # print "BEFORE walk = $walk\n"; 1614 #walk backwards to find how many lines from the end to start at 1615 while($num_lines >= 0 && $before[$num_lines] !~ /^< \[/){ 1616 $num_lines--; 1617 } 1618 1619 my $lcount = scalar(@before)-1 - $num_lines; 1620 #walk is where to start walking *forward* in the clean reg file 1621 $walk = $first_end - $lcount; 1622 1623 # print "BEFORE lcount = $lcount, walk = $walk\n"; 1624 1625 while($self->{reg1}->[$walk] !~ /^\[/){ 1626 if($self->{reg1}->[$walk] !~ /^\r\n/){ 1627 # print "pushing $self->{reg1}->[$walk]"; 1628 push @tmp_array, $self->{reg1}->[$walk]; 1629 } 1630 $walk++; 1631 } 1632 1633 open CHANGES, ">>$self->{change_file}" or die "Cannot open $self->{change_file} (3): $!\n"; 1634 if(scalar(@tmp_array) > 0){ 1635 print CHANGES "\nDeleted key and name/data: \n"; 1636 my $enclosing_key = _find_enclosing_key($self, $first_end, 1); 1637 # print "enclosing $enclosing_key"; 1638 print CHANGES $enclosing_key; 1639 foreach (@tmp_array){ 1640 print CHANGES; 1641 print "in da top $_"; 1642 } 1643 } 1644 else{ 1645 print CHANGES "\nDeleted empty key: \n"; 1646 $walk = $first_end - $lcount-1; 1647 print CHANGES "$self->{reg1}->[$walk]\n"; 1648 print "in da top $self->{reg1}->[$walk]\n"; 1649 1650 } 1651 $g_reg_changes = 1; 1652 close CHANGES; 1653 1654 #the +1 is because we want to delete the extra empty line from the array 1655 $lcount++; 1656 1657 # print "before before: @before"; 1658 1659 while($lcount > 0){ 1660 pop @before; 1661 $lcount--; 1662 } 1663 1664 # print "before after: @before"; 1665 1666 ############################## 1667 #now the array is safe to be treated as a normal change+deletion array 1668 ############################### 1669 if(scalar(@before) > 0){ 1670 # print "BEFORE\n @before BEFORE\n"; 1671 _parser($self, "cd", "(^< )(.*)", "^< \\[", scalar(@before)-1, $first_start, 0, @before); 1672 } 1673 1674 } 1675 ################################################################################ 1676 1677 # Because changes can be ambiguous this function (and _top_half) were created 1678 # to first deal with the ambigious case and then pass the rest into _parser(). 1679 # Based on the way that diff works and testing, it seems that ambiguous cases 1680 # can only manifest themselves in the last entry in the top half (the stuff 1681 # immediately before the "---" line when reading from top to bottom). Similarly 1682 # it can only manifest in the last entry of the bottom half. Therefore if it is 1683 # deal with in this code, the remainder of the array representing changes in the 1684 # top or bottom half should be safe to parse with _parser(). 1685 1686 1687 sub _bottom_half{ 1688 my $self = shift; 1689 1690 my $second_start = shift; 1691 my $second_end = shift; 1692 my @after = @_; 1693 my $num_lines = scalar(@after)-1; 1694 my @tmp_array; 1695 my $walk = $second_end; 1696 1697 ############################## 1698 #treat the bottom like *adds* 1699 #BUT first go to file for the last one and check its contents! 1700 ############################## 1701 1702 # print "AFTER walk = $walk\n"; 1703 #walk backwards to find how many lines from the end to start at 1704 while($num_lines >= 0 && $after[$num_lines] !~ /^> \[/){ 1705 $num_lines--; 1706 } 1707 1708 my $lcount = scalar(@after)-1 - $num_lines; 1709 #walk is where to start walking *forward* in the clean reg file 1710 $walk = $second_end - $lcount; 1711 1712 1713 # print "AFTER lcount = $lcount, walk = $walk\n"; 1714 1715 while($self->{reg2}->[$walk] !~ /^\[/){ 1716 1717 if($self->{reg2}->[$walk] !~ /^\r\n/){ 1718 # print "AFTER pushing $self->{reg2}->[$walk]"; 1719 push @tmp_array, $self->{reg2}->[$walk]; 1720 } 1721 $walk++; 1722 } 1723 1724 open CHANGES, ">>$self->{change_file}" or die "Cannot open $self->{change_file} (4): $!\n"; 1725 if(scalar(@tmp_array) > 0){ 1726 1727 print CHANGES "\nAdded key and name/data: \n"; 1728 my $enclosing_key = _find_enclosing_key($self, $second_end, 2); 1729 # print "AFTER enclosing $enclosing_key"; 1730 print CHANGES $enclosing_key; 1731 foreach (@tmp_array){ 1732 print CHANGES; 1733 # print "in da bottom $_"; 1734 } 1735 } 1736 else{ 1737 print CHANGES "\nAdded empty key: \n"; 1738 $walk = $second_end - $lcount-1; 1739 print CHANGES "$self->{reg2}->[$walk]\n"; 1740 # print "in da bottom $self->{reg2}->[$walk]\n"; 1741 1742 } 1743 $g_reg_changes = 1; 1744 close CHANGES; 1745 1746 #the +1 is because we want to delete the extra empty line from the array 1747 $lcount++; 1748 1749 # print "after before: @after\n"; 1750 1751 while($lcount > 0){ 1752 pop @after; 1753 $lcount--; 1754 } 1755 1756 # print "after after: @after"; 1757 1758 ############################## 1759 #now the array is safe to be treated as a normal change+addition array 1760 ############################### 1761 if(scalar(@after) > 0){ 1762 # print "AFTER\n @after AFTER\n"; 1763 _parser($self, "ca", "(^> )(.*)", "^> \\[", scalar(@after)-1, $second_start, 0, @after); 1764 } 1765 1766 } 1767 1768 1769 1770 1771 ################################################################################ 1772 1773 =pod 1774 1775 =head1 1776 1777 startCheckProcesses() : Currently just a placeholder incase we put Thanh's 1778 real-time checking here. 1779 1780 =cut 1781 1782 #Holder incase we put Thanh's stuff in here 1783 sub startCheckProcesses { 1784 return; 809 ## print "\t _recursive_exclude()d $foundfile\n"; 810 } 1785 811 } 1786 812 … … 1845 871 # we can simply leave the garbage collection up to Perl's internal 1846 872 # mechanism. 1847 sub DESTROY {1848 }873 #sub DESTROY { 874 #} 1849 875 ################################################################################ 1850 876 honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry.pm
r122 r123 376 376 '^HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Internet Explorer\\\TypedURLs$', 377 377 '^HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MenuOrder\\\Favorites\\\Links.*$', 378 '^HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MenuOrder\\\Start Menu2\\\Programs.*$', 378 379 '^HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MountPoints2\\\CPC\\\Volume.*$', 379 380 '^HKEY_CURRENT_USER\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\UserAssist\\\.+\\\Count.*$', … … 401 402 '^HKEY_USERS\\\.+\\\Software\\\Microsoft\\\Windows\\\ShellNoRoam\\\BagMRU.*$', 402 403 '^HKEY_USERS\\\.+\\\UNICODE Program Groups.*$', 404 '^HKEY_USERS\\\S.+\\\SessionInformation$', 403 405 '^HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Internet Explorer\\\Main$', 404 406 '^HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Internet Explorer\\\Security\\\AntiPhishing.*$', 405 407 '^HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Internet Explorer\\\TypedURLs$', 406 408 '^HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MenuOrder\\\Favorites\\\Links.*$', 409 '^HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MenuOrder\\\Start Menu2\\\Programs.*$', 407 410 '^HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Explorer\\\MountPoints2\\\CPC\\\Volume.*$', 408 411 '^HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\CurrentVersion\\\Ext\\\Stats\\\.+\\\iexplore.*$', … … 411 414 '^HKEY_USERS\\\S.+\\\Software\\\Microsoft\\\Windows\\\ShellNoRoam\\\MUICache.*$', 412 415 ], 413 414 416 415 417 # When set to 1, the object will forgo any type of initial baselining … … 473 475 $LOG->debug("Deleting baseline of hive '" . $hive . "' in '" . 474 476 $fname . "'."); 475 if (!unlink 0($parser->getFileHandle(),$fname)) {477 if (!unlink($fname)) { 476 478 $LOG->fatal("Error: Unable to unlink '" . $hive . "' hive data in '" . $fname ."'."); 477 479 Carp::croak("Error: Unable to unlink '" . $hive . "' hive data in '" . $fname ."'."); … … 485 487 $LOG->debug("Deleting checkpoint of hive '" . $hive . "' in '" . 486 488 $fname . "'."); 487 if (!unlink 0($parser->getFileHandle(),$fname)) {489 if (!unlink($fname)) { 488 490 $LOG->fatal("Error: Unable to unlink '" . $hive . "' hive data in '" . $fname ."'."); 489 491 Carp::croak("Error: Unable to unlink '" . $hive . "' hive data in '" . $fname ."'."); … … 525 527 _cleanup($fname_tmp); 526 528 527 $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $fname, 528 index_groups => 1); 529 $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $fname, 530 index_groups => 1, 531 show_progress => 0); 529 532 530 533 $parser_collection->{$hive} = $parser; … … 1546 1549 } 1547 1550 1551 =pod 1552 1553 =head2 $object->closeFiles() 1554 1555 =over 4 1556 1557 Closes any temporary files that have been created by the 1558 Registry B<$object>. By performing this operation, the 1559 Registry B<$object> can become serializable. 1560 1561 =back 1562 1563 =begin testing 1564 1565 # Perform Registry baseline on HKEY_CURRENT_CONFIG. 1566 diag("Performing baseline check of 'HKEY_CURRENT_CONFIG' hive; this may take some time..."); 1567 my $registry = HoneyClient::Agent::Integrity::Registry->new(hives_to_check => [ 'HKEY_CURRENT_CONFIG' ]); 1568 $registry->closeFiles(); 1569 my @files_created = $registry->getFilesCreated(); 1570 use Data::Dumper; 1571 my $tmpfile = tmpnam(); 1572 unlink($tmpfile); 1573 my $tmpdir = dirname($tmpfile); 1574 foreach my $file (@files_created) { 1575 like($file, qr/$tmpdir/, "closeFiles()") or diag("The closeFiles() call failed."); 1576 } 1577 1578 =end testing 1579 1580 =cut 1581 1582 sub closeFiles { 1583 # Extract arguments. 1584 my ($self, %args) = @_; 1585 1586 # Log resolved arguments. 1587 # Make Dumper format more terse. 1588 $Data::Dumper::Terse = 1; 1589 $Data::Dumper::Indent = 0; 1590 $LOG->debug(Dumper(\%args)); 1591 1592 # Close any temporary files created. 1593 my $parser = undef; 1594 foreach my $hive (@{$self->{hives_to_check}}) { 1595 $parser = $self->{_baseline_parsers}->{$hive}; 1596 if (defined($parser)) { 1597 $parser->closeFileHandle(); 1598 } 1599 $parser = $self->{_checkpoint_parsers}->{$hive}; 1600 if (defined($parser)) { 1601 $parser->closeFileHandle(); 1602 } 1603 } 1604 } 1605 1548 1606 1; 1549 1607 honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Parser.pm
r119 r123 597 597 $LOG->debug("Resetting parser."); 598 598 599 my $fh = $self->YYData->{'file_handle'}; 599 $self->YYData->{'file_handle'} = undef; 600 601 my $fh = new IO::File($self->YYData->{'filename'}, "r"); 602 if (!defined($fh)) { 603 $LOG->fatal("Error: Unable to read file '" . $self->YYData->{'filename'} . "'!"); 604 Carp::croak("Error: Unable to read file '" . $self->YYData->{'filename'} . "'!"); 605 } 606 607 $self->YYData->{'file_handle'} = $fh; 600 608 601 609 # Check the offset. … … 806 814 } 807 815 816 # Save the file name. 817 $parser->YYData->{'filename'} = $args{'input_file'}; 818 808 819 # Save the file handle. 809 820 $parser->YYData->{'file_handle'} = $fh; … … 1012 1023 $LOG->debug(Dumper(\%args)); 1013 1024 1025 # Reopen the file_handle, if it's been closed. 1026 if (!defined($self->YYData->{'file_handle'})) { 1027 $self->_reset(); 1028 } 1029 1014 1030 if ($self->YYData->{'input_pos'} == 0) { 1015 1031 $LOG->debug("Beginning parse of input stream."); … … 1162 1178 1163 1179 return $self->YYData->{'file_handle'}; 1180 } 1181 1182 =pod 1183 1184 =head2 $object->getFilename() 1185 1186 =over 4 1187 1188 Returns the file name associated with the current Parser B<$object>. 1189 1190 I<Output>: Returns the file name in use. 1191 1192 =back 1193 1194 =begin testing 1195 1196 my ($filename); 1197 my $test_registry_file = $ENV{PWD} . "/" . getVar(name => "registry_file", 1198 namespace => "HoneyClient::Agent::Integrity::Registry::Parser::Test"); 1199 1200 # Create a generic Parser object, with test state data. 1201 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 1202 1203 $filename = $parser->getFilename(); 1204 1205 is($filename, $test_registry_file, "getFilename()") or diag("The getFilename() call failed."); 1206 1207 =end testing 1208 1209 =cut 1210 1211 sub getFilename { 1212 # Extract arguments. 1213 my ($self, %args) = @_; 1214 1215 # Log resolved arguments. 1216 # Make Dumper format more terse. 1217 $Data::Dumper::Terse = 1; 1218 $Data::Dumper::Indent = 0; 1219 $LOG->debug(Dumper(\%args)); 1220 1221 return $self->YYData->{'filename'}; 1222 } 1223 1224 =pod 1225 1226 =head2 $object->closeFileHandle() 1227 1228 =over 4 1229 1230 Closes the file handle associated with the current Parser B<$object>. 1231 1232 =back 1233 1234 =begin testing 1235 1236 my ($handle); 1237 my $test_registry_file = $ENV{PWD} . "/" . getVar(name => "registry_file", 1238 namespace => "HoneyClient::Agent::Integrity::Registry::Parser::Test"); 1239 1240 # Create a generic Parser object, with test state data. 1241 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 1242 $parser->closeFileHandle(); 1243 1244 # Verify Test Group #1 1245 my $nextGroup = $parser->nextGroup(); 1246 my $expectedGroup = { 1247 key => 'HKEY_CURRENT_USER\]Testing Group 1[', 1248 entries => [ { 1249 name => '@', 1250 value => 'Default', 1251 }, { 1252 name => 'Foo', 1253 value => 'Bar', 1254 }, ], 1255 }; 1256 is_deeply($nextGroup, $expectedGroup, "closeFileHandle()") or diag("The closeFileHandle() call failed."); 1257 1258 =end testing 1259 1260 =cut 1261 1262 sub closeFileHandle { 1263 # Extract arguments. 1264 my ($self, %args) = @_; 1265 1266 # Log resolved arguments. 1267 # Make Dumper format more terse. 1268 $Data::Dumper::Terse = 1; 1269 $Data::Dumper::Indent = 0; 1270 $LOG->debug(Dumper(\%args)); 1271 1272 $self->YYData->{'file_handle'} = undef; 1164 1273 } 1165 1274 honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Parser.yp
r119 r123 442 442 $LOG->debug("Resetting parser."); 443 443 444 my $fh = $self->YYData->{'file_handle'}; 444 $self->YYData->{'file_handle'} = undef; 445 446 my $fh = new IO::File($self->YYData->{'filename'}, "r"); 447 if (!defined($fh)) { 448 $LOG->fatal("Error: Unable to read file '" . $self->YYData->{'filename'} . "'!"); 449 Carp::croak("Error: Unable to read file '" . $self->YYData->{'filename'} . "'!"); 450 } 451 452 $self->YYData->{'file_handle'} = $fh; 445 453 446 454 # Check the offset. … … 651 659 } 652 660 661 # Save the file name. 662 $parser->YYData->{'filename'} = $args{'input_file'}; 663 653 664 # Save the file handle. 654 665 $parser->YYData->{'file_handle'} = $fh; … … 857 868 $LOG->debug(Dumper(\%args)); 858 869 870 # Reopen the file_handle, if it's been closed. 871 if (!defined($self->YYData->{'file_handle'})) { 872 $self->_reset(); 873 } 874 859 875 if ($self->YYData->{'input_pos'} == 0) { 860 876 $LOG->debug("Beginning parse of input stream."); … … 1007 1023 1008 1024 return $self->YYData->{'file_handle'}; 1025 } 1026 1027 =pod 1028 1029 =head2 $object->getFilename() 1030 1031 =over 4 1032 1033 Returns the file name associated with the current Parser B<$object>. 1034 1035 I<Output>: Returns the file name in use. 1036 1037 =back 1038 1039 =begin testing 1040 1041 my ($filename); 1042 my $test_registry_file = $ENV{PWD} . "/" . getVar(name => "registry_file", 1043 namespace => "HoneyClient::Agent::Integrity::Registry::Parser::Test"); 1044 1045 # Create a generic Parser object, with test state data. 1046 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 1047 1048 $filename = $parser->getFilename(); 1049 1050 is($filename, $test_registry_file, "getFilename()") or diag("The getFilename() call failed."); 1051 1052 =end testing 1053 1054 =cut 1055 1056 sub getFilename { 1057 # Extract arguments. 1058 my ($self, %args) = @_; 1059 1060 # Log resolved arguments. 1061 # Make Dumper format more terse. 1062 $Data::Dumper::Terse = 1; 1063 $Data::Dumper::Indent = 0; 1064 $LOG->debug(Dumper(\%args)); 1065 1066 return $self->YYData->{'filename'}; 1067 } 1068 1069 =pod 1070 1071 =head2 $object->closeFileHandle() 1072 1073 =over 4 1074 1075 Closes the file handle associated with the current Parser B<$object>. 1076 1077 =back 1078 1079 =begin testing 1080 1081 my ($handle); 1082 my $test_registry_file = $ENV{PWD} . "/" . getVar(name => "registry_file", 1083 namespace => "HoneyClient::Agent::Integrity::Registry::Parser::Test"); 1084 1085 # Create a generic Parser object, with test state data. 1086 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 1087 $parser->closeFileHandle(); 1088 1089 # Verify Test Group #1 1090 my $nextGroup = $parser->nextGroup(); 1091 my $expectedGroup = { 1092 key => 'HKEY_CURRENT_USER\]Testing Group 1[', 1093 entries => [ { 1094 name => '@', 1095 value => 'Default', 1096 }, { 1097 name => 'Foo', 1098 value => 'Bar', 1099 }, ], 1100 }; 1101 is_deeply($nextGroup, $expectedGroup, "closeFileHandle()") or diag("The closeFileHandle() call failed."); 1102 1103 =end testing 1104 1105 =cut 1106 1107 sub closeFileHandle { 1108 # Extract arguments. 1109 my ($self, %args) = @_; 1110 1111 # Log resolved arguments. 1112 # Make Dumper format more terse. 1113 $Data::Dumper::Terse = 1; 1114 $Data::Dumper::Indent = 0; 1115 $LOG->debug(Dumper(\%args)); 1116 1117 $self->YYData->{'file_handle'} = undef; 1009 1118 } 1010 1119 honeyclient/branches/bug/42/t/honeyclient_agent_integrity.t
r96 r123 17 17 can_ok('HoneyClient::Agent::Integrity', 'initFileSystem'); 18 18 can_ok('HoneyClient::Agent::Integrity', 'checkFileSystem'); 19 can_ok('HoneyClient::Agent::Integrity', 'initRegistry'); 20 can_ok('HoneyClient::Agent::Integrity', 'checkRegistry'); 21 use HoneyClient::Agent::Integrity qw(initAll checkAll initRegistry checkRegistry initFileSystem checkFileSystem); 19 use HoneyClient::Agent::Integrity qw(initAll checkAll initFileSystem checkFileSystem); 22 20 23 21 # Make sure HoneyClient::Util::Config loads. … … 46 44 47 45 # Make sure Storable loads. 48 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."); }46 BEGIN { 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."); } 49 47 require_ok('Storable'); 50 48 can_ok('Storable', 'dclone'); 51 use Storable qw(dclone); 49 can_ok('Storable', 'nfreeze'); 50 can_ok('Storable', 'thaw'); 51 use Storable qw(dclone nfreeze thaw); 52 52 53 53 ###Testing Globals### … … 160 160 161 161 162 # =begin testing163 {164 #Testing initRegistry()165 my $ob = HoneyClient::Agent::Integrity->new();166 167 system("regedit.exe /s noTEST.reg");168 system("regedit.exe /s /c $test_dir/t1a.reg");169 $ob->initRegistry("HKEY_LOCAL_MACHINE\\HARDWARE\\TEST");170 open (DIFF, "diff $test_dir/t1a.reg clean.reg0 |") or die "Can't check the changes files\n";171 @result = <DIFF>;172 close DIFF;173 #Bad test because it will be empty in the case of an error anyway?174 is(scalar(@result), 0, 'initRegistry: General Test');175 }176 177 178 179 # =begin testing180 {181 my $ob = HoneyClient::Agent::Integrity->new();182 183 reg_test($ob, 1, "checkRegistry: case 1 Multi-line addition changes.");184 reg_test($ob, 2, "checkRegistry: case 2 Single-line addition changes.");185 reg_test($ob, 3, "checkRegistry: case 3 Multi-line deletion changes.");186 reg_test($ob, 4, "checkRegistry: case 4 Single-line deletion changes.");187 reg_test($ob, 5, "checkRegistry: case 5 Simple multi-line to multi-line changes.");188 is(6, 6, "checkRegistry: case 6 - SKIPPING (currently can't recreate conditions for test)");189 #reg_test($ob, 6, "checkRegistry: case 6 Complicated multi-line to multi-line changes.");190 reg_test($ob, 7, "checkRegistry: case 7 Simple multi-line to single-line changes.");191 reg_test($ob, 8, "checkRegistry: case 8 Complicated multi-line to single-line changes.");192 reg_test($ob, 9, "checkRegistry: case 9 Simple single-line to multi-line changes.");193 reg_test($ob, 10, "checkRegistry: case 10 Complicated single-line to multi-line changes.");194 reg_test($ob, 11, "checkRegistry: case 11 Simple single-line to single-line changes.");195 reg_test($ob, 12, "checkRegistry: case12 Complicated single-line to single-line changes.");196 197 sub reg_test{198 my $ob = shift;199 my $num = shift;200 my $string = shift;201 202 #for safety203 if(-e "temp_reg_export.reg"){204 system("mv temp_reg_export.reg temp_reg_export.reg.CBL");205 }206 system('regedit.exe /a temp_reg_export.reg "HKEY_LOCAL_MACHINE\HARDWARE\TEST"');207 208 system("regedit.exe /s noTEST.reg");209 system("regedit.exe /s /c $test_dir/t" . "$num" . "a.reg");210 $ob->initRegistry("HKEY_LOCAL_MACHINE\\HARDWARE");211 system("regedit.exe /s noTEST.reg");212 system("regedit.exe /s /c $test_dir/t" . "$num" . "b.reg");213 $ob->checkRegistry("HKEY_LOCAL_MACHINE\\HARDWARE");214 open (DIFF, "diff $test_dir/t" . "$num" . "changes.txt changes.txt |") or die "Can't check the changes files\n";215 @result = <DIFF>;216 close DIFF;217 #Bad test because it will be empty in the case of an error anyway?218 is(scalar(@result), 0, "$string");219 220 #for safety/cleanup221 if(-e "temp_reg_export.reg"){222 system("regedit.exe /s noTEST.reg");223 system("regedit.exe /s /c temp_reg_export.reg");224 system("rm temp_reg_export.reg");225 if(-e "temp_reg_export.reg.CBL"){226 system("mv temp_reg_export.reg.CBL temp_reg_export.reg");227 }228 }229 230 }231 }232 233 234 235 162 236 163 1; honeyclient/branches/bug/42/t/honeyclient_agent_integrity_registry.t
r122 r123 288 288 289 289 290 # =begin testing 291 { 292 # Perform Registry baseline on HKEY_CURRENT_CONFIG. 293 diag("Performing baseline check of 'HKEY_CURRENT_CONFIG' hive; this may take some time..."); 294 my $registry = HoneyClient::Agent::Integrity::Registry->new(hives_to_check => [ 'HKEY_CURRENT_CONFIG' ]); 295 $registry->closeFiles(); 296 my @files_created = $registry->getFilesCreated(); 297 use Data::Dumper; 298 my $tmpfile = tmpnam(); 299 unlink($tmpfile); 300 my $tmpdir = dirname($tmpfile); 301 foreach my $file (@files_created) { 302 like($file, qr/$tmpdir/, "closeFiles()") or diag("The closeFiles() call failed."); 303 } 304 } 305 306 307 290 308 291 309 1; honeyclient/branches/bug/42/t/honeyclient_agent_integrity_registry_parser.t
r116 r123 297 297 # =begin testing 298 298 { 299 my ($filename); 300 my $test_registry_file = $ENV{PWD} . "/" . getVar(name => "registry_file", 301 namespace => "HoneyClient::Agent::Integrity::Registry::Parser::Test"); 302 303 # Create a generic Parser object, with test state data. 304 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 305 306 $filename = $parser->getFilename(); 307 308 is($filename, $test_registry_file, "getFilename()") or diag("The getFilename() call failed."); 309 } 310 311 312 313 # =begin testing 314 { 315 my ($handle); 316 my $test_registry_file = $ENV{PWD} . "/" . getVar(name => "registry_file", 317 namespace => "HoneyClient::Agent::Integrity::Registry::Parser::Test"); 318 319 # Create a generic Parser object, with test state data. 320 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 321 $parser->closeFileHandle(); 322 323 # Verify Test Group #1 324 my $nextGroup = $parser->nextGroup(); 325 my $expectedGroup = { 326 key => 'HKEY_CURRENT_USER\]Testing Group 1[', 327 entries => [ { 328 name => '@', 329 value => 'Default', 330 }, { 331 name => 'Foo', 332 value => 'Bar', 333 }, ], 334 }; 335 is_deeply($nextGroup, $expectedGroup, "closeFileHandle()") or diag("The closeFileHandle() call failed."); 336 } 337 338 339 340 # =begin testing 341 { 299 342 my ($handle); 300 343 my $test_registry_file = $ENV{PWD} . "/" . getVar(name => "registry_file",
