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