Full Disclosure mailing list archives

Release : ComLog 1.0, a WIN32 command prompt logger


From: full-disclosure () lists netsys com (Floydman)
Date: Wed, 14 Aug 2002 12:44:49 -0400

ComLog.pl, a WIN32 command prompt logger
by Floydman, floydian_99 () yahoo com
August 13th 2002

This paper is available online at www.geocities.com/floydian_99 and 
http://securit.iquebec.com

This paper can be freely distributed and reproduced, as long as correct 
credentials are maintained, and that no modifications are made to this 
file.  For corrections, suggestions or comments, please send me an e-mail.

Abstract

The goal of this paper is to present a new Perl tool that I made to monitor 
DOS sessions on Windows NT/2K (should also work on XP, but cannot try 
it).  This tool can be used by administrator to keep a history of commands 
typed in the DOS command prompt and the associated output, for example on 
an IIS server.  This can help admins to figure out what the attacker has 
done after compromising the machine via one of the numerous vulnerabilities 
this software present.  Of course, like any keylogger out there, it can 
also be use for malicious purpose, but I think other programs out there 
make better spying tools.


Preface

I started writing about my own experiences in the security field after 
reading Lance Spitzner's whitepapers, way back before the HoneyNet Project 
grew into the multi-disciplinary team that has now joined him and make the 
project as we know it today.  I also wanted to inspire myself of what was 
being done on the UNIX platform (making your own tools when they don't 
exists) to transpose it in the Windows world, where I am more 
comfortable.  This paper follows these traditions, as the idea for it came 
to me while reading the HoneyNet Project recent book, Know your ennemy.  In 
the book, one passage relate to how the HoneyNet is designed to sniff all 
the traffic that passes into it since all of this traffic is suspicious by 
nature.  This worked great for capturing what the attackers were doing on 
the systems, up to the day when someone was using cryptcat to hide his 
session.  To circumvent this problem, the team made a modification in the 
source code of bash to log the session and recompiled it for the next 
attack.  However, the book says, since we can not do the same with 
Microsoft code, they didn't bother to make an equivalent solution for 
Windows.  ComLog fills that gap.

Special thanks to Lance Spitzner for his comments and ideas during the 
improvement of the pre-release.

Targeted audience

This document is presented to anyone who has interests in computer 
security, honeynets, trojan horse, keyloggers, network administration and 
computing in general.

1. Introduction
2. Purpose of the program
3. How it works
4. Things you need to know
5. To Install
6. Conclusion
Appendix A. Source code
Appendix B. Sample session history (console)
Appendix C. Sample session history (history.txt)

1. Introduction

One of the most common ways that Windows machines are hacked is through the 
command prompt.  This is not surprising, since this is the shell 
environment on the Win32 platform, it permits the execution of commands 
without the need of a GUI, and is easily accessed by executing one single 
file, either command.com on Win 9x/Me, or cmd.exe on Win NT/2K.  While this 
file in itself is not a problem, the thing is that it can be accessed by 
many ways by anyone who can guess where is located this file, and most of 
the time, it is always in the same places, because the installations were 
made by default.  This is how most of IIS exploits work, they rely on a 
Unicode encoding or a special format string to fool the server into 
accessing files outside of the web directory and make a renamed copy of 
cmd.exe (because IIS filters commands sent directly to cmd.exe, thanks 
Microsoft for the great security), and then simply issues command to this 
copy via a URL in their web browser.  Code Red and Nimda were doing that 
automatically.

Also, admins may want to keep an eye on what's going on in the DOS prompts 
on their users workstations, as the inside threat remains the greatest 
concern for computer security.  I mean, what could secretaries, accountants 
and other office employees be doing in a DOS prompt that is related to 
their job?  I wouldn't go as far as to remove their access to the command 
prompt, besides it may be needed from time to time by support people.  But 
right now, how can you tell if one of the employees on your network is not 
doing a ping scan or is netcating his way to the restricted file server and 
making password dumps?

2. Purpose of the program

The purpose of this program is quite simple: improve the forensics 
disponibility in case of a break-in in order to better determine the 
actions of the attacker.  Forensics is a whole ball game in itself in 
security.  It requires a good understanding of the systems involved, and 
experience of attacks usually made helps in focusing on the important 
things.  Forensics is all about figuring out what has happened on a 
computer system (or network) after an intrusion has been done.  To do this, 
all the information available is crucial: firewall logs, IDS logs (if any), 
system logs, volatile information on the systems (what processes are 
running in memory, ...), complete bit-by-bit disk image.  All of this in 
order to try to understand what has happened, but on top of it, one must 
make sure not to alter this data by manipulating it, considering that the 
attacker may have gone through great efforts to hide his traces.

ComLog will not solve all the problems computer forensics face today.  But 
it will help greatly in reducing the time necessary to understand the scope 
of an attack if the intruder made his attack via the command 
prompt.  Instead of trying to reverse-engineer the attackers tool or to 
look for modified signature files to determine the actions of the attacker, 
one will only have to check these logs to determine what commands were 
typed by the attacker.  By storing centrally the history files of the 
command prompts on your network, along with your antivirus log files and 
maybe even personal firewall log files (for more details on this, read 
"Securing the Microsoft internal network"), you improve your knowledge 
about the kind of activity that is going on on your machines.  And it gives 
you the chance to act wisely before it is too late.

3. How it works

