laziness, impatience, and hubris PerlMonks

### SPOILER! (Guildenstern) Re: My 2 cents worth

by Guildenstern (Deacon)
 on May 04, 2001 at 19:51 UTC ( #78000=note: print w/replies, xml ) Need Help??

in reply to My 2 cents worth

I figure I might as well take a stab at some more of Erudil's code after deciphering How to (ab)use substr. I don't in any way mean intend these spoilers to demean the work Erudil has done. I've discovered that it's far, far easier to deconstruct than construct. I'm not even sure I could come up with the thought processes necessary to create the obfus.

Now, on to the spoiler!

Okay. Usually the first step in understanding an obfuscation is to reformat the code so it's more readable. With this example, however, we don't quite want to do that yet. There are only a couple of lines at the very end that are of interest to us at the momemt. Let's break those out.

```#!/usr/bin/perl -w           # my 2 cents worth

use strict;
\$_='\$_=tue(\$=+(two
(\$;)>>(two(\$;)>>2+2))){tue
(too(two(tue(\$=+(two(\$;)>>(two
(\$;)>>2+2))))+(two(\$;)>>2+2))){tue
(too(two(tue(\$=+(two(\$;)>>(two(\$;)>>2+
2))))+(two(\$;)>>2+2))-2){tue(too(two(tue
(\$=+(two(\$;)>>(two(\$;)>>2+2)))))){tue(too(
too(two(\$;)>>(two(\$;)  >>2+2)))){tue(too(\$=+
+(two(\$;)>>2+2))){tue    ((two(\$;)<<2)-2){tue
((two(\$;)<<2)-(two(\$;     )>>2+2)){tue(too(two(
tue(\$=+(two(\$;)>>(two     (\$;)>>2+2)))))){{tue
(too(\$=+(two(\$;)>>2)+
(two(\$;)>>2+2))){{tue
(too(\$=+(two(\$;)>>2)-
2)){{{tue(too(\$=+(two
(\$;)>>(two(\$;)>>2+2))
-2)){tue(too(too(two(
\$;)>>(two(\$;)>>2+2)))
){tue(too(too(too(too
(two(\$;)>>(two(\$;)>>2
+2)))))){{tue(too(\$=+
(two(\$;)>>2)-2))}tue(
too(\$=+(two(\$;)>>(two
(\$;)>>2+2))-2)){tue((
two(\$;)<<2)-((two(\$;)
>>2>>2)<<2))}tue(too(
too(two(\$;)>>(two(\$;)
>>2+2))))}}tue(too(\$=
+(two(\$;)>>2)+(two(\$;)>>2+2)))}}tue(too(\$=+(
two(\$;)>>2+2)))}}tue(too((two(\$;)<<(two(\$;)>>
2>>2))+(two(\$;)>>2)))}}}tue((two(\$;)<<2)-((two
(\$;)>>2>>2)<<2)-(two(\$;)>>2>>2))}}}tue(too(\$=+(
two(\$;)>>2)-2))}}}tue(too(\$=+(two(\$;)>>(two(\$;)
>>2+2))-2))}}}tue(too(too(two(\$;)>>(two(\$;)>>2+
2)))+(two(\$;)>>(two(\$;)>>2+2))-2);';

y;{};..;sd;
s;two;ord;g;
s;too;hex;g;
s;tue;chr;g;
eval;
print;

We can pull these lines out because if you look closely, you'll see that everything else after the use strict; to the y is an assignment to \$_, and is essentially one line. The extracted lines may look a bit strange at first, but remember that Perl lets you use other delimeters in regular expressions. The last few lines can be easily rewritten as this:

```y/{}/../sd;
s/two/ord/g;
s/too/hex/g;
s/tue/chr/g;

Now, we apply the y to translate all of the braces to periods. This is why we didn't want to format the code right off the bat - it wouldn't make much sense and gets messy quickly. After translation, we essesntially have:

```               \$_='\$_=tue(\$=+(two
(\$;)>>(two(\$;)>>2+2))).tue
(too(two(tue(\$=+(two(\$;)>>(two
(\$;)>>2+2))))+(two(\$;)>>2+2))).tue
(too(two(tue(\$=+(two(\$;)>>(two(\$;)>>2+
2))))+(two(\$;)>>2+2))-2).tue(too(two(tue
(\$=+(two(\$;)>>(two(\$;)>>2+2)))))).tue(too(
too(two(\$;)>>(two(\$;)  >>2+2)))).tue(too(\$=+
+(two(\$;)>>2+2))).tue    ((two(\$;)<<2)-2).tue
((two(\$;)<<2)-(two(\$;     )>>2+2)).tue(too(two(
tue(\$=+(two(\$;)>>(two     (\$;)>>2+2)))))).tue
(too(\$=+(two(\$;)>>2)+
(two(\$;)>>2+2))).tue
(too(\$=+(two(\$;)>>2)-
2)).tue(too(\$=+(two
(\$;)>>(two(\$;)>>2+2))
-2)).tue(too(too(two(
\$;)>>(two(\$;)>>2+2)))
).tue(too(too(too(too
(two(\$;)>>(two(\$;)>>2
+2)))))).tue(too(\$=+
(two(\$;)>>2)-2)).tue(
too(\$=+(two(\$;)>>(two
(\$;)>>2+2))-2)).tue((
two(\$;)<<2)-((two(\$;)
>>2>>2)<<2)).tue(too(
too(two(\$;)>>(two(\$;)
>>2+2)))).tue(too(\$=
+(two(\$;)>>2)+(two(\$;)>>2+2))).tue(too(\$=+(
two(\$;)>>2+2))).tue(too((two(\$;)<<(two(\$;)>>
2>>2))+(two(\$;)>>2))).tue((two(\$;)<<2)-((two
(\$;)>>2>>2)<<2)-(two(\$;)>>2>>2)).tue(too(\$=+(
two(\$;)>>2)-2)).tue(too(\$=+(two(\$;)>>(two(\$;)
>>2+2))-2)).tue(too(too(two(\$;)>>(two(\$;)>>2+
2)))+(two(\$;)>>(two(\$;)>>2+2))-2);';

s/two/ord/g;
s/too/hex/g;
s/tue/chr/g;
eval;
print;

Next, we apply the s/// statements. This is where most of the trickery of this obfuscation comes in to play. I'm sure a lot of people (myself included) looked at this the first time wondering where the heck the subs two, tue, and too were declared. Turns out they're just placeholders for ord, chr, and hex. The next step's result is:

```               \$_='\$_=chr(\$=+(ord
(\$;)>>(ord(\$;)>>2+2))).chr
(hex(ord(chr(\$=+(ord(\$;)>>(ord
(\$;)>>2+2))))+(ord(\$;)>>2+2))).chr
(hex(ord(chr(\$=+(ord(\$;)>>(ord(\$;)>>2+
2))))+(ord(\$;)>>2+2))-2).chr(hex(ord(chr
(\$=+(ord(\$;)>>(ord(\$;)>>2+2)))))).chr(hex(
hex(ord(\$;)>>(ord(\$;)  >>2+2)))).chr(hex(\$=+
+(ord(\$;)>>2+2))).chr    ((ord(\$;)<<2)-2).chr
((ord(\$;)<<2)-(ord(\$;     )>>2+2)).chr(hex(ord(
chr(\$=+(ord(\$;)>>(ord     (\$;)>>2+2)))))).chr
(hex(\$=+(ord(\$;)>>2)+
(ord(\$;)>>2+2))).chr
(hex(\$=+(ord(\$;)>>2)-
2)).chr(hex(\$=+(ord
(\$;)>>(ord(\$;)>>2+2))
-2)).chr(hex(hex(ord(
\$;)>>(ord(\$;)>>2+2)))
).chr(hex(hex(hex(hex
(ord(\$;)>>(ord(\$;)>>2
+2)))))).chr(hex(\$=+
(ord(\$;)>>2)-2)).chr(
hex(\$=+(ord(\$;)>>(ord
(\$;)>>2+2))-2)).chr((
ord(\$;)<<2)-((ord(\$;)
>>2>>2)<<2)).chr(hex(
hex(ord(\$;)>>(ord(\$;)
>>2+2)))).chr(hex(\$=
+(ord(\$;)>>2)+(ord(\$;)>>2+2))).chr(hex(\$=+(
ord(\$;)>>2+2))).chr(hex((ord(\$;)<<(ord(\$;)>>
2>>2))+(ord(\$;)>>2))).chr((ord(\$;)<<2)-((ord
(\$;)>>2>>2)<<2)-(ord(\$;)>>2>>2)).chr(hex(\$=+(
ord(\$;)>>2)-2)).chr(hex(\$=+(ord(\$;)>>(ord(\$;)
>>2+2))-2)).chr(hex(hex(ord(\$;)>>(ord(\$;)>>2+
2)))+(ord(\$;)>>(ord(\$;)>>2+2))-2);';

