| 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 | | ); |
|---|
| 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 |
|---|