├── .dockerignore ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── Dockerfile ├── bin ├── lua51.dll └── luajit.exe ├── esbuild.js ├── index.js ├── lua ├── cli.lua ├── colors.lua ├── config.lua ├── highlightlua.lua ├── logger.lua ├── presets.lua ├── prometheus.lua └── prometheus │ ├── ast.lua │ ├── bit.lua │ ├── compiler │ └── compiler.lua │ ├── enums.lua │ ├── namegenerators.lua │ ├── namegenerators │ ├── Il.lua │ ├── confuse.lua │ ├── mangled.lua │ ├── mangled_shuffled.lua │ └── number.lua │ ├── parser.lua │ ├── pipeline.lua │ ├── randomLiterals.lua │ ├── randomStrings.lua │ ├── scope.lua │ ├── step.lua │ ├── steps.lua │ ├── steps │ ├── AddVararg.lua │ ├── AntiTamper.lua │ ├── ConstantArray.lua │ ├── EncryptStrings.lua │ ├── NumbersToExpressions.lua │ ├── ProxifyLocals.lua │ ├── SplitStrings.lua │ ├── Vmify.lua │ └── WrapInFunction.lua │ ├── tokenizer.lua │ ├── unparser.lua │ ├── util.lua │ └── visitast.lua ├── package-lock.json ├── package.json ├── src ├── index.ts ├── logger.ts └── obfuscate.ts └── tsconfig.json /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | esbuild.js 2 | index.js 3 | node_modules -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | }, 6 | extends: [ 7 | 'airbnb-base', 8 | ], 9 | parser: '@typescript-eslint/parser', 10 | parserOptions: { 11 | ecmaVersion: 'latest', 12 | sourceType: 'module', 13 | }, 14 | plugins: [ 15 | '@typescript-eslint', 16 | ], 17 | rules: { 18 | 'linebreak-style': 0, 19 | 'no-console': 'off', 20 | 'import/no-unresolved': 0, 21 | 'import/extensions': 0, 22 | indent: ['error', 4], 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node related stuff 2 | node_modules 3 | .vscode 4 | 5 | # Do not share Bot token 6 | .env -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:latest 2 | 3 | # install nodejs 4 | RUN apt-get update && apt-get install -y curl 5 | RUN apt-get install -y nodejs 6 | RUN apt-get install -y npm 7 | 8 | # install lua 9 | RUN apt-get install -y lua5.3 10 | 11 | # Create app directory 12 | WORKDIR /usr/src/app 13 | 14 | # Install app dependencies 15 | # A wildcard is used to ensure both package.json AND package-lock.json are copied 16 | # where available (npm@5+) 17 | COPY package*.json ./ 18 | 19 | RUN npm install 20 | # If you are building your code for production 21 | # RUN npm ci --only=production 22 | 23 | # Bundle app source 24 | COPY . . 25 | 26 | RUN npm run build 27 | 28 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /bin/lua51.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prometheus-lua/Prometheus-discord-bot/f4b33792f3834292635f1fde7bff75193a8cdfd7/bin/lua51.dll -------------------------------------------------------------------------------- /bin/luajit.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prometheus-lua/Prometheus-discord-bot/f4b33792f3834292635f1fde7bff75193a8cdfd7/bin/luajit.exe -------------------------------------------------------------------------------- /esbuild.js: -------------------------------------------------------------------------------- 1 | const { nodeExternalsPlugin } = require('esbuild-node-externals'); 2 | 3 | require('esbuild').build({ 4 | entryPoints: ['./src/index.ts'], 5 | sourceRoot: './src', 6 | bundle: true, 7 | outfile: 'index.js', 8 | minify: true, 9 | plugins: [nodeExternalsPlugin()], 10 | external: ['fs', 'child_process'], 11 | minifyWhitespace: false, 12 | }).catch(() => process.exit(1)); 13 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | (()=>{var C=Object.create;var w=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var R=Object.getPrototypeOf,U=Object.prototype.hasOwnProperty;var i=(e=>typeof require!="undefined"?require:typeof Proxy!="undefined"?new Proxy(e,{get:(t,o)=>(typeof require!="undefined"?require:t)[o]}):e)(function(e){if(typeof require!="undefined")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});var D=(e,t,o,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of A(t))!U.call(e,n)&&n!==o&&w(e,n,{get:()=>t[n],enumerable:!(s=M(t,n))||s.enumerable});return e};var m=(e,t,o)=>(o=e!=null?C(R(e)):{},D(t||!e||!e.__esModule?w(o,"default",{value:e,enumerable:!0}):o,e));var L=i("dotenv/config"),r=i("discord.js"),B=i("@colors/colors"),S=i("uuid"),P=m(i("tmp")),O=m(i("axios")),E=m(i("fs"));var l={log:(...e)=>{console.log("[PROMETHEUS]".magenta,...e)},warn:(...e)=>{console.warn("[PROMETHEUS]".yellow,...e)},error:(...e)=>{console.error("[PROMETHEUS]".red,...e)}};var h=m(i("tmp")),y=i("child_process");function p(e,t){return new Promise((o,s)=>{let n=h.default.fileSync(),a=(0,y.spawn)("./bin/luajit.exe",["./lua/cli.lua","--preset",t,e,"--out",n.name]);a.stderr.on("data",c=>{l.error(c.toString()),s(c.toString())}),a.on("close",()=>{o(n)})})}var k=process.env.DISCORD_TOKEN;l.log("Bot is starting ...");var u=new r.Client({intents:[r.Intents.FLAGS.DIRECT_MESSAGES,r.Intents.FLAGS.DIRECT_MESSAGE_REACTIONS],partials:["CHANNEL"]});u.login(k);u.once("ready",()=>{l.log(`Logged in as ${(u.user?.tag||"Unknown").cyan}`)});var d=new Map;u.on("interactionCreate",async e=>{if(!e.isButton())return;let t=d.get(e.customId);if(!t){e.update({embeds:[{title:"Prometheus Obfuscator",description:"Something went wrong. Please try again.",color:"#ff8800"}],components:[]});return}let{message:o}=t;e.update({}),console.log(`${(t.tag||"Unknown User").cyan} -> ${t.url} @ ${t.preset}`),await o.edit({embeds:[{title:"Prometheus Obfuscator",description:`\u{1F504} Uploading your file ... 2 | \u{1F504} Obfuscating your file using ${t?.preset} Preset ... 3 | \u{1F504} Downloading your file ...`,color:"#ff8800"}],components:[]});let s=P.default.fileSync({postfix:".lua"}),n=await(0,O.default)({method:"GET",url:t.url,responseType:"stream"});if(n.headers["content-length"]&&Number.parseInt(n.headers["content-length"],10)>4e4){o.edit({embeds:[{title:"Prometheus Obfuscator",description:`The max filesize for the obfuscator bot is 40KB. 4 | If you want to obfuscate larger files, please use the standalone version.`,color:"#ff0000"}],components:[]});return}n.data.pipe(E.default.createWriteStream(s.name));try{await new Promise((f,I)=>{n.data.on("end",()=>{f()}),n.data.on("error",()=>{I()})})}catch{o.edit({embeds:[{title:"Prometheus Obfuscator",description:"Upload failed! Please try again.",color:"#ff0000"}],components:[]});return}await o.edit({embeds:[{title:"Prometheus Obfuscator",description:`\u2705 Uploading your file ... 5 | \u{1F504} Obfuscating your file using ${t?.preset} Preset ... 6 | \u{1F504} Downloading your file ...`,color:"#ff8800"}],components:[]});let a;try{a=await p(s.name,t.preset)}catch(f){o.edit({embeds:[{title:"Prometheus Obfuscator",description:`Obfuscation failed: 7 | ${f}`,color:"#ff0000"}],components:[]});return}await o.edit({embeds:[{title:"Prometheus Obfuscator",description:`\u2705 Uploading your file ... 8 | \u2705 Obfuscating your file using ${t?.preset} Preset ... 9 | \u{1F504} Downloading your file ...`,color:"#ff8800"}],components:[]});let c=new r.MessageAttachment(a.name,"obfuscated.lua"),g=await o.channel.send({files:[c]}),b=g.attachments.first()?.url;if(!b){o.edit({embeds:[{title:"Prometheus Obfuscator",description:"Download failed! Please try again.",color:"#ff0000"}],components:[]});return}g.delete(),await o.edit({embeds:[{title:"Prometheus Obfuscator",description:`\u2705 Uploading your file ... 10 | \u2705 Obfuscating your file using ${t?.preset} Preset ... 11 | \u2705 Downloading your file ... 12 | 13 | \u{1F517} [Download](${b})`,color:"#00ff00"}],components:[]}),a.removeCallback(),s.removeCallback()});u.on("messageCreate",async e=>{if(!e.author.bot){let t=e.attachments.first()?.url;if(!t){e.reply("Please upload a file!");return}let o=new Array(3).fill(0).map(()=>(0,S.v4)()),s=new r.MessageActionRow().addComponents(new r.MessageButton().setCustomId(o[0]).setLabel("Weak").setStyle("SUCCESS"),new r.MessageButton().setCustomId(o[1]).setLabel("Medium").setStyle("PRIMARY"),new r.MessageButton().setCustomId(o[2]).setLabel("Strong").setStyle("DANGER")),n=`For much more options, please use the standalone version. 14 | 15 | Select the Preset to use:`,a=await e.reply({embeds:[{title:"Prometheus Obfuscator",color:"#ff8800",description:n}],components:[s]});d.set(o[0],{url:t,preset:"Weak",tag:e.author.tag,message:a}),d.set(o[1],{url:t,preset:"Medium",tag:e.author.tag,message:a}),d.set(o[2],{url:t,preset:"Strong",tag:e.author.tag,message:a})}});})(); 16 | -------------------------------------------------------------------------------- /lua/cli.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- test.lua 4 | -- This script contains the Code for the Prometheus CLI 5 | 6 | -- Configure package.path for requiring Prometheus 7 | local function script_path() 8 | local str = debug.getinfo(2, "S").source:sub(2) 9 | return str:match("(.*[/%\\])") 10 | end 11 | package.path = script_path() .. "?.lua;" .. package.path; 12 | ---@diagnostic disable-next-line: different-requires 13 | local Prometheus = require("prometheus"); 14 | Prometheus.Logger.logLevel = Prometheus.Logger.LogLevel.Info; 15 | 16 | -- Override Error callback 17 | --[[Prometheus.Logger.errorCallback = function(...) 18 | print(Prometheus.colors(Prometheus.Config.NameUpper .. ": " .. ..., "red")) 19 | os.exit(1); 20 | end]] 21 | 22 | -- see if the file exists 23 | local function file_exists(file) 24 | local f = io.open(file, "rb") 25 | if f then f:close() end 26 | return f ~= nil 27 | end 28 | 29 | -- get all lines from a file, returns an empty 30 | -- list/table if the file does not exist 31 | local function lines_from(file) 32 | if not file_exists(file) then return {} end 33 | local lines = {} 34 | for line in io.lines(file) do 35 | lines[#lines + 1] = line 36 | end 37 | return lines 38 | end 39 | 40 | -- CLI 41 | local config; 42 | local sourceFile; 43 | local outFile; 44 | local luaVersion; 45 | local prettyPrint; 46 | 47 | Prometheus.colors.enabled = true; 48 | 49 | -- Parse Arguments 50 | local i = 1; 51 | while i <= #arg do 52 | local curr = arg[i]; 53 | if curr:sub(1, 2) == "--" then 54 | if curr == "--preset" or curr == "--p" then 55 | if config then 56 | Prometheus.Logger:warn("The config was set multiple times"); 57 | end 58 | 59 | i = i + 1; 60 | local preset = Prometheus.Presets[arg[i]]; 61 | if not preset then 62 | Prometheus.Logger:error(string.format("A Preset with the name \"%s\" was not found!", tostring(arg[i]))); 63 | end 64 | 65 | config = preset; 66 | elseif curr == "--config" or curr == "--c" then 67 | i = i + 1; 68 | local filename = tostring(arg[i]); 69 | if not file_exists(filename) then 70 | Prometheus.Logger:error(string.format("The config file \"%s\" was not found!", filename)); 71 | end 72 | 73 | local content = table.concat(lines_from(filename), "\n"); 74 | -- Load Config from File 75 | local func = loadstring(content); 76 | -- Sandboxing 77 | setfenv(func, {}); 78 | config = func(); 79 | elseif curr == "--out" or curr == "--o" then 80 | i = i + 1; 81 | if(outFile) then 82 | Prometheus.Logger:warn("The output file was specified multiple times!"); 83 | end 84 | outFile = arg[i]; 85 | elseif curr == "--nocolors" then 86 | Prometheus.colors.enabled = false; 87 | elseif curr == "--Lua51" then 88 | luaVersion = "Lua51"; 89 | elseif curr == "--LuaU" then 90 | luaVersion = "LuaU"; 91 | elseif curr == "--pretty" then 92 | prettyPrint = true; 93 | else 94 | Prometheus.Logger:warn(string.format("The option \"%s\" is not valid and therefore ignored", curr)); 95 | end 96 | else 97 | if sourceFile then 98 | Prometheus.Logger:error(string.format("Unexpected argument \"%s\"", arg[i])); 99 | end 100 | sourceFile = tostring(arg[i]); 101 | end 102 | i = i + 1; 103 | end 104 | 105 | if not sourceFile then 106 | Prometheus.Logger:error("No input file was specified!") 107 | end 108 | 109 | if not config then 110 | Prometheus.Logger:warn("No config was specified, falling back to Minify preset"); 111 | config = Prometheus.Presets.Minify; 112 | end 113 | 114 | -- Add Option to override Lua Version 115 | config.LuaVersion = luaVersion or config.LuaVersion; 116 | config.PrettyPrint = prettyPrint ~= nil and prettyPrint or config.PrettyPrint; 117 | 118 | if not file_exists(sourceFile) then 119 | Prometheus.Logger:error(string.format("The File \"%s\" was not found!", sourceFile)); 120 | end 121 | 122 | if not outFile then 123 | if sourceFile:sub(-4) == ".lua" then 124 | outFile = sourceFile:sub(0, -5) .. ".obfuscated.lua"; 125 | else 126 | outFile = sourceFile .. ".obfuscated.lua"; 127 | end 128 | end 129 | 130 | local source = table.concat(lines_from(sourceFile), "\n"); 131 | local pipeline = Prometheus.Pipeline:fromConfig(config); 132 | local out = pipeline:apply(source, sourceFile); 133 | Prometheus.Logger:info(string.format("Writing output to \"%s\"", outFile)); 134 | 135 | -- Write Output 136 | local handle = io.open(outFile, "w"); 137 | handle:write(out); 138 | handle:close(); -------------------------------------------------------------------------------- /lua/colors.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | 3 | local keys = { 4 | reset = 0, 5 | 6 | bright = 1, 7 | dim = 2, 8 | underline = 4, 9 | blink = 5, 10 | reverse = 7, 11 | hidden = 8, 12 | 13 | black = 30, 14 | pink = 91, 15 | red = 31, 16 | green = 32, 17 | yellow = 33, 18 | blue = 34, 19 | magenta = 35, 20 | cyan = 36, 21 | grey = 37, 22 | gray = 37, 23 | white = 97, 24 | 25 | blackbg = 40, 26 | redbg = 41, 27 | greenbg = 42, 28 | yellowbg = 43, 29 | bluebg = 44, 30 | magentabg = 45, 31 | cyanbg = 46, 32 | greybg = 47, 33 | graybg = 47, 34 | whitebg = 107, 35 | } 36 | 37 | local escapeString = string.char(27) .. '[%dm'; 38 | local function escapeNumber(number) 39 | return escapeString:format(number) 40 | end 41 | 42 | 43 | local settings = { 44 | enabled = true, 45 | } 46 | 47 | local function colors(str, ...) 48 | if not settings.enabled then 49 | return str; 50 | end 51 | str = tostring(str or '') 52 | 53 | local escapes = {}; 54 | for i, name in ipairs({...}) do 55 | table.insert(escapes, escapeNumber(keys[name])) 56 | end 57 | 58 | return escapeNumber(keys.reset) .. table.concat(escapes) .. str .. escapeNumber(keys.reset); 59 | end 60 | 61 | return setmetatable(settings, { __call = function(_, ...) return colors(...) end}); -------------------------------------------------------------------------------- /lua/config.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- config.lua 4 | -- 5 | -- In this Script, some Global config Variables are defined 6 | 7 | local NAME = "Prometheus"; 8 | local REVISION = "Alpha"; 9 | local VERSION = "v0.2"; 10 | local BY = "levno-710"; 11 | 12 | for _, currArg in pairs(arg) do 13 | if currArg == "--CI" then 14 | local releaseName = string.gsub(string.format("%s %s %s", NAME, REVISION, VERSION), "%s", "-") 15 | print(releaseName) 16 | end 17 | 18 | if currArg == "--FullVersion" then 19 | print(VERSION) 20 | end 21 | end 22 | 23 | -- Config Starts here 24 | return { 25 | Name = NAME, 26 | NameUpper = string.upper(NAME), 27 | NameAndVersion = string.format("%s %s", NAME, VERSION), 28 | Version = VERSION; 29 | Revision = REVISION; 30 | -- Config Starts Here 31 | IdentPrefix = "__prometheus_"; -- The Prefix used for Identifiers generated by PROMETHEUS. NOTE: There should be no identifiers in the script to be obfuscated starting with that prefix, because that can lead to weird bugs 32 | 33 | SPACE = " "; -- The Whitespace to be used by the unparser 34 | TAB = "\t"; -- The Tab Whitespace to be used by the unparser for pretty printing 35 | } -------------------------------------------------------------------------------- /lua/highlightlua.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- This Script provides a simple Method for Syntax Highlighting of Lua code 4 | 5 | local Tokenizer = require("prometheus.tokenizer"); 6 | local colors = require("colors"); 7 | local TokenKind = Tokenizer.TokenKind; 8 | local lookupify = require("prometheus.util").lookupify; 9 | 10 | return function(code, luaVersion) 11 | local out = ""; 12 | local tokenizer = Tokenizer:new({ 13 | LuaVersion = luaVersion, 14 | }); 15 | 16 | tokenizer:append(code); 17 | local tokens = tokenizer:scanAll(); 18 | 19 | local nonColorSymbols = lookupify{ 20 | ",", ";", "(", ")", "{", "}", ".", ":", "[", "]" 21 | } 22 | 23 | local defaultGlobals = lookupify{ 24 | "string", "table", "bit32", "bit" 25 | } 26 | 27 | local currentPos = 1; 28 | for _, token in ipairs(tokens) do 29 | if token.startPos >= currentPos then 30 | out = out .. string.sub(code, currentPos, token.startPos); 31 | end 32 | if token.kind == TokenKind.Ident then 33 | if defaultGlobals[token.source] then 34 | out = out .. colors(token.source, "red"); 35 | else 36 | out = out .. token.source; 37 | end 38 | elseif token.kind == TokenKind.Keyword then 39 | if token.source == "nil" then 40 | out = out .. colors(token.source, "yellow"); 41 | else 42 | out = out .. colors(token.source, "yellow"); 43 | end 44 | elseif token.kind == TokenKind.Symbol then 45 | if nonColorSymbols[token.source] then 46 | out = out .. token.source; 47 | else 48 | out = out .. colors(token.source, "yellow"); 49 | end 50 | elseif token.kind == TokenKind.String then 51 | out = out .. colors(token.source, "green") 52 | elseif token.kind == TokenKind.Number then 53 | out = out .. colors(token.source, "red") 54 | else 55 | out = out .. token.source; 56 | end 57 | 58 | currentPos = token.endPos + 1; 59 | end 60 | return out; 61 | end -------------------------------------------------------------------------------- /lua/logger.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- logger.lua 4 | 5 | local logger = {} 6 | local config = require("config"); 7 | local colors = require("colors"); 8 | 9 | logger.LogLevel = { 10 | Error = 0, 11 | Warn = 1, 12 | Log = 2, 13 | Info = 2, 14 | Debug = 3, 15 | } 16 | 17 | logger.logLevel = logger.LogLevel.Log; 18 | 19 | logger.debugCallback = function(...) 20 | print(colors(config.NameUpper .. ": " .. ..., "grey")); 21 | end; 22 | function logger:debug(...) 23 | if self.logLevel >= self.LogLevel.Debug then 24 | self.debugCallback(...); 25 | end 26 | end 27 | 28 | logger.logCallback = function(...) 29 | print(colors(config.NameUpper .. ": ", "magenta") .. ...); 30 | end; 31 | function logger:log(...) 32 | if self.logLevel >= self.LogLevel.Log then 33 | self.logCallback(...); 34 | end 35 | end 36 | 37 | function logger:info(...) 38 | if self.logLevel >= self.LogLevel.Log then 39 | self.logCallback(...); 40 | end 41 | end 42 | 43 | logger.warnCallback = function(...) 44 | print(colors(config.NameUpper .. ": " .. ..., "yellow")); 45 | end; 46 | function logger:warn(...) 47 | if self.logLevel >= self.LogLevel.Warn then 48 | self.warnCallback(...); 49 | end 50 | end 51 | 52 | logger.errorCallback = function(...) 53 | print(colors(config.NameUpper .. ": " .. ..., "red")) 54 | error(...); 55 | end; 56 | function logger:error(...) 57 | self.errorCallback(...); 58 | error(config.NameUpper .. ": logger.errorCallback did not throw an Error!"); 59 | end 60 | 61 | 62 | return logger; -------------------------------------------------------------------------------- /lua/presets.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- pipeline.lua 4 | -- 5 | -- This Script Provides some configuration presets 6 | 7 | return { 8 | ["Minify"] = { 9 | -- The default LuaVersion is Lua51 10 | LuaVersion = "Lua51"; 11 | -- For minifying no VarNamePrefix is applied 12 | VarNamePrefix = ""; 13 | -- Name Generator for Variables 14 | NameGenerator = "MangledShuffled"; 15 | -- No pretty printing 16 | PrettyPrint = false; 17 | -- Seed is generated based on current time 18 | Seed = 0; 19 | -- No obfuscation steps 20 | Steps = { 21 | 22 | } 23 | }; 24 | ["Weak"] = { 25 | -- The default LuaVersion is Lua51 26 | LuaVersion = "Lua51"; 27 | -- For minifying no VarNamePrefix is applied 28 | VarNamePrefix = ""; 29 | -- Name Generator for Variables that look like this: IlI1lI1l 30 | NameGenerator = "MangledShuffled"; 31 | -- No pretty printing 32 | PrettyPrint = false; 33 | -- Seed is generated based on current time 34 | Seed = 0; 35 | -- Obfuscation steps 36 | Steps = { 37 | { 38 | Name = "Vmify"; 39 | Settings = { 40 | 41 | }; 42 | }, 43 | { 44 | Name = "ConstantArray"; 45 | Settings = { 46 | Treshold = 1; 47 | StringsOnly = true; 48 | } 49 | }, 50 | { 51 | Name = "WrapInFunction"; 52 | Settings = { 53 | 54 | } 55 | }, 56 | } 57 | }; 58 | ["Medium"] = { 59 | -- The default LuaVersion is Lua51 60 | LuaVersion = "Lua51"; 61 | -- For minifying no VarNamePrefix is applied 62 | VarNamePrefix = ""; 63 | -- Name Generator for Variables 64 | NameGenerator = "MangledShuffled"; 65 | -- No pretty printing 66 | PrettyPrint = false; 67 | -- Seed is generated based on current time 68 | Seed = 0; 69 | -- Obfuscation steps 70 | Steps = { 71 | { 72 | Name = "EncryptStrings"; 73 | Settings = { 74 | 75 | }; 76 | }, 77 | { 78 | Name = "AntiTamper"; 79 | Settings = { 80 | UseDebug = false; 81 | }; 82 | }, 83 | { 84 | Name = "Vmify"; 85 | Settings = { 86 | 87 | }; 88 | }, 89 | { 90 | Name = "ConstantArray"; 91 | Settings = { 92 | Treshold = 1; 93 | StringsOnly = true; 94 | Shuffle = true; 95 | Rotate = true; 96 | LocalWrapperTreshold = 0; 97 | } 98 | }, 99 | { 100 | Name = "NumbersToExpressions"; 101 | Settings = { 102 | 103 | } 104 | }, 105 | { 106 | Name = "WrapInFunction"; 107 | Settings = { 108 | 109 | } 110 | }, 111 | } 112 | }; 113 | ["Strong"] = { 114 | -- The default LuaVersion is Lua51 115 | LuaVersion = "Lua51"; 116 | -- For minifying no VarNamePrefix is applied 117 | VarNamePrefix = ""; 118 | -- Name Generator for Variables that look like this: IlI1lI1l 119 | NameGenerator = "MangledShuffled"; 120 | -- No pretty printing 121 | PrettyPrint = false; 122 | -- Seed is generated based on current time 123 | Seed = 0; 124 | -- Obfuscation steps 125 | Steps = { 126 | { 127 | Name = "Vmify"; 128 | Settings = { 129 | 130 | }; 131 | }, 132 | { 133 | Name = "EncryptStrings"; 134 | Settings = { 135 | 136 | }; 137 | }, 138 | { 139 | Name = "AntiTamper"; 140 | Settings = { 141 | 142 | }; 143 | }, 144 | { 145 | Name = "Vmify"; 146 | Settings = { 147 | 148 | }; 149 | }, 150 | { 151 | Name = "ConstantArray"; 152 | Settings = { 153 | Treshold = 1; 154 | StringsOnly = true; 155 | Shuffle = true; 156 | Rotate = true; 157 | LocalWrapperTreshold = 0; 158 | } 159 | }, 160 | { 161 | Name = "NumbersToExpressions"; 162 | Settings = { 163 | 164 | } 165 | }, 166 | { 167 | Name = "WrapInFunction"; 168 | Settings = { 169 | 170 | } 171 | }, 172 | } 173 | }, 174 | } -------------------------------------------------------------------------------- /lua/prometheus.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- prometheus.lua 4 | -- This file is the entrypoint for Prometheus 5 | 6 | -- Configure package.path for require 7 | local function script_path() 8 | local str = debug.getinfo(2, "S").source:sub(2) 9 | return str:match("(.*[/%\\])") 10 | end 11 | 12 | local oldPkgPath = package.path; 13 | package.path = script_path() .. "?.lua;" .. package.path; 14 | 15 | -- Math.random Fix for Lua5.1 16 | -- Check if fix is needed 17 | if not pcall(function() 18 | return math.random(1, 2^40); 19 | end) then 20 | local oldMathRandom = math.random; 21 | math.random = function(a, b) 22 | if not a and b then 23 | return oldMathRandom(); 24 | end 25 | if not b then 26 | return math.random(1, a); 27 | end 28 | if a > b then 29 | a, b = b, a; 30 | end 31 | local diff = b - a; 32 | assert(diff >= 0); 33 | if diff > 2 ^ 31 - 1 then 34 | return math.floor(oldMathRandom() * diff + a); 35 | else 36 | return oldMathRandom(a, b); 37 | end 38 | end 39 | end 40 | 41 | -- newproxy polyfill 42 | _G.newproxy = _G.newproxy or function(arg) 43 | if arg then 44 | return setmetatable({}, {}); 45 | end 46 | return {}; 47 | end 48 | 49 | 50 | -- Require Prometheus Submodules 51 | local Pipeline = require("prometheus.pipeline"); 52 | local highlight = require("highlightlua"); 53 | local colors = require("colors"); 54 | local Logger = require("logger"); 55 | local Presets = require("presets"); 56 | local Config = require("config"); 57 | local util = require("prometheus.util"); 58 | 59 | -- Restore package.path 60 | package.path = oldPkgPath; 61 | 62 | -- Export 63 | return { 64 | Pipeline = Pipeline; 65 | colors = colors; 66 | Config = util.readonly(Config); -- Readonly 67 | Logger = Logger; 68 | highlight = highlight; 69 | Presets = Presets; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /lua/prometheus/ast.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- ast.lua 4 | 5 | local Ast = {} 6 | 7 | local AstKind = { 8 | -- Misc 9 | TopNode = "TopNode"; 10 | Block = "Block"; 11 | 12 | -- Statements 13 | ContinueStatement = "ContinueStatement"; 14 | BreakStatement = "BreakStatement"; 15 | DoStatement = "DoStatement"; 16 | WhileStatement = "WhileStatement"; 17 | ReturnStatement = "ReturnStatement"; 18 | RepeatStatement = "RepeatStatement"; 19 | ForInStatement = "ForInStatement"; 20 | ForStatement = "ForStatement"; 21 | IfStatement = "IfStatement"; 22 | FunctionDeclaration = "FunctionDeclaration"; 23 | LocalFunctionDeclaration = "LocalFunctionDeclaration"; 24 | LocalVariableDeclaration = "LocalVariableDeclaration"; 25 | FunctionCallStatement = "FunctionCallStatement"; 26 | PassSelfFunctionCallStatement = "PassSelfFunctionCallStatement"; 27 | AssignmentStatement = "AssignmentStatement"; 28 | 29 | -- LuaU Compound Statements 30 | CompoundAddStatement = "CompoundAddStatement"; 31 | CompoundSubStatement = "CompoundSubStatement"; 32 | CompoundMulStatement = "CompoundMulStatement"; 33 | CompoundDivStatement = "CompoundDivStatement"; 34 | CompoundModStatement = "CompoundModStatement"; 35 | CompoundPowStatement = "CompoundPowStatement"; 36 | CompoundConcatStatement = "CompoundConcatStatement"; 37 | 38 | -- Assignment Index 39 | AssignmentIndexing = "AssignmentIndexing"; 40 | AssignmentVariable = "AssignmentVariable"; 41 | 42 | -- Expression Nodes 43 | BooleanExpression = "BooleanExpression"; 44 | NumberExpression = "NumberExpression"; 45 | StringExpression = "StringExpression"; 46 | NilExpression = "NilExpression"; 47 | VarargExpression = "VarargExpression"; 48 | OrExpression = "OrExpression"; 49 | AndExpression = "AndExpression"; 50 | LessThanExpression = "LessThanExpression"; 51 | GreaterThanExpression = "GreaterThanExpression"; 52 | LessThanOrEqualsExpression = "LessThanOrEqualsExpression"; 53 | GreaterThanOrEqualsExpression = "GreaterThanOrEqualsExpression"; 54 | NotEqualsExpression = "NotEqualsExpression"; 55 | EqualsExpression = "EqualsExpression"; 56 | StrCatExpression = "StrCatExpression"; 57 | AddExpression = "AddExpression"; 58 | SubExpression = "SubExpression"; 59 | MulExpression = "MulExpression"; 60 | DivExpression = "DivExpression"; 61 | ModExpression = "ModExpression"; 62 | NotExpression = "NotExpression"; 63 | LenExpression = "LenExpression"; 64 | NegateExpression = "NegateExpression"; 65 | PowExpression = "PowExpression"; 66 | IndexExpression = "IndexExpression"; 67 | FunctionCallExpression = "FunctionCallExpression"; 68 | PassSelfFunctionCallExpression = "PassSelfFunctionCallExpression"; 69 | VariableExpression = "VariableExpression"; 70 | FunctionLiteralExpression = "FunctionLiteralExpression"; 71 | TableConstructorExpression = "TableConstructorExpression"; 72 | 73 | -- Table Entry 74 | TableEntry = "TableEntry"; 75 | KeyedTableEntry = "KeyedTableEntry"; 76 | 77 | -- Misc 78 | NopStatement = "NopStatement"; 79 | } 80 | 81 | local astKindExpressionLookup = { 82 | [AstKind.BooleanExpression] = 0; 83 | [AstKind.NumberExpression] = 0; 84 | [AstKind.StringExpression] = 0; 85 | [AstKind.NilExpression] = 0; 86 | [AstKind.VarargExpression] = 0; 87 | [AstKind.OrExpression] = 12; 88 | [AstKind.AndExpression] = 11; 89 | [AstKind.LessThanExpression] = 10; 90 | [AstKind.GreaterThanExpression] = 10; 91 | [AstKind.LessThanOrEqualsExpression] = 10; 92 | [AstKind.GreaterThanOrEqualsExpression] = 10; 93 | [AstKind.NotEqualsExpression] = 10; 94 | [AstKind.EqualsExpression] = 10; 95 | [AstKind.StrCatExpression] = 9; 96 | [AstKind.AddExpression] = 8; 97 | [AstKind.SubExpression] = 8; 98 | [AstKind.MulExpression] = 7; 99 | [AstKind.DivExpression] = 7; 100 | [AstKind.ModExpression] = 7; 101 | [AstKind.NotExpression] = 5; 102 | [AstKind.LenExpression] = 5; 103 | [AstKind.NegateExpression] = 5; 104 | [AstKind.PowExpression] = 4; 105 | [AstKind.IndexExpression] = 1; 106 | [AstKind.AssignmentIndexing] = 1; 107 | [AstKind.FunctionCallExpression] = 2; 108 | [AstKind.PassSelfFunctionCallExpression] = 2; 109 | [AstKind.VariableExpression] = 0; 110 | [AstKind.AssignmentVariable] = 0; 111 | [AstKind.FunctionLiteralExpression] = 3; 112 | [AstKind.TableConstructorExpression] = 3; 113 | } 114 | 115 | Ast.AstKind = AstKind; 116 | 117 | function Ast.astKindExpressionToNumber(kind) 118 | return astKindExpressionLookup[kind] or 100; 119 | end 120 | 121 | function Ast.ConstantNode(val) 122 | if type(val) == "nil" then 123 | return Ast.NilExpression(); 124 | end 125 | 126 | if type(val) == "string" then 127 | return Ast.StringExpression(val); 128 | end 129 | 130 | if type(val) == "number" then 131 | return Ast.NumberExpression(val); 132 | end 133 | 134 | if type(val) == "boolean" then 135 | return Ast.BooleanExpression(val); 136 | end 137 | end 138 | 139 | 140 | 141 | function Ast.NopStatement() 142 | return { 143 | kind = AstKind.NopStatement; 144 | } 145 | end 146 | 147 | -- Create Ast Top Node 148 | function Ast.TopNode(body, globalScope) 149 | return { 150 | kind = AstKind.TopNode, 151 | body = body, 152 | globalScope = globalScope, 153 | 154 | } 155 | end 156 | 157 | function Ast.TableEntry(value) 158 | return { 159 | kind = AstKind.TableEntry, 160 | value = value, 161 | 162 | } 163 | end 164 | 165 | function Ast.KeyedTableEntry(key, value) 166 | return { 167 | kind = AstKind.KeyedTableEntry, 168 | key = key, 169 | value = value, 170 | 171 | } 172 | end 173 | 174 | function Ast.TableConstructorExpression(entries) 175 | return { 176 | kind = AstKind.TableConstructorExpression, 177 | entries = entries, 178 | }; 179 | end 180 | 181 | -- Create Statement Block 182 | function Ast.Block(statements, scope) 183 | return { 184 | kind = AstKind.Block, 185 | statements = statements, 186 | scope = scope, 187 | } 188 | end 189 | 190 | -- Create Break Statement 191 | function Ast.BreakStatement(loop, scope) 192 | return { 193 | kind = AstKind.BreakStatement, 194 | loop = loop, 195 | scope = scope, 196 | } 197 | end 198 | 199 | -- Create Continue Statement 200 | function Ast.ContinueStatement(loop, scope) 201 | return { 202 | kind = AstKind.ContinueStatement, 203 | loop = loop, 204 | scope = scope, 205 | } 206 | end 207 | 208 | function Ast.PassSelfFunctionCallStatement(base, passSelfFunctionName, args) 209 | return { 210 | kind = AstKind.PassSelfFunctionCallStatement, 211 | base = base, 212 | passSelfFunctionName = passSelfFunctionName, 213 | args = args, 214 | } 215 | end 216 | 217 | function Ast.AssignmentStatement(lhs, rhs) 218 | if(#lhs < 1) then 219 | print(debug.traceback()); 220 | error("Something went wrong!"); 221 | end 222 | return { 223 | kind = AstKind.AssignmentStatement, 224 | lhs = lhs, 225 | rhs = rhs, 226 | } 227 | end 228 | 229 | function Ast.CompoundAddStatement(lhs, rhs) 230 | return { 231 | kind = AstKind.CompoundAddStatement, 232 | lhs = lhs, 233 | rhs = rhs, 234 | } 235 | end 236 | 237 | function Ast.CompoundSubStatement(lhs, rhs) 238 | return { 239 | kind = AstKind.CompoundSubStatement, 240 | lhs = lhs, 241 | rhs = rhs, 242 | } 243 | end 244 | 245 | function Ast.CompoundMulStatement(lhs, rhs) 246 | return { 247 | kind = AstKind.CompoundMulStatement, 248 | lhs = lhs, 249 | rhs = rhs, 250 | } 251 | end 252 | 253 | function Ast.CompoundDivStatement(lhs, rhs) 254 | return { 255 | kind = AstKind.CompoundDivStatement, 256 | lhs = lhs, 257 | rhs = rhs, 258 | } 259 | end 260 | 261 | function Ast.CompoundPowStatement(lhs, rhs) 262 | return { 263 | kind = AstKind.CompoundPowStatement, 264 | lhs = lhs, 265 | rhs = rhs, 266 | } 267 | end 268 | 269 | function Ast.CompoundModStatement(lhs, rhs) 270 | return { 271 | kind = AstKind.CompoundModStatement, 272 | lhs = lhs, 273 | rhs = rhs, 274 | } 275 | end 276 | 277 | function Ast.CompoundConcatStatement(lhs, rhs) 278 | return { 279 | kind = AstKind.CompoundConcatStatement, 280 | lhs = lhs, 281 | rhs = rhs, 282 | } 283 | end 284 | 285 | function Ast.FunctionCallStatement(base, args) 286 | return { 287 | kind = AstKind.FunctionCallStatement, 288 | base = base, 289 | args = args, 290 | } 291 | end 292 | 293 | function Ast.ReturnStatement(args) 294 | return { 295 | kind = AstKind.ReturnStatement, 296 | args = args, 297 | } 298 | end 299 | 300 | function Ast.DoStatement(body) 301 | return { 302 | kind = AstKind.DoStatement, 303 | body = body, 304 | } 305 | end 306 | 307 | function Ast.WhileStatement(body, condition, parentScope) 308 | return { 309 | kind = AstKind.WhileStatement, 310 | body = body, 311 | condition = condition, 312 | parentScope = parentScope, 313 | } 314 | end 315 | 316 | function Ast.ForInStatement(scope, vars, expressions, body, parentScope) 317 | return { 318 | kind = AstKind.ForInStatement, 319 | scope = scope, 320 | ids = vars, 321 | vars = vars, 322 | expressions = expressions, 323 | body = body, 324 | parentScope = parentScope, 325 | } 326 | end 327 | 328 | function Ast.ForStatement(scope, id, initialValue, finalValue, incrementBy, body, parentScope) 329 | return { 330 | kind = AstKind.ForStatement, 331 | scope = scope, 332 | id = id, 333 | initialValue = initialValue, 334 | finalValue = finalValue, 335 | incrementBy = incrementBy, 336 | body = body, 337 | parentScope = parentScope, 338 | } 339 | end 340 | 341 | function Ast.RepeatStatement(condition, body, parentScope) 342 | return { 343 | kind = AstKind.RepeatStatement, 344 | body = body, 345 | condition = condition, 346 | parentScope = parentScope, 347 | } 348 | end 349 | 350 | function Ast.IfStatement(condition, body, elseifs, elsebody) 351 | return { 352 | kind = AstKind.IfStatement, 353 | condition = condition, 354 | body = body, 355 | elseifs = elseifs, 356 | elsebody = elsebody, 357 | } 358 | end 359 | 360 | function Ast.FunctionDeclaration(scope, id, indices, args, body) 361 | return { 362 | kind = AstKind.FunctionDeclaration, 363 | scope = scope, 364 | baseScope = scope, 365 | id = id, 366 | baseId = id, 367 | indices = indices, 368 | args = args, 369 | body = body, 370 | getName = function(self) 371 | return self.scope:getVariableName(self.id); 372 | end, 373 | } 374 | end 375 | 376 | function Ast.LocalFunctionDeclaration(scope, id, args, body) 377 | return { 378 | kind = AstKind.LocalFunctionDeclaration, 379 | scope = scope, 380 | id = id, 381 | args = args, 382 | body = body, 383 | getName = function(self) 384 | return self.scope:getVariableName(self.id); 385 | end, 386 | } 387 | end 388 | 389 | function Ast.LocalVariableDeclaration(scope, ids, expressions) 390 | return { 391 | kind = AstKind.LocalVariableDeclaration, 392 | scope = scope, 393 | ids = ids, 394 | expressions = expressions, 395 | } 396 | end 397 | 398 | function Ast.VarargExpression() 399 | return { 400 | kind = AstKind.VarargExpression; 401 | isConstant = false, 402 | } 403 | end 404 | 405 | function Ast.BooleanExpression(value) 406 | return { 407 | kind = AstKind.BooleanExpression, 408 | isConstant = true, 409 | value = value, 410 | } 411 | end 412 | 413 | function Ast.NilExpression() 414 | return { 415 | kind = AstKind.NilExpression, 416 | isConstant = true, 417 | value = nil, 418 | } 419 | end 420 | 421 | function Ast.NumberExpression(value) 422 | return { 423 | kind = AstKind.NumberExpression, 424 | isConstant = true, 425 | value = value, 426 | } 427 | end 428 | 429 | function Ast.StringExpression(value) 430 | return { 431 | kind = AstKind.StringExpression, 432 | isConstant = true, 433 | value = value, 434 | } 435 | end 436 | 437 | function Ast.OrExpression(lhs, rhs, simplify) 438 | if(simplify and rhs.isConstant and lhs.isConstant) then 439 | local success, val = pcall(function() return lhs.value or rhs.value end); 440 | if success then 441 | return Ast.ConstantNode(val); 442 | end 443 | end 444 | 445 | return { 446 | kind = AstKind.OrExpression, 447 | lhs = lhs, 448 | rhs = rhs, 449 | isConstant = false, 450 | } 451 | end 452 | 453 | function Ast.AndExpression(lhs, rhs, simplify) 454 | if(simplify and rhs.isConstant and lhs.isConstant) then 455 | local success, val = pcall(function() return lhs.value and rhs.value end); 456 | if success then 457 | return Ast.ConstantNode(val); 458 | end 459 | end 460 | 461 | return { 462 | kind = AstKind.AndExpression, 463 | lhs = lhs, 464 | rhs = rhs, 465 | isConstant = false, 466 | } 467 | end 468 | 469 | function Ast.LessThanExpression(lhs, rhs, simplify) 470 | if(simplify and rhs.isConstant and lhs.isConstant) then 471 | local success, val = pcall(function() return lhs.value < rhs.value end); 472 | if success then 473 | return Ast.ConstantNode(val); 474 | end 475 | end 476 | 477 | return { 478 | kind = AstKind.LessThanExpression, 479 | lhs = lhs, 480 | rhs = rhs, 481 | isConstant = false, 482 | } 483 | end 484 | 485 | function Ast.GreaterThanExpression(lhs, rhs, simplify) 486 | if(simplify and rhs.isConstant and lhs.isConstant) then 487 | local success, val = pcall(function() return lhs.value > rhs.value end); 488 | if success then 489 | return Ast.ConstantNode(val); 490 | end 491 | end 492 | 493 | return { 494 | kind = AstKind.GreaterThanExpression, 495 | lhs = lhs, 496 | rhs = rhs, 497 | isConstant = false, 498 | } 499 | end 500 | 501 | function Ast.LessThanOrEqualsExpression(lhs, rhs, simplify) 502 | if(simplify and rhs.isConstant and lhs.isConstant) then 503 | local success, val = pcall(function() return lhs.value <= rhs.value end); 504 | if success then 505 | return Ast.ConstantNode(val); 506 | end 507 | end 508 | 509 | return { 510 | kind = AstKind.LessThanOrEqualsExpression, 511 | lhs = lhs, 512 | rhs = rhs, 513 | isConstant = false, 514 | } 515 | end 516 | 517 | function Ast.GreaterThanOrEqualsExpression(lhs, rhs, simplify) 518 | if(simplify and rhs.isConstant and lhs.isConstant) then 519 | local success, val = pcall(function() return lhs.value >= rhs.value end); 520 | if success then 521 | return Ast.ConstantNode(val); 522 | end 523 | end 524 | 525 | return { 526 | kind = AstKind.GreaterThanOrEqualsExpression, 527 | lhs = lhs, 528 | rhs = rhs, 529 | isConstant = false, 530 | } 531 | end 532 | 533 | function Ast.NotEqualsExpression(lhs, rhs, simplify) 534 | if(simplify and rhs.isConstant and lhs.isConstant) then 535 | local success, val = pcall(function() return lhs.value ~= rhs.value end); 536 | if success then 537 | return Ast.ConstantNode(val); 538 | end 539 | end 540 | 541 | return { 542 | kind = AstKind.NotEqualsExpression, 543 | lhs = lhs, 544 | rhs = rhs, 545 | isConstant = false, 546 | } 547 | end 548 | 549 | function Ast.EqualsExpression(lhs, rhs, simplify) 550 | if(simplify and rhs.isConstant and lhs.isConstant) then 551 | local success, val = pcall(function() return lhs.value == rhs.value end); 552 | if success then 553 | return Ast.ConstantNode(val); 554 | end 555 | end 556 | 557 | return { 558 | kind = AstKind.EqualsExpression, 559 | lhs = lhs, 560 | rhs = rhs, 561 | isConstant = false, 562 | } 563 | end 564 | 565 | function Ast.StrCatExpression(lhs, rhs, simplify) 566 | if(simplify and rhs.isConstant and lhs.isConstant) then 567 | local success, val = pcall(function() return lhs.value .. rhs.value end); 568 | if success then 569 | return Ast.ConstantNode(val); 570 | end 571 | end 572 | 573 | return { 574 | kind = AstKind.StrCatExpression, 575 | lhs = lhs, 576 | rhs = rhs, 577 | isConstant = false, 578 | } 579 | end 580 | 581 | function Ast.AddExpression(lhs, rhs, simplify) 582 | if(simplify and rhs.isConstant and lhs.isConstant) then 583 | local success, val = pcall(function() return lhs.value + rhs.value end); 584 | if success then 585 | return Ast.ConstantNode(val); 586 | end 587 | end 588 | 589 | return { 590 | kind = AstKind.AddExpression, 591 | lhs = lhs, 592 | rhs = rhs, 593 | isConstant = false, 594 | } 595 | end 596 | 597 | function Ast.SubExpression(lhs, rhs, simplify) 598 | if(simplify and rhs.isConstant and lhs.isConstant) then 599 | local success, val = pcall(function() return lhs.value - rhs.value end); 600 | if success then 601 | return Ast.ConstantNode(val); 602 | end 603 | end 604 | 605 | return { 606 | kind = AstKind.SubExpression, 607 | lhs = lhs, 608 | rhs = rhs, 609 | isConstant = false, 610 | } 611 | end 612 | 613 | function Ast.MulExpression(lhs, rhs, simplify) 614 | if(simplify and rhs.isConstant and lhs.isConstant) then 615 | local success, val = pcall(function() return lhs.value * rhs.value end); 616 | if success then 617 | return Ast.ConstantNode(val); 618 | end 619 | end 620 | 621 | return { 622 | kind = AstKind.MulExpression, 623 | lhs = lhs, 624 | rhs = rhs, 625 | isConstant = false, 626 | } 627 | end 628 | 629 | function Ast.DivExpression(lhs, rhs, simplify) 630 | if(simplify and rhs.isConstant and lhs.isConstant and rhs.value ~= 0) then 631 | local success, val = pcall(function() return lhs.value / rhs.value end); 632 | if success then 633 | return Ast.ConstantNode(val); 634 | end 635 | end 636 | 637 | return { 638 | kind = AstKind.DivExpression, 639 | lhs = lhs, 640 | rhs = rhs, 641 | isConstant = false, 642 | } 643 | end 644 | 645 | function Ast.ModExpression(lhs, rhs, simplify) 646 | if(simplify and rhs.isConstant and lhs.isConstant) then 647 | local success, val = pcall(function() return lhs.value % rhs.value end); 648 | if success then 649 | return Ast.ConstantNode(val); 650 | end 651 | end 652 | 653 | return { 654 | kind = AstKind.ModExpression, 655 | lhs = lhs, 656 | rhs = rhs, 657 | isConstant = false, 658 | } 659 | end 660 | 661 | function Ast.NotExpression(rhs, simplify) 662 | if(simplify and rhs.isConstant) then 663 | local success, val = pcall(function() return not rhs.value end); 664 | if success then 665 | return Ast.ConstantNode(val); 666 | end 667 | end 668 | 669 | return { 670 | kind = AstKind.NotExpression, 671 | rhs = rhs, 672 | isConstant = false, 673 | } 674 | end 675 | 676 | function Ast.NegateExpression(rhs, simplify) 677 | if(simplify and rhs.isConstant) then 678 | local success, val = pcall(function() return -rhs.value end); 679 | if success then 680 | return Ast.ConstantNode(val); 681 | end 682 | end 683 | 684 | return { 685 | kind = AstKind.NegateExpression, 686 | rhs = rhs, 687 | isConstant = false, 688 | } 689 | end 690 | 691 | function Ast.LenExpression(rhs, simplify) 692 | if(simplify and rhs.isConstant) then 693 | local success, val = pcall(function() return #rhs.value end); 694 | if success then 695 | return Ast.ConstantNode(val); 696 | end 697 | end 698 | 699 | return { 700 | kind = AstKind.LenExpression, 701 | rhs = rhs, 702 | isConstant = false, 703 | } 704 | end 705 | 706 | function Ast.PowExpression(lhs, rhs, simplify) 707 | if(simplify and rhs.isConstant and lhs.isConstant) then 708 | local success, val = pcall(function() return lhs.value ^ rhs.value end); 709 | if success then 710 | return Ast.ConstantNode(val); 711 | end 712 | end 713 | 714 | return { 715 | kind = AstKind.PowExpression, 716 | lhs = lhs, 717 | rhs = rhs, 718 | isConstant = false, 719 | } 720 | end 721 | 722 | function Ast.IndexExpression(base, index) 723 | return { 724 | kind = AstKind.IndexExpression, 725 | base = base, 726 | index = index, 727 | isConstant = false, 728 | } 729 | end 730 | 731 | function Ast.AssignmentIndexing(base, index) 732 | return { 733 | kind = AstKind.AssignmentIndexing, 734 | base = base, 735 | index = index, 736 | isConstant = false, 737 | } 738 | end 739 | 740 | function Ast.PassSelfFunctionCallExpression(base, passSelfFunctionName, args) 741 | return { 742 | kind = AstKind.PassSelfFunctionCallExpression, 743 | base = base, 744 | passSelfFunctionName = passSelfFunctionName, 745 | args = args, 746 | 747 | } 748 | end 749 | 750 | function Ast.FunctionCallExpression(base, args) 751 | return { 752 | kind = AstKind.FunctionCallExpression, 753 | base = base, 754 | args = args, 755 | } 756 | end 757 | 758 | function Ast.VariableExpression(scope, id) 759 | scope:addReference(id); 760 | return { 761 | kind = AstKind.VariableExpression, 762 | scope = scope, 763 | id = id, 764 | getName = function(self) 765 | return self.scope.getVariableName(self.id); 766 | end, 767 | } 768 | end 769 | 770 | function Ast.AssignmentVariable(scope, id) 771 | scope:addReference(id); 772 | return { 773 | kind = AstKind.AssignmentVariable, 774 | scope = scope, 775 | id = id, 776 | getName = function(self) 777 | return self.scope.getVariableName(self.id); 778 | end, 779 | } 780 | end 781 | 782 | function Ast.FunctionLiteralExpression(args, body) 783 | return { 784 | kind = AstKind.FunctionLiteralExpression, 785 | args = args, 786 | body = body, 787 | } 788 | end 789 | 790 | 791 | 792 | return Ast; -------------------------------------------------------------------------------- /lua/prometheus/bit.lua: -------------------------------------------------------------------------------- 1 | -- This Module was NOT written by Levno_710 2 | -- Credit: https://github.com/davidm/lua-bit-numberlua 3 | 4 | --[[ 5 | LUA MODULE 6 | bit.numberlua - Bitwise operations implemented in pure Lua as numbers, 7 | with Lua 5.2 'bit32' and (LuaJIT) LuaBitOp 'bit' compatibility interfaces. 8 | SYNOPSIS 9 | local bit = require 'bit.numberlua' 10 | print(bit.band(0xff00ff00, 0x00ff00ff)) --> 0xffffffff 11 | 12 | -- Interface providing strong Lua 5.2 'bit32' compatibility 13 | local bit32 = require 'bit.numberlua'.bit32 14 | assert(bit32.band(-1) == 0xffffffff) 15 | 16 | -- Interface providing strong (LuaJIT) LuaBitOp 'bit' compatibility 17 | local bit = require 'bit.numberlua'.bit 18 | assert(bit.tobit(0xffffffff) == -1) 19 | 20 | DESCRIPTION 21 | 22 | This library implements bitwise operations entirely in Lua. 23 | This module is typically intended if for some reasons you don't want 24 | to or cannot install a popular C based bit library like BitOp 'bit' [1] 25 | (which comes pre-installed with LuaJIT) or 'bit32' (which comes 26 | pre-installed with Lua 5.2) but want a similar interface. 27 | 28 | This modules represents bit arrays as non-negative Lua numbers. [1] 29 | It can represent 32-bit bit arrays when Lua is compiled 30 | with lua_Number as double-precision IEEE 754 floating point. 31 | The module is nearly the most efficient it can be but may be a few times 32 | slower than the C based bit libraries and is orders or magnitude 33 | slower than LuaJIT bit operations, which compile to native code. Therefore, 34 | this library is inferior in performane to the other modules. 35 | The `xor` function in this module is based partly on Roberto Ierusalimschy's 36 | post in http://lua-users.org/lists/lua-l/2002-09/msg00134.html . 37 | 38 | The included BIT.bit32 and BIT.bit sublibraries aims to provide 100% 39 | compatibility with the Lua 5.2 "bit32" and (LuaJIT) LuaBitOp "bit" library. 40 | This compatbility is at the cost of some efficiency since inputted 41 | numbers are normalized and more general forms (e.g. multi-argument 42 | bitwise operators) are supported. 43 | 44 | STATUS 45 | WARNING: Not all corner cases have been tested and documented. 46 | Some attempt was made to make these similar to the Lua 5.2 [2] 47 | and LuaJit BitOp [3] libraries, but this is not fully tested and there 48 | are currently some differences. Addressing these differences may 49 | be improved in the future but it is not yet fully determined how to 50 | resolve these differences. 51 | 52 | The BIT.bit32 library passes the Lua 5.2 test suite (bitwise.lua) 53 | http://www.lua.org/tests/5.2/ . The BIT.bit library passes the LuaBitOp 54 | test suite (bittest.lua). However, these have not been tested on 55 | platforms with Lua compiled with 32-bit integer numbers. 56 | API 57 | BIT.tobit(x) --> z 58 | 59 | Similar to function in BitOp. 60 | 61 | BIT.tohex(x, n) 62 | 63 | Similar to function in BitOp. 64 | 65 | BIT.band(x, y) --> z 66 | 67 | Similar to function in Lua 5.2 and BitOp but requires two arguments. 68 | 69 | BIT.bor(x, y) --> z 70 | 71 | Similar to function in Lua 5.2 and BitOp but requires two arguments. 72 | BIT.bxor(x, y) --> z 73 | 74 | Similar to function in Lua 5.2 and BitOp but requires two arguments. 75 | 76 | BIT.bnot(x) --> z 77 | 78 | Similar to function in Lua 5.2 and BitOp. 79 | BIT.lshift(x, disp) --> z 80 | 81 | Similar to function in Lua 5.2 (warning: BitOp uses unsigned lower 5 bits of shift), 82 | 83 | BIT.rshift(x, disp) --> z 84 | 85 | Similar to function in Lua 5.2 (warning: BitOp uses unsigned lower 5 bits of shift), 86 | BIT.extract(x, field [, width]) --> z 87 | 88 | Similar to function in Lua 5.2. 89 | 90 | BIT.replace(x, v, field, width) --> z 91 | 92 | Similar to function in Lua 5.2. 93 | 94 | BIT.bswap(x) --> z 95 | 96 | Similar to function in Lua 5.2. 97 | BIT.rrotate(x, disp) --> z 98 | BIT.ror(x, disp) --> z 99 | 100 | Similar to function in Lua 5.2 and BitOp. 101 | BIT.lrotate(x, disp) --> z 102 | BIT.rol(x, disp) --> z 103 | Similar to function in Lua 5.2 and BitOp. 104 | 105 | BIT.arshift 106 | 107 | Similar to function in Lua 5.2 and BitOp. 108 | 109 | BIT.btest 110 | 111 | Similar to function in Lua 5.2 with requires two arguments. 112 | BIT.bit32 113 | 114 | This table contains functions that aim to provide 100% compatibility 115 | with the Lua 5.2 "bit32" library. 116 | 117 | bit32.arshift (x, disp) --> z 118 | bit32.band (...) --> z 119 | bit32.bnot (x) --> z 120 | bit32.bor (...) --> z 121 | bit32.btest (...) --> true | false 122 | bit32.bxor (...) --> z 123 | bit32.extract (x, field [, width]) --> z 124 | bit32.replace (x, v, field [, width]) --> z 125 | bit32.lrotate (x, disp) --> z 126 | bit32.lshift (x, disp) --> z 127 | bit32.rrotate (x, disp) --> z 128 | bit32.rshift (x, disp) --> z 129 | BIT.bit 130 | 131 | This table contains functions that aim to provide 100% compatibility 132 | with the LuaBitOp "bit" library (from LuaJIT). 133 | 134 | bit.tobit(x) --> y 135 | bit.tohex(x [,n]) --> y 136 | bit.bnot(x) --> y 137 | bit.bor(x1 [,x2...]) --> y 138 | bit.band(x1 [,x2...]) --> y 139 | bit.bxor(x1 [,x2...]) --> y 140 | bit.lshift(x, n) --> y 141 | bit.rshift(x, n) --> y 142 | bit.arshift(x, n) --> y 143 | bit.rol(x, n) --> y 144 | bit.ror(x, n) --> y 145 | bit.bswap(x) --> y 146 | 147 | DEPENDENCIES 148 | None (other than Lua 5.1 or 5.2). 149 | 150 | DOWNLOAD/INSTALLATION 151 | If using LuaRocks: 152 | luarocks install lua-bit-numberlua 153 | Otherwise, download . 154 | Alternately, if using git: 155 | git clone git://github.com/davidm/lua-bit-numberlua.git 156 | cd lua-bit-numberlua 157 | Optionally unpack: 158 | ./util.mk 159 | or unpack and install in LuaRocks: 160 | ./util.mk install 161 | REFERENCES 162 | [1] http://lua-users.org/wiki/FloatingPoint 163 | [2] http://www.lua.org/manual/5.2/ 164 | [3] http://bitop.luajit.org/ 165 | 166 | LICENSE 167 | (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT). 168 | Permission is hereby granted, free of charge, to any person obtaining a copy 169 | of this software and associated documentation files (the "Software"), to deal 170 | in the Software without restriction, including without limitation the rights 171 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 172 | copies of the Software, and to permit persons to whom the Software is 173 | furnished to do so, subject to the following conditions: 174 | The above copyright notice and this permission notice shall be included in 175 | all copies or substantial portions of the Software. 176 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 177 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 179 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 180 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 181 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 182 | THE SOFTWARE. 183 | (end license) 184 | --]] 185 | 186 | local M = {_TYPE='module', _NAME='bit.numberlua', _VERSION='0.3.1.20120131'} 187 | 188 | local floor = math.floor 189 | 190 | local MOD = 2^32 191 | local MODM = MOD-1 192 | 193 | local function memoize(f) 194 | local mt = {} 195 | local t = setmetatable({}, mt) 196 | function mt:__index(k) 197 | local v = f(k); t[k] = v 198 | return v 199 | end 200 | return t 201 | end 202 | 203 | local function make_bitop_uncached(t, m) 204 | local function bitop(a, b) 205 | local res,p = 0,1 206 | while a ~= 0 and b ~= 0 do 207 | local am, bm = a%m, b%m 208 | res = res + t[am][bm]*p 209 | a = (a - am) / m 210 | b = (b - bm) / m 211 | p = p*m 212 | end 213 | res = res + (a+b)*p 214 | return res 215 | end 216 | return bitop 217 | end 218 | 219 | local function make_bitop(t) 220 | local op1 = make_bitop_uncached(t,2^1) 221 | local op2 = memoize(function(a) 222 | return memoize(function(b) 223 | return op1(a, b) 224 | end) 225 | end) 226 | return make_bitop_uncached(op2, 2^(t.n or 1)) 227 | end 228 | 229 | -- ok? probably not if running on a 32-bit int Lua number type platform 230 | function M.tobit(x) 231 | return x % 2^32 232 | end 233 | 234 | M.bxor = make_bitop {[0]={[0]=0,[1]=1},[1]={[0]=1,[1]=0}, n=4} 235 | local bxor = M.bxor 236 | 237 | function M.bnot(a) return MODM - a end 238 | local bnot = M.bnot 239 | 240 | function M.band(a,b) return ((a+b) - bxor(a,b))/2 end 241 | local band = M.band 242 | 243 | function M.bor(a,b) return MODM - band(MODM - a, MODM - b) end 244 | local bor = M.bor 245 | 246 | local lshift, rshift -- forward declare 247 | 248 | function M.rshift(a,disp) -- Lua5.2 insipred 249 | if disp < 0 then return lshift(a,-disp) end 250 | return floor(a % 2^32 / 2^disp) 251 | end 252 | rshift = M.rshift 253 | 254 | function M.lshift(a,disp) -- Lua5.2 inspired 255 | if disp < 0 then return rshift(a,-disp) end 256 | return (a * 2^disp) % 2^32 257 | end 258 | lshift = M.lshift 259 | 260 | function M.tohex(x, n) -- BitOp style 261 | n = n or 8 262 | local up 263 | if n <= 0 then 264 | if n == 0 then return '' end 265 | up = true 266 | n = - n 267 | end 268 | x = band(x, 16^n-1) 269 | return ('%0'..n..(up and 'X' or 'x')):format(x) 270 | end 271 | local tohex = M.tohex 272 | 273 | function M.extract(n, field, width) -- Lua5.2 inspired 274 | width = width or 1 275 | return band(rshift(n, field), 2^width-1) 276 | end 277 | local extract = M.extract 278 | 279 | function M.replace(n, v, field, width) -- Lua5.2 inspired 280 | width = width or 1 281 | local mask1 = 2^width-1 282 | v = band(v, mask1) -- required by spec? 283 | local mask = bnot(lshift(mask1, field)) 284 | return band(n, mask) + lshift(v, field) 285 | end 286 | local replace = M.replace 287 | 288 | function M.bswap(x) -- BitOp style 289 | local a = band(x, 0xff); x = rshift(x, 8) 290 | local b = band(x, 0xff); x = rshift(x, 8) 291 | local c = band(x, 0xff); x = rshift(x, 8) 292 | local d = band(x, 0xff) 293 | return lshift(lshift(lshift(a, 8) + b, 8) + c, 8) + d 294 | end 295 | local bswap = M.bswap 296 | 297 | function M.rrotate(x, disp) -- Lua5.2 inspired 298 | disp = disp % 32 299 | local low = band(x, 2^disp-1) 300 | return rshift(x, disp) + lshift(low, 32-disp) 301 | end 302 | local rrotate = M.rrotate 303 | 304 | function M.lrotate(x, disp) -- Lua5.2 inspired 305 | return rrotate(x, -disp) 306 | end 307 | local lrotate = M.lrotate 308 | 309 | M.rol = M.lrotate -- LuaOp inspired 310 | M.ror = M.rrotate -- LuaOp insipred 311 | 312 | 313 | function M.arshift(x, disp) -- Lua5.2 inspired 314 | local z = rshift(x, disp) 315 | if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end 316 | return z 317 | end 318 | local arshift = M.arshift 319 | 320 | function M.btest(x, y) -- Lua5.2 inspired 321 | return band(x, y) ~= 0 322 | end 323 | 324 | -- 325 | -- Start Lua 5.2 "bit32" compat section. 326 | -- 327 | 328 | M.bit32 = {} -- Lua 5.2 'bit32' compatibility 329 | 330 | 331 | local function bit32_bnot(x) 332 | return (-1 - x) % MOD 333 | end 334 | M.bit32.bnot = bit32_bnot 335 | 336 | local function bit32_bxor(a, b, c, ...) 337 | local z 338 | if b then 339 | a = a % MOD 340 | b = b % MOD 341 | z = bxor(a, b) 342 | if c then 343 | z = bit32_bxor(z, c, ...) 344 | end 345 | return z 346 | elseif a then 347 | return a % MOD 348 | else 349 | return 0 350 | end 351 | end 352 | M.bit32.bxor = bit32_bxor 353 | 354 | local function bit32_band(a, b, c, ...) 355 | local z 356 | if b then 357 | a = a % MOD 358 | b = b % MOD 359 | z = ((a+b) - bxor(a,b)) / 2 360 | if c then 361 | z = bit32_band(z, c, ...) 362 | end 363 | return z 364 | elseif a then 365 | return a % MOD 366 | else 367 | return MODM 368 | end 369 | end 370 | M.bit32.band = bit32_band 371 | 372 | local function bit32_bor(a, b, c, ...) 373 | local z 374 | if b then 375 | a = a % MOD 376 | b = b % MOD 377 | z = MODM - band(MODM - a, MODM - b) 378 | if c then 379 | z = bit32_bor(z, c, ...) 380 | end 381 | return z 382 | elseif a then 383 | return a % MOD 384 | else 385 | return 0 386 | end 387 | end 388 | M.bit32.bor = bit32_bor 389 | 390 | function M.bit32.btest(...) 391 | return bit32_band(...) ~= 0 392 | end 393 | 394 | function M.bit32.lrotate(x, disp) 395 | return lrotate(x % MOD, disp) 396 | end 397 | 398 | function M.bit32.rrotate(x, disp) 399 | return rrotate(x % MOD, disp) 400 | end 401 | 402 | function M.bit32.lshift(x,disp) 403 | if disp > 31 or disp < -31 then return 0 end 404 | return lshift(x % MOD, disp) 405 | end 406 | 407 | function M.bit32.rshift(x,disp) 408 | if disp > 31 or disp < -31 then return 0 end 409 | return rshift(x % MOD, disp) 410 | end 411 | 412 | function M.bit32.arshift(x,disp) 413 | x = x % MOD 414 | if disp >= 0 then 415 | if disp > 31 then 416 | return (x >= 0x80000000) and MODM or 0 417 | else 418 | local z = rshift(x, disp) 419 | if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end 420 | return z 421 | end 422 | else 423 | return lshift(x, -disp) 424 | end 425 | end 426 | 427 | function M.bit32.extract(x, field, ...) 428 | local width = ... or 1 429 | if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end 430 | x = x % MOD 431 | return extract(x, field, ...) 432 | end 433 | 434 | function M.bit32.replace(x, v, field, ...) 435 | local width = ... or 1 436 | if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end 437 | x = x % MOD 438 | v = v % MOD 439 | return replace(x, v, field, ...) 440 | end 441 | 442 | 443 | -- 444 | -- Start LuaBitOp "bit" compat section. 445 | -- 446 | 447 | M.bit = {} -- LuaBitOp "bit" compatibility 448 | 449 | function M.bit.tobit(x) 450 | x = x % MOD 451 | if x >= 0x80000000 then x = x - MOD end 452 | return x 453 | end 454 | local bit_tobit = M.bit.tobit 455 | 456 | function M.bit.tohex(x, ...) 457 | return tohex(x % MOD, ...) 458 | end 459 | 460 | function M.bit.bnot(x) 461 | return bit_tobit(bnot(x % MOD)) 462 | end 463 | 464 | local function bit_bor(a, b, c, ...) 465 | if c then 466 | return bit_bor(bit_bor(a, b), c, ...) 467 | elseif b then 468 | return bit_tobit(bor(a % MOD, b % MOD)) 469 | else 470 | return bit_tobit(a) 471 | end 472 | end 473 | M.bit.bor = bit_bor 474 | 475 | local function bit_band(a, b, c, ...) 476 | if c then 477 | return bit_band(bit_band(a, b), c, ...) 478 | elseif b then 479 | return bit_tobit(band(a % MOD, b % MOD)) 480 | else 481 | return bit_tobit(a) 482 | end 483 | end 484 | M.bit.band = bit_band 485 | 486 | local function bit_bxor(a, b, c, ...) 487 | if c then 488 | return bit_bxor(bit_bxor(a, b), c, ...) 489 | elseif b then 490 | return bit_tobit(bxor(a % MOD, b % MOD)) 491 | else 492 | return bit_tobit(a) 493 | end 494 | end 495 | M.bit.bxor = bit_bxor 496 | 497 | function M.bit.lshift(x, n) 498 | return bit_tobit(lshift(x % MOD, n % 32)) 499 | end 500 | 501 | function M.bit.rshift(x, n) 502 | return bit_tobit(rshift(x % MOD, n % 32)) 503 | end 504 | 505 | function M.bit.arshift(x, n) 506 | return bit_tobit(arshift(x % MOD, n % 32)) 507 | end 508 | 509 | function M.bit.rol(x, n) 510 | return bit_tobit(lrotate(x % MOD, n % 32)) 511 | end 512 | 513 | function M.bit.ror(x, n) 514 | return bit_tobit(rrotate(x % MOD, n % 32)) 515 | end 516 | 517 | function M.bit.bswap(x) 518 | return bit_tobit(bswap(x % MOD)) 519 | end 520 | 521 | return M -------------------------------------------------------------------------------- /lua/prometheus/enums.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- enums.lua 4 | -- This file Provides some enums used by the Obfuscator 5 | 6 | local Enums = {}; 7 | 8 | local chararray = require("prometheus.util").chararray; 9 | 10 | Enums.LuaVersion = { 11 | LuaU = "LuaU" , 12 | Lua51 = "Lua51", 13 | } 14 | 15 | Enums.Conventions = { 16 | [Enums.LuaVersion.Lua51] = { 17 | Keywords = { 18 | "and", "break", "do", "else", "elseif", 19 | "end", "false", "for", "function", "if", 20 | "in", "local", "nil", "not", "or", 21 | "repeat", "return", "then", "true", "until", "while" 22 | }, 23 | 24 | SymbolChars = chararray("+-*/%^#=~<>(){}[];:,."), 25 | MaxSymbolLength = 3, 26 | Symbols = { 27 | "+", "-", "*", "/", "%", "^", "#", 28 | "==", "~=", "<=", ">=", "<", ">", "=", 29 | "(", ")", "{", "}", "[", "]", 30 | ";", ":", ",", ".", "..", "...", 31 | }, 32 | 33 | IdentChars = chararray("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"), 34 | NumberChars = chararray("0123456789"), 35 | HexNumberChars = chararray("0123456789abcdefABCDEF"), 36 | BinaryNumberChars = {"0", "1"}, 37 | DecimalExponent = {"e", "E"}, 38 | HexadecimalNums = {"x", "X"}, 39 | BinaryNums = false, 40 | DecimalSeperators = false, 41 | 42 | EscapeSequences = { 43 | ["a"] = "\a"; 44 | ["b"] = "\b"; 45 | ["f"] = "\f"; 46 | ["n"] = "\n"; 47 | ["r"] = "\r"; 48 | ["t"] = "\t"; 49 | ["v"] = "\v"; 50 | ["\\"] = "\\"; 51 | ["\""] = "\""; 52 | ["\'"] = "\'"; 53 | }, 54 | NumericalEscapes = true, 55 | EscapeZIgnoreNextWhitespace = false, 56 | HexEscapes = false, 57 | UnicodeEscapes = false, 58 | }, 59 | [Enums.LuaVersion.LuaU] = { 60 | Keywords = { 61 | "and", "break", "do", "else", "elseif", "continue", 62 | "end", "false", "for", "function", "if", 63 | "in", "local", "nil", "not", "or", 64 | "repeat", "return", "then", "true", "until", "while" 65 | }, 66 | 67 | SymbolChars = chararray("+-*/%^#=~<>(){}[];:,."), 68 | MaxSymbolLength = 3, 69 | Symbols = { 70 | "+", "-", "*", "/", "%", "^", "#", 71 | "==", "~=", "<=", ">=", "<", ">", "=", 72 | "+=", "-=", "/=", "%=", "^=", "..=", "*=", 73 | "(", ")", "{", "}", "[", "]", 74 | ";", ":", ",", ".", "..", "...", 75 | "::", "->", "?", "|", "&", 76 | }, 77 | 78 | IdentChars = chararray("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"), 79 | NumberChars = chararray("0123456789"), 80 | HexNumberChars = chararray("0123456789abcdefABCDEF"), 81 | BinaryNumberChars = {"0", "1"}, 82 | DecimalExponent = {"e", "E"}, 83 | HexadecimalNums = {"x", "X"}, 84 | BinaryNums = {"b", "B"}, 85 | DecimalSeperators = {"_"}, 86 | 87 | EscapeSequences = { 88 | ["a"] = "\a"; 89 | ["b"] = "\b"; 90 | ["f"] = "\f"; 91 | ["n"] = "\n"; 92 | ["r"] = "\r"; 93 | ["t"] = "\t"; 94 | ["v"] = "\v"; 95 | ["\\"] = "\\"; 96 | ["\""] = "\""; 97 | ["\'"] = "\'"; 98 | }, 99 | NumericalEscapes = true, 100 | EscapeZIgnoreNextWhitespace = true, 101 | HexEscapes = true, 102 | UnicodeEscapes = true, 103 | }, 104 | } 105 | 106 | return Enums; -------------------------------------------------------------------------------- /lua/prometheus/namegenerators.lua: -------------------------------------------------------------------------------- 1 | return { 2 | Mangled = require("prometheus.namegenerators.mangled"); 3 | MangledShuffled = require("prometheus.namegenerators.mangled_shuffled"); 4 | Il = require("prometheus.namegenerators.Il"); 5 | Number = require("prometheus.namegenerators.number"); 6 | Confuse = require("prometheus.namegenerators.confuse"); 7 | } -------------------------------------------------------------------------------- /lua/prometheus/namegenerators/Il.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- namegenerators/mangled.lua 4 | -- 5 | -- This Script provides a function for generation of weird names consisting of I, l and 1 6 | 7 | local MIN_CHARACTERS = 5; 8 | local MAX_INITIAL_CHARACTERS = 10; 9 | 10 | 11 | local util = require("prometheus.util"); 12 | local chararray = util.chararray; 13 | 14 | local offset = 0; 15 | local VarDigits = chararray("Il1"); 16 | local VarStartDigits = chararray("Il"); 17 | 18 | local function generateName(id, scope) 19 | local name = '' 20 | id = id + offset; 21 | local d = id % #VarStartDigits 22 | id = (id - d) / #VarStartDigits 23 | name = name..VarStartDigits[d+1] 24 | while id > 0 do 25 | local d = id % #VarDigits 26 | id = (id - d) / #VarDigits 27 | name = name..VarDigits[d+1] 28 | end 29 | return name 30 | end 31 | 32 | local function prepare(ast) 33 | util.shuffle(VarDigits); 34 | util.shuffle(VarStartDigits); 35 | offset = math.random(3 ^ MIN_CHARACTERS, 3 ^ MAX_INITIAL_CHARACTERS); 36 | end 37 | 38 | return { 39 | generateName = generateName, 40 | prepare = prepare 41 | }; -------------------------------------------------------------------------------- /lua/prometheus/namegenerators/confuse.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- namegenerators/mangled.lua 4 | -- 5 | -- This Script provides a function for generation of confusing variable names 6 | 7 | local util = require("prometheus.util"); 8 | local chararray = util.chararray; 9 | 10 | local varNames = { 11 | "index", 12 | "iterator", 13 | "length", 14 | "size", 15 | "key", 16 | "value", 17 | "data", 18 | "count", 19 | "increment", 20 | "include", 21 | "string", 22 | "number", 23 | "type", 24 | "void", 25 | "int", 26 | "float", 27 | "bool", 28 | "char", 29 | "double", 30 | "long", 31 | "short", 32 | "unsigned", 33 | "signed", 34 | "program", 35 | "factory", 36 | "Factory", 37 | "new", 38 | "delete", 39 | "table", 40 | "array", 41 | "object", 42 | "class", 43 | "arr", 44 | "obj", 45 | "cls", 46 | "dir", 47 | "directory", 48 | "isWindows", 49 | "isLinux", 50 | "game", 51 | "roblox", 52 | "gmod", 53 | "gsub", 54 | "gmatch", 55 | "gfind", 56 | "onload", 57 | "load", 58 | "loadstring", 59 | "loadfile", 60 | "dofile", 61 | "require", 62 | "parse", 63 | "byte", 64 | "code", 65 | "bytecode", 66 | "idx", 67 | "const", 68 | "loader", 69 | "loaders", 70 | "module", 71 | "export", 72 | "exports", 73 | "import", 74 | "imports", 75 | "package", 76 | "packages", 77 | "_G", 78 | "math", 79 | "os", 80 | "io", 81 | "write", 82 | "print", 83 | "read", 84 | "readline", 85 | "readlines", 86 | "close", 87 | "flush", 88 | "open", 89 | "popen", 90 | "tmpfile", 91 | "tmpname", 92 | "rename", 93 | "remove", 94 | "seek", 95 | "setvbuf", 96 | "lines", 97 | "call", 98 | "apply", 99 | "raise", 100 | "pcall", 101 | "xpcall", 102 | "coroutine", 103 | "create", 104 | "resume", 105 | "status", 106 | "wrap", 107 | "yield", 108 | "debug", 109 | "traceback", 110 | "getinfo", 111 | "getlocal", 112 | "setlocal", 113 | "getupvalue", 114 | "setupvalue", 115 | "getuservalue", 116 | "setuservalue", 117 | "upvalueid", 118 | "upvaluejoin", 119 | "sethook", 120 | "gethook", 121 | "hookfunction", 122 | "hooks", 123 | "error", 124 | "setmetatable", 125 | "getmetatable", 126 | "rand", 127 | "randomseed", 128 | "next", 129 | "ipairs", 130 | "hasnext", 131 | "loadlib", 132 | "searchpath", 133 | "oldpath", 134 | "newpath", 135 | "path", 136 | "rawequal", 137 | "rawset", 138 | "rawget", 139 | "rawnew", 140 | "rawlen", 141 | "select", 142 | "tonumber", 143 | "tostring", 144 | "assert", 145 | "collectgarbage", 146 | "a", "b", "c", "i", "j", "m", 147 | } 148 | 149 | local function generateName(id, scope) 150 | local name = {}; 151 | local d = id % #varNames 152 | id = (id - d) / #varNames 153 | table.insert(name, varNames[d + 1]); 154 | while id > 0 do 155 | local d = id % #varNames 156 | id = (id - d) / #varNames 157 | table.insert(name, varNames[d + 1]); 158 | end 159 | return table.concat(name, "_"); 160 | end 161 | 162 | local function prepare(ast) 163 | util.shuffle(varNames); 164 | end 165 | 166 | return { 167 | generateName = generateName, 168 | prepare = prepare 169 | }; -------------------------------------------------------------------------------- /lua/prometheus/namegenerators/mangled.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- namegenerators/mangled.lua 4 | -- 5 | -- This Script provides a function for generation of mangled names 6 | 7 | 8 | local util = require("prometheus.util"); 9 | local chararray = util.chararray; 10 | 11 | local idGen = 0 12 | local VarDigits = chararray("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"); 13 | local VarStartDigits = chararray("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); 14 | 15 | return function(id, scope) 16 | local name = '' 17 | local d = id % #VarStartDigits 18 | id = (id - d) / #VarStartDigits 19 | name = name..VarStartDigits[d+1] 20 | while id > 0 do 21 | local d = id % #VarDigits 22 | id = (id - d) / #VarDigits 23 | name = name..VarDigits[d+1] 24 | end 25 | return name 26 | end -------------------------------------------------------------------------------- /lua/prometheus/namegenerators/mangled_shuffled.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- namegenerators/mangled_shuffled.lua 4 | -- 5 | -- This Script provides a function for generation of mangled names with shuffled character order 6 | 7 | 8 | local util = require("prometheus.util"); 9 | local chararray = util.chararray; 10 | 11 | local VarDigits = chararray("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"); 12 | local VarStartDigits = chararray("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); 13 | 14 | local function generateName(id, scope) 15 | local name = '' 16 | local d = id % #VarStartDigits 17 | id = (id - d) / #VarStartDigits 18 | name = name..VarStartDigits[d+1] 19 | while id > 0 do 20 | local d = id % #VarDigits 21 | id = (id - d) / #VarDigits 22 | name = name..VarDigits[d+1] 23 | end 24 | return name 25 | end 26 | 27 | local function prepare(ast) 28 | util.shuffle(VarDigits); 29 | util.shuffle(VarStartDigits); 30 | end 31 | 32 | return { 33 | generateName = generateName, 34 | prepare = prepare 35 | }; -------------------------------------------------------------------------------- /lua/prometheus/namegenerators/number.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- namegenerators/mangled.lua 4 | -- 5 | -- This Script provides a function for generation of simple up counting names but with hex numbers 6 | 7 | local PREFIX = "_"; 8 | 9 | return function(id, scope) 10 | return PREFIX .. tostring(id); 11 | end -------------------------------------------------------------------------------- /lua/prometheus/pipeline.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- pipeline.lua 4 | -- 5 | -- This Script Provides a Configurable Obfuscation Pipeline that can obfuscate code using different Modules 6 | -- These Modules can simply be added to the pipeline 7 | 8 | local config = require("config"); 9 | local Ast = require("prometheus.ast"); 10 | local Enums = require("prometheus.enums"); 11 | local util = require("prometheus.util"); 12 | local Parser = require("prometheus.parser"); 13 | local Unparser = require("prometheus.unparser"); 14 | local logger = require("logger"); 15 | 16 | local NameGenerators = require("prometheus.namegenerators"); 17 | 18 | local Steps = require("prometheus.steps"); 19 | 20 | local lookupify = util.lookupify; 21 | local LuaVersion = Enums.LuaVersion; 22 | local AstKind = Ast.AstKind; 23 | 24 | -- On Windows os.clock can be used. On other Systems os.time must be used for benchmarking 25 | local isWindows = package and package.config and type(package.config) == "string" and package.config:sub(1,1) == "\\"; 26 | local function gettime() 27 | if isWindows then 28 | return os.clock(); 29 | else 30 | return os.time(); 31 | end 32 | end 33 | 34 | local Pipeline = { 35 | NameGenerators = NameGenerators; 36 | Steps = Steps; 37 | DefaultSettings = { 38 | LuaVersion = LuaVersion.LuaU; -- The Lua Version to use for the Tokenizer, Parser and Unparser 39 | PrettyPrint = false; -- Note that Pretty Print is currently not producing Pretty results 40 | Seed = 0; -- The Seed. 0 or below uses the current time as a seed 41 | VarNamePrefix = ""; -- The Prefix that every variable will start with 42 | } 43 | } 44 | 45 | 46 | function Pipeline:new(settings) 47 | local luaVersion = settings.luaVersion or settings.LuaVersion or Pipeline.DefaultSettings.LuaVersion; 48 | local conventions = Enums.Conventions[luaVersion]; 49 | if(not conventions) then 50 | logger:error("The Lua Version \"" .. luaVersion 51 | .. "\" is not recognised by the Tokenizer! Please use one of the following: \"" .. table.concat(util.keys(Enums.Conventions), "\",\"") .. "\""); 52 | end 53 | 54 | local prettyPrint = settings.PrettyPrint or Pipeline.DefaultSettings.PrettyPrint; 55 | local prefix = settings.VarNamePrefix or Pipeline.DefaultSettings.VarNamePrefix; 56 | local seed = settings.Seed or 0; 57 | 58 | local pipeline = { 59 | LuaVersion = luaVersion; 60 | PrettyPrint = prettyPrint; 61 | VarNamePrefix = prefix; 62 | Seed = seed; 63 | parser = Parser:new({ 64 | LuaVersion = luaVersion; 65 | }); 66 | unparser = Unparser:new({ 67 | LuaVersion = luaVersion; 68 | PrettyPrint = prettyPrint; 69 | Highlight = settings.Highlight; 70 | }); 71 | namegenerator = Pipeline.NameGenerators.MangledShuffled; 72 | conventions = conventions; 73 | steps = {}; 74 | } 75 | 76 | setmetatable(pipeline, self); 77 | self.__index = self; 78 | 79 | return pipeline; 80 | end 81 | 82 | function Pipeline:fromConfig(config) 83 | config = config or {}; 84 | local pipeline = Pipeline:new({ 85 | LuaVersion = config.LuaVersion or LuaVersion.Lua51; 86 | PrettyPrint = config.PrettyPrint or false; 87 | VarNamePrefix = config.VarNamePrefix or ""; 88 | Seed = config.Seed or 0; 89 | }); 90 | 91 | pipeline:setNameGenerator(config.NameGenerator or "MangledShuffled") 92 | 93 | -- Add all Steps defined in Config 94 | local steps = config.Steps or {}; 95 | for i, step in ipairs(steps) do 96 | if type(step.Name) ~= "string" then 97 | logger:error("Step.Name must be a String"); 98 | end 99 | local constructor = pipeline.Steps[step.Name]; 100 | if not constructor then 101 | logger:error(string.format("The Step \"%s\" was not found!", step.Name)); 102 | end 103 | pipeline:addStep(constructor:new(step.Settings or {})); 104 | end 105 | 106 | return pipeline; 107 | end 108 | 109 | function Pipeline:addStep(step) 110 | table.insert(self.steps, step); 111 | end 112 | 113 | function Pipeline:resetSteps(step) 114 | self.steps = {}; 115 | end 116 | 117 | function Pipeline:getSteps() 118 | return self.steps; 119 | end 120 | 121 | function Pipeline:setOption(name, value) 122 | assert(false, "TODO"); 123 | if(Pipeline.DefaultSettings[name] ~= nil) then 124 | 125 | else 126 | logger:error(string.format("\"%s\" is not a valid setting")); 127 | end 128 | end 129 | 130 | function Pipeline:setLuaVersion(luaVersion) 131 | local conventions = Enums.Conventions[luaVersion]; 132 | if(not conventions) then 133 | logger:error("The Lua Version \"" .. luaVersion 134 | .. "\" is not recognised by the Tokenizer! Please use one of the following: \"" .. table.concat(util.keys(Enums.Conventions), "\",\"") .. "\""); 135 | end 136 | 137 | self.parser = Parser:new({ 138 | luaVersion = luaVersion; 139 | }); 140 | self.unparser = Unparser:new({ 141 | luaVersion = luaVersion; 142 | }); 143 | self.conventions = conventions; 144 | end 145 | 146 | function Pipeline:getLuaVersion() 147 | return self.luaVersion; 148 | end 149 | 150 | function Pipeline:setNameGenerator(nameGenerator) 151 | if(type(nameGenerator) == "string") then 152 | nameGenerator = Pipeline.NameGenerators[nameGenerator]; 153 | end 154 | 155 | if(type(nameGenerator) == "function" or type(nameGenerator) == "table") then 156 | self.namegenerator = nameGenerator; 157 | return; 158 | else 159 | logger:error("The Argument to Pipeline:setNameGenerator must be a valid NameGenerator function or function name e.g: \"mangled\"") 160 | end 161 | end 162 | 163 | function Pipeline:apply(code, filename) 164 | local startTime = gettime(); 165 | filename = filename or "Anonymus Script"; 166 | logger:info(string.format("Applying Obfuscation Pipeline to %s ...", filename)); 167 | -- Seed the Random Generator 168 | if(self.Seed > 0) then 169 | math.randomseed(self.Seed); 170 | else 171 | math.randomseed(os.time()) 172 | end 173 | 174 | logger:info("Parsing ..."); 175 | local parserStartTime = gettime(); 176 | 177 | local sourceLen = string.len(code); 178 | local ast = self.parser:parse(code); 179 | 180 | local parserTimeDiff = gettime() - parserStartTime; 181 | logger:info(string.format("Parsing Done in %.2f seconds", parserTimeDiff)); 182 | 183 | -- User Defined Steps 184 | for i, step in ipairs(self.steps) do 185 | local stepStartTime = gettime(); 186 | logger:info(string.format("Applying Step \"%s\" ...", step.Name or "Unnamed")); 187 | local newAst = step:apply(ast, self); 188 | if type(newAst) == "table" then 189 | ast = newAst; 190 | end 191 | logger:info(string.format("Step \"%s\" Done in %.2f seconds", step.Name or "Unnamed", gettime() - stepStartTime)); 192 | end 193 | 194 | -- Rename Variables Step 195 | self:renameVariables(ast); 196 | 197 | code = self:unparse(ast); 198 | 199 | local timeDiff = gettime() - startTime; 200 | logger:info(string.format("Obfuscation Done in %.2f seconds", timeDiff)); 201 | 202 | logger:info(string.format("Generated Code size is %.2f%% of the Source Code size", (string.len(code) / sourceLen)*100)) 203 | 204 | return code; 205 | end 206 | 207 | function Pipeline:unparse(ast) 208 | local startTime = gettime(); 209 | logger:info("Generating Code ..."); 210 | 211 | local unparsed = self.unparser:unparse(ast); 212 | 213 | local timeDiff = gettime() - startTime; 214 | logger:info(string.format("Code Generation Done in %.2f seconds", timeDiff)); 215 | 216 | return unparsed; 217 | end 218 | 219 | function Pipeline:renameVariables(ast) 220 | local startTime = gettime(); 221 | logger:info("Renaming Variables ..."); 222 | 223 | 224 | local generatorFunction = self.namegenerator or Pipeline.NameGenerators.mangled; 225 | if(type(generatorFunction) == "table") then 226 | if (type(generatorFunction.prepare) == "function") then 227 | generatorFunction.prepare(ast); 228 | end 229 | generatorFunction = generatorFunction.generateName; 230 | end 231 | 232 | if not self.unparser:isValidIdentifier(self.VarNamePrefix) and #self.VarNamePrefix ~= 0 then 233 | logger:error(string.format("The Prefix \"%s\" is not a valid Identifier in %s", self.VarNamePrefix, self.LuaVersion)); 234 | end 235 | 236 | local globalScope = ast.globalScope; 237 | globalScope:renameVariables({ 238 | Keywords = self.conventions.Keywords; 239 | generateName = generatorFunction; 240 | prefix = self.VarNamePrefix; 241 | }); 242 | 243 | local timeDiff = gettime() - startTime; 244 | logger:info(string.format("Renaming Done in %.2f seconds", timeDiff)); 245 | end 246 | 247 | 248 | 249 | 250 | return Pipeline; 251 | -------------------------------------------------------------------------------- /lua/prometheus/randomLiterals.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- Library for Creating Random Literals 4 | 5 | local Ast = require("prometheus.ast"); 6 | local RandomStrings = require("prometheus.randomStrings"); 7 | 8 | local RandomLiterals = {}; 9 | 10 | local function callNameGenerator(generatorFunction, ...) 11 | if(type(generatorFunction) == "table") then 12 | generatorFunction = generatorFunction.generateName; 13 | end 14 | return generatorFunction(...); 15 | end 16 | 17 | function RandomLiterals.String(pipeline) 18 | return Ast.StringExpression(callNameGenerator(pipeline.namegenerator, math.random(1, 4096))); 19 | end 20 | 21 | function RandomLiterals.Dictionary() 22 | return RandomStrings.randomStringNode(true); 23 | end 24 | 25 | function RandomLiterals.Number() 26 | return Ast.NumberExpression(math.random(-8388608, 8388607)); 27 | end 28 | 29 | function RandomLiterals.Any(pipeline) 30 | local type = math.random(1, 3); 31 | if type == 1 then 32 | return RandomLiterals.String(pipeline); 33 | elseif type == 2 then 34 | return RandomLiterals.Number(); 35 | elseif type == 3 then 36 | return RandomLiterals.Dictionary(); 37 | end 38 | end 39 | 40 | 41 | return RandomLiterals; -------------------------------------------------------------------------------- /lua/prometheus/randomStrings.lua: -------------------------------------------------------------------------------- 1 | local Ast = require("prometheus.ast"); 2 | 3 | local charset = {} 4 | 5 | -- qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890 6 | for i = 48, 57 do table.insert(charset, string.char(i)) end 7 | for i = 65, 90 do table.insert(charset, string.char(i)) end 8 | for i = 97, 122 do table.insert(charset, string.char(i)) end 9 | 10 | local function randomString(wordsOrLen) 11 | if type(wordsOrLen) == "table" then 12 | return wordsOrLen[math.random(1, #wordsOrLen)]; 13 | end 14 | 15 | wordsOrLen = wordsOrLen or math.random(2, 15); 16 | if wordsOrLen > 0 then 17 | return randomString(wordsOrLen - 1) .. charset[math.random(1, #charset)] 18 | else 19 | return "" 20 | end 21 | end 22 | 23 | local function randomStringNode(wordsOrLen) 24 | return Ast.StringExpression(randomString(wordsOrLen)) 25 | end 26 | 27 | return { 28 | randomString = randomString, 29 | randomStringNode = randomStringNode, 30 | } -------------------------------------------------------------------------------- /lua/prometheus/scope.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- scope.lua 4 | 5 | local logger = require("logger"); 6 | local config = require("config"); 7 | 8 | local Scope = {}; 9 | 10 | local scopeI = 0; 11 | local function nextName() 12 | scopeI = scopeI + 1; 13 | return "local_scope_" .. tostring(scopeI); 14 | end 15 | 16 | local function generateWarning(token, message) 17 | return "Warning at Position " .. tostring(token.line) .. ":" .. tostring(token.linePos) .. ", " .. message; 18 | end 19 | 20 | -- Create a new Local Scope 21 | function Scope:new(parentScope, name) 22 | local scope = { 23 | isGlobal = false, 24 | parentScope = parentScope, 25 | variables = {}, 26 | referenceCounts = {}; 27 | variablesLookup = {}, 28 | variablesFromHigherScopes = {}, 29 | skipIdLookup = {}; 30 | name = name or nextName(), 31 | children = {}, 32 | level = parentScope.level and (parentScope.level + 1) or 1; 33 | } 34 | 35 | setmetatable(scope, self); 36 | self.__index = self; 37 | parentScope:addChild(scope); 38 | return scope; 39 | end 40 | 41 | -- Create a new Global Scope 42 | function Scope:newGlobal() 43 | local scope = { 44 | isGlobal = true, 45 | parentScope = nil, 46 | variables = {}, 47 | variablesLookup = {}; 48 | referenceCounts = {}; 49 | skipIdLookup = {}; 50 | name = "global_scope", 51 | children = {}, 52 | level = 0, 53 | }; 54 | 55 | setmetatable(scope, self); 56 | self.__index = self; 57 | 58 | return scope; 59 | end 60 | 61 | -- Returns the Parent Scope 62 | function Scope:getParent(parentScope) 63 | return self.parentScope; 64 | end 65 | 66 | function Scope:setParent(parentScope) 67 | self.parentScope:removeChild(self); 68 | parentScope:addChild(self); 69 | self.parentScope = parentScope; 70 | self.level = parentScope.level + 1; 71 | end 72 | 73 | local next_name_i = 1; 74 | -- Adds a Variable to the scope and returns the variable id, if no name is passed then a name is generated 75 | function Scope:addVariable(name, token) 76 | if (not name) then 77 | name = string.format("%s%i", config.IdentPrefix, next_name_i); 78 | next_name_i = next_name_i + 1; 79 | end 80 | 81 | if self.variablesLookup[name] ~= nil then 82 | if(token) then 83 | logger:warn(generateWarning(token, "the variable \"" .. name .. "\" is already defined in that scope")); 84 | else 85 | logger:error(string.format("A variable with the name \"%s\" was already defined, you should have no variables starting with \"%s\"", name, config.IdentPrefix)); 86 | end 87 | 88 | --return self.variablesLookup[name]; 89 | end 90 | 91 | table.insert(self.variables, name); 92 | local id = #self.variables; 93 | self.variablesLookup[name] = id; 94 | return id; 95 | end 96 | 97 | function Scope:enableVariable(id) 98 | local name = self.variables[id]; 99 | self.variablesLookup[name] = id; 100 | end 101 | 102 | function Scope:addDisabledVariable(name, token) 103 | if (not name) then 104 | name = string.format("%s%i", config.IdentPrefix, next_name_i); 105 | next_name_i = next_name_i + 1; 106 | end 107 | 108 | if self.variablesLookup[name] ~= nil then 109 | if(token) then 110 | logger:warn(generateWarning(token, "the variable \"" .. name .. "\" is already defined in that scope")); 111 | else 112 | logger:warn(string.format("a variable with the name \"%s\" was already defined", name)); 113 | end 114 | 115 | --return self.variablesLookup[name]; 116 | end 117 | 118 | table.insert(self.variables, name); 119 | local id = #self.variables; 120 | return id; 121 | end 122 | 123 | function Scope:addIfNotExists(id) 124 | if(not self.variables[id]) then 125 | local name = string.format("%s%i", config.IdentPrefix, next_name_i); 126 | next_name_i = next_name_i + 1; 127 | self.variables[id] = name; 128 | self.variablesLookup[name] = id; 129 | end 130 | return id; 131 | end 132 | 133 | -- Returns wether the variable is defined in this Scope 134 | function Scope:hasVariable(name) 135 | if(self.isGlobal) then 136 | if self.variablesLookup[name] == nil then 137 | self:addVariable(name); 138 | end 139 | return true; 140 | end 141 | return self.variablesLookup[name] ~= nil; 142 | end 143 | 144 | -- Get List of all Variables defined in this Scope 145 | function Scope:getVariables() 146 | return self.variables; 147 | end 148 | 149 | function Scope:resetReferences(id) 150 | self.referenceCounts[id] = 0; 151 | end 152 | 153 | function Scope:getReferences(id) 154 | return self.referenceCounts[id] or 0; 155 | end 156 | 157 | function Scope:removeReference(id) 158 | self.referenceCounts[id] = (self.referenceCounts[id] or 0) - 1; 159 | end 160 | 161 | function Scope:addReference(id) 162 | self.referenceCounts[id] = (self.referenceCounts[id] or 0) + 1; 163 | end 164 | 165 | -- Resolve the scope of a variable by name 166 | function Scope:resolve(name) 167 | if(self:hasVariable(name)) then 168 | return self, self.variablesLookup[name]; 169 | end 170 | assert(self.parentScope, "No Global Variable Scope was Created! This should not be Possible!"); 171 | local scope, id = self.parentScope:resolve(name); 172 | self:addReferenceToHigherScope(scope, id, nil, true); 173 | return scope, id; 174 | end 175 | 176 | function Scope:resolveGlobal(name) 177 | if(self.isGlobal and self:hasVariable(name)) then 178 | return self, self.variablesLookup[name]; 179 | end 180 | assert(self.parentScope, "No Global Variable Scope was Created! This should not be Possible!"); 181 | local scope, id = self.parentScope:resolveGlobal(name); 182 | self:addReferenceToHigherScope(scope, id, nil, true); 183 | return scope, id; 184 | end 185 | 186 | -- Returns the name of an Variable by id - this is used for unparsing 187 | function Scope:getVariableName(id) 188 | return self.variables[id]; 189 | end 190 | 191 | -- Remove A Variable from this Scope 192 | function Scope:removeVariable(id) 193 | local name = self.variables[id]; 194 | self.variables[id] = nil; 195 | self.variablesLookup[name] = nil; 196 | self.skipIdLookup[id] = true; 197 | end 198 | 199 | -- Add a Children Scope 200 | function Scope:addChild(scope) 201 | -- This will add all References from that Scope to higher Scopes. Note that the higher scopes may only be global 202 | for scope, ids in pairs(scope.variablesFromHigherScopes) do 203 | for id, count in pairs(ids) do 204 | if count and count > 0 then 205 | self:addReferenceToHigherScope(scope, id, count); 206 | end 207 | end 208 | end 209 | table.insert(self.children, scope); 210 | end 211 | 212 | function Scope:clearReferences() 213 | self.referenceCounts = {}; 214 | self.variablesFromHigherScopes = {}; 215 | end 216 | 217 | function Scope:removeChild(child) 218 | for i, v in ipairs(self.children) do 219 | if(v == child) then 220 | -- This will add all References from that Scope to higher Scopes. Note that the higher scopes may only be global 221 | for scope, ids in pairs(v.variablesFromHigherScopes) do 222 | for id, count in pairs(ids) do 223 | if count and count > 0 then 224 | self:removeReferenceToHigherScope(scope, id, count); 225 | end 226 | end 227 | end 228 | return table.remove(self.children, i); 229 | end 230 | end 231 | end 232 | 233 | function Scope:getMaxId() 234 | return #self.variables; 235 | end 236 | 237 | function Scope:addReferenceToHigherScope(scope, id, n, b) 238 | n = n or 1; 239 | if self.isGlobal then 240 | if not scope.isGlobal then 241 | logger:error(string.format("Could not resolve Scope \"%s\"", scope.name)) 242 | end 243 | return 244 | end 245 | if scope == self then 246 | self.referenceCounts[id] = (self.referenceCounts[id] or 0) + n; 247 | return 248 | end 249 | if not self.variablesFromHigherScopes[scope] then 250 | self.variablesFromHigherScopes[scope] = {}; 251 | end 252 | local scopeReferences = self.variablesFromHigherScopes[scope]; 253 | if scopeReferences[id] then 254 | scopeReferences[id] = scopeReferences[id] + n; 255 | else 256 | scopeReferences[id] = n; 257 | end 258 | if not b then 259 | self.parentScope:addReferenceToHigherScope(scope, id, n); 260 | end 261 | end 262 | 263 | function Scope:removeReferenceToHigherScope(scope, id, n, b) 264 | n = n or 1; 265 | if self.isGlobal then 266 | return 267 | end 268 | if scope == self then 269 | self.referenceCounts[id] = (self.referenceCounts[id] or 0) - n; 270 | return 271 | end 272 | if not self.variablesFromHigherScopes[scope] then 273 | self.variablesFromHigherScopes[scope] = {}; 274 | end 275 | local scopeReferences = self.variablesFromHigherScopes[scope]; 276 | if scopeReferences[id] then 277 | scopeReferences[id] = scopeReferences[id] - n; 278 | else 279 | scopeReferences[id] = 0; 280 | end 281 | if not b then 282 | self.parentScope:removeReferenceToHigherScope(scope, id, n); 283 | end 284 | end 285 | 286 | -- Rename Variables from that scope downwards 287 | -- this function needs a settings object with the following properties 288 | -- Keywords => forbidden Variable Names 289 | -- generateName(id, scope, originalName) => function to generate unique variable name based on the id and scope 290 | function Scope:renameVariables(settings) 291 | if(not self.isGlobal) then 292 | local prefix = settings.prefix or ""; 293 | local forbiddenNamesLookup = {}; 294 | for _, keyword in pairs(settings.Keywords) do 295 | forbiddenNamesLookup[keyword] = true; 296 | end 297 | 298 | for scope, ids in pairs(self.variablesFromHigherScopes) do 299 | for id, count in pairs(ids) do 300 | if count and count > 0 then 301 | local name = scope:getVariableName(id); 302 | forbiddenNamesLookup[name] = true; 303 | end 304 | end 305 | end 306 | 307 | self.variablesLookup = {}; 308 | 309 | local i = 0; 310 | for id, originalName in pairs(self.variables) do 311 | if(not self.skipIdLookup[id] and (self.referenceCounts[id] or 0) >= 0) then 312 | local name; 313 | repeat 314 | name = prefix .. settings.generateName(i, self, originalName); 315 | if name == nil then 316 | name = originalName; 317 | end 318 | i = i + 1; 319 | until not forbiddenNamesLookup[name]; 320 | 321 | self.variables[id] = name; 322 | self.variablesLookup[name] = id; 323 | end 324 | end 325 | end 326 | 327 | for _, scope in pairs(self.children) do 328 | scope:renameVariables(settings); 329 | end 330 | end 331 | 332 | return Scope; -------------------------------------------------------------------------------- /lua/prometheus/step.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- util.lua 4 | -- 5 | -- This file Provides the base class for Obfuscation Steps 6 | 7 | local logger = require("logger"); 8 | local util = require("prometheus.util"); 9 | 10 | local lookupify = util.lookupify; 11 | 12 | local Step = {}; 13 | 14 | Step.SettingsDescriptor = {} 15 | 16 | function Step:new(settings) 17 | local instance = {}; 18 | setmetatable(instance, self); 19 | self.__index = self; 20 | 21 | if type(settings) ~= "table" then 22 | settings = {}; 23 | end 24 | 25 | for key, data in pairs(self.SettingsDescriptor) do 26 | if settings[key] == nil then 27 | if data.default == nil then 28 | logger:error(string.format("The Setting \"%s\" was not provided for the Step \"%s\"", key, self.Name)); 29 | end 30 | instance[key] = data.default; 31 | elseif(data.type == "enum") then 32 | local lookup = lookupify(data.values); 33 | if not lookup[settings[key]] then 34 | logger:error(string.format("Invalid value for the Setting \"%s\" of the Step \"%s\". It must be one of the following: %s", key, self.Name, table.concat(data, ", "))); 35 | end 36 | instance[key] = settings[key]; 37 | elseif(type(settings[key]) ~= data.type) then 38 | logger:error(string.format("Invalid value for the Setting \"%s\" of the Step \"%s\". It must be a %s", key, self.Name, data.type)); 39 | else 40 | if data.min then 41 | if settings[key] < data.min then 42 | logger:error(string.format("Invalid value for the Setting \"%s\" of the Step \"%s\". It must be at least %d", key, self.Name, data.min)); 43 | end 44 | end 45 | 46 | if data.max then 47 | if settings[key] > data.max then 48 | logger:error(string.format("Invalid value for the Setting \"%s\" of the Step \"%s\". The biggest allowed value is %d", key, self.Name, data.min)); 49 | end 50 | end 51 | 52 | instance[key] = settings[key]; 53 | end 54 | end 55 | 56 | instance:init(); 57 | 58 | return instance; 59 | end 60 | 61 | function Step:init() 62 | logger:error("Abstract Steps cannot be Created"); 63 | end 64 | 65 | function Step:extend() 66 | local ext = {}; 67 | setmetatable(ext, self); 68 | self.__index = self; 69 | return ext; 70 | end 71 | 72 | function Step:apply(ast, pipeline) 73 | logger:error("Abstract Steps cannot be Applied") 74 | end 75 | 76 | Step.Name = "Abstract Step"; 77 | Step.Description = "Abstract Step"; 78 | 79 | return Step; -------------------------------------------------------------------------------- /lua/prometheus/steps.lua: -------------------------------------------------------------------------------- 1 | return { 2 | WrapInFunction = require("prometheus.steps.WrapInFunction"); 3 | SplitStrings = require("prometheus.steps.SplitStrings"); 4 | Vmify = require("prometheus.steps.Vmify"); 5 | ConstantArray = require("prometheus.steps.ConstantArray"); 6 | ProxifyLocals = require("prometheus.steps.ProxifyLocals"); 7 | AntiTamper = require("prometheus.steps.AntiTamper"); 8 | EncryptStrings = require("prometheus.steps.EncryptStrings"); 9 | NumbersToExpressions = require("prometheus.steps.NumbersToExpressions"); 10 | AddVararg = require("prometheus.steps.AddVararg"); 11 | } -------------------------------------------------------------------------------- /lua/prometheus/steps/AddVararg.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- AddVararg.lua 4 | -- 5 | -- This Script provides a Simple Obfuscation Step that wraps the entire Script into a function 6 | 7 | local Step = require("prometheus.step"); 8 | local Ast = require("prometheus.ast"); 9 | local visitast = require("prometheus.visitast"); 10 | local AstKind = Ast.AstKind; 11 | 12 | local AddVararg = Step:extend(); 13 | AddVararg.Description = "This Step Adds Vararg to all Functions"; 14 | AddVararg.Name = "Add Vararg"; 15 | 16 | AddVararg.SettingsDescriptor = { 17 | } 18 | 19 | function AddVararg:init(settings) 20 | 21 | end 22 | 23 | function AddVararg:apply(ast) 24 | visitast(ast, nil, function(node) 25 | if node.kind == AstKind.FunctionDeclaration or node.kind == AstKind.LocalFunctionDeclaration or node.kind == AstKind.FunctionLiteralExpression then 26 | if #node.args < 1 or node.args[#node.args].kind ~= AstKind.VarargExpression then 27 | node.args[#node.args + 1] = Ast.VarargExpression(); 28 | end 29 | end 30 | end) 31 | end 32 | 33 | return AddVararg; -------------------------------------------------------------------------------- /lua/prometheus/steps/AntiTamper.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- AntiTamper.lua 4 | -- 5 | -- This Script provides an Obfuscation Step, that breaks the script, when someone tries to tamper with it. 6 | 7 | local Step = require("prometheus.step"); 8 | local Ast = require("prometheus.ast"); 9 | local Scope = require("prometheus.scope"); 10 | local RandomStrings = require("prometheus.randomStrings") 11 | local Parser = require("prometheus.parser"); 12 | local Enums = require("prometheus.enums"); 13 | local logger = require("logger"); 14 | 15 | local AntiTamper = Step:extend(); 16 | AntiTamper.Description = "This Step Breaks your Script when it is modified. This is only effective when using the new VM."; 17 | AntiTamper.Name = "Anti Tamper"; 18 | 19 | AntiTamper.SettingsDescriptor = { 20 | UseDebug = { 21 | type = "boolean", 22 | default = true, 23 | description = "Use debug library. (Recommended, however scripts will not work without debug library.)" 24 | } 25 | } 26 | 27 | function AntiTamper:init(settings) 28 | 29 | end 30 | 31 | function AntiTamper:apply(ast, pipeline) 32 | if pipeline.PrettyPrint then 33 | logger:warn(string.format("\"%s\" cannot be used with PrettyPrint, ignoring \"%s\"", self.Name, self.Name)); 34 | return ast; 35 | end 36 | local code = "do local valid = true;"; 37 | if self.UseDebug then 38 | local string = RandomStrings.randomString(); 39 | code = code .. [[ 40 | -- Anti Beautify 41 | local sethook = debug and debug.sethook or function() end; 42 | local allowedLine = nil; 43 | local called = 0; 44 | sethook(function(s, line) 45 | called = called + 1; 46 | if allowedLine then 47 | if allowedLine ~= line then 48 | sethook(error, "l"); 49 | end 50 | else 51 | allowedLine = line; 52 | end 53 | end, "l"); 54 | (function() end)(); 55 | (function() end)(); 56 | sethook(); 57 | if called < 2 then 58 | valid = false; 59 | end 60 | 61 | -- Anti Function Hook 62 | local funcs = {pcall, string.char, debug.getinfo} 63 | for i = 1, #funcs do 64 | if debug.getinfo(funcs[i]).what ~= "C" then 65 | valid = false; 66 | end 67 | end 68 | 69 | -- Anti Beautify 70 | local function getTraceback() 71 | local str = (function(arg) 72 | return debug.traceback(arg) 73 | end)("]] .. string .. [["); 74 | return str; 75 | end 76 | 77 | local traceback = getTraceback(); 78 | valid = valid and traceback:sub(1, traceback:find("\n") - 1) == "]] .. string .. [["; 79 | local iter = traceback:gmatch(":(%d*):"); 80 | local v, c = iter(), 1; 81 | for i in iter do 82 | valid = valid and i == v; 83 | c = c + 1; 84 | end 85 | valid = valid and c >= 2; 86 | ]] 87 | end 88 | code = code .. [[ 89 | local gmatch = string.gmatch; 90 | local err = function() error("Tamper Detected!") end; 91 | 92 | local pcallIntact2 = false; 93 | local pcallIntact = pcall(function() 94 | pcallIntact2 = true; 95 | end) and pcallIntact2; 96 | 97 | local random = math.random; 98 | local tblconcat = table.concat; 99 | local unpkg = table and table.unpack or unpack; 100 | local n = random(3, 65); 101 | local acc1 = 0; 102 | local acc2 = 0; 103 | local pcallRet = {pcall(function() local a = ]] .. tostring(math.random(1, 2^24)) .. [[ - "]] .. RandomStrings.randomString() .. [[" ^ ]] .. tostring(math.random(1, 2^24)) .. [[ return "]] .. RandomStrings.randomString() .. [[" / a; end)}; 104 | local origMsg = pcallRet[2]; 105 | local line = tonumber(gmatch(tostring(origMsg), ':(%d*):')()); 106 | for i = 1, n do 107 | local len = math.random(1, 100); 108 | local n2 = random(0, 255); 109 | local pos = random(1, len); 110 | local shouldErr = random(1, 2) == 1; 111 | local msg = origMsg:gsub(':(%d*):', ':' .. tostring(random(0, 10000)) .. ':'); 112 | local arr = {pcall(function() 113 | if random(1, 2) == 1 or i == n then 114 | local line2 = tonumber(gmatch(tostring(({pcall(function() local a = ]] .. tostring(math.random(1, 2^24)) .. [[ - "]] .. RandomStrings.randomString() .. [[" ^ ]] .. tostring(math.random(1, 2^24)) .. [[ return "]] .. RandomStrings.randomString() .. [[" / a; end)})[2]), ':(%d*):')()); 115 | valid = valid and line == line2; 116 | end 117 | if shouldErr then 118 | error(msg, 0); 119 | end 120 | local arr = {}; 121 | for i = 1, len do 122 | arr[i] = random(0, 255); 123 | end 124 | arr[pos] = n2; 125 | return unpkg(arr); 126 | end)}; 127 | if shouldErr then 128 | valid = valid and arr[1] == false and arr[2] == msg; 129 | else 130 | valid = valid and arr[1]; 131 | acc1 = (acc1 + arr[pos + 1]) % 256; 132 | acc2 = (acc2 + n2) % 256; 133 | end 134 | end 135 | valid = valid and acc1 == acc2; 136 | 137 | if valid then else 138 | repeat 139 | return (function() 140 | while true do 141 | l1, l2 = l2, l1; 142 | err(); 143 | end 144 | end)(); 145 | until true; 146 | while true do 147 | l2 = random(1, 6); 148 | if l2 > 2 then 149 | l2 = tostring(l1); 150 | else 151 | l1 = l2; 152 | end 153 | end 154 | return; 155 | end 156 | end 157 | 158 | -- Anti Function Arg Hook 159 | local obj = setmetatable({}, { 160 | __tostring = err, 161 | }); 162 | obj[math.random(1, 100)] = obj; 163 | (function() end)(obj); 164 | 165 | repeat until valid; 166 | ]] 167 | 168 | local parsed = Parser:new({LuaVersion = Enums.LuaVersion.Lua51}):parse(code); 169 | local doStat = parsed.body.statements[1]; 170 | doStat.body.scope:setParent(ast.body.scope); 171 | table.insert(ast.body.statements, 1, doStat); 172 | 173 | return ast; 174 | end 175 | 176 | return AntiTamper; -------------------------------------------------------------------------------- /lua/prometheus/steps/ConstantArray.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- ConstantArray.lua 4 | -- 5 | -- This Script provides a Simple Obfuscation Step that wraps the entire Script into a function 6 | 7 | -- TODO: Wrapper Functions 8 | -- TODO: Proxy Object for indexing: e.g: ARR[X] becomes ARR + X 9 | 10 | local Step = require("prometheus.step"); 11 | local Ast = require("prometheus.ast"); 12 | local Scope = require("prometheus.scope"); 13 | local visitast = require("prometheus.visitast"); 14 | local util = require("prometheus.util") 15 | local Parser = require("prometheus.parser"); 16 | local enums = require("prometheus.enums") 17 | 18 | local LuaVersion = enums.LuaVersion; 19 | local AstKind = Ast.AstKind; 20 | 21 | local ConstantArray = Step:extend(); 22 | ConstantArray.Description = "This Step will Extract all Constants and put them into an Array at the beginning of the script"; 23 | ConstantArray.Name = "Constant Array"; 24 | 25 | ConstantArray.SettingsDescriptor = { 26 | Treshold = { 27 | name = "Treshold", 28 | description = "The relative amount of nodes that will be affected", 29 | type = "number", 30 | default = 1, 31 | min = 0, 32 | max = 1, 33 | }, 34 | StringsOnly = { 35 | name = "StringsOnly", 36 | description = "Wether to only Extract Strings", 37 | type = "boolean", 38 | default = false, 39 | }, 40 | Shuffle = { 41 | name = "Shuffle", 42 | description = "Wether to shuffle the order of Elements in the Array", 43 | type = "boolean", 44 | default = true, 45 | }, 46 | Rotate = { 47 | name = "Rotate", 48 | description = "Wether to rotate the String Array by a specific (random) amount. This will be undone on runtime.", 49 | type = "boolean", 50 | default = true, 51 | }, 52 | LocalWrapperTreshold = { 53 | name = "LocalWrapperTreshold", 54 | description = "The relative amount of nodes functions, that will get local wrappers", 55 | type = "number", 56 | default = 1, 57 | min = 0, 58 | max = 1, 59 | }, 60 | LocalWrapperCount = { 61 | name = "LocalWrapperCount", 62 | description = "The number of Local wrapper Functions per scope. This only applies if LocalWrapperTreshold is greater than 0", 63 | type = "number", 64 | min = 0, 65 | max = 512, 66 | default = 0, 67 | }, 68 | LocalWrapperArgCount = { 69 | name = "LocalWrapperArgCount", 70 | description = "The number of Arguments to the Local wrapper Functions", 71 | type = "number", 72 | min = 1, 73 | default = 10, 74 | max = 200, 75 | }; 76 | MaxWrapperOffset = { 77 | name = "MaxWrapperOffset", 78 | description = "The Max Offset for the Wrapper Functions", 79 | type = "number", 80 | min = 0, 81 | default = 65535, 82 | }; 83 | Encoding = { 84 | name = "Encoding", 85 | description = "The Encoding to use for the Strings", 86 | type = "enum", 87 | default = "base64", 88 | values = { 89 | "none", 90 | "base64", 91 | }, 92 | } 93 | } 94 | 95 | local function callNameGenerator(generatorFunction, ...) 96 | if(type(generatorFunction) == "table") then 97 | generatorFunction = generatorFunction.generateName; 98 | end 99 | return generatorFunction(...); 100 | end 101 | 102 | function ConstantArray:init(settings) 103 | 104 | end 105 | 106 | function ConstantArray:createArray() 107 | local entries = {}; 108 | for i, v in ipairs(self.constants) do 109 | if type(v) == "string" then 110 | v = self:encode(v); 111 | end 112 | entries[i] = Ast.TableEntry(Ast.ConstantNode(v)); 113 | end 114 | return Ast.TableConstructorExpression(entries); 115 | end 116 | 117 | function ConstantArray:indexing(index, data) 118 | if self.LocalWrapperCount > 0 and data.functionData.local_wrappers then 119 | local wrappers = data.functionData.local_wrappers; 120 | local wrapper = wrappers[math.random(#wrappers)]; 121 | 122 | local args = {}; 123 | local ofs = index - self.wrapperOffset - wrapper.offset; 124 | for i = 1, self.LocalWrapperArgCount, 1 do 125 | if i == wrapper.arg then 126 | args[i] = Ast.NumberExpression(ofs); 127 | else 128 | args[i] = Ast.NumberExpression(math.random(ofs - 1024, ofs + 1024)); 129 | end 130 | end 131 | 132 | data.scope:addReferenceToHigherScope(wrappers.scope, wrappers.id); 133 | return Ast.FunctionCallExpression(Ast.IndexExpression( 134 | Ast.VariableExpression(wrappers.scope, wrappers.id), 135 | Ast.StringExpression(wrapper.index) 136 | ), args); 137 | else 138 | data.scope:addReferenceToHigherScope(self.rootScope, self.wrapperId); 139 | return Ast.FunctionCallExpression(Ast.VariableExpression(self.rootScope, self.wrapperId), { 140 | Ast.NumberExpression(index - self.wrapperOffset); 141 | }); 142 | end 143 | end 144 | 145 | function ConstantArray:getConstant(value, data) 146 | if(self.lookup[value]) then 147 | return self:indexing(self.lookup[value], data) 148 | end 149 | local idx = #self.constants + 1; 150 | self.constants[idx] = value; 151 | self.lookup[value] = idx; 152 | return self:indexing(idx, data); 153 | end 154 | 155 | function ConstantArray:addConstant(value) 156 | if(self.lookup[value]) then 157 | return 158 | end 159 | local idx = #self.constants + 1; 160 | self.constants[idx] = value; 161 | self.lookup[value] = idx; 162 | end 163 | 164 | local function reverse(t, i, j) 165 | while i < j do 166 | t[i], t[j] = t[j], t[i] 167 | i, j = i+1, j-1 168 | end 169 | end 170 | 171 | local function rotate(t, d, n) 172 | n = n or #t 173 | d = (d or 1) % n 174 | reverse(t, 1, n) 175 | reverse(t, 1, d) 176 | reverse(t, d+1, n) 177 | end 178 | 179 | local rotateCode = [=[ 180 | for i, v in ipairs({{1, LEN}, {1, SHIFT}, {SHIFT + 1, LEN}}) do 181 | while v[1] < v[2] do 182 | ARR[v[1]], ARR[v[2]], v[1], v[2] = ARR[v[2]], ARR[v[1]], v[1] + 1, v[2] - 1 183 | end 184 | end 185 | ]=]; 186 | 187 | function ConstantArray:addRotateCode(ast, shift) 188 | local parser = Parser:new({ 189 | LuaVersion = LuaVersion.Lua51; 190 | }); 191 | 192 | local newAst = parser:parse(string.gsub(string.gsub(rotateCode, "SHIFT", tostring(shift)), "LEN", tostring(#self.constants))); 193 | local forStat = newAst.body.statements[1]; 194 | forStat.body.scope:setParent(ast.body.scope); 195 | visitast(newAst, nil, function(node, data) 196 | if(node.kind == AstKind.VariableExpression) then 197 | if(node.scope:getVariableName(node.id) == "ARR") then 198 | data.scope:removeReferenceToHigherScope(node.scope, node.id); 199 | data.scope:addReferenceToHigherScope(self.rootScope, self.arrId); 200 | node.scope = self.rootScope; 201 | node.id = self.arrId; 202 | end 203 | end 204 | end) 205 | 206 | table.insert(ast.body.statements, 1, forStat); 207 | end 208 | 209 | function ConstantArray:addDecodeCode(ast) 210 | if self.Encoding == "base64" then 211 | local base64DecodeCode = [[ 212 | do ]] .. table.concat(util.shuffle{ 213 | "local lookup = LOOKUP_TABLE;", 214 | "local len = string.len;", 215 | "local sub = string.sub;", 216 | "local floor = math.floor;", 217 | "local strchar = string.char;", 218 | "local insert = table.insert;", 219 | "local concat = table.concat;", 220 | "local type = type;", 221 | "local arr = ARR;", 222 | }) .. [[ 223 | for i = 1, #arr do 224 | local data = arr[i]; 225 | if type(data) == "string" then 226 | local length = len(data) 227 | local parts = {} 228 | local index = 1 229 | local value = 0 230 | local count = 0 231 | while index <= length do 232 | local char = sub(data, index, index) 233 | local code = lookup[char] 234 | if code then 235 | value = value + code * (64 ^ (3 - count)) 236 | count = count + 1 237 | if count == 4 then 238 | count = 0 239 | local c1 = floor(value / 65536) 240 | local c2 = floor(value % 65536 / 256) 241 | local c3 = value % 256 242 | insert(parts, strchar(c1, c2, c3)) 243 | value = 0 244 | end 245 | elseif char == "=" then 246 | insert(parts, strchar(floor(value / 65536))); 247 | if index >= length or sub(data, index + 1, index + 1) ~= "=" then 248 | insert(parts, strchar(floor(value % 65536 / 256))); 249 | end 250 | break 251 | end 252 | index = index + 1 253 | end 254 | arr[i] = concat(parts) 255 | end 256 | end 257 | end 258 | ]]; 259 | 260 | local parser = Parser:new({ 261 | LuaVersion = LuaVersion.Lua51; 262 | }); 263 | 264 | local newAst = parser:parse(base64DecodeCode); 265 | local forStat = newAst.body.statements[1]; 266 | forStat.body.scope:setParent(ast.body.scope); 267 | 268 | visitast(newAst, nil, function(node, data) 269 | if(node.kind == AstKind.VariableExpression) then 270 | if(node.scope:getVariableName(node.id) == "ARR") then 271 | data.scope:removeReferenceToHigherScope(node.scope, node.id); 272 | data.scope:addReferenceToHigherScope(self.rootScope, self.arrId); 273 | node.scope = self.rootScope; 274 | node.id = self.arrId; 275 | end 276 | 277 | if(node.scope:getVariableName(node.id) == "LOOKUP_TABLE") then 278 | data.scope:removeReferenceToHigherScope(node.scope, node.id); 279 | return self:createBase64Lookup(); 280 | end 281 | end 282 | end) 283 | 284 | table.insert(ast.body.statements, 1, forStat); 285 | end 286 | end 287 | 288 | function ConstantArray:createBase64Lookup() 289 | local entries = {}; 290 | local i = 0; 291 | for char in string.gmatch(self.base64chars, ".") do 292 | table.insert(entries, Ast.KeyedTableEntry(Ast.StringExpression(char), Ast.NumberExpression(i))); 293 | i = i + 1; 294 | end 295 | util.shuffle(entries); 296 | return Ast.TableConstructorExpression(entries); 297 | end 298 | 299 | function ConstantArray:encode(str) 300 | if self.Encoding == "base64" then 301 | return ((str:gsub('.', function(x) 302 | local r,b='',x:byte() 303 | for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end 304 | return r; 305 | end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x) 306 | if (#x < 6) then return '' end 307 | local c=0 308 | for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end 309 | return self.base64chars:sub(c+1,c+1) 310 | end)..({ '', '==', '=' })[#str%3+1]); 311 | end 312 | end 313 | 314 | function ConstantArray:apply(ast, pipeline) 315 | self.rootScope = ast.body.scope; 316 | self.arrId = self.rootScope:addVariable(); 317 | 318 | self.base64chars = table.concat(util.shuffle{ 319 | "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 320 | "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", 321 | "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 322 | "+", "/", 323 | }); 324 | 325 | self.constants = {}; 326 | self.lookup = {}; 327 | 328 | -- Extract Constants 329 | visitast(ast, nil, function(node, data) 330 | -- Apply only to some nodes 331 | if math.random() <= self.Treshold then 332 | node.__apply_constant_array = true; 333 | if node.kind == AstKind.StringExpression then 334 | self:addConstant(node.value); 335 | elseif not self.StringsOnly then 336 | if node.isConstant then 337 | if node.value ~= nil then 338 | self:addConstant(node.value); 339 | end 340 | end 341 | end 342 | end 343 | end); 344 | 345 | -- Shuffle Array 346 | if self.Shuffle then 347 | self.constants = util.shuffle(self.constants); 348 | self.lookup = {}; 349 | for i, v in ipairs(self.constants) do 350 | self.lookup[v] = i; 351 | end 352 | end 353 | 354 | -- Set Wrapper Function Offset 355 | self.wrapperOffset = math.random(-self.MaxWrapperOffset, self.MaxWrapperOffset); 356 | self.wrapperId = self.rootScope:addVariable(); 357 | 358 | visitast(ast, function(node, data) 359 | -- Add Local Wrapper Functions 360 | if self.LocalWrapperCount > 0 and node.kind == AstKind.Block and node.isFunctionBlock and math.random() <= self.LocalWrapperTreshold then 361 | local id = node.scope:addVariable() 362 | data.functionData.local_wrappers = { 363 | id = id; 364 | scope = node.scope, 365 | }; 366 | local nameLookup = {}; 367 | for i = 1, self.LocalWrapperCount, 1 do 368 | local name; 369 | repeat 370 | name = callNameGenerator(pipeline.namegenerator, math.random(1, self.LocalWrapperArgCount * 16)); 371 | until not nameLookup[name]; 372 | nameLookup[name] = true; 373 | 374 | local offset = math.random(-self.MaxWrapperOffset, self.MaxWrapperOffset); 375 | local argPos = math.random(1, self.LocalWrapperArgCount); 376 | 377 | data.functionData.local_wrappers[i] = { 378 | arg = argPos, 379 | index = name, 380 | offset = offset, 381 | }; 382 | data.functionData.__used = false; 383 | end 384 | end 385 | if node.__apply_constant_array then 386 | data.functionData.__used = true; 387 | end 388 | end, function(node, data) 389 | -- Actually insert Statements to get the Constant Values 390 | if node.__apply_constant_array then 391 | if node.kind == AstKind.StringExpression then 392 | return self:getConstant(node.value, data); 393 | elseif not self.StringsOnly then 394 | if node.isConstant then 395 | return node.value ~= nil and self:getConstant(node.value, data); 396 | end 397 | end 398 | node.__apply_constant_array = nil; 399 | end 400 | 401 | -- Insert Local Wrapper Declarations 402 | if self.LocalWrapperCount > 0 and node.kind == AstKind.Block and node.isFunctionBlock and data.functionData.local_wrappers and data.functionData.__used then 403 | data.functionData.__used = nil; 404 | local elems = {}; 405 | local wrappers = data.functionData.local_wrappers; 406 | for i = 1, self.LocalWrapperCount, 1 do 407 | local wrapper = wrappers[i]; 408 | local argPos = wrapper.arg; 409 | local offset = wrapper.offset; 410 | local name = wrapper.index; 411 | 412 | local funcScope = Scope:new(node.scope); 413 | 414 | local arg = nil; 415 | local args = {}; 416 | 417 | for i = 1, self.LocalWrapperArgCount, 1 do 418 | args[i] = funcScope:addVariable(); 419 | if i == argPos then 420 | arg = args[i]; 421 | end 422 | end 423 | 424 | local addSubArg; 425 | 426 | -- Create add and Subtract code 427 | if offset < 0 then 428 | addSubArg = Ast.SubExpression(Ast.VariableExpression(funcScope, arg), Ast.NumberExpression(-offset)); 429 | else 430 | addSubArg = Ast.AddExpression(Ast.VariableExpression(funcScope, arg), Ast.NumberExpression(offset)); 431 | end 432 | 433 | funcScope:addReferenceToHigherScope(self.rootScope, self.wrapperId); 434 | local callArg = Ast.FunctionCallExpression(Ast.VariableExpression(self.rootScope, self.wrapperId), { 435 | addSubArg 436 | }); 437 | 438 | local fargs = {}; 439 | for i, v in ipairs(args) do 440 | fargs[i] = Ast.VariableExpression(funcScope, v); 441 | end 442 | 443 | elems[i] = Ast.KeyedTableEntry( 444 | Ast.StringExpression(name), 445 | Ast.FunctionLiteralExpression(fargs, Ast.Block({ 446 | Ast.ReturnStatement({ 447 | callArg 448 | }); 449 | }, funcScope)) 450 | ) 451 | end 452 | table.insert(node.statements, 1, Ast.LocalVariableDeclaration(node.scope, { 453 | wrappers.id 454 | }, { 455 | Ast.TableConstructorExpression(elems) 456 | })); 457 | end 458 | end); 459 | 460 | self:addDecodeCode(ast); 461 | 462 | local steps = util.shuffle({ 463 | -- Add Wrapper Function Code 464 | function() 465 | local funcScope = Scope:new(self.rootScope); 466 | -- Add Reference to Array 467 | funcScope:addReferenceToHigherScope(self.rootScope, self.arrId); 468 | 469 | local arg = funcScope:addVariable(); 470 | local addSubArg; 471 | 472 | -- Create add and Subtract code 473 | if self.wrapperOffset < 0 then 474 | addSubArg = Ast.SubExpression(Ast.VariableExpression(funcScope, arg), Ast.NumberExpression(-self.wrapperOffset)); 475 | else 476 | addSubArg = Ast.AddExpression(Ast.VariableExpression(funcScope, arg), Ast.NumberExpression(self.wrapperOffset)); 477 | end 478 | 479 | -- Create and Add the Function Declaration 480 | table.insert(ast.body.statements, 1, Ast.LocalFunctionDeclaration(self.rootScope, self.wrapperId, { 481 | Ast.VariableExpression(funcScope, arg) 482 | }, Ast.Block({ 483 | Ast.ReturnStatement({ 484 | Ast.IndexExpression( 485 | Ast.VariableExpression(self.rootScope, self.arrId), 486 | addSubArg 487 | ) 488 | }); 489 | }, funcScope))); 490 | 491 | -- Resulting Code: 492 | -- function xy(a) 493 | -- return ARR[a - 10] 494 | -- end 495 | end, 496 | -- Rotate Array and Add unrotate code 497 | function() 498 | if self.Rotate and #self.constants > 1 then 499 | local shift = math.random(1, #self.constants - 1); 500 | 501 | rotate(self.constants, -shift); 502 | self:addRotateCode(ast, shift); 503 | end 504 | end, 505 | }); 506 | 507 | for i, f in ipairs(steps) do 508 | f(); 509 | end 510 | 511 | -- Add the Array Declaration 512 | table.insert(ast.body.statements, 1, Ast.LocalVariableDeclaration(self.rootScope, {self.arrId}, {self:createArray()})); 513 | 514 | self.rootScope = nil; 515 | self.arrId = nil; 516 | 517 | self.constants = nil; 518 | self.lookup = nil; 519 | end 520 | 521 | return ConstantArray; -------------------------------------------------------------------------------- /lua/prometheus/steps/EncryptStrings.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- EncryptStrings.lua 4 | -- 5 | -- This Script provides a Simple Obfuscation Step that encrypts strings 6 | 7 | local Step = require("prometheus.step") 8 | local Ast = require("prometheus.ast") 9 | local Scope = require("prometheus.scope") 10 | local RandomStrings = require("prometheus.randomStrings") 11 | local Parser = require("prometheus.parser") 12 | local Enums = require("prometheus.enums") 13 | local logger = require("logger") 14 | local visitast = require("prometheus.visitast"); 15 | local util = require("prometheus.util") 16 | local AstKind = Ast.AstKind; 17 | 18 | local EncryptStrings = Step:extend() 19 | EncryptStrings.Description = "This Step will encrypt strings within your Program." 20 | EncryptStrings.Name = "Encrypt Strings" 21 | 22 | EncryptStrings.SettingsDescriptor = {} 23 | 24 | function EncryptStrings:init(settings) end 25 | 26 | 27 | function EncryptStrings:CreateEncrypionService() 28 | local usedSeeds = {}; 29 | 30 | local secret_key_6 = math.random(0, 63) -- 6-bit arbitrary integer (0..63) 31 | local secret_key_7 = math.random(0, 127) -- 7-bit arbitrary integer (0..127) 32 | local secret_key_44 = math.random(0, 17592186044415) -- 44-bit arbitrary integer (0..17592186044415) 33 | local secret_key_8 = math.random(0, 255); -- 8-bit arbitrary integer (0..255) 34 | 35 | local floor = math.floor 36 | 37 | local function primitive_root_257(idx) 38 | local g, m, d = 1, 128, 2 * idx + 1 39 | repeat 40 | g, m, d = g * g * (d >= m and 3 or 1) % 257, m / 2, d % m 41 | until m < 1 42 | return g 43 | end 44 | 45 | local param_mul_8 = primitive_root_257(secret_key_7) 46 | local param_mul_45 = secret_key_6 * 4 + 1 47 | local param_add_45 = secret_key_44 * 2 + 1 48 | 49 | local state_45 = 0 50 | local state_8 = 2 51 | 52 | local prev_values = {} 53 | local function set_seed(seed_53) 54 | state_45 = seed_53 % 35184372088832 55 | state_8 = seed_53 % 255 + 2 56 | prev_values = {} 57 | end 58 | 59 | local function gen_seed() 60 | local seed; 61 | repeat 62 | seed = math.random(0, 35184372088832); 63 | until not usedSeeds[seed]; 64 | return seed; 65 | end 66 | 67 | local function get_random_32() 68 | state_45 = (state_45 * param_mul_45 + param_add_45) % 35184372088832 69 | repeat 70 | state_8 = state_8 * param_mul_8 % 257 71 | until state_8 ~= 1 72 | local r = state_8 % 32 73 | local n = floor(state_45 / 2 ^ (13 - (state_8 - r) / 32)) % 2 ^ 32 / 2 ^ r 74 | return floor(n % 1 * 2 ^ 32) + floor(n) 75 | end 76 | 77 | local function get_next_pseudo_random_byte() 78 | if #prev_values == 0 then 79 | local rnd = get_random_32() -- value 0..4294967295 80 | local low_16 = rnd % 65536 81 | local high_16 = (rnd - low_16) / 65536 82 | local b1 = low_16 % 256 83 | local b2 = (low_16 - b1) / 256 84 | local b3 = high_16 % 256 85 | local b4 = (high_16 - b3) / 256 86 | prev_values = { b1, b2, b3, b4 } 87 | end 88 | --print(unpack(prev_values)) 89 | return table.remove(prev_values) 90 | end 91 | 92 | local function encrypt(str) 93 | local seed = gen_seed(); 94 | set_seed(seed) 95 | local len = string.len(str) 96 | local out = {} 97 | local prevVal = secret_key_8; 98 | for i = 1, len do 99 | local byte = string.byte(str, i); 100 | out[i] = string.char((byte - (get_next_pseudo_random_byte() + prevVal)) % 256); 101 | prevVal = byte; 102 | end 103 | return table.concat(out), seed; 104 | end 105 | 106 | local function genCode() 107 | local code = [[ 108 | do 109 | local floor = math.floor 110 | local random = math.random; 111 | local remove = table.remove; 112 | local char = string.char; 113 | local state_45 = 0 114 | local state_8 = 2 115 | local digits = {} 116 | local charmap = {}; 117 | local i = 0; 118 | 119 | local nums = {}; 120 | for i = 1, 256 do 121 | nums[i] = i; 122 | end 123 | 124 | repeat 125 | local idx = random(1, #nums); 126 | local n = remove(nums, idx); 127 | charmap[n] = char(n - 1); 128 | until #nums == 0; 129 | 130 | local prev_values = {} 131 | local function get_next_pseudo_random_byte() 132 | if #prev_values == 0 then 133 | state_45 = (state_45 * ]] .. tostring(param_mul_45) .. [[ + ]] .. tostring(param_add_45) .. [[) % 35184372088832 134 | repeat 135 | state_8 = state_8 * ]] .. tostring(param_mul_8) .. [[ % 257 136 | until state_8 ~= 1 137 | local r = state_8 % 32 138 | local n = floor(state_45 / 2 ^ (13 - (state_8 - r) / 32)) % 2 ^ 32 / 2 ^ r 139 | local rnd = floor(n % 1 * 2 ^ 32) + floor(n) 140 | local low_16 = rnd % 65536 141 | local high_16 = (rnd - low_16) / 65536 142 | local b1 = low_16 % 256 143 | local b2 = (low_16 - b1) / 256 144 | local b3 = high_16 % 256 145 | local b4 = (high_16 - b3) / 256 146 | prev_values = { b1, b2, b3, b4 } 147 | end 148 | return table.remove(prev_values) 149 | end 150 | 151 | local realStrings = {}; 152 | STRINGS = setmetatable({}, { 153 | __index = realStrings; 154 | __metatable = nil; 155 | }); 156 | function DECRYPT(str, seed) 157 | local realStringsLocal = realStrings; 158 | if(realStringsLocal[seed]) then else 159 | prev_values = {}; 160 | local chars = charmap; 161 | state_45 = seed % 35184372088832 162 | state_8 = seed % 255 + 2 163 | local len = string.len(str); 164 | realStringsLocal[seed] = ""; 165 | local prevVal = ]] .. tostring(secret_key_8) .. [[; 166 | for i=1, len do 167 | prevVal = (string.byte(str, i) + get_next_pseudo_random_byte() + prevVal) % 256 168 | realStringsLocal[seed] = realStringsLocal[seed] .. chars[prevVal + 1]; 169 | end 170 | end 171 | return seed; 172 | end 173 | end]] 174 | 175 | return code; 176 | end 177 | 178 | return { 179 | encrypt = encrypt, 180 | param_mul_45 = param_mul_45, 181 | param_mul_8 = param_mul_8, 182 | param_add_45 = param_add_45, 183 | secret_key_8 = secret_key_8, 184 | genCode = genCode, 185 | } 186 | end 187 | 188 | function EncryptStrings:apply(ast, pipeline) 189 | local Encryptor = self:CreateEncrypionService(); 190 | 191 | local code = Encryptor.genCode(); 192 | local newAst = Parser:new({ LuaVersion = Enums.LuaVersion.Lua51 }):parse(code); 193 | local doStat = newAst.body.statements[1]; 194 | 195 | local scope = ast.body.scope; 196 | local decryptVar = scope:addVariable(); 197 | local stringsVar = scope:addVariable(); 198 | 199 | doStat.body.scope:setParent(ast.body.scope); 200 | 201 | visitast(newAst, nil, function(node, data) 202 | if(node.kind == AstKind.FunctionDeclaration) then 203 | if(node.scope:getVariableName(node.id) == "DECRYPT") then 204 | data.scope:removeReferenceToHigherScope(node.scope, node.id); 205 | data.scope:addReferenceToHigherScope(scope, decryptVar); 206 | node.scope = scope; 207 | node.id = decryptVar; 208 | end 209 | end 210 | if(node.kind == AstKind.AssignmentVariable or node.kind == AstKind.VariableExpression) then 211 | if(node.scope:getVariableName(node.id) == "STRINGS") then 212 | data.scope:removeReferenceToHigherScope(node.scope, node.id); 213 | data.scope:addReferenceToHigherScope(scope, stringsVar); 214 | node.scope = scope; 215 | node.id = stringsVar; 216 | end 217 | end 218 | end) 219 | 220 | visitast(ast, nil, function(node, data) 221 | if(node.kind == AstKind.StringExpression) then 222 | data.scope:addReferenceToHigherScope(scope, stringsVar); 223 | data.scope:addReferenceToHigherScope(scope, decryptVar); 224 | local encrypted, seed = Encryptor.encrypt(node.value); 225 | return Ast.IndexExpression(Ast.VariableExpression(scope, stringsVar), Ast.FunctionCallExpression(Ast.VariableExpression(scope, decryptVar), { 226 | Ast.StringExpression(encrypted), Ast.NumberExpression(seed), 227 | })); 228 | end 229 | end) 230 | 231 | 232 | -- Insert to Main Ast 233 | table.insert(ast.body.statements, 1, doStat); 234 | table.insert(ast.body.statements, 1, Ast.LocalVariableDeclaration(scope, util.shuffle{ decryptVar, stringsVar }, {})); 235 | return ast 236 | end 237 | 238 | return EncryptStrings 239 | -------------------------------------------------------------------------------- /lua/prometheus/steps/NumbersToExpressions.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- NumbersToExpressions.lua 4 | -- 5 | -- This Script provides an Obfuscation Step, that converts Number Literals to expressions 6 | unpack = unpack or table.unpack; 7 | 8 | local Step = require("prometheus.step"); 9 | local Ast = require("prometheus.ast"); 10 | local Scope = require("prometheus.scope"); 11 | local visitast = require("prometheus.visitast"); 12 | local util = require("prometheus.util") 13 | 14 | local AstKind = Ast.AstKind; 15 | 16 | local NumbersToExpressions = Step:extend(); 17 | NumbersToExpressions.Description = "This Step Converts number Literals to Expressions"; 18 | NumbersToExpressions.Name = "Numbers To Expressions"; 19 | 20 | NumbersToExpressions.SettingsDescriptor = { 21 | Treshold = { 22 | type = "number", 23 | default = 1, 24 | min = 0, 25 | max = 1, 26 | }, 27 | InternalTreshold = { 28 | type = "number", 29 | default = 0.2, 30 | min = 0, 31 | max = 0.8, 32 | } 33 | } 34 | 35 | function NumbersToExpressions:init(settings) 36 | self.ExpressionGenerators = { 37 | function(val, depth) -- Addition 38 | local val2 = math.random(-2^20, 2^20); 39 | local diff = val - val2; 40 | if tonumber(tostring(diff)) + tonumber(tostring(val2)) ~= val then 41 | return false; 42 | end 43 | return Ast.AddExpression(self:CreateNumberExpression(val2, depth), self:CreateNumberExpression(diff, depth), false); 44 | end, 45 | function(val, depth) -- Subtraction 46 | local val2 = math.random(-2^20, 2^20); 47 | local diff = val + val2; 48 | if tonumber(tostring(diff)) - tonumber(tostring(val2)) ~= val then 49 | return false; 50 | end 51 | return Ast.SubExpression(self:CreateNumberExpression(diff, depth), self:CreateNumberExpression(val2, depth), false); 52 | end 53 | } 54 | end 55 | 56 | function NumbersToExpressions:CreateNumberExpression(val, depth) 57 | if depth > 0 and math.random() >= self.InternalTreshold or depth > 15 then 58 | return Ast.NumberExpression(val) 59 | end 60 | 61 | local generators = util.shuffle({unpack(self.ExpressionGenerators)}); 62 | for i, generator in ipairs(generators) do 63 | local node = generator(val, depth + 1); 64 | if node then 65 | return node; 66 | end 67 | end 68 | 69 | return Ast.NumberExpression(val) 70 | end 71 | 72 | function NumbersToExpressions:apply(ast) 73 | visitast(ast, nil, function(node, data) 74 | if node.kind == AstKind.NumberExpression then 75 | if math.random() <= self.Treshold then 76 | return self:CreateNumberExpression(node.value, 0); 77 | end 78 | end 79 | end) 80 | end 81 | 82 | return NumbersToExpressions; -------------------------------------------------------------------------------- /lua/prometheus/steps/ProxifyLocals.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- ProxifyLocals.lua 4 | -- 5 | -- This Script provides a Obfuscation Step for putting all Locals into Proxy Objects 6 | 7 | local Step = require("prometheus.step"); 8 | local Ast = require("prometheus.ast"); 9 | local Scope = require("prometheus.scope"); 10 | local visitast = require("prometheus.visitast"); 11 | local RandomLiterals = require("prometheus.randomLiterals") 12 | 13 | local AstKind = Ast.AstKind; 14 | 15 | local ProifyLocals = Step:extend(); 16 | ProifyLocals.Description = "This Step wraps all locals into Proxy Objects"; 17 | ProifyLocals.Name = "Proxify Locals"; 18 | 19 | ProifyLocals.SettingsDescriptor = { 20 | LiteralType = { 21 | name = "LiteralType", 22 | description = "The type of the randomly generated literals", 23 | type = "enum", 24 | values = { 25 | "dictionary", 26 | "number", 27 | "string", 28 | "any", 29 | }, 30 | default = "string", 31 | }, 32 | } 33 | 34 | local function shallowcopy(orig) 35 | local orig_type = type(orig) 36 | local copy 37 | if orig_type == 'table' then 38 | copy = {} 39 | for orig_key, orig_value in pairs(orig) do 40 | copy[orig_key] = orig_value 41 | end 42 | else -- number, string, boolean, etc 43 | copy = orig 44 | end 45 | return copy 46 | end 47 | 48 | local function callNameGenerator(generatorFunction, ...) 49 | if(type(generatorFunction) == "table") then 50 | generatorFunction = generatorFunction.generateName; 51 | end 52 | return generatorFunction(...); 53 | end 54 | 55 | local MetatableExpressions = { 56 | { 57 | constructor = Ast.AddExpression, 58 | key = "__add"; 59 | }, 60 | { 61 | constructor = Ast.SubExpression, 62 | key = "__sub"; 63 | }, 64 | { 65 | constructor = Ast.IndexExpression, 66 | key = "__index"; 67 | }, 68 | { 69 | constructor = Ast.MulExpression, 70 | key = "__mul"; 71 | }, 72 | { 73 | constructor = Ast.DivExpression, 74 | key = "__div"; 75 | }, 76 | { 77 | constructor = Ast.PowExpression, 78 | key = "__pow"; 79 | }, 80 | { 81 | constructor = Ast.StrCatExpression, 82 | key = "__concat"; 83 | } 84 | } 85 | 86 | function ProifyLocals:init(settings) 87 | 88 | end 89 | 90 | local function generateLocalMetatableInfo(pipeline) 91 | local usedOps = {}; 92 | local info = {}; 93 | for i, v in ipairs({"setValue","getValue", "index"}) do 94 | local rop; 95 | repeat 96 | rop = MetatableExpressions[math.random(#MetatableExpressions)]; 97 | until not usedOps[rop]; 98 | usedOps[rop] = true; 99 | info[v] = rop; 100 | end 101 | 102 | info.valueName = callNameGenerator(pipeline.namegenerator, math.random(1, 4096)); 103 | 104 | return info; 105 | end 106 | 107 | function ProifyLocals:CreateAssignmentExpression(info, expr, parentScope) 108 | local metatableVals = {}; 109 | 110 | -- Setvalue Entry 111 | local setValueFunctionScope = Scope:new(parentScope); 112 | local setValueSelf = setValueFunctionScope:addVariable(); 113 | local setValueArg = setValueFunctionScope:addVariable(); 114 | local setvalueFunctionLiteral = Ast.FunctionLiteralExpression( 115 | { 116 | Ast.VariableExpression(setValueFunctionScope, setValueSelf), -- Argument 1 117 | Ast.VariableExpression(setValueFunctionScope, setValueArg), -- Argument 2 118 | }, 119 | Ast.Block({ -- Create Function Body 120 | Ast.AssignmentStatement({ 121 | Ast.AssignmentIndexing(Ast.VariableExpression(setValueFunctionScope, setValueSelf), Ast.StringExpression(info.valueName)); 122 | }, { 123 | Ast.VariableExpression(setValueFunctionScope, setValueArg) 124 | }) 125 | }, setValueFunctionScope) 126 | ); 127 | table.insert(metatableVals, Ast.KeyedTableEntry(Ast.StringExpression(info.setValue.key), setvalueFunctionLiteral)); 128 | 129 | -- Getvalue Entry 130 | local getValueFunctionScope = Scope:new(parentScope); 131 | local getValueSelf = getValueFunctionScope:addVariable(); 132 | local getValueArg = getValueFunctionScope:addVariable(); 133 | local getValueIdxExpr; 134 | if(info.getValue.key == "__index" or info.setValue.key == "__index") then 135 | getValueIdxExpr = Ast.FunctionCallExpression(Ast.VariableExpression(getValueFunctionScope:resolveGlobal("rawget")), { 136 | Ast.VariableExpression(getValueFunctionScope, getValueSelf), 137 | Ast.StringExpression(info.valueName), 138 | }); 139 | else 140 | getValueIdxExpr = Ast.IndexExpression(Ast.VariableExpression(getValueFunctionScope, getValueSelf), Ast.StringExpression(info.valueName)); 141 | end 142 | local getvalueFunctionLiteral = Ast.FunctionLiteralExpression( 143 | { 144 | Ast.VariableExpression(getValueFunctionScope, getValueSelf), -- Argument 1 145 | Ast.VariableExpression(getValueFunctionScope, getValueArg), -- Argument 2 146 | }, 147 | Ast.Block({ -- Create Function Body 148 | Ast.ReturnStatement({ 149 | getValueIdxExpr; 150 | }); 151 | }, getValueFunctionScope) 152 | ); 153 | table.insert(metatableVals, Ast.KeyedTableEntry(Ast.StringExpression(info.getValue.key), getvalueFunctionLiteral)); 154 | 155 | parentScope:addReferenceToHigherScope(self.setMetatableVarScope, self.setMetatableVarId); 156 | return Ast.FunctionCallExpression( 157 | Ast.VariableExpression(self.setMetatableVarScope, self.setMetatableVarId), 158 | { 159 | Ast.TableConstructorExpression({ 160 | Ast.KeyedTableEntry(Ast.StringExpression(info.valueName), expr) 161 | }), 162 | Ast.TableConstructorExpression(metatableVals) 163 | } 164 | ); 165 | end 166 | 167 | function ProifyLocals:apply(ast, pipeline) 168 | local localMetatableInfos = {}; 169 | local function getLocalMetatableInfo(scope, id) 170 | -- Global Variables should not be transformed 171 | if(scope.isGlobal) then return nil end; 172 | 173 | localMetatableInfos[scope] = localMetatableInfos[scope] or {}; 174 | if localMetatableInfos[scope][id] then 175 | -- If locked, return no Metatable 176 | if localMetatableInfos[scope][id].locked then 177 | return nil 178 | end 179 | return localMetatableInfos[scope][id]; 180 | end 181 | local localMetatableInfo = generateLocalMetatableInfo(pipeline); 182 | localMetatableInfos[scope][id] = localMetatableInfo; 183 | return localMetatableInfo; 184 | end 185 | 186 | local function disableMetatableInfo(scope, id) 187 | -- Global Variables should not be transformed 188 | if(scope.isGlobal) then return nil end; 189 | 190 | localMetatableInfos[scope] = localMetatableInfos[scope] or {}; 191 | localMetatableInfos[scope][id] = {locked = true} 192 | end 193 | 194 | -- Create Setmetatable Variable 195 | self.setMetatableVarScope = ast.body.scope; 196 | self.setMetatableVarId = ast.body.scope:addVariable(); 197 | 198 | -- Create Empty Function Variable 199 | self.emptyFunctionScope = ast.body.scope; 200 | self.emptyFunctionId = ast.body.scope:addVariable(); 201 | self.emptyFunctionUsed = false; 202 | 203 | -- Add Empty Function Declaration 204 | table.insert(ast.body.statements, 1, Ast.LocalVariableDeclaration(self.emptyFunctionScope, {self.emptyFunctionId}, { 205 | Ast.FunctionLiteralExpression({}, Ast.Block({}, Scope:new(ast.body.scope))); 206 | })); 207 | 208 | 209 | visitast(ast, function(node, data) 210 | -- Lock for loop variables 211 | if(node.kind == AstKind.ForStatement) then 212 | disableMetatableInfo(node.scope, node.id) 213 | end 214 | if(node.kind == AstKind.ForInStatement) then 215 | for i, id in ipairs(node.ids) do 216 | disableMetatableInfo(node.scope, id); 217 | end 218 | end 219 | 220 | -- Lock Function Arguments 221 | if(node.kind == AstKind.FunctionDeclaration or node.kind == AstKind.LocalFunctionDeclaration or node.kind == AstKind.FunctionLiteralExpression) then 222 | for i, expr in ipairs(node.args) do 223 | if expr.kind == AstKind.VariableExpression then 224 | disableMetatableInfo(expr.scope, expr.id); 225 | end 226 | end 227 | end 228 | 229 | -- Assignment Statements may be Obfuscated Differently 230 | if(node.kind == AstKind.AssignmentStatement) then 231 | if(#node.lhs == 1 and node.lhs[1].kind == AstKind.AssignmentVariable) then 232 | local variable = node.lhs[1]; 233 | local localMetatableInfo = getLocalMetatableInfo(variable.scope, variable.id); 234 | if localMetatableInfo then 235 | local args = shallowcopy(node.rhs); 236 | local vexp = Ast.VariableExpression(variable.scope, variable.id); 237 | vexp.__ignoreProxifyLocals = true; 238 | args[1] = localMetatableInfo.setValue.constructor(vexp, args[1]); 239 | self.emptyFunctionUsed = true; 240 | data.scope:addReferenceToHigherScope(self.emptyFunctionScope, self.emptyFunctionId); 241 | return Ast.FunctionCallStatement(Ast.VariableExpression(self.emptyFunctionScope, self.emptyFunctionId), args); 242 | end 243 | end 244 | end 245 | end, function(node, data) 246 | -- Local Variable Declaration 247 | if(node.kind == AstKind.LocalVariableDeclaration) then 248 | for i, id in ipairs(node.ids) do 249 | local expr = node.expressions[i] or Ast.NilExpression(); 250 | local localMetatableInfo = getLocalMetatableInfo(node.scope, id); 251 | -- Apply Only to Some Variables if Treshold is non 1 252 | if localMetatableInfo then 253 | local newExpr = self:CreateAssignmentExpression(localMetatableInfo, expr, node.scope); 254 | node.expressions[i] = newExpr; 255 | end 256 | end 257 | end 258 | 259 | -- Variable Expression 260 | if(node.kind == AstKind.VariableExpression and not node.__ignoreProxifyLocals) then 261 | local localMetatableInfo = getLocalMetatableInfo(node.scope, node.id); 262 | -- Apply Only to Some Variables if Treshold is non 1 263 | if localMetatableInfo then 264 | local literal; 265 | if self.LiteralType == "dictionary" then 266 | literal = RandomLiterals.Dictionary(); 267 | elseif self.LiteralType == "number" then 268 | literal = RandomLiterals.Number(); 269 | elseif self.LiteralType == "string" then 270 | literal = RandomLiterals.String(pipeline); 271 | else 272 | literal = RandomLiterals.Any(pipeline); 273 | end 274 | return localMetatableInfo.getValue.constructor(node, literal); 275 | end 276 | end 277 | 278 | -- Assignment Variable for Assignment Statement 279 | if(node.kind == AstKind.AssignmentVariable) then 280 | local localMetatableInfo = getLocalMetatableInfo(node.scope, node.id); 281 | -- Apply Only to Some Variables if Treshold is non 1 282 | if localMetatableInfo then 283 | return Ast.AssignmentIndexing(node, Ast.StringExpression(localMetatableInfo.valueName)); 284 | end 285 | end 286 | 287 | -- Local Function Declaration 288 | if(node.kind == AstKind.LocalFunctionDeclaration) then 289 | local localMetatableInfo = getLocalMetatableInfo(node.scope, node.id); 290 | -- Apply Only to Some Variables if Treshold is non 1 291 | if localMetatableInfo then 292 | local funcLiteral = Ast.FunctionLiteralExpression(node.args, node.body); 293 | local newExpr = self:CreateAssignmentExpression(localMetatableInfo, funcLiteral, node.scope); 294 | return Ast.LocalVariableDeclaration(node.scope, {node.id}, {newExpr}); 295 | end 296 | end 297 | 298 | -- Function Declaration 299 | if(node.kind == AstKind.FunctionDeclaration) then 300 | local localMetatableInfo = getLocalMetatableInfo(node.scope, node.id); 301 | if(localMetatableInfo) then 302 | table.insert(node.indices, 1, localMetatableInfo.valueName); 303 | end 304 | end 305 | end) 306 | 307 | -- Add Setmetatable Variable Declaration 308 | table.insert(ast.body.statements, 1, Ast.LocalVariableDeclaration(self.setMetatableVarScope, {self.setMetatableVarId}, { 309 | Ast.VariableExpression(self.setMetatableVarScope:resolveGlobal("setmetatable")) 310 | })); 311 | end 312 | 313 | return ProifyLocals; -------------------------------------------------------------------------------- /lua/prometheus/steps/SplitStrings.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- SplitStrings.lua 4 | -- 5 | -- This Script provides a Simple Obfuscation Step for splitting Strings 6 | 7 | local Step = require("prometheus.step"); 8 | local Ast = require("prometheus.ast"); 9 | local visitAst = require("prometheus.visitast"); 10 | local Parser = require("prometheus.parser"); 11 | local util = require("prometheus.util"); 12 | local enums = require("prometheus.enums") 13 | 14 | local LuaVersion = enums.LuaVersion; 15 | 16 | local SplitStrings = Step:extend(); 17 | SplitStrings.Description = "This Step splits Strings to a specific or random length"; 18 | SplitStrings.Name = "Split Strings"; 19 | 20 | SplitStrings.SettingsDescriptor = { 21 | Treshold = { 22 | name = "Treshold", 23 | description = "The relative amount of nodes that will be affected", 24 | type = "number", 25 | default = 1, 26 | min = 0, 27 | max = 1, 28 | }, 29 | MinLength = { 30 | name = "MinLength", 31 | description = "The minimal length for the chunks in that the Strings are splitted", 32 | type = "number", 33 | default = 5, 34 | min = 1, 35 | max = nil, 36 | }, 37 | MaxLength = { 38 | name = "MaxLength", 39 | description = "The maximal length for the chunks in that the Strings are splitted", 40 | type = "number", 41 | default = 5, 42 | min = 1, 43 | max = nil, 44 | }, 45 | ConcatenationType = { 46 | name = "ConcatenationType", 47 | description = "The Functions used for Concatenation. Note that when using custom, the String Array will also be Shuffled", 48 | type = "enum", 49 | values = { 50 | "strcat", 51 | "table", 52 | "custom", 53 | }, 54 | default = "custom", 55 | }, 56 | CustomFunctionType = { 57 | name = "CustomFunctionType", 58 | description = "The Type of Function code injection This Option only applies when custom Concatenation is selected.\ 59 | Note that when chosing inline, the code size may increase significantly!", 60 | type = "enum", 61 | values = { 62 | "global", 63 | "local", 64 | "inline", 65 | }, 66 | default = "global", 67 | }, 68 | CustomLocalFunctionsCount = { 69 | name = "CustomLocalFunctionsCount", 70 | description = "The number of local functions per scope. This option only applies when CustomFunctionType = local", 71 | type = "number", 72 | default = 2, 73 | min = 1, 74 | } 75 | } 76 | 77 | function SplitStrings:init(settings) end 78 | 79 | local function generateTableConcatNode(chunks, data) 80 | local chunkNodes = {}; 81 | for i, chunk in ipairs(chunks) do 82 | table.insert(chunkNodes, Ast.TableEntry(Ast.StringExpression(chunk))); 83 | end 84 | local tb = Ast.TableConstructorExpression(chunkNodes); 85 | data.scope:addReferenceToHigherScope(data.tableConcatScope, data.tableConcatId); 86 | return Ast.FunctionCallExpression(Ast.VariableExpression(data.tableConcatScope, data.tableConcatId), {tb}); 87 | end 88 | 89 | local function generateStrCatNode(chunks) 90 | -- Put Together Expression for Concatenating String 91 | local generatedNode = nil; 92 | for i, chunk in ipairs(chunks) do 93 | if generatedNode then 94 | generatedNode = Ast.StrCatExpression(generatedNode, Ast.StringExpression(chunk)); 95 | else 96 | generatedNode = Ast.StringExpression(chunk); 97 | end 98 | end 99 | return generatedNode 100 | end 101 | 102 | local customVariants = 2; 103 | local custom1Code = [=[ 104 | function custom(table) 105 | local stringTable, str = table[#table], ""; 106 | for i=1,#stringTable, 1 do 107 | str = str .. stringTable[table[i]]; 108 | end 109 | return str 110 | end 111 | ]=]; 112 | 113 | local custom2Code = [=[ 114 | function custom(tb) 115 | local str = ""; 116 | for i=1, #tb / 2, 1 do 117 | str = str .. tb[#tb / 2 + tb[i]]; 118 | end 119 | return str 120 | end 121 | ]=]; 122 | 123 | local function generateCustomNodeArgs(chunks, data, variant) 124 | local shuffled = {}; 125 | local shuffledIndices = {}; 126 | for i = 1, #chunks, 1 do 127 | shuffledIndices[i] = i; 128 | end 129 | util.shuffle(shuffledIndices); 130 | 131 | for i, v in ipairs(shuffledIndices) do 132 | shuffled[v] = chunks[i]; 133 | end 134 | 135 | -- Custom Function Type 1 136 | if variant == 1 then 137 | local args = {}; 138 | local tbNodes = {}; 139 | 140 | for i, v in ipairs(shuffledIndices) do 141 | table.insert(args, Ast.TableEntry(Ast.NumberExpression(v))); 142 | end 143 | 144 | for i, chunk in ipairs(shuffled) do 145 | table.insert(tbNodes, Ast.TableEntry(Ast.StringExpression(chunk))); 146 | end 147 | 148 | local tb = Ast.TableConstructorExpression(tbNodes); 149 | 150 | table.insert(args, Ast.TableEntry(tb)); 151 | return {Ast.TableConstructorExpression(args)}; 152 | 153 | -- Custom Function Type 2 154 | else 155 | 156 | local args = {}; 157 | for i, v in ipairs(shuffledIndices) do 158 | table.insert(args, Ast.TableEntry(Ast.NumberExpression(v))); 159 | end 160 | for i, chunk in ipairs(shuffled) do 161 | table.insert(args, Ast.TableEntry(Ast.StringExpression(chunk))); 162 | end 163 | return {Ast.TableConstructorExpression(args)}; 164 | end 165 | 166 | end 167 | 168 | local function generateCustomFunctionLiteral(parentScope, variant) 169 | local parser = Parser:new({ 170 | LuaVersion = LuaVersion.Lua52; 171 | }); 172 | 173 | -- Custom Function Type 1 174 | if variant == 1 then 175 | local funcDeclNode = parser:parse(custom1Code).body.statements[1]; 176 | local funcBody = funcDeclNode.body; 177 | local funcArgs = funcDeclNode.args; 178 | funcBody.scope:setParent(parentScope); 179 | return Ast.FunctionLiteralExpression(funcArgs, funcBody); 180 | 181 | -- Custom Function Type 2 182 | else 183 | local funcDeclNode = parser:parse(custom2Code).body.statements[1]; 184 | local funcBody = funcDeclNode.body; 185 | local funcArgs = funcDeclNode.args; 186 | funcBody.scope:setParent(parentScope); 187 | return Ast.FunctionLiteralExpression(funcArgs, funcBody); 188 | end 189 | end 190 | 191 | local function generateGlobalCustomFunctionDeclaration(ast, data) 192 | local parser = Parser:new({ 193 | LuaVersion = LuaVersion.Lua52; 194 | }); 195 | 196 | -- Custom Function Type 1 197 | if data.customFunctionVariant == 1 then 198 | local astScope = ast.body.scope; 199 | local funcDeclNode = parser:parse(custom1Code).body.statements[1]; 200 | local funcBody = funcDeclNode.body; 201 | local funcArgs = funcDeclNode.args; 202 | funcBody.scope:setParent(astScope); 203 | return Ast.LocalVariableDeclaration(astScope, {data.customFuncId}, 204 | {Ast.FunctionLiteralExpression(funcArgs, funcBody)}); 205 | -- Custom Function Type 2 206 | else 207 | local astScope = ast.body.scope; 208 | local funcDeclNode = parser:parse(custom2Code).body.statements[1]; 209 | local funcBody = funcDeclNode.body; 210 | local funcArgs = funcDeclNode.args; 211 | funcBody.scope:setParent(astScope); 212 | return Ast.LocalVariableDeclaration(data.customFuncScope, {data.customFuncId}, 213 | {Ast.FunctionLiteralExpression(funcArgs, funcBody)}); 214 | end 215 | end 216 | 217 | function SplitStrings:variant() 218 | return math.random(1, customVariants); 219 | end 220 | 221 | function SplitStrings:apply(ast, pipeline) 222 | local data = {}; 223 | 224 | 225 | if(self.ConcatenationType == "table") then 226 | local scope = ast.body.scope; 227 | local id = scope:addVariable(); 228 | data.tableConcatScope = scope; 229 | data.tableConcatId = id; 230 | elseif(self.ConcatenationType == "custom") then 231 | data.customFunctionType = self.CustomFunctionType; 232 | if data.customFunctionType == "global" then 233 | local scope = ast.body.scope; 234 | local id = scope:addVariable(); 235 | data.customFuncScope = scope; 236 | data.customFuncId = id; 237 | data.customFunctionVariant = self:variant(); 238 | end 239 | end 240 | 241 | 242 | local customLocalFunctionsCount = self.CustomLocalFunctionsCount; 243 | local self2 = self; 244 | 245 | visitAst(ast, function(node, data) 246 | -- Previsit Function 247 | 248 | -- Create Local Function declarations 249 | if(self.ConcatenationType == "custom" and data.customFunctionType == "local" and node.kind == Ast.AstKind.Block and node.isFunctionBlock) then 250 | data.functionData.localFunctions = {}; 251 | for i = 1, customLocalFunctionsCount, 1 do 252 | local scope = data.scope; 253 | local id = scope:addVariable(); 254 | local variant = self:variant(); 255 | table.insert(data.functionData.localFunctions, { 256 | scope = scope, 257 | id = id, 258 | variant = variant, 259 | used = false, 260 | }); 261 | end 262 | end 263 | 264 | end, function(node, data) 265 | -- PostVisit Function 266 | 267 | -- Create actual function literals for local customFunctionType 268 | if(self.ConcatenationType == "custom" and data.customFunctionType == "local" and node.kind == Ast.AstKind.Block and node.isFunctionBlock) then 269 | for i, func in ipairs(data.functionData.localFunctions) do 270 | if func.used then 271 | local literal = generateCustomFunctionLiteral(func.scope, func.variant); 272 | table.insert(node.statements, 1, Ast.LocalVariableDeclaration(func.scope, {func.id}, {literal})); 273 | end 274 | end 275 | end 276 | 277 | 278 | -- Apply Only to String nodes 279 | if(node.kind == Ast.AstKind.StringExpression) then 280 | local str = node.value; 281 | local chunks = {}; 282 | local i = 1; 283 | 284 | -- Split String into Parts of length between MinLength and MaxLength 285 | while i <= string.len(str) do 286 | local len = math.random(self.MinLength, self.MaxLength); 287 | table.insert(chunks, string.sub(str, i, i + len - 1)); 288 | i = i + len; 289 | end 290 | 291 | if(#chunks > 1) then 292 | if math.random() < self.Treshold then 293 | if self.ConcatenationType == "strcat" then 294 | node = generateStrCatNode(chunks); 295 | elseif self.ConcatenationType == "table" then 296 | node = generateTableConcatNode(chunks, data); 297 | elseif self.ConcatenationType == "custom" then 298 | if self.CustomFunctionType == "global" then 299 | local args = generateCustomNodeArgs(chunks, data, data.customFunctionVariant); 300 | -- Add Reference for Variable Renaming 301 | data.scope:addReferenceToHigherScope(data.customFuncScope, data.customFuncId); 302 | node = Ast.FunctionCallExpression(Ast.VariableExpression(data.customFuncScope, data.customFuncId), args); 303 | elseif self.CustomFunctionType == "local" then 304 | local lfuncs = data.functionData.localFunctions; 305 | local idx = math.random(1, #lfuncs); 306 | local func = lfuncs[idx]; 307 | local args = generateCustomNodeArgs(chunks, data, func.variant); 308 | func.used = true; 309 | -- Add Reference for Variable Renaming 310 | data.scope:addReferenceToHigherScope(func.scope, func.id); 311 | node = Ast.FunctionCallExpression(Ast.VariableExpression(func.scope, func.id), args); 312 | elseif self.CustomFunctionType == "inline" then 313 | local variant = self:variant(); 314 | local args = generateCustomNodeArgs(chunks, data, variant); 315 | local literal = generateCustomFunctionLiteral(data.scope, variant); 316 | node = Ast.FunctionCallExpression(literal, args); 317 | end 318 | end 319 | end 320 | end 321 | 322 | return node, true; 323 | end 324 | end, data) 325 | 326 | 327 | if(self.ConcatenationType == "table") then 328 | local globalScope = data.globalScope; 329 | local tableScope, tableId = globalScope:resolve("table") 330 | ast.body.scope:addReferenceToHigherScope(globalScope, tableId); 331 | table.insert(ast.body.statements, 1, Ast.LocalVariableDeclaration(data.tableConcatScope, {data.tableConcatId}, 332 | {Ast.IndexExpression(Ast.VariableExpression(tableScope, tableId), Ast.StringExpression("concat"))})); 333 | elseif(self.ConcatenationType == "custom" and self.CustomFunctionType == "global") then 334 | table.insert(ast.body.statements, 1, generateGlobalCustomFunctionDeclaration(ast, data)); 335 | end 336 | end 337 | 338 | return SplitStrings; -------------------------------------------------------------------------------- /lua/prometheus/steps/Vmify.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- Vmify.lua 4 | -- 5 | -- This Script provides a Complex Obfuscation Step that will compile the entire Script to a fully custom bytecode that does not share it's instructions 6 | -- with lua, making it much harder to crack than other lua obfuscators 7 | 8 | local Step = require("prometheus.step"); 9 | local Compiler = require("prometheus.compiler.compiler"); 10 | 11 | local Vmify = Step:extend(); 12 | Vmify.Description = "This Step will Compile your script into a fully-custom (not a half custom like other lua obfuscators) Bytecode Format and emit a vm for executing it."; 13 | Vmify.Name = "Vmify"; 14 | 15 | Vmify.SettingsDescriptor = { 16 | } 17 | 18 | function Vmify:init(settings) 19 | 20 | end 21 | 22 | function Vmify:apply(ast) 23 | -- Create Compiler 24 | local compiler = Compiler:new(); 25 | 26 | -- Compile the Script into a bytecode vm 27 | return compiler:compile(ast); 28 | end 29 | 30 | return Vmify; -------------------------------------------------------------------------------- /lua/prometheus/steps/WrapInFunction.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- WrapInFunction.lua 4 | -- 5 | -- This Script provides a Simple Obfuscation Step that wraps the entire Script into a function 6 | 7 | local Step = require("prometheus.step"); 8 | local Ast = require("prometheus.ast"); 9 | local Scope = require("prometheus.scope"); 10 | 11 | local WrapInFunction = Step:extend(); 12 | WrapInFunction.Description = "This Step Wraps the Entire Script into a Function"; 13 | WrapInFunction.Name = "Wrap in Function"; 14 | 15 | WrapInFunction.SettingsDescriptor = { 16 | Iterations = { 17 | name = "Iterations", 18 | description = "The Number Of Iterations", 19 | type = "number", 20 | default = 1, 21 | min = 1, 22 | max = nil, 23 | } 24 | } 25 | 26 | function WrapInFunction:init(settings) 27 | 28 | end 29 | 30 | function WrapInFunction:apply(ast) 31 | for i = 1, self.Iterations, 1 do 32 | local body = ast.body; 33 | 34 | local scope = Scope:new(ast.globalScope); 35 | body.scope:setParent(scope); 36 | 37 | ast.body = Ast.Block({ 38 | Ast.ReturnStatement({ 39 | Ast.FunctionCallExpression(Ast.FunctionLiteralExpression({Ast.VarargExpression()}, body), {Ast.VarargExpression()}) 40 | }); 41 | }, scope); 42 | end 43 | end 44 | 45 | return WrapInFunction; -------------------------------------------------------------------------------- /lua/prometheus/tokenizer.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- tokenizer.lua 4 | -- Overview: 5 | -- This Script provides a class for lexical Analysis of lua code. 6 | -- This Tokenizer is Capable of tokenizing LuaU and Lua5.1 7 | local Enums = require("prometheus.enums"); 8 | local util = require("prometheus.util"); 9 | local logger = require("logger"); 10 | local config = require("config"); 11 | 12 | local LuaVersion = Enums.LuaVersion; 13 | local lookupify = util.lookupify; 14 | local unlookupify = util.unlookupify; 15 | local escape = util.escape; 16 | local chararray = util.chararray; 17 | local keys = util.keys; 18 | local Tokenizer = {}; 19 | 20 | Tokenizer.EOF_CHAR = ""; 21 | Tokenizer.WHITESPACE_CHARS = lookupify{ 22 | " ", "\t", "\n", "\r", 23 | } 24 | 25 | Tokenizer.ANNOTATION_CHARS = lookupify(chararray("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_")) 26 | Tokenizer.ANNOTATION_START_CHARS = lookupify(chararray("!@")) 27 | 28 | Tokenizer.Conventions = Enums.Conventions; 29 | 30 | Tokenizer.TokenKind = { 31 | Eof = "Eof", 32 | Keyword = "Keyword", 33 | Symbol = "Symbol", 34 | Ident = "Identifier", 35 | Number = "Number", 36 | String = "String", 37 | } 38 | 39 | Tokenizer.EOF_TOKEN = { 40 | kind = Tokenizer.TokenKind.Eof, 41 | value = "", 42 | startPos = -1, 43 | endPos = -1, 44 | source = "", 45 | } 46 | 47 | local function getPosition(source, i) 48 | local line = 1; 49 | local linePos = 1; 50 | 51 | for j = 1, i do 52 | local c = source:sub(j,j) 53 | if c == '\n' then 54 | line = line + 1; 55 | linePos = 1; 56 | else 57 | linePos = linePos + 1; 58 | end 59 | end 60 | return line, linePos 61 | end 62 | 63 | local function token(self, startPos, kind, value) 64 | local line, linePos = getPosition(self.source, self.index); 65 | local annotations = self.annotations 66 | self.annotations = {}; 67 | return { 68 | kind = kind, 69 | value = value, 70 | startPos = startPos, 71 | endPos = self.index, 72 | source = self.source:sub(startPos + 1, self.index), 73 | line = line, 74 | linePos = linePos, 75 | annotations = annotations, 76 | } 77 | end 78 | 79 | local function generateError(self, message) 80 | local line, linePos = getPosition(self.source, self.index); 81 | return "Lexing Error at Position " .. tostring(line) .. ":" .. tostring(linePos) .. ", " .. message; 82 | end 83 | 84 | local function generateWarning(token, message) 85 | return "Warning at Position " .. tostring(token.line) .. ":" .. tostring(token.linePos) .. ", " .. message; 86 | end 87 | 88 | -- Constructor for Tokenizer 89 | function Tokenizer:new(settings) 90 | local luaVersion = (settings and (settings.luaVersion or settings.LuaVersion)) or LuaVersion.LuaU; 91 | local conventions = Tokenizer.Conventions[luaVersion]; 92 | 93 | if(conventions == nil) then 94 | logger:error("The Lua Version \"" .. luaVersion .. "\" is not recognised by the Tokenizer! Please use one of the following: \"" .. table.concat(keys(Tokenizer.Conventions), "\",\"") .. "\""); 95 | end 96 | 97 | local tokenizer = { 98 | index = 0, -- Index where the current char is read 99 | length = 0, 100 | source = "", -- Source to Tokenize 101 | luaVersion = luaVersion, -- LuaVersion to be used while Tokenizing 102 | conventions = conventions; 103 | 104 | NumberChars = conventions.NumberChars, 105 | NumberCharsLookup = lookupify(conventions.NumberChars), 106 | Keywords = conventions.Keywords, 107 | KeywordsLookup = lookupify(conventions.Keywords), 108 | BinaryNumberChars = conventions.BinaryNumberChars, 109 | BinaryNumberCharsLookup = lookupify(conventions.BinaryNumberChars); 110 | BinaryNums = conventions.BinaryNums, 111 | HexadecimalNums = conventions.HexadecimalNums, 112 | HexNumberChars = conventions.HexNumberChars, 113 | HexNumberCharsLookup = lookupify(conventions.HexNumberChars), 114 | DecimalExponent = conventions.DecimalExponent, 115 | DecimalSeperators = conventions.DecimalSeperators, 116 | IdentChars = conventions.IdentChars, 117 | IdentCharsLookup = lookupify(conventions.IdentChars), 118 | 119 | EscapeSequences = conventions.EscapeSequences, 120 | NumericalEscapes = conventions.NumericalEscapes, 121 | EscapeZIgnoreNextWhitespace = conventions.EscapeZIgnoreNextWhitespace, 122 | HexEscapes = conventions.HexEscapes, 123 | UnicodeEscapes = conventions.UnicodeEscapes, 124 | 125 | SymbolChars = conventions.SymbolChars, 126 | SymbolCharsLookup = lookupify(conventions.SymbolChars), 127 | MaxSymbolLength = conventions.MaxSymbolLength, 128 | Symbols = conventions.Symbols, 129 | SymbolsLookup = lookupify(conventions.Symbols), 130 | 131 | StringStartLookup = lookupify({"\"", "\'"}), 132 | annotations = {}, 133 | }; 134 | 135 | setmetatable(tokenizer, self); 136 | self.__index = self; 137 | 138 | return tokenizer; 139 | end 140 | 141 | -- Reset State of Tokenizer to Tokenize another File 142 | function Tokenizer:reset() 143 | self.index = 0; 144 | self.length = 0; 145 | self.source = ""; 146 | self.annotations = {}; 147 | end 148 | 149 | -- Append String to this Tokenizer 150 | function Tokenizer:append(code) 151 | self.source = self.source .. code 152 | self.length = self.length + code:len(); 153 | end 154 | 155 | -- Function to peek the n'th char in the source of the tokenizer 156 | local function peek(self, n) 157 | n = n or 0; 158 | local i = self.index + n + 1; 159 | if i > self.length then 160 | return Tokenizer.EOF_CHAR 161 | end 162 | return self.source:sub(i, i); 163 | end 164 | 165 | -- Function to get the next char in the source 166 | local function get(self) 167 | local i = self.index + 1; 168 | if i > self.length then 169 | logger:error(generateError(self, "Unexpected end of Input")); 170 | end 171 | self.index = self.index + 1; 172 | return self.source:sub(i, i); 173 | end 174 | 175 | -- The same as get except it throws an Error if the char is not contained in charOrLookup 176 | local function expect(self, charOrLookup) 177 | if(type(charOrLookup) == "string") then 178 | charOrLookup = {[charOrLookup] = true}; 179 | end 180 | 181 | local char = peek(self); 182 | if charOrLookup[char] ~= true then 183 | local etb = unlookupify(charOrLookup); 184 | for i, v in ipairs(etb) do 185 | etb[i] = escape(v); 186 | end 187 | local errorMessage = "Unexpected char \"" .. escape(char) .. "\"! Expected one of \"" .. table.concat(etb, "\",\"") .. "\""; 188 | logger:error(generateError(self, errorMessage)); 189 | end 190 | 191 | self.index = self.index + 1; 192 | return char; 193 | end 194 | 195 | -- Returns wether the n'th char is in the lookup 196 | local function is(self, charOrLookup, n) 197 | local char = peek(self, n); 198 | if(type(charOrLookup) == "string") then 199 | return char == charOrLookup; 200 | end 201 | return charOrLookup[char]; 202 | end 203 | 204 | function Tokenizer:parseAnnotation() 205 | if is(self, Tokenizer.ANNOTATION_START_CHARS) then 206 | self.index = self.index + 1; 207 | local source = ""; 208 | while(is(self, Tokenizer.ANNOTATION_CHARS)) do 209 | source = source .. get(self); 210 | end 211 | if #source > 0 then 212 | self.annotations[string.lower(source)] = true; 213 | end 214 | return nil; 215 | end 216 | return get(self); 217 | end 218 | 219 | -- skip one or 0 Comments and return wether one was found 220 | function Tokenizer:skipComment() 221 | if(is(self, "-", 0) and is(self, "-", 1)) then 222 | self.index = self.index + 2; 223 | if(is(self, "[")) then 224 | self.index = self.index + 1; 225 | local eqCount = 0; 226 | while(is(self, "=")) do 227 | self.index = self.index + 1; 228 | eqCount = eqCount + 1; 229 | end 230 | if(is(self, "[")) then 231 | -- Multiline Comment 232 | -- Get all Chars to Closing bracket but also consider that the count of equal signs must be the same 233 | while true do 234 | if(self:parseAnnotation() == ']') then 235 | local eqCount2 = 0; 236 | while(is(self, "=")) do 237 | self.index = self.index + 1; 238 | eqCount2 = eqCount2 + 1; 239 | end 240 | if(is(self, "]")) then 241 | if(eqCount2 == eqCount) then 242 | self.index = self.index + 1; 243 | return true 244 | end 245 | end 246 | end 247 | end 248 | end 249 | end 250 | -- Single Line Comment 251 | -- Get all Chars to next Newline 252 | while(self.index < self.length and self:parseAnnotation() ~= "\n") do end 253 | return true; 254 | end 255 | return false; 256 | end 257 | 258 | -- skip All Whitespace and Comments to next Token 259 | function Tokenizer:skipWhitespaceAndComments() 260 | while self:skipComment() do end 261 | while is(self, Tokenizer.WHITESPACE_CHARS) do 262 | self.index = self.index + 1; 263 | while self:skipComment() do end 264 | end 265 | end 266 | 267 | local function int(self, chars, seperators) 268 | local source = ""; 269 | while true do 270 | if(is(self, chars)) then 271 | source = source .. get(self); 272 | elseif(is(self, seperators)) then 273 | self.index = self.index + 1; 274 | else 275 | break 276 | end 277 | end 278 | return source; 279 | end 280 | 281 | -- Lex the next token as a Number 282 | function Tokenizer:number() 283 | local startPos = self.index; 284 | local source = expect(self, setmetatable({["."] = true}, {__index = self.NumberCharsLookup})); 285 | 286 | if source == "0" then 287 | if self.BinaryNums and is(self, lookupify(self.BinaryNums)) then 288 | self.index = self.index + 1; 289 | source = int(self, self.BinaryNumberCharsLookup, lookupify(self.DecimalSeperators or {})); 290 | local value = tonumber(source, 2); 291 | return token(self, startPos, Tokenizer.TokenKind.Number, value); 292 | end 293 | 294 | if self.HexadecimalNums and is(self, lookupify(self.HexadecimalNums)) then 295 | self.index = self.index + 1; 296 | source = int(self, self.HexNumberCharsLookup, lookupify(self.DecimalSeperators or {})); 297 | local value = tonumber(source, 16); 298 | return token(self, startPos, Tokenizer.TokenKind.Number, value); 299 | end 300 | end 301 | 302 | if source == "." then 303 | source = source .. int(self, self.NumberCharsLookup, lookupify(self.DecimalSeperators or {})); 304 | else 305 | source = source .. int(self, self.NumberCharsLookup, lookupify(self.DecimalSeperators or {})); 306 | if(is(self, ".")) then 307 | source = source .. get(self) .. int(self, self.NumberCharsLookup, lookupify(self.DecimalSeperators or {})); 308 | end 309 | end 310 | 311 | if(self.DecimalExponent and is(self, lookupify(self.DecimalExponent))) then 312 | source = source .. get(self); 313 | if(is(self, lookupify({"+","-"}))) then 314 | source = source .. get(self); 315 | end 316 | local v = int(self, self.NumberCharsLookup, lookupify(self.DecimalSeperators or {})); 317 | if(v:len() < 1) then 318 | logger:error(generateError(self, "Expected a Valid Exponent!")); 319 | end 320 | source = source .. v; 321 | end 322 | 323 | local value = tonumber(source); 324 | return token(self, startPos, Tokenizer.TokenKind.Number, value); 325 | end 326 | 327 | -- Lex the Next Token as Identifier or Keyword 328 | function Tokenizer:ident() 329 | local startPos = self.index; 330 | local source = expect(self, self.IdentCharsLookup); 331 | while(is(self, self.IdentCharsLookup)) do 332 | source = source .. get(self); 333 | end 334 | if(self.KeywordsLookup[source]) then 335 | return token(self, startPos, Tokenizer.TokenKind.Keyword, source); 336 | end 337 | 338 | local tk = token(self, startPos, Tokenizer.TokenKind.Ident, source); 339 | 340 | if(string.sub(source, 1, string.len(config.IdentPrefix)) == config.IdentPrefix) then 341 | logger:warn(generateWarning(tk, string.format("identifiers should not start with \"%s\" as this may break the program", config.IdentPrefix))); 342 | end 343 | 344 | return tk; 345 | end 346 | 347 | function Tokenizer:singleLineString() 348 | local startPos = self.index; 349 | local startChar = expect(self, self.StringStartLookup); 350 | local value = ""; 351 | 352 | while(not is(self, startChar)) do 353 | local char = get(self); 354 | 355 | -- Single Line String may not contain Linebreaks except when they are escaped by \ 356 | if(char == '\n') then 357 | self.index = self.index - 1; 358 | logger:error(generateError(self, "Unterminated String")); 359 | end 360 | 361 | 362 | if(char == "\\") then 363 | char = get(self); 364 | 365 | local escape = self.EscapeSequences[char]; 366 | if(type(escape) == "string") then 367 | char = escape; 368 | 369 | elseif(self.NumericalEscapes and self.NumberCharsLookup[char]) then 370 | local numstr = char; 371 | 372 | if(is(self, self.NumberCharsLookup)) then 373 | char = get(self); 374 | numstr = numstr .. char; 375 | end 376 | 377 | if(is(self, self.NumberCharsLookup)) then 378 | char = get(self); 379 | numstr = numstr .. char; 380 | end 381 | 382 | char = string.char(tonumber(numstr)); 383 | 384 | elseif(self.UnicodeEscapes and char == "u") then 385 | expect(self, "{"); 386 | local num = ""; 387 | while (is(self, self.HexNumberCharsLookup)) do 388 | num = num .. get(self); 389 | end 390 | expect(self, "}"); 391 | char = util.utf8char(tonumber(num, 16)); 392 | elseif(self.HexEscapes and char == "x") then 393 | local hex = expect(self, self.HexNumberCharsLookup) .. expect(self, self.HexNumberCharsLookup); 394 | char = string.char(tonumber(hex, 16)); 395 | elseif(self.EscapeZIgnoreNextWhitespace and char == "z") then 396 | char = ""; 397 | while(is(self, Tokenizer.WHITESPACE_CHARS)) do 398 | self.index = self.index + 1; 399 | end 400 | end 401 | end 402 | 403 | value = value .. char; 404 | end 405 | 406 | expect(self, startChar); 407 | 408 | return token(self, startPos, Tokenizer.TokenKind.String, value) 409 | end 410 | 411 | function Tokenizer:multiLineString() 412 | local startPos = self.index; 413 | if(is(self, "[")) then 414 | self.index = self.index + 1; 415 | local eqCount = 0; 416 | while(is(self, "=")) do 417 | self.index = self.index + 1; 418 | eqCount = eqCount + 1; 419 | end 420 | if(is(self, "[")) then 421 | -- Multiline String 422 | -- Parse String to Closing bracket but also consider that the count of equal signs must be the same 423 | 424 | -- Skip Leading newline if existing 425 | self.index = self.index + 1; 426 | if(is(self, "\n")) then 427 | self.index = self.index + 1; 428 | end 429 | 430 | local value = ""; 431 | while true do 432 | local char = get(self); 433 | if(char == ']') then 434 | local eqCount2 = 0; 435 | while(is(self, "=")) do 436 | char = char .. get(self); 437 | eqCount2 = eqCount2 + 1; 438 | end 439 | if(is(self, "]")) then 440 | if(eqCount2 == eqCount) then 441 | self.index = self.index + 1; 442 | return token(self, startPos, Tokenizer.TokenKind.String, value), true 443 | end 444 | end 445 | end 446 | value = value .. char; 447 | end 448 | end 449 | end 450 | self.index = startPos; 451 | return nil, false -- There was not an actual multiline string at the given Position 452 | end 453 | 454 | function Tokenizer:symbol() 455 | local startPos = self.index; 456 | for len = self.MaxSymbolLength, 1, -1 do 457 | local str = self.source:sub(self.index + 1, self.index + len); 458 | if self.SymbolsLookup[str] then 459 | self.index = self.index + len; 460 | return token(self, startPos, Tokenizer.TokenKind.Symbol, str); 461 | end 462 | end 463 | logger:error(generateError(self, "Unknown Symbol")); 464 | end 465 | 466 | 467 | -- get the Next token 468 | function Tokenizer:next() 469 | -- Skip All Whitespace before the token 470 | self:skipWhitespaceAndComments(); 471 | 472 | local startPos = self.index; 473 | if startPos >= self.length then 474 | return token(self, startPos, Tokenizer.TokenKind.Eof); 475 | end 476 | 477 | -- Numbers 478 | if(is(self, self.NumberCharsLookup)) then 479 | return self:number(); 480 | end 481 | 482 | -- Identifiers and Keywords 483 | if(is(self, self.IdentCharsLookup)) then 484 | return self:ident(); 485 | end 486 | 487 | -- Singleline String Literals 488 | if(is(self, self.StringStartLookup)) then 489 | return self:singleLineString(); 490 | end 491 | 492 | -- Multiline String Literals 493 | if(is(self, "[", 0)) then 494 | -- The isString variable is due to the fact that "[" could also be a symbol for indexing 495 | local value, isString = self:multiLineString(); 496 | if isString then 497 | return value; 498 | end 499 | end 500 | 501 | -- Number starting with dot 502 | if(is(self, ".") and is(self, self.NumberCharsLookup, 1)) then 503 | return self:number(); 504 | end 505 | 506 | -- Symbols 507 | if(is(self, self.SymbolCharsLookup)) then 508 | return self:symbol(); 509 | end 510 | 511 | 512 | logger:error(generateError(self, "Unexpected char \"" .. escape(peek(self)) .. "\"!")); 513 | end 514 | 515 | function Tokenizer:scanAll() 516 | local tb = {}; 517 | repeat 518 | local token = self:next(); 519 | table.insert(tb, token); 520 | until token.kind == Tokenizer.TokenKind.Eof 521 | return tb 522 | end 523 | 524 | return Tokenizer -------------------------------------------------------------------------------- /lua/prometheus/util.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- util.lua 4 | -- This file Provides some utility functions 5 | 6 | local logger = require("logger"); 7 | local bit32 = require("prometheus.bit").bit32; 8 | 9 | local function lookupify(tb) 10 | local tb2 = {}; 11 | for _, v in ipairs(tb) do 12 | tb2[v] = true 13 | end 14 | return tb2 15 | end 16 | 17 | local function unlookupify(tb) 18 | local tb2 = {}; 19 | for v, _ in pairs(tb) do 20 | table.insert(tb2, v); 21 | end 22 | return tb2; 23 | end 24 | 25 | local function escape(str) 26 | return str:gsub(".", function(char) 27 | if char:match('[^ -~\n\t\a\b\v\r\"\']') then -- Check if non Printable Ascii Character 28 | return string.format("\\%03d", string.byte(char)) 29 | end 30 | if(char == "\\") then 31 | return "\\\\"; 32 | end 33 | if(char == "\n") then 34 | return "\\n"; 35 | end 36 | if(char == "\r") then 37 | return "\\r"; 38 | end 39 | if(char == "\t") then 40 | return "\\t"; 41 | end 42 | if(char == "\a") then 43 | return "\\a"; 44 | end 45 | if(char == "\b") then 46 | return "\\b"; 47 | end 48 | if(char == "\v") then 49 | return "\\v"; 50 | end 51 | if(char == "\"") then 52 | return "\\\""; 53 | end 54 | if(char == "\'") then 55 | return "\\\'"; 56 | end 57 | return char; 58 | end) 59 | end 60 | 61 | local function chararray(str) 62 | local tb = {}; 63 | for i = 1, str:len(), 1 do 64 | table.insert(tb, str:sub(i, i)); 65 | end 66 | return tb; 67 | end 68 | 69 | local function keys(tb) 70 | local keyset={} 71 | local n=0 72 | for k,v in pairs(tb) do 73 | n=n+1 74 | keyset[n]=k 75 | end 76 | return keyset 77 | end 78 | 79 | local utf8char; 80 | do 81 | local string_char = string.char 82 | function utf8char(cp) 83 | if cp < 128 then 84 | return string_char(cp) 85 | end 86 | local suffix = cp % 64 87 | local c4 = 128 + suffix 88 | cp = (cp - suffix) / 64 89 | if cp < 32 then 90 | return string_char(192 + cp, c4) 91 | end 92 | suffix = cp % 64 93 | local c3 = 128 + suffix 94 | cp = (cp - suffix) / 64 95 | if cp < 16 then 96 | return string_char(224 + cp, c3, c4) 97 | end 98 | suffix = cp % 64 99 | cp = (cp - suffix) / 64 100 | return string_char(240 + cp, 128 + suffix, c3, c4) 101 | end 102 | end 103 | 104 | local function shuffle(tb) 105 | for i = #tb, 2, -1 do 106 | local j = math.random(i) 107 | tb[i], tb[j] = tb[j], tb[i] 108 | end 109 | return tb 110 | end 111 | 112 | local function readDouble(bytes) 113 | local sign = 1 114 | local mantissa = bytes[2] % 2^4 115 | for i = 3, 8 do 116 | mantissa = mantissa * 256 + bytes[i] 117 | end 118 | if bytes[1] > 127 then sign = -1 end 119 | local exponent = (bytes[1] % 128) * 2^4 + math.floor(bytes[2] / 2^4) 120 | 121 | if exponent == 0 then 122 | return 0 123 | end 124 | mantissa = (math.ldexp(mantissa, -52) + 1) * sign 125 | return math.ldexp(mantissa, exponent - 1023) 126 | end 127 | 128 | local function writeDouble(num) 129 | local bytes = {0,0,0,0, 0,0,0,0} 130 | if num == 0 then 131 | return bytes 132 | end 133 | local anum = math.abs(num) 134 | 135 | local mantissa, exponent = math.frexp(anum) 136 | exponent = exponent - 1 137 | mantissa = mantissa * 2 - 1 138 | local sign = num ~= anum and 128 or 0 139 | exponent = exponent + 1023 140 | 141 | bytes[1] = sign + math.floor(exponent / 2^4) 142 | mantissa = mantissa * 2^4 143 | local currentmantissa = math.floor(mantissa) 144 | mantissa = mantissa - currentmantissa 145 | bytes[2] = (exponent % 2^4) * 2^4 + currentmantissa 146 | for i= 3, 8 do 147 | mantissa = mantissa * 2^8 148 | currentmantissa = math.floor(mantissa) 149 | mantissa = mantissa - currentmantissa 150 | bytes[i] = currentmantissa 151 | end 152 | return bytes 153 | end 154 | 155 | local function writeU16(u16) 156 | if (u16 < 0 or u16 > 65535) then 157 | logger:error(string.format("u16 out of bounds: %d", u16)); 158 | end 159 | local lower = bit32.band(u16, 255); 160 | local upper = bit32.rshift(u16, 8); 161 | return {lower, upper} 162 | end 163 | 164 | local function readU16(arr) 165 | return bit32.bor(arr[1], bit32.lshift(arr[2], 8)); 166 | end 167 | 168 | local function writeU24(u24) 169 | if(u24 < 0 or u24 > 16777215) then 170 | logger:error(string.format("u24 out of bounds: %d", u24)); 171 | end 172 | 173 | local arr = {}; 174 | for i = 0, 2 do 175 | arr[i + 1] = bit32.band(bit32.rshift(u24, 8 * i), 255); 176 | end 177 | return arr; 178 | end 179 | 180 | local function readU24(arr) 181 | local val = 0; 182 | 183 | for i = 0, 2 do 184 | val = bit32.bor(val, bit32.lshift(arr[i + 1], 8 * i)); 185 | end 186 | 187 | return val; 188 | end 189 | 190 | local function writeU32(u32) 191 | if(u32 < 0 or u32 > 4294967295) then 192 | logger:error(string.format("u32 out of bounds: %d", u32)); 193 | end 194 | 195 | local arr = {}; 196 | for i = 0, 3 do 197 | arr[i + 1] = bit32.band(bit32.rshift(u32, 8 * i), 255); 198 | end 199 | return arr; 200 | end 201 | 202 | local function readU32(arr) 203 | local val = 0; 204 | 205 | for i = 0, 3 do 206 | val = bit32.bor(val, bit32.lshift(arr[i + 1], 8 * i)); 207 | end 208 | 209 | return val; 210 | end 211 | 212 | local function bytesToString(arr) 213 | local str = ""; 214 | for i = 1, #arr do 215 | str = str .. string.char(arr[i]); 216 | end 217 | return str; 218 | end 219 | 220 | local function isNaN(n) 221 | return type(n) == "number" and n ~= n; 222 | end 223 | 224 | local function isInt(n) 225 | return math.floor(n) == n; 226 | end 227 | 228 | local function isU32(n) 229 | return n >= 0 and n <= 4294967295 and isInt(n); 230 | end 231 | 232 | local function toBits(num) 233 | -- returns a table of bits, least significant first. 234 | local t={} -- will contain the bits 235 | local rest; 236 | while num>0 do 237 | rest=math.fmod(num,2) 238 | t[#t+1]=rest 239 | num=(num-rest)/2 240 | end 241 | return t 242 | end 243 | 244 | 245 | local function readonly(obj) 246 | local r = newproxy(true); 247 | getmetatable(r).__index = obj; 248 | return r; 249 | end 250 | 251 | return { 252 | lookupify = lookupify, 253 | unlookupify = unlookupify, 254 | escape = escape, 255 | chararray = chararray, 256 | keys = keys, 257 | shuffle = shuffle, 258 | readDouble = readDouble, 259 | writeDouble = writeDouble, 260 | readU16 = readU16, 261 | writeU16 = writeU16, 262 | readU32 = readU32, 263 | writeU32 = writeU32, 264 | readU24 = readU24, 265 | writeU24 = writeU24, 266 | isNaN = isNaN, 267 | isU32 = isU32, 268 | isInt = isInt, 269 | utf8char = utf8char, 270 | toBits = toBits, 271 | bytesToString = bytesToString, 272 | readonly = readonly, 273 | } -------------------------------------------------------------------------------- /lua/prometheus/visitast.lua: -------------------------------------------------------------------------------- 1 | -- This Script is Part of the Prometheus Obfuscator by Levno_710 2 | -- 3 | -- util.lua 4 | -- This file Provides a Utility function for visiting each node of an ast 5 | 6 | local Ast = require("prometheus.ast"); 7 | local util = require("prometheus.util"); 8 | 9 | local AstKind = Ast.AstKind; 10 | local lookupify = util.lookupify; 11 | 12 | local visitAst, visitBlock, visitStatement, visitExpression; 13 | 14 | function visitAst(ast, previsit, postvisit, data) 15 | ast.isAst = true; 16 | data = data or {}; 17 | data.scopeStack = {}; 18 | data.functionData = { 19 | depth = 0; 20 | scope = ast.body.scope; 21 | node = ast; 22 | }; 23 | data.scope = ast.globalScope; 24 | data.globalScope = ast.globalScope; 25 | if(type(previsit) == "function") then 26 | local node, skip = previsit(ast, data); 27 | ast = node or ast; 28 | if skip then 29 | return ast; 30 | end 31 | end 32 | 33 | -- Is Function Block because global scope is treated like a Function 34 | visitBlock(ast.body, previsit, postvisit, data, true); 35 | 36 | if(type(postvisit) == "function") then 37 | ast = postvisit(ast, data) or ast; 38 | end 39 | return ast; 40 | end 41 | 42 | local compundStats = lookupify{ 43 | AstKind.CompoundAddStatement, 44 | AstKind.CompoundSubStatement, 45 | AstKind.CompoundMulStatement, 46 | AstKind.CompoundDivStatement, 47 | AstKind.CompoundModStatement, 48 | AstKind.CompoundPowStatement, 49 | AstKind.CompoundConcatStatement, 50 | } 51 | 52 | function visitBlock(block, previsit, postvisit, data, isFunctionBlock) 53 | block.isBlock = true; 54 | block.isFunctionBlock = isFunctionBlock or false; 55 | data.scope = block.scope; 56 | local parentBlockData = data.blockData; 57 | data.blockData = {}; 58 | table.insert(data.scopeStack, block.scope); 59 | if(type(previsit) == "function") then 60 | local node, skip = previsit(block, data); 61 | block = node or block; 62 | if skip then 63 | data.scope = table.remove(data.scopeStack); 64 | return block 65 | end 66 | end 67 | 68 | local i = 1; 69 | while i <= #block.statements do 70 | local statement = table.remove(block.statements, i); 71 | i = i - 1; 72 | local returnedStatements = {visitStatement(statement, previsit, postvisit, data)}; 73 | for j, statement in ipairs(returnedStatements) do 74 | i = i + 1; 75 | table.insert(block.statements, i, statement); 76 | end 77 | i = i + 1; 78 | end 79 | 80 | if(type(postvisit) == "function") then 81 | block = postvisit(block, data) or block; 82 | end 83 | data.scope = table.remove(data.scopeStack); 84 | data.blockData = parentBlockData; 85 | return block; 86 | end 87 | 88 | function visitStatement(statement, previsit, postvisit, data) 89 | statement.isStatement = true; 90 | if(type(previsit) == "function") then 91 | local node, skip = previsit(statement, data); 92 | statement = node or statement; 93 | if skip then 94 | return statement; 95 | end 96 | end 97 | 98 | -- Visit Child Nodes of Statement 99 | if(statement.kind == AstKind.ReturnStatement) then 100 | for i, expression in ipairs(statement.args) do 101 | statement.args[i] = visitExpression(expression, previsit, postvisit, data); 102 | end 103 | elseif(statement.kind == AstKind.PassSelfFunctionCallStatement or statement.kind == AstKind.FunctionCallStatement) then 104 | statement.base = visitExpression(statement.base, previsit, postvisit, data); 105 | for i, expression in ipairs(statement.args) do 106 | statement.args[i] = visitExpression(expression, previsit, postvisit, data); 107 | end 108 | elseif(statement.kind == AstKind.AssignmentStatement) then 109 | for i, primaryExpr in ipairs(statement.lhs) do 110 | statement.lhs[i] = visitExpression(primaryExpr, previsit, postvisit, data); 111 | end 112 | for i, expression in ipairs(statement.rhs) do 113 | statement.rhs[i] = visitExpression(expression, previsit, postvisit, data); 114 | end 115 | elseif(statement.kind == AstKind.FunctionDeclaration or statement.kind == AstKind.LocalFunctionDeclaration) then 116 | local parentFunctionData = data.functionData; 117 | data.functionData = { 118 | depth = parentFunctionData.depth + 1; 119 | scope = statement.body.scope; 120 | node = statement; 121 | }; 122 | statement.body = visitBlock(statement.body, previsit, postvisit, data, true); 123 | data.functionData = parentFunctionData; 124 | elseif(statement.kind == AstKind.DoStatement) then 125 | statement.body = visitBlock(statement.body, previsit, postvisit, data, false); 126 | elseif(statement.kind == AstKind.WhileStatement) then 127 | statement.condition = visitExpression(statement.condition, previsit, postvisit, data); 128 | statement.body = visitBlock(statement.body, previsit, postvisit, data, false); 129 | elseif(statement.kind == AstKind.RepeatStatement) then 130 | statement.body = visitBlock(statement.body, previsit, postvisit, data); 131 | statement.condition = visitExpression(statement.condition, previsit, postvisit, data); 132 | elseif(statement.kind == AstKind.ForStatement) then 133 | statement.initialValue = visitExpression(statement.initialValue, previsit, postvisit, data); 134 | statement.finalValue = visitExpression(statement.finalValue, previsit, postvisit, data); 135 | statement.incrementBy = visitExpression(statement.incrementBy, previsit, postvisit, data); 136 | statement.body = visitBlock(statement.body, previsit, postvisit, data, false); 137 | elseif(statement.kind == AstKind.ForInStatement) then 138 | for i, expression in ipairs(statement.expressions) do 139 | statement.expressions[i] = visitExpression(expression, previsit, postvisit, data); 140 | end 141 | visitBlock(statement.body, previsit, postvisit, data, false); 142 | elseif(statement.kind == AstKind.IfStatement) then 143 | statement.condition = visitExpression(statement.condition, previsit, postvisit, data); 144 | statement.body = visitBlock(statement.body, previsit, postvisit, data, false); 145 | for i, eif in ipairs(statement.elseifs) do 146 | eif.condition = visitExpression(eif.condition, previsit, postvisit, data); 147 | eif.body = visitBlock(eif.body, previsit, postvisit, data, false); 148 | end 149 | if(statement.elsebody) then 150 | statement.elsebody = visitBlock(statement.elsebody, previsit, postvisit, data, false); 151 | end 152 | elseif(statement.kind == AstKind.LocalVariableDeclaration) then 153 | for i, expression in ipairs(statement.expressions) do 154 | statement.expressions[i] = visitExpression(expression, previsit, postvisit, data); 155 | end 156 | elseif compundStats[statement.kind] then 157 | statement.lhs = visitExpression(statement.lhs, previsit, postvisit, data); 158 | statement.rhs = visitExpression(statement.rhs, previsit, postvisit, data); 159 | end 160 | 161 | if(type(postvisit) == "function") then 162 | local statements = {postvisit(statement, data)}; 163 | if #statements > 0 then 164 | return unpack(statements); 165 | end 166 | end 167 | 168 | return statement; 169 | end 170 | 171 | local binaryExpressions = lookupify{ 172 | AstKind.OrExpression, 173 | AstKind.AndExpression, 174 | AstKind.LessThanExpression, 175 | AstKind.GreaterThanExpression, 176 | AstKind.LessThanOrEqualsExpression, 177 | AstKind.GreaterThanOrEqualsExpression, 178 | AstKind.NotEqualsExpression, 179 | AstKind.EqualsExpression, 180 | AstKind.StrCatExpression, 181 | AstKind.AddExpression, 182 | AstKind.SubExpression, 183 | AstKind.MulExpression, 184 | AstKind.DivExpression, 185 | AstKind.ModExpression, 186 | AstKind.PowExpression, 187 | } 188 | function visitExpression(expression, previsit, postvisit, data) 189 | expression.isExpression = true; 190 | if(type(previsit) == "function") then 191 | local node, skip = previsit(expression, data); 192 | expression = node or expression; 193 | if skip then 194 | return expression; 195 | end 196 | end 197 | 198 | if(binaryExpressions[expression.kind]) then 199 | expression.lhs = visitExpression(expression.lhs, previsit, postvisit, data); 200 | expression.rhs = visitExpression(expression.rhs, previsit, postvisit, data); 201 | end 202 | 203 | if(expression.kind == AstKind.NotExpression or expression.kind == AstKind.NegateExpression or expression.kind == AstKind.LenExpression) then 204 | expression.rhs = visitExpression(expression.rhs, previsit, postvisit, data); 205 | end 206 | 207 | if(expression.kind == AstKind.PassSelfFunctionCallExpression or expression.kind == AstKind.FunctionCallExpression) then 208 | expression.base = visitExpression(expression.base, previsit, postvisit, data); 209 | for i, arg in ipairs(expression.args) do 210 | expression.args[i] = visitExpression(arg, previsit, postvisit, data); 211 | end 212 | end 213 | 214 | if(expression.kind == AstKind.FunctionLiteralExpression) then 215 | local parentFunctionData = data.functionData; 216 | data.functionData = { 217 | depth = parentFunctionData.depth + 1; 218 | scope = expression.body.scope; 219 | node = expression; 220 | }; 221 | expression.body = visitBlock(expression.body, previsit, postvisit, data, true); 222 | data.functionData = parentFunctionData; 223 | end 224 | 225 | if(expression.kind == AstKind.TableConstructorExpression) then 226 | for i, entry in ipairs(expression.entries) do 227 | if entry.kind == AstKind.KeyedTableEntry then 228 | entry.key = visitExpression(entry.key, previsit, postvisit, data); 229 | end 230 | entry.value = visitExpression(entry.value, previsit, postvisit, data); 231 | end 232 | end 233 | 234 | if(expression.kind == AstKind.IndexExpression or expression.kind == AstKind.AssignmentIndexing) then 235 | expression.base = visitExpression(expression.base, previsit, postvisit, data); 236 | expression.index = visitExpression(expression.index, previsit, postvisit, data); 237 | end 238 | 239 | if(type(postvisit) == "function") then 240 | expression = postvisit(expression, data) or expression; 241 | end 242 | return expression; 243 | end 244 | 245 | return visitAst; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prometheus-discord-bot", 3 | "version": "0.2.0", 4 | "description": "The Discord Bot for the Prometheus Obfuscator", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "node esbuild.js", 8 | "start": "node index.js", 9 | "dev": "npm run build && npm run start" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/levno-710/Prometheus-dicord-bot.git" 14 | }, 15 | "keywords": [ 16 | "lua", 17 | "obfuscator" 18 | ], 19 | "author": "Elias Oelschner", 20 | "license": "ISC", 21 | "bugs": { 22 | "url": "https://github.com/levno-710/Prometheus-dicord-bot/issues" 23 | }, 24 | "homepage": "https://github.com/levno-710/Prometheus-dicord-bot#readme", 25 | "devDependencies": { 26 | "@types/node": "^17.0.31", 27 | "@typescript-eslint/eslint-plugin": "^5.22.0", 28 | "@typescript-eslint/parser": "^5.22.0", 29 | "esbuild": "^0.14.38", 30 | "esbuild-node-externals": "^1.4.1", 31 | "eslint": "^8.14.0", 32 | "eslint-config-airbnb-base": "^15.0.0", 33 | "eslint-plugin-import": "^2.26.0", 34 | "typescript": "^4.6.4" 35 | }, 36 | "dependencies": { 37 | "@colors/colors": "^1.5.0", 38 | "@types/tmp": "^0.2.3", 39 | "@types/uuid": "^8.3.4", 40 | "axios": "^0.27.2", 41 | "discord.js": "^13.6.0", 42 | "dotenv": "^16.0.0", 43 | "tmp": "^0.2.1", 44 | "uuid": "^8.3.2" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | import { 3 | Client, Intents, MessageButton, MessageActionRow, Message, MessageAttachment, 4 | } from 'discord.js'; 5 | import '@colors/colors'; 6 | import { v4 as uuid } from 'uuid'; 7 | import tmp from 'tmp'; 8 | import Axios from 'axios'; 9 | import fs from 'fs'; 10 | import logger from './logger'; 11 | import obfuscate from './obfuscate'; 12 | 13 | // Load token from .env 14 | const token = process.env.DISCORD_TOKEN; 15 | const MAX_SIZE = 40000; // 40kB max size 16 | 17 | logger.log('Bot is starting ...'); 18 | 19 | // Create Discord Bot Client 20 | const client = new Client({ 21 | intents: [ 22 | Intents.FLAGS.DIRECT_MESSAGES, 23 | Intents.FLAGS.DIRECT_MESSAGE_REACTIONS, 24 | ], 25 | partials: ['CHANNEL'], 26 | }); 27 | 28 | // Login using token 29 | client.login(token); 30 | 31 | client.once('ready', () => { // When the client is ready 32 | logger.log(`Logged in as ${(client.user?.tag || 'Unknown').cyan}`); 33 | }); 34 | 35 | interface ButtonInfo { 36 | url: string; 37 | preset: string; 38 | tag: string; 39 | message: Message, 40 | buttonIds: string[], 41 | } 42 | 43 | const buttonInfos = new Map(); 44 | 45 | client.on('interactionCreate', async (interaction) => { 46 | if (!interaction.isButton()) { 47 | return; 48 | } 49 | 50 | const buttonInfo = buttonInfos.get(interaction.customId); 51 | if (!buttonInfo) { 52 | interaction.update({ 53 | embeds: [ 54 | { 55 | title: 'Prometheus Obfuscator', 56 | description: 'Something went wrong. Please try again.', 57 | color: '#ff8800', 58 | }, 59 | ], 60 | components: [], 61 | }); 62 | return; 63 | } 64 | 65 | buttonInfo.buttonIds.forEach((id) => { 66 | buttonInfos.delete(id); 67 | }); 68 | 69 | const { message } = buttonInfo; 70 | interaction.update({}); 71 | 72 | // Log obfuscations 73 | console.log(`${(buttonInfo.tag || 'Unknown User').cyan} -> ${buttonInfo.url} @ ${buttonInfo.preset}`); 74 | 75 | // Update Message 76 | await message.edit({ 77 | embeds: [ 78 | { 79 | title: 'Prometheus Obfuscator', 80 | description: `🔄 Uploading your file ...\n🔄 Obfuscating your file using ${buttonInfo?.preset} Preset ...\n🔄 Downloading your file ...`, 81 | color: '#ff8800', 82 | }, 83 | ], 84 | components: [], 85 | }); 86 | 87 | // Download file 88 | const tmpFile = tmp.fileSync({ postfix: '.lua' }); 89 | 90 | const response = await Axios({ 91 | method: 'GET', 92 | url: buttonInfo.url, 93 | responseType: 'stream', 94 | }); 95 | 96 | if (response.headers['content-length'] && Number.parseInt(response.headers['content-length'], 10) > MAX_SIZE) { 97 | message.edit({ 98 | embeds: [ 99 | { 100 | title: 'Prometheus Obfuscator', 101 | description: 'The max filesize for the obfuscator bot is 40KB.\nIf you want to obfuscate larger files, please use the standalone version.', 102 | color: '#ff0000', 103 | }, 104 | ], 105 | components: [], 106 | }); 107 | return; 108 | } 109 | 110 | response.data.pipe(fs.createWriteStream(tmpFile.name)); 111 | 112 | // Wait for download to complete 113 | try { 114 | await new Promise((resolve, reject) => { 115 | response.data.on('end', () => { 116 | resolve(); 117 | }); 118 | 119 | response.data.on('error', () => { 120 | reject(); 121 | }); 122 | }); 123 | } catch (e) { 124 | message.edit({ 125 | embeds: [ 126 | { 127 | title: 'Prometheus Obfuscator', 128 | description: 'Upload failed! Please try again.', 129 | color: '#ff0000', 130 | }, 131 | ], 132 | components: [], 133 | }); 134 | return; 135 | } 136 | 137 | // Update Message 138 | await message.edit({ 139 | embeds: [ 140 | { 141 | title: 'Prometheus Obfuscator', 142 | description: `✅ Uploading your file ...\n🔄 Obfuscating your file using ${buttonInfo?.preset} Preset ...\n🔄 Downloading your file ...`, 143 | color: '#ff8800', 144 | }, 145 | ], 146 | components: [], 147 | }); 148 | 149 | let outFile; 150 | try { 151 | outFile = await obfuscate(tmpFile.name, buttonInfo.preset); 152 | } catch (e) { 153 | message.edit({ 154 | embeds: [ 155 | { 156 | title: 'Prometheus Obfuscator', 157 | description: `Obfuscation failed:\n${e}`, 158 | color: '#ff0000', 159 | }, 160 | ], 161 | components: [], 162 | }); 163 | return; 164 | } 165 | 166 | // Update Message 167 | await message.edit({ 168 | embeds: [ 169 | { 170 | title: 'Prometheus Obfuscator', 171 | description: `✅ Uploading your file ...\n✅ Obfuscating your file using ${buttonInfo?.preset} Preset ...\n🔄 Downloading your file ...`, 172 | color: '#ff8800', 173 | }, 174 | ], 175 | components: [], 176 | }); 177 | 178 | // Update Message 179 | const attachment = new MessageAttachment(outFile.name, 'obfuscated.lua'); 180 | const fileMessage = await message.channel.send({ 181 | files: [attachment], 182 | }); 183 | const url = fileMessage.attachments.first()?.url; 184 | if (!url) { 185 | message.edit({ 186 | embeds: [ 187 | { 188 | title: 'Prometheus Obfuscator', 189 | description: 'Download failed! Please try again.', 190 | color: '#ff0000', 191 | }, 192 | ], 193 | components: [], 194 | }); 195 | return; 196 | } 197 | fileMessage.delete(); 198 | 199 | await message.edit({ 200 | embeds: [ 201 | { 202 | title: 'Prometheus Obfuscator', 203 | description: `✅ Uploading your file ...\n✅ Obfuscating your file using ${buttonInfo?.preset} Preset ...\n✅ Downloading your file ...\n\n🔗 [Download](${url})`, 204 | color: '#00ff00', 205 | }, 206 | ], 207 | components: [], 208 | }); 209 | 210 | // Delete Temp files 211 | outFile.removeCallback(); 212 | tmpFile.removeCallback(); 213 | }); 214 | 215 | client.on('messageCreate', async (message) => { 216 | if (!message.author.bot) { 217 | // Handle file upload 218 | const file = message.attachments.first()?.url; 219 | if (!file) { 220 | message.reply('Please upload a file!'); 221 | return; 222 | } 223 | 224 | const buttonIds = new Array(3).fill(0).map(() => uuid()); 225 | 226 | const row = new MessageActionRow() 227 | .addComponents( 228 | new MessageButton() 229 | .setCustomId(buttonIds[0]) 230 | .setLabel('Weak') 231 | .setStyle('SUCCESS'), 232 | new MessageButton() 233 | .setCustomId(buttonIds[1]) 234 | .setLabel('Medium') 235 | .setStyle('PRIMARY'), 236 | new MessageButton() 237 | .setCustomId(buttonIds[2]) 238 | .setLabel('Strong') 239 | .setStyle('DANGER'), 240 | ); 241 | 242 | const content = 'For much more options, please use the standalone version.\n\nSelect the Preset to use:'; 243 | 244 | const msg = await message.reply({ 245 | embeds: [{ 246 | title: 'Prometheus Obfuscator', 247 | color: '#ff8800', 248 | description: content, 249 | }], 250 | components: [row], 251 | }); 252 | 253 | buttonInfos.set(buttonIds[0], { 254 | url: file, 255 | preset: 'Weak', 256 | tag: message.author.tag, 257 | message: msg, 258 | buttonIds, 259 | }); 260 | buttonInfos.set(buttonIds[1], { 261 | url: file, 262 | preset: 'Medium', 263 | tag: message.author.tag, 264 | message: msg, 265 | buttonIds, 266 | }); 267 | buttonInfos.set(buttonIds[2], { 268 | url: file, 269 | preset: 'Strong', 270 | tag: message.author.tag, 271 | message: msg, 272 | buttonIds, 273 | }); 274 | } 275 | }); 276 | -------------------------------------------------------------------------------- /src/logger.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | log: (...message: unknown[]) => { 3 | console.log('[PROMETHEUS]'.magenta, ...message); 4 | }, 5 | warn: (...message: unknown[]) => { 6 | console.warn('[PROMETHEUS]'.yellow, ...message); 7 | }, 8 | error: (...message: unknown[]) => { 9 | console.error('[PROMETHEUS]'.red, ...message); 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /src/obfuscate.ts: -------------------------------------------------------------------------------- 1 | import tmp from 'tmp'; 2 | import { spawn } from 'child_process'; 3 | import logger from './logger'; 4 | 5 | /** 6 | * Obfuscate a Lua file using Prometheus Obfuscator 7 | * @param filename the path to the lua file 8 | * @returns the path to the obfuscated file 9 | */ 10 | export default function obfuscate(filename: string, preset: string): Promise { 11 | return new Promise((resolve, reject) => { 12 | const outFile = tmp.fileSync(); 13 | const child = spawn('lua', ['./lua/cli.lua', '--LuaU', '--preset', preset, filename, '--out', outFile.name]); 14 | child.stderr.on('data', (data) => { 15 | logger.error(data.toString()); 16 | reject(data.toString()); 17 | }); 18 | child.on('close', () => { 19 | resolve(outFile); 20 | }); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | // "outDir": "./", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | 43 | /* Module Resolution Options */ 44 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 45 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 46 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 47 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 48 | // "typeRoots": [], /* List of folders to include type definitions from. */ 49 | // "types": [], /* Type declaration files to be included in compilation. */ 50 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 51 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 52 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 53 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 54 | 55 | /* Source Map Options */ 56 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 59 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 60 | 61 | /* Experimental Options */ 62 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 63 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 64 | 65 | /* Advanced Options */ 66 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 67 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 68 | } 69 | } 70 | --------------------------------------------------------------------------------