#!/usr/local/bin/perl -w

my $version=1.0;

sub decode;


my @itable = (0,2,1,0,2,1,2,1,1,2,1,2,0,1,2,1,
	      0,1,2,1,0,0,2,1,1,2,0,1,2,1,1,2,
	      0,0,1,2,1,2,1,0,1,0,0,2,1,0,1,2,
	      0,1,2,1,0,0,2,1,1,0,0,2,1,0,1,2);

my @dectab = 
    (
     [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x57,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
      0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
      0x2E,0x47,0x7A,0x56,0x42,0x6A,0x2F,0x26,0x49,0x41,0x34,0x32,0x5B,0x76,0x72,0x43,
      0x38,0x39,0x70,0x45,0x68,0x71,0x4F,0x09,0x62,0x44,0x23,0x75,0x3C,0x7E,0x3E,0x5E,
      0xFF,0x77,0x4A,0x61,0x5D,0x22,0x4B,0x6F,0x4E,0x3B,0x4C,0x50,0x67,0x2A,0x7D,0x74,
      0x54,0x2B,0x2D,0x2C,0x30,0x6E,0x6B,0x66,0x35,0x25,0x21,0x64,0x4D,0x52,0x63,0x3F,
      0x7B,0x78,0x29,0x28,0x73,0x59,0x33,0x7F,0x6D,0x55,0x53,0x7C,0x3A,0x5F,0x65,0x46,
      0x58,0x31,0x69,0x6C,0x5A,0x48,0x27,0x5C,0x3D,0x24,0x79,0x37,0x60,0x51,0x20,0x36],
     [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x7B,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
      0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
      0x32,0x30,0x21,0x29,0x5B,0x38,0x33,0x3D,0x58,0x3A,0x35,0x65,0x39,0x5C,0x56,0x73,
      0x66,0x4E,0x45,0x6B,0x62,0x59,0x78,0x5E,0x7D,0x4A,0x6D,0x71,0x3C,0x60,0x3E,0x53,
      0xFF,0x42,0x27,0x48,0x72,0x75,0x31,0x37,0x4D,0x52,0x22,0x54,0x6A,0x47,0x64,0x2D,
      0x20,0x7F,0x2E,0x4C,0x5D,0x7E,0x6C,0x6F,0x79,0x74,0x43,0x26,0x76,0x25,0x24,0x2B,
      0x28,0x23,0x41,0x34,0x09,0x2A,0x44,0x3F,0x77,0x3B,0x55,0x69,0x61,0x63,0x50,0x67,
      0x51,0x49,0x4F,0x46,0x68,0x7C,0x36,0x70,0x6E,0x7A,0x2F,0x5F,0x4B,0x5A,0x2C,0x57],    
     [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x6E,0x0A,0x0B,0x0C,0x06,0x0E,0x0F,
      0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
      0x2D,0x75,0x52,0x60,0x71,0x5E,0x49,0x5C,0x62,0x7D,0x29,0x36,0x20,0x7C,0x7A,0x7F,
      0x6B,0x63,0x33,0x2B,0x68,0x51,0x66,0x76,0x31,0x64,0x54,0x43,0x3C,0x3A,0x3E,0x7E,
      0xFF,0x45,0x2C,0x2A,0x74,0x27,0x37,0x44,0x79,0x59,0x2F,0x6F,0x26,0x72,0x6A,0x39,
      0x7B,0x3F,0x38,0x77,0x67,0x53,0x47,0x34,0x78,0x5D,0x30,0x23,0x5A,0x5B,0x6C,0x48,
      0x55,0x70,0x69,0x2E,0x4C,0x21,0x24,0x4E,0x50,0x09,0x56,0x73,0x35,0x61,0x4B,0x58,
      0x3B,0x57,0x22,0x6D,0x4D,0x25,0x28,0x46,0x4A,0x32,0x41,0x3D,0x5F,0x4F,0x42,0x65]);

if (scalar(@ARGV) < 2)
{
    print "\nJScript.decode.pl $version\n(c) Christophe Grosjean 01/2004\nUsage: JScript.decode.pl infile.htm outfile.htm\n";
    exit;
}

open(IN,"<$ARGV[0]") || die "Can't open input file\n";
open(OUT,">$ARGV[1]") || die "Can't open output file\n";

my $before;
my $coded;
my $after;

while (<IN>){
    ($before,$coded,$after)= ($_ =~ /^(.*)\#@~\^(.*)\^\#~@(.*)$/);
    if (defined($coded)){
	print OUT $before;
	decode($coded);
	print OUT $after;
	$coded = undef;
    }
    else{
	print OUT $_;
    }
}
exit;

sub decode {
    my $coded = shift;
    my $decoded;
    my $pos = 0;
    my $i = 8;
    while ($i<length($coded)){
	my $res = ord(substr($coded,$i++,1));
	if ($res < 0x80){
	    $res = ${$dectab[$itable[$pos]]}[$res];
	    # following char is marked as a special char
	    if ($res == 0xFF){
		$res = ord(substr($coded,$i++,1));
		if ($res == 0x26) {$res = 0x0A;}
		elsif ($res == 0x23){$res = 0x0D;}
		elsif ($res == 0x2A){$res = 0x3E;}
		elsif ($res == 0x26){$res = 0x0A;}
		elsif ($res == 0x21){$res = 0x3C;}
		elsif ($res == 0x24){$res = 0x40;}
	    }
	}
	$pos = ($pos+1)&0x3F;
	if ($res != 255){
	    $decoded.=chr($res);
	}
    }
    print OUT $decoded;
}

# POD documentation

=head1 SYNOPSIS

JScript.decode.pl jscript_encoded_webpage.htm script_in_clear_webpage.htm

=head1 README

JScript.decode.pl - read encrypted JScript macros 
    (Microsoft proprietary extension to Javascript) 
    and write unencoded equivalent script.

This script read a web page containing encoded macros from STDIN 
or from an input file (-i) extract and decodes any encoded macros
and writes a new web page to STDOUT or to out file (-o) with macros
decoded. Is my decoding accurate ? Anyone's guess.

=head1 DESCRIPTION

This script was originally written to decode the body of an encrypted virus,
to understand what it did to my father's windows system. I originally wrote
it to work on Linux ;-) because I usually work with it. However this script
do not use anything OS specific so it should work on non-OSes like Windows too.

=head1 AUTHORSHIP

Christophe Grosjean

=head1 LICENSE

This software is licensed under the terms of the GNU Public License,
which is available for review at http://www.gnu.org/copyleft/gpl.html

=head1 CHANGE LOG

Jan-07-2004: Originally created by Christophe Grosjean

=head1 PREREQUISITES

None.

=head1 COREQUISITES

None.

=pod OSNAMES

Any.

=pod SCRIPT CATEGORIES

Web
Cryptography

=cut


