• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

[HowTo] "Close Source" your .lua scripts.

Shinmaru

エロルアー Scripter!
Joined
Aug 20, 2007
Messages
1,988
Reaction score
88
Location
Puerto Rico
Perhaps many did not know about this(as myself), there is a way to compile .lua source files into LUA readable binaries, and they work with TFS(As far as I had tested them).

I know that, it is a common problem with having, users dedicate their time in making scripts for other users to use, but sometimes, some of those users simply steal our scripts and pass them as their own.

Now I'll teach you how to do this.

Warning: Even though I have tested it, there is still more testing to be done, but with more complex LUA scripting, always keep a backup of the source file.

Requirements:
Latest LUA or the one that is compatible with your server(Currently 5.1.4) - Lua Binaries

Preparations:
LUA Architecture must be the same as the Compiled server Architecture, example: if Server is compiled 64-bit then you must get LUA that is meant for 64-bit, otherwise you will get a "Bad Header" error.

Steps:
1. Download LUA and extract(On Linux, you can install it from terminal), if on windows, open command prompt, then change directory(cd) to the path where the *.lua script is located, if on linux, open terminal and do the same.
2. If on windows, type:
Code:
luac5.1 -o 'OutputName' NameofScript.lua
(in this case it will be 5.1, you can rename that program to just luac)
on linux type:
Code:
luac -o 'OutputName' NameofScript.lua
3. Add it to its responding folder in the server, make sure you also update the .xml with the proper name.

I'll update this tutorial later, I'm a bit tired and in need of sleep.
 
There is 4 libs in luaforge to "decompile" it. Also using string.dump you can do the same:

Code:
local filename = 'file';
do
	local file = io.open(filename..'.lua','rb');
	io.open(filename..'.luac','wb'):write(file:read(-1):dump());
	file:close();
end
 
Last edited:
There is 4 libs in luaforge to "decompile" it. Also using string.dump you can do the same:

Code:
local filename = 'file';
do
	local file = io.open(filename..'.lua','rb');
	io.open(filename..'.luac','wb'):write(file:read(-1):dump());
	file:close();
end
Yea, I know, I've seen only 2 of them and they are for 5.0(outdated AFIAK), also, your code does not work, if it was as simple as a dump then there would be no need to make libs to "decompile" it.

The code you posted, does a 'dump', but it is empty.

My results:
Code:
> local filename = 'machete'; do local file = io.open(filename..'.lua', 'rb'); i
o.open(filename..'.luac', 'wb'):write(file:read(-1):dump()); file:close(); end
stdin:1: calling 'dump' on bad self (function expected, got string)
stack traceback:
        [C]: in function 'dump'
        stdin:1: in main chunk
        [C]: ?
 
Yea, I know, I've seen only 2 of them and they are for 5.0(outdated AFIAK), also, your code does not work, if it was as simple as a dump then there would be no need to make libs to "decompile" it.

The code you posted, does a 'dump', but it is empty.

My results:
Code:
> local filename = 'machete'; do local file = io.open(filename..'.lua', 'rb'); i
o.open(filename..'.luac', 'wb'):write(file:read(-1):dump()); file:close(); end
stdin:1: calling 'dump' on bad self (function expected, got string)
stack traceback:
        [C]: in function 'dump'
        stdin:1: in main chunk
        [C]: ?
Ops~
Code:
local filename = 'file';
do
	local file = io.open(filename..'.lua','rb');
	io.open(filename..'.luac','wb'):write(string.dump(loadstring(file:read(-1)))); --with loadstring
	file:close();
end
 
Ops~
Code:
local filename = 'file';
do
	local file = io.open(filename..'.lua','rb');
	io.open(filename..'.luac','wb'):write(string.dump(loadstring(file:read(-1)))); --with loadstring
	file:close();
end
Opps yourself again, that code is more fail then the last one, I still doubt that a "dump" will get the original code, because if that was true then there would be no need for a "Decompiler".
 
The dump is only to encrypt the code.
Using luac this code:
string("something") Will be like:
0x6 0x0 0x0 string 0x0 0x15 [size bytes] "Something"~

You are not compiling, just using and generic encryption
 
4vo9j7.gif
 
anyone got it working? I can't even print a single line with it
edit: nvm, was using wrong encoding function
 
Last edited:
I think it is easy to decompile such a script. Better will be some kind of script that makes the code so messy that it won't be editable, it would be readable only by computer.
 
Theres no way to protect em 100% since your computer needs to access the scripts.

Dont waste time if your script is 'encrypted' and someone really wants it he will get it
 
Theres no way to protect em 100% since your computer needs to access the scripts.

Dont waste time if your script is 'encrypted' and someone really wants it he will get it
you won't tell me how to live

as decoded the script looks like:
kPKzWWK.jpg


btw. reminds me of this:
 