ComLog is a Perl program that sits in front of the command prompt and 
emulates it, capturing any data typed in and out before transmitting it to 
the real prompt for execution or before displaying the data on the 
screen.  It could be considered as a wrapper.  To do so, the program must 
be compiled with perl2exe (available from www.indigostar.com) and renamed 
cmd.exe (this is why it doesn't work on Win9x/Me, these OS use command.com, 
which allow for smaller files, and I haven't figured how to make a .com 
file.  Besides, it is used for boot-up.  If you can help on this one, send 
me an e-mail).  The real cmd.exe has to be renamed cm_.exe (or whatever 
name you chose, but make sure to change the source code approprietly), 
because we still need it to execute the commands asked by the user.

So this way, when a user double-click on the command prompt icon, or run 
cmd.exe from the Start menu, or a cracker issues commands to the prompt by 
abusing the web server, web browser, database server, mail client, netcat 
session, etc., or to a renamed or relocated copy of it, it will be thru 
ComLog that these commands will be issued.  ComLog makes a timestamp in the 
log file (*.clg) between each input and output, allowing the administrator 
to know things like at what time each event occured, how much time each 
command took to perform, how much time passes between the result of the 
last command and the when the next command is issued, etc.

Since ComLog emulates the command prompt, there are certain things we need 
to keep track of in order to make the session as transparent as possible to 
the user.  Such things to keep track of is the current directory and 
current drive, and to keep track of this we monitor closely 'cd' command 
and changes of drive.  'cls' is also a command that I cannot rely on 
cm_.exe to implement, since it returns an empty screen as output, so we 
implement that as well.  We also have to check if the drive or directory 
the user wishes to go to really exists, or else ComLog will contain 
erroneous environment data and will stop working properly.  This causes a 
limitation in the use of the wildcard '*' in directory names (more on that 
in the next chapter).

That is about all the checking and emulating that is done, all the rest 
that is typep by the user and/or attacker will be sent as is to the real 
prompt (cm_.exe), and bad commands will simply produce the expected "The 
name specified is not recognized as an internal or external command, 
operable program or batch file." error message, as it normally would.

ComLog always start in the . (current) directory.  Issuing cd commands with 
relative paths will create a relative path chain that will keep track of 
the current directory.  So after browsing a couple of directories out of 
and back in to C:\WINNT\SYSTEM32(cd..; cd..; cd winnt; cd system32), the 
path should look like .\..\..\WINNT\SYSTEM32, altough the user will only 
perceive his current directory.  Issuing a cd command with a path starting 
with \ will replace the whole relative path that built over the session 
with that absolute path, in order to avoid getting too long and confusing 
relative path names in memory.  Further relative path browsing will be 
appended to this absolute path, until a new absolute path is 
entered.  Drives and current directories for each drive are kept in a 
self-adjusting table.  Bad directories and bad drives error messages are 
handled by ComLog, and will replace the user's command with something 
neutral so not to disturb environment variables.  Once these checks are 
done, commands are sent in the form of cm_.exe /C currentdrive: && cd 
currentdir && usercommand, the && signs are letting us to issue more than 
one command on the same line.  So this way, the new instance of cm_.exe 
(which has its own environment variables) is always kept fresh on where the 
user wants to be.  cm_.exe terminates after executing the command.  This is 
why we have to keep track of the environment variables ourselves.  The 
output is captured, sanitized to hide ComLog's prosence, and  then sent to 
its log file and displayed on the screen.

In the first, pre-release version of ComLog, log files were stored in a 
file called history.txt, that was present in the . (current directory) 
along with cmd.exe.  I thought that this was good, because ComLog would 
produce a log file wherever it is copied to.  But this produced two 
problems that are now solved with a single solution.  First, if two (or 
more) instances of the same cmd.exe were running, they were all writing to 
the same log files.  So issuing an intensive command like dir \ /s on one 
instance meant that one command typed in another instance had to wait until 
the intensice dir finishes before producing its output.  The other thing 
was that having a potentially floating location for the log files, it was 
hard to keep an eye on it using a tool like LogAgent.  This was solved by 
storing the log files in \WINNT\Help\Tutor, each instance having a 
random-generated filename associated to it, to prevent collision.  ComLog 
log files have a .clg extension.  Take note that if you install ComLog 
manually (not using the install pack), you have to create the \Tutor folder 
in \WINNT\Help.

4. Things you need to know

ComLog does a pretty good job at pretending to be the real command prompt, 
but in fact it has some limitations that can affect or not its actor 
performance, depending on the situations.  Some limitations are gone since 
the pre-release version, but some still remain.  First of all, since I 
mentionned it earlier, there is a limitation in the use of the * wildcard 
in directory names.  In normal circumstances, under NT/2K, you can cd to a 
directory by supplying only the first few letters followed by a *, which 
can be convenient with long path names.  The limitation occured when I 
implemented the checkdir() function (which I cannot remove, or else ComLog 
may be fooled into non-existing directories, and at that point you can kiss 
your cover goodbye).  I tried doing it with the opendir() function, like I 
did with checkdrive(), but it doesn't support wildcards whatsoever (from my 
testing, anyway).  So I use the same trick as when I send commands, and I 
use this to make a IF EXIST on the directory (this is usually used only in 
batch files, since there is little use to make an IF statement on a 
one-liner, but it works just as well when it is typed in DOS) to validate 
its existence.  And the IF EXIST command cannot handle more than one layer 
of wildcarded directories.  For example, in a ComLog session, let's pretend 
that I am in the root directory, and I want to move to \Program 
Files\Common Files.  If I type cd pro* [ENTER], cd com* [ENTER], this will 
work just great.  But if I type cd pro*\com*, the program will issue a "The 
system cannot find the path specified." error message.  But under a real NT 
command prompt, that line should work.