eval;
print;

If you look at the first line, \$_ is being assigned a string that starts with "\$_=". \$_ is then eval'ed, which results in \$_ being assigned the value of the string. It's almost recursive. It is also easy to remove without affecting the operation of the script.

```               \$_=chr(\$=+(ord
(\$;)>>(ord(\$;)>>2+2))).chr
(hex(ord(chr(\$=+(ord(\$;)>>(ord
(\$;)>>2+2))))+(ord(\$;)>>2+2))).chr
(hex(ord(chr(\$=+(ord(\$;)>>(ord(\$;)>>2+
2))))+(ord(\$;)>>2+2))-2).chr(hex(ord(chr
(\$=+(ord(\$;)>>(ord(\$;)>>2+2)))))).chr(hex(
hex(ord(\$;)>>(ord(\$;)  >>2+2)))).chr(hex(\$=+
+(ord(\$;)>>2+2))).chr    ((ord(\$;)<<2)-2).chr
((ord(\$;)<<2)-(ord(\$;     )>>2+2)).chr(hex(ord(
chr(\$=+(ord(\$;)>>(ord     (\$;)>>2+2)))))).chr
(hex(\$=+(ord(\$;)>>2)+
(ord(\$;)>>2+2))).chr
(hex(\$=+(ord(\$;)>>2)-
2)).chr(hex(\$=+(ord
(\$;)>>(ord(\$;)>>2+2))
-2)).chr(hex(hex(ord(
\$;)>>(ord(\$;)>>2+2)))
).chr(hex(hex(hex(hex
(ord(\$;)>>(ord(\$;)>>2
+2)))))).chr(hex(\$=+
(ord(\$;)>>2)-2)).chr(
hex(\$=+(ord(\$;)>>(ord
(\$;)>>2+2))-2)).chr((
ord(\$;)<<2)-((ord(\$;)
>>2>>2)<<2)).chr(hex(
hex(ord(\$;)>>(ord(\$;)
>>2+2)))).chr(hex(\$=
+(ord(\$;)>>2)+(ord(\$;)>>2+2))).chr(hex(\$=+(
ord(\$;)>>2+2))).chr(hex((ord(\$;)<<(ord(\$;)>>
2>>2))+(ord(\$;)>>2))).chr((ord(\$;)<<2)-((ord
(\$;)>>2>>2)<<2)-(ord(\$;)>>2>>2)).chr(hex(\$=+(
ord(\$;)>>2)-2)).chr(hex(\$=+(ord(\$;)>>(ord(\$;)
>>2+2))-2)).chr(hex(hex(ord(\$;)>>(ord(\$;)>>2+
2)))+(ord(\$;)>>(ord(\$;)>>2+2))-2);

print;

Now we can start applying some formatting to make it manageable. Let's break each line on a period because that will make the most sense as we progress.

```\$_= chr(\$=+(ord(\$;)>>(ord(\$;)>>2+2))).
chr(hex(ord(chr(\$=+(ord(\$;)>>(ord(\$;)>>2+2))))+(ord(\$;)>>2+2))).
chr(hex(ord(chr(\$=+(ord(\$;)>>(ord(\$;)>>2+2))))+(ord(\$;)>>2+2))-2).
chr(hex(ord(chr(\$=+(ord(\$;)>>(ord(\$;)>>2+2)))))).
chr(hex(hex(ord(\$;)>>(ord(\$;)>>2+2)))).
chr(hex(\$=+ +(ord(\$;)>>2+2))).
chr((ord(\$;)<<2)-2).
chr((ord(\$;)<<2)-(ord(\$;)>>2+2)).
chr(hex(ord(chr(\$=+(ord(\$;)>>(ord(\$;)>>2+2)))))).
chr(hex(\$=+(ord(\$;)>>2)+(ord(\$;)>>2+2))).
chr(hex(\$=+(ord(\$;)>>2)-2)).
chr(hex(\$=+(ord(\$;)>>(ord(\$;)>>2+2))-2)).
chr(hex(hex(ord(\$;)>>(ord(\$;)>>2+2)))).
chr(hex(hex(hex(hex(ord(\$;)>>(ord(\$;)>>2+2)))))).
chr(hex(\$=+(ord(\$;)>>2)-2)).
chr(hex(\$=+(ord(\$;)>>(ord(\$;)>>2+2))-2)).
chr((ord(\$;)<<2)-((ord(\$;)>>2>>2)<<2)).
chr(hex(hex(ord(\$;)>>(ord(\$;)>>2+2)))).
chr(hex(\$=+(ord(\$;)>>2)+(ord(\$;)>>2+2))).
chr(hex(\$=+(ord(\$;)>>2+2))).
chr(hex((ord(\$;)<<(ord(\$;)>>2>>2))+(ord(\$;)>>2))).
chr((ord(\$;)<<2)-((ord(\$;)>>2>>2)<<2)-(ord(\$;)>>2>>2)).
chr(hex(\$=+(ord(\$;)>>2)-2)).
chr(hex(\$=+(ord(\$;)>>(ord(\$;)>>2+2))-2)).
chr(hex(hex(ord(\$;)>>(ord(\$;)>>2+2)))+(ord(\$;)>>(ord(\$;)>>2+2))-2)
+;

