How to dump (most) obfuscators
Obfuscators use varies techniques when it comes to protecting and loading their constants. But most obfuscators have this as their flaw. It can be easily dumped.
Well you may ask yourself. Why is it so easy to dump them? Well since every obfuscator has to load their constants somehow, we can easily figure out where that is when we know a function that is being used by the script.
But what we first need to do is beautify the script using some sort of formatter. My choice is going to be luamin but you can choose yourself.
Let's take the function 'print' as an example for now. What we can do is change print to error by doing
print = error
Now what this will do is change print into error and then it will error at the specific line it's being loaded (in the beautified script)
Now this error may look like this

1043 is the line where the function is being called. A example of how that calling may look like is like this:
local L_171_ = L_122_[2];
L_120_[L_171_](L_120_[ L_171_ + 1 ]);
Now what can we get out of this? First of all we can see that L_120_ is some sort of table which contains, functions and possibly strings due to it being passed in the function called. Out of the L_171_ we can make some index being accessed for the functions. And that is exactly what it is.
L_120_ is the constant table where everything is located (the functions and constants itself) L_171_ is the index being used to load the constant. In this example we already know that L_120_[L_171_] will be the function 'print' and L_120_[ L_171_ + 1 ] must then be the message being passed in. In this example "true". (It's L_171_ + 1 because the next constant to the function will be the argument that is passed into the function ) So this code translates to
local Index = ConstantIndex[2]
-- Constants[Index] -> print
-- Constants[Index + 1] -> "true"
Constants[Index](Constants[Index + 1 ])
Ok so that we know that the Constants are a table we can just iterate over them and print every constant in the script (on larger scripts this may crash, lag so find a alternative to my method)
for key, value in pairs(Constants) do
local value_type = typeof(value)
if value_type == "function" then
print(debug.info(value,"n")) -- attempting to get the function name
elseif value_type == "table" then
table.foreach(value,print) -- simple foreach looping printing everything in it
else
print(value) -- printing everything else that mostly doesn't need special handling
end
end
-- We will also comment out the constants being called in Constants[Index](Constants[Index + 1 ])
-- Constants[Index](Constants[Index + 1 ])
And there you have it a simple way to dump constants! Note this is works on most obfuscators but not all. There are other methods to dumping but this is my favourite one since it allows for fast analyzing instead of trying to understand the whole obfuscator directly.
Second Method
Another method is to look at all the functions being used by the obfuscator and see which functions could be used to unpack the constants. A example is luaobfuscator. We can directly from the start see all the functions being used
local L_1_ = tonumber;
local L_2_ = string.byte;
local L_3_ = string.char;
local L_4_ = string.sub;
local L_5_ = string.gsub;
local L_6_ = string.rep;
local L_7_ = table.concat;
local L_8_ = table.insert;
local L_9_ = math.ldexp;
local L_10_ = getfenv or function()
return _ENV;
end ;
local L_11_ = setmetatable;
local L_12_ = pcall;
local L_13_ = select;
local L_14_ = unpack or table.unpack ;
local L_15_ = tonumber;
Now we make out which functions could be called to unpack the constants and hook the function. For here we can find 2 functions which could unpack the constants. table.concat and unpack could both be used to find the constants so we will start off by hooking them and finding out which functions unpacks the constants. A example script would look like this
local old = table.concat
table.concat = function(table,seperator)
local output = old(table,seperator)
print(output)
return output
end
And what do we see? The Constants are unpacked using table.concat so this method also works.
Last updated