Obfuscated Perl



I have a rather strange relationship with the programming language perl. I've never used it for doing anything beyond quick and dirty scripts, and even then, I haven't done much with those. On the other hand, the regular expression engine built into perl makes it ideal to do obfuscated programming, and I've done a number of those. Most of these have been created with David Chan, who's more ept at perl programming than I, with me taking on more of the algorithms side, and he taking more of the programming side.

The Perl Journal

Our first program was intended to be an entry into The Perl Journal's obfuscated perl contest (which was unfortunately shut down before we could submit it).

#!/usr/bin/perl -w
$_=$0;s|.*\W||;sub K{s;[^a-z\n ];"/".ord($&)."j";ge;y; 0-9k-uyo/jv-xz
;`ja-|;d;s\.\for($O=0,$o=-96+ord$&;$o>7-$O;$o-=7-$O++){}($o+=$O)+$O<5
|5<$O?"$o.$O":"$O.$o"\eg,($O=$_)=~y;70-{.;\\|/ ;,y;2-}10;_\\|/_ ;;"$_
$O\n"}if(/k/){print K while<>;exit}(?o?&&open O,"|-")?(y|_| |,print O
K):do{s`.\..`'esg'&$&`eg,y,'|/EDd%G\\,50-{,,s,(.*\n)(.*\n?),$1|$2,eg,
s;(.)"(.);chr 125-(7.5-($1>$2?$2:$1))**2/2+abs$2-$1;ge,y}`j-|} k-uy\b
jv-xz},s!\n([ka-i]+)j!$_=$1;y;ka-{;0-};;chr!esg,print while$_=<>.<>};
close"O"

The program, called "The_Perl_Journal", prints "The Perl Journal", using interprocess communication, and semaphores. Just like gzip, it behaves differently depending on what its name is; try creating symlinks/copies called "sink" and "swim".

In case you can't work out what it does, there are hints, and solution1 and solution2.

More Perl

Continuing the theme set by the above program, we continued into similar areas...

perl -ple'(/[^.-\s]/)?(s.[^a-z0-9\s].$_=unpack"B*",$&;y;01;\n`;;lc.ge,y.
`-z0-9.ajzges}mqo{hrkxypibuw|vntfdc@PX\\^_OGCA.,s-\S-(unpack"B*",$&)." "
-ge,s-\b01+0--g,y,01,-.,):(y,-.,01,,s,([01]+),0 .1x(6-length$1).0 .$1,ge
,s-\b([01]+) ?-pack"B*",$1-ge,y.ajzges}mqo{hrkxypibuw|vntfdc@PX\\^_OGCA.
`-z0-9.,s-([\n`]{8})-$_=$1;y;\n`;01;;pack"B*",$_-ge)'&& You fit it in 4

Alas, the program didn't quite manage to fit it into signature size, as the comment at the end shows. On the other hand, it does have the ability to handle non-standard characters and to autodetect what conversion it's supposed to be performing. Why not give it a spin?

Tetris

The next program we created was a perl implementation of Tetris, in under 640 bytes. You use the arrow keys to control the pieces, and space to drop them. It comes complete with higher score for scoring multiple lines and the ability to move your piece after you've dropped it using space.

#!/usr/bin/perl
`stty cbreak -echo`;END{`stty sane`}$;=0 .($p=" "x10)."0 \n";sub
j{/$*/&&return,s/\S/0/g,$a=$_,s/0/\e[7m \e[m/g,s/^/$p/g,s/ / /g
,print"\e[;H$_"for$b|$k&$*x length$b;$a}sub n{$_=qw(@J@Eon@J@@J@
dJbEOEHJa HJdEOEaJb @N@Mog@K@ @OEEOJ@@J EO@JoeJ@@ @Oo@oO)[rand
7];$*=$|=s/.../````$&``````\n/g;s/n`/eE/;$k=$_;j}print"\e[H\e[J"
;$b=$;x20 .($;^"\cP"x12);for(n;@_=($k,$*);!$||++$i>6**6/(@ARGV?
$ARGV[0]:1)?$_="B":do{(select$t=chr 1,"","",0)[0]||next;sysread
STDIN,$_,1;$|^=/ /}){$*=1 if($*<<=/A/)>8;$i=$k=" $p \n$k"if/B/;
$k=~s/(.*)`/`$1/g if/C/;$k=~s/`(.*)/$1`/g if/D/;j or($k,$*)=@_,
/B/and$|++and$b=$;x(($b=j)=~s/0{12} \n//g).$b,n||exit}

Unfortunately, the program comes up with a warning when run under -w, which we were unable to prevent due to space constraints, so it's being run without -w instead.

This program is somewhat harder than the others to decode - to help you, the key logic is in the for loop in line 6, which picks up the input to control the pieces using sysread in line 7. This calls subroutines j (which prints the screen) and n (which generates a new piece). The data structures in subroutine n contain the position data for the pieces in all rotated states - we don't try to rotate them on the fly.

Sokoban

One thing that I learnt when creating these programs was that the key part of any program was working out the correct data structure to encode the data in as minimalist a way as possible, and the next most important part was working out how to handle the data structure to get it to the state that you wanted it to be in. When creating a version of sokoban, David got around the first problem by using the level data from xsok. I thought this was cheating, and by dint of some creative hacking, created the following .sig sized version.

#!/usr/bin/perl -w
END{`stty sane`}`stty cbreak -echo`;$p=27;@b=split//,7x9 .60210x2 .61020602416 .
7x9;for(print"\e[H\e[J";$_=join"",@b and/2/&s/./(" ",qw{:: [] XX <> <>},"#\n#",
"#")[$&]/ge&print"\e[;H$_";$p+=$i){read STDIN,$_,1;$i=(-5,5,1,-1)[-65+ord]or$i=0
;(*y,*z)=\@b[$p+$i,$p+2*$i];$y>3|$z>1&$y>1&&redo;$z|=($y+=4)&2;$y&=~2;@b[$p]-=4}

The program contains a level which is pleasingly non-trivial given its size - a number of people have got stuck the first time the tried it.

If you have any questions or comments about these programs (or ideas about how to make them smaller / more featurefull), then do feel free to contact me - I'd be interested to hear what you have to say.


This page was last updated on 1st May 2006, and is best viewed with any browser that can read xhtml. Feel free to contact me with any comments you may have.