{"id":25902049,"url":"https://github.com/BetterWayElectronics/diy-pyarmor-rft-mode","last_synced_at":"2025-03-03T03:02:17.392Z","repository":{"id":276753249,"uuid":"930162132","full_name":"BetterWayElectronics/diy-pyarmor-rft-mode","owner":"BetterWayElectronics","description":"DIY PyArmor RFT Mode is an AST-based obfuscation tool that mimics the renaming functionality of PyArmor’s RFT mode. ","archived":false,"fork":false,"pushed_at":"2025-03-02T11:27:16.000Z","size":50,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-02T12:27:45.008Z","etag":null,"topics":["pyarmor","pyarmor-rft","python","python-ast","python-encode","python-obfuscator","python-renamer"],"latest_commit_sha":null,"homepage":"https://www.betterwayelectronics.com.au","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BetterWayElectronics.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-10T07:15:12.000Z","updated_at":"2025-03-02T11:27:20.000Z","dependencies_parsed_at":"2025-02-10T08:42:28.904Z","dependency_job_id":null,"html_url":"https://github.com/BetterWayElectronics/diy-pyarmor-rft-mode","commit_stats":null,"previous_names":["betterwayelectronics/diy-pyarmor-rft-mode"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BetterWayElectronics%2Fdiy-pyarmor-rft-mode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BetterWayElectronics%2Fdiy-pyarmor-rft-mode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BetterWayElectronics%2Fdiy-pyarmor-rft-mode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BetterWayElectronics%2Fdiy-pyarmor-rft-mode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BetterWayElectronics","download_url":"https://codeload.github.com/BetterWayElectronics/diy-pyarmor-rft-mode/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241600487,"owners_count":19988713,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pyarmor","pyarmor-rft","python","python-ast","python-encode","python-obfuscator","python-renamer"],"created_at":"2025-03-03T03:01:31.146Z","updated_at":"2025-03-03T03:02:17.384Z","avatar_url":"https://github.com/BetterWayElectronics.png","language":"Python","funding_links":[],"categories":["Obfuscators"],"sub_categories":["Manual analysis"],"readme":"# DIY PyArmor RFT Mode\n\nDIY PyArmor RFT Mode is an AST-based obfuscation tool that mimics the renaming functionality of PyArmor’s RFT mode. It systematically renames function names, class names, global and local variables, builtin references, and import aliases—while preserving function argument names, keyword argument names, any identifier that starts with `__`, strings in the module attribute `__all__`, and any names you choose to exclude.\n\nThe tool runs interactively:\n- It scans the current working directory for Python (`.py`) files.\n- It prompts you to select the file to transform.\n- It asks for a custom alias prefix (default is `BwE_`).\n- It allows you to enter a comma-separated list of identifiers to exclude from renaming.\n- It outputs the transformed code as `\u003cfilename\u003e_rft.py` and writes a detailed rename log as `\u003cfilename\u003e_tracelog.log`.\n\n## Features\n\n- **AST-based Renaming**:\n  - Renames **function names**, **class names**, **global and local variables**, **builtin references**, and **import aliases**.\n- **Exclusions**:\n  - Skips renaming for:\n    - Function arguments in definitions.\n    - Keyword argument names in calls.\n    - Any identifier that starts with `__` (e.g. `__init__`, `__all__`, `__name__`).\n    - Strings in the module attribute `__all__`.\n    - Any names provided in the exclude list.\n- **Interactive File Selection**:\n  - Automatically lists all `.py` files in the current directory for you to choose from.\n- **Custom Alias Prefix**:\n  - Allows you to specify a custom prefix for generated aliases (default is `BwE_`).\n- **Rename Log**:\n  - Outputs a log file named `\u003cfilename\u003e_tracelog.log` that lists each renaming event with its corresponding line number.\n\n## Requirements\n\n- **Python 3.6+** (Python 3.9+ is recommended if you want to use `ast.unparse` instead of `astunparse`).\n- The **`astunparse`** package (if using Python versions older than 3.9):\n  ```bash\n  pip install astunparse\n\n## Example\n\nGiven an original `hello.py`\n\n```#!/usr/bin/env python3\n\nimport random\nimport base64\nimport string\nimport secrets\nimport binascii\nfrom Crypto.Cipher import AES\nimport hashlib\nfrom math import log2\n\ndef pointless_banner():\n    banner = r\"\"\"\n__________          ___________\n\\______   \\___  _  _\\_   _____/\n |    |  _/\\  \\/ \\/ /|   __)_ \n |    |   \\ \\      //        \\\n |______  /  \\_/\\_//_______  /\n        \\/                 \\/\n\"\"\"\n    print(banner)\n\ndef scramble_text(txt):\n    arr = list(txt)\n    random.shuffle(arr)\n    return ''.join(arr)\n\ndef calculate_entropy(data):\n    prob = {char: data.count(char) / len(data) for char in set(data)}\n    return -sum(p * log2(p) for p in prob.values())\n\ndef rot18(text):\n    table = str.maketrans(\n        string.ascii_uppercase + string.ascii_lowercase + string.digits,\n        string.ascii_uppercase[13:] + string.ascii_uppercase[:13] +\n        string.ascii_lowercase[13:] + string.ascii_lowercase[:13] +\n        string.digits[5:] + string.digits[:5]\n    )\n    return text.translate(table)\n\ndef to_binary(data):\n    return ''.join(format(ord(c), '08b') for c in data)\n\ndef reverse_bytes(data):\n    hex_data = binascii.hexlify(data.encode()).decode()\n    return ''.join([hex_data[i:i+2] for i in range(0, len(hex_data), 2)][::-1])\n\ndef aes_encrypt(data, key):\n    key = hashlib.sha256(key.encode()).digest()\n    cipher = AES.new(key, AES.MODE_EAX)\n    ciphertext, tag = cipher.encrypt_and_digest(data.encode())\n    return base64.b64encode(cipher.nonce + tag + ciphertext).decode()\n\ndef main():\n    pointless_banner()\n    u = input(\"Type something: \")\n    print(\"Base64:\", base64.b64encode(u.encode()).decode())\n    print(\"Entropy:\", calculate_entropy(u))\n    print(\"ROT18:\", rot18(u))\n    print(\"Binary:\", to_binary(u))\n    print(\"Byte Reversed:\", reverse_bytes(u))\n    print(\"AES Encrypted:\", aes_encrypt(u, 'pyarmoriscool'))\n    input(\"Press Enter to quit...\")\n\nif __name__ == \"__main__\":\n    main()\n```\n\n### Post Obfuscation\n\n```import base64\nimport builtins\nBwE_78142 = getattr(builtins, base64.b64decode(\"cHJpbnQ=\").decode())\nBwE_79432 = getattr(builtins, base64.b64decode(\"bGlzdA==\").decode())\nBwE_59119 = getattr(builtins, base64.b64decode(\"c2V0\").decode())\nBwE_83485 = getattr(builtins, base64.b64decode(\"bGVu\").decode())\nBwE_30150 = getattr(builtins, base64.b64decode(\"c3Vt\").decode())\nBwE_23312 = getattr(builtins, base64.b64decode(\"c3Ry\").decode())\nBwE_43630 = getattr(builtins, base64.b64decode(\"Zm9ybWF0\").decode())\nBwE_11014 = getattr(builtins, base64.b64decode(\"b3Jk\").decode())\nBwE_68792 = getattr(builtins, base64.b64decode(\"cmFuZ2U=\").decode())\nBwE_80301 = getattr(builtins, base64.b64decode(\"aW5wdXQ=\").decode())\n\nimport random as BwE_60249\nimport base64 as BwE_56370\nimport string as BwE_21763\nimport secrets as BwE_19661\nimport binascii as BwE_78577\nfrom Crypto.Cipher import AES as BwE_80065\nimport hashlib as BwE_05887\nfrom math import log2 as BwE_75993\n\ndef BwE_71821():\n    BwE_96432 = '\\n__________          ___________\\n\\\\______   \\\\___  _  _\\\\_   _____/\\n |    |  _/\\\\  \\\\/ \\\\/ /|   __)_ \\n |    |   \\\\ \\\\      //        \\\\\\n |______  /  \\\\_/\\\\_//_______  /\\n        \\\\/                 \\\\/\\n'\n    BwE_78142(BwE_96432)\n\ndef BwE_55875(txt):\n    BwE_62684 = BwE_79432(txt)\n    BwE_60249.shuffle(BwE_62684)\n    return ''.join(BwE_62684)\n\ndef BwE_86601(data):\n    BwE_08559 = {BwE_16840: (data.count(BwE_16840) / BwE_83485(data)) for BwE_16840 in BwE_59119(data)}\n    return (- BwE_30150(((BwE_47176 * BwE_75993(BwE_47176)) for BwE_47176 in BwE_08559.values())))\n\ndef BwE_99230(text):\n    BwE_26962 = BwE_23312.maketrans(((BwE_21763.ascii_uppercase + BwE_21763.ascii_lowercase) + BwE_21763.digits), (((((BwE_21763.ascii_uppercase[13:] + BwE_21763.ascii_uppercase[:13]) + BwE_21763.ascii_lowercase[13:]) + BwE_21763.ascii_lowercase[:13]) + BwE_21763.digits[5:]) + BwE_21763.digits[:5]))\n    return text.translate(BwE_26962)\n\ndef BwE_73833(data):\n    return ''.join((BwE_43630(BwE_11014(BwE_71590), '08b') for BwE_71590 in data))\n\ndef BwE_99644(data):\n    BwE_03204 = BwE_78577.hexlify(data.encode()).decode()\n    return ''.join([BwE_03204[BwE_28021:(BwE_28021 + 2)] for BwE_28021 in BwE_68792(0, BwE_83485(BwE_03204), 2)][::(- 1)])\n\ndef BwE_19451(data, key):\n    key = BwE_05887.sha256(key.encode()).digest()\n    BwE_87340 = BwE_80065.new(key, BwE_80065.MODE_EAX)\n    (BwE_32200, BwE_79708) = BwE_87340.encrypt_and_digest(data.encode())\n    return BwE_56370.b64encode(((BwE_87340.nonce + BwE_79708) + BwE_32200)).decode()\n\ndef BwE_17395():\n    BwE_71821()\n    BwE_21786 = BwE_80301('Type something: ')\n    BwE_78142('Base64:', BwE_56370.b64encode(BwE_21786.encode()).decode())\n    BwE_78142('Entropy:', BwE_86601(BwE_21786))\n    BwE_78142('ROT18:', BwE_99230(BwE_21786))\n    BwE_78142('Binary:', BwE_73833(BwE_21786))\n    BwE_78142('Byte Reversed:', BwE_99644(BwE_21786))\n    BwE_78142('AES Encrypted:', BwE_19451(BwE_21786, 'pyarmoriscool'))\n    BwE_80301('Press Enter to quit...')\nif (__name__ == '__main__'):\n    BwE_17395()\n```\n\n### PyArmor's RFT Mode\n\n```\n#!/usr/bin/env python3\nimport base64\nimport builtins\nimport random as pyarmor__9\nimport base64 as pyarmor__10\nimport string as pyarmor__11\nimport secrets as pyarmor__12\nimport binascii as pyarmor__13\nfrom Crypto.Cipher import AES as pyarmor__14\nimport hashlib as pyarmor__15\nfrom math import log2 as pyarmor__16\n\ndef pyarmor__1():\n    pyarmor__17 = r\"\"\"\n__________          ___________\n\\______   \\___  _  _\\_   _____/\n |    |  _/\\  \\/ \\/ /|   __)_ \n |    |   \\ \\      //        \\\n |______  /  \\_/\\_//_______  /\n        \\/                 \\/\n\"\"\"\n    pyarmor__18(pyarmor__17)\n\ndef pyarmor__2(txt):\n    pyarmor__19 = pyarmor__20(txt)\n    pyarmor__9.shuffle(pyarmor__19)\n    return ''.join(pyarmor__19)\n\ndef pyarmor__3(data):\n    pyarmor__21 = {pyarmor__22: data.count(pyarmor__22) / pyarmor__23(data) for pyarmor__22 in pyarmor__24(data)}\n    return -pyarmor__25(pyarmor__26 * pyarmor__16(pyarmor__26) for pyarmor__26 in pyarmor__21.values())\n\ndef pyarmor__4(text):\n    pyarmor__27 = pyarmor__28.maketrans(\n        pyarmor__11.ascii_uppercase + pyarmor__11.ascii_lowercase + pyarmor__11.digits,\n        pyarmor__11.ascii_uppercase[13:] + pyarmor__11.ascii_uppercase[:13] +\n        pyarmor__11.ascii_lowercase[13:] + pyarmor__11.ascii_lowercase[:13] +\n        pyarmor__11.digits[5:] + pyarmor__11.digits[:5]\n    )\n    return text.translate(pyarmor__27)\n\ndef pyarmor__5(data):\n    return ''.join(pyarmor__29(pyarmor__30(pyarmor__31), '08b') for pyarmor__31 in data)\n\ndef pyarmor__6(data):\n    pyarmor__32 = pyarmor__13.hexlify(data.encode()).decode()\n    return ''.join([pyarmor__32[pyarmor__33:pyarmor__33+2] for pyarmor__33 in pyarmor__34(0, pyarmor__23(pyarmor__32), 2)][::-1])\n\ndef pyarmor__7(data, key):\n    key = pyarmor__15.sha256(key.encode()).digest()\n    pyarmor__35 = pyarmor__14.new(key, pyarmor__14.MODE_EAX)\n    pyarmor__36, pyarmor__37 = pyarmor__35.encrypt_and_digest(data.encode())\n    return pyarmor__10.b64encode(pyarmor__35.nonce + pyarmor__37 + pyarmor__36).decode()\n\ndef pyarmor__8():\n    pyarmor__1()\n    pyarmor__38 = pyarmor__39(\"Type something: \")\n    pyarmor__18(\"Base64:\", pyarmor__10.b64encode(pyarmor__38.encode()).decode())\n    pyarmor__18(\"Entropy:\", pyarmor__3(pyarmor__38))\n    pyarmor__18(\"ROT18:\", pyarmor__4(pyarmor__38))\n    pyarmor__18(\"Binary:\", pyarmor__5(pyarmor__38))\n    pyarmor__18(\"Byte Reversed:\", pyarmor__6(pyarmor__38))\n    pyarmor__18(\"AES Encrypted:\", pyarmor__7(pyarmor__38, 'pyarmoriscool'))\n    pyarmor__39(\"Press Enter to quit...\")\n\nif __name__ == \"__main__\":\n    pyarmor__8()\n\n```\n\nAs you can see the functionality is identical to that of PyArmor!\n\n## My Trace Log Example (Truncated)\n\n```Line 3: random -\u003e BwE_60249\nLine 4: base64 -\u003e BwE_56370\nLine 5: string -\u003e BwE_21763\nLine 6: secrets -\u003e BwE_19661\nLine 7: binascii -\u003e BwE_78577\nLine 8: AES -\u003e BwE_80065\nLine 9: hashlib -\u003e BwE_05887\nLine 10: log2 -\u003e BwE_75993\nLine 12: pointless_banner -\u003e BwE_71821\nLine 13: banner -\u003e BwE_96432\nLine 21: print -\u003e BwE_78142\nLine 21: banner -\u003e BwE_96432\nLine 23: scramble_text -\u003e BwE_55875\nLine 24: arr -\u003e BwE_62684\nLine 24: list -\u003e BwE_79432\nLine 25: random -\u003e BwE_60249\nLine 25: arr -\u003e BwE_62684\nLine 26: arr -\u003e BwE_62684\nLine 28: calculate_entropy -\u003e BwE_86601\nLine 29: prob -\u003e BwE_08559\nLine 29: char -\u003e BwE_16840\nLine 29: set -\u003e BwE_59119\nLine 29: char -\u003e BwE_16840\nLine 29: char -\u003e BwE_16840\nLine 29: len -\u003e BwE_83485\nLine 30: sum -\u003e BwE_30150\nLine 30: p -\u003e BwE_47176\nLine 30: prob -\u003e BwE_08559\nLine 30: p -\u003e BwE_47176\nLine 30: log2 -\u003e BwE_75993\nLine 30: p -\u003e BwE_47176\n```\n\n## PyArmor's Trace Log Example (Truncated)\n\n```trace.rft            hello:3 (import random as pyarmor__9)\ntrace.rft            hello:4 (import base64 as pyarmor__10)\ntrace.rft            hello:5 (import string as pyarmor__11)\ntrace.rft            hello:6 (import secrets as pyarmor__12)\ntrace.rft            hello:7 (import binascii as pyarmor__13)\ntrace.rft            hello:8 (from Crypto.Cipher import AES as pyarmor__14)\ntrace.rft            hello:9 (import hashlib as pyarmor__15)\ntrace.rft            hello:10 (from math import log2 as pyarmor__16)\ntrace.rft            hello:12 (pointless_banner-\u003epyarmor__1)\ntrace.rft            hello:13 (banner-\u003epyarmor__17)\ntrace.rft            hello:21 (print-\u003epyarmor__18)\ntrace.rft            hello:21 (banner-\u003epyarmor__17)\ntrace.rft            hello:23 (scramble_text-\u003epyarmor__2)\ntrace.rft            hello:24 (arr-\u003epyarmor__19)\ntrace.rft            hello:24 (list-\u003epyarmor__20)\ntrace.rft            hello:25 (random-\u003epyarmor__9)\ntrace.rft            hello:25 (arr-\u003epyarmor__19)\ntrace.rft            hello:26 (arr-\u003epyarmor__19)\ntrace.rft            hello:28 (calculate_entropy-\u003epyarmor__3)\ntrace.rft            hello:29 (prob-\u003epyarmor__21)\ntrace.rft            hello:29 (char-\u003epyarmor__22)\ntrace.rft            hello:29 (char-\u003epyarmor__22)\ntrace.rft            hello:29 (len-\u003epyarmor__23)\ntrace.rft            hello:29 (char-\u003epyarmor__22)\ntrace.rft            hello:29 (set-\u003epyarmor__24)\ntrace.rft            hello:30 (sum-\u003epyarmor__25)\ntrace.rft            hello:30 (p-\u003epyarmor__26)\ntrace.rft            hello:30 (log2-\u003epyarmor__16)\ntrace.rft            hello:30 (p-\u003epyarmor__26)\ntrace.rft            hello:30 (p-\u003epyarmor__26)\ntrace.rft            hello:30 (prob-\u003epyarmor__21)\n```\n\nFunctionally identical!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBetterWayElectronics%2Fdiy-pyarmor-rft-mode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FBetterWayElectronics%2Fdiy-pyarmor-rft-mode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBetterWayElectronics%2Fdiy-pyarmor-rft-mode/lists"}