print;

Now we can start simplifying these lines. The first step is to remove the Perl special characters. \$; is the subscript separator for multi dimension arrays. Its default is '\034', which is the decimal value 28. \$= is the number of lines per page as used in formats. It defaults to 60. Therefore, we can replace ord(\$;) with 28, and \$= with 60.

```\$_= chr(60+(28>>(28>>2+2))).
chr(hex(ord(chr(60+(28>>(28>>2+2))))+(28>>2+2))).
chr(hex(ord(chr(60+(28>>(28>>2+2))))+(28>>2+2))-2).
chr(hex(ord(chr(60+(28>>(28>>2+2)))))).
chr(hex(hex(28>>(28>>2+2)))).
chr(hex(60+ +(28>>2+2))).
chr((28<<2)-2).
chr((28<<2)-(28>>2+2)).
chr(hex(ord(chr(60+(28>>(28>>2+2)))))).
chr(hex(60+(28>>2)+(28>>2+2))).
chr(hex(60+(28>>2)-2)).
chr(hex(60+(28>>(28>>2+2))-2)).
chr(hex(hex(28>>(28>>2+2)))).
chr(hex(hex(hex(hex(28>>(28>>2+2)))))).
chr(hex(60+(28>>2)-2)).
chr(hex(60+(28>>(28>>2+2))-2)).
chr((28<<2)-((28>>2>>2)<<2)).
chr(hex(hex(28>>(28>>2+2)))).
chr(hex(60+(28>>2)+(28>>2+2))).
chr(hex(60+(28>>2+2))).
chr(hex((28<<(28>>2>>2))+(28>>2))).
chr((28<<2)-((28>>2>>2)<<2)-(28>>2>>2)).
chr(hex(60+(28>>2)-2)).
chr(hex(60+(28>>(28>>2+2))-2)).
chr(hex(hex(28>>(28>>2+2)))+(28>>(28>>2+2))-2);

print;

Now it's starting to become more manageable. The next step is to get rid of those bit shift operations. At this point, there are basically four different operations that we can replace with their values. 28>>2+2 evaluates to 1. 28<<2 equals 112, 28>>2>>2 is 1, and 28>>2 is 7. Let's make these substitutions.

```\$_= chr(60+(28>>(1))).
chr(hex(ord(chr(60+(28>>(1))))+(1))).
chr(hex(ord(chr(60+(28>>(1))))+(1))-2).
chr(hex(ord(chr(60+(28>>(1)))))).
chr(hex(hex(28>>(1)))).
chr(hex(60+ +(1))).
chr((112)-2).
chr((112)-(1)).
chr(hex(ord(chr(60+(28>>(1)))))).
chr(hex(60+(7)+(1))).
chr(hex(60+(7)-2)).
chr(hex(60+(28>>(1))-2)).
chr(hex(hex(28>>(1)))).
chr(hex(hex(hex(hex(28>>(1)))))).
chr(hex(60+(7)-2)).
chr(hex(60+(28>>(1))-2)).
chr((112)-((1)<<2)).
chr(hex(hex(28>>(1)))).
chr(hex(60+(7)+(1))).
chr(hex(60+(1))).
chr(hex((28<<(1))+(7))).
chr((112)-((1)<<2)-(1)).
chr(hex(60+(7)-2)).
chr(hex(60+(28>>(1))-2)).
chr(hex(hex(28>>(1)))+(28>>(1))-2);