Another problem is that it cannot handle interactive DOS programs, such as 
a regular FTP session or something as simple as date or time (you have to 
at least press enter to exit date and time).  Since the command prompt 
output is captured by ComLog, and that ComLog waits for cm_.exe to 
terminate to continue its execution, and that cm_.exe is waiting for some 
sort of user input that will not come before quitting, we can see where the 
problem lies.  Under certain circumstances, this is not so much of a 
problem, for example a web server that the command prompt can be abused 
with netcat, since netcat won't allow for interactive programs either, so 
the attacker behavior will already be adjusted to that limitation (or else 
he will face the same results).  But on a local prompt, where a user might 
want to launch an interactive DOS program (be it a network scanner waiting 
for its parameters or a mere DOS game), it will be obvious that something 
is not working right.  Launching such a program from the GUI should not 
pose a problem, but if you must absolutely start a program from a DOS 
prompt, remember that you can always do so from cm_.exe.

One other thing is that ComLog will try to hide himself from the view of 
the user, by modifying the output when cm_ or ComLog log files shows 
up.  This will be the case if the user issues a dir or a pslist command to 
see what files or running programs are present on the system.  This have 
the side effect of having a different file count at the end of the dir 
commands and the number of files displayed on the sreen (or the user's 
dumpfile, as he is likely to do).  While this has little chance of being 
detected on directories containing a lot of files, in an empty directory, 
this might ring a bell to an attacker.  Another thing that could give it is 
that by hiding the bigger file size for cmd.exe (695 kb once compiled with 
perl2exe, compared to 204 kb on NT and 231 kb on 2K), I drop any files that 
is the same exact size as ComLog.  So, in a directory where you have 
cm_.exe (204 kb), cmd.exe(695 kb), and you copy cmd.exe to root.exe and 
produce a dir, you will see cmd.exe(204 kb), but no trace of cm_.exe 
(that's good) or root.exe (not so good).

Oh!, I almost forgot.  If you use ComLog in its Perl format, or if you 
compile it and is it called comlog.exe or anything else except cmd.exe, it 
will work as advertised.  But when you rename cmd.exe to cm_.exe, and 
rename ComLog.exe to cmd.exe, ComLog will go on an infinite loop when you 
try to execute cmd.exe.  This is because the compiled program still need a 
shell environment to start into, and that shell is by default... 
cmd.exe.  So the program just keep launching itself in the useless hope of 
ever finding a shell environment.  It took me quite a while to figure this 
one out, tried almost everything from changing my COMSPEC variable, editing 
the registry, patching some Windows executables and DLLs (the later caused 
my system not to be able to boot anymore.  Luckily I had a NT Recovery CD 
with NTFS4DOS on it, which let me put the original DLLs in place).  It 
turns out that all you need to do is to patch 2 ActivePerl DLL with a hex 
editor to do the trick.  This is where is stored the hardcoded call to 
cmd.exe that kept haunting me, no matter what change I was applying to my 
system.  The files that need to be changed are p2x560.dll and 
perl56.dll.  Make a backup of these files and open them with a hexadecimal 
editor.  Make a string search for cmd.exe (there's only one instance in 
each file), and replace the 'd' character with '_'.  Of course, you could 
chose another name, but you have to realize that you are limited to a three 
characters filename, and that you must change the name evrywhere in the 
program so that it matches accordingly.  Windows 200 involve one more step 
(not covered with the ComLog shareware install pack, to come later), thanks 
to Windows File Protection, a feature added in Win2K that lets the system 
monitor its system files and replace them with the original version if they 
become corrupted or deleted.  This feature, which was inexistant on Windows 
before, will effectively keep replacing ComLog with the real cmd.exe.  This 
feature can be disabled with a simple registry tweak on Win2K, a DLL have 
to be patched in addition of the tweak on Win2K SP2.  Full details on how 
to disable Windows File Protection can be found at 
http://www.jsifaq.com/SUBK/tip5300/rh5392.htm and 
http://www.lanovation.com/support/docs/NT_2000/WFP_2000XP.htm or by typing 
'disabling Windows File Protection' on Google.

The last thing is the giveaway that is the banner displayed at the end of 
execution when compiled with perl2exe evaluation version.  This is why you 
may want to download the install pack, it is compiled with a registered 
version of perl2exe.

5. To Install

For Win NT4:

1) Download the installation package (free) at 
http://securit.iquebec.com/download.html;

or 2) Installing it manually from the source code displayed below.

In the case of 1), simply download the file and execute it on the machine 
you want to install it on.  This file will copy 2 files in your 
\Winnt\System32 directory (cmd.exe, cm_.exe), and will create the directory 
\Tutor in \Winnt\Help\.  ComLog Log files are stored in \Winnt\Help\Tutor.

