My usual disclaimer:
Realizing that i'm not a master at obfu, the following code may or may not be more difficult to parse than the original. But i had fun with the exercise, and hopefully this will help others a bit as well...
That being said, here's another Attempted Helpfulness...
First of all, let's seperate that obfu into some proper white-spacing to see where to begin. My formatting attempts produced:
#/usr/bin/perl -w
use strict;
$_[$_]=0 for 0..7;
my$i;
for my$a(grep{s@^00@@}
unpack'B8'x28,
join'',
map{chr}
split/\*+/,
q{61*31*28*32*20*40*25*63*63*9*52*58*49*18*30*47*20*2*10*4*8*63*63*1*3
+6*2*13*30}
){
$i=0;
grep{$_[$i++].=$_}split//,$a;
length$_[0]==8 && print pack'B8',$_ for@_;
length$_[0]==8 && grep{$_=0}@_;
}
print"\n";
Not to nitpick, but here's a few points:
- Doing extra work for initialization, while nice (and in this case necessary), let's the reader see where you're starting from.
- Checking against explicit values let's the reader know explicitly what a value is expected to be, allowing them to trace the code more easily
- Redundant code amalgamates chunks of code that are easier to understand
- Using built-in functions rather than features gives the reader explicit behavior
- Using explicit delimiters for data is a tad unsubtle
- Using $_ where available makes it to that readers can't always see where you're referencing it, as opposed to using an explicit loop value (for your for loop)
Those were the points that i most thought worthwhile to go through, unfortunately it takes a bit for some of them. Here are some iterations that show one possible direction for the code...
1
Alright, that splitting on asterisk has to go bye-bye... $_[$_]=0 for 0..7;my$i;
for my$a(grep{s@^00@@}
unpack'B8'x28,
join'',
map{chr}
'61312832204025636309525849183047200210040863630136021330'=~/
+../g
){
$i=0;
grep{$_[$i++].=$_}split//,$a;
length$_[0]==8 && print pack'B8',$_ for@_;
length$_[0]==8 && grep{$_=0}@_;
}
print"\n";
2
Change the initialization of @_. My penchant is to use split, and it
seems that in perl 5.8 warnings doesn't complain about split's
moving things to @_ anymore :)
NOTE: have to wrap the code in an anonymous sub block in order
to use the split trick...sub{split//,'0'x6;my$i;
for my $a(grep{s@^00@@}
unpack'B8'x28,
join'',
map{chr}
'61312832204025636309525849183047200210040863630136021330'=~/
+../g
){
$i=0;
grep{$_[$i++].=$_}split//,$a;
length$_[0]==8 && print pack'B8',$_ for@_;
length$_[0]==8 && grep{$_=0}@_;
}print"\n"}->()
3
Use the $_ default variable for the for loop, and stop using split
for the grep. Also note how the $_ inside of the grep doesn't need
to be changed :)sub{split//,'0'x6;my$i;
for (grep{s@^00@@}
unpack'B8'x28,
join'',
map{chr}
'61312832204025636309525849183047200210040863630136021330'=~/
+../g
){
$i=0;
grep{$_[$i++].=$_}/./g;
length$_[0]==8 && print pack'B8',$_ for@_;
length$_[0]==8 && grep{$_=0}@_;
}print"\n"}->()
4
Get rid of $i, since it requires declaration and initializaion...
($; requires initialization, but it's hopefully less obvious)
move the grep to a map (my paranoia :)sub{split//,'0'x6;$;--;
for (grep{s@^00@@}
unpack'B8'x28,
join'',
map{chr}
'61312832204025636309525849183047200210040863630136021330'=~/
+../g
){
map{$_[($;+=1)%=6].=$_}/./g;
length$_[0]==8 && print pack'B8',$_ for@_;
length$_[0]==8 && grep{$_=0}@_;
}print"\n"}->()
5
Get rid of the redundant length checks...sub{split//,'0'x6;$;--;
for (grep{s@^00@@}
unpack'B8'x28,
join'',
map{chr}
'61312832204025636309525849183047200210040863630136021330'=~/
+../g
){
map{$_[($;+=1)%=6].=$_}/./g;
for (@_) {
length==8 && (print(pack'B8',$_) and ($_=0))
}
}print"\n"}->()
6
Combine the $_ assignment and print, stop using length to check,
add a small bit of misdirection (using ?: instead of &&), and since
we only have one statement, move to a postfix for
some notes:
- print returns 1 if successful, so -1+print returns 0
- The $_ assignment happens after the print, so we don't sully what we're printing beforehand
- In the for(@_) loop $_ will be the elements of
@_, and /./g in array context returns each element. Wrapping that like @{[/./g]} and using it in scalar context makes it evaluate numerically returning the length of $_...
- Using length-8 instead of length==8 makes it so that the false section of the ?: will do the processing, but there's no longer an explicit check against a number...
- In the ?:, ?? is a regular expression matching on $_.
sub{split//,'0'x6;$;--;
for (grep{s@^00@@}
unpack'B8'x28,
join'',
map{chr}
'61312832204025636309525849183047200210040863630136021330'=~/
+../g
){
map{$_[($;+=1)%=6].=$_}/./g;
@{[/./g]}-8???:($_=-1+print pack'B8',$_)for@_
}print"\n"}->()
7 (final version)
Now because there's no reason to give people the easiest time
figuring out what's going on, change some delimiters and collapse
it again into a few lines of text (again using my predilection for even lines of code in obfuscations)...sub{split q,,,q;0;x6;$;--;for(grep s,^00,,,unpack'B8'x28,join'',map ch
+r,q,61
312832204025636309525849183047200210040863630136021330,=~m,..,g){map$_
+[($;+=
1)%=6].=$_,m,.,g;@{[m,.,g]}-8???:($_=-1+print pack'B8',$_)for@_}print$
+/}->()
It still compiles and runs under strict and warnings, but now it's more difficult to break it into chewable chunks. Anyway, that's the process i went through after running your obfu. Sorry about the long post, but with any luck it was helpful...
nuf evah,
jynx
update: fixed a typo (thanx to Ferret for catching it)
Also, i would like to note that this was an obfuscation before
i twisted it. The reason is because the algorithm is
difficult to comprehend. All i did was add some window dressing
to it. i hope i didn't sound critical in the above post, because this was a good
first obfu before the window dressing :-) |