#!/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;
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Spoiler: YAJAPH
by ambrus (Abbot) on Jun 21, 2004 at 21:14 UTC | |
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 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. | [reply] [d/l] [select] |
by Dietz (Curate) on Jun 22, 2004 at 05:34 UTC | |
Wow...! I'm really impressed. To code is one thing, but to explain others code is ingenius. Your explantion is way clearer as I thought it during coding. Congrats! I bow to you. | [reply] |