I like Lua as a programming language for its beauty and simplicity, but sometimes you have to defile a language with horribly obfuscated code:
L= {} for k,v
in next ,_G ._G
do L[#k ]=v end
L[10 ](([[p =prin t;for
'q=99, 1,-1'do' gg'q>1' th{n'p(
q.."'Bs' {f'!:::'{n 'th{'<114 ,'"..q.."
'Bs'of'!:: [.")gg'q>2't h{n's=(q-1) .."'Bs'{f'[
!::'{n'th{ '<!+$."{lse' s="1'B'{f'$ !::'{n'th{'
<onx."{nd; elsegg'q==1' then'p"1'B' {f'x!::'{n'
th{'wall,' 1'B'of'[!::. "s="no'mor{ '!::''{n'th
e'<'!4!"en d;p("Take'{n {'down,'pas s'it'around
,'"..s)p"- "{nd]]):gsub ("["..[==[$ 4[]==]..[[x
]].."]","" ):gsub([[B]] ,"bottle"): gsub("''?",
" "):gsub( "!:+","beer" ):gsub("gg" ,"if"):rep(
3-2):gsub( "<..","wall" ):gsub("{", function(_)
B=((B)or(3 ))+1;return( "eooe"):sub (B%4+1,(B+1
+2+9)%4+(# L[1]-13),(B* 2)%7)end))( L[#L]or...)
Despite what it looks like, it is valid Lua 5.1 code. If it isn't immediately obvious what it does, then you can see the output.
The overall form of the code is loadstring(([[code]]):decrypt())()
. Of course, putting a straight loadstring
call into the code would make things obvious (and it would break the nice formatting). Hence there is this lovely piece of code instead:
L = {}
for key, value in pairs(_G) do
L[#key] = value
end
This relies on the fact that loadstring
is the only global variable whose name is 10 characters long:
Length | Globals |
---|
1 | L |
2 | _G os |
4 | load math type next |
5 | debug error pairs pcall print table |
6 | dofile ipairs module rawget rawset select string unpack xpcall |
7 | getfenv package require setfenv |
8 | _VERSION loadfile newproxy tostring |
9 | coroutine |
10 | loadstring |
12 | getmetatable setmetatable |
14 | collectgarbage |
Next comes a long string containing the true program code (although not in plaintext), and then after it come a number of calls to
string.gsub
to turn the string back into valid Lua code. The calls to gsub are:
Pattern | Replacement |
[$4[x%s] | (nothing) |
B | bottle |
''? | (space) |
!:+ | beer |
gg | if |
<.. | wall |
{ | function()
B = (B or 3) + 1
return ("eooe"):sub((B % 4) + 1, (B % 4) + 1)
end
|
After all of these replacements, the code that gets send to loadstring
is: (linebreaks and indentation added for clarity)
p=print;
for q=99,1,-1 do
if q>1 then
p(q.." bottles of beer on the wall, "..q.." bottles of beer.")
if q>2 then
s=(q-1).." bottles of beer on the wall."
else
s="1 bottle of beer on the wall."
end;
elseif q==1 then
p"1 bottle of beer on the wall, 1 bottle of beer."
s="no more beer on the wall!"
end;
p("Take one down, pass it around, "..s)
p"-"
end
This code is loaded, and then executed, and the result is (obviously) the 99 bottles of beer song.