diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8d07a08 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +root = true + +[*] +end_of_line = crlf +indent_style = tab +indent_size = 4 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.py] +indent_style = space + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..929e77f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.spec +dist +build diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..466f742 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,57 @@ +# env: + # global: + # - PYTHONIOENCODING=utf-8 +jobs: + include: + - os: windows + language: shell + env: PATH=/c/Python38:/c/Python38/Scripts:$PATH + before_install: + - choco install --x86 python + - choco install zip + script: + - zip -r ./LuaObfuscator-win-x32 ./dist + - os: windows + language: shell + env: PATH=/c/Python38:/c/Python38/Scripts:$PATH + before_install: + - choco install python + - choco install zip + script: + - zip -r ./LuaObfuscator-win-x64 ./dist + - os: linux + language: python + python: "3.6" # 3.6 works! + - os: osx + language: generic +cache: + directories: + - ./dist +addons: + apt: + packages: + - zip +install: +- pip install pyinstaller + +branches: + only: + - master + +before_script: +- ls ./dist +- pyinstaller --onefile __main__.py -n LuaObfuscator +script: +- zip -r ./LuaObfuscator-$TRAVIS_OS_NAME ./dist +before_deploy: +- export TRAVIS_TAG=$(date +'%Y.%m.%d') + +deploy: + provider: releases + api_key: $GITHUB_TOKEN + file_glob: true + file: ./LuaObfuscator-* + skip_cleanup: true + name: $(date +'%Y.%m.%d') + on: + branch: master diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9197864 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,12 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/__main__.py", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..58eb1df --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.jediEnabled": false +} \ No newline at end of file diff --git a/README.md b/README.md index d468672..4d3a8c2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# LuaObfuscator +# LuaObfuscator [![Build Status](https://travis-ci.com/SupinePandora43/LuaObfuscator.svg)](https://travis-ci.com/SupinePandora43/LuaObfuscator) This lua obfuscator was originally designed for Garry's Mod, but should work on vanilla lua. Written for private use in January 2016. I never did anything with it so I decided to put it on GitHub. diff --git a/__main__.py b/__main__.py index df90885..9b47504 100644 --- a/__main__.py +++ b/__main__.py @@ -15,12 +15,6 @@ print("The obfuscator may not work correctly!") -VERSION = "Beta 1.0.3" -VERSION_DATE = time.strftime("%b %d, %Y @ %I:%M %p", time.localtime(os.path.getmtime(__file__))) - -print("Version: {0} (Updated on {1})".format(VERSION, VERSION_DATE)) - - in_file = "input.lua" out_file = "output.lua" decrypt_file = "__decrypt.lua" @@ -39,9 +33,6 @@ parser.add_argument("--level", help='0 = original strings, 1 = small file, 2 = large file, 3 = huge file', default=1) -parser.add_argument("--dontcopy", - help='Disable copying the output', - action='store_true') parser.add_argument("--debug", help="Enable debug mode", action='store_true') @@ -67,9 +58,9 @@ with open(global_file, "r") as f: globs = json.loads(f.read()) - # Do the obfuscation - lua, tokens, strings, comments = obfuscator.obfuscate(lua, encoder, globs, debug_mode) + lua, tokens, strings, comments = obfuscator.obfuscate( + lua, encoder, globs, debug_mode) except: if not debug_mode: @@ -79,15 +70,6 @@ raise -if not dontcopy: - try: - import pyperclip - pyperclip.copy(lua) - print("Code copied to clipboard.") - except: - pass - - # Write the results with open(out_file, "wb") as f: - f.write(lua.encode("utf-8")) \ No newline at end of file + f.write(lua.encode("utf-8")) diff --git a/finalize.py b/finalize.py index 02faf69..b8d7f62 100644 --- a/finalize.py +++ b/finalize.py @@ -1,7 +1,8 @@ import re import tokenizer -WORD_PTRN = re.compile(r"^[^" + re.escape("".join(tokenizer.SPECIAL_CHARS)) + r"]*$") +WORD_PTRN = re.compile( + r"^[^" + re.escape("".join(tokenizer.SPECIAL_CHARS)) + r"]*$") def finalize(tokens, decrypt_code): @@ -43,4 +44,4 @@ def render_code(tokens, decrypt_code): def is_word(s): - return WORD_PTRN.match(s) \ No newline at end of file + return WORD_PTRN.match(s) diff --git a/obfuscator.py b/obfuscator.py index 0f6de30..0592d04 100644 --- a/obfuscator.py +++ b/obfuscator.py @@ -49,7 +49,8 @@ def obfuscate(lua, encoder, globs, debug=False, xor_val=-1): # Strip comments and strings lua, strings, comments = stringstripper.strip(lua) - log("Stripped {0} strings and {1} comments.".format(len(strings), len(comments)), False) + log("Stripped {0} strings and {1} comments.".format( + len(strings), len(comments)), False) # Tokenize tokens = tokenizer.tokenize(lua) @@ -96,7 +97,8 @@ def obfuscate(lua, encoder, globs, debug=False, xor_val=-1): strings = encoder.encode_all(strings, xor_val) log("Obfuscated strings.") - tokens = stringstripper.replace(tokens, strings, DECRYPT_FUNC, encoder.get_str_start(), encoder.get_str_end()) + tokens = stringstripper.replace( + tokens, strings, DECRYPT_FUNC, encoder.get_str_start(), encoder.get_str_end()) log("Replaced strings.") lua = finalize.finalize(tokens, decrypt_code) @@ -297,7 +299,8 @@ def rename_loops(tokens): args = tokens[i+1:e:2] for arg in args: if arg not in replaced: - tokens = replace_locals(tokens, arg, new_local_name(index(tokens, arg)), i) + tokens = replace_locals( + tokens, arg, new_local_name(index(tokens, arg)), i) replaced.append(arg) return tokens @@ -457,4 +460,4 @@ def index(tokens, item, start_index=0): i = tokens.index(item, start_index) return i except: - return -1 \ No newline at end of file + return -1 diff --git a/stringencoder.py b/stringencoder.py index 0965df9..2c783b5 100644 --- a/stringencoder.py +++ b/stringencoder.py @@ -101,6 +101,7 @@ class Level3Encoder(Encoder): Up to 2 additional ascii characters will be added, and then each character is closed with '|'. """ + def __init__(self): self.level = 3 @@ -113,7 +114,8 @@ def encode_char(self, c, xor): # number of invis characters (lua counts 1 invis as 3) invis = math.floor(total / 3) - regchars = ''.join(random.choice(ascii_letters + digits) for _ in range(regular)) + regchars = ''.join(random.choice(ascii_letters + digits) + for _ in range(regular)) return obfuscator.INVISIBLE_CHAR * invis + regchars + "|" @@ -132,4 +134,4 @@ def get_by_level(level): def _read_decrypt_file(level, xor): with open("__decrypt_" + str(level) + ".lua", "rb") as f: - return f.read().decode("utf-8").replace("__XOR__", str(xor)) \ No newline at end of file + return f.read().decode("utf-8").replace("__XOR__", str(xor)) diff --git a/stringstripper.py b/stringstripper.py index 6668bbd..2448c03 100644 --- a/stringstripper.py +++ b/stringstripper.py @@ -50,15 +50,15 @@ def replace(lua, strings, decrypt_func="", start="[[", end="]]"): def strip_multiline_comments(lua): removed = [] - for i in range(len(COMMENT_START)): - r = _build_regex(COMMENT_START[i], COMMENT_END[i]) - while True: - match = r.search(lua) - if match is None: - break - removed.append(match.group(0)) - lua = lua[:match.start()] + lua[match.end():] - print(match) + # for i in range(len(COMMENT_START)): + # r = _build_regex(COMMENT_START[i], COMMENT_END[i]) + # while True: + # match = r.search(lua) + # if match is None: + # break + # removed.append(match.group(0)) + # lua = lua[:match.start()] + lua[match.end():] + # print(match) return lua, removed @@ -110,7 +110,8 @@ def _strip_regular_strings(lua): if found is not None: placeholder = _build_string_placeholder() removed[placeholder] = found.group()[len(start):-len(end)] - lua = lua[:found.start()] + " " + placeholder + " " + lua[found.end():] + lua = lua[:found.start()] + " " + placeholder + \ + " " + lua[found.end():] else: break @@ -133,6 +134,8 @@ def _strip_multiline_strings(lua): string_index = -1 + + def _build_string_placeholder(): global string_index string_index += 1 diff --git a/tokenizer.py b/tokenizer.py index 20bff90..6f45a5c 100644 --- a/tokenizer.py +++ b/tokenizer.py @@ -23,14 +23,16 @@ TOKEN_PATTERN = re.compile(r"(\d*\.?\d+|[^\s" # Checks for decimals with optional lead and required end ex: ".5", "0.5" + re.escape("".join(SPECIAL_CHARS)) + r"]+|" - + re.escape("___sep___".join(SPECIAL_STRINGS)).replace("___sep___", "|") + r"|[" + + re.escape("___sep___".join(SPECIAL_STRINGS) + ).replace("___sep___", "|") + r"|[" + re.escape("".join(SPECIAL_CHARS)) + r"])") WORD_PATTERN = re.compile(r"^[^\s" + re.escape("".join(SPECIAL_CHARS)) + r"]+$") SCOPE_IN = ['do', 'then', 'function'] -SCOPE_OUT = ['end', 'elseif'] # 'elseif' because it comes with a second 'then'. +# 'elseif' because it comes with a second 'then'. +SCOPE_OUT = ['end', 'elseif'] def tokenize(lua): @@ -136,7 +138,8 @@ def find_table_end(tokens, start_index): if depth == 0: return i + 1 - print("Fatal error occurred.", "Please check that your input is syntactically correct.", sep="\n") + print("Fatal error occurred.", + "Please check that your input is syntactically correct.", sep="\n") exit(0) @@ -162,4 +165,4 @@ def is_word(s): def is_number(s): - return s.isdigit() \ No newline at end of file + return s.isdigit()