Obfuscations of Christmas Past
Rather than always focusing on SERIOUS BUSINESS, I’d like share something a little more light hearted today. Whether you celebrate Christmas or not, I think you’ll find this little holiday themed hack a great deal of fun to play with.
Leah Neukirchen’s Christmas Hack
When I first started programming in Ruby, the ruby-talk mailing list was the best place to interact with the community and keep up with other active Ruby hackers. But because there were a lot more hobbyists in 2004 than there were people doing Ruby as a full time job, the posts focused on sharing fun hacks just as often as they did on discussing practical issues.
One of my favorites was Leah Neukirchen’s obfuscated Christmas message to the Ruby community in 2004. I’ve copied the source code below, and I encourage you to run it and see that it is indeed a valid Ruby program!
s="IyBUaGFua3MgZm9yIGxvb2tpbmcgYXQgbXkgY29kZ
S4KIwojIENvcHlyaWdodCAoQykgMjAwMiAgQ2hyaXN0a
WFuI E 5 l d Wtpc
mNoZ W 4 gP G N obmV
1a2l y Y 2hlb k B nbWF
pbC5 j b 20+CiM K I yBUa
GlzI H Byb2dyYW 0 gaXM
gZnJ l Z SBzb2Z0d2F y Z Tsge
W91I G NhbiByZWRpc3 R yaWJ
1dGU g aXQgYW5kL29yCi M g bW9k
aWZ5 I Gl0IHVuZGVyIHRoZ S B0ZX
Jtcy B vZiB0aGUgR05VIEdlb m VyYW
wgUH V ibGljIExpY 2 Vuc2
UuCg p T VERPVVQuc3lu Y y A9IH
RydW U KZDEsIGQyID0gM C 4xNS
wgMC 4 wNgpzID0gIk1lcnJ 5 IGNo
cmlz d G1hcywgLi4uIGFuZCB h IGhh
cHB5 I G5ldyB5ZWFyIgptID0gJ X d7LC
AuID ogISArICogMCBPIEB9CnUg P SAiI
CIgK i BzLnNpemUKCnByaW50ICJcci A gI3t
1fVx y IjsKCigwLi4ocy5z a XplL
TEpK S 50b19hLnNvcnRfYnkg e yByY
W5kI H 0uZWFjaCB7IHxyfAogIH N sZWV
wIGQ x CiAgbmV4dCBpZiBzW3JdID 0 9ICI
gIls wXQogIG0uZWFjaCB7IHxrfAo gICA
gdVt y XSA9IGsKICAgIHByaW50ICIgIC N 7dX1
cciI KICAgIHNsZWVwIGQyCiAgfQogIHV bcl0
gPSB zW3JdCiAgcHJpbnQgIiAgI3t1fVxyI g p9Cg
pzbG VlcCBkMgpwcmludCAiICAje3V9IVxyI jsKc
2xlZ X A gMwpwc m l udCA
iICA j e3V9IS A g LS1j
aHJp c z JcbiI7 C g ojIG
ZpbG x lciBzc G F jZSA
jIyM j I yMjIyM j I yMjI
yMjI y M j I yMjI
yMK";eval s.delete!(" \n").unpack("m*")[0]##
### Copyright (C) 2004 Christian Neukirchen
When run, this code prints out “Merry christmas, … and a happy new year! –chris2” by randomly filling in each character in a little animation. After some folks commented on how cool this hack was, someone inevitably asked how it was done, which lead another Ruby hacker Michael Neumann to post his guess to the list. Here is what he said:
Pretty easy (except drawing the tree :). Write the source-code first, then
base64
encode it, and insert newlines/whitespace to make the picture.
At the time, I was too much of a beginner with Ruby to fully appreciate the solution discussion, and mostly just chalked it up to magic. But now, the above statement is immediately obvious to me, and since it wasn’t further explained in the mailing list thread, I can give an example for those who are in the same shoes now that I was in a few years ago.
What I didn’t know at the time is that Base64
is an encoding that allows you to translate any binary data into purely printable characters by converting the contents into a string of characters that uses basic alphanumeric values. I would have known that if I read the documentation for Ruby’s Base64
standard library, but again, I was a newbie at the time. :)
It turns out that the idea for Base64
encoding was extracted from how MIME attachments in email are implemented. This is all stuff you can find on wikipedia, so rather than digging into the gory details, let’s see how it relates to the problem at hand.
The following small snippet should clear things up a bit.
>> source = "puts 'hello world'"
=> "puts 'hello world'"
>> encoded_source = Base64.encode64(source)
=> "cHV0cyAnaGVsbG8gd29ybGQn\n"
>> Base64.decode64(encoded_source)
=> "puts 'hello world'"
>> eval Base64.decode64(encoded_source)
hello world
=> nil
Another way of decoding Base64
encoded strings is via the String#unpack
method, using the template "m*"
. You can see this in Leah’s code, which is what tipped Michael off in the first place. With that in mind, we can build a tiny obfuscated “Hello World” program.
s =
"c H V0cyA
n a G
VsbG 8
g d 2
9 y bGQn"
eval s.delete(" \n").unpack("m*")[0]
In the end, Michael was right when he said this was pretty easy to do. As long
as you understand some basic string manipulation and how to decode a base64
encoded string, you could use this technique to render your code as pretty much any arbitrary ASCII art.
Of course, one would expect that the person who eventually would go on to create something as clever and useful as the Rack web server interface would have an extra trick or two up their sleeve. Not to disappoint, Leah confirmed Michael’s explanation was valid, but in the process revealed that they felt it’d be too fragile and tedious to manually format the code themselves into the desired ascii art.
For those curious about how they got around this problem, you can check out their full solution
which implements a code generator that fills in a template with the base64
encoded source.
While the code should be pretty easy to follow with a little effort, feel free to post questions here if you need help figuring things out. It’s a really neat bit of code and is worth exploring, so I don’t mind giving some hints where needed.
Reflections
Writing this article reminded me of two lessons that I sometimes forget, even to this day.
The first lesson is that you can’t judge the complexity of something by simply scratching its surface. When I saw this code posted to ruby-talk back in 2004, even though I was a newbie at the time, I could have figured it out if I only took a bit of time to study the topics that were being discussed. But since I saw a bunch of obscure binary data in the shape of a Christmas tree being passed to eval()
, I judged the snippet as being too complicated for me, appreciated it for its magic, and moved on. That sort of lack of self-confidence can really prevent you from stumbling upon interesting new ideas, tools, and techniques.
The second lesson is that hacking doesn’t always have to be SERIOUS BUSINESS. Because I’m working on things I feel are super important most of the time, it’s easy for me to forget to be playful and generally curious. Sometimes I feel like I’m too busy to do something just for the joy of the hack, and that worries me a bit. Writing this article reminded that I should resist this temptation, and make more time and space in my life for playful discovery, because it is a great way to learn and have fun at the same time.
NOTE: This article has also been published on the Ruby Best Practices blog. There may be additional commentary over there worth taking a look at.
Practicing Ruby is a Practicing Developer project.
All articles on this website are independently published, open source, and advertising-free.