Hide evil code - print files containing a given string anywhere in a directory tree The point of this puzzle is to learn how a malicious code can be hidden and discovered in a program.

A person is asking the question:


  Plz give me some code that how can I search a file may be in Present
  Directory or in its Sub-Directories.


(This is a variant of a real question I've seen posted on one site.)

To be more specific: The OP wants you to write a program that accepts a string and a directory. It will traverse all files in the directory and recursively all its subdirectories. For each file it will check if the file contains the string, and if it does, will print the name of the file. (The program can have additional features as long as they are relevant to the main goal, if you wish.) There are no requirements on the traversal order.

However, the main task of this puzzle is to hide into the program additional code that will make a fool of the person that asks for the program in the eyes of its users/colleagues/boss/etc. For example, print a humiliating text at some point, such as: The author of the program doesn't know how to program, should return his/her diploma and get fired. Be creative.

Rules:


The solution must not be harmful (except making fool of the OP, of course). It must not do any irreversible damage to end users (no stuff like rm -rf)! Such solutions will be disqualified.
The trolling stuff should be hidden so that the OP won't find it easily.
It shouldn't be obvious that you're trolling the OP. The code should look genuine.
The solution must come with a proper explanation how it trolls the OP so that everybody can learn something from your solution. The explanation should be hidden in a hidden-until-you-click text (spoilers). When judging, try to discover the trolling without looking at the explanation and vote for those that are difficult to discover.
Also try to hide the trolling from the OP if (s)he tries to run the code a few times. Perhaps start trolling only after a particular date, or under some conditions that a sloppy programmer won't test. Be creative and don't forget to explain the trick.
Don't just create a script using existing tools such as grep or find. Write the program from scratch. Better avoid libraries and prefer low-level calls - this will make the code more complex and gives you the opportunity to hide the evil stuff there.


This is a popularity-contest. Please judge according the above points.
Here is my solution (in Perl):

#! /usr/bin/perl -w

use Cwd 'abs_path';

# Check the command line arguments
my $F = abs_path($0);
if ($#ARGV!=1) {
    print "Usage: ".$F." &lt;dir&gt; &lt;expr&gt;\n";
    exit(1);
}

# The first argument is the directory
my @u = (abs_path($ARGV[0]));
# Check for trailing slash
my $c = substr $u[0], -1, 0;


# Iterate on the files
for my $k ( @u ) {
    if (-d $k &amp;&amp; -r $k &amp;&amp; -x $k) {
        # If the file is a directory, we add its sub-files to the list of files
        push (@u, glob($k.($c eq "/" ? "*" : "/*")));
    } elsif (-f $k &amp;&amp; -r $k) {
        # If it's a regular file, we open it (read-only ) 
        open(FILE, "&lt;", $k) or die "cannot open $k : $!";
        # Do we have a match
        my $y=0;
        # Number of matches
        my $o=0;
        # We iterate on the lines
        while (&lt;FILE&gt;) {
            # We check if the line match using regular expressions, and we update the number of matches
            (/$ARGV[1]()/ || $F eq $k &amp;&amp; /y .([F c-y])/) &amp;&amp; (($c,$y,$o)=($c.$1,1,$o+1))
        }
        # Do we need to use the plural form of "match"
        my $u=$o&gt;1;
        # If we have a match, we print it
        if ($y) {
            print "$c$k : $o match".($u?"es\n":"\n");
        }
        # Close the file (opened read-only ) 
        close(FILE) or die "cannot close $k : $!";
    }
}


The first argument of the program is the directory and the second argument is the string we are looking for. The program also show the number of matches in each file.

Here is how to search "VGA" in /etc:

$ ./mygrep.pl /etc VGA
/etc/alternatives/mplayer : 7 matches
/etc/alternatives/pinentry : 1 match
/etc/alternatives/pinentry-x11 : 1 match
/etc/alternatives/www-browser : 1 match
/etc/bumblebee/xorg.conf.nouveau : 2 matches
/etc/bumblebee/xorg.conf.nvidia : 2 matches
/etc/default/console-setup : 2 matches
/etc/htdig/english.0 : 1 match
/etc/X11/X : 6 matches
/etc/laptop-mode/conf.d/video-out.conf : 3 matches
$


And now, here is the trick :


   The program works exactly as advised as long as it doesn't encounter itself in the files. As soon as it encounters itself, it starts to prefix each file found with insanity.
 Let's copy some files in the current directory and try again :
 $ cp /etc/default/console-setup /etc/bumblebee/xorg.conf.nouveau /etc/bumblebee/xorg.conf.nvidia /etc/htdig/english.0 ./
$ ./mygrep.pl ./ VGA
/tmp/mygrep/console-setup : 2 matches
/tmp/mygrep/english.0 : 1 match
Fuck you /tmp/mygrep/mygrep.pl : 9 matches
Fuck you /tmp/mygrep/xorg.conf.nouveau : 2 matches
Fuck you /tmp/mygrep/xorg.conf.nvidia : 2 matches
$
 This is due to this code:
 $F eq $k &amp;&amp; /y .([F c-y])/
 It tests if the current file is the running program, and if it is, it extract some part of the program with a regexp and affects it to $c with
 $c = $c.$1
 What is extracted by the regexp are the variable declarations (variables are named $F, @u, $c, $k, $y, $o, $u) and two spaces from the comments.
 I had to do that to keep it hidden, even if the program is relatively short.