Reputation: 1075
I'm trying to see what this file has inside of it (written in L u a) for a game I play, so that I can learn and see how it is done. But at the beginning it has functions defined that make everything unreadable - The code is in the file.
And as the code goes on you get more "prettified" coding with ###. Could someone tell me how to make it so it is readable again?
Upvotes: 2
Views: 1253
Reputation: 28991
Your file contains a block of compressed code between [===[
and ]===]
. The compression is just a dictionary coder, where keywords are mapped to individual byte values. The decompression is done via prettify
(see Lorenzo's post).
Running the compressed code through prettify
gives you this code (compression ratio ~46%), which happens to be another decompression routine! In fact, it appears to be an minimized version of this code.
That "ungzip" routine is then used to process another ~150KB string contained in the file, which expands into 675KB of text.
Believe or not, that text is also compressed, via the same scheme as the ungzip code, and contains its own copy of prettify
. Running that text through its prettify
gives us the final 963KB of Lua, which is then executed.
Here's the final, decompressed code, posted to the first site I found that would allow a 963KB upload. The formatting is just as it comes out of prettify
.
Upvotes: 5
Reputation: 7924
I'm the author of the utility, Squish, that was used to create that file.
Some of Squish's filters are reversible, some are not. Here is a tip for reversing as much as possible as easily as possible:
At the top of the file, paste this code snippet:
local _ls = loadstring;
function loadstring(...)
local f = assert(io.open("unsquished.lua", "w+"));
f:write((...));
f:close();
return _ls(...)
end
Then run the file with Lua. It will generate a new file, unsquished.lua
, in the current directory. This file is now 100% pure Lua.
However you won't find it particularly easy to read, as all unnecessary whitespace will have been stripped, and some variable names replaced by short alternatives. You could look at lunadry to reformat the code, but the original variable names are irretrievable.
Also, the file contains multiple modules merged into one. You will see these looking like:
package.preload['modulename']=(function(...)
--code here--
end)
You can split these back out into separate files if you want to, to help with readability.
Hope this helps!
Edit: Be careful using this technique on files you don't trust, as it will actually execute them as you run it. Not a good idea if you don't already know what they do!
Upvotes: 3
Reputation: 6985
Since the posted code is not complete, and probably messed-up, mine are only educated guesses.
It seems that the whole code stores, in the variable ungz
, the result of a call to an "anonymous function": the (function ()
fragment probably is closed somewhere like this:
ungz = (function() -- "anonymous function"
-- ...
-- definition of `prettify` + helper data
-- ...
return assert( loadstring(
prettify [===[
...obfuscated code in this long string...
]===]
) ) -- end of `loadstring` and of `assert` calls
end)() --<<-- note the () to call the "anonymous function"
Inside this function you may see the definition of the function prettify
with its helper data, which can be reformatted for better understanding in this way:
local base_char,keywords=128, {
"and","break","do","else","elseif","end","false","for",
"function","if","in","local","nil","not","or","repeat","return",
"then","true","until","while","read","nbits","nbits_left_in_byte",
"wnd_pos","output","val","input",};
function prettify(code)
return code:gsub(
"["..string.char(base_char).."-"..string.char(base_char+#keywords).."]",
function (c)
return keywords[c:byte()-base_char];
end
)
end
The function prettify
, when applied to a string, will return the same string where any character having a numeric code in the range base_char
-base_char+#keywords
is replaced with a keyword of the keyword
list.
This is used to "deobfuscate" the "obfuscated" code using assert(loadstring(prettify[===[xxxx]===]))
where I indicated the obfuscated code as xxxx
.
Addendum: note that applying prettify
to the fragment [===[xxxx]===]
doesn't give back meaningful code (a base_char
value of 202
would give better results, although not perfect). Moreover you have to merge all the lines inside that long string and substitute it with a normal string, i.e. turn it to "yyyy"
, where yyyy
is xxxx
with all hard newlines removed.
Probably all that code is preprocessed in some further way.
Upvotes: 2