Showing preview only (424K chars total). Download the full file or copy to clipboard to get everything.
Repository: prometheus-lua/Prometheus
Branch: master
Commit: 9d90158b54f4
Files: 124
Total size: 391.9 KB
Directory structure:
gitextract_h0mah7x0/
├── .editorconfig
├── .gitattributes
├── .gitbook.yaml
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ └── bug_report.md
│ └── workflows/
│ ├── Build.yml
│ └── Test.yml
├── .gitignore
├── LICENSE
├── benchmark.lua
├── cli.lua
├── doc/
│ ├── README.md
│ ├── SUMMARY.md
│ ├── advanced/
│ │ └── using-prometheus-in-your-lua-application.md
│ ├── getting-started/
│ │ ├── command-line-options.md
│ │ ├── installation.md
│ │ ├── obfuscating-your-first-script.md
│ │ ├── presets.md
│ │ ├── the-config-object.md
│ │ └── writing-a-custom-config-file.md
│ └── steps/
│ ├── anti-tamper.md
│ ├── constantarray.md
│ ├── encryptstrings.md
│ ├── proxifylocals.md
│ ├── splitstrings.md
│ ├── vmify.md
│ └── wrapinfunction.md
├── prometheus-main.lua
├── readme.md
├── src/
│ ├── cli.lua
│ ├── colors.lua
│ ├── highlightlua.lua
│ ├── logger.lua
│ ├── presets.lua
│ ├── prometheus/
│ │ ├── ast.lua
│ │ ├── compiler/
│ │ │ ├── block.lua
│ │ │ ├── compile_core.lua
│ │ │ ├── compile_top.lua
│ │ │ ├── compiler.lua
│ │ │ ├── constants.lua
│ │ │ ├── emit.lua
│ │ │ ├── expressions/
│ │ │ │ ├── and.lua
│ │ │ │ ├── binary.lua
│ │ │ │ ├── boolean.lua
│ │ │ │ ├── function_call.lua
│ │ │ │ ├── function_literal.lua
│ │ │ │ ├── index.lua
│ │ │ │ ├── len.lua
│ │ │ │ ├── negate.lua
│ │ │ │ ├── nil.lua
│ │ │ │ ├── not.lua
│ │ │ │ ├── number.lua
│ │ │ │ ├── or.lua
│ │ │ │ ├── pass_self_function_call.lua
│ │ │ │ ├── string.lua
│ │ │ │ ├── table_constructor.lua
│ │ │ │ ├── vararg.lua
│ │ │ │ └── variable.lua
│ │ │ ├── expressions.lua
│ │ │ ├── register.lua
│ │ │ ├── statements/
│ │ │ │ ├── assignment.lua
│ │ │ │ ├── break_statement.lua
│ │ │ │ ├── compound.lua
│ │ │ │ ├── continue_statement.lua
│ │ │ │ ├── do_statement.lua
│ │ │ │ ├── for_in_statement.lua
│ │ │ │ ├── for_statement.lua
│ │ │ │ ├── function_call.lua
│ │ │ │ ├── function_declaration.lua
│ │ │ │ ├── if_statement.lua
│ │ │ │ ├── local_function_declaration.lua
│ │ │ │ ├── local_variable_declaration.lua
│ │ │ │ ├── pass_self_function_call.lua
│ │ │ │ ├── repeat_statement.lua
│ │ │ │ ├── return.lua
│ │ │ │ └── while_statement.lua
│ │ │ ├── statements.lua
│ │ │ └── upvalue.lua
│ │ ├── enums.lua
│ │ ├── namegenerators/
│ │ │ ├── Il.lua
│ │ │ ├── confuse.lua
│ │ │ ├── mangled.lua
│ │ │ ├── mangled_shuffled.lua
│ │ │ └── number.lua
│ │ ├── namegenerators.lua
│ │ ├── parser.lua
│ │ ├── pipeline.lua
│ │ ├── randomLiterals.lua
│ │ ├── randomStrings.lua
│ │ ├── scope.lua
│ │ ├── step.lua
│ │ ├── steps/
│ │ │ ├── AddVararg.lua
│ │ │ ├── AntiTamper.lua
│ │ │ ├── ConstantArray.lua
│ │ │ ├── EncryptStrings.lua
│ │ │ ├── NumbersToExpressions.lua
│ │ │ ├── ProxifyLocals.lua
│ │ │ ├── SplitStrings.lua
│ │ │ ├── Vmify.lua
│ │ │ ├── Watermark.lua
│ │ │ ├── WatermarkCheck.lua
│ │ │ └── WrapInFunction.lua
│ │ ├── steps.lua
│ │ ├── tokenizer.lua
│ │ ├── unparser.lua
│ │ ├── util.lua
│ │ └── visitast.lua
│ └── prometheus.lua
├── tests/
│ ├── ambiguous-call.lua
│ ├── closures.lua
│ ├── coroutines.lua
│ ├── fibonacci.lua
│ ├── iterator.lua
│ ├── loops.lua
│ ├── matrix.lua
│ ├── metatables.lua
│ ├── multi-return.lua
│ ├── primes.lua
│ ├── repeat-test.lua
│ ├── state-machine.lua
│ ├── strings.lua
│ ├── syntax.lua
│ ├── table-merge.lua
│ └── upvalues.lua
└── tests.lua
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
[*.lua]
indent_style = tab
indent_size = 4
end_of_line = lf
================================================
FILE: .gitattributes
================================================
*.lua text=auto
*.lua eol=lf
================================================
FILE: .gitbook.yaml
================================================
root: ./doc/
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Expected behavior**
A clear and concise description of what you expected to happen.
**To Reproduce**
Steps to reproduce the behavior:
If your problem is a non-working obfuscated file, please also include a minimal source code example, your config file as well as the output file that you got.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/workflows/Build.yml
================================================
name: Build
on:
push:
branches:
main
jobs:
build:
runs-on: windows-latest # gh-actions-lua doesn't work on windows
steps:
- name: Checkout repo
uses: actions/checkout@master
- name: Download srlua-mingw
run: curl -o srlua.zip "https://raw.githubusercontent.com/joedf/LuaBuilds/gh-pages/hdata/srlua-5.1.5_Win32_bin.zip"
- name: Unzip srlua-mingw
run: |
tar -xf srlua.zip
Rename-Item -Path srglue.exe -NewName glue.exe
- name: Download Lua53
run: curl -o Lua53.zip "https://raw.githubusercontent.com/joedf/LuaBuilds/gh-pages/hdata/lua-5.3.5_Win64_bin.zip"
- name: Unzip Lua53
run: |
tar -xf Lua53.zip
- run: dir
- name: Build the project
run: |
./build.bat
shell: bash
- name: Zip the build
uses: papeloto/action-zip@v1
with:
files: build/
dest: build.zip
- name: Load version and name
run: | # I have no idea why but 5.1 just won't work for some reason
echo "prometheus_full_version=$(./lua.exe ./src/config.lua --FullVersion)" >> $GITHUB_ENV
echo "prometheus_version=$(./lua.exe ./src/config.lua --Version)" >> $GITHUB_ENV
shell: bash
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build.zip
asset_name: ${{ env.prometheus_full_version }}.zip
tag: release-${{ github.ref }}-${{ env.prometheus_version }}
release_name: ${{ env.prometheus_version }}
overwrite: true
body: ${{ env.prometheus_full_version }} ${{ github.event.commits[0].message }}
================================================
FILE: .github/workflows/Test.yml
================================================
name: Test
on:
push:
pull_request:
branches:
- master
jobs:
test-linux:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@master
- name: Install Lua
uses: leafo/gh-actions-lua@master
with:
luaVersion: 5.1
- name: Run test case
run: lua ./tests.lua --Linux --CI
================================================
FILE: .gitignore
================================================
# Ignore Vscode Folder
.vscode
# Ignore Lua Implementation and srlua
lua51.dll
luajit.exe
srlua
luajit
buildnotes.txt
srlua.exe
glue.exe
build
# Ignore Local Test Files
test.lua
test.obfuscated.lua
config.lua
================================================
FILE: LICENSE
================================================
PROMETHEUS LICENSE
Copyright (c) 2025 Elias Oelschner
https://github.com/prometheus-lua/Prometheus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
1. Retained Notice.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software that are distributed
in source or object form, unless explicitly stated otherwise in this
license.
2. Attribution Requirement.
Any Product or Service that (a) includes, links to, wraps, depends on,
is derived from, uses, or otherwise incorporates the Software (including
via modification, obfuscation, binary linking, packaging, or embedding),
whether distributed, provided for use, or made available over a network
(collectively, "Using Products/Services"), must provide clear,
reasonably prominent attribution to Prometheus as follows:
"Based on Prometheus by Elias Oelschner, https://github.com/prometheus-lua/Prometheus"
This attribution must appear in at least one of the following locations,
as applicable and reasonably prominent for the type of Using Product/Service:
a) In-user interface: a visible "About", "Credits", or equivalent screen
within the product's primary user interface (graphical or web UI).
b) On the product web site: a visible place such as a footer, About page,
or documentation landing page that is accessible to the product's users.
c) In the tool itself: the program's --version, --help output, or similar
command-line/displayed metadata for CLI tools.
d) Documentation: in user or developer documentation, README, or product
manual that accompanies the product.
For Software provided as a Network Service or SaaS (i.e., made available
for use over a network rather than distributed as a copy), the attribution
must be visible on the public-facing web UI (for example on the login
screen, footer, About page, or a help/credits page accessible without an
account), and must include the exact phrase above and the URL.
3. Derivative Statement.
Any derivative work, modification, fork, or reimplementation of the
Software that is publicly distributed, publicly hosted, or provided as a
service must include a prominent statement in its README (or equivalent
public-facing documentation) that it is based on Prometheus and include the
exact attribution text in section 2.
4. Generated Output Exception.
Files or artifacts produced by running or using the Software (for example,
obfuscated output files, compiled artifacts, transformed source files,
or other generated outputs) are NOT required by this license to carry
copyright notices or license text. The attribution obligations in section 2
continue to apply to the Using Product/Service that produces, distributes,
or serves those outputs.
5. No Trademark License.
This license does not grant any rights to use the trade names, trademarks,
service marks, or product names of the Licensor except as required for the
textual attribution specified in section 2.
6. Compliance and Termination.
Any failure to comply with the obligations in sections 2 or 3 will
terminate the rights granted under this license for the non-compliant
party with respect to the Software. Rights may be reinstated if the
non-compliant party cures the breach within thirty (30) days after
receiving written notice from the Licensor and provides reasonable proof
of cure.
7. Sublicensing.
You may sublicense the Software, provided that any sublicensee is bound
by the terms of this license and the attribution obligations described
herein.
8. Warranty Disclaimer.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9. Limitation of Liability.
IN NO EVENT WILL THE COPYRIGHT HOLDER BE LIABLE FOR ANY INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ARISING IN ANY
WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
10. Governing Law.
This license shall be governed by and construed in accordance with the
laws of the jurisdiction chosen by the Licensor. This clause does not
limit any mandatory consumer protections that may apply in certain
jurisdictions.
By exercising any rights granted to you under this License, you accept and
agree to be bound by the terms and conditions of this License.
================================================
FILE: benchmark.lua
================================================
print("PROMETHEUS Benchmark")
print("Based On IronBrew Benchmark")
local Iterations = 100000
print("Iterations: " .. tostring(Iterations))
print("CLOSURE testing.")
local Start = os.clock()
local TStart = Start
for _ = 1, Iterations do
(function()
if not true then
print("Hey gamer.")
end
end)()
end
print("Time:", os.clock() - Start .. "s")
print("SETTABLE testing.")
Start = os.clock()
local T = {}
for Idx = 1, Iterations do
T[tostring(Idx)] = "EPIC GAMER " .. tostring(Idx)
end
print("Time:", os.clock() - Start .. "s")
print("GETTABLE testing.")
Start = os.clock()
for Idx = 1, Iterations do
T[1] = T[tostring(Idx)]
end
print("Time:", os.clock() - Start .. "s")
print("Total Time:", os.clock() - TStart .. "s")
================================================
FILE: cli.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- cli.lua
--
-- This Script contains the Code for the Prometheus CLI
-- Configure package.path for requiring Prometheus
local function script_path()
local str = debug.getinfo(2, "S").source:sub(2)
return str:match("(.*[/%\\])") or "";
end
package.path = script_path() .. "?.lua;" .. package.path;
require("src.cli");
================================================
FILE: doc/README.md
================================================
---
description: Prometheus is an Lua Obfuscator, that is written in pure Lua.
---
# Prometheus
Prometheus can obfuscate Lua51 as well as Roblox's LuaU, which is an optionally typed superset of Lua51.
View Prometheus on [github](https://github.com/levno-710/Prometheus).
This Documentation only applies to the newest version of Prometheus.
================================================
FILE: doc/SUMMARY.md
================================================
# Table of contents
* [Prometheus](README.md)
## Getting Started
* [Installation](getting-started/installation.md)
* [Obfuscating your first script](getting-started/obfuscating-your-first-script.md)
* [Command Line Options](getting-started/command-line-options.md)
* [Presets](getting-started/presets.md)
* [Writing a custom Config File](getting-started/writing-a-custom-config-file.md)
* [The Config Object](getting-started/the-config-object.md)
## Steps
* [WrapInFunction](steps/wrapinfunction.md)
* [Vmify](steps/vmify.md)
* [SplitStrings](steps/splitstrings.md)
* [ProxifyLocals](steps/proxifylocals.md)
* [EncryptStrings](steps/encryptstrings.md)
* [ConstantArray](steps/constantarray.md)
* [AntiTamper](steps/anti-tamper.md)
## advanced
* [Using Prometheus in your Lua Application](advanced/using-prometheus-in-your-lua-application.md)
================================================
FILE: doc/advanced/using-prometheus-in-your-lua-application.md
================================================
# Using Prometheus in your Lua Application
Prometheus can also be used as a library for your custom Lua Applications instead of using its cli tool. 
In order to do that you'll first need to clone the github repo:
```batch
git clone "https://github.com/levno-710/Prometheus.git"
```
After that, you'll need to copy everything within the src folder to your project. Let's say you created a folder named `prometheus`, where all the Prometheus files are located. You can the use the following code to obfuscate a string:
{% code title="use_prometheus.lua" %}
```lua
local Prometheus = require("prometheus.prometheus")
-- If you don't want console output
Prometheus.Logger.logLevel = Prometheus.Logger.LogLevel.Error
-- Your code
local code = 'print("Hello, World!")'
-- Create a Pipeline using the Strong preset
local pipeline = Prometheus.Pipeline:fromConfig(Prometheus.Presets.Strong)
-- Apply the obfuscation and print the result
print(pipeline:apply(code));
```
{% endcode %}
Instead of passing the Strong preset you could also pass a custom [Config Object](../getting-started/the-config-object.md).
================================================
FILE: doc/getting-started/command-line-options.md
================================================
# Command Line Options
The following table provides a brief overview over the command line options:
| Option | Usage |
| ----------------------------- | ----------------------------------------------------------- |
| --preset \[name]; --p \[name] | Specify the config preset to be used; [Details](presets.md) |
| --config \[path]; --c \[path] | Specify the path to a custom config file |
| --out \[path]; --o \[path] | Specify the path of the output file |
| --nocolors | Disable ansi colors escape sequences |
| --Lua51 | Handle input as Lua 5.1 |
| --LuaU | Handle input as LuaU |
| --pretty | Pretty print the output |
================================================
FILE: doc/getting-started/installation.md
================================================
# Installation
To install Prometheus, simply clone the Github Repository using:
```batch
git clone "https://github.com/levno-710/Prometheus.git"
```
Alternatively you can download the Sources [here](https://github.com/levno-710/Prometheus/archive/refs/heads/master.zip).
Prometheus also Requires LuaJIT or Lua51 in order to work. The Lua51 binaries can be downloaded [here](https://sourceforge.net/projects/luabinaries/files/5.1.5/Tools%20Executables/).
================================================
FILE: doc/getting-started/obfuscating-your-first-script.md
================================================
# Obfuscating your first script
Now that you have downloaded and Prometheus, you probably wonder how to use it. In this quick tutorial you are going to learn how to obfuscate your first file.
Note that in the following command examples `lua` should be replaced by your lua implementation.
Create the following file within the Prometheus main directory that you just downloaded:
{% code title="hello_world.lua" %}
```lua
print("Hello, World")
```
{% endcode %}
Now run the following command inside of the Prometheus directory:
```batch
lua ./cli.lua ./hello_world.lua
```
You may notice, that the console output looks weird. If that is the case, your terminal does not support ansi color escape sequences. You should add the `--nocolors` option:
```batch
lua ./cli.lua --nocolors ./hello_world.lua
```
This should create the following file:
{% code title="hello_world.obfuscated.lua" %}
```lua
print("Hello, World")
```
{% endcode %}
As you can see, the file hasn't changed at all. That is because by default prometheus is just a minifier and the code we gave it was already as small as possible. To actually obfuscate the file, prometheus must be told which obfuscation steps it should apply in which order. In order to do this, the cli provides the `--preset` option which allows you to specify the name of a predefined configuration. There are currently the following presets:
* Minify
* Weak
* Medium
* Strong
In order to perform the obfuscation, you need to specify that Prometheus should use the Strong preset:
```batch
lua ./cli.lua --preset Medium ./hello_world.lua
```
The `hello_world.obfuscated.lua` should now contain the obfuscated code that should still print "Hello World".
Note that using the "Strong" preset is not recommended for large projects.
================================================
FILE: doc/getting-started/presets.md
================================================
# Presets
The following table provides an overview over the presets
| name | size | speed |
| ------ | ------ | ------- |
| Minify | tiny | fastest |
| Weak | small | fast |
| Medium | medium | medium |
| Strong | huge | slowest |
================================================
FILE: doc/getting-started/the-config-object.md
================================================
# The Config Object
Prometheus takes a configuration object. In this object there can be many properties applied. \
The following table provides an overview:
| Property | type | possible values | default |
| ------------- | ------- | -------------------------------------------- | ----------------- |
| LuaVersion | string | "Lua51", "LuaU" | "Lua51" |
| PrettyPrint | boolean | true, false | false |
| VarNamePrefix | string | any | "" |
| NameGenerator | string | "Mangled", "MangledShuffled", "Il", "Number" | "MangledShuffled" |
| Seed | number | any | 0 |
| Steps | table | StepConfig\[] | {} |
As this table shows, all properties in the config object are optional as they have a default value.
As an example, here is the code for the minify preset:
```lua
{
-- The default LuaVersion is Lua51
LuaVersion = "Lua51";
-- For minifying no VarNamePrefix is applied
VarNamePrefix = "";
-- Name Generator for Variables
NameGenerator = "MangledShuffled";
-- No pretty printing
PrettyPrint = false;
-- Seed is generated based on current time
Seed = 0;
-- No obfuscation steps
Steps = {}
};
```
### Steps
The most important property is the Steps property. This property must be a table of so called Step Configs. A Step in Prometheus describes a single transformation applied to your script by the Prometheus obfuscation pipeline. A StepConfiguration consists of the Name of the Step as well as settings for the step. All Steps will later be applied in the order they are defined. A single Step can be defined twice and will then be applied twice.
```lua
-- Obfuscation steps
Steps = {
{
-- This obfuscation step puts all constants into an array at the beginning of the code
Name = "ConstantArray";
Settings = {
-- Apply to Strings only
StringsOnly = true;
-- Apply to all Constants, 0.5 would only affect 50% of strings
Threshold = 1;
}
},
}
```
Under [Steps](broken-reference), you can find all current Steps, their names as well as the possible options.
================================================
FILE: doc/getting-started/writing-a-custom-config-file.md
================================================
# Writing a custom Config File
Configuration Files for Prometheus are just lua modules, that return a single object, which contains the configuration. Let's say we have the following config file:
{% code title="config.lua" %}
```lua
return {
-- The default LuaVersion is Lua51
LuaVersion = "Lua51"; -- or "LuaU"
-- All Variables will start with this prefix
VarNamePrefix = "";
-- Name Generator for Variables that look like this: b, a, c, D, t, G
NameGenerator = "MangledShuffled";
-- No pretty printing
PrettyPrint = false;
-- Seed is generated based on current time
-- When specifying a seed that is not 0, you will get the same output every time
Seed = 0;
-- Obfuscation steps
Steps = {
{
-- This obfuscation step puts all constants into an array at the beginning of the code
Name = "ConstantArray";
Settings = {
-- Apply to Strings only
StringsOnly = true;
-- Apply to all Constants, 0.5 would only affect 50% of strings
Threshold = 1;
}
},
}
}
```
{% endcode %}
One can now obfuscate a script using this configuration by running:
```batch
lua ./cli.lua --config config.lua hello_world.lua
```
You should get the following output:
{% code title="hello_world.obfuscated.lua" %}
```lua
local N={"Hello, World!"}local function k(k)return N[k+40058]end print(k(-40057))
```
{% endcode %}
As you can see, the only transformation that was applied to our Hello World example was putting all strings (in this case only `"Hello, World!"` ) into an array and creating a wrapper function for retrieving the value.
### How does the Config File work?
The config file is simply a lua file, that returns the configuration object. Please note that this lua file is sandboxed by Prometheus when loading the configuration, meaning that you can't use any predefined functions like `tostring` or libraries like `math`.
See [The Config Object](the-config-object.md) to learn what this configuration object consists of.
================================================
FILE: doc/steps/anti-tamper.md
================================================
---
description: This step provides an obfuscation step, that breaks the script, when someone tries to tamper with it.
---
# Anti Tamper
### Settings
| Name | type | description | values |
| ----------- | ---- | ------------------------------------------- | --------------------------------------- |
| UseDebug | boolean | Uses the debug library in lua. Disable this if you don't have access to debug library | "true","false" |
================================================
FILE: doc/steps/constantarray.md
================================================
---
description: >-
This Step will Extract all Constants and put them into an Array at the
beginning of the script
---
# ConstantArray
### Settings
| Name | type | description |
| -------------------- | ------- | ------------------------------------------------------------------------------------------------------------ |
| Threshold | number | The relative amount of nodes that will be affected" |
| StringsOnly | boolean | Whether to only Extract Strings |
| Shuffle | boolean | Whether to shuffle the order of Elements in the Array |
| Rotate | boolean | Whether to rotate the String Array by a specific (random) amount. This will be undone on runtime. |
| LocalWrapperThreshold | number | The relative amount of nodes functions, that will get local wrappers |
| LocalWrapperCount | number | The number of Local wrapper Functions per scope. This only applies if LocalWrapperThreshold is greater than 0 |
| LocalWrapperArgCount | number | The number of Arguments to the Local wrapper Functions |
| MaxWrapperOffset | number | The Max Offset for the Wrapper Functions |
### Example
{% code title="in.lua" %}
```lua
print("1")
print("2")
print("3")
print("4")
```
{% endcode %}
{% code title="out.lua" %}
```lua
-- LocalWrapperCount = 3
-- LocalWrapperArgCount = 5
local F = {"4", "3", "2", "1"}
do
local y, G = 1, 4
while y < G do
F[y], F[G] = F[G], F[y]
y, G = y + 1, G - 1
end
y, G = 1, 3
while y < G do
F[y], F[G] = F[G], F[y]
y, G = y + 1, G - 1
end
y, G = 4, 4
while y < G do
F[y], F[G] = F[G], F[y]
y, G = y + 1, G - 1
end
end
local function y(y)
return F[y + 440]
end
local G = {cb = function(F, G, R, p, b)
return y(G - 2277)
end, n = function(F, G, R, p, b)
return y(p + 47178)
end, B = function(F, G, R, p, b)
return y(F + 31775)
end}
print(G.cb(1575, 1840, 2367, 1293, 1280))
print(G.B(-32213, -31781, -31538, -32780, -32728))
print(G.B(-32214, -33004, -31973, -32125, -31855))
print(G.B(-32211, -31884, -31217, -32222, -31210))
```
{% endcode %}
================================================
FILE: doc/steps/encryptstrings.md
================================================
---
description: This Step will encrypt all String constants in your code
---
# EncryptStrings
## Settings
None
## Example
{% code title="in.lua" %}
```lua
print("Hello, World!")
```
{% endcode %}
{% code title="out.lua" %}
```lua
-- Settings: None
local x, F
do
local k = math.floor
local I = math.random
local Y = table.remove
local i = string.char
local K = 0
local J = 2
local Q = {}
local W = {}
local q = 0
local R = {}
for F = 1, 256, 1 do
R[F] = F
end
repeat
local F = I(1, #R)
local x = Y(R, F)
W[x] = i(x - 1)
until #R == 0
local j = {}
local function B()
if #j == 0 then
K = (K * 173 + 8408159861491) % 35184372088832
repeat
J = (J * 160) % 257
until J ~= 1
local F = J % 32
local x = (k(K / 2 ^ (13 - (J - F) / 32)) % 4294967296) / 2 ^ F
local I = k((x % 1) * 4294967296) + k(x)
local Y = I % 65536
local i = (I - Y) / 65536
local Q = Y % 256
local W = (Y - Q) / 256
local q = i % 256
local R = (i - q) / 256
j = {Q, W, q, R}
end
return table.remove(j)
end
local d = {}
x = setmetatable({}, {__index = d, __metatable = nil})
function F(x, k)
local I = d
if I[k] then
else
j = {}
local F = W
K = k % 35184372088832
J = k % 255 + 2
local Y = string.len(x)
I[k] = ""
local i = 198
for Y = 1, Y, 1 do
i = ((string.byte(x, Y) + B()) + i) % 256
I[k] = I[k] .. F[i + 1]
end
end
return k
end
end
print(x[F("\219\018Q%~Y\225\128u\128\208&\155", 6909832146399)])
```
{% endcode %}
================================================
FILE: doc/steps/proxifylocals.md
================================================
---
description: This Step wraps all locals into Proxy Objects
---
# ProxifyLocals
### Settings
| Name | type | description | values |
| ----------- | ---- | ------------------------------------------- | --------------------------------------- |
| LiteralType | enum | The type of the randomly generated literals | "dictionary", "number", "string", "any" |
### Example
{% code title="in.lua" %}
```lua
local x = "Hello, World!"
print(x)
```
{% endcode %}
{% code title="out.lua" %}
```lua
-- LiteralType = "dictionary"
local n = setmetatable
local D =
n(
{Wz = function()
end},
{__div = function(R, n)
R.Wz = n
end, __concat = function(R, n)
return R.Wz
end}
)
local R =
n(
{Js = "Hello, World!"},
{__add = function(R, n)
R.Js = n
end, __index = function(R, n)
return rawget(R, "Js")
end}
)
print(R.Muirgen)
```
{% endcode %}
================================================
FILE: doc/steps/splitstrings.md
================================================
---
description: This Step splits Strings to a specific or random length
---
# SplitStrings
### Settings
| Name | type | description | Values |
| ------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
| Threshold | number | The relative amount of nodes that will be affected | 0 <= x <= 1 |
| MinLength | number | The minimal length for the chunks in that the Strings are splitted | x > 0 |
| MaxLength | number | The maximal length for the chunks in that the Strings are splitted | x >= MinLength |
| ConcatenationType | enum | The Functions used for Concatenation. Note that when using custom, the String Array will also be Shuffled | "strcat", "table", "custom" |
| CustomFunctionType | enum | <p>The Type of Function code injection This Option only applies when custom Concatenation is selected.<br>Note that when choosing inline, the code size may increase significantly!</p> | "global", "local", "inline" |
| CustomLocalFunctionsCount | number | The number of local functions per scope. This option only applies when CustomFunctionType = local | x > 0 |
### Example
{% code title="in.lua" %}
```lua
print("Hello, World!")
```
{% endcode %}
{% code title="out.lua" %}
```lua
-- MinLength = 1
-- MaxLength = 1
local f = function(f)
local k, C = f[#f], ""
for j = 1, #k, 1 do
C = C .. k[f[j]]
end
return C
end
print(f({13, 11, 4, 12, 1, 6, 8, 10, 9, 7, 3, 2, 5, {"o", "d", "l", "l", "!", ",", "r", " ", "o", "W", "e", "l", "H"}}))
```
{% endcode %}
================================================
FILE: doc/steps/vmify.md
================================================
---
description: This Step will Compile your script and run it within a VM.
---
# Vmify
### Settings
None
================================================
FILE: doc/steps/wrapinfunction.md
================================================
---
description: This Step Wraps the Entire Script into a Function
---
# WrapInFunction
### Settings
| Name | type | description |
| ---------- | ------ | ------------------------ |
| Iterations | number | The Number Of Iterations |
### Example
{% code title="in.lua" %}
```lua
print("Hello, World!")
```
{% endcode %}
{% code title="out.lua" %}
```lua
-- Iterations = 1
return (function()
print("Hello, World!")
end)()
```
{% endcode %}
================================================
FILE: prometheus-main.lua
================================================
require("cli")
================================================
FILE: readme.md
================================================
# :fire: Prometheus Lua Obfuscator
[](https://github.com/prometheus-lua/Prometheus/actions/workflows/Test.yml)
Prometheus is a Lua obfuscator written in pure Lua.
It uses several AST-based transformations including Control-Flow Flattening, Constant Encryption and more.
This project was inspired by the amazing [javascript-obfuscator](https://github.com/javascript-obfuscator/javascript-obfuscator).
It can currently obfuscate Lua51 and Roblox's LuaU, however LuaU support is not finished yet.
You can find the full Documentation including a getting started guide [here](https://levno-710.gitbook.io/prometheus/).
Prometheus has an official [Discord server](https://discord.gg/U8h4d4Rf64).
<p align="center">
<img src="assets/readme/obfuscation-preview.gif" alt="Prometheus obfuscation process preview" width="900" />
</p>
## Installation
To install Prometheus, simply clone the GitHub repository using:
```batch
git clone https://github.com/prometheus-lua/Prometheus.git
```
Alternatively you can download the sources [here](https://github.com/prometheus-lua/Prometheus/archive/refs/heads/master.zip).
Prometheus also Requires LuaJIT or Lua51 in order to work. The Lua51 binaries can be downloaded [here](https://sourceforge.net/projects/luabinaries/files/5.1.5/Tools%20Executables/).
## Usage
To quickly obfuscate a script:
```batch
lua ./cli.lua --preset Medium ./your_file.lua
```
### Example output
```lua
-- input.lua
print("Hello, World!");
```
```lua
-- input.obfuscated.lua
return(function(...)local L={"afT6mf1V","/7mJXsuvmE1c/fT3";"tn1ZSn6=","37ghSJM=";"WqermfWAWuuZpb3XX7M=","tqXGSJ3u","XQXpL9x21dxAWJa//p==","SrM=";"3q+5SJM=","/D==";"t7XUt0p=";"mIeOmIx9";"LdgrBfWdWuNABsb+KJxj","SJWJ4dahKsebW7t+KQv=","/cDu3AvP/D==";"Llv7uD==","tJWhFfTE";"TQ43ctIuy9HIop==","mEu93p==";"WJax1sXEXEaxWuxGt6==","t0gPSEp=",...
-- remaining obfuscated output omitted
```
For more advanced use cases see the [Documentation](https://levno-710.gitbook.io/prometheus/).
## Tests
To perform the Prometheus Tests, just run
```batch
lua ./tests.lua [--Linux]
```
## License and Commercial Use
Prometheus is licensed under the Prometheus License, a modified MIT-style license.
You are free to use, modify, and distribute this software, including for commercial purposes, under the following conditions:
- Any commercial product, wrapper, or service (including SaaS or hosted solutions) that uses or integrates Prometheus must include clear attribution to:
```
Based on Prometheus by Elias Oelschner, https://github.com/prometheus-lua/Prometheus
```
- The attribution must be visible in the product’s UI, documentation, and public website.
- The obfuscated output files generated by Prometheus do not need to include any license or copyright notice.
- Derivative works and public forks must also include a statement in their README noting that they are based on Prometheus.
Full license text: [Prometheus License](https://github.com/levno-710/Prometheus/blob/master/LICENSE)
================================================
FILE: src/cli.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- cli.lua
--
-- This Script contains the Code for the Prometheus CLI.
-- Configure package.path for requiring Prometheus.
local function script_path()
local str = debug.getinfo(2, "S").source:sub(2)
return str:match("(.*[/%\\])")
end
package.path = script_path() .. "?.lua;" .. package.path
---@diagnostic disable-next-line: different-requires
local Prometheus = require("prometheus")
Prometheus.Logger.logLevel = Prometheus.Logger.LogLevel.Info
-- Check if the file exists
local function file_exists(file)
local f = io.open(file, "rb")
if f then
f:close()
end
return f ~= nil
end
string.split = function(str, sep)
local fields = {}
local pattern = string.format("([^%s]+)", sep)
str:gsub(pattern, function(c)
fields[#fields + 1] = c
end)
return fields
end
-- get all lines from a file, returns an empty
-- list/table if the file does not exist
local function lines_from(file)
if not file_exists(file) then
return {}
end
local lines = {}
for line in io.lines(file) do
lines[#lines + 1] = line
end
return lines
end
local function load_chunk(content, chunkName, environment)
if type(loadstring) == "function" then
local func, err = loadstring(content, chunkName)
if not func then
return nil, err
end
if environment and type(setfenv) == "function" then
setfenv(func, environment)
elseif environment and type(load) == "function" then
return load(content, chunkName, "t", environment)
end
return func
end
if type(load) ~= "function" then
return nil, "No load function available"
end
return load(content, chunkName, "t", environment)
end
-- CLI
local config, sourceFile, outFile, luaVersion, prettyPrint
Prometheus.colors.enabled = true
-- Parse Arguments
local i = 1
while i <= #arg do
local curr = arg[i]
if curr:sub(1, 2) == "--" then
if curr == "--preset" or curr == "--p" then
if config then
Prometheus.Logger:warn("The config was set multiple times")
end
i = i + 1
local preset = Prometheus.Presets[arg[i]]
if not preset then
Prometheus.Logger:error(string.format('A Preset with the name "%s" was not found!', tostring(arg[i])))
end
config = preset
elseif curr == "--config" or curr == "--c" then
i = i + 1
local filename = tostring(arg[i])
if not file_exists(filename) then
Prometheus.Logger:error(string.format('The config file "%s" was not found!', filename))
end
local content = table.concat(lines_from(filename), "\n")
-- Load Config from File
local func, err = load_chunk(content, "@" .. filename, {})
if not func then
Prometheus.Logger:error(string.format('Failed to parse config file "%s": %s', filename, tostring(err)))
end
config = func()
elseif curr == "--out" or curr == "--o" then
i = i + 1
if outFile then
Prometheus.Logger:warn("The output file was specified multiple times!")
end
outFile = arg[i]
elseif curr == "--nocolors" then
Prometheus.colors.enabled = false
elseif curr == "--Lua51" then
luaVersion = "Lua51"
elseif curr == "--LuaU" then
luaVersion = "LuaU"
elseif curr == "--pretty" then
prettyPrint = true
elseif curr == "--saveerrors" then
-- Override error callback
Prometheus.Logger.errorCallback = function(...)
print(Prometheus.colors(Prometheus.Config.NameUpper .. ": " .. ..., "red"))
local args = { ... }
local message = table.concat(args, " ")
local fileName = sourceFile:sub(-4) == ".lua" and sourceFile:sub(0, -5) .. ".error.txt"
or sourceFile .. ".error.txt"
local handle = io.open(fileName, "w")
handle:write(message)
handle:close()
os.exit(1)
end
else
Prometheus.Logger:warn(string.format('The option "%s" is not valid and therefore ignored', curr))
end
else
if sourceFile then
Prometheus.Logger:error(string.format('Unexpected argument "%s"', arg[i]))
end
sourceFile = tostring(arg[i])
end
i = i + 1
end
if not sourceFile then
Prometheus.Logger:error("No input file was specified!")
end
if not config then
Prometheus.Logger:warn("No config was specified, falling back to Minify preset")
config = Prometheus.Presets.Minify
end
-- Add Option to override Lua Version
config.LuaVersion = luaVersion or config.LuaVersion
config.PrettyPrint = prettyPrint ~= nil and prettyPrint or config.PrettyPrint
if not file_exists(sourceFile) then
Prometheus.Logger:error(string.format('The File "%s" was not found!', sourceFile))
end
if not outFile then
if sourceFile:sub(-4) == ".lua" then
outFile = sourceFile:sub(0, -5) .. ".obfuscated.lua"
else
outFile = sourceFile .. ".obfuscated.lua"
end
end
local source = table.concat(lines_from(sourceFile), "\n")
local pipeline = Prometheus.Pipeline:fromConfig(config)
local out = pipeline:apply(source, sourceFile)
Prometheus.Logger:info(string.format('Writing output to "%s"', outFile))
-- Write Output
local handle = io.open(outFile, "w")
handle:write(out)
handle:close()
================================================
FILE: src/colors.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- colors.lua
--
-- This Script provides a simple method for syntax highlighting of Lua code
local keys = {
reset = 0,
bright = 1,
dim = 2,
underline = 4,
blink = 5,
reverse = 7,
hidden = 8,
black = 30,
pink = 91,
red = 31,
green = 32,
yellow = 33,
blue = 34,
magenta = 35,
cyan = 36,
grey = 37,
gray = 37,
white = 97,
blackbg = 40,
redbg = 41,
greenbg = 42,
yellowbg = 43,
bluebg = 44,
magentabg = 45,
cyanbg = 46,
greybg = 47,
graybg = 47,
whitebg = 107,
}
local escapeString = string.char(27) .. "[%dm"
local function escapeNumber(number)
return escapeString:format(number)
end
local settings = {
enabled = true,
}
local function colors(str, ...)
if not settings.enabled then
return str
end
str = tostring(str or "")
local escapes = {}
for _, name in ipairs({ ... }) do
table.insert(escapes, escapeNumber(keys[name]))
end
return escapeNumber(keys.reset) .. table.concat(escapes) .. str .. escapeNumber(keys.reset)
end
return setmetatable(settings, {
__call = function(_, ...)
return colors(...)
end,
})
================================================
FILE: src/highlightlua.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- highlightlua.lua
--
-- This Script provides a simple Method for Syntax Highlighting of Lua code
local Tokenizer = require("prometheus.tokenizer");
local colors = require("colors");
local TokenKind = Tokenizer.TokenKind;
local lookupify = require("prometheus.util").lookupify;
return function(code, luaVersion)
local out = "";
local tokenizer = Tokenizer:new({
LuaVersion = luaVersion,
});
tokenizer:append(code);
local tokens = tokenizer:scanAll();
local nonColorSymbols = lookupify{
",", ";", "(", ")", "{", "}", ".", ":", "[", "]"
}
local defaultGlobals = lookupify{
"string", "table", "bit32", "bit"
}
local currentPos = 1;
for _, token in ipairs(tokens) do
if token.startPos >= currentPos then
out = out .. string.sub(code, currentPos, token.startPos);
end
if token.kind == TokenKind.Ident then
if defaultGlobals[token.source] then
out = out .. colors(token.source, "red");
else
out = out .. token.source;
end
elseif token.kind == TokenKind.Keyword then
if token.source == "nil" then
out = out .. colors(token.source, "yellow");
else
out = out .. colors(token.source, "yellow");
end
elseif token.kind == TokenKind.Symbol then
if nonColorSymbols[token.source] then
out = out .. token.source;
else
out = out .. colors(token.source, "yellow");
end
elseif token.kind == TokenKind.String then
out = out .. colors(token.source, "green")
elseif token.kind == TokenKind.Number then
out = out .. colors(token.source, "red")
else
out = out .. token.source;
end
currentPos = token.endPos + 1;
end
return out;
end
================================================
FILE: src/logger.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- logger.lua
--
-- This Script provides a Logger for Prometheus.
local logger = {}
local config = require("config");
local colors = require("colors");
logger.LogLevel = {
Error = 0,
Warn = 1,
Log = 2,
Info = 2,
Debug = 3,
}
logger.logLevel = logger.LogLevel.Log;
logger.debugCallback = function(...)
print(colors(config.NameUpper .. ": " .. ..., "grey"));
end;
function logger:debug(...)
if self.logLevel >= self.LogLevel.Debug then
self.debugCallback(...);
end
end
logger.logCallback = function(...)
print(colors(config.NameUpper .. ": ", "magenta") .. ...);
end;
function logger:log(...)
if self.logLevel >= self.LogLevel.Log then
self.logCallback(...);
end
end
function logger:info(...)
if self.logLevel >= self.LogLevel.Log then
self.logCallback(...);
end
end
logger.warnCallback = function(...)
print(colors(config.NameUpper .. ": " .. ..., "yellow"));
end;
function logger:warn(...)
if self.logLevel >= self.LogLevel.Warn then
self.warnCallback(...);
end
end
logger.errorCallback = function(...)
print(colors(config.NameUpper .. ": " .. ..., "red"))
error(...);
end;
function logger:error(...)
self.errorCallback(...);
error(config.NameUpper .. ": logger.errorCallback did not throw an Error!");
end
return logger;
================================================
FILE: src/presets.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- presets.lua
--
-- This Script provides the predefined obfuscation presets for Prometheus
return {
-- Minifies your code. Does not obfuscate it. No performance loss.
["Minify"] = {
LuaVersion = "Lua51",
VarNamePrefix = "",
NameGenerator = "MangledShuffled",
PrettyPrint = false,
Seed = 0,
Steps = {},
},
-- Weak obfuscation. Very readable, low performance loss.
["Weak"] = {
LuaVersion = "Lua51",
VarNamePrefix = "",
NameGenerator = "MangledShuffled",
PrettyPrint = false,
Seed = 0,
Steps = {
{ Name = "Vmify", Settings = {} },
{
Name = "ConstantArray",
Settings = {
Threshold = 1,
StringsOnly = true
},
},
{ Name = "WrapInFunction", Settings = {} },
},
},
-- This is here for the tests.lua file.
-- It helps isolate any problems with the Vmify step.
-- It is not recommended to use this preset for obfuscation.
-- Use the Weak, Medium, or Strong for obfuscation instead.
["Vmify"] = {
LuaVersion = "Lua51",
VarNamePrefix = "",
NameGenerator = "MangledShuffled",
PrettyPrint = false,
Seed = 0,
Steps = {
{ Name = "Vmify", Settings = {} },
},
},
-- Medium obfuscation. Moderate obfuscation, moderate performance loss.
["Medium"] = {
LuaVersion = "Lua51",
VarNamePrefix = "",
NameGenerator = "MangledShuffled",
PrettyPrint = false,
Seed = 0,
Steps = {
{ Name = "EncryptStrings", Settings = {} },
{
Name = "AntiTamper",
Settings = {
UseDebug = false,
},
},
{ Name = "Vmify", Settings = {} },
{
Name = "ConstantArray",
Settings = {
Threshold = 1,
StringsOnly = true,
Shuffle = true,
Rotate = true,
LocalWrapperThreshold = 0,
},
},
{ Name = "NumbersToExpressions", Settings = {} },
{ Name = "WrapInFunction", Settings = {} },
},
},
-- Strong obfuscation, high performance loss.
["Strong"] = {
LuaVersion = "Lua51",
VarNamePrefix = "",
NameGenerator = "MangledShuffled",
PrettyPrint = false,
Seed = 0,
Steps = {
{ Name = "Vmify", Settings = {} },
{ Name = "EncryptStrings", Settings = {} },
{
Name = "AntiTamper",
Settings = {
UseDebug = false,
},
},
{ Name = "Vmify", Settings = {} },
{
Name = "ConstantArray",
Settings = {
Threshold = 1,
StringsOnly = true,
Shuffle = true,
Rotate = true,
LocalWrapperThreshold = 0
},
},
{
Name = "NumbersToExpressions",
Settings = {
NumberRepresentationMutaton = true
},
},
{ Name = "WrapInFunction", Settings = {} },
},
},
}
================================================
FILE: src/prometheus/ast.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- ast.lua
--
-- This Script provides the Abstract Syntax Tree (AST) for Prometheus.
local Ast = {}
local AstKind = {
-- Misc
TopNode = "TopNode";
Block = "Block";
-- Statements
ContinueStatement = "ContinueStatement";
BreakStatement = "BreakStatement";
DoStatement = "DoStatement";
WhileStatement = "WhileStatement";
ReturnStatement = "ReturnStatement";
RepeatStatement = "RepeatStatement";
ForInStatement = "ForInStatement";
ForStatement = "ForStatement";
IfStatement = "IfStatement";
FunctionDeclaration = "FunctionDeclaration";
LocalFunctionDeclaration = "LocalFunctionDeclaration";
LocalVariableDeclaration = "LocalVariableDeclaration";
FunctionCallStatement = "FunctionCallStatement";
PassSelfFunctionCallStatement = "PassSelfFunctionCallStatement";
AssignmentStatement = "AssignmentStatement";
-- LuaU Compound Statements
CompoundAddStatement = "CompoundAddStatement";
CompoundSubStatement = "CompoundSubStatement";
CompoundMulStatement = "CompoundMulStatement";
CompoundDivStatement = "CompoundDivStatement";
CompoundModStatement = "CompoundModStatement";
CompoundPowStatement = "CompoundPowStatement";
CompoundConcatStatement = "CompoundConcatStatement";
-- Assignment Index
AssignmentIndexing = "AssignmentIndexing";
AssignmentVariable = "AssignmentVariable";
-- Expression Nodes
BooleanExpression = "BooleanExpression";
NumberExpression = "NumberExpression";
StringExpression = "StringExpression";
NilExpression = "NilExpression";
VarargExpression = "VarargExpression";
OrExpression = "OrExpression";
AndExpression = "AndExpression";
LessThanExpression = "LessThanExpression";
GreaterThanExpression = "GreaterThanExpression";
LessThanOrEqualsExpression = "LessThanOrEqualsExpression";
GreaterThanOrEqualsExpression = "GreaterThanOrEqualsExpression";
NotEqualsExpression = "NotEqualsExpression";
EqualsExpression = "EqualsExpression";
StrCatExpression = "StrCatExpression";
AddExpression = "AddExpression";
SubExpression = "SubExpression";
MulExpression = "MulExpression";
DivExpression = "DivExpression";
ModExpression = "ModExpression";
NotExpression = "NotExpression";
LenExpression = "LenExpression";
NegateExpression = "NegateExpression";
PowExpression = "PowExpression";
IndexExpression = "IndexExpression";
FunctionCallExpression = "FunctionCallExpression";
PassSelfFunctionCallExpression = "PassSelfFunctionCallExpression";
VariableExpression = "VariableExpression";
FunctionLiteralExpression = "FunctionLiteralExpression";
TableConstructorExpression = "TableConstructorExpression";
-- Table Entry
TableEntry = "TableEntry";
KeyedTableEntry = "KeyedTableEntry";
-- Misc
NopStatement = "NopStatement";
IfElseExpression = "IfElseExpression";
}
local astKindExpressionLookup = {
[AstKind.BooleanExpression] = 0;
[AstKind.NumberExpression] = 0;
[AstKind.StringExpression] = 0;
[AstKind.NilExpression] = 0;
[AstKind.VarargExpression] = 0;
[AstKind.OrExpression] = 12;
[AstKind.AndExpression] = 11;
[AstKind.LessThanExpression] = 10;
[AstKind.GreaterThanExpression] = 10;
[AstKind.LessThanOrEqualsExpression] = 10;
[AstKind.GreaterThanOrEqualsExpression] = 10;
[AstKind.NotEqualsExpression] = 10;
[AstKind.EqualsExpression] = 10;
[AstKind.StrCatExpression] = 9;
[AstKind.AddExpression] = 8;
[AstKind.SubExpression] = 8;
[AstKind.MulExpression] = 7;
[AstKind.DivExpression] = 7;
[AstKind.ModExpression] = 7;
[AstKind.NotExpression] = 5;
[AstKind.LenExpression] = 5;
[AstKind.NegateExpression] = 5;
[AstKind.PowExpression] = 4;
[AstKind.IndexExpression] = 1;
[AstKind.AssignmentIndexing] = 1;
[AstKind.FunctionCallExpression] = 2;
[AstKind.PassSelfFunctionCallExpression] = 2;
[AstKind.VariableExpression] = 0;
[AstKind.AssignmentVariable] = 0;
[AstKind.FunctionLiteralExpression] = 3;
[AstKind.TableConstructorExpression] = 3;
}
Ast.AstKind = AstKind;
function Ast.astKindExpressionToNumber(kind)
return astKindExpressionLookup[kind] or 100;
end
function Ast.ConstantNode(val)
if type(val) == "nil" then
return Ast.NilExpression();
end
if type(val) == "string" then
return Ast.StringExpression(val);
end
if type(val) == "number" then
return Ast.NumberExpression(val);
end
if type(val) == "boolean" then
return Ast.BooleanExpression(val);
end
end
function Ast.NopStatement()
return {
kind = AstKind.NopStatement;
}
end
function Ast.IfElseExpression(condition, true_value, false_value)
return {
kind = AstKind.IfElseExpression,
condition = condition,
true_value = true_value,
false_value = false_value
}
end
-- Create Ast Top Node
function Ast.TopNode(body, globalScope)
return {
kind = AstKind.TopNode,
body = body,
globalScope = globalScope,
}
end
function Ast.TableEntry(value)
return {
kind = AstKind.TableEntry,
value = value,
}
end
function Ast.KeyedTableEntry(key, value)
return {
kind = AstKind.KeyedTableEntry,
key = key,
value = value,
}
end
function Ast.TableConstructorExpression(entries)
return {
kind = AstKind.TableConstructorExpression,
entries = entries,
};
end
-- Create Statement Block
function Ast.Block(statements, scope)
return {
kind = AstKind.Block,
statements = statements,
scope = scope,
}
end
-- Create Break Statement
function Ast.BreakStatement(loop, scope)
return {
kind = AstKind.BreakStatement,
loop = loop,
scope = scope,
}
end
-- Create Continue Statement
function Ast.ContinueStatement(loop, scope)
return {
kind = AstKind.ContinueStatement,
loop = loop,
scope = scope,
}
end
function Ast.PassSelfFunctionCallStatement(base, passSelfFunctionName, args)
return {
kind = AstKind.PassSelfFunctionCallStatement,
base = base,
passSelfFunctionName = passSelfFunctionName,
args = args,
}
end
function Ast.AssignmentStatement(lhs, rhs)
if(#lhs < 1) then
print(debug.traceback());
error("Something went wrong!");
end
return {
kind = AstKind.AssignmentStatement,
lhs = lhs,
rhs = rhs,
}
end
function Ast.CompoundAddStatement(lhs, rhs)
return {
kind = AstKind.CompoundAddStatement,
lhs = lhs,
rhs = rhs,
}
end
function Ast.CompoundSubStatement(lhs, rhs)
return {
kind = AstKind.CompoundSubStatement,
lhs = lhs,
rhs = rhs,
}
end
function Ast.CompoundMulStatement(lhs, rhs)
return {
kind = AstKind.CompoundMulStatement,
lhs = lhs,
rhs = rhs,
}
end
function Ast.CompoundDivStatement(lhs, rhs)
return {
kind = AstKind.CompoundDivStatement,
lhs = lhs,
rhs = rhs,
}
end
function Ast.CompoundPowStatement(lhs, rhs)
return {
kind = AstKind.CompoundPowStatement,
lhs = lhs,
rhs = rhs,
}
end
function Ast.CompoundModStatement(lhs, rhs)
return {
kind = AstKind.CompoundModStatement,
lhs = lhs,
rhs = rhs,
}
end
function Ast.CompoundConcatStatement(lhs, rhs)
return {
kind = AstKind.CompoundConcatStatement,
lhs = lhs,
rhs = rhs,
}
end
function Ast.FunctionCallStatement(base, args)
return {
kind = AstKind.FunctionCallStatement,
base = base,
args = args,
}
end
function Ast.ReturnStatement(args)
return {
kind = AstKind.ReturnStatement,
args = args,
}
end
function Ast.DoStatement(body)
return {
kind = AstKind.DoStatement,
body = body,
}
end
function Ast.WhileStatement(body, condition, parentScope)
return {
kind = AstKind.WhileStatement,
body = body,
condition = condition,
parentScope = parentScope,
}
end
function Ast.ForInStatement(scope, vars, expressions, body, parentScope)
return {
kind = AstKind.ForInStatement,
scope = scope,
ids = vars,
vars = vars,
expressions = expressions,
body = body,
parentScope = parentScope,
}
end
function Ast.ForStatement(scope, id, initialValue, finalValue, incrementBy, body, parentScope)
return {
kind = AstKind.ForStatement,
scope = scope,
id = id,
initialValue = initialValue,
finalValue = finalValue,
incrementBy = incrementBy,
body = body,
parentScope = parentScope,
}
end
function Ast.RepeatStatement(condition, body, parentScope)
return {
kind = AstKind.RepeatStatement,
body = body,
condition = condition,
parentScope = parentScope,
}
end
function Ast.IfStatement(condition, body, elseifs, elsebody)
return {
kind = AstKind.IfStatement,
condition = condition,
body = body,
elseifs = elseifs,
elsebody = elsebody,
}
end
function Ast.FunctionDeclaration(scope, id, indices, args, body)
return {
kind = AstKind.FunctionDeclaration,
scope = scope,
baseScope = scope,
id = id,
baseId = id,
indices = indices,
args = args,
body = body,
getName = function(self)
return self.scope:getVariableName(self.id);
end,
}
end
function Ast.LocalFunctionDeclaration(scope, id, args, body)
return {
kind = AstKind.LocalFunctionDeclaration,
scope = scope,
id = id,
args = args,
body = body,
getName = function(self)
return self.scope:getVariableName(self.id);
end,
}
end
function Ast.LocalVariableDeclaration(scope, ids, expressions)
return {
kind = AstKind.LocalVariableDeclaration,
scope = scope,
ids = ids,
expressions = expressions,
}
end
function Ast.VarargExpression()
return {
kind = AstKind.VarargExpression;
isConstant = false,
}
end
function Ast.BooleanExpression(value)
return {
kind = AstKind.BooleanExpression,
isConstant = true,
value = value,
}
end
function Ast.NilExpression()
return {
kind = AstKind.NilExpression,
isConstant = true,
value = nil,
}
end
function Ast.NumberExpression(value)
return {
kind = AstKind.NumberExpression,
isConstant = true,
value = value,
}
end
function Ast.StringExpression(value)
return {
kind = AstKind.StringExpression,
isConstant = true,
value = value,
}
end
function Ast.OrExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value or rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.OrExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.AndExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value and rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.AndExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.LessThanExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value < rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.LessThanExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.GreaterThanExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value > rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.GreaterThanExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.LessThanOrEqualsExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value <= rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.LessThanOrEqualsExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.GreaterThanOrEqualsExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value >= rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.GreaterThanOrEqualsExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.NotEqualsExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value ~= rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.NotEqualsExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.EqualsExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value == rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.EqualsExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.StrCatExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value .. rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.StrCatExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.AddExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value + rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.AddExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.SubExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value - rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.SubExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.MulExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value * rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.MulExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.DivExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant and rhs.value ~= 0) then
local success, val = pcall(function() return lhs.value / rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.DivExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.ModExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value % rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.ModExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.NotExpression(rhs, simplify)
if(simplify and rhs.isConstant) then
local success, val = pcall(function() return not rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.NotExpression,
rhs = rhs,
isConstant = false,
}
end
function Ast.NegateExpression(rhs, simplify)
if(simplify and rhs.isConstant) then
local success, val = pcall(function() return -rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.NegateExpression,
rhs = rhs,
isConstant = false,
}
end
function Ast.LenExpression(rhs, simplify)
if(simplify and rhs.isConstant) then
local success, val = pcall(function() return #rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.LenExpression,
rhs = rhs,
isConstant = false,
}
end
function Ast.PowExpression(lhs, rhs, simplify)
if(simplify and rhs.isConstant and lhs.isConstant) then
local success, val = pcall(function() return lhs.value ^ rhs.value end);
if success then
return Ast.ConstantNode(val);
end
end
return {
kind = AstKind.PowExpression,
lhs = lhs,
rhs = rhs,
isConstant = false,
}
end
function Ast.IndexExpression(base, index)
return {
kind = AstKind.IndexExpression,
base = base,
index = index,
isConstant = false,
}
end
function Ast.AssignmentIndexing(base, index)
return {
kind = AstKind.AssignmentIndexing,
base = base,
index = index,
isConstant = false,
}
end
function Ast.PassSelfFunctionCallExpression(base, passSelfFunctionName, args)
return {
kind = AstKind.PassSelfFunctionCallExpression,
base = base,
passSelfFunctionName = passSelfFunctionName,
args = args,
}
end
function Ast.FunctionCallExpression(base, args)
return {
kind = AstKind.FunctionCallExpression,
base = base,
args = args,
}
end
function Ast.VariableExpression(scope, id)
scope:addReference(id);
return {
kind = AstKind.VariableExpression,
scope = scope,
id = id,
getName = function(self)
return self.scope.getVariableName(self.id);
end,
}
end
function Ast.AssignmentVariable(scope, id)
scope:addReference(id);
return {
kind = AstKind.AssignmentVariable,
scope = scope,
id = id,
getName = function(self)
return self.scope.getVariableName(self.id);
end,
}
end
function Ast.FunctionLiteralExpression(args, body)
return {
kind = AstKind.FunctionLiteralExpression,
args = args,
body = body,
}
end
return Ast;
================================================
FILE: src/prometheus/compiler/block.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- block.lua
--
-- Block management for the compiler
local Scope = require("prometheus.scope");
local util = require("prometheus.util");
local lookupify = util.lookupify;
return function(Compiler)
function Compiler:createBlock()
local id;
repeat
id = math.random(0, 2^24)
until not self.usedBlockIds[id];
self.usedBlockIds[id] = true;
local scope = Scope:new(self.containerFuncScope);
local block = {
id = id;
statements = {};
scope = scope;
advanceToNextBlock = true;
};
table.insert(self.blocks, block);
return block;
end
function Compiler:setActiveBlock(block)
self.activeBlock = block;
end
function Compiler:addStatement(statement, writes, reads, usesUpvals)
if(self.activeBlock.advanceToNextBlock) then
table.insert(self.activeBlock.statements, {
statement = statement,
writes = lookupify(writes),
reads = lookupify(reads),
usesUpvals = usesUpvals or false,
});
end
end
end
================================================
FILE: src/prometheus/compiler/compile_core.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- compile_core.lua
-- This Script contains the core compilation functions: compileTopNode, compileFunction, compileBlock,
-- compileStatement, and compileExpression
local compileTop = require("prometheus.compiler.compile_top");
local statementHandlers = require("prometheus.compiler.statements");
local expressionHandlers = require("prometheus.compiler.expressions");
local Ast = require("prometheus.ast");
local logger = require("logger");
return function(Compiler)
compileTop(Compiler);
function Compiler:compileStatement(statement, funcDepth)
local handler = statementHandlers[statement.kind];
if handler then
handler(self, statement, funcDepth);
return;
end
logger:error(string.format("%s is not a compileable statement!", statement.kind));
end
function Compiler:compileExpression(expression, funcDepth, numReturns)
local handler = expressionHandlers[expression.kind];
if handler then
return handler(self, expression, funcDepth, numReturns);
end
logger:error(string.format("%s is not an compliable expression!", expression.kind));
end
end
================================================
FILE: src/prometheus/compiler/compile_top.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- compile_top.lua
--
-- This Script contains the compilation of the top node, function, and block.
local Ast = require("prometheus.ast");
local util = require("prometheus.util");
local visitast = require("prometheus.visitast");
local lookupify = util.lookupify;
local AstKind = Ast.AstKind;
return function(Compiler)
function Compiler:compileTopNode(node)
local startBlock = self:createBlock();
local scope = startBlock.scope;
self.startBlockId = startBlock.id;
self:setActiveBlock(startBlock);
local varAccessLookup = lookupify{
AstKind.AssignmentVariable,
AstKind.VariableExpression,
AstKind.FunctionDeclaration,
AstKind.LocalFunctionDeclaration,
}
local functionLookup = lookupify{
AstKind.FunctionDeclaration,
AstKind.LocalFunctionDeclaration,
AstKind.FunctionLiteralExpression,
AstKind.TopNode,
}
visitast(node, function(node, data)
if node.kind == AstKind.Block then
node.scope.__depth = data.functionData.depth;
end
if varAccessLookup[node.kind] then
if not node.scope.isGlobal then
if node.scope.__depth < data.functionData.depth then
if not self:isUpvalue(node.scope, node.id) then
self:makeUpvalue(node.scope, node.id);
end
end
end
end
end, nil, nil)
self.varargReg = self:allocRegister(true);
scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar);
scope:addReferenceToHigherScope(self.scope, self.selectVar);
scope:addReferenceToHigherScope(self.scope, self.unpackVar);
self:addStatement(self:setRegister(scope, self.varargReg, Ast.VariableExpression(self.containerFuncScope, self.argsVar)), {self.varargReg}, {}, false);
self:compileBlock(node.body, 0);
if(self.activeBlock.advanceToNextBlock) then
self:addStatement(self:setPos(self.activeBlock.scope, nil), {self.POS_REGISTER}, {}, false);
self:addStatement(self:setReturn(self.activeBlock.scope, Ast.TableConstructorExpression({})), {self.RETURN_REGISTER}, {}, false)
self.activeBlock.advanceToNextBlock = false;
end
self:resetRegisters();
end
function Compiler:compileFunction(node, funcDepth)
funcDepth = funcDepth + 1;
local oldActiveBlock = self.activeBlock;
local upperVarargReg = self.varargReg;
self.varargReg = nil;
local upvalueExpressions = {};
local upvalueIds = {};
local usedRegs = {};
local oldGetUpvalueId = self.getUpvalueId;
self.getUpvalueId = function(self, scope, id)
if(not upvalueIds[scope]) then
upvalueIds[scope] = {};
end
if(upvalueIds[scope][id]) then
return upvalueIds[scope][id];
end
local scopeFuncDepth = self.scopeFunctionDepths[scope];
local expression;
if(scopeFuncDepth == funcDepth) then
oldActiveBlock.scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction);
expression = Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {});
elseif(scopeFuncDepth == funcDepth - 1) then
local varReg = self:getVarRegister(scope, id, scopeFuncDepth, nil);
expression = self:register(oldActiveBlock.scope, varReg);
table.insert(usedRegs, varReg);
else
local higherId = oldGetUpvalueId(self, scope, id);
oldActiveBlock.scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar);
expression = Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(higherId));
end
table.insert(upvalueExpressions, Ast.TableEntry(expression));
local uid = #upvalueExpressions;
upvalueIds[scope][id] = uid;
return uid;
end
local block = self:createBlock();
self:setActiveBlock(block);
local scope = self.activeBlock.scope;
self:pushRegisterUsageInfo();
for i, arg in ipairs(node.args) do
if(arg.kind == AstKind.VariableExpression) then
if(self:isUpvalue(arg.scope, arg.id)) then
scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction);
local argReg = self:getVarRegister(arg.scope, arg.id, funcDepth, nil);
self:addStatement(self:setRegister(scope, argReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {argReg}, {}, false);
self:addStatement(self:setUpvalueMember(scope, self:register(scope, argReg), Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.argsVar), Ast.NumberExpression(i))), {}, {argReg}, true);
else
local argReg = self:getVarRegister(arg.scope, arg.id, funcDepth, nil);
scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar);
self:addStatement(self:setRegister(scope, argReg, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.argsVar), Ast.NumberExpression(i))), {argReg}, {}, false);
end
else
self.varargReg = self:allocRegister(true);
scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar);
scope:addReferenceToHigherScope(self.scope, self.selectVar);
scope:addReferenceToHigherScope(self.scope, self.unpackVar);
self:addStatement(self:setRegister(scope, self.varargReg, Ast.TableConstructorExpression({
Ast.TableEntry(Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.selectVar), {
Ast.NumberExpression(i);
Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.unpackVar), {
Ast.VariableExpression(self.containerFuncScope, self.argsVar),
});
})),
})), {self.varargReg}, {}, false);
end
end
self:compileBlock(node.body, funcDepth);
if(self.activeBlock.advanceToNextBlock) then
self:addStatement(self:setPos(self.activeBlock.scope, nil), {self.POS_REGISTER}, {}, false);
self:addStatement(self:setReturn(self.activeBlock.scope, Ast.TableConstructorExpression({})), {self.RETURN_REGISTER}, {}, false);
self.activeBlock.advanceToNextBlock = false;
end
if(self.varargReg) then
self:freeRegister(self.varargReg, true);
end
self.varargReg = upperVarargReg;
self.getUpvalueId = oldGetUpvalueId;
self:popRegisterUsageInfo();
self:setActiveBlock(oldActiveBlock);
local scope = self.activeBlock.scope;
local retReg = self:allocRegister(false);
local isVarargFunction = #node.args > 0 and node.args[#node.args].kind == AstKind.VarargExpression;
local retrieveExpression
if isVarargFunction then
scope:addReferenceToHigherScope(self.scope, self.createVarargClosureVar);
retrieveExpression = Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.createVarargClosureVar), {
Ast.NumberExpression(block.id),
Ast.TableConstructorExpression(upvalueExpressions)
});
else
local varScope, var = self:getCreateClosureVar(#node.args + math.random(0, 5));
scope:addReferenceToHigherScope(varScope, var);
retrieveExpression = Ast.FunctionCallExpression(Ast.VariableExpression(varScope, var), {
Ast.NumberExpression(block.id),
Ast.TableConstructorExpression(upvalueExpressions)
});
end
self:addStatement(self:setRegister(scope, retReg, retrieveExpression), {retReg}, usedRegs, false);
return retReg;
end
function Compiler:compileBlock(block, funcDepth)
for i, stat in ipairs(block.statements) do
self:compileStatement(stat, funcDepth);
end
local scope = self.activeBlock.scope;
for id, name in ipairs(block.scope.variables) do
local varReg = self:getVarRegister(block.scope, id, funcDepth, nil);
if self:isUpvalue(block.scope, id) then
scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc);
self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), {
self:register(scope, varReg)
})), {varReg}, {varReg}, false);
else
self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), {varReg}, {}, false);
end
self:freeRegister(varReg, true);
end
end
end
================================================
FILE: src/prometheus/compiler/compiler.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- compiler.lua
--
-- This Script is the main compiler module.
local Ast = require("prometheus.ast");
local Scope = require("prometheus.scope");
local util = require("prometheus.util");
local lookupify = util.lookupify;
local AstKind = Ast.AstKind;
local unpack = unpack or table.unpack;
local blockModule = require("prometheus.compiler.block");
local registerModule = require("prometheus.compiler.register");
local upvalueModule = require("prometheus.compiler.upvalue");
local emitModule = require("prometheus.compiler.emit");
local compileCoreModule = require("prometheus.compiler.compile_core");
local Compiler = {};
function Compiler:new()
local compiler = {
blocks = {};
registers = {};
activeBlock = nil;
registersForVar = {};
usedRegisters = 0;
maxUsedRegister = 0;
registerVars = {};
VAR_REGISTER = newproxy(false);
RETURN_ALL = newproxy(false);
POS_REGISTER = newproxy(false);
RETURN_REGISTER = newproxy(false);
UPVALUE = newproxy(false);
BIN_OPS = lookupify{
AstKind.LessThanExpression,
AstKind.GreaterThanExpression,
AstKind.LessThanOrEqualsExpression,
AstKind.GreaterThanOrEqualsExpression,
AstKind.NotEqualsExpression,
AstKind.EqualsExpression,
AstKind.StrCatExpression,
AstKind.AddExpression,
AstKind.SubExpression,
AstKind.MulExpression,
AstKind.DivExpression,
AstKind.ModExpression,
AstKind.PowExpression,
};
};
setmetatable(compiler, self);
self.__index = self;
return compiler;
end
blockModule(Compiler);
registerModule(Compiler);
upvalueModule(Compiler);
emitModule(Compiler);
compileCoreModule(Compiler);
function Compiler:pushRegisterUsageInfo()
table.insert(self.registerUsageStack, {
usedRegisters = self.usedRegisters;
registers = self.registers;
});
self.usedRegisters = 0;
self.registers = {};
end
function Compiler:popRegisterUsageInfo()
local info = table.remove(self.registerUsageStack);
self.usedRegisters = info.usedRegisters;
self.registers = info.registers;
end
function Compiler:compile(ast)
self.blocks = {};
self.registers = {};
self.activeBlock = nil;
self.registersForVar = {};
self.scopeFunctionDepths = {};
self.maxUsedRegister = 0;
self.usedRegisters = 0;
self.registerVars = {};
self.usedBlockIds = {};
self.upvalVars = {};
self.registerUsageStack = {};
self.upvalsProxyLenReturn = math.random(-2^22, 2^22);
local newGlobalScope = Scope:newGlobal();
local psc = Scope:new(newGlobalScope, nil);
local _, getfenvVar = newGlobalScope:resolve("getfenv");
local _, tableVar = newGlobalScope:resolve("table");
local _, unpackVar = newGlobalScope:resolve("unpack");
local _, envVar = newGlobalScope:resolve("_ENV");
local _, newproxyVar = newGlobalScope:resolve("newproxy");
local _, setmetatableVar = newGlobalScope:resolve("setmetatable");
local _, getmetatableVar = newGlobalScope:resolve("getmetatable");
local _, selectVar = newGlobalScope:resolve("select");
psc:addReferenceToHigherScope(newGlobalScope, getfenvVar, 2);
psc:addReferenceToHigherScope(newGlobalScope, tableVar);
psc:addReferenceToHigherScope(newGlobalScope, unpackVar);
psc:addReferenceToHigherScope(newGlobalScope, envVar);
psc:addReferenceToHigherScope(newGlobalScope, newproxyVar);
psc:addReferenceToHigherScope(newGlobalScope, setmetatableVar);
psc:addReferenceToHigherScope(newGlobalScope, getmetatableVar);
self.scope = Scope:new(psc);
self.envVar = self.scope:addVariable();
self.containerFuncVar = self.scope:addVariable();
self.unpackVar = self.scope:addVariable();
self.newproxyVar = self.scope:addVariable();
self.setmetatableVar = self.scope:addVariable();
self.getmetatableVar = self.scope:addVariable();
self.selectVar = self.scope:addVariable();
local argVar = self.scope:addVariable();
self.containerFuncScope = Scope:new(self.scope);
self.whileScope = Scope:new(self.containerFuncScope);
self.posVar = self.containerFuncScope:addVariable();
self.argsVar = self.containerFuncScope:addVariable();
self.currentUpvaluesVar = self.containerFuncScope:addVariable();
self.detectGcCollectVar = self.containerFuncScope:addVariable();
self.returnVar = self.containerFuncScope:addVariable();
self.upvaluesTable = self.scope:addVariable();
self.upvaluesReferenceCountsTable = self.scope:addVariable();
self.allocUpvalFunction = self.scope:addVariable();
self.currentUpvalId = self.scope:addVariable();
self.upvaluesProxyFunctionVar = self.scope:addVariable();
self.upvaluesGcFunctionVar = self.scope:addVariable();
self.freeUpvalueFunc = self.scope:addVariable();
self.createClosureVars = {};
self.createVarargClosureVar = self.scope:addVariable();
local createClosureScope = Scope:new(self.scope);
local createClosurePosArg = createClosureScope:addVariable();
local createClosureUpvalsArg = createClosureScope:addVariable();
local createClosureProxyObject = createClosureScope:addVariable();
local createClosureFuncVar = createClosureScope:addVariable();
local createClosureSubScope = Scope:new(createClosureScope);
local upvalEntries = {};
local upvalueIds = {};
self.getUpvalueId = function(self, scope, id)
local expression;
local scopeFuncDepth = self.scopeFunctionDepths[scope];
if(scopeFuncDepth == 0) then
if upvalueIds[id] then
return upvalueIds[id];
end
expression = Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {});
else
require("logger"):error("Unresolved Upvalue, this error should not occur!");
end
table.insert(upvalEntries, Ast.TableEntry(expression));
local uid = #upvalEntries;
upvalueIds[id] = uid;
return uid;
end
createClosureSubScope:addReferenceToHigherScope(self.scope, self.containerFuncVar);
createClosureSubScope:addReferenceToHigherScope(createClosureScope, createClosurePosArg)
createClosureSubScope:addReferenceToHigherScope(createClosureScope, createClosureUpvalsArg, 1)
createClosureScope:addReferenceToHigherScope(self.scope, self.upvaluesProxyFunctionVar)
createClosureSubScope:addReferenceToHigherScope(createClosureScope, createClosureProxyObject);
self:compileTopNode(ast);
local functionNodeAssignments = {
{
var = Ast.AssignmentVariable(self.scope, self.containerFuncVar),
val = Ast.FunctionLiteralExpression({
Ast.VariableExpression(self.containerFuncScope, self.posVar),
Ast.VariableExpression(self.containerFuncScope, self.argsVar),
Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar),
Ast.VariableExpression(self.containerFuncScope, self.detectGcCollectVar)
}, self:emitContainerFuncBody());
}, {
var = Ast.AssignmentVariable(self.scope, self.createVarargClosureVar),
val = Ast.FunctionLiteralExpression({
Ast.VariableExpression(createClosureScope, createClosurePosArg),
Ast.VariableExpression(createClosureScope, createClosureUpvalsArg),
},
Ast.Block({
Ast.LocalVariableDeclaration(createClosureScope, {
createClosureProxyObject
}, {
Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.upvaluesProxyFunctionVar), {
Ast.VariableExpression(createClosureScope, createClosureUpvalsArg)
})
}),
Ast.LocalVariableDeclaration(createClosureScope, {createClosureFuncVar},{
Ast.FunctionLiteralExpression({
Ast.VarargExpression();
},
Ast.Block({
Ast.ReturnStatement{
Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.containerFuncVar), {
Ast.VariableExpression(createClosureScope, createClosurePosArg),
Ast.TableConstructorExpression({Ast.TableEntry(Ast.VarargExpression())}),
Ast.VariableExpression(createClosureScope, createClosureUpvalsArg),
Ast.VariableExpression(createClosureScope, createClosureProxyObject)
})
}
}, createClosureSubScope)
);
});
Ast.ReturnStatement{Ast.VariableExpression(createClosureScope, createClosureFuncVar)};
}, createClosureScope)
);
}, {
var = Ast.AssignmentVariable(self.scope, self.upvaluesTable),
val = Ast.TableConstructorExpression({}),
}, {
var = Ast.AssignmentVariable(self.scope, self.upvaluesReferenceCountsTable),
val = Ast.TableConstructorExpression({}),
}, {
var = Ast.AssignmentVariable(self.scope, self.allocUpvalFunction),
val = self:createAllocUpvalFunction(),
}, {
var = Ast.AssignmentVariable(self.scope, self.currentUpvalId),
val = Ast.NumberExpression(0),
}, {
var = Ast.AssignmentVariable(self.scope, self.upvaluesProxyFunctionVar),
val = self:createUpvaluesProxyFunc(),
}, {
var = Ast.AssignmentVariable(self.scope, self.upvaluesGcFunctionVar),
val = self:createUpvaluesGcFunc(),
}, {
var = Ast.AssignmentVariable(self.scope, self.freeUpvalueFunc),
val = self:createFreeUpvalueFunc(),
},
}
local tbl = {
Ast.VariableExpression(self.scope, self.containerFuncVar),
Ast.VariableExpression(self.scope, self.createVarargClosureVar),
Ast.VariableExpression(self.scope, self.upvaluesTable),
Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable),
Ast.VariableExpression(self.scope, self.allocUpvalFunction),
Ast.VariableExpression(self.scope, self.currentUpvalId),
Ast.VariableExpression(self.scope, self.upvaluesProxyFunctionVar),
Ast.VariableExpression(self.scope, self.upvaluesGcFunctionVar),
Ast.VariableExpression(self.scope, self.freeUpvalueFunc),
};
for i, entry in pairs(self.createClosureVars) do
table.insert(functionNodeAssignments, entry);
table.insert(tbl, Ast.VariableExpression(entry.var.scope, entry.var.id));
end
util.shuffle(functionNodeAssignments);
local assignmentStatLhs, assignmentStatRhs = {}, {};
for i, v in ipairs(functionNodeAssignments) do
assignmentStatLhs[i] = v.var;
assignmentStatRhs[i] = v.val;
end
-- NEW: Position Shuffler
local ids = util.shuffle({1, 2, 3, 4, 5, 6, 7});
local items = {
Ast.VariableExpression(self.scope, self.envVar),
Ast.VariableExpression(self.scope, self.unpackVar),
Ast.VariableExpression(self.scope, self.newproxyVar),
Ast.VariableExpression(self.scope, self.setmetatableVar),
Ast.VariableExpression(self.scope, self.getmetatableVar),
Ast.VariableExpression(self.scope, self.selectVar),
Ast.VariableExpression(self.scope, argVar),
}
local astItems = {
Ast.OrExpression(Ast.AndExpression(Ast.VariableExpression(newGlobalScope, getfenvVar), Ast.FunctionCallExpression(Ast.VariableExpression(newGlobalScope, getfenvVar), {})), Ast.VariableExpression(newGlobalScope, envVar));
Ast.OrExpression(Ast.VariableExpression(newGlobalScope, unpackVar), Ast.IndexExpression(Ast.VariableExpression(newGlobalScope, tableVar), Ast.StringExpression("unpack")));
Ast.VariableExpression(newGlobalScope, newproxyVar);
Ast.VariableExpression(newGlobalScope, setmetatableVar);
Ast.VariableExpression(newGlobalScope, getmetatableVar);
Ast.VariableExpression(newGlobalScope, selectVar);
Ast.TableConstructorExpression({
Ast.TableEntry(Ast.VarargExpression());
})
}
local functionNode = Ast.FunctionLiteralExpression({
items[ids[1]], items[ids[2]], items[ids[3]], items[ids[4]],
items[ids[5]], items[ids[6]], items[ids[7]],
unpack(util.shuffle(tbl))
}, Ast.Block({
Ast.AssignmentStatement(assignmentStatLhs, assignmentStatRhs);
Ast.ReturnStatement{
Ast.FunctionCallExpression(Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.createVarargClosureVar), {
Ast.NumberExpression(self.startBlockId);
Ast.TableConstructorExpression(upvalEntries);
}), {Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.unpackVar), {Ast.VariableExpression(self.scope, argVar)})});
}
}, self.scope));
return Ast.TopNode(Ast.Block({
Ast.ReturnStatement{Ast.FunctionCallExpression(functionNode, {
astItems[ids[1]], astItems[ids[2]], astItems[ids[3]], astItems[ids[4]],
astItems[ids[5]], astItems[ids[6]], astItems[ids[7]],
})};
}, psc), newGlobalScope);
end
function Compiler:getCreateClosureVar(argCount)
if not self.createClosureVars[argCount] then
local var = Ast.AssignmentVariable(self.scope, self.scope:addVariable());
local createClosureScope = Scope:new(self.scope);
local createClosureSubScope = Scope:new(createClosureScope);
local createClosurePosArg = createClosureScope:addVariable();
local createClosureUpvalsArg = createClosureScope:addVariable();
local createClosureProxyObject = createClosureScope:addVariable();
local createClosureFuncVar = createClosureScope:addVariable();
createClosureSubScope:addReferenceToHigherScope(self.scope, self.containerFuncVar);
createClosureSubScope:addReferenceToHigherScope(createClosureScope, createClosurePosArg)
createClosureSubScope:addReferenceToHigherScope(createClosureScope, createClosureUpvalsArg, 1)
createClosureScope:addReferenceToHigherScope(self.scope, self.upvaluesProxyFunctionVar)
createClosureSubScope:addReferenceToHigherScope(createClosureScope, createClosureProxyObject);
local argsTb, argsTb2 = {}, {};
for i = 1, argCount do
local arg = createClosureSubScope:addVariable()
argsTb[i] = Ast.VariableExpression(createClosureSubScope, arg);
argsTb2[i] = Ast.TableEntry(Ast.VariableExpression(createClosureSubScope, arg));
end
local val = Ast.FunctionLiteralExpression({
Ast.VariableExpression(createClosureScope, createClosurePosArg),
Ast.VariableExpression(createClosureScope, createClosureUpvalsArg),
}, Ast.Block({
Ast.LocalVariableDeclaration(createClosureScope, {
createClosureProxyObject
}, {
Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.upvaluesProxyFunctionVar), {
Ast.VariableExpression(createClosureScope, createClosureUpvalsArg)
})
}),
Ast.LocalVariableDeclaration(createClosureScope, {createClosureFuncVar},{
Ast.FunctionLiteralExpression(argsTb,
Ast.Block({
Ast.ReturnStatement{
Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.containerFuncVar), {
Ast.VariableExpression(createClosureScope, createClosurePosArg),
Ast.TableConstructorExpression(argsTb2),
Ast.VariableExpression(createClosureScope, createClosureUpvalsArg),
Ast.VariableExpression(createClosureScope, createClosureProxyObject)
})
}
}, createClosureSubScope)
);
});
Ast.ReturnStatement{Ast.VariableExpression(createClosureScope, createClosureFuncVar)}
}, createClosureScope)
);
self.createClosureVars[argCount] = {
var = var,
val = val,
}
end
local var = self.createClosureVars[argCount].var;
return var.scope, var.id;
end
return Compiler;
================================================
FILE: src/prometheus/compiler/constants.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- constants.lua
--
-- This Script contains the compiler constants shared across modules.
return {
MAX_REGS = 100,
MAX_REGS_MUL = 0,
}
================================================
FILE: src/prometheus/compiler/emit.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- emit.lua
--
-- This Script contains the container function body emission for the compiler.
local Ast = require("prometheus.ast");
local Scope = require("prometheus.scope");
local util = require("prometheus.util");
local constants = require("prometheus.compiler.constants");
local AstKind = Ast.AstKind;
local MAX_REGS = constants.MAX_REGS;
return function(Compiler)
local function hasAnyEntries(tbl)
return type(tbl) == "table" and next(tbl) ~= nil;
end
local function unionLookupTables(a, b)
local out = {};
for k, v in pairs(a or {}) do
out[k] = v;
end
for k, v in pairs(b or {}) do
out[k] = v;
end
return out;
end
local function canMergeParallelAssignmentStatements(statA, statB)
if type(statA) ~= "table" or type(statB) ~= "table" then
return false;
end
if statA.usesUpvals or statB.usesUpvals then
return false;
end
local a = statA.statement;
local b = statB.statement;
if type(a) ~= "table" or type(b) ~= "table" then
return false;
end
if a.kind ~= AstKind.AssignmentStatement or b.kind ~= AstKind.AssignmentStatement then
return false;
end
if type(a.lhs) ~= "table" or type(a.rhs) ~= "table" or type(b.lhs) ~= "table" or type(b.rhs) ~= "table" then
return false;
end
if #a.lhs ~= #a.rhs or #b.lhs ~= #b.rhs then
return false;
end
-- Avoid merging vararg/call assignments because they can affect multi-return behavior.
local function hasUnsafeRhs(rhsList)
for _, rhsExpr in ipairs(rhsList) do
if type(rhsExpr) ~= "table" then
return true;
end
local kind = rhsExpr.kind;
if kind == AstKind.FunctionCallExpression or kind == AstKind.PassSelfFunctionCallExpression or kind == AstKind.VarargExpression then
return true;
end
end
return false;
end
if hasUnsafeRhs(a.rhs) or hasUnsafeRhs(b.rhs) then
return false;
end
local aReads = type(statA.reads) == "table" and statA.reads or {};
local aWrites = type(statA.writes) == "table" and statA.writes or {};
local bReads = type(statB.reads) == "table" and statB.reads or {};
local bWrites = type(statB.writes) == "table" and statB.writes or {};
-- Allow merging even if one statement has no writes (e.g., x = o(x) style assignments)
-- Only require that at least one of them has writes
if not hasAnyEntries(aWrites) and not hasAnyEntries(bWrites) then
return false;
end
for r in pairs(aReads) do
if bWrites[r] then
return false;
end
end
for r, b in pairs(aWrites) do
if bWrites[r] or bReads[r] then
return false;
end
end
return true;
end
local function mergeParallelAssignmentStatements(statA, statB)
local lhs = {};
local rhs = {};
local aLhs, bLhs = statA.statement.lhs, statB.statement.lhs;
local aRhs, bRhs = statA.statement.rhs, statB.statement.rhs;
for i = 1, #aLhs do lhs[i] = aLhs[i]; end
for i = 1, #bLhs do lhs[#aLhs + i] = bLhs[i]; end
for i = 1, #aRhs do rhs[i] = aRhs[i]; end
for i = 1, #bRhs do rhs[#aRhs + i] = bRhs[i]; end
return {
statement = Ast.AssignmentStatement(lhs, rhs),
writes = unionLookupTables(statA.writes, statB.writes),
reads = unionLookupTables(statA.reads, statB.reads),
usesUpvals = statA.usesUpvals or statB.usesUpvals,
};
end
local function mergeAdjacentParallelAssignments(blockstats)
local merged = {};
local i = 1;
while i <= #blockstats do
local stat = blockstats[i];
i = i + 1;
while i <= #blockstats and canMergeParallelAssignmentStatements(stat, blockstats[i]) do
stat = mergeParallelAssignmentStatements(stat, blockstats[i]);
i = i + 1;
end
table.insert(merged, stat);
end
return merged;
end
function Compiler:emitContainerFuncBody()
local blocks = {};
util.shuffle(self.blocks);
for i, block in ipairs(self.blocks) do
local id = block.id;
local blockstats = block.statements;
for i = 2, #blockstats do
local stat = blockstats[i];
local reads = stat.reads;
local writes = stat.writes;
local maxShift = 0;
local usesUpvals = stat.usesUpvals;
for shift = 1, i - 1 do
local stat2 = blockstats[i - shift];
if stat2.usesUpvals and usesUpvals then
break;
end
local reads2 = stat2.reads;
local writes2 = stat2.writes;
local f = true;
for r, b in pairs(reads2) do
if(writes[r]) then
f = false;
break;
end
end
if f then
for r, b in pairs(writes2) do
if(writes[r]) then
f = false;
break;
end
if(reads[r]) then
f = false;
break;
end
end
end
if not f then
break
end
maxShift = shift;
end
local shift = math.random(0, maxShift);
for j = 1, shift do
blockstats[i - j], blockstats[i - j + 1] = blockstats[i - j + 1], blockstats[i - j];
end
end
local mergedBlockStats = mergeAdjacentParallelAssignments(blockstats);
for _=1, 7 do
mergedBlockStats = mergeAdjacentParallelAssignments(mergedBlockStats);
end
blockstats = {};
for _, stat in ipairs(mergedBlockStats) do
table.insert(blockstats, stat.statement);
end
local block = { id = id, index = i, block = Ast.Block(blockstats, block.scope) }
table.insert(blocks, block);
blocks[id] = block;
end
table.sort(blocks, function(a, b) return a.id < b.id end);
-- Build a strict threshold condition between adjacent block IDs.
-- Using a midpoint avoids exact-id comparisons while preserving dispatch.
local function buildBlockThresholdCondition(scope, leftId, rightId, useAndOr)
local bound = math.floor((leftId + rightId) / 2);
local posExpr = self:pos(scope);
local boundExpr = Ast.NumberExpression(bound);
if useAndOr then
-- Kept for compatibility with caller variations.
return Ast.LessThanExpression(posExpr, boundExpr);
else
local variant = math.random(1, 2);
if variant == 1 then
return Ast.LessThanExpression(posExpr, boundExpr);
else
return Ast.GreaterThanExpression(boundExpr, posExpr);
end
end
end
-- Build an elseif chain for a range of blocks
local function buildElseifChain(tb, l, r, pScope)
-- Handle invalid range by returning an empty block
if r < l then
local emptyScope = Scope:new(pScope);
return Ast.Block({}, emptyScope);
end
local len = r - l + 1;
-- For single block
if len == 1 then
tb[l].block.scope:setParent(pScope);
return tb[l].block;
end
-- For small ranges, use elseif chain
if len <= 4 then
local ifScope = Scope:new(pScope);
local elseifs = {};
-- First block uses the first midpoint threshold
tb[l].block.scope:setParent(ifScope);
local firstCondition = buildBlockThresholdCondition(ifScope, tb[l].id, tb[l + 1].id, false);
local firstBlock = tb[l].block;
-- Middle blocks use their upper midpoint threshold
for i = l + 1, r - 1 do
tb[i].block.scope:setParent(ifScope);
local condition = buildBlockThresholdCondition(ifScope, tb[i].id, tb[i + 1].id, false);
table.insert(elseifs, {
condition = condition,
body = tb[i].block
});
end
-- Last block becomes else
tb[r].block.scope:setParent(ifScope);
local elseBlock = tb[r].block;
return Ast.Block({
Ast.IfStatement(firstCondition, firstBlock, elseifs, elseBlock);
}, ifScope);
end
-- For larger ranges, use binary split with and/or chaining
local mid = l + math.ceil(len / 2);
local leftMaxId = tb[mid - 1].id;
local rightMinId = tb[mid].id;
-- Float-safe split: any bound strictly between adjacent IDs works.
-- Midpoint avoids integer-only math.random(min, max) behavior.
local bound = math.floor((leftMaxId + rightMinId) / 2);
local ifScope = Scope:new(pScope);
local lBlock = buildElseifChain(tb, l, mid - 1, ifScope);
local rBlock = buildElseifChain(tb, mid, r, ifScope);
-- Randomly choose between different condition styles
local condStyle = math.random(1, 3);
local condition;
local trueBlock, falseBlock;
if condStyle == 1 then
-- pos < bound
condition = Ast.LessThanExpression(self:pos(ifScope), Ast.NumberExpression(bound));
trueBlock, falseBlock = lBlock, rBlock;
elseif condStyle == 2 then
-- bound > pos
condition = Ast.GreaterThanExpression(Ast.NumberExpression(bound), self:pos(ifScope));
trueBlock, falseBlock = lBlock, rBlock;
else
-- Equivalent split using strict > with branches reversed.
condition = Ast.GreaterThanExpression(self:pos(ifScope), Ast.NumberExpression(bound));
trueBlock, falseBlock = rBlock, lBlock;
end
return Ast.Block({
Ast.IfStatement(condition, trueBlock, {}, falseBlock);
}, ifScope);
end
local whileBody = buildElseifChain(blocks, 1, #blocks, self.containerFuncScope);
if self.whileScope then
-- Ensure whileScope is properly connected
self.whileScope:setParent(self.containerFuncScope);
end
self.whileScope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar, 1);
self.whileScope:addReferenceToHigherScope(self.containerFuncScope, self.posVar);
self.containerFuncScope:addReferenceToHigherScope(self.scope, self.unpackVar);
local declarations = {
self.returnVar,
}
for i, var in pairs(self.registerVars) do
if(i ~= MAX_REGS) then
table.insert(declarations, var);
end
end
local stats = {}
if self.maxUsedRegister >= MAX_REGS then
table.insert(stats, Ast.LocalVariableDeclaration(self.containerFuncScope, {self.registerVars[MAX_REGS]}, {Ast.TableConstructorExpression({})}));
end
table.insert(stats, Ast.LocalVariableDeclaration(self.containerFuncScope, util.shuffle(declarations), {}));
table.insert(stats, Ast.WhileStatement(whileBody, Ast.VariableExpression(self.containerFuncScope, self.posVar)));
table.insert(stats, Ast.AssignmentStatement({
Ast.AssignmentVariable(self.containerFuncScope, self.posVar)
}, {
Ast.LenExpression(Ast.VariableExpression(self.containerFuncScope, self.detectGcCollectVar))
}));
table.insert(stats, Ast.ReturnStatement{
Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.unpackVar), {
Ast.VariableExpression(self.containerFuncScope, self.returnVar)
});
});
return Ast.Block(stats, self.containerFuncScope);
end
end
================================================
FILE: src/prometheus/compiler/expressions/and.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- and.lua
--
-- This Script contains the expression handler for the AndExpression.
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local posState = self.registers[self.POS_REGISTER];
self.registers[self.POS_REGISTER] = self.VAR_REGISTER;
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister();
if i ~= 1 then
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
local resReg = regs[1];
local tmpReg;
if posState then
tmpReg = self:allocRegister(false);
self:addStatement(self:copyRegisters(scope, {tmpReg}, {self.POS_REGISTER}), {tmpReg}, {self.POS_REGISTER}, false);
end
local lhsReg = self:compileExpression(expression.lhs, funcDepth, 1)[1];
if expression.rhs.isConstant then
local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1];
self:addStatement(self:setRegister(scope, resReg, Ast.AndExpression(self:register(scope, lhsReg), self:register(scope, rhsReg))), {resReg}, {lhsReg, rhsReg}, false);
if tmpReg then
self:freeRegister(tmpReg, false);
end
self:freeRegister(lhsReg, false);
self:freeRegister(rhsReg, false);
return regs;
end
local block1, block2 = self:createBlock(), self:createBlock();
self:addStatement(self:copyRegisters(scope, {resReg}, {lhsReg}), {resReg}, {lhsReg}, false);
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, lhsReg), Ast.NumberExpression(block1.id)), Ast.NumberExpression(block2.id))), {self.POS_REGISTER}, {lhsReg}, false);
self:freeRegister(lhsReg, false);
do
self:setActiveBlock(block1);
scope = block1.scope;
local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1];
self:addStatement(self:copyRegisters(scope, {resReg}, {rhsReg}), {resReg}, {rhsReg}, false);
self:freeRegister(rhsReg, false);
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(block2.id)), {self.POS_REGISTER}, {}, false);
end
self.registers[self.POS_REGISTER] = posState;
self:setActiveBlock(block2);
scope = block2.scope;
if tmpReg then
self:addStatement(self:copyRegisters(scope, {self.POS_REGISTER}, {tmpReg}), {self.POS_REGISTER}, {tmpReg}, false);
self:freeRegister(tmpReg, false);
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/binary.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- binary.lua
--
-- This Script contains the expression handler for the Binary operations (Add, Sub, Mul, Div, etc.).
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister();
if i == 1 then
local lhsReg = self:compileExpression(expression.lhs, funcDepth, 1)[1];
local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1];
local binaryExpr = Ast[expression.kind](self:register(scope, lhsReg), self:register(scope, rhsReg));
self:addStatement(self:setRegister(scope, regs[i], binaryExpr), {regs[i]}, {lhsReg, rhsReg}, true);
self:freeRegister(rhsReg, false);
self:freeRegister(lhsReg, false);
else
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/boolean.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- boolean.lua
--
-- This Script contains the expression handler for the BooleanExpression.
local Ast = require("prometheus.ast");
local expressionEvaluators = {
[Ast.GreaterThanExpression] = function(left, right)
return left > right
end,
[Ast.LessThanExpression] = function(left, right)
return left < right
end,
[Ast.GreaterThanOrEqualsExpression] = function(left, right)
return left >= right
end,
[Ast.LessThanOrEqualsExpression] = function(left, right)
return left <= right
end,
[Ast.NotEqualsExpression] = function(left, right)
return left ~= right
end,
}
local function createRandomASTCFlowExpression(resultBool)
local expTB = {
Ast.GreaterThanExpression,
Ast.LessThanExpression,
Ast.GreaterThanOrEqualsExpression,
Ast.LessThanOrEqualsExpression,
Ast.NotEqualsExpression
}
local leftInt, rightInt, boolResult, randomExp
repeat
randomExp = expTB[math.random(1, #expTB)]
leftInt = Ast.NumberExpression(math.random(1, 2^24))
rightInt = Ast.NumberExpression(math.random(1, 2^24))
boolResult = expressionEvaluators[randomExp](leftInt.value, rightInt.value)
until boolResult == resultBool
return randomExp(leftInt, rightInt, false)
end
return function(self, expression, _, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister();
if i == 1 then
self:addStatement(self:setRegister(scope, regs[i], createRandomASTCFlowExpression(expression.value)), {regs[i]}, {}, false);
else
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/function_call.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- function_call.lua
--
-- This Script contains the expression handler for the FunctionCallExpression.
local Ast = require("prometheus.ast");
local AstKind = Ast.AstKind;
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local baseReg = self:compileExpression(expression.base, funcDepth, 1)[1];
local retRegs = {};
local returnAll = numReturns == self.RETURN_ALL;
if returnAll then
retRegs[1] = self:allocRegister(false);
else
for i = 1, numReturns do
retRegs[i] = self:allocRegister(false);
end
end
local regs = {};
local args = {};
for i, expr in ipairs(expression.args) do
if i == #expression.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then
local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1];
table.insert(args, Ast.FunctionCallExpression(
self:unpack(scope),
{self:register(scope, reg)}));
table.insert(regs, reg);
else
local reg = self:compileExpression(expr, funcDepth, 1)[1];
table.insert(args, self:register(scope, reg));
table.insert(regs, reg);
end
end
if returnAll then
self:addStatement(self:setRegister(scope, retRegs[1], Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, baseReg), args))}), {retRegs[1]}, {baseReg, unpack(regs)}, true);
else
if numReturns > 1 then
local tmpReg = self:allocRegister(false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, baseReg), args))}), {tmpReg}, {baseReg, unpack(regs)}, true);
for i, reg in ipairs(retRegs) do
self:addStatement(self:setRegister(scope, reg, Ast.IndexExpression(self:register(scope, tmpReg), Ast.NumberExpression(i))), {reg}, {tmpReg}, false);
end
self:freeRegister(tmpReg, false);
else
self:addStatement(self:setRegister(scope, retRegs[1], Ast.FunctionCallExpression(self:register(scope, baseReg), args)), {retRegs[1]}, {baseReg, unpack(regs)}, true);
end
end
self:freeRegister(baseReg, false);
for i, reg in ipairs(regs) do
self:freeRegister(reg, false);
end
return retRegs;
end;
================================================
FILE: src/prometheus/compiler/expressions/function_literal.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- function_literal.lua
--
-- This Script contains the expression handler for the FunctionLiteralExpression
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns do
if i == 1 then
regs[i] = self:compileFunction(expression, funcDepth);
else
regs[i] = self:allocRegister();
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/index.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- index.lua
--
-- This Script contains the expression handler for the IndexExpression.
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister();
if i == 1 then
local baseReg = self:compileExpression(expression.base, funcDepth, 1)[1];
local indexReg = self:compileExpression(expression.index, funcDepth, 1)[1];
self:addStatement(self:setRegister(scope, regs[i], Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, indexReg))), {regs[i]}, {baseReg, indexReg}, true);
self:freeRegister(baseReg, false);
self:freeRegister(indexReg, false);
else
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/len.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- len.lua
--
-- This Script contains the expression handler for the LenExpression
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister();
if i == 1 then
local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1];
self:addStatement(self:setRegister(scope, regs[i], Ast.LenExpression(self:register(scope, rhsReg))), {regs[i]}, {rhsReg}, true);
self:freeRegister(rhsReg, false);
else
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/negate.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- negate.lua
--
-- This Script contains the expression handler for the NegateExpression.
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister();
if i == 1 then
local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1];
self:addStatement(self:setRegister(scope, regs[i], Ast.NegateExpression(self:register(scope, rhsReg))), {regs[i]}, {rhsReg}, true);
self:freeRegister(rhsReg, false);
else
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/nil.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- nil.lua
--
-- This Script contains the expression handler for the NilExpression.
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister();
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/not.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- not.lua
--
-- This Script contains the expression handler for the NotExpression.
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister();
if i == 1 then
local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1];
self:addStatement(self:setRegister(scope, regs[i], Ast.NotExpression(self:register(scope, rhsReg))), {regs[i]}, {rhsReg}, false);
self:freeRegister(rhsReg, false);
else
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/number.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- number.lua
--
-- This Script contains the expression handler for the NumberExpression.
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister();
if i == 1 then
self:addStatement(self:setRegister(scope, regs[i], Ast.NumberExpression(expression.value)), {regs[i]}, {}, false);
else
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/or.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- or.lua
--
-- This Script contains the expression handler for the OrExpression.
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local posState = self.registers[self.POS_REGISTER];
self.registers[self.POS_REGISTER] = self.VAR_REGISTER;
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister();
if i ~= 1 then
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
local resReg = regs[1];
local tmpReg;
if posState then
tmpReg = self:allocRegister(false);
self:addStatement(self:copyRegisters(scope, {tmpReg}, {self.POS_REGISTER}), {tmpReg}, {self.POS_REGISTER}, false);
end
local lhsReg = self:compileExpression(expression.lhs, funcDepth, 1)[1];
if expression.rhs.isConstant then
local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1];
self:addStatement(self:setRegister(scope, resReg, Ast.OrExpression(self:register(scope, lhsReg), self:register(scope, rhsReg))), {resReg}, {lhsReg, rhsReg}, false);
if tmpReg then
self:freeRegister(tmpReg, false);
end
self:freeRegister(lhsReg, false);
self:freeRegister(rhsReg, false);
return regs;
end
local block1, block2 = self:createBlock(), self:createBlock();
self:addStatement(self:copyRegisters(scope, {resReg}, {lhsReg}), {resReg}, {lhsReg}, false);
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, lhsReg), Ast.NumberExpression(block2.id)), Ast.NumberExpression(block1.id))), {self.POS_REGISTER}, {lhsReg}, false);
self:freeRegister(lhsReg, false);
do
self:setActiveBlock(block1);
local scope = block1.scope;
local rhsReg = self:compileExpression(expression.rhs, funcDepth, 1)[1];
self:addStatement(self:copyRegisters(scope, {resReg}, {rhsReg}), {resReg}, {rhsReg}, false);
self:freeRegister(rhsReg, false);
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(block2.id)), {self.POS_REGISTER}, {}, false);
end
self.registers[self.POS_REGISTER] = posState;
self:setActiveBlock(block2);
scope = block2.scope;
if tmpReg then
self:addStatement(self:copyRegisters(scope, {self.POS_REGISTER}, {tmpReg}), {self.POS_REGISTER}, {tmpReg}, false);
self:freeRegister(tmpReg, false);
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/pass_self_function_call.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- pass_self_function_call.lua
--
-- This Script contains the expression handler for the PassSelfFunctionCallExpression.
local Ast = require("prometheus.ast");
local AstKind = Ast.AstKind;
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local baseReg = self:compileExpression(expression.base, funcDepth, 1)[1];
local retRegs = {};
local returnAll = numReturns == self.RETURN_ALL;
if returnAll then
retRegs[1] = self:allocRegister(false);
else
for i = 1, numReturns do
retRegs[i] = self:allocRegister(false);
end
end
local args = { self:register(scope, baseReg) };
local regs = { baseReg };
for i, expr in ipairs(expression.args) do
if i == #expression.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then
local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1];
table.insert(args, Ast.FunctionCallExpression(
self:unpack(scope),
{self:register(scope, reg)}));
table.insert(regs, reg);
else
local reg = self:compileExpression(expr, funcDepth, 1)[1];
table.insert(args, self:register(scope, reg));
table.insert(regs, reg);
end
end
if returnAll or numReturns > 1 then
local tmpReg = self:allocRegister(false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(expression.passSelfFunctionName)), {tmpReg}, {}, false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, tmpReg))), {tmpReg}, {baseReg, tmpReg}, false);
if returnAll then
self:addStatement(self:setRegister(scope, retRegs[1], Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, tmpReg), args))}), {retRegs[1]}, {tmpReg, unpack(regs)}, true);
else
self:addStatement(self:setRegister(scope, tmpReg, Ast.TableConstructorExpression{Ast.TableEntry(Ast.FunctionCallExpression(self:register(scope, tmpReg), args))}), {tmpReg}, {tmpReg, unpack(regs)}, true);
for i, reg in ipairs(retRegs) do
self:addStatement(self:setRegister(scope, reg, Ast.IndexExpression(self:register(scope, tmpReg), Ast.NumberExpression(i))), {reg}, {tmpReg}, false);
end
end
self:freeRegister(tmpReg, false);
else
local tmpReg = retRegs[1] or self:allocRegister(false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(expression.passSelfFunctionName)), {tmpReg}, {}, false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, tmpReg))), {tmpReg}, {baseReg, tmpReg}, false);
self:addStatement(self:setRegister(scope, retRegs[1], Ast.FunctionCallExpression(self:register(scope, tmpReg), args)), {retRegs[1]}, {baseReg, unpack(regs)}, true);
end
for i, reg in ipairs(regs) do
self:freeRegister(reg, false);
end
return retRegs;
end;
================================================
FILE: src/prometheus/compiler/expressions/string.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- string.lua
--
-- This Script contains the expression handler for the StringExpression.
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns, 1 do
regs[i] = self:allocRegister();
if i == 1 then
self:addStatement(self:setRegister(scope, regs[i], Ast.StringExpression(expression.value)), {regs[i]}, {}, false);
else
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/table_constructor.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- table_constructor.lua
--
-- This Script contains the expression handler for the TableConstructorExpression.
local Ast = require("prometheus.ast");
local AstKind = Ast.AstKind;
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister();
if i == 1 then
local entries = {};
local entryRegs = {};
for i, entry in ipairs(expression.entries) do
if entry.kind == AstKind.TableEntry then
local value = entry.value;
if i == #expression.entries and (value.kind == AstKind.FunctionCallExpression or value.kind == AstKind.PassSelfFunctionCallExpression or value.kind == AstKind.VarargExpression) then
local reg = self:compileExpression(entry.value, funcDepth, self.RETURN_ALL)[1];
table.insert(entries, Ast.TableEntry(Ast.FunctionCallExpression(
self:unpack(scope),
{self:register(scope, reg)})));
table.insert(entryRegs, reg);
else
local reg = self:compileExpression(entry.value, funcDepth, 1)[1];
table.insert(entries, Ast.TableEntry(self:register(scope, reg)));
table.insert(entryRegs, reg);
end
else
local keyReg = self:compileExpression(entry.key, funcDepth, 1)[1];
local valReg = self:compileExpression(entry.value, funcDepth, 1)[1];
table.insert(entries, Ast.KeyedTableEntry(self:register(scope, keyReg), self:register(scope, valReg)));
table.insert(entryRegs, valReg);
table.insert(entryRegs, keyReg);
end
end
self:addStatement(self:setRegister(scope, regs[i], Ast.TableConstructorExpression(entries)), {regs[i]}, entryRegs, false);
for i, reg in ipairs(entryRegs) do
self:freeRegister(reg, false);
end
else
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/vararg.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- vararg.lua
--
-- This Script contains the expression handler for the VarargExpression
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
if numReturns == self.RETURN_ALL then
return {self.varargReg};
end
local regs = {};
for i = 1, numReturns do
regs[i] = self:allocRegister(false);
self:addStatement(self:setRegister(scope, regs[i], Ast.IndexExpression(self:register(scope, self.varargReg), Ast.NumberExpression(i))), {regs[i]}, {self.varargReg}, false);
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions/variable.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- variable.lua
--
-- This Script contains the expression handler for the VariableExpression
local Ast = require("prometheus.ast");
return function(self, expression, funcDepth, numReturns)
local scope = self.activeBlock.scope;
local regs = {};
for i = 1, numReturns do
if i == 1 then
if expression.scope.isGlobal then
regs[i] = self:allocRegister(false);
local tmpReg = self:allocRegister(false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(expression.scope:getVariableName(expression.id))), {tmpReg}, {}, false);
self:addStatement(self:setRegister(scope, regs[i], Ast.IndexExpression(self:env(scope), self:register(scope, tmpReg))), {regs[i]}, {tmpReg}, true);
self:freeRegister(tmpReg, false);
else
if self.scopeFunctionDepths[expression.scope] == funcDepth then
if self:isUpvalue(expression.scope, expression.id) then
local reg = self:allocRegister(false);
local varReg = self:getVarRegister(expression.scope, expression.id, funcDepth, nil);
self:addStatement(self:setRegister(scope, reg, self:getUpvalueMember(scope, self:register(scope, varReg))), {reg}, {varReg}, true);
regs[i] = reg;
else
regs[i] = self:getVarRegister(expression.scope, expression.id, funcDepth, nil);
end
else
local reg = self:allocRegister(false);
local upvalId = self:getUpvalueId(expression.scope, expression.id);
scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar);
self:addStatement(self:setRegister(scope, reg, self:getUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)))), {reg}, {}, true);
regs[i] = reg;
end
end
else
regs[i] = self:allocRegister();
self:addStatement(self:setRegister(scope, regs[i], Ast.NilExpression()), {regs[i]}, {}, false);
end
end
return regs;
end;
================================================
FILE: src/prometheus/compiler/expressions.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- expressions.lua
--
-- This Script contains the expression handlers: exports handler table keyed by AstKind.
local Ast = require("prometheus.ast");
local AstKind = Ast.AstKind;
local handlers = {};
local expressions = "prometheus.compiler.expressions.";
local function requireExpression(name)
return require(expressions .. name);
end
handlers[AstKind.StringExpression] = requireExpression("string");
handlers[AstKind.NumberExpression] = requireExpression("number");
handlers[AstKind.BooleanExpression] = requireExpression("boolean");
handlers[AstKind.NilExpression] = requireExpression("nil");
handlers[AstKind.VariableExpression] = requireExpression("variable");
handlers[AstKind.FunctionCallExpression] = requireExpression("function_call");
handlers[AstKind.PassSelfFunctionCallExpression] = requireExpression("pass_self_function_call");
handlers[AstKind.IndexExpression] = requireExpression("index");
handlers[AstKind.NotExpression] = requireExpression("not");
handlers[AstKind.NegateExpression] = requireExpression("negate");
handlers[AstKind.LenExpression] = requireExpression("len");
handlers[AstKind.OrExpression] = requireExpression("or");
handlers[AstKind.AndExpression] = requireExpression("and");
handlers[AstKind.TableConstructorExpression] = requireExpression("table_constructor");
handlers[AstKind.FunctionLiteralExpression] = requireExpression("function_literal");
handlers[AstKind.VarargExpression] = requireExpression("vararg");
-- Binary ops share one handler
local binaryHandler = requireExpression("binary");
handlers[AstKind.LessThanExpression] = binaryHandler;
handlers[AstKind.GreaterThanExpression] = binaryHandler;
handlers[AstKind.LessThanOrEqualsExpression] = binaryHandler;
handlers[AstKind.GreaterThanOrEqualsExpression] = binaryHandler;
handlers[AstKind.NotEqualsExpression] = binaryHandler;
handlers[AstKind.EqualsExpression] = binaryHandler;
handlers[AstKind.StrCatExpression] = binaryHandler;
handlers[AstKind.AddExpression] = binaryHandler;
handlers[AstKind.SubExpression] = binaryHandler;
handlers[AstKind.MulExpression] = binaryHandler;
handlers[AstKind.DivExpression] = binaryHandler;
handlers[AstKind.ModExpression] = binaryHandler;
handlers[AstKind.PowExpression] = binaryHandler;
return handlers;
================================================
FILE: src/prometheus/compiler/register.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- register.lua
--
-- This Script contains the register management for the compiler.
local Ast = require("prometheus.ast");
local constants = require("prometheus.compiler.constants");
local randomStrings = require("prometheus.randomStrings");
local MAX_REGS = constants.MAX_REGS;
return function(Compiler)
function Compiler:freeRegister(id, force)
if force or not (self.registers[id] == self.VAR_REGISTER) then
self.usedRegisters = self.usedRegisters - 1;
self.registers[id] = false
end
end
function Compiler:isVarRegister(id)
return self.registers[id] == self.VAR_REGISTER;
end
function Compiler:allocRegister(isVar)
self.usedRegisters = self.usedRegisters + 1;
if not isVar then
if not self.registers[self.POS_REGISTER] then
self.registers[self.POS_REGISTER] = true;
return self.POS_REGISTER;
end
if not self.registers[self.RETURN_REGISTER] then
self.registers[self.RETURN_REGISTER] = true;
return self.RETURN_REGISTER;
end
end
local id = 0;
if self.usedRegisters < MAX_REGS * constants.MAX_REGS_MUL then
repeat
id = math.random(1, MAX_REGS - 1);
until not self.registers[id];
else
repeat
id = id + 1;
until not self.registers[id];
end
if id > self.maxUsedRegister then
self.maxUsedRegister = id;
end
if(isVar) then
self.registers[id] = self.VAR_REGISTER;
else
self.registers[id] = true
end
return id;
end
function Compiler:isUpvalue(scope, id)
return self.upvalVars[scope] and self.upvalVars[scope][id];
end
function Compiler:makeUpvalue(scope, id)
if(not self.upvalVars[scope]) then
self.upvalVars[scope] = {}
end
self.upvalVars[scope][id] = true;
end
function Compiler:getVarRegister(scope, id, functionDepth, potentialId)
if(not self.registersForVar[scope]) then
self.registersForVar[scope] = {};
self.scopeFunctionDepths[scope] = functionDepth;
end
local reg = self.registersForVar[scope][id];
if not reg then
if potentialId and self.registers[potentialId] ~= self.VAR_REGISTER and potentialId ~= self.POS_REGISTER and potentialId ~= self.RETURN_REGISTER then
self.registers[potentialId] = self.VAR_REGISTER;
reg = potentialId;
else
reg = self:allocRegister(true);
end
self.registersForVar[scope][id] = reg;
end
return reg;
end
function Compiler:getRegisterVarId(id)
local varId = self.registerVars[id];
if not varId then
varId = self.containerFuncScope:addVariable();
self.registerVars[id] = varId;
end
return varId;
end
function Compiler:register(scope, id)
if id == self.POS_REGISTER then
return self:pos(scope);
end
if id == self.RETURN_REGISTER then
return self:getReturn(scope);
end
if id < MAX_REGS then
local vid = self:getRegisterVarId(id);
scope:addReferenceToHigherScope(self.containerFuncScope, vid);
return Ast.VariableExpression(self.containerFuncScope, vid);
end
local vid = self:getRegisterVarId(MAX_REGS);
scope:addReferenceToHigherScope(self.containerFuncScope, vid);
return Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, vid), Ast.NumberExpression((id - MAX_REGS) + 1));
end
function Compiler:registerList(scope, ids)
local l = {};
for i, id in ipairs(ids) do
table.insert(l, self:register(scope, id));
end
return l;
end
function Compiler:registerAssignment(scope, id)
if id == self.POS_REGISTER then
return self:posAssignment(scope);
end
if id == self.RETURN_REGISTER then
return self:returnAssignment(scope);
end
if id < MAX_REGS then
local vid = self:getRegisterVarId(id);
scope:addReferenceToHigherScope(self.containerFuncScope, vid);
return Ast.AssignmentVariable(self.containerFuncScope, vid);
end
local vid = self:getRegisterVarId(MAX_REGS);
scope:addReferenceToHigherScope(self.containerFuncScope, vid);
return Ast.AssignmentIndexing(Ast.VariableExpression(self.containerFuncScope, vid), Ast.NumberExpression((id - MAX_REGS) + 1));
end
function Compiler:setRegister(scope, id, val, compundArg)
if(compundArg) then
return compundArg(self:registerAssignment(scope, id), val);
end
return Ast.AssignmentStatement({
self:registerAssignment(scope, id)
}, {
val
});
end
function Compiler:setRegisters(scope, ids, vals)
local idStats = {};
for i, id in ipairs(ids) do
table.insert(idStats, self:registerAssignment(scope, id));
end
return Ast.AssignmentStatement(idStats, vals);
end
function Compiler:copyRegisters(scope, to, from)
local idStats = {};
local vals = {};
for i, id in ipairs(to) do
local fromId = from[i];
if(fromId ~= id) then
table.insert(idStats, self:registerAssignment(scope, id));
table.insert(vals, self:register(scope, fromId));
end
end
if(#idStats > 0 and #vals > 0) then
return Ast.AssignmentStatement(idStats, vals);
end
end
function Compiler:resetRegisters()
self.registers = {};
end
function Compiler:pos(scope)
scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar);
return Ast.VariableExpression(self.containerFuncScope, self.posVar);
end
function Compiler:posAssignment(scope)
scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar);
return Ast.AssignmentVariable(self.containerFuncScope, self.posVar);
end
function Compiler:args(scope)
scope:addReferenceToHigherScope(self.containerFuncScope, self.argsVar);
return Ast.VariableExpression(self.containerFuncScope, self.argsVar);
end
function Compiler:unpack(scope)
scope:addReferenceToHigherScope(self.scope, self.unpackVar);
return Ast.VariableExpression(self.scope, self.unpackVar);
end
function Compiler:env(scope)
scope:addReferenceToHigherScope(self.scope, self.envVar);
return Ast.VariableExpression(self.scope, self.envVar);
end
function Compiler:jmp(scope, to)
scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar);
return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.posVar)},{to});
end
function Compiler:setPos(scope, val)
if not val then
local v = Ast.IndexExpression(self:env(scope), randomStrings.randomStringNode(math.random(12, 14)));
scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar);
return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.posVar)}, {v});
end
scope:addReferenceToHigherScope(self.containerFuncScope, self.posVar);
return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.posVar)}, {Ast.NumberExpression(val) or Ast.NilExpression()});
end
function Compiler:setReturn(scope, val)
scope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar);
return Ast.AssignmentStatement({Ast.AssignmentVariable(self.containerFuncScope, self.returnVar)}, {val});
end
function Compiler:getReturn(scope)
scope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar);
return Ast.VariableExpression(self.containerFuncScope, self.returnVar);
end
function Compiler:returnAssignment(scope)
scope:addReferenceToHigherScope(self.containerFuncScope, self.returnVar);
return Ast.AssignmentVariable(self.containerFuncScope, self.returnVar);
end
function Compiler:setUpvalueMember(scope, idExpr, valExpr, compoundConstructor)
scope:addReferenceToHigherScope(self.scope, self.upvaluesTable);
if compoundConstructor then
return compoundConstructor(Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), idExpr), valExpr);
end
return Ast.AssignmentStatement({Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), idExpr)}, {valExpr});
end
function Compiler:getUpvalueMember(scope, idExpr)
scope:addReferenceToHigherScope(self.scope, self.upvaluesTable);
return Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesTable), idExpr);
end
end
================================================
FILE: src/prometheus/compiler/statements/assignment.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- assignment.lua
--
-- This Script contains the statement handler for the AssignmentStatement.
local Ast = require("prometheus.ast");
local AstKind = Ast.AstKind;
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local exprregs = {};
local assignmentIndexingRegs = {};
for i, primaryExpr in ipairs(statement.lhs) do
if(primaryExpr.kind == AstKind.AssignmentIndexing) then
assignmentIndexingRegs [i] = {
base = self:compileExpression(primaryExpr.base, funcDepth, 1)[1],
index = self:compileExpression(primaryExpr.index, funcDepth, 1)[1],
};
end
end
for i, expr in ipairs(statement.rhs) do
if(i == #statement.rhs and #statement.lhs > #statement.rhs) then
local regs = self:compileExpression(expr, funcDepth, #statement.lhs - #statement.rhs + 1);
for i, reg in ipairs(regs) do
if(self:isVarRegister(reg)) then
local ro = reg;
reg = self:allocRegister(false);
self:addStatement(self:copyRegisters(scope, {reg}, {ro}), {reg}, {ro}, false);
end
table.insert(exprregs, reg);
end
else
if statement.lhs[i] or expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression then
local reg = self:compileExpression(expr, funcDepth, 1)[1];
if(self:isVarRegister(reg)) then
local ro = reg;
reg = self:allocRegister(false);
self:addStatement(self:copyRegisters(scope, {reg}, {ro}), {reg}, {ro}, false);
end
table.insert(exprregs, reg);
end
end
end
for i, primaryExpr in ipairs(statement.lhs) do
if primaryExpr.kind == AstKind.AssignmentVariable then
if primaryExpr.scope.isGlobal then
local tmpReg = self:allocRegister(false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(primaryExpr.scope:getVariableName(primaryExpr.id))), {tmpReg}, {}, false);
self:addStatement(Ast.AssignmentStatement({Ast.AssignmentIndexing(self:env(scope), self:register(scope, tmpReg))},
{self:register(scope, exprregs[i])}), {}, {tmpReg, exprregs[i]}, true);
self:freeRegister(tmpReg, false);
else
if self.scopeFunctionDepths[primaryExpr.scope] == funcDepth then
if self:isUpvalue(primaryExpr.scope, primaryExpr.id) then
local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth);
self:addStatement(self:setUpvalueMember(scope, self:register(scope, reg), self:register(scope, exprregs[i])), {}, {reg, exprregs[i]}, true);
else
local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth, exprregs[i]);
if reg ~= exprregs[i] then
self:addStatement(self:setRegister(scope, reg, self:register(scope, exprregs[i])), {reg}, {exprregs[i]}, false);
end
end
else
local upvalId = self:getUpvalueId(primaryExpr.scope, primaryExpr.id);
scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar);
self:addStatement(self:setUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)), self:register(scope, exprregs[i])), {}, {exprregs[i]}, true);
end
end
elseif primaryExpr.kind == AstKind.AssignmentIndexing then
local baseReg = assignmentIndexingRegs[i].base;
local indexReg = assignmentIndexingRegs[i].index;
self:addStatement(Ast.AssignmentStatement({
Ast.AssignmentIndexing(self:register(scope, baseReg), self:register(scope, indexReg))
}, {
self:register(scope, exprregs[i])
}), {}, {exprregs[i], baseReg, indexReg}, true);
self:freeRegister(exprregs[i], false);
self:freeRegister(baseReg, false);
self:freeRegister(indexReg, false);
else
error(string.format("Invalid Assignment lhs: %s", statement.lhs));
end
end
end;
================================================
FILE: src/prometheus/compiler/statements/break_statement.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- break_statement.lua
--
-- This Script contains the statement handler for the BreakStatement.
local Ast = require("prometheus.ast");
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local toFreeVars = {};
local statScope;
repeat
statScope = statScope and statScope.parentScope or statement.scope;
for id, name in ipairs(statScope.variables) do
table.insert(toFreeVars, {
scope = statScope,
id = id;
});
end
until statScope == statement.loop.body.scope;
for i, var in pairs(toFreeVars) do
local varScope, id = var.scope, var.id;
local varReg = self:getVarRegister(varScope, id, nil, nil);
if self:isUpvalue(varScope, id) then
scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc);
self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), {
self:register(scope, varReg)
})), {varReg}, {varReg}, false);
else
self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), {varReg}, {}, false);
end
end
self:addStatement(self:setPos(scope, statement.loop.__final_block.id), {self.POS_REGISTER}, {}, false);
self.activeBlock.advanceToNextBlock = false;
end;
================================================
FILE: src/prometheus/compiler/statements/compound.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- compound.lua
--
-- This Script contains the statement handler for the Compound statements (compound add, sub, mul, etc.)
local Ast = require("prometheus.ast");
local AstKind = Ast.AstKind;
local compoundConstructors = {
[AstKind.CompoundAddStatement] = Ast.CompoundAddStatement,
[AstKind.CompoundSubStatement] = Ast.CompoundSubStatement,
[AstKind.CompoundMulStatement] = Ast.CompoundMulStatement,
[AstKind.CompoundDivStatement] = Ast.CompoundDivStatement,
[AstKind.CompoundModStatement] = Ast.CompoundModStatement,
[AstKind.CompoundPowStatement] = Ast.CompoundPowStatement,
[AstKind.CompoundConcatStatement] = Ast.CompoundConcatStatement,
};
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local compoundConstructor = compoundConstructors[statement.kind];
if statement.lhs.kind == AstKind.AssignmentIndexing then
local indexing = statement.lhs;
local baseReg = self:compileExpression(indexing.base, funcDepth, 1)[1];
local indexReg = self:compileExpression(indexing.index, funcDepth, 1)[1];
local valueReg = self:compileExpression(statement.rhs, funcDepth, 1)[1];
self:addStatement(compoundConstructor(Ast.AssignmentIndexing(self:register(scope, baseReg), self:register(scope, indexReg)), self:register(scope, valueReg)), {}, {baseReg, indexReg, valueReg}, true);
self:freeRegister(baseReg, false);
self:freeRegister(indexReg, false);
self:freeRegister(valueReg, false);
else
local valueReg = self:compileExpression(statement.rhs, funcDepth, 1)[1];
local primaryExpr = statement.lhs;
if primaryExpr.scope.isGlobal then
local tmpReg = self:allocRegister(false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(primaryExpr.scope:getVariableName(primaryExpr.id))), {tmpReg}, {}, false);
self:addStatement(compoundConstructor(Ast.AssignmentIndexing(self:env(scope), self:register(scope, tmpReg)),
self:register(scope, valueReg)), {}, {tmpReg, valueReg}, true);
self:freeRegister(tmpReg, false);
self:freeRegister(valueReg, false);
else
if self.scopeFunctionDepths[primaryExpr.scope] == funcDepth then
if self:isUpvalue(primaryExpr.scope, primaryExpr.id) then
local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth);
self:addStatement(self:setUpvalueMember(scope, self:register(scope, reg), self:register(scope, valueReg), compoundConstructor), {}, {reg, valueReg}, true);
else
local reg = self:getVarRegister(primaryExpr.scope, primaryExpr.id, funcDepth, valueReg);
if reg ~= valueReg then
self:addStatement(self:setRegister(scope, reg, self:register(scope, valueReg), compoundConstructor), {reg}, {valueReg}, false);
end
end
else
local upvalId = self:getUpvalueId(primaryExpr.scope, primaryExpr.id);
scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar);
self:addStatement(self:setUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)), self:register(scope, valueReg), compoundConstructor), {}, {valueReg}, true);
end
self:freeRegister(valueReg, false);
end
end
end;
================================================
FILE: src/prometheus/compiler/statements/continue_statement.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- continue_statement.lua
--
-- This Script contains the statement handler for the ContinueStatement.
local Ast = require("prometheus.ast");
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local toFreeVars = {};
local statScope;
repeat
statScope = statScope and statScope.parentScope or statement.scope;
for id, _ in pairs(statScope.variables) do
table.insert(toFreeVars, {
scope = statScope,
id = id;
});
end
until statScope == statement.loop.body.scope;
for _, var in ipairs(toFreeVars) do
local varScope, id = var.scope, var.id;
local varReg = self:getVarRegister(varScope, id, nil, nil);
if self:isUpvalue(varScope, id) then
scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc);
self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), {
self:register(scope, varReg)
})), {varReg}, {varReg}, false);
else
self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), {varReg}, {}, false);
end
end
self:addStatement(self:setPos(scope, statement.loop.__start_block.id), {self.POS_REGISTER}, {}, false);
self.activeBlock.advanceToNextBlock = false;
end;
================================================
FILE: src/prometheus/compiler/statements/do_statement.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- do_statement.lua
--
-- This Script contains the statement handler for the DoStatement.
return function(self, statement, funcDepth)
self:compileBlock(statement.body, funcDepth);
end;
================================================
FILE: src/prometheus/compiler/statements/for_in_statement.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- for_in_statement.lua
--
-- This Script contains the statement handler for the ForInStatement
local Ast = require("prometheus.ast");
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local expressionsLength = #statement.expressions;
local exprregs = {};
for i, expr in ipairs(statement.expressions) do
if(i == expressionsLength and expressionsLength < 3) then
local regs = self:compileExpression(expr, funcDepth, 4 - expressionsLength);
for i = 1, 4 - expressionsLength do
table.insert(exprregs, regs[i]);
end
else
if i <= 3 then
table.insert(exprregs, self:compileExpression(expr, funcDepth, 1)[1])
else
self:freeRegister(self:compileExpression(expr, funcDepth, 1)[1], false);
end
end
end
for i, reg in ipairs(exprregs) do
if reg and self.registers[reg] ~= self.VAR_REGISTER and reg ~= self.POS_REGISTER and reg ~= self.RETURN_REGISTER then
self.registers[reg] = self.VAR_REGISTER;
else
exprregs[i] = self:allocRegister(true);
self:addStatement(self:copyRegisters(scope, {exprregs[i]}, {reg}), {exprregs[i]}, {reg}, false);
end
end
local checkBlock = self:createBlock();
local bodyBlock = self:createBlock();
local finalBlock = self:createBlock();
statement.__start_block = checkBlock;
statement.__final_block = finalBlock;
self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false);
self:setActiveBlock(checkBlock);
local scope = self.activeBlock.scope;
local varRegs = {};
for i, id in ipairs(statement.ids) do
varRegs[i] = self:getVarRegister(statement.scope, id, funcDepth)
end
self:addStatement(Ast.AssignmentStatement({
self:registerAssignment(scope, exprregs[3]),
varRegs[2] and self:registerAssignment(scope, varRegs[2]),
}, {
Ast.FunctionCallExpression(self:register(scope, exprregs[1]), {
self:register(scope, exprregs[2]),
self:register(scope, exprregs[3]),
})
}), {exprregs[3], varRegs[2]}, {exprregs[1], exprregs[2], exprregs[3]}, true);
self:addStatement(Ast.AssignmentStatement({
self:posAssignment(scope)
}, {
Ast.OrExpression(Ast.AndExpression(self:register(scope, exprregs[3]), Ast.NumberExpression(bodyBlock.id)), Ast.NumberExpression(finalBlock.id))
}), {self.POS_REGISTER}, {exprregs[3]}, false);
self:setActiveBlock(bodyBlock);
local scope = self.activeBlock.scope;
self:addStatement(self:copyRegisters(scope, {varRegs[1]}, {exprregs[3]}), {varRegs[1]}, {exprregs[3]}, false);
for i=3, #varRegs do
self:addStatement(self:setRegister(scope, varRegs[i], Ast.NilExpression()), {varRegs[i]}, {}, false);
end
for i, id in ipairs(statement.ids) do
if(self:isUpvalue(statement.scope, id)) then
local varreg = varRegs[i];
local tmpReg = self:allocRegister(false);
scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction);
self:addStatement(self:setRegister(scope, tmpReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {tmpReg}, {}, false);
self:addStatement(self:setUpvalueMember(scope, self:register(scope, tmpReg), self:register(scope, varreg)), {}, {tmpReg, varreg}, true);
self:addStatement(self:copyRegisters(scope, {varreg}, {tmpReg}), {varreg}, {tmpReg}, false);
self:freeRegister(tmpReg, false);
end
end
self:compileBlock(statement.body, funcDepth);
self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false);
self:setActiveBlock(finalBlock);
for i, _ in ipairs(exprregs) do
self:freeRegister(exprregs[i], true)
end
end;
================================================
FILE: src/prometheus/compiler/statements/for_statement.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- for_statement.lua
--
-- This Script contains the statement handler for the ForStatement
local Ast = require("prometheus.ast");
local util = require("prometheus.util");
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local checkBlock = self:createBlock();
local innerBlock = self:createBlock();
local finalBlock = self:createBlock();
statement.__start_block = checkBlock;
statement.__final_block = finalBlock;
local posState = self.registers[self.POS_REGISTER];
self.registers[self.POS_REGISTER] = self.VAR_REGISTER;
local initialReg = self:compileExpression(statement.initialValue, funcDepth, 1)[1];
local finalExprReg = self:compileExpression(statement.finalValue, funcDepth, 1)[1];
local finalReg = self:allocRegister(false);
self:addStatement(self:copyRegisters(scope, {finalReg}, {finalExprReg}), {finalReg}, {finalExprReg}, false);
self:freeRegister(finalExprReg);
local incrementExprReg = self:compileExpression(statement.incrementBy, funcDepth, 1)[1];
local incrementReg = self:allocRegister(false);
self:addStatement(self:copyRegisters(scope, {incrementReg}, {incrementExprReg}), {incrementReg}, {incrementExprReg}, false);
self:freeRegister(incrementExprReg);
local tmpReg = self:allocRegister(false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.NumberExpression(0)), {tmpReg}, {}, false);
local incrementIsNegReg = self:allocRegister(false);
local shouldSwap3 = math.random(1, 2) == 2;
local shuffledRegs4 = shouldSwap3 and {incrementReg, tmpReg} or {tmpReg, incrementReg};
self:addStatement(self:setRegister(scope, incrementIsNegReg, Ast[shouldSwap3 and "LessThanExpression" or "GreaterThanExpression"](self:register(scope, shuffledRegs4[1]), self:register(scope, shuffledRegs4[2]))), {incrementIsNegReg}, {shuffledRegs4[1], shuffledRegs4[2]}, false);
self:freeRegister(tmpReg);
local currentReg = self:allocRegister(true);
self:addStatement(self:setRegister(scope, currentReg, Ast.SubExpression(self:register(scope, initialReg), self:register(scope, incrementReg))), {currentReg}, {initialReg, incrementReg}, false);
self:freeRegister(initialReg);
self:addStatement(self:jmp(scope, Ast.NumberExpression(checkBlock.id)), {self.POS_REGISTER}, {}, false);
self:setActiveBlock(checkBlock);
scope = checkBlock.scope;
-- x = x + y or x = y + x instead of just x = x + y.
--> NEW: In an attempt to thwart deobfuscations, despite this being a simple comparison... Shuffling these causes problems for decompilers.
--> NOTE: This isn't unstable code, I've tested it multiple times.
local shuffledRegs = util.shuffle({currentReg, incrementReg});
self:addStatement(self:setRegister(scope, currentReg, Ast.AddExpression(self:register(scope, shuffledRegs[1]), self:register(scope, shuffledRegs[2]))), {currentReg}, {shuffledRegs[1], shuffledRegs[2]}, false);
local tmpReg1 = self:allocRegister(false);
local tmpReg2 = self:allocRegister(false);
self:addStatement(self:setRegister(scope, tmpReg2, Ast.NotExpression(self:register(scope, incrementIsNegReg))), {tmpReg2}, {incrementIsNegReg}, false);
local shouldSwap = math.random(1, 2) == 2;
local shuffledRegs2 = shouldSwap and {currentReg, finalReg} or {finalReg, currentReg};
self:addStatement(self:setRegister(scope, tmpReg1, Ast[shouldSwap and "LessThanOrEqualsExpression" or "GreaterThanOrEqualsExpression"](self:register(scope, shuffledRegs2[1]), self:register(scope, shuffledRegs2[2]))), {tmpReg1}, {shuffledRegs2[1], shuffledRegs2[2]}, false);
self:addStatement(self:setRegister(scope, tmpReg1, Ast.AndExpression(self:register(scope, tmpReg2), self:register(scope, tmpReg1))), {tmpReg1}, {tmpReg1, tmpReg2}, false);
local shouldSwap2 = math.random(1, 2) == 2;
local shuffledRegs3 = shouldSwap2 and {currentReg, finalReg} or {finalReg, currentReg};
self:addStatement(self:setRegister(scope, tmpReg2, Ast[shouldSwap2 and "GreaterThanOrEqualsExpression" or "LessThanOrEqualsExpression"](self:register(scope, shuffledRegs3[1]), self:register(scope, shuffledRegs3[2]))), {tmpReg2}, {shuffledRegs3[1], shuffledRegs3[2]}, false);
self:addStatement(self:setRegister(scope, tmpReg2, Ast.AndExpression(self:register(scope, incrementIsNegReg), self:register(scope, tmpReg2))), {tmpReg2}, {tmpReg2, incrementIsNegReg}, false);
self:addStatement(self:setRegister(scope, tmpReg1, Ast.OrExpression(self:register(scope, tmpReg2), self:register(scope, tmpReg1))), {tmpReg1}, {tmpReg1, tmpReg2}, false);
self:freeRegister(tmpReg2);
tmpReg2 = self:compileExpression(Ast.NumberExpression(innerBlock.id), funcDepth, 1)[1];
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.AndExpression(self:register(scope, tmpReg1), self:register(scope, tmpReg2))), {self.POS_REGISTER}, {tmpReg1, tmpReg2}, false);
self:freeRegister(tmpReg2);
self:freeRegister(tmpReg1);
tmpReg2 = self:compileExpression(Ast.NumberExpression(finalBlock.id), funcDepth, 1)[1];
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(self:register(scope, self.POS_REGISTER), self:register(scope, tmpReg2))), {self.POS_REGISTER}, {self.POS_REGISTER, tmpReg2}, false);
self:freeRegister(tmpReg2);
self:setActiveBlock(innerBlock);
scope = innerBlock.scope;
self.registers[self.POS_REGISTER] = posState;
local varReg = self:getVarRegister(statement.scope, statement.id, funcDepth, nil);
if(self:isUpvalue(statement.scope, statement.id)) then
scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction);
self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {varReg}, {}, false);
self:addStatement(self:setUpvalueMember(scope, self:register(scope, varReg), self:register(scope, currentReg)), {}, {varReg, currentReg}, true);
else
self:addStatement(self:setRegister(scope, varReg, self:register(scope, currentReg)), {varReg}, {currentReg}, false);
end
self:compileBlock(statement.body, funcDepth);
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(checkBlock.id)), {self.POS_REGISTER}, {}, false);
self.registers[self.POS_REGISTER] = self.VAR_REGISTER;
self:freeRegister(finalReg);
self:freeRegister(incrementIsNegReg);
self:freeRegister(incrementReg);
self:freeRegister(currentReg, true);
self.registers[self.POS_REGISTER] = posState;
self:setActiveBlock(finalBlock);
end;
================================================
FILE: src/prometheus/compiler/statements/function_call.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- function_call.lua
--
-- This Script contains the statement handler for the FunctionCallStatement.
local Ast = require("prometheus.ast");
local AstKind = Ast.AstKind;
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local baseReg = self:compileExpression(statement.base, funcDepth, 1)[1];
local retReg = self:allocRegister(false);
local regs = {};
local args = {};
for i, expr in ipairs(statement.args) do
if i == #statement.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then
local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1];
table.insert(args, Ast.FunctionCallExpression(
self:unpack(scope),
{self:register(scope, reg)}));
table.insert(regs, reg);
else
local reg = self:compileExpression(expr, funcDepth, 1)[1];
local argExpr = self:register(scope, reg);
table.insert(args, argExpr);
table.insert(regs, reg);
end
end
self:addStatement(self:setRegister(scope, retReg, Ast.FunctionCallExpression(self:register(scope, baseReg), args)), {retReg}, {baseReg, unpack(regs)}, true);
self:freeRegister(baseReg, false);
self:freeRegister(retReg, false);
for _, reg in ipairs(regs) do
self:freeRegister(reg, false);
end
end;
================================================
FILE: src/prometheus/compiler/statements/function_declaration.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- function_declaration.lua
--
-- This Script contains the statement handler for the FunctionDeclaration.
local Ast = require("prometheus.ast");
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local retReg = self:compileFunction(statement, funcDepth);
if(#statement.indices > 0) then
local tblReg;
if statement.scope.isGlobal then
tblReg = self:allocRegister(false);
self:addStatement(self:setRegister(scope, tblReg, Ast.StringExpression(statement.scope:getVariableName(statement.id))), {tblReg}, {}, false);
self:addStatement(self:setRegister(scope, tblReg, Ast.IndexExpression(self:env(scope), self:register(scope, tblReg))), {tblReg}, {tblReg}, true);
else
if self.scopeFunctionDepths[statement.scope] == funcDepth then
if self:isUpvalue(statement.scope, statement.id) then
tblReg = self:allocRegister(false);
local reg = self:getVarRegister(statement.scope, statement.id, funcDepth);
self:addStatement(self:setRegister(scope, tblReg, self:getUpvalueMember(scope, self:register(scope, reg))), {tblReg}, {reg}, true);
else
tblReg = self:getVarRegister(statement.scope, statement.id, funcDepth, retReg);
end
else
tblReg = self:allocRegister(false);
local upvalId = self:getUpvalueId(statement.scope, statement.id);
scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar);
self:addStatement(self:setRegister(scope, tblReg, self:getUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)))), {tblReg}, {}, true);
end
end
for i = 1, #statement.indices - 1 do
local index = statement.indices[i];
local indexReg = self:compileExpression(Ast.StringExpression(index), funcDepth, 1)[1];
local tblRegOld = tblReg;
tblReg = self:allocRegister(false);
self:addStatement(self:setRegister(scope, tblReg, Ast.IndexExpression(self:register(scope, tblRegOld), self:register(scope, indexReg))), {tblReg}, {tblReg, indexReg}, false);
self:freeRegister(tblRegOld, false);
self:freeRegister(indexReg, false);
end
local index = statement.indices[#statement.indices];
local indexReg = self:compileExpression(Ast.StringExpression(index), funcDepth, 1)[1];
self:addStatement(Ast.AssignmentStatement({
Ast.AssignmentIndexing(self:register(scope, tblReg), self:register(scope, indexReg)),
}, {
self:register(scope, retReg),
}), {}, {tblReg, indexReg, retReg}, true);
self:freeRegister(indexReg, false);
self:freeRegister(tblReg, false);
self:freeRegister(retReg, false);
return;
end
if statement.scope.isGlobal then
local tmpReg = self:allocRegister(false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(statement.scope:getVariableName(statement.id))), {tmpReg}, {}, false);
self:addStatement(Ast.AssignmentStatement({Ast.AssignmentIndexing(self:env(scope), self:register(scope, tmpReg))},
{self:register(scope, retReg)}), {}, {tmpReg, retReg}, true);
self:freeRegister(tmpReg, false);
else
if self.scopeFunctionDepths[statement.scope] == funcDepth then
if self:isUpvalue(statement.scope, statement.id) then
local reg = self:getVarRegister(statement.scope, statement.id, funcDepth);
self:addStatement(self:setUpvalueMember(scope, self:register(scope, reg), self:register(scope, retReg)), {}, {reg, retReg}, true);
else
local reg = self:getVarRegister(statement.scope, statement.id, funcDepth, retReg);
if reg ~= retReg then
self:addStatement(self:setRegister(scope, reg, self:register(scope, retReg)), {reg}, {retReg}, false);
end
end
else
local upvalId = self:getUpvalueId(statement.scope, statement.id);
scope:addReferenceToHigherScope(self.containerFuncScope, self.currentUpvaluesVar);
self:addStatement(self:setUpvalueMember(scope, Ast.IndexExpression(Ast.VariableExpression(self.containerFuncScope, self.currentUpvaluesVar), Ast.NumberExpression(upvalId)), self:register(scope, retReg)), {}, {retReg}, true);
end
end
self:freeRegister(retReg, false);
end;
================================================
FILE: src/prometheus/compiler/statements/if_statement.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- if_statement.lua
--
-- This Script contains the statement handler for the IfStatement.
local Ast = require("prometheus.ast");
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local conditionReg = self:compileExpression(statement.condition, funcDepth, 1)[1];
local finalBlock = self:createBlock();
local nextBlock
if statement.elsebody or #statement.elseifs > 0 then
nextBlock = self:createBlock();
else
nextBlock = finalBlock;
end
local innerBlock = self:createBlock();
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(innerBlock.id)), Ast.NumberExpression(nextBlock.id))), {self.POS_REGISTER}, {conditionReg}, false);
self:freeRegister(conditionReg, false);
self:setActiveBlock(innerBlock);
scope = innerBlock.scope
self:compileBlock(statement.body, funcDepth);
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(finalBlock.id)), {self.POS_REGISTER}, {}, false);
for i, eif in ipairs(statement.elseifs) do
self:setActiveBlock(nextBlock);
conditionReg = self:compileExpression(eif.condition, funcDepth, 1)[1];
local innerBlock = self:createBlock();
if statement.elsebody or i < #statement.elseifs then
nextBlock = self:createBlock();
else
nextBlock = finalBlock;
end
local scope = self.activeBlock.scope;
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(innerBlock.id)), Ast.NumberExpression(nextBlock.id))), {self.POS_REGISTER}, {conditionReg}, false);
self:freeRegister(conditionReg, false);
self:setActiveBlock(innerBlock);
scope = innerBlock.scope;
self:compileBlock(eif.body, funcDepth);
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(finalBlock.id)), {self.POS_REGISTER}, {}, false);
end
if statement.elsebody then
self:setActiveBlock(nextBlock);
self:compileBlock(statement.elsebody, funcDepth);
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(finalBlock.id)), {self.POS_REGISTER}, {}, false);
end
self:setActiveBlock(finalBlock);
end;
================================================
FILE: src/prometheus/compiler/statements/local_function_declaration.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- local_function_declaration.lua
--
-- This Script contains the statement handler for the LocalFunctionDeclaration
local Ast = require("prometheus.ast");
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
if(self:isUpvalue(statement.scope, statement.id)) then
local varReg = self:getVarRegister(statement.scope, statement.id, funcDepth, nil);
scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction);
self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {varReg}, {}, false);
local retReg = self:compileFunction(statement, funcDepth);
self:addStatement(self:setUpvalueMember(scope, self:register(scope, varReg), self:register(scope, retReg)), {}, {varReg, retReg}, true);
self:freeRegister(retReg, false);
else
local retReg = self:compileFunction(statement, funcDepth);
local varReg = self:getVarRegister(statement.scope, statement.id, funcDepth, retReg);
self:addStatement(self:copyRegisters(scope, {varReg}, {retReg}), {varReg}, {retReg}, false);
self:freeRegister(retReg, false);
end
end;
================================================
FILE: src/prometheus/compiler/statements/local_variable_declaration.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- local_variable_declaration.lua
--
-- This Script contains the statement handler for the LocalVariableDeclaration
local Ast = require("prometheus.ast");
local AstKind = Ast.AstKind;
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local exprregs = {};
for i, expr in ipairs(statement.expressions) do
if(i == #statement.expressions and #statement.ids > #statement.expressions) then
local regs = self:compileExpression(expr, funcDepth, #statement.ids - #statement.expressions + 1);
for i, reg in ipairs(regs) do
table.insert(exprregs, reg);
end
else
if statement.ids[i] or expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression then
local reg = self:compileExpression(expr, funcDepth, 1)[1];
table.insert(exprregs, reg);
end
end
end
if #exprregs == 0 then
for _=1, #statement.ids do
table.insert(exprregs, self:compileExpression(Ast.NilExpression(), funcDepth, 1)[1]);
end
end
for i, id in ipairs(statement.ids) do
if(exprregs[i]) then
if(self:isUpvalue(statement.scope, id)) then
local varreg = self:getVarRegister(statement.scope, id, funcDepth);
local varReg = self:getVarRegister(statement.scope, id, funcDepth, nil);
scope:addReferenceToHigherScope(self.scope, self.allocUpvalFunction);
self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.allocUpvalFunction), {})), {varReg}, {}, false);
self:addStatement(self:setUpvalueMember(scope, self:register(scope, varReg), self:register(scope, exprregs[i])), {}, {varReg, exprregs[i]}, true);
self:freeRegister(exprregs[i], false);
else
local varreg = self:getVarRegister(statement.scope, id, funcDepth, exprregs[i]);
self:addStatement(self:copyRegisters(scope, {varreg}, {exprregs[i]}), {varreg}, {exprregs[i]}, false);
self:freeRegister(exprregs[i], false);
end
end
end
if not self.scopeFunctionDepths[statement.scope] then
self.scopeFunctionDepths[statement.scope] = funcDepth;
end
end;
================================================
FILE: src/prometheus/compiler/statements/pass_self_function_call.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- pass_self_function_call.lua
--
-- This Script contains the statement handler for the PassSelfFunctionCallStatement.
local Ast = require("prometheus.ast");
local AstKind = Ast.AstKind;
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local baseReg = self:compileExpression(statement.base, funcDepth, 1)[1];
local tmpReg = self:allocRegister(false);
local args = { self:register(scope, baseReg) };
local regs = { baseReg };
for i, expr in ipairs(statement.args) do
if i == #statement.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then
local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1];
table.insert(args, Ast.FunctionCallExpression(
self:unpack(scope),
{self:register(scope, reg)}));
table.insert(regs, reg);
else
local reg = self:compileExpression(expr, funcDepth, 1)[1];
table.insert(args, self:register(scope, reg));
table.insert(regs, reg);
end
end
self:addStatement(self:setRegister(scope, tmpReg, Ast.StringExpression(statement.passSelfFunctionName)), {tmpReg}, {}, false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.IndexExpression(self:register(scope, baseReg), self:register(scope, tmpReg))), {tmpReg}, {tmpReg, baseReg}, false);
self:addStatement(self:setRegister(scope, tmpReg, Ast.FunctionCallExpression(self:register(scope, tmpReg), args)), {tmpReg}, {tmpReg, unpack(regs)}, true);
self:freeRegister(tmpReg, false);
for _, reg in ipairs(regs) do
self:freeRegister(reg, false);
end
end;
================================================
FILE: src/prometheus/compiler/statements/repeat_statement.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- repeat_statement.lua
--
-- This Script contains the statement handler for the RepeatStatement.
local Ast = require("prometheus.ast");
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local innerBlock = self:createBlock();
local finalBlock = self:createBlock();
statement.__start_block = innerBlock;
statement.__final_block = finalBlock;
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.NumberExpression(innerBlock.id)), {self.POS_REGISTER}, {}, false);
self:setActiveBlock(innerBlock);
for _, stat in ipairs(statement.body.statements) do
self:compileStatement(stat, funcDepth);
end;
local scope = self.activeBlock.scope;
local conditionReg = (self:compileExpression(statement.condition, funcDepth, 1))[1];
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(finalBlock.id)), Ast.NumberExpression(innerBlock.id))), { self.POS_REGISTER }, { conditionReg }, false);
self:freeRegister(conditionReg, false);
for id, _ in ipairs(statement.body.scope.variables) do
local varReg = self:getVarRegister(statement.body.scope, id, funcDepth, nil);
if self:isUpvalue(statement.body.scope, id) then
scope:addReferenceToHigherScope(self.scope, self.freeUpvalueFunc);
self:addStatement(self:setRegister(scope, varReg, Ast.FunctionCallExpression(Ast.VariableExpression(self.scope, self.freeUpvalueFunc), { self:register(scope, varReg) })), { varReg }, { varReg }, false);
else
self:addStatement(self:setRegister(scope, varReg, Ast.NilExpression()), { varReg }, {}, false);
end;
self:freeRegister(varReg, true);
end;
self:setActiveBlock(finalBlock);
end;
================================================
FILE: src/prometheus/compiler/statements/return.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- return.lua
--
-- This Script contains the statement handler for the ReturnStatement.
local Ast = require("prometheus.ast");
local AstKind = Ast.AstKind;
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local entries = {};
local regs = {};
for i, expr in ipairs(statement.args) do
if i == #statement.args and (expr.kind == AstKind.FunctionCallExpression or expr.kind == AstKind.PassSelfFunctionCallExpression or expr.kind == AstKind.VarargExpression) then
local reg = self:compileExpression(expr, funcDepth, self.RETURN_ALL)[1];
table.insert(entries, Ast.TableEntry(Ast.FunctionCallExpression(
self:unpack(scope),
{self:register(scope, reg)})));
table.insert(regs, reg);
else
local reg = self:compileExpression(expr, funcDepth, 1)[1];
table.insert(entries, Ast.TableEntry(self:register(scope, reg)));
table.insert(regs, reg);
end
end
for _, reg in ipairs(regs) do
self:freeRegister(reg, false);
end
self:addStatement(self:setReturn(scope, Ast.TableConstructorExpression(entries)), {self.RETURN_REGISTER}, regs, false);
self:addStatement(self:setPos(self.activeBlock.scope, nil), {self.POS_REGISTER}, {}, false);
self.activeBlock.advanceToNextBlock = false;
end;
================================================
FILE: src/prometheus/compiler/statements/while_statement.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- while_statement.lua
--
-- This Script contains the statement handler for the WhileStatement
local Ast = require("prometheus.ast");
return function(self, statement, funcDepth)
local scope = self.activeBlock.scope;
local innerBlock = self:createBlock();
local finalBlock = self:createBlock();
local checkBlock = self:createBlock();
statement.__start_block = checkBlock;
statement.__final_block = finalBlock;
self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false);
self:setActiveBlock(checkBlock);
scope = self.activeBlock.scope;
local conditionReg = self:compileExpression(statement.condition, funcDepth, 1)[1];
self:addStatement(self:setRegister(scope, self.POS_REGISTER, Ast.OrExpression(Ast.AndExpression(self:register(scope, conditionReg), Ast.NumberExpression(innerBlock.id)), Ast.NumberExpression(finalBlock.id))), {self.POS_REGISTER}, {conditionReg}, false);
self:freeRegister(conditionReg, false);
self:setActiveBlock(innerBlock);
local scope = self.activeBlock.scope;
self:compileBlock(statement.body, funcDepth);
self:addStatement(self:setPos(scope, checkBlock.id), {self.POS_REGISTER}, {}, false);
self:setActiveBlock(finalBlock);
end;
================================================
FILE: src/prometheus/compiler/statements.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- statements.lua
--
-- This Script contains the statement handlers: exports handler table keyed by AstKind.
local Ast = require("prometheus.ast");
local AstKind = Ast.AstKind;
local handlers = {};
local statements = "prometheus.compiler.statements.";
local function requireStatement(name)
return require(statements .. name);
end
handlers[AstKind.ReturnStatement] = requireStatement("return");
handlers[AstKind.LocalVariableDeclaration] = requireStatement("local_variable_declaration");
handlers[AstKind.FunctionCallStatement] = requireStatement("function_call");
handlers[AstKind.PassSelfFunctionCallStatement] = requireStatement("pass_self_function_call");
handlers[AstKind.LocalFunctionDeclaration] = requireStatement("local_function_declaration");
handlers[AstKind.FunctionDeclaration] = requireStatement("function_declaration");
handlers[AstKind.AssignmentStatement] = requireStatement("assignment");
handlers[AstKind.IfStatement] = requireStatement("if_statement");
handlers[AstKind.DoStatement] = requireStatement("do_statement");
handlers[AstKind.WhileStatement] = requireStatement("while_statement");
handlers[AstKind.RepeatStatement] = requireStatement("repeat_statement");
handlers[AstKind.ForStatement] = requireStatement("for_statement");
handlers[AstKind.ForInStatement] = requireStatement("for_in_statement");
handlers[AstKind.BreakStatement] = requireStatement("break_statement");
handlers[AstKind.ContinueStatement] = requireStatement("continue_statement");
-- Compound statements share one handler
local compoundHandler = requireStatement("compound");
handlers[AstKind.CompoundAddStatement] = compoundHandler;
handlers[AstKind.CompoundSubStatement] = compoundHandler;
handlers[AstKind.CompoundMulStatement] = compoundHandler;
handlers[AstKind.CompoundDivStatement] = compoundHandler;
handlers[AstKind.CompoundModStatement] = compoundHandler;
handlers[AstKind.CompoundPowStatement] = compoundHandler;
handlers[AstKind.CompoundConcatStatement] = compoundHandler;
return handlers;
================================================
FILE: src/prometheus/compiler/upvalue.lua
================================================
-- This Script is Part of the Prometheus Obfuscator by Levno_710
--
-- upvalue.lua
--
-- This Script contains the upvalue and GC management for the compiler.
local Ast = require("prometheus.ast");
local Scope = require("prometheus.scope");
local util = require("prometheus.util");
local unpack = unpack or table.unpack;
return function(Compiler)
function Compiler:createUpvaluesGcFunc()
local scope = Scope:new(self.scope);
local selfVar = scope:addVariable();
local iteratorVar = scope:addVariable();
local valueVar = scope:addVariable();
local whileScope = Scope:new(scope);
whileScope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 3);
whileScope:addReferenceToHigherScope(scope, valueVar, 3);
whileScope:addReferenceToHigherScope(scope, iteratorVar, 3);
local ifScope = Scope:new(whileScope);
ifScope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 1);
ifScope:addReferenceToHigherScope(self.scope, self.upvaluesTable, 1);
return Ast.FunctionLiteralExpression({Ast.VariableExpression(scope, selfVar)}, Ast.Block({
Ast.LocalVariableDeclaration(scope, {iteratorVar, valueVar}, {Ast.NumberExpression(1), Ast.IndexExpression(Ast.VariableExpression(scope, selfVar), Ast.NumberExpression(1))}),
Ast.WhileStatement(Ast.Block({
Ast.AssignmentStatement({
Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)),
Ast.AssignmentVariable(scope, iteratorVar),
}, {
Ast.SubExpression(Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)), Ast.NumberExpression(1)),
Ast.AddExpression(unpack(util.shuffle{Ast.VariableExpression(scope, iteratorVar), Ast.NumberExpression(1)})),
}),
Ast.IfStatement(Ast.EqualsExpression(unpack(util.shuffle{Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)), Ast.NumberExpression(0)})), Ast.Block({
Ast.AssignmentStatement({
Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, valueVar)),
Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), Ast.VariableExpression(scope, valueVar)),
}, {
Ast.NilExpression(),
Ast.NilExpression(),
})
}, ifScope), {}, nil),
Ast.AssignmentStatement({
Ast.AssignmentVariable(scope, valueVar),
}, {
Ast.IndexExpression(Ast.VariableExpression(scope, selfVar), Ast.VariableExpression(scope, iteratorVar)),
}),
}, whileScope), Ast.VariableExpression(scope, valueVar), scope);
}, scope));
end
function Compiler:createFreeUpvalueFunc()
local scope = Scope:new(self.scope);
local argVar = scope:addVariable();
local ifScope = Scope:new(scope);
ifScope:addReferenceToHigherScope(scope, argVar, 3);
scope:addReferenceToHigherScope(self.scope, self.upvaluesReferenceCountsTable, 2);
return Ast.FunctionLiteralExpression({Ast.VariableExpression(scope, argVar)}, Ast.Block({
Ast.AssignmentStatement({
Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar))
}, {
Ast.SubExpression(Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar)), Ast.NumberExpression(1));
}),
Ast.IfStatement(Ast.EqualsExpression(unpack(util.shuffle{Ast.IndexExpression(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar)), Ast.NumberExpression(0)})), Ast.Block({
Ast.AssignmentStatement({
Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesReferenceCountsTable), Ast.VariableExpression(scope, argVar)),
Ast.AssignmentIndexing(Ast.VariableExpression(self.scope, self.upvaluesTable), Ast.VariableExpression(scope, argVar)),
}, {
Ast.NilExpression(),
gitextract_h0mah7x0/ ├── .editorconfig ├── .gitattributes ├── .gitbook.yaml ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ └── bug_report.md │ └── workflows/ │ ├── Build.yml │ └── Test.yml ├── .gitignore ├── LICENSE ├── benchmark.lua ├── cli.lua ├── doc/ │ ├── README.md │ ├── SUMMARY.md │ ├── advanced/ │ │ └── using-prometheus-in-your-lua-application.md │ ├── getting-started/ │ │ ├── command-line-options.md │ │ ├── installation.md │ │ ├── obfuscating-your-first-script.md │ │ ├── presets.md │ │ ├── the-config-object.md │ │ └── writing-a-custom-config-file.md │ └── steps/ │ ├── anti-tamper.md │ ├── constantarray.md │ ├── encryptstrings.md │ ├── proxifylocals.md │ ├── splitstrings.md │ ├── vmify.md │ └── wrapinfunction.md ├── prometheus-main.lua ├── readme.md ├── src/ │ ├── cli.lua │ ├── colors.lua │ ├── highlightlua.lua │ ├── logger.lua │ ├── presets.lua │ ├── prometheus/ │ │ ├── ast.lua │ │ ├── compiler/ │ │ │ ├── block.lua │ │ │ ├── compile_core.lua │ │ │ ├── compile_top.lua │ │ │ ├── compiler.lua │ │ │ ├── constants.lua │ │ │ ├── emit.lua │ │ │ ├── expressions/ │ │ │ │ ├── and.lua │ │ │ │ ├── binary.lua │ │ │ │ ├── boolean.lua │ │ │ │ ├── function_call.lua │ │ │ │ ├── function_literal.lua │ │ │ │ ├── index.lua │ │ │ │ ├── len.lua │ │ │ │ ├── negate.lua │ │ │ │ ├── nil.lua │ │ │ │ ├── not.lua │ │ │ │ ├── number.lua │ │ │ │ ├── or.lua │ │ │ │ ├── pass_self_function_call.lua │ │ │ │ ├── string.lua │ │ │ │ ├── table_constructor.lua │ │ │ │ ├── vararg.lua │ │ │ │ └── variable.lua │ │ │ ├── expressions.lua │ │ │ ├── register.lua │ │ │ ├── statements/ │ │ │ │ ├── assignment.lua │ │ │ │ ├── break_statement.lua │ │ │ │ ├── compound.lua │ │ │ │ ├── continue_statement.lua │ │ │ │ ├── do_statement.lua │ │ │ │ ├── for_in_statement.lua │ │ │ │ ├── for_statement.lua │ │ │ │ ├── function_call.lua │ │ │ │ ├── function_declaration.lua │ │ │ │ ├── if_statement.lua │ │ │ │ ├── local_function_declaration.lua │ │ │ │ ├── local_variable_declaration.lua │ │ │ │ ├── pass_self_function_call.lua │ │ │ │ ├── repeat_statement.lua │ │ │ │ ├── return.lua │ │ │ │ └── while_statement.lua │ │ │ ├── statements.lua │ │ │ └── upvalue.lua │ │ ├── enums.lua │ │ ├── namegenerators/ │ │ │ ├── Il.lua │ │ │ ├── confuse.lua │ │ │ ├── mangled.lua │ │ │ ├── mangled_shuffled.lua │ │ │ └── number.lua │ │ ├── namegenerators.lua │ │ ├── parser.lua │ │ ├── pipeline.lua │ │ ├── randomLiterals.lua │ │ ├── randomStrings.lua │ │ ├── scope.lua │ │ ├── step.lua │ │ ├── steps/ │ │ │ ├── AddVararg.lua │ │ │ ├── AntiTamper.lua │ │ │ ├── ConstantArray.lua │ │ │ ├── EncryptStrings.lua │ │ │ ├── NumbersToExpressions.lua │ │ │ ├── ProxifyLocals.lua │ │ │ ├── SplitStrings.lua │ │ │ ├── Vmify.lua │ │ │ ├── Watermark.lua │ │ │ ├── WatermarkCheck.lua │ │ │ └── WrapInFunction.lua │ │ ├── steps.lua │ │ ├── tokenizer.lua │ │ ├── unparser.lua │ │ ├── util.lua │ │ └── visitast.lua │ └── prometheus.lua ├── tests/ │ ├── ambiguous-call.lua │ ├── closures.lua │ ├── coroutines.lua │ ├── fibonacci.lua │ ├── iterator.lua │ ├── loops.lua │ ├── matrix.lua │ ├── metatables.lua │ ├── multi-return.lua │ ├── primes.lua │ ├── repeat-test.lua │ ├── state-machine.lua │ ├── strings.lua │ ├── syntax.lua │ ├── table-merge.lua │ └── upvalues.lua └── tests.lua
Condensed preview — 124 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (436K chars).
[
{
"path": ".editorconfig",
"chars": 60,
"preview": "[*.lua]\nindent_style = tab\nindent_size = 4\nend_of_line = lf\n"
},
{
"path": ".gitattributes",
"chars": 29,
"preview": "*.lua text=auto\n*.lua eol=lf\n"
},
{
"path": ".gitbook.yaml",
"chars": 13,
"preview": "root: ./doc/\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 629,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[BUG]\"\nlabels: bug\nassignees: ''\n\n---\n\n**Describe"
},
{
"path": ".github/workflows/Build.yml",
"chars": 1763,
"preview": "name: Build\n\non:\n push:\n branches:\n main\n\njobs:\n build:\n runs-on: windows-latest # gh-actions-lua doesn't w"
},
{
"path": ".github/workflows/Test.yml",
"chars": 373,
"preview": "name: Test\non: \n push:\n pull_request:\n branches:\n - master\n\njobs:\n test-linux:\n runs-on: ubuntu-latest\n "
},
{
"path": ".gitignore",
"chars": 210,
"preview": "# Ignore Vscode Folder\n.vscode\n\n# Ignore Lua Implementation and srlua\nlua51.dll\nluajit.exe\nsrlua\nluajit\nbuildnotes.txt\ns"
},
{
"path": "LICENSE",
"chars": 5376,
"preview": "PROMETHEUS LICENSE\nCopyright (c) 2025 Elias Oelschner\nhttps://github.com/prometheus-lua/Prometheus\n\nPermission is hereby"
},
{
"path": "benchmark.lua",
"chars": 732,
"preview": "print(\"PROMETHEUS Benchmark\")\nprint(\"Based On IronBrew Benchmark\")\nlocal Iterations = 100000\nprint(\"Iterations: \" .. tos"
},
{
"path": "cli.lua",
"chars": 388,
"preview": "-- This Script is Part of the Prometheus Obfuscator by Levno_710\n--\n-- cli.lua\n--\n-- This Script contains the Code for t"
},
{
"path": "doc/README.md",
"chars": 344,
"preview": "---\ndescription: Prometheus is an Lua Obfuscator, that is written in pure Lua.\n---\n\n# Prometheus\n\nPrometheus can obfusca"
},
{
"path": "doc/SUMMARY.md",
"chars": 850,
"preview": "# Table of contents\n\n* [Prometheus](README.md)\n\n## Getting Started\n\n* [Installation](getting-started/installation.md)\n* "
},
{
"path": "doc/advanced/using-prometheus-in-your-lua-application.md",
"chars": 1115,
"preview": "# Using Prometheus in your Lua Application\n\nPrometheus can also be used as a library for your custom Lua Applications in"
},
{
"path": "doc/getting-started/command-line-options.md",
"chars": 966,
"preview": "# Command Line Options\n\nThe following table provides a brief overview over the command line options:\n\n| Option "
},
{
"path": "doc/getting-started/installation.md",
"chars": 458,
"preview": "# Installation\n\nTo install Prometheus, simply clone the Github Repository using:\n\n```batch\ngit clone \"https://github.com"
},
{
"path": "doc/getting-started/obfuscating-your-first-script.md",
"chars": 1779,
"preview": "# Obfuscating your first script\n\nNow that you have downloaded and Prometheus, you probably wonder how to use it. In this"
},
{
"path": "doc/getting-started/presets.md",
"chars": 250,
"preview": "# Presets\n\nThe following table provides an overview over the presets\n\n| name | size | speed |\n| ------ | ------ | "
},
{
"path": "doc/getting-started/the-config-object.md",
"chars": 2418,
"preview": "# The Config Object\n\nPrometheus takes a configuration object. In this object there can be many properties applied. \\\nT"
},
{
"path": "doc/getting-started/writing-a-custom-config-file.md",
"chars": 2196,
"preview": "# Writing a custom Config File\n\nConfiguration Files for Prometheus are just lua modules, that return a single object, wh"
},
{
"path": "doc/steps/anti-tamper.md",
"chars": 503,
"preview": "---\ndescription: This step provides an obfuscation step, that breaks the script, when someone tries to tamper with it.\n-"
},
{
"path": "doc/steps/constantarray.md",
"chars": 2637,
"preview": "---\ndescription: >-\n This Step will Extract all Constants and put them into an Array at the\n beginning of the script\n-"
},
{
"path": "doc/steps/encryptstrings.md",
"chars": 1882,
"preview": "---\ndescription: This Step will encrypt all String constants in your code\n---\n\n# EncryptStrings\n\n## Settings\n\nNone\n\n## E"
},
{
"path": "doc/steps/proxifylocals.md",
"chars": 1016,
"preview": "---\ndescription: This Step wraps all locals into Proxy Objects\n---\n\n# ProxifyLocals\n\n### Settings\n\n| Name | type "
},
{
"path": "doc/steps/splitstrings.md",
"chars": 2562,
"preview": "---\ndescription: This Step splits Strings to a specific or random length\n---\n\n# SplitStrings\n\n### Settings\n\n| Name "
},
{
"path": "doc/steps/vmify.md",
"chars": 109,
"preview": "---\ndescription: This Step will Compile your script and run it within a VM.\n---\n\n# Vmify\n\n### Settings\n\nNone\n"
},
{
"path": "doc/steps/wrapinfunction.md",
"chars": 470,
"preview": "---\ndescription: This Step Wraps the Entire Script into a Function\n---\n\n# WrapInFunction\n\n### Settings\n\n| Name | t"
},
{
"path": "prometheus-main.lua",
"chars": 14,
"preview": "require(\"cli\")"
},
{
"path": "readme.md",
"chars": 3071,
"preview": "# :fire: Prometheus Lua Obfuscator\n[. The extraction includes 124 files (391.9 KB), approximately 102.0k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.