#!/usr/bin/perl -w

use strict;

print "CamoDetect - Written October 2004 by Andrew Christensen, anc at protego dot denmark\n";

# NOTE - I only work on .doc files. Look at the site mentioned below for something that works on other files.

# RESEARCH DISCLAIMER:
#
# The camouflage detection capability is new research, to the best of my knowlege.
#
# This decryption capability in this program is based on research found at 
# http://www.guillermito2.net/stegano/camouflage/
#
# The decryption mask below is part of the data which comes from the site mentioned above.

my @decryptMask = (2, 149, 122, 34, 12, 166, 20, 225, 225, 207, 191, 101, 32, 111, 158, 179, 153, 101, 74, 83, 251, 246, 117, 84, 173, 35, 205, 126, 156, 41, 231, 252, 226, 249, 77, 210, 66, 78, 6, 192, 248, 154, 28, 98, 56, 116, 36, 0, 85, 223, 65, 203, 1, 162, 183, 243, 143, 138, 221, 172, 51, 131, 96, 41, 243, 120, 36, 62, 122, 235, 211, 228, 157, 157, 67, 148, 74, 199, 69, 109, 37, 116, 235, 11, 152, 201, 124, 252, 200, 186, 50, 107, 0, 211, 197, 194, 148, 52, 175, 176, 229, 149, 125, 42, 132, 164, 95, 229, 110, 39, 42, 219, 150, 126, 62, 72, 57, 70, 207, 111, 113, 170, 60, 49, 154, 169, 158, 143, 137, 115, 179, 57, 202, 50, 213, 240, 49, 89, 124, 2, 46, 134, 55, 249, 43, 126, 81, 242, 65, 129, 12, 212, 101, 21, 247, 112, 212, 25, 152, 32, 191, 32, 184, 85, 103, 204, 129, 24, 140, 19, 60, 99, 60, 146, 17, 228, 91, 27, 8, 34, 96, 76, 74, 197, 138, 179, 197, 117, 195, 144, 122, 242, 178, 182, 200, 208, 56, 138, 194, 134, 240, 172, 233, 202, 92, 78, 62, 9, 41, 120, 41, 153, 90, 132, 213, 186, 94, 213, 146, 122, 56, 250, 208, 96, 236, 245, 39, 186, 238, 183, 222, 159, 155, 222, 101, 212, 118, 57, 118, 156, 218, 104, 141, 168, 160, 166, 30, 217, 219, 15, 77, 171, 146, 205, 113);

my $fn = defined($ARGV[0]) ? $ARGV[0] : die("$0 filename.doc\n");

unless(-r $fn){ die ("$fn is not a regular file\n");}   open(my $FH,"<$fn") or die("Cannot read $fn\n");

my $buff = ""; my $data = "";

while(sysread($FH,$buff,1000)){
  $data .= $buff;
}
close($FH);

(my @fcount) = $data =~ m/\x20\x00..\xc4\x01......\xc4\x01......\xc4\x01/mgs;
(my @matches) = $data =~ m/\x20\x00..\xc4\x01......\xc4\x01......\xc4\x01.*\x74\xa4\x54\x10\x22\x97.*/mgs; 

unless($#matches + 1){
  print "Camo Status: No hidden data found in $fn...\n";
  exit 0;
}

my $offset = index($data,$matches[0]);
my $datalength = (length($matches[0]) - 855);
my $encoded_datalength = length($matches[0]);

print "Camo Status: $fn contains " . $#fcount . " hidden file(s). \n";
print "Approx. $datalength bytes of hidden data were found\n";

my $unprotected_data = $data; my $prepass; my $pass; my $postpass;
$pass = substr($data,-275,255);
($prepass,$postpass) = $unprotected_data =~ m/(.*\x00\x00[\x04\x02]\x00)\Q$pass\E(.{20})$/mgs;
$pass =~ s/\x20*$//;
if(length($pass)){
  print "The " . length($pass) . "-character password to open the original file is: ";
  my $decryptIndex = 0;
  foreach my $p_letter (split(//,$pass)){
    my $xor = ord($p_letter) ^ $decryptMask[$decryptIndex];
    print chr($xor);
    $decryptIndex++;
  } 
  print "\n";
  $pass = "\x20" x length($pass);
  $unprotected_data = "$prepass" . "\x20" x 255 . "$postpass";
  open(my $CLEAN,">$fn.unprotected") or die("Unable to create/overwrite '$fn.unprotected'\n");
  syswrite($CLEAN,$unprotected_data) or die("Unable to write to '$fn.unprotected'\n");
  close($CLEAN);
  print "Saving an unprotected version of the file, named '$fn.unprotected'\n";
}
else{
  print "This archive requires no password to open\n";
}