Last edited:
you won't tell me how to live

a simple function which doesn't return true if a table declared in same file was modified, TA6T is a table with shuffled letters, equation is a number to hide:
Code:
function j0j9()
local k4h = script_table
    if k4h[TA6T.L .. TA6T.I .. TA6T.B .. TA6T.R .. TA6T.n .. TA6T.u] == TA6T.m .. TA6T.n .. TA6T.u .. "i" .. TA6T.L .. TA6T.z .. TA6T.L and
    k4h[TA6T.H .. TA6T.F .. TA6T.u .. "s" .. "i" .. TA6T.n .. TA6T.z] == TA6T.j .. TA6T.F .. "m" .. TA6T.n and
    k4h[TA6T.I .. TA6T.u .. TA6T.r] == TA6T.R .. TA6T.B .. TA6T.B .. TA6T.g .. "s" .. "://" .. TA6T.n .. TA6T.B .. TA6T.r .. TA6T.L .. TA6T.z .. TA6T.j .. "." .. TA6T.z .. TA6T.F .. TA6T.B .. "/" ..  "m" .. TA6T.F .. "m" .. TA6T.J .. TA6T.F .. TA6T.u .. "s" .. "/" ..  TA6T.r .. TA6T.n .. TA6T.u .. "i" .. TA6T.L .. TA6T.z .. TA6T.L .. "." .. (10^4 + 1 + (77 * 10)) * 5 * 4 .. "/"
    then
        return true
    end
end

The shuffled letters if took a little time would be easy to decipher, since you already gave us clues
Like this for instance
Code:
TA6T.R .. TA6T.B .. TA6T.B .. TA6T.g .. "s" .. "://"
Looks like it is the beginings of a url
Code:
h .. t .. t .. p .. "s" .. "://"
And the string index could possibly be labeled url

@zbizu is a nice try at encoding :p
I wrote this some time ago when I was learning Java :)
PHP:
//import java.lang.*;
import java.util.*;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.math.*;
//import java.io.*;

public class EnDe{
   
    private String[] encrytped;
    private ArrayList<Integer> keys = new ArrayList<Integer>();
   
    public EnDe(){}
   
    public int Ord(String s, int i){
        int num = (int) s.charAt(i);
        return num;
    }
   
    public int Ord(char c){
        int num = (int)c;
        return num;
    }
   
    public int Ord(String s){
        if(isInteger(s, 10)){
            int num = Integer.parseInt(s, 10);
            return num;
        }else{
            return this.HexDex(s);
        }
    }
    // home made
    /*
    public int HexToDec(String s){
        char[] c = s.toCharArray();
        int value = 0;
        for(int i = 0; i < c.length; i++){
            switch(c[i]){
                case 'A' :
                case 'a' :
                    c[i] = 10;
                    break;
                case 'B' :
                case 'b' :
                    c[i] = 11;
                    break;
                case 'C' :
                case 'c' :
                    c[i] = 12;
                    break;
                case 'D' :
                case 'd' :
                    c[i] = 13;
                    break;
                case 'E' :
                case 'e' :
                    c[i] = 14;
                    break;
                case 'F' :
                case 'f' :
                    c[i] = 15;
                    break;
            }// end of switch
            value += (int)c[i];
        }// end of for
        return value;
    }*/
   
    public boolean isInteger(String str, int radix) {
        try {
            Integer.parseInt(str, radix);
            return true;
        } catch (NumberFormatException e) {}
        return false;
    }
   
    public boolean isBigInt(String str, int radix) {
        try {
            new BigInteger(str, radix);
            return true;
        } catch (NumberFormatException e) {}
        return false;
    }
   
    public String DecHex(int dec){
        String hex = Integer.toHexString(dec);
        return hex;
    }
   
    public int HexDex(String str){
        int dec = Integer.parseInt(str, 16);
        return dec;
    }
   
    public int BinToDec(String str){
        if(isInteger(str, 2)){
            int bin = Integer.parseInt(str, 2);
            return bin;
        }else{
            //System.out.println("inside of bin " + str + "\nsize of str " + str.length());
            if(this.isBigInt(str,2)){
               
            }
            return 0;
        }
    }
   
    public String Chr(int dec){
        String chr = Integer.toString(dec);
        return chr;
    }
   
    public String Implode(String glue, String[] strArray)
    {
        String ret = "";
        for(int i = 0; i < strArray.length; i++)
        {
            if (strArray[i].trim() != "")
                ret += (i == strArray.length - 1) ? strArray[i] : strArray[i] + glue;
        }
        return ret;
    }
   
    public void Encode(String str, int min, int max){
       
        String[] hex = new String[str.length()];

        for (int i = 0; i < str.length(); i++) {
            hex[i] = this.DecHex(this.Ord(str, i));
        }
        this.EncryptData(hex,min,max);
    }
   