In the case of 2), first of all you need a copy of Perl installed, I 
suggest ActivePerl from www.activestate.com (it's free) if you don't 
already have one.  Then you need a hex editor, I suggest XVI32 (also free) 
that you can download at 
http://download.com.com/3000-2352-7621132.html?tag=lst-0-15.  Then, using 
the hex editor, you have to edit p2x560.dll and perl56.dll in your 
\Perl\bin directory, and change the instance of cmd.exe to cm_.exe.  Copy 
cmd.exe to cm_.exe in \Winnt\System32.  Copy the code presented below and 
save it to comlog.pl.  Then, using perl2exe, compile comlog.pl, and rename 
the resulting comlog.exe to cmd.exe.  Then copy this cmd.exe over your 
original cmd.exe (keep your cm_.exe, comlog needs it).  Finally, create a 
directory called \Tutor in \Winnt\Help, for storing the log files.  To use, 
simply go to a Dos prompt via your preferred way.

For Win2K : The same, except that you first have to disable the Windows 
File Protection feature.  Look at 
http://www.jsifaq.com/SUBK/tip5300/rh5392.htm and 
http://www.lanovation.com/support/docs/NT_2000/WFP_2000XP.htm or by typing 
'disabling Windows File Protection' on Google for more details about this.

6. Conclusion

So this concludes the documentation accompanying this software.  As we have 
seen above, ComLog is a tool that can empowers network administrators into 
knowing what is going on with the command prompts on their machines, and 
can use it to determine the actions of an attacker.  Since only what is 
going through the command prompt is logged, I think this is not too 
intrusive to be placed eventually on every PC on a network, since regular 
office employees rarely have a professional reason to justify the use of 
the command prompt.  ComLog being an emulator, it does show some 
shortcomings when compared with the real McCoy, but it should not prevent 
its use in most cases.  However, fine knowledge of these shortcomings could 
help an intruder to determine that he is being watched, and more effort 
should be put into improving the program even more.  A lot has been done 
recently to improve this, such as improving LogAgent to handle these logs 
and to make sure that ComLog has a LogAgent-compatible log file storing 
strategy, but more could be done to improve concealing.  Finally, the 
source code is presented in Appendix A, and a sample session is showed as 
it appears on the console (Appendix B) and in the history.txt log file 
(Appendix C).  The code should be easy to read, as I used comprehensive 
variable and procedure names, and I made a lot of comments along the code.

Appendix A. Source code
#!D:\dev\perl\bin\perl.exe
# ComLog 1.0

#########################################################################################
# ComLog 1.0                                                                            #
# by Floydman  floydian_99 () yahoo com                                                 #
# Copyright 2002 SecurIT Informatique Inc.  http://securit.iquebec.com                  #
#                                                                                       #
# This program captures the input/output of the Windows NT Command Promt 
(cmd.exe).      #
# It does so by prentending to be the real prompt and forwarding the 
commands to the         #
# real (and renamed) cmd.exe.  I/O is stored in a random-generated log file 
in              #
# \WINNT\Help\Tutor.
#########################################################################################

#########################################################################################
# LICENSE                                                                               #
# This software is Open Source.  This means that its source code is open, 
free and avai-#
# lable for anyone to look into, make modifications, correct bugs (let me 
know, please) #
# and use for personal and commercial use.  You can create your own 
binaries with   #
# perl2exe (www.indigostar.com), or download the install package from                   #
# securit.iquebec.com/download.html.                                                    #
#########################################################################################

#########################################################################################
# Main Program                                                                          #
# This is the main structure of ComLog.                                                 #
# This programs is a loop that will be passed only once if arguments are 
passed with     #
# ComLog, since it means it was not launched for interactive use.  Else, 
the loop will   #
# go on until the user types 'exit' or breaks otherwhise the program 
execution (CTRL-C).#
# The program then presents the prompt to the user, and gets the command 
typed at the    #
# keyboard.  Change of drives or directories are checked for, since ComLog 
have to #
# provide these parameters to the real command prompt.  Everything is 
logged in a     #
# random generated filename to allow for multiple instances.  Output is 
sanitized to    #
# hide ComLog's presence.                                                               #
#########################################################################################


use Win32;

# Initialization of entrant parameters, current dir, command, exit and 
currentdrive
$input = join (' ',@ARGV);
$index = 0;
$currentdir[$index] = '.\\';
$command = '';
$exit = 1;
$currentdrive[$index] = getcurrentdrive ($currentdir[$index]);
$nothing = 1;   # nop
$winnt = "Windows NT Version 4.0";
$wintwok = "Microsoft Windows 2000";
$cleanlog = 0;  # Set to 0 to keep the local log files, set to 1 to delete 
them after the session is done

$history = randomfilename();

open (WINVER, "cm_.exe /C ver |") or die "Can't open pipe";
@header = <WINVER>;
close (WINVER);

$header = join('', @header);

