#!/usr/bin/perl -w # Just another Perl hacker
use strict;my($x,$y,@x)="0321008106149147148"
."06412914214314813613"."3146064112133146140"
."06413612913113913314"."6142112114105110116"
;$y=(pack("C*"=>,=>,@x[local$|..+$#x-+1])),$_
-=substr$x,substr($x,@x-21,,@++$|+1)=>3,=>for
(@x=map/([^\$"(?{\$_=~|index@x|e})]{1,3})$"$"
/xg=>substr($x.=1,@x+7,75+$|));$_=$x?$y:@x;$x
=substr($x,@x-41,@x-10);($x=~s/(.{2,3})/pack'
c*'=>$1/eg);$y="There=>is=>no=>spoon";eval$x;
Spoiler! This is the solution of the obfu.
First, I've reformatted the code and removed some obvious dead code
(there is no spoon).
What the code does is still not obvious, this means that I've started
dechyphering a good obfu, with a lot of twists.
Now we can do a lot of small changes in the code,
chechking that the obfu still works after each step.
Then we replace local $| or 0 with
0;
also @+ (in scalar context) by 2,
as the above regular expression has one set of capturing parenthesis.
Let's look at that regular expression further.
The other parenthesis in the regexp seems to be a
(?{ }) code block, but it's really not, as it's in a character
class. I found that a very good obfu idea.
As that character class is negated, and its left side ($x)
contains only numbers, we can safely replace the character class with a dot.
We can also delete $"$" from the regex,
which would stringify to two spaces, but is ignoder by the /x flag.
We can eliminate the map in the for's argument because it
only has two arguments.
Now we can factor the $x.=1 assignment to the initial assignment
of $x, as it's only executed once.
Let's rename @x to @z for convinience, so
that I don't confuse it with @z.
We now have
From @z+7 we can remove @z as @z is
unassigned at that time. As substr($x, @z+7, 75) is 75 long,
the regexp will match 25 times, so we can simplify @z-21
in the for body to 4.
Thus, we get substr($x, 4, 2) as the inner substr,
which is simply zero, so the outer substr($x, 0, 3) evaluates
to 32.
Seeing that the second statement in the for body
is just $_ -= 32; we can move the first statement out
the loop (as it's idempotent and does not depend on the induction variable):
We can change $x ? $y : @z to $y, as
$x is true.
We can also substitute the other two occurences of scalar @z
below, thus the fourth substr becomes
substr ($x, -16, 15) which is
"112114105110116".
Now we've got this:
Which is not nearly as much frightening as the original one.
We can already find out what the last line (eval $x;)
does. You see that above it $x=~s/(.{2,3})/pack 'c*', $1/eg
encodes "112114105110116" as decimal character codes,
which is chr(112) ==> "p", chr(114) ==> "r", ..., "print"!
Thus, the last four lines just print $y.
The code above that takes substr($x, 7, 75),
which is
"106149147148064129142143148136133146064112133146140064136129".
"131139133146142",
and converts each three digits to character, but first subtracts 32 from
each number. Note that it ignores the last number, which is caused by
the slicing @z[0..$#z-1].
Thus we get
106 149 147 148 064 129 142 143 148 136 133 146 064 112
133 146 140 064 136 129 131 139 133 146 142 ,
subtracting 32 from each we get
74 117 115 116 32 97 110 111 116 104 101 114 32 80 101 114
108 32 104 97 99 107 101 114 110
eval $x;
Which is not nearly as much frightening as the original one.
We can already find out what the last line (eval $x;)
does. You see that above it $x=~s/(.{2,3})/pack 'c*', $1/eg
encodes "112114105110116" as decimal character codes,
which is chr(112) ==> "p", chr(114) ==> "r", ..., "print"!
Thus, the last four lines just print $y.
The code above that takes substr($x, 7, 75),
which is
"106149147148064129142143148136133146064112133146140064136129".
"131139133146142",
and converts each three digits to character, but first subtracts 32 from
each number. Note that it ignores the last number, which is caused by
the slicing @z[0..$#z-1].
Thus we get
106 149 147 148 064 129 142 143 148 136 133 146 064 112
133 146 140 064 136 129 131 139 133 146 142 ,
subtracting 32 from each we get
74 117 115 116 32 97 110 111 116 104 101 114 32 80 101 114
108 32 104 97 99 107 101 114 110
chring each but the last one we get
"Just another Perl hacker".
Now we have solved the obfu.
The script first puts "Just another Perl hacker" in
$y, then prints it.
#!/usr/bin/perl -w
use strict;
my $x = "0321008106149147148064129142143148136133146064112133146140" .
"064136129131139133146142112114105110116";
my($y, @x);
for (
@x = map { /([^\$"(?{\$_=~|index@x|e})]{1,3})$"$"/xg }
substr($x.=1, @x+7, 75+$|)
) {
$y = (pack("C*", @x[local$|..$#x-1]));
$_ -= substr($x, substr($x, @x-21, @++$|+1), 3);
}
$_ = $x ? $y : @x;
$x = substr ($x, @x-41, @x-10);
$x=~s/(.{2,3})/pack 'c*', $1/eg;
eval $x;
#!/usr/bin/perl -w
use strict;
my $x = "0321008106149147148064129142143148136133146064112133146140" .
"0641361291311391331461421121141051101161";
my($y, @z);
@z = substr($x, @z+7, 75) =~ /(.{1,3})/xg;
for (@z) {
$y = pack("C*", @z[0..$#z-1]);
$_ -= substr($x, substr($x, @z-21, 2), 3);
}
$_ = $x ? $y : @z;
$x = substr ($x, @z-41, @z-10);
$x=~s/(.{2,3})/pack 'c*', $1/eg;
eval $x;
for (@z) { $_ -= 32; }
$y = pack("C*", @z[0..$#z-1]);
$_ = $y;
#!/usr/bin/perl -w
use strict;
my $x = "0321008106149147148064129142143148136133146064112133146140" .
"0641361291311391331461421121141051101161";
my($y, @z);
@z = substr($x, 7, 75) =~ /(.{1,3})/xg;
for (@z) { $_ -= 32; }
$y = pack("C*", @z[0..$#z-1]);
$_ = $y;
$x = "112114105110116";
$x=~s/(.{2,3})/pack 'c*', $1/eg;
eval $x;
perlmonks.org content © perlmonks.org and ambrus, Dietz
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03