    /*
    // not used at the moment
    public void Build(String[] str){
        String imploded = this.Implode("", str);
        String[] charArray = imploded.split("", 0);
        for (int i = 0; i < str.length; i++) {
            System.out.println(" i " + i + " : " +str[i]);
        }
    }*/
   
    public void EncryptData(String[] str, int min, int max){
        int i = 0;
        int k = 1;
        this.encrytped = new String[str.length];
        while(i < str.length-1){
            //System.out.println("this is str : " + str[i]);
            this.encrytped[i] = ((i % 2) == 0) ? this.DecHex( ( (this.Ord( str[i] ) - min ) >> k )  ) : this.DecHex( ( ( this.Ord( str[i]  ) - max ) >> k) );
            this.encrytped[i] = this.encrytped[i].substring(6);
            //System.out.println("this is encrypted String : " + this.encrytped[i]);
            this.WriteToFile("test.txt", this.encrytped[i]);
            i++;
           
        }
        //this.WriteToFile("test.txt", this.encrytped);
        // TODO :
        //return this.btemp;
    }
   
    public void GenerateMinMax(int min, int max){
        // TODO :
    }
   
    public void GenerateKey(String str, int min, int max){
       
        char[] strA = str.toCharArray();
        int maxchr = Integer.MAX_VALUE;
        short count = 24;
        int len = (str.length() > count) ? count : str.length();
        String num = "";
        
       
        for(int j = 0; j < len; j++){
            //System.out.println("i : "+ this.Ord( strA[j] ) + " - strA - " + strA[j]);
            if( ( this.Ord( strA[j] ) % 2) == 0){
                num += "1";
            }else{
                num += "0";
            }
        }
        //System.out.println("len num : "+ num);
        if(len < count){
            for (int i = 0; i < (count-len); i++) {
                if(i % 2 == 0){
                    num += "1";
                }else{
                    num += "0";
                }
            }
            //System.out.println("size num : "+ num + "\nmax value of count " + maxchr );
        }
        if(num.length() >= len){
            this.setKeys( 0, ( ( min * len ) + this.Ord( this.Chr( this.BinToDec( num ) ) ) > maxchr) ? maxchr : ( min * len ) + this.Ord( this.Chr( this.BinToDec( num ) ) ) );
            this.setKeys( 1, ( ( max * len ) + this.Ord( this.Chr( this.BinToDec( num ) ) ) > maxchr) ? maxchr : ( max * len ) + this.Ord( this.Chr( this.BinToDec( num ) ) ) );
        }else if(num.length() < len){
            this.setKeys(0, ( ( str.length() + min ) * len ) + this.Ord( this.Chr( this.BinToDec( num ) ) ) );
            this.setKeys(1, ( ( str.length() + max ) * len ) + this.Ord( this.Chr( this.BinToDec( num ) ) ) );
        }
        //return this.getKeys();
        //this.WriteToFile("test.txt", num);
    }
   
    public void setKeys(int index, int value){
        this.keys.add(index, value);
    }
   
    public int getKeys(int i) {
        int key = (int)this.keys.get(i);
        return key;
    }
   
    public void WriteToFile(String Fname, String data){
        try 
        {
            FileWriter fstream = new FileWriter(Fname, true); //true tells to append data.
            BufferedWriter out = new BufferedWriter(fstream);
            out.write(data);
            out.close();
        }
        catch (Exception e)
        {
            System.err.println("Error: " + e.getMessage());
        }
    }
    // TODO : Lots more =)

    public static void main(String[] args) {
        String evt = "~`1!@2#3$4%5^6&7*8(9)0_-+=QqWwEeR rTtYyUuIiOoPp{[}]|\\AaSsDdFfGgHhJjKkLl:;'\"ZzXxCcVvBbNnMm<,>.?/";
       
        EnDe e = new EnDe();
        //e.WriteToFile("test.txt", evt);
        e.GenerateKey("Codex", 10, 12);
        e.Encode(evt,e.getKeys(0),e.getKeys(1));
        //System.out.println("key min - " + e.getKeys(0));
        //System.out.println("key max - " + e.getKeys(1));
    }
}
 
Last edited by a moderator:
Its an incomplete variation of a php encryption algorithm i made which i can't find :(
I'll post it when i find it.. anyway the output is never the same & there is no pattern :p

Edit: Found it :)
Who knows maybe it will be useful to someone.
PHP:
class EnDe
{
    private $b;
    private $c;
    private $key;

    public function __construct()
    {
   
    }
    public function Encode($string, $min, $max)
    {
        $hex = array();
        for ($i = 0; $i < strlen($string); $i++)
        {
            $hex[$i] = dechex(ord($string[$i]));
        }
        $inv = $this->Build($hex);
        return implode("", $this->EncryptData($inv, $min, $max));
    }