print;

Now, we can make the substitutions of 28>>1 = 14 , 28<<1 = 56, and 1<<2 = 4, and clean up extra parens.

```\$_= chr(60+14).
chr(hex(ord(chr(60+14))+1)).
chr(hex(ord(chr(60+14))+1)-2).
chr(hex(ord(chr(60+14)))).
chr(hex(hex(14))).
chr(hex(60+ +1)).
chr(112-2).
chr(112-1).
chr(hex(ord(chr(60+14)))).
chr(hex(60+7+1)).
chr(hex(60+7-2)).
chr(hex(60+14-2)).
chr(hex(hex(14))).
chr(hex(hex(hex(hex(14))))).
chr(hex(60+7-2)).
chr(hex(60+14-2)).
chr(112-4).
chr(hex(hex(14))).
chr(hex(60+7+1)).
chr(hex(60+1)).
chr(hex(56+7)).
chr(112-4-1).
chr(hex(60+7-2)).
chr(hex(60+14-2)).
chr(hex(hex(14))+14-2);

print;

Now we can do some arithmetic simplification, and a little more cleanup. There are several places where ord(chr(X)) shows up in the script. If you think about what ord() and chr() do, it's obvious that ord(chr(X)) = X, so we can simplify those statements quite a bit.

```\$_= chr(74).
chr(hex(75)).
chr(hex(75)-2).
chr(hex(74)).
chr(hex(hex(14)).
chr(hex(61)).
chr(110).
chr(111).
chr(hex(74)).
chr(hex(68)).
chr(hex(65)).
chr(hex(72)).
chr(hex(hex(14))).
chr(hex(hex(hex(hex(14))))).
chr(hex(65)).
chr(hex(72)).
chr(108).
chr(hex(hex(14))).
chr(hex(68)).
chr(hex(61)).
chr(hex(63)).
chr(107).
chr(hex(65)).
chr(hex(72)).
chr(hex(hex(14))+12);

print;

It should be pretty easy to get the solution now, but I'll make it a little easier to get you started.

```\$_= 'J'.
chr(hex(75)).
chr(hex(75)-2).
chr(hex(74)).
chr(hex(hex(14)).
chr(hex(61)).
'n'.
'o'.
chr(hex(74)).
chr(hex(68)).
chr(hex(65)).
chr(hex(72)).
chr(hex(hex(14))).
chr(hex(hex(hex(hex(14))))).
chr(hex(65)).
chr(hex(72)).
'l'.
chr(hex(hex(14))).
chr(hex(68)).
chr(hex(61)).
chr(hex(63)).
'k'.
chr(hex(65)).
chr(hex(72)).
chr(hex(hex(14))+12);

print;

Guildenstern
Negaterd character class uber alles!

Replies are listed 'Best First'.
Re: SPOILER! (Guildenstern) Re: My 2 cents worth
by one4k4 (Hermit) on Sep 13, 2001 at 20:03 UTC
You know something.. The interesting part (besides your spoiler, of course!), is that I'm actually understanding this, and I'm concerned that I'll start using ideas like tr on strings you'll eval, and end up with obfus like that. :)

_14k4 - perlmonks@poorheart.com (www.poorheart.com)

Create A New User
Node Status?
node history
Node Type: note [id://78000]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (6)
As of 2020-10-29 02:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
My favourite web site is:

Results (267 votes). Check out past polls.

Notices?