http://www.perlmonks.org?node_id=192174


in reply to My first attempt at obfu


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:
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:

  1. print returns 1 if successful, so -1+print returns 0
  2. The $_ assignment happens after the print, so we don't sully what we're printing beforehand
  3. 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 $_...
  4. 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...
  5. 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 :-)