     public function Decode($data)
    {
        $rev = $this->Build($data, false);
        $bin    = "";
        $i      = 0;
        do {
            $bin    .= chr(hexdec($rev[$i]));
            $i      += 1;
        } while ($i < sizeof($rev));

        return $bin;
    }

    private function Build($a, $c = true){
        if($c){
            $b = str_split(implode("", $a));
            unset($b[sizeof($b) + 1]);
        }
        else{
            $b = str_split(implode("", $a), 2);
            unset($b[sizeof($b) + 1]);
        }
        return $b;
    }

    public function EncryptData($p, $min, $max) {
        $i = 0;
        $k = 1;
        while($i < sizeof($p)) {
        $this->b[$i] = ($i & 2) ? chr( ( (hexdec( $p[$i] ) << $k) + $min ) ) : chr( ( (hexdec( $p[$i] ) << $k) + $max ) );
        $i++;
        }
        return $this->b;
   
    }

    public function DecryptData($s, $min, $max) {
        $i = 0;
        $k = 1;
        $p = str_split($s);
        unset($p[sizeof($p) + 1]);
        //$p = $this->Build($s);
        while($i < sizeof($p)) {
        $this->c[$i] = ($i & 2) ?  dechex( ( (ord( $p[$i] ) - $min ) >> $k )  )   :   dechex( ( ( ord( $p[$i] ) - $max ) >> $k) );
        $i++;
        }
        return $this->Decode($this->c);
    }

    public function GenerateKeys($a, $l = 4, $min = 10, $max = 12)
    {
   
        $rb;
        for($k = 0;$k <= $l; $k++){
            if(!empty($a[$k])){
                if(ord($a[$k]) & 2){
                    $rb .= 1;   
                }
                else{
                    $rb .= 0;
                }
            }
            else{
                break;
            }
        }
        if(strlen($rb) >= $l){
            $this->setKeys('min', (($min * $l) + ord(chr(bindec($rb))) > 240) ? 240 : ($min * $l) + ord(chr(bindec($rb))));
            $this->setKeys('max', (($max * $l) + ord(chr(bindec($rb))) > 240)  ? 240 : ($max * $l) + ord(chr(bindec($rb))));           
        }
        else if(strlen($rb) < $l){
            $this->setKeys('min', ((sizeof($a) + $min) * $l) + ord(chr(bindec($rb))));
            $this->setKeys('max', ((sizeof($a) + $max) * $l) + ord(chr(bindec($rb))));
        }
        return $this->getKeys();
   
   
    }
    private function setKeys($i,$key)
    {
        $this->key[$i] = $key;
    }

    protected function getKeys(){

        return $this->key;
    }
}

The out put for say "Hello", depending on the key or modifier used, the output would be something like ^$$IL, or it could come out &&&&9.
 
Last edited:
@Codex NG for someone who has plain version of script it's possible to guess,
for those who have only bytecode version it would be harder

could anyone check if script encoded on windows works on linux and vice versa?
 
Last edited:
could anyone check if script encoded on windows works on linux and vice versa?
It should, it is Lua bytecode, that is why it will still work the same way it would in plain text. It is not encryption nor encoding, its practical use - other than the original one, that is, to make the program lighter and slightly faster to run in embedded systems - is at most obfuscation of a Lua file.

Code:
local script = string.dump(
    function()
        function example(player)
            print(player:getId())
            return true
        end
        return true
    end
)

--[[
buff=""
for v=1,string.len(script) do --Convert our string into a hex string.
    buff=buff..'\\'..string.byte(script,v)
    -- encrypted output
    -- io.write(string.char(string.byte(script,v)))
end]]

file=io.open('encrypted.txt','wb') --Output our bytecode into ascii format to encrypted.txt
file:write(script)
--file:flush() -- ?
file:close()

local luadec = io.popen('luadec.exe encrypted.txt', 'rb')
print(luadec:read('*all'))
luadec:close()

Output:
Code:
C:\Users\Cezar\Documents\Code\Luadec>lua a.lua
-- Decompiled using luadec 2.0 standard by sztupy (http://luadec51.luaforge.net)
-- Command line was: encrypted.txt

()
  example = function(l_1_0)
    print(l_1_0:getId())
    return true
   end
  return true

No matter what you do with any Lua file, if it can still be interpreted by a vanilla host (i.e TFS/Bots), its content can't be hidden.

LuaDec luaforge's repository for the interested.
 
tried with function from my previous post with script I posted and last 3 lines of your script and got this:

F:\ot\luac>luadec encrypted.txt
luadec: encrypted.txt: bad constant in precompiled chunk


btw. is there anything like pjorion or solace scriptmaze for lua?
I suppose they work a bit different way than just bytecoding the script.
 
Last edited:
Back
Top