if ($header=~m/$winnt/) {sendoutput ("Microsoft(R) Windows NT(TM)\n(C) 
Copyright 1985-1996 Microsoft Corp.\n");}
if ($header=~m/$wintwok/) {sendoutput ("Microsoft Windows 2000 [Version 
5.00.2195]\n(C) Copyright 1985-1999 Microsoft Corp.\n");}

# Get the path for the fake prompt
getprompt($currentdrive[$index], $currentdir[$index]);

# If no args are passed, we cancel the $exit marker and launch the prompt
if ($input eq '') {$input = <STDIN>; $exit = 0;}

# Enters in an "interactive" session and will terminate on 'exit', the loop 
will run only once if $exit is set to 1
while ($input ne "exit\n")
{
chomp $input;
$cdcommand = 0; $baddir = 0; $baddrive = 0;

SWITCH: {
        # If the command starts with 'cd', then it checks if the next character is \
        # If it is, then the string replaces the $currentdir.  If it does not 
start with
        # a \, then the string is appended at the end of the path in $currentdir
        # If nothing follows the cd command, then the command is put back in $input
        # since we modified the string for analysis with the shift command above
         $input=~m/^cd/i      && do {
                                        @input = split (//,$input);
                                        if ($input[0] eq "c" or $input[0] eq "C") {shift @input;}
                                        if ($input[0] eq "d" or $input[0] eq "D") {shift @input;}
                                        while ($input[0] eq " ") {shift @input;}

                                        if (@input)
                                        {
                                                if ($input[0] eq "\\")
                                                {
                                                  $input = join ('',@input);
                                                  $direxist = checkdir($currentdrive[$index], "\\", $input);
                                                  if ($direxist)
                                                  {
                                                  $currentdir[$index] = $input;
                                                  $cdcommand = 1;
                                                  $input = "cd ".$input;
                                                  }
                                                  else {$cdcommand = 1; $baddir = 1; $input="cd";}
                                                }
                                                else
                                                {
                                                  $input = join ('',@input);
                                                  $direxist = checkdir($currentdrive[$index],$currentdir[$index], 
$input);
                                                  if ($direxist)
                                                  {
                                                    $currentdir[$index] = $currentdir[$index].$input.'\\';
                                                    $cdcommand = 1;
                                                    $input = "cd ".$input;
                                                  }
                                                  else
                                                  { $cdcommand = 1; $baddir = 1; $input="cd"; }
                                                }
                                        }
                                        else
                                        { $input="cd"; }
                                        last SWITCH;
                                    };
        # If the command is 'cls', we nullify the command and simulate it from the 
perl program
         $input=~m/cls/i      && do {
                                     system("cls");
                                    sendinput ($input."\n");
                                    $input = "";
                                     last SWITCH;
                                     };
        # If the command is to change the drive letter (c:, d:, etc), we set our 
variables accordingly
        # If it's the first time the drive is accessed, an entry is added in the 
table to store it with its current directory
        $input=~m/^\w:$/    && do {
                                    $i = 0;
                                     foreach $drive (@currentdrive)
                                        {
                                        if ($currentdrive[$i]=~m/$input/i)
                                           {$index = $i; last SWITCH;}
                                        $i++;
                                        }
                                    if ($index ne $i)
                                        {
                                        $driveexist = checkdrive($input);
                                         if ($driveexist)
                                          {     
                                          $index = $i;
                                          $currentdrive[$index] = $input;
                                          $currentdir[$index] = '.\\';
                                          }
                                     else {$baddrive=1; $input = $currentdrive[$index];}
                                        }
                                
                                    last SWITCH;
                                    };
         $nothing = 1;
     }

# If it is a 'cd' command, then we simply execute a 'cd' command with the 
$currentdir path
# If not, then we issue the 'cd' command anyway, as it is needed to 
position the summoned instance
# of cm_.exe in the right directory, then we call the command typed at the 
prompt
# $command contains the string of the final command to be sent to the real 
DOS prompt
if ($cdcommand)
    { $command = "cm_.exe /C ".$currentdrive[$index]." && cd 
".$currentdir[$index]; }
else
    { $command = "cm_.exe /C ".$currentdrive[$index]." && cd 
".$currentdir[$index]." && ".$input; }

# Writes the input to the history file
sendinput ($input."\n");

# If the command is valid and it's not an empty carriage return, then we 
call the command and capture the output

if ($baddir) { sendoutput("The system cannot find the path specified.\n"); }
if ($baddrive) { sendoutput("The system cannot find the drive specified.\n"); }

if ($input ne '')
    {
    open (COMMANDOUTPUT, $command." |") or die "Can't open pipe";
    @output = <COMMANDOUTPUT>;
    close (COMMANDOUTPUT);
    sendoutput (@output);
    }

# If the $exit marker is not set, get the fake prompt
if ($exit) {$input = "exit\n";} else {getprompt($currentdrive[$index], 
$currentdir[$index]); $input = <STDIN>;}

} # End of While

# sends the final command (exit) to the history log file
sendinput ($input."\n");

if ($cleanlog) {unlink ($history);}

#End Of Main

#########################################################################################
# procedure getcurrentdrive(currentdir)                                                 #
# This procedure gets the drive  where is located the current directory.                #
#########################################################################################
sub getcurrentdrive
{ my ($dir) = @_;

open (PROMPT, "cd".$dir." && cd |") or die "Can't open pipe";
$prompt = <PROMPT>;
chomp $prompt;
close (PROMPT);

@prompt = split (//,$prompt);
$drive = join ('', ($prompt[0], $prompt[1]));
return ($drive);
}

#########################################################################################
# procedure getprompt(currentdrive, currentdir)                                         #
# This procedure receives the current drive and directory and fakes a 
command prompt. #
#########################################################################################
sub getprompt
{ my ($drive, $dir) = @_;

open (PROMPT, $drive."&& cd ".$dir." && cd |") or die "Can't open pipe";
$prompt = <PROMPT>;
chomp $prompt;
close (PROMPT);
sendoutput ("\n".$prompt.">");
}


#########################################################################################
# procedure sendinput(line)                                                             #
# This procedure writes the input received into the history file                        #
#########################################################################################
sub sendinput
{ my (@line) = @_;

$now = localtime;

# Opening of history file
open (HISTORY, ">>".$history) || die "Can't open session log file";
lock HISTORY;
print HISTORY "$now\n";
print HISTORY "@line";
close (HISTORY);
}

#########################################################################################
# procedure sendoutput(output)                                                          #
# This procedure writes the output from commands received into the history 
file    and to  #
# the console.  It also sanitize the output to conceal the program presence.            #
#########################################################################################
sub sendoutput
{ my (@output) = @_;

$now = localtime;

# Opening of history file
open (HISTORY, ">>".$history) || die "Can't open session log file";
lock HISTORY;
print HISTORY "$now\n";
foreach $line (@output)
{
$line=~s/cm_.exe/cmd.exe/i;
if (!(($line=~m/711,342/) || ($line=~m/\w{8}.clg/) || ($line=~m/cm_/)))
   { print "$line";
     print HISTORY "$line";
   }
}
close (HISTORY);
}

#########################################################################################
# procedure checkdir($drive, $path, $dir)                                               #
# This procedure checks for the existence of a directory before changing to 
it.             #
#########################################################################################
sub checkdir
{ my ($drive, $dir, $unknown) = @_;

$command = "cm_.exe /C ".$drive." && cd ".$dir." && if exist ".$unknown." 
echo OK";

    open (COMMANDOUTPUT, $command." |") or die "Can't open pipe";
    $output = <COMMANDOUTPUT>;
    close (COMMANDOUTPUT);
    if ($output eq "OK\n") {return 1;} else {return 0;}
}

#########################################################################################
# procedure checkdrive($drive)                                                          #
# This procedure checks for the existence of a drive before changing to it.             #
#########################################################################################
sub checkdrive
{ my ($drive) = @_;

    opendir (TESTDRIVE, $drive."\\") or return 0;
    closedir (TESTDRIVE);
    return 1;
}

#########################################################################################
# procedure randomfilename()                                                            #
# This procedure generates a random filename for the session log.                       #
#########################################################################################
sub randomfilename
{
  for ($gen=0; $gen<8; $gen++) {$random = int (rand 26)+97; $history = 
$history.chr($random);}
  $history = $history.".clg";
  $history = $ENV{SystemRoot}."/Help/tutor/".$history;
  return $history;
}
#EOF


Appendix B. Sample session history (console)
(note: this session history was made with the pre-release version of 
ComLog.  The same commands would now produce a slightly different result.)

Microsoft(R) Windows NT(TM)
(C) Copyright 1985-1996 Microsoft Corp.


D:\commandlog>dir
  Volume in drive D is D
  Volume Serial Number is 0480-D01C


  Directory of D:\commandlog


08/04/02  04:35a        <DIR>          .
08/04/02  04:35a        <DIR>          ..
08/04/02  04:26a               655,520 cmd.exe
08/04/02  04:20a                 8,726 comlog.pl
08/04/02  04:10a                18,433 comlog.txt
05/13/02  02:42p                 1,506 command logger.txt
02/11/02  11:47a                   971 pseudo code.txt
08/04/02  04:26a               655,520 root.exe
08/04/02  04:28a                   583 Shortcut to cmd.exe.lnk
05/30/02  02:04p                    35 systempath.txt
07/21/02  03:27p                   878 test.txt
               13 File(s)      1,557,580 bytes
                             488,346,112 bytes free


D:\commandlog>echo "There is a copy of cm_.exe and history.txt in here, but 
we d
on't see it"


D:\commandlog>echo "That last message didn't echo because it contained the 
fobid
den words"
"That last message didn't echo because it contained the fobidden words"


D:\commandlog>cd ..


D:\>dir
  Volume in drive D is D
  Volume Serial Number is 0480-D01C


  Directory of D:\


08/04/02  04:35a        <DIR>          commandlog
06/25/02  12:57p        <DIR>          Dev
12/25/00  09:34p        <DIR>          downloads
08/04/02  04:20a        <DIR>          Log
08/04/02  04:21a        <DIR>          LogAgent 2.0
01/02/01  03:57p        <DIR>          movies
07/24/01  12:59p        <DIR>          Musique
08/04/02  02:42a        <DIR>          NONE
06/25/02  01:59p        <DIR>          NTRESKIT
08/04/02  02:59a            67,108,864 pagefile.sys
05/20/01  06:10a        <DIR>          Program Files
08/04/02  04:36a        <DIR>          TEMP
04/30/02  02:33p        <DIR>          Test
10/15/00  04:06p        <DIR>          VIRUSES
05/24/02  06:22p        <DIR>          WINNT
05/24/02  06:22p                    92 WINNTdun.bat
               16 File(s)     67,109,842 bytes
                             488,345,088 bytes free


D:\>ipconfig


Windows NT IP Configuration


Ethernet adapter DE5284:


         IP Address. . . . . . . . . : 192.168.0.1
         Subnet Mask . . . . . . . . : 255.255.0.0
         Default Gateway . . . . . . : 192.168.0.1


PPP adapter NdisWan3:


         IP Address. . . . . . . . . : 0.0.0.0
         Subnet Mask . . . . . . . . : 0.0.0.0
         Default Gateway . . . . . . :


D:\>net share


Share name   Resource                        Remark


-------------------------------------------------------------------------------
IPC$                                         Remote IPC
C$           C:\                             Default share
D$           D:\                             Default share
G$           G:\                             Default share
Log$         D:\Log
ADMIN$       D:\WINNT                        Remote Admin
Log          D:\Log
The command completed successfully.



D:\>dir \log >> dirlog.txt


D:\>echo "The user see no display because he sent the output to a file"
"The user see no display because he sent the output to a file"


D:\>type dirlog.txt
  Volume in drive D is D
  Volume Serial Number is 0480-D01C


  Directory of D:\log


08/04/02  04:20a        <DIR>          .
08/04/02  04:20a        <DIR>          ..
04/30/02  02:37p                 3,819 adam.log
09/25/00  08:31p                   373 bind.log
05/20/01  05:46a                 6,917 getright.log
08/04/02  02:50a               131,546 IAMDB.RDB
09/25/00  08:31p                    41 restart.log
08/04/02  04:20a                   177 Scan Viruses.lnk
09/25/00  08:31p                    36 shutdown.log
09/25/00  08:31p                   104 startup.log
04/29/02  02:56p                   218 test.bat
04/30/02  02:33p                 3,721 test.txt
07/24/01  11:26a                 5,553 ZALog.txt
               14 File(s)        153,044 bytes
                             488,340,480 bytes free


D:\>dir
  Volume in drive D is D
  Volume Serial Number is 0480-D01C


  Directory of D:\


08/04/02  04:35a        <DIR>          commandlog
06/25/02  12:57p        <DIR>          Dev
08/04/02  04:39a                   886 dirlog.txt
12/25/00  09:34p        <DIR>          downloads
08/04/02  04:20a        <DIR>          Log
08/04/02  04:21a        <DIR>          LogAgent 2.0
01/02/01  03:57p        <DIR>          movies
07/24/01  12:59p        <DIR>          Musique
08/04/02  02:42a        <DIR>          NONE
06/25/02  01:59p        <DIR>          NTRESKIT
08/04/02  02:59a            67,108,864 pagefile.sys
05/20/01  06:10a        <DIR>          Program Files
08/04/02  04:36a        <DIR>          TEMP
04/30/02  02:33p        <DIR>          Test
10/15/00  04:06p        <DIR>          VIRUSES
05/24/02  06:22p        <DIR>          WINNT
05/24/02  06:22p                    92 WINNTdun.bat
               17 File(s)     67,109,842 bytes
                             488,339,456 bytes free


D:\>cd commandlog


D:\commandlog>dir
  Volume in drive D is D
  Volume Serial Number is 0480-D01C


  Directory of D:\commandlog


08/04/02  04:35a        <DIR>          .
08/04/02  04:35a        <DIR>          ..
08/04/02  04:26a               655,520 cmd.exe
08/04/02  04:20a                 8,726 comlog.pl
08/04/02  04:10a                18,433 comlog.txt
05/13/02  02:42p                 1,506 command logger.txt
02/11/02  11:47a                   971 pseudo code.txt
08/04/02  04:26a               655,520 root.exe
08/04/02  04:28a                   583 Shortcut to cmd.exe.lnk
05/30/02  02:04p                    35 systempath.txt
07/21/02  03:27p                   878 test.txt
               13 File(s)      1,563,574 bytes
                             488,338,432 bytes free


D:\commandlog>copy cmd.exe root.exe
         1 file(s) copied.


D:\commandlog>exit



Appendix C. Sample session history (history.txt)


Sun Aug  4 04:31:09 2002
Microsoft(R) Windows NT(TM)
(C) Copyright 1985-1996 Microsoft Corp.
Sun Aug  4 04:31:09 2002


D:\commandlog>dir
Sun Aug  4 04:31:15 2002
  Volume in drive D is D
  Volume Serial Number is 0480-D01C


  Directory of D:\commandlog


08/04/02  04:31a        <DIR>          .
08/04/02  04:31a        <DIR>          ..
08/04/02  04:26a               655,520 cmd.exe
08/04/02  04:20a                 8,726 comlog.pl
08/04/02  04:10a                18,433 comlog.txt
05/13/02  02:42p                 1,506 command logger.txt
02/11/02  11:47a                   971 pseudo code.txt
08/04/02  04:28a                   583 Shortcut to cmd.exe.lnk
05/30/02  02:04p                    35 systempath.txt
07/21/02  03:27p                   878 test.txt
               12 File(s)        894,939 bytes
                             489,010,688 bytes free
Sun Aug  4 04:31:15 2002


D:\commandlog>echo "There is a copy of cm_.exe and history.txt in here, but 
we don't see it"
Sun Aug  4 04:32:02 2002
Sun Aug  4 04:32:02 2002


D:\commandlog>echo "That last message didn't echo because it contained the 
fobidden words"
Sun Aug  4 04:32:31 2002
"That last message didn't echo because it contained the fobidden words"
Sun Aug  4 04:32:31 2002


D:\commandlog>cd ..
Sun Aug  4 04:32:35 2002
Sun Aug  4 04:32:35 2002


D:\>dir
Sun Aug  4 04:32:36 2002
  Volume in drive D is D
  Volume Serial Number is 0480-D01C


  Directory of D:\


08/04/02  04:31a        <DIR>          commandlog
06/25/02  12:57p        <DIR>          Dev
12/25/00  09:34p        <DIR>          downloads
08/04/02  04:20a        <DIR>          Log
08/04/02  04:21a        <DIR>          LogAgent 2.0
01/02/01  03:57p        <DIR>          movies
07/24/01  12:59p        <DIR>          Musique
08/04/02  02:42a        <DIR>          NONE
06/25/02  01:59p        <DIR>          NTRESKIT
08/04/02  02:59a            67,108,864 pagefile.sys
05/20/01  06:10a        <DIR>          Program Files
08/04/02  04:31a        <DIR>          TEMP
04/30/02  02:33p        <DIR>          Test
10/15/00  04:06p        <DIR>          VIRUSES
05/24/02  06:22p        <DIR>          WINNT
05/24/02  06:22p                    92 WINNTdun.bat
               16 File(s)     67,108,956 bytes
                             489,009,152 bytes free
Sun Aug  4 04:32:37 2002


D:\>ipconfig
Sun Aug  4 04:32:43 2002



Windows NT IP Configuration




Ethernet adapter DE5284:




         IP Address. . . . . . . . . : 192.168.0.1


         Subnet Mask . . . . . . . . : 255.255.0.0


         Default Gateway . . . . . . : 192.168.0.1



PPP adapter NdisWan3:




         IP Address. . . . . . . . . : 0.0.0.0


         Subnet Mask . . . . . . . . : 0.0.0.0


         Default Gateway . . . . . . :


Sun Aug  4 04:32:43 2002


D:\>net share
Sun Aug  4 04:32:47 2002


Share name   Resource                        Remark



-------------------------------------------------------------------------------
IPC$                                         Remote IPC
C$           C:\                             Default share
D$           D:\                             Default share
G$           G:\                             Default share
Log$         D:\Log
ADMIN$       D:\WINNT                        Remote Admin
Log          D:\Log
The command completed successfully.



Sun Aug  4 04:32:47 2002


D:\>dir \log >> dirlog.txt
Sun Aug  4 04:33:52 2002
Sun Aug  4 04:33:52 2002


D:\>echo "The user see no display because he sent the output to a file"
Sun Aug  4 04:34:39 2002
"The user see no display because he sent the output to a file"
Sun Aug  4 04:34:39 2002


D:\>type dirlog.txt
Sun Aug  4 04:34:45 2002
  Volume in drive D is D
  Volume Serial Number is 0480-D01C


  Directory of D:\log


08/04/02  04:20a        <DIR>          .
08/04/02  04:20a        <DIR>          ..
04/30/02  02:37p                 3,819 adam.log
09/25/00  08:31p                   373 bind.log
05/20/01  05:46a                 6,917 getright.log
08/04/02  02:50a               131,546 IAMDB.RDB
09/25/00  08:31p                    41 restart.log
08/04/02  04:20a                   177 Scan Viruses.lnk
09/25/00  08:31p                    36 shutdown.log
09/25/00  08:31p                   104 startup.log
04/29/02  02:56p                   218 test.bat
04/30/02  02:33p                 3,721 test.txt
07/24/01  11:26a                 5,553 ZALog.txt
               14 File(s)        153,044 bytes
                             489,005,568 bytes free
Sun Aug  4 04:34:46 2002


D:\>dir
Sun Aug  4 04:34:51 2002
  Volume in drive D is D
  Volume Serial Number is 0480-D01C


  Directory of D:\


08/04/02  04:31a        <DIR>          commandlog
06/25/02  12:57p        <DIR>          Dev
08/04/02  04:33a                   886 dirlog.txt
12/25/00  09:34p        <DIR>          downloads
08/04/02  04:20a        <DIR>          Log
08/04/02  04:21a        <DIR>          LogAgent 2.0
01/02/01  03:57p        <DIR>          movies
07/24/01  12:59p        <DIR>          Musique
08/04/02  02:42a        <DIR>          NONE
06/25/02  01:59p        <DIR>          NTRESKIT
08/04/02  02:59a            67,108,864 pagefile.sys
05/20/01  06:10a        <DIR>          Program Files
08/04/02  04:31a        <DIR>          TEMP
04/30/02  02:33p        <DIR>          Test
10/15/00  04:06p        <DIR>          VIRUSES
05/24/02  06:22p        <DIR>          WINNT
05/24/02  06:22p                    92 WINNTdun.bat
               17 File(s)     67,109,842 bytes
                             489,004,544 bytes free
Sun Aug  4 04:34:51 2002


D:\>cd commandlog
Sun Aug  4 04:34:57 2002
Sun Aug  4 04:34:57 2002


D:\commandlog>dir
Sun Aug  4 04:34:59 2002
  Volume in drive D is D
  Volume Serial Number is 0480-D01C


  Directory of D:\commandlog


08/04/02  04:31a        <DIR>          .
08/04/02  04:31a        <DIR>          ..
08/04/02  04:26a               655,520 cmd.exe
08/04/02  04:20a                 8,726 comlog.pl
08/04/02  04:10a                18,433 comlog.txt
05/13/02  02:42p                 1,506 command logger.txt
02/11/02  11:47a                   971 pseudo code.txt
08/04/02  04:28a                   583 Shortcut to cmd.exe.lnk
05/30/02  02:04p                    35 systempath.txt
07/21/02  03:27p                   878 test.txt
               12 File(s)        900,833 bytes
                             489,003,520 bytes free
Sun Aug  4 04:34:59 2002


D:\commandlog>copy cmd.exe root.exe
Sun Aug  4 04:35:44 2002
         1 file(s) copied.
Sun Aug  4 04:35:44 2002


D:\commandlog>exit
Sun Aug  4 04:35:50 2002



Current thread: