Luafuck

From Esolang
Jump to navigation Jump to search

Luafuck is an esoteric subset of the Lua language. It uses 12 distinct characters in the source code. The characters are []()#._Gchar.
The creation of Luafuck was inspired by JSFuck.

Description

Just like JSFuck, Luafuck works because every Lua program can be written as a string that gets evaluated.
The way to evaluate a string in Lua is by using the global function loadstring.
loadstring receives a string and returns a function. Upon invoking the returned function, the encoded script starts running.

For example, this normal Lua code:

print("Hello from original code:)")

can be written as:

loadstring('print("Hello from original code:)")')()

The next section will detail Luafuck's primitives and how we can create any character in the script print("Hello from original code:)").

Primitives

This example will show you how the character 'b' can be encoded (notice how 'a' is in the charset, so we don't need special tricks to use it).

  1. "b": Is returned when invoking string.char(98). b's ASCII value is 98.
  2. string.char("98"): We can get the string "98" by combining two strings.
  3. string.char("9".."8"): We can get each string using the method shown in #Encoding n-sized strings
  4. string.char(#[[.........]]..#[[........]]): The char function of the string class can be accessed if we treat the class as a table.
  5. string["char"](#[[.........]]..#[[........]]): Lua allows string to be defined using [[double brackets]] instead of "qoutes".
    1. The "table access" brackets are interfering so we need to isolate the inner string with paranthesis.
  6. string[([[char]])](#[[.........]]..#[[........]]): Instead of accessing the string class object, we can substitue with any valid string. We'll use the empty string [[]].
  7. [[]][([[char]])](#[[.........]]..#[[........]]) ← That's the result in Luafuck.

Encoding n-sized strings

As you've seen above, to create the decimal value n we need to use # on a n-sized string. Here are a few short examples that'll hopefully explain the overall strategy:

The number 0 is achieved from an empty string: #[[]]
The number 1 is acheved by first creating a 1-char srting, containing a single dot: #[[.]]
The number 2 is achieved in a similar way: #[[..]] and so on.

Alternatively, and 1-byte shorter, we can abuse the _G global table to get 0: #_G.
When using the # operator on a table, it returns the number of elements in its "array part". _G has an empty array part by default.

Accessing loadstring

The only thing left to solve is accessing to the global function loadstring.
Lucky for us, Lua keeps all of its globals in the special table called _G.
That means we only need to access _G["loadstring"]. Using the above tricks, this could be written like so:

_G[([[]]).char(#[[.]]..#_G..#[[........]])..([[]]).char(#[[.]]..#[[.]]..#[[.]])..[[a]]..
([[]]).char(#[[.]]..#_G..#_G)..([[]]).char(#[[.]]..#[[.]]..#[[.....]])..([[]]).char(#[[.]]..#[[.]]..#[[......]])..
[[r]]..([[]]).char(#[[.]]..#_G..#[[.....]])..([[]]).char(#[[.]]..#[[.]]..#_G)..([[]]).char(#[[.]]..#_G..#[[...]])]

This breakdown of the line above makes it easier to see:

_G[
 ([[]]).char(#[[.]]..#_G..#[[........]])
..
 ([[]]).char(#[[.]]..#[[.]]..#[[.]])
..
[[a]]
..
 ([[]]).char(#[[.]]..#_G..#_G)
..
 ([[]]).char(#[[.]]..#[[.]]..#[[.....]])
..
 ([[]]).char(#[[.]]..#[[.]]..#[[......]])
..
[[r]]
..
 ([[]]).char(#[[.]]..#_G..#[[.....]])
..
 ([[]]).char(#[[.]]..#[[.]]..#_G)
..
 ([[]]).char(#[[.]]..#_G..#[[...]])
]


Primitives Cheatsheet

1. ""               (Empty string)    ==> '[[]]'
2. 0                (number)          ==> '#_G' or '#[[]]'
3. "0"              (string)          ==> '[[]] .. #[[]]'
4. "00"             (string)          ==> '#[[]] .. #[[]]'
6. 1                (number)          ==> '#[[.]]'
7. 2                (number)          ==> '#[[..]]'
8. 3                (number)          ==> '#[[...]]'
8. string.char      (func)            ==> '[[]][([[char]])]'
9. 'a'              (char)            ==> Assume 'strchar' holds 'string.char', 'strchar(97)' or 'strchar("97")'
10. 'b'             (char)            ==> Assume 'strchar' holds 'string.char', 'strchar(98)' or 'strchar("98")'
11. 'abc'           (string)          ==> Assume 'chr_a','chr_b','chr_c' holds the chars, 'char_a .. char_b .. char_c'
12. Globals table                     ==> '_G'
13. A global 'glb'                    ==> '_G[([[glb]])]'
14. loadstring      (func)            ==> '_G[([[loadstring]])]'
15. Execute code                      ==> Construct the code as a string in memory (like any other string, shown above) then call 'loadstring(code_var)()'

Encoders

There's a single encoder available for Luafuck, written in C#: