diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b9c127d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = crlf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..068955e --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @ByteCorum \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..54dd1b6 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: bytecorum # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 0000000..4cb62a7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,30 @@ +--- +name: Bug Report +about: Please take your time and provide us some info about an issue that you've faced. +title: "Bug: " +labels: bug, no-priority +assignees: ByteCorum +--- + +### Description + +A field to provide the detailed info about faced issue. + +### Condition & circumstances + +A field to provide the information how did u get this issue and how to reproduce these circumstances. + +### Expected behavior + +A field to provide the information of what have you expected to happen. + +### PC configuration + +- CPU: +- GPU: +- RAM: +- OS: + +### Additional context + +A field to provide any other context about the problem: logs, screenshots, debug info. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..c324c06 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Contact Author + url: https://discord.com/users/798503509522645012 + about: Author's discord account. + - name: Stackoverflow + url: https://stackoverflow.com/users/26622521/bytecorum + about: Maybe you can find solution on stackoverflow. diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 0000000..dd4abfa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,25 @@ +--- +name: Feature request +about: "Please take your time and provide us info about your idea for this project " +title: "Request: " +labels: suggestion, no-priority +assignees: ByteCorum +--- + +### General + +- Related issue or pr: +- Similar to feature in todo: +- Should be involved in: + +### Description + +A field to provide the detailed info about your idea and what you want to happen. + +### Alternatives + +A field to provide the description of any alternative solutions or features you've considered. + +### Additional context + +A field to provide any other context about the idea: templates, screenshots, code blocks. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000..974b4b0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,21 @@ +--- +name: Question +about: Please take your time and tell us about your question. +title: "Question: " +labels: question, no-priority +assignees: ByteCorum +--- + +### Basic + +- Related issue or pr: +- Related functionality: +- Should be documented: y/n + +### Description + +A field to provide the detailed info about faced issue. + +### Additional context + +A field to provide any other context about the question: screenshots, code blocks. diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 0000000..1bf7cd8 --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,73 @@ +# Type +- name: "bug" + color: ee0701 + description: "Something isn't working as expected or causes issues." +- name: "question" + color: cc317c + description: "Further information is requested or clarification needed." +- name: "suggestion" + color: 84b6eb + description: "Ideas for improvements or new features." +- name: "docs" + color: 0075ca + description: "Documentation improvements or additions." +- name: "feat" + color: 0e8a16 + description: "New feature or functionality." +- name: "fix" + color: ee0701 + description: "Bug fix or correction." +- name: "style" + color: f9d0c4 + description: "Code style, formatting, or cosmetic changes." +- name: "refactor" + color: fbca04 + description: "Code restructuring without changing functionality." +- name: "test" + color: 1d76db + description: "Adding or updating tests." +- name: "chore" + color: fef2c0 + description: "Maintenance tasks, build processes, or tooling changes." + +# Priority +- name: "high-priority" + color: b60205 + description: "High priority issue that should be addressed urgently." +- name: "medium-priority" + color: fbca04 + description: "Medium priority issue for normal workflow." +- name: "low-priority" + color: 0e8a16 + description: "Low priority issue that can be addressed when time permits." +- name: "no-priority" + color: e4e669 + description: "No specific priority assigned." + +# Status +- name: "wip-status" + color: ff9500 + description: "Work in progress - currently being worked on." +- name: "suspended-status" + color: 5319e7 + description: "Work has been suspended or put on hold." +- name: "invalid-status" + color: 000000 + description: "This issue or pull request is not valid." +- name: "duplicate-status" + color: cccccc + description: "This issue or pull request already exists." +- name: "wontfix-status" + color: ffffff + description: "This will not be worked on or fixed." + +# Impact +- name: "major" + color: d73a4a + description: "Major changes with significant impact." +- name: "minor" + color: 0075ca + description: "Minor changes with limited impact." +- name: "regular" + color: 28a745 + description: "Regular changes as part of normal development." diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..6e37202 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,31 @@ + + +### General + +- Related issue: +- Related functionality: +- Feature in todo: +- Should be documented: y/n + + +### Type + +- [ ] Bugfix +- [ ] Feature +- [ ] Code style update +- [ ] Refactor +- [ ] Tests-related changes +- [ ] Documentation content changes +- [ ] Other (please describe): + +### Description + +A field to provide the detailed info about what have you modified. + +### Effect + +A field to provide the detailed info about how do your changes affect entire project. + +## Other information + +A field to provide any other context about your changes: logs, screenshots, debug info. diff --git a/.github/workflows/issues-reply.yml b/.github/workflows/issues-reply.yml new file mode 100644 index 0000000..d365fce --- /dev/null +++ b/.github/workflows/issues-reply.yml @@ -0,0 +1,59 @@ +name: Auto-Reply to Issues + +on: + issues: + types: [opened] + +jobs: + auto-reply: + runs-on: ubuntu-latest + steps: + - name: Reply to issue based on type + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issue = context.payload.issue; + const issueTitle = issue.title.toLowerCase(); + const issueBody = issue.body || ''; + const labels = issue.labels.map(label => label.name); + let issueComment = ''; + + // Determine issue type and set appropriate response + if (labels.includes('bug') || issueTitle.includes('bug:')) { + issueComment = `**Thank you for reporting this bug!** + We appreciate you taking the time to provide detailed information about the issue you've encountered. Our team will investigate this bug and work on a fix as soon as possible. + Thank you for helping us improve our software!`; + + } else if (labels.includes('enhancement') || issueTitle.includes('request:')) { + issueComment = `**Thank you for your feature request!** + We're excited to hear your ideas for improving our project. Feature requests from our community are valuable and help shape the future direction of our software. + Thank you for contributing to our project's growth!`; + + } else if (labels.includes('question') || issueTitle.includes('question:')) { + issueComment = `**Thank you for your question!** + We're here to help you get the most out of our software. Questions from users help us identify areas where our documentation can be improved. + We appreciate your engagement with our project!`; + + } else { + // Generic response for unclassified issues + issueComment = `**Thank you for opening this issue!** + We appreciate you taking the time to contribute to our project. To help us assist you better, please: + Our team will review and respond soon. Thank you for using our software!`; + } + + // Post the comment + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: issueComment + }); + + // Add reaction to show the bot has processed the issue + await github.rest.reactions.createForIssue({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + content: 'eyes' + }); diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml deleted file mode 100644 index 5217bd4..0000000 --- a/.github/workflows/issues.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Auto-Reply to Issues - -on: - issues: - types: [opened] - -jobs: - auto-reply: - runs-on: ubuntu-latest - steps: - - name: Reply to issue - uses: actions/github-script@v5 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const issueComment = ` - 🖐️ Hello @${{ github.actor }}! - Thanks for using our software! We will look into and fix your issue asap.`; - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: issueComment - }); - - github.rest.issues.update({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: ['new'] - }); \ No newline at end of file diff --git a/.github/workflows/linux-tests.yml b/.github/workflows/linux-tests.yml new file mode 100644 index 0000000..4a8ae50 --- /dev/null +++ b/.github/workflows/linux-tests.yml @@ -0,0 +1,231 @@ +name: Linux tests + +on: + push: + branches: [ stable, WIP ] + pull_request: + branches: [ stable, WIP ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Build Executable + working-directory: scr + run: | + chmod +x build-linux.sh + ./build-linux.sh + - name: Archive Executable + uses: actions/upload-artifact@v4 + with: + name: dotpyguard-linux + path: scr/dotpyguard + + obfuscation-multifile-linux: + needs: ["build"] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Download Executable + uses: actions/download-artifact@v4 + with: + name: dotpyguard-linux + path: "examples" + + - name: Preparation For Tests + working-directory: examples + run: | + mv dotpyguard multifile/ + chmod +x multifile/dotpyguard + rm -rf multifile/obfuscated + + - name: Obfuscation + working-directory: examples/multifile + run: | + ./dotpyguard obfuscate --aes --hashdata --fernet --chacha --salsa --base64 --recursive 4 --follow-imports --no-input --files lib.py main.py + + - name: Testing + working-directory: examples/multifile/obfuscated + run: | + OUTPUT=$(python main.py) + echo "Output: " + echo "$OUTPUT" + + echo "Result: " + if [ "$OUTPUT" = "hello world" ]; then + echo "Success: main.py output contains 'hello world'" + else + echo "Failure: main.py output does not contain 'hello world'" + exit 1 + fi + + obfuscation-onefile-linux: + needs: ["build"] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Download Executable + uses: actions/download-artifact@v4 + with: + name: dotpyguard-linux + path: "examples" + + - name: Preparation For Tests + working-directory: examples + run: | + mv dotpyguard onefile/ + chmod +x onefile/dotpyguard + rm -rf onefile/obfuscated + + - name: Obfuscation + working-directory: examples/onefile + run: | + ./dotpyguard obfuscate --aes --hashdata --fernet --chacha --salsa --base64 --recursive 4 --follow-imports --no-input main.py + + - name: Testing + working-directory: examples/onefile/obfuscated + run: | + OUTPUT=$(python main.py) + echo "Output: " + echo "$OUTPUT" + + echo "Result: " + if [ "$OUTPUT" = "hello world" ]; then + echo "Success: main.py output contains 'hello world'" + else + echo "Failure: main.py output does not contain 'hello world'" + exit 1 + fi + + obfuscationlegacy-multifile-linux: + needs: ["build"] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Download Executable + uses: actions/download-artifact@v4 + with: + name: dotpyguard-linux + path: "examples" + + - name: Preparation For Tests + working-directory: examples + run: | + mv dotpyguard multifile-legacy/ + chmod +x multifile-legacy/dotpyguard + rm -rf multifile-legacy/obfuscated + + - name: Obfuscation + working-directory: examples/multifile-legacy + run: | + ./dotpyguard obfuscatelegacy --no-input --mode 4 --loops 6 --files lib.py,main.py + + - name: Testing + working-directory: examples/multifile-legacy/obfuscated + run: | + OUTPUT=$(python main.py) + echo "Output: " + echo "$OUTPUT" + + echo "Result: " + if [ "$OUTPUT" = "hello world" ]; then + echo "Success: main.py output contains 'hello world'" + else + echo "Failure: main.py output does not contain 'hello world'" + exit 1 + fi + + obfuscationlegacy-onefile-linux: + needs: ["build"] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Download Executable + uses: actions/download-artifact@v4 + with: + name: dotpyguard-linux + path: "examples" + + - name: Preparation For Tests + working-directory: examples + run: | + mv dotpyguard onefile-legacy/ + chmod +x onefile-legacy/dotpyguard + rm -rf onefile-legacy/obfuscated + + - name: Obfuscation + working-directory: examples/onefile-legacy + run: | + ./dotpyguard obfuscatelegacy --no-input --mode 4 --loops 6 --files main.py + + - name: Testing + working-directory: examples/onefile-legacy/obfuscated + run: | + OUTPUT=$(python main.py) + echo "Output: " + echo "$OUTPUT" + + echo "Result: " + if [ "$OUTPUT" = "hello world" ]; then + echo "Success: main.py output contains 'hello world'" + else + echo "Failure: main.py output does not contain 'hello world'" + exit 1 + fi \ No newline at end of file diff --git a/.github/workflows/mac-tests.yml b/.github/workflows/mac-tests.yml new file mode 100644 index 0000000..b9914eb --- /dev/null +++ b/.github/workflows/mac-tests.yml @@ -0,0 +1,231 @@ +name: MacOS tests + +on: + push: + branches: [ stable, WIP ] + pull_request: + branches: [ stable, WIP ] + +jobs: + build: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Build Executable + working-directory: scr + run: | + chmod +x build-mac.sh + ./build-mac.sh + - name: Archive Executable + uses: actions/upload-artifact@v4 + with: + name: dotpyguard-mac + path: scr/dotpyguard + + obfuscation-multifile-macos: + needs: ["build"] + runs-on: macos-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Download Executable + uses: actions/download-artifact@v4 + with: + name: dotpyguard-mac + path: "examples" + + - name: Preparation For Tests + working-directory: examples + run: | + mv dotpyguard multifile/ + chmod +x multifile/dotpyguard + rm -rf multifile/obfuscated + + - name: Obfuscation + working-directory: examples/multifile + run: | + ./dotpyguard obfuscate --aes --hashdata --fernet --chacha --salsa --base64 --recursive 4 --follow-imports --no-input --files lib.py main.py + + - name: Testing + working-directory: examples/multifile/obfuscated + run: | + OUTPUT=$(python main.py) + echo "Output: " + echo "$OUTPUT" + + echo "Result: " + if [ "$OUTPUT" = "hello world" ]; then + echo "Success: main.py output contains 'hello world'" + else + echo "Failure: main.py output does not contain 'hello world'" + exit 1 + fi + + obfuscation-onefile-macos: + needs: ["build"] + runs-on: macos-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Download Executable + uses: actions/download-artifact@v4 + with: + name: dotpyguard-mac + path: "examples" + + - name: Preparation For Tests + working-directory: examples + run: | + mv dotpyguard onefile/ + chmod +x onefile/dotpyguard + rm -rf onefile/obfuscated + + - name: Obfuscation + working-directory: examples/onefile + run: | + ./dotpyguard obfuscate --aes --hashdata --fernet --chacha --salsa --base64 --recursive 4 --follow-imports --no-input main.py + + - name: Testing + working-directory: examples/onefile/obfuscated + run: | + OUTPUT=$(python main.py) + echo "Output: " + echo "$OUTPUT" + + echo "Result: " + if [ "$OUTPUT" = "hello world" ]; then + echo "Success: main.py output contains 'hello world'" + else + echo "Failure: main.py output does not contain 'hello world'" + exit 1 + fi + + obfuscationlegacy-multifile-macos: + needs: ["build"] + runs-on: macos-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Download Executable + uses: actions/download-artifact@v4 + with: + name: dotpyguard-mac + path: "examples" + + - name: Preparation For Tests + working-directory: examples + run: | + mv dotpyguard multifile-legacy/ + chmod +x multifile-legacy/dotpyguard + rm -rf multifile-legacy/obfuscated + + - name: Obfuscation + working-directory: examples/multifile-legacy + run: | + ./dotpyguard obfuscatelegacy --no-input --mode 4 --loops 6 --files lib.py,main.py + + - name: Testing + working-directory: examples/multifile-legacy/obfuscated + run: | + OUTPUT=$(python main.py) + echo "Output: " + echo "$OUTPUT" + + echo "Result: " + if [ "$OUTPUT" = "hello world" ]; then + echo "Success: main.py output contains 'hello world'" + else + echo "Failure: main.py output does not contain 'hello world'" + exit 1 + fi + + obfuscationlegacy-onefile-macos: + needs: ["build"] + runs-on: macos-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Download Executable + uses: actions/download-artifact@v4 + with: + name: dotpyguard-mac + path: "examples" + + - name: Preparation For Tests + working-directory: examples + run: | + mv dotpyguard onefile-legacy/ + chmod +x onefile-legacy/dotpyguard + rm -rf onefile-legacy/obfuscated + + - name: Obfuscation + working-directory: examples/onefile-legacy + run: | + ./dotpyguard obfuscatelegacy --no-input --mode 4 --loops 6 --files main.py + + - name: Testing + working-directory: examples/onefile-legacy/obfuscated + run: | + OUTPUT=$(python main.py) + echo "Output: " + echo "$OUTPUT" + + echo "Result: " + if [ "$OUTPUT" = "hello world" ]; then + echo "Success: main.py output contains 'hello world'" + else + echo "Failure: main.py output does not contain 'hello world'" + exit 1 + fi \ No newline at end of file diff --git a/.github/workflows/prs-reply.yml b/.github/workflows/prs-reply.yml new file mode 100644 index 0000000..d136419 --- /dev/null +++ b/.github/workflows/prs-reply.yml @@ -0,0 +1,44 @@ +name: Auto-Reply to Pull Requests +on: + pull_request: + types: [opened, ready_for_review] + +jobs: + auto-reply: + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + steps: + - name: Reply to pull request + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const pr = context.payload.pull_request; + const isDraft = pr.draft; + + // Skip if it's a draft PR being opened (not converted to ready) + if (isDraft && context.payload.action === 'opened') { + return; + } + + let prComment = `**Thank you for contributing into our project!** + We appreciate the invest of your time and efforts to help us improve our project. + Your pull request will be reviewed as soon as possible!`; + + // Post the comment + await github.rest.issues.createComment({ + issue_number: pr.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: prComment + }); + + // Add reaction to show the bot has processed the issue + await github.rest.reactions.createForIssue({ + issue_number: pr.number, + owner: context.repo.owner, + repo: context.repo.repo, + content: 'eyes' + }); diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml deleted file mode 100644 index 37cc4bc..0000000 --- a/.github/workflows/pull-request.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Auto-Reply to PR -on: - pull_request: - types: [opened] - -jobs: - comment: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Reply to PR - uses: actions/github-script@v5 - with: - script: | - const prComment = ` - 🖐️ Hello @${{ github.actor }}! - Thank you for your contribution. We will review your pull request soon. Please make sure you have followed our contributing guidelines. - `; - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: prComment - }); - - github.rest.issues.update({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: ['enhancement', 'new'] - }); diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml new file mode 100644 index 0000000..36d9641 --- /dev/null +++ b/.github/workflows/sync-labels.yml @@ -0,0 +1,23 @@ +name: Sync labels + +on: + push: + branches: + - main + - master + - stable + paths: + - .github/labels.yml + +jobs: + labels: + permissions: write-all + name: Sync labels + runs-on: ubuntu-latest + steps: + - name: Check out code from GitHub + uses: actions/checkout@v2 + - name: Run Label Syncer + uses: micnncim/action-label-syncer@v1.2.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/win-tests.yml similarity index 54% rename from .github/workflows/tests.yml rename to .github/workflows/win-tests.yml index a873831..a160ba5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/win-tests.yml @@ -1,4 +1,4 @@ -name: tests +name: Windows tests on: push: @@ -7,7 +7,7 @@ on: branches: [ stable, WIP ] jobs: - win-build: + build: runs-on: windows-latest steps: @@ -31,57 +31,109 @@ jobs: - name: Archive Executable uses: actions/upload-artifact@v4 with: - name: py-shield-win - path: scr/py-shield.exe + name: dotpyguard-win + path: scr\dotpyguard.exe + + obfuscation-multifile: + needs: ["build"] + runs-on: windows-latest - linux-build: - runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.12' - - name: Install dependencies + + - name: Install Dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - - name: Build Executable - working-directory: scr - run: | - chmod +x build-linux.sh - ./build-linux.sh - - name: Archive Executable - uses: actions/upload-artifact@v4 + + - name: Download Executable + uses: actions/download-artifact@v4 with: - name: py-shield-linux - path: scr/py-shield + name: dotpyguard-win + path: "examples" + + - name: Preparation For Tests + working-directory: examples + run: | + move "dotpyguard.exe" "multifile" + Remove-Item -Path "multifile\obfuscated" -Recurse -Force + + - name: Obfuscation + working-directory: examples\multifile + run: | + .\dotpyguard.exe obfuscate --aes --hashdata --fernet --chacha --salsa --base64 --recursive 4 --follow-imports --no-input --files lib.py main.py + + - name: Testing + working-directory: examples\multifile\obfuscated + run: | + $OUTPUT = $(python main.py) + Write-Host "Output: " + Write-Host $OUTPUT + + Write-Host "Result: " + if ($OUTPUT -eq "hello world") { + Write-Host "Success: main.py output contains 'hello world'" + } else { + Write-Host "Failure: main.py output does not contain 'hello world'" + exit 1 + } + + obfuscation-onefile: + needs: ["build"] + runs-on: windows-latest - mac-build: - runs-on: macos-latest steps: - uses: actions/checkout@v4 + - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.12' - - name: Install dependencies + + - name: Install Dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - - name: Build Executable - working-directory: scr - run: | - chmod +x build-mac.sh - ./build-mac.sh - - name: Archive Executable - uses: actions/upload-artifact@v4 + + - name: Download Executable + uses: actions/download-artifact@v4 with: - name: py-shield-mac - path: scr/py-shield + name: dotpyguard-win + path: "examples" + + - name: Preparation For Tests + working-directory: examples + run: | + move "dotpyguard.exe" "onefile" + Remove-Item -Path "onefile\obfuscated" -Recurse -Force + + - name: Obfuscation + working-directory: examples\onefile + run: | + .\dotpyguard.exe obfuscate --aes --hashdata --fernet --chacha --salsa --base64 --recursive 4 --follow-imports --no-input main.py - obfuscation-test: - needs: ["win-build", "linux-build", "mac-build"] + - name: Testing + working-directory: examples\onefile\obfuscated + run: | + $OUTPUT = $(python main.py) + Write-Host "Output: " + Write-Host $OUTPUT + + Write-Host "Result: " + if ($OUTPUT -eq "hello world") { + Write-Host "Success: main.py output contains 'hello world'" + } else { + Write-Host "Failure: main.py output does not contain 'hello world'" + exit 1 + } + + obfuscationlegacy-multifile: + needs: ["build"] runs-on: windows-latest steps: @@ -100,22 +152,22 @@ jobs: - name: Download Executable uses: actions/download-artifact@v4 with: - name: py-shield-win + name: dotpyguard-win path: "examples" - name: Preparation For Tests working-directory: examples run: | - move "py-shield.exe" "multifile" - Remove-Item -Path "multifile\obfuscated" -Recurse -Force + move "dotpyguard.exe" "multifile-legacy" + Remove-Item -Path "multifile-legacy\obfuscated" -Recurse -Force - name: Obfuscation - working-directory: examples\multifile + working-directory: examples\multifile-legacy run: | - .\py-shield.exe obfuscate --aes --hashdata --fernet --chacha --salsa --base64 --recursive 4 --no-input --files lib.py main.py + .\dotpyguard obfuscatelegacy --no-input --mode 3 --loops 6 --files lib.py,main.py - name: Testing - working-directory: examples\multifile\obfuscated + working-directory: examples\multifile-legacy\obfuscated run: | $OUTPUT = $(python main.py) Write-Host "Output: " @@ -129,8 +181,8 @@ jobs: exit 1 } - obfuscationlegacy-test: - needs: ["win-build", "linux-build", "mac-build"] + obfuscationlegacy-onefile: + needs: ["build"] runs-on: windows-latest steps: @@ -149,22 +201,22 @@ jobs: - name: Download Executable uses: actions/download-artifact@v4 with: - name: py-shield-win + name: dotpyguard-win path: "examples" - name: Preparation For Tests working-directory: examples run: | - move "py-shield.exe" "onefile" - Remove-Item -Path "onefile\obfuscated" -Recurse -Force + move "dotpyguard.exe" "onefile-legacy" + Remove-Item -Path "onefile-legacy\obfuscated" -Recurse -Force - name: Obfuscation - working-directory: examples\onefile + working-directory: examples\onefile-legacy run: | - .\py-shield obfuscatelegacy --no-input --mode 3 --loops 6 --files main.py + .\dotpyguard obfuscatelegacy --no-input --mode 4 --loops 6 --files main.py - name: Testing - working-directory: examples\onefile\obfuscated + working-directory: examples\onefile-legacy\obfuscated run: | $OUTPUT = $(python main.py) Write-Host "Output: " diff --git a/README.md b/README.md index 38b631c..be2567d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

- + @@ -15,7 +15,7 @@ --- -### 🛡Py-Shield🛡 +### 🛡.PyGuard🛡 Tool/Library for Python used to obfuscate and protect your code in static and runtime from decompilation, reverse debug, etc. Also, can prevent detection by antiviruses. @@ -23,10 +23,10 @@ Tool/Library for Python used to obfuscate and protect your code in static and ru ### 💻Supported Platforms💻 -- Python 3 up to latest -- Windows -- All Linux distributions -- Mac OS +- Python 3 up to latest +- Windows +- All Linux distributions +- Mac OS --- @@ -34,62 +34,62 @@ Tool/Library for Python used to obfuscate and protect your code in static and ru > **Static & Runtime Protection** > -> - Total advanced static and runtime protection from decompilation, reverse debug, etc. +> - Total advanced static and runtime protection from decompilation, reverse debug, etc. > **Hash Variables** > -> - Hash all variables and constants values in fragment of code. -> - Protects variables and constants content. +> - Hash all variables and constants values in fragment of code. +> - Protects variables and constants content. > **Recursive obfuscation** > -> - Recurseve encrypt fragment of code using base64 and zlib n times. -> - Best way to decrease/prevent antiviruses detection. +> - Recurseve encrypt fragment of code using base64 and zlib n times. +> - Best way to decrease/prevent antiviruses detection. > **Best encryption algorithms** > -> - Fernet, AES-GCM, ChaCha20, Salsa20 -> - Symmetric cipher which offer strong confidentiality, and provide authentication and integrity to protect against tampering. +> - Fernet, AES-GCM, ChaCha20, Salsa20 +> - Symmetric cipher which offer strong confidentiality, and provide authentication and integrity to protect against tampering. > **File Integrity Protection** > -> - Protect files against modification. -> - Advanced file hash/content integrity check and comparison. +> - Protect files against modification. +> - Advanced file hash/content integrity check and comparison. --- ### 🏁Quick start🏁 1. Clone repo - ``` - git clone https://github.com/ByteCorum/Py-Shield.git - ``` + ``` + git clone https://github.com/ByteCorum/.PyGuard.git + ``` 2. Install requirements - ``` - pip install -r requirements.txt - ``` + ``` + pip install -r requirements.txt + ``` 3. Usage info - ``` - py-shield --help - ``` + ``` + dotpyguard --help + ``` 4. Example - ``` - py-shield obfuscate --hashdata --aes --chacha --follow-imports main.py - ``` + ``` + dotpyguard obfuscate --hashdata --aes --chacha --follow-imports main.py + ``` 5. Output - ``` - #Obfuscated by Py-Shield 3.0.0.0 - from PyShield.script_55958136 import PyShield, _ - _(PyShield(b'x\x9c\x05\xc1\xc7\xa2k@\x00\x00\xd0\x0f\xb2P\xa3,\xdeB\...') - ``` + ``` + #Obfuscated by .PyGuard 3.1.0.0 + from DotPyGuard.script_55958136 import DotPyGuard, _ + _(DotPyGuard(b'x\x9c\x05\xc1\xc7\xa2k@\x00\x00\xd0\x0f\xb2P\xa3,\xdeB\...') + ``` 6. Example legacy - ``` - py-shield obfuscatelegacy --loops 3 --mode 2 --file code.py - ``` + ``` + dotpyguard obfuscatelegacy --loops 3 --mode 2 --file code.py + ``` 7. Output legacy - ``` - _=lambda __:__import__('zlib').decompress(__import__('cryptography.fernet').fernet.Fernet(__import__('base64').b64decode(((__import__('zlib').decompress(__))[::-1].split(b'eY3NTTr:S|dD'))[1])).decrypt(((__import__('zlib').decompress(__))[::-1].split(b'eY3NTTr:S|dD'))[0])[::-1]);exec((_x)(b'x\x9c\x15\x97U\xce\x86\...') - ``` + ``` + _=lambda __:__import__('zlib').decompress(__import__('cryptography.fernet').fernet.Fernet(__import__('base64').b64decode(((__import__('zlib').decompress(__))[::-1].split(b'eY3NTTr:S|dD'))[1])).decrypt(((__import__('zlib').decompress(__))[::-1].split(b'eY3NTTr:S|dD'))[0])[::-1]);exec((_x)(b'x\x9c\x15\x97U\xce\x86\...') + ``` --- diff --git a/TODO.txt b/TODO.txt deleted file mode 100644 index e69de29..0000000 diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md new file mode 100644 index 0000000..afd4e80 --- /dev/null +++ b/docs/ChangeLog.md @@ -0,0 +1,5 @@ +# Change log + +### Program v3.1.0.0 + +--- diff --git a/docs/CommitMessagesGuidance.md b/docs/CommitMessagesGuidance.md new file mode 100644 index 0000000..15e2082 --- /dev/null +++ b/docs/CommitMessagesGuidance.md @@ -0,0 +1,49 @@ +# Commit messages guidance + +### Basic suggestion + +- Don't mess all changes in one commit, commit per change +- Write exact and understandable subject +- Provide more detailed description +- Avoid non linear commit history + +### Structure + +Commit should be made up with three parts: + +``` + + + + + +``` + +#### Subject + +``` +(optional scope): (50 characters max) + +example: +chore: Update Python version to use newer libs +``` + +#### Description + +``` +More recent versions of important project libs no longer support Python +3.6. This has prevented us from using new features offered by such libs. +Add support for Python 3.12. +``` + +### Types table + +| Type | Description | +| :----------- | :------------------------------------------ | +| **feat** | Introduce a new feature to the codebase | +| **fix** | Fix a bug in the codebase | +| **docs** | Create/update documentation | +| **style** | Feature and updates related to styling | +| **refactor** | Refactor a specific section of the codebase | +| **test** | Add or update code related to testing | +| **chore** | Regular code maintenance | diff --git a/docs/Todo.md b/docs/Todo.md new file mode 100644 index 0000000..7bd561e --- /dev/null +++ b/docs/Todo.md @@ -0,0 +1,20 @@ +# Todo list + +### Height Priority + +- [x] Test imports manager on challenging cases +- [x] Rename the project + +### Medium Priority + +- [x] Add workflows to check obfuscation on mac and linux +- [x] Add workflows to check onefile/multifile legacy/global obfuscation + +### Low Priority + +- [x] Refactor self giving to cmds +- [ ] Publish as python lib + +### Suspended + +- [ ] Add precompilation of cmds dir diff --git a/examples/executor/PyShield.py b/examples/executor/DotPyGuard.py similarity index 99% rename from examples/executor/PyShield.py rename to examples/executor/DotPyGuard.py index 4010521..01d7fbf 100644 --- a/examples/executor/PyShield.py +++ b/examples/executor/DotPyGuard.py @@ -1,4 +1,3 @@ - from hashlib import sha256 from os import path, getcwd from Crypto.Cipher import ChaCha20 @@ -12,7 +11,7 @@ _ = exec -class PyShield: +class DotPyGuard: def __init__(self, code, file): try: self.__codee812520fd9c71232668515d6bd91bd4c386f014e41cc3bdd9262101759019196 = code diff --git a/examples/multifile-legacy/obfuscate.bat b/examples/multifile-legacy/obfuscate.bat index fb13979..1be079a 100644 --- a/examples/multifile-legacy/obfuscate.bat +++ b/examples/multifile-legacy/obfuscate.bat @@ -1,2 +1,2 @@ -py-shield obfuscatelegacy --no-input --mode 3 --loops 6 --files main.py,lib.py +dotpyguard obfuscatelegacy --no-input --mode 3 --loops 6 --files main.py,lib.py pause null \ No newline at end of file diff --git a/examples/multifile-legacy/obfuscated/lib.py b/examples/multifile-legacy/obfuscated/lib.py index 4ef9303..590cf35 100644 --- a/examples/multifile-legacy/obfuscated/lib.py +++ b/examples/multifile-legacy/obfuscated/lib.py @@ -1 +1 @@ -_=lambda __:__import__('zlib').decompress(__import__('cryptography.fernet').fernet.Fernet(__import__('base64').b64decode(((__import__('zlib').decompress(__))[::-1].split(b'1('OHh4qk>YR'))[1])).decrypt(((__import__('zlib').decompress(__))[::-1].split(b'1('OHh4qk>YR'))[0])[::-1]);exec((_)(b'x\x9c\x15\x97\xb7\xca\xc6J\x0e@\x1fg\xb718\xdb_\xb1\x0b\xce9g7\xc69\xe7\xec\xa7\xbf\xff\x9df`\x8aA \xe9\xe8\xe8\x7f\xa0k?\x12\x98\xa1\x03\x123\xbf@\x83!\xd8\xfdz0\x8f\xf8)\xb7\x07.\xc0\xa2)\x9e\x07\xd8uc\xd1\xe1\xe2@\xdfe\xaf\xd0\xe3\xce\x824\xc8\xb7\xa3\xff\xf7+\xda\x88\xc6\x7f\xfe\x0b)~\xdf\x9c\x15Zm*\xf4U4i\xe0\xee\xcb\xf9(b\xd5\x9c\x9d\xa3dq\xaa\\iF\xdf\x05\x89w\xbe\x9e\xa7\xca\x7fY\x1f.\xacb\xfa\xab\xdf\xa3\xe8\xaf\xda\xbf*\xa9\xcc\x0e7\x99\x00x}i\xe2\xd4\xdc0\x91\x03\xbd\x01\xd2\xa5\xdc\xeaY\x12\xaf\xa9\xee\xa7%2\xc3_~\x0e\x93\xa6A\x9c\xc0\xd7\xdd\xeb\xda\x10\xc0\x1b\xef=\xfe\xd8\xa0+\xd8\x96\xc4\x0c9\x85\xfa\xb3\xd1\xad\xee\x9e\xf9\x96\xaf\x83\x08\xca\x8d\x01\xea\x06%\xaaN\xaa;I\n[g\x14\xa7\xfb\x9a\xe6P\x83\xaa\xbd\x19.\xf5\xe1-\x8a\x86\x82\x86c.\x1db\xaf,a\xa1\xcc\x90\x96){\xe3!ts\x9a!\xc9\xa8\xe0\xf2D\x99\x83\xed\xf3v#\x8e\xea\x1f\xfe\x15y%\xf3\xe9C;\xbd\x93\x9d.~\xef\xd0\xaa\x90\x16\x11\xdd\xcf\xc2D&\xce3b\x83W!U\x1b\x87\x03\xac\xd6\xb5\t\xd2C*{fN\x9a\xfd\xf8\x80\xceW\x92{\xc6\x91\xc9S\xa6\xda\x07\xeeU\x05\xa1\xd40%lWf\xa0\xa8\xbaJ\x95\'I\xeb\x9a\xa9\xff\xf8\x1d\x97a\xb9\xec4\x91\x15-\xe9y\x83\x1b^\x18\x0fE7\xb0\xfd\xbc\xa0E\xd5\xa9\xa8=3\xd1j\xc0\x89z\x04\xa4\x83\x161\xb6-J\x98\xd3)\x89\x015\xd2\xe6(d\x8a%[OVI]\x16n\x8c\x0c\xc1\xb2\xf3\xdb\x1f\xa2o\xcf(\xc0\xfb^@\xac\xbd\xb0\xc1\xa61\x9d7\xd1wi\x826h\xbeV\xa3t$*D"\x15\x91\x96\xa9\x0c\xde\x9c\x16\x96\xe2)\xb1\xbe0>\x8a\x1fa\xec{n\xfb\xf3\xa0:\xa3N\xed\xf3L\x8d\xcd\xa9+\xb4tF\xb43q.G\x8d\x1cS\xde\xbb\xba\xc3\xf6l\xbb\x13\xcf\x10\xf5\xb3\'\xd6\xd0\x0c\xde\xbb3\x8b\x84\xc0\xe0\xd7\x92\x07f;)\xd1[a\xfb&Y0}d\x0e\xc5\xa1\xa9A<>\xb1\xe1\xddQ\x07"\xe7\x98\xbb\xee\xa7\xb4\x0e~\xbd[\x0fw\x1d\xfd\x88\x87\n\xacW\xd6\x90\x13<;f\x98y^,?5\xc4}\x9f\r~\xbf\x1d\xa6\x89Y%\xe8TM\x82\xaeE\xd4\x12\x9a\xffj\x18\x15\xc5[k\'v\xda\xab\xc2\xe9\xef\xf2\x98G/\x8f\x01\xf2\x93\x02\xf9\xc5Hn\xa5C\xafS\xf5PC\xa2\xe4t.\x8ck\xc1\xce\x12\xa1\x86\xad\x13G\x80\x16\x95\xf3\xc3\xc8q\xa9\x11\xa7\x903.I\xbd8\xa8\x81&\\\xa4\xf0\x88fh@\x16&Z\xdeL\xa2\xdbz\xf0\x91tS\x1eX\x16\x92.U_\x0f\xb6\xa1\xef>\xb3\xf4\x9d\x1a]\x8d\xb4\xaa\xcc\xdeoW\x9d\x0fQ\xf9\x83Zd\xa61Q\xad&\x14-b\x0b\xf2\xa6\x13Yp\x16L\xc1v\xa7\xb7P\xf4&\xad\x1d\xce\r\xf4W\xf0\xf0\xbf\xcd\xa1\xa6\xa5\xdbP\xba\xab\xb4<\xd7\x08\xadw\x98\xda\xaf\'i|\xce\xbe5\x1b~\x9f|cw\x1b\xc0}\x8e\xae\x8dt\xa3\xcc\x12\xd8\x04\x04U$ hjI\xe0W\xe8\xeb\xdd\x06\xb7\xa6e\xa3Ne\xf0T3\xa2\xb464\xdf:\xfa\xc4\xc3z<\xee\xe8\xdf\x0f\xf0\x8e\xd8\xfal\x93\xc2\xda\xa5\x8f\x9am\xf2u]\xf8\xbe\x1d\x87m/+y\x117\xac\xd1&\x1e\x93HY\xcdC\x07\x85@\xc3u\xc4\xf3\x1e\xa4\xd6\xd4\xf0\xc6:zJ9_\xea\x12\xack=\xf1j%\x04\x8e\xad"\xec\x8f\x9c\xfc\x00*\xaf{B%\x94$$u\xc1\xb8\xa95\x88\x9d\x10\xba\xbfV\xe51ZO\\\x11SDI\xe2\x95\x02\xcb?\x07)0\x0c\xbe\x99\x84\xf9\xf5\xb1\xd1\xc6\xf6(\xf0\xb8\x93\x8f4\xa6\xadA\xed\x90\xc3\xed\x85)\x891\x11N\xdc\x01PC3\xc0\r\xb1\xb9\x81jk\x81\x8b\xf7\x10\xd0\xcfE\x17\xe7\xf0\x1f\xa6\xe3>\x1aJ\x17cJ\x08\x03\xb7\x14\x95\xa6\x81\x90\xcdD\xfc\xad\xfd\x1fr\xeeH\xdc\x925\x1ex``{B\x07\xfbi+\x04u\x93M*\xb6\x90\x80\xed\xf9\xeb\x15\xf2\xdf\xacA\xa3\xc6~\xc1\xbb\xb20\xd7.\xb5\xa1ZP)\x17\x10\x00k\xbc\x93\xe9\x9bn;\xd7\xcb\xfd$sg\xb8\xbf\x14/)\xb3\xbf\x8bF \x84\xe0\xac\xfcX\x92\xe0|@O\x0c\x0cEa\x12\xeaEyr\xd0;J\x9f\xd6\xce\xafB\x92\x82x\xf32J\x9fO\x8e\xd5Sm\xae\xba\xd8\xd6\xfd<\xbbu\xbf\xa1W\xa8[\x127\xfa\xfc\x1aRa\x05\xb4\xae\xc2\xcbi\\\xd1y\xef\xe5B\x80H\r\x1a\xb0\xa7\\\x06#D\xc8d8G75\x02\x19\x17\x89\xa8\xc1k\x00/\xfc*\x0c+*\xe6\xb3\xbcl\x93\xac\x92&\x87\xbbC\x0bY\x9a\xd9\xf0\x89\x0c\xe0Xb\xde\x12\xe8\xee\xb86C\x1c\x9a\r\xb2\xce\xed+w-K\xc7|PcJ\x7f\xc1r\\\xb5\x8ds\xbdLiq\xe5\xc7\x1e\xbf\x0b\x1b\xd0o\x0e\xd8\xae\xe9A\xa8\x00r[\x1b\xc2\xf3\xc4\x1f\xea/\xf3}\xa7\xd6\x08D\xacO\xdf*\xa4;\xf3\x04\x9a\xa8\xfc\xdd\xbfk\xf7mSq\xcad\xfd\xc3x7\xad:3N\xa2\xa3\x92?uJ\x86\x9d5\x9e\xadm`\xd2\x7f\xb9\xd9!\x19\x10\x1e\xbee\x9a\xb1Q<\xb9\x02F\xda{\x85\xa0.\x80\xc6\xccfT&\xf4\xd2\xdfT\xd8V\x89\xb1.`\x94\xef@\x0c\x9c?SF\x8c\xcd\x15$\x0cy\xe2\xda\xb8\xd7\xd0U\xce\xba\xbf\x1f\x884y^\'i\x06\xb8\x1a\xb7[+\xcfE)\xe4\x18\x8c\x14\xa1B\xd5\x9dh\\\x8f\x84\xa9\x81g\xf3\x01r\xd5\xcc#\xe2\x1cQ\xaf\xed\xfc:00`\xab\x13\r\xe43d\x1d|_\xa8\\C\xec\xd2xW\x19X\x16\x95\xfa\x002\xaaK\x08\xb0\xb1\xc1\x1eG\xba\x85O\xe5\x93\x1b\xaa$\x1b\xa2\xc9\x193\xa3ww\x11\xd6\x7f\xd1\x92\xbfT\x8d\x1e/e\xee\x02\x90{\xc2\xf5\xd8jL\xe9\xd3Z\xc23bu3Y\xc8\xec,\x14\xb0t\x93$\xd4\x04\x9f\x1b\rp]K\xc7FZ\xf3\xa5\x81\xb8\xc6[\xd2R\xaah\x1c\xdc\xec\xf6\xe6~?`\xea\xa6\x9aI\xe2\xdeX@\x9c\x16\xfcq\xe7PL#\xf2\xe1\x92\x96.w\x8e\x98\xca\xcd\x15=$B\xfd \xdc\xd7\xcf\x00>\xaeE\x13\xfd\x90\xf0\x0f\xd2\x06\x1e\xd7\xb0\x88e\xecM\xad\xa0\xec\xca#m\xc2\xe48&\xbb\x18\\\xcf\xde\xa1\x83\xbf\x84\xb3\x96\xb9t\x19\xd2\xb7Vn\x89\xa8\x1b\xb1\xe37\x8d\x8f+-u\xfc\t1\xf47\xd1\xbe\x04F\x11\x9d\xfc\xb5\xe1`\x9d\x81\x97t\x87d\xabWe\x91\x7f\x81\x1c_4 \xc0x\x15\xb9{\xce\xf6\xa4u\xa4\xbd\x110\x89z\x99\x81\xc3\x8ca\xc4+E\xf3\xac\xb5\xcd\xe3|_\xd7[\xc4Q\xfb\x821\x8a\x06%\xb8s9\xdf\xaa,b\x92w)\xeby;\x99%\x1a\xa6_\xa9e\xed9\r\xb8\x82L{\xddT\xac\x07\x04\x8b\x17\xa9t*\x10\xbf\x99\xe8,^\x01I\x0e\xb2Rn\x13x~\xae\xa7R!~\x8b)\x8c\xbb\x8b\xd8@\xb3~SEI.\x8e#\xb59\xedd\x022E\xf5.x\xda\xcd\xf9\xf8\x94yB\xd7\xb8\x06\xf6\x01KXT\xc1\xcc\x90\xdb\xb2\xbb\xed%4;\xdd-}In\xeff\x7fI\x8f@.\xcf\'Z\x8b\xd2b\xe1\x06\xa6\xf9B\xdd\xf7&\x1cP\xd6\xe9\xf4\xecARc\xe8\xd7H\xa4\x07\xf4\x02s\x0c\xfc\x06J\rxj\x0c\xdbD\x0b;=\n\xfa\x9438\xb9\xd9\x18[Q\xf8C\xda\xed\xdd\xa6e\xec\rYA\\\xb1\xfbm@a\xf51l\xfc(\x97\xbf\xba\t\xe5\x8c.M\xdd\xb1\x88QP\xcd\xf4^]\xd8\xd4\x8a\xbf\x82T \x1a3\xa8pg\xf9\x97\xdd\xea\x0c\xd0\x91\xc8\x80:\xe3\x9ek\xde\x7f\xca\x02\xc0\x16\xc2\x94oj`\xb1S\xa4\x87\x05\xf4\x99k(\x94\xa3\xdc\x16\xa7\xaf\x84\xbcb\x03\x94N\x82\x1e\x84\xd6\x94\x89sZHFD\xc5]_\x7f\x84\x03G\x9aZCH\x95\x0c\x9c\xc3\xea\x8f\xd9\x07[\xfaLYZ\xb6\x12=\x13\x14\x8a\x04\xa4\x0e\xbcc\xc9\x82N\xbb9}G\xe0#\xce\xe3\xed\x0c\xf6!\x96RvUf\x93/[\x1f;\x08t5\xd7;\xf1\x00\xae\xa7=\xaa\x8c\x9c\xfb\xfc\xd8\xc1{\x08\x02z\'\xfb\xe7\xcf)\xec%5k*~\x80\x12:\xfam\xbcS\xf0\xd1\xa4\xd1\xac7\xc5^\x93\x10\xfa\xfd\xbcYP\xbb\xc5\x0b ~t\xdb\x8bG\x07\xec\xd4X\xa1\xc1\xd1\xd4\x82$7w\x82\xd73\xa9\x9f\x03\x10\x93\r\xdbX\x00\x11\'\xb1\xbb\x04\xb1\xe4\xc9:]\xcd\xb5\xb6k\x05\xbaJ|n\xe3/#\x88\xed\x94fd.\xc0\xa9\xecf\x0f\xafD\xd2\xd1pJ^\xd9C\xfe\x99Qz\xc7\xb1\x1c\'k\x1c\x1c\xb3\x1b|N=\xb94\xe2\xe9\xc1\x17qJx*\xeeL\xe7\xf6\xdb)\x1d\xbdz\x96a\x9a\x86\x8816\xbd\xb4\xaft<\xc0\xf3\xd5\xdec6+\xab\xcf2!\xf6U\x85t\x1a\x17*\xb4\xeeI L\x18\xc2\xab\x04\x05}\xd1\x07\xab{\xe3@\xf1\xb8O\xd9\x80\x1e\x0b_\x89\xfbL\xac\x02&\xff\xa3\xb7\xd7\x8bVe\x01\xde\xac\xc2\'?\x03\xf1h.\n\xb5\xda\x94\xa5\x05\x00\x08\x86/P\xe6M\xa9JQ\x87>\x88R\xf0\x0bpA\x17.\xcf\xd6\xdbDI\x98d\x90\xce\xb2\xb4\'pw\xf5\xa3#s2\xd4?a\xccQ\xc3S`\xd3C\x05\xffo\x10(\x8e},\x82ME\x0c$\x16\xe4\x97\xe7\x1d\xe5\xe4\x05B%l\x8f9|\xbcv\xd1;@!\xa7x$_0\xe3\xf6\xd7\xcf-"TD8\x91\xaezKy\x8a\xd5\\\xb70\xf1o\xb5\xbaO\x00\xb9V\xb9\xf8\r\x90,\x11\xaf\x00\xb0\xacaL\xa2\xb4=YI\x9f\xc5\xc9f+U\xfc\xe7\xbd\xc03\xbb@{{>\x17\x1a:\x1c\xea/}\xfe\x95>\xe8w\x88\x8fEr\xdfqO!\x99\x94\xae\x86\'?[\x95f\xd0\x81\x81|\xf2|0\x13s\xc1\xd9\x19\x8c\x02\xfd\xfd]\x1e\xe5\xfe\\q\x83\xa9\x8a\xfcq\xf50u\x9bM,B\'t\x8aq\x1c\x81y+\x03\x07\xa1\x825\x99S\xdf_Hm\x8bi\xcc\xdb\x1b\xbbbxyE\xab\xfa\x80\xa8\x12\rI\xb5\x1d\x01\xbe\xe9\xfe{v\xce\x1b%\xad\xe3_:\xbe\xbe\x05"q\xc4\xd1y\xabRc\xaf\xf1\xe7\xf4\r\xd56\xd35\xa5lX\xf1!!\xc9\x93\x81\x1fYC<1\xa11\x0b\xa1\xbc\xb2\x15\xbe\xa7;\xc8\x85\x94\xa5\xafb\x9fR\xd5\x86I\x8a\xdb\xb6\x17or-\xc6\xb58\x9b\xa0fOy\xea\x97\xad\xdc\xb8b\xbdQ\xc9\xd6{\xfa\xb3\x8c\r\x0e\x0f87\x1ep\xd0\xc7\x9cg\x83\xca\xc7Y\xe3\xf3\xe7\x06 \xe9\xcftu%\x8e\x82\xc1\x9e\x82\x89\xe4e\xcf\x04D\xbeN%L\x94\x9b\x84L\x8e\xf0\x1a\xa4(l-\x96\xa9\x9b\xa1n\xed^\xc9\x98`\xfc\xc5\xc6f\xe2\xe9\x7f8U\xfb\xcb\x14\xcf\xa8\x85\x9a\xf0\xf4w\x94\'\x0f\x82[qHhk\xe0\xb5P\xbc*&\xc8\x1eQ\x95\xbe\xa5vtF\xf2_\xef^\xb5\xb22V\x14\xb7\xdd\xc8\xec"\x02:\xf4\xd0\xf0\xaf\x07\xd9=2<\xc8\x9e\xf7\xfd\xd3\x9d\xb6C\xdas"Fa\x8e\xad\xcfU<\x8c\x0e\xc2\xbbO\x13\xe7M\x99i\',\xd1\xc6d\x1b\xd0k^R\xe6\xc9|\x82\x84\xb5\x85\xff@\xe2F\xbf\xf4\x1a\xf6\x1e\xb8\x83\xcd\xda\xbd\xfb\x0fo\xdf02\xac\xdasY\xbd\xb3\xe0\xcf\x99:\xdf\xbd\xa3\xcaN\xa7c\xfa\xc5{\x07\xe2\xb9H\x18\xb3#]qC\xd2\xab\xc1`\xdb\xc9\xc4\x15\xecT\xabl\x15\x7f\xcfo+\x08\xfc\xf9\x93\x92\x90}\xfc%\x90\x00\xc8\x9b?\xd7\x00\xff\x04\xcf\xc3\x89\xcd\xa8\xcdc\x10\x0eS\xba\x8e\x98\xe7\x7f\xef\x8bOp\xe2m\xf4 \x85\xd9\x02\x96\xd8E+\x0e~\x10?\x87[\x7f\x87\xb3\x87\x17\x18/\xa0c\xc2\xb6\x10t\x03\xe7\xb2?~\xb3\xe9\xf8\x95Yn\x97\xe5\x96].\x03\xdf\xc7\xeb\x86(\xf0\x06\xb3\x0c\xee\x12\xb2\xc2 (\xbd\xe5\xed\x13\xb1\xb9\x15>\xc5a\x8b\x82\x04\xd4\x8a\'+\x19%\xd9\xcaB\xebm\x86r\x01\xd4jS\x9bu\xe9vXd1\xaa\xc44a\xfc\xcd\xf6\xd9\xb8j3\xd4\x92\x81\x99H\x0f\xec\xd9$-$JT\x1bJlL\xb4x\xf2C\x07(\xc4\xa5r:\x95\xb8\xa8t\xe9\xfa\xe0\'\xaf\xe0\xf9<\xa8\x8aJ\xfb\xd7\n\xbc\tz\xec-\xad\x86\x13\xbb\x18\xd5\xae\xc8\'W\x98\xeb\xd3\xd8\xe684\x12N\xa4\xf4o1^\xc4\xaf\xcb\xa1Z\xfd3\xd9\x85CU\xef\xfct\xaby\xf0.|\xa3\xa8\xbd\xeb]^\xb0R\xeda\xc1\xf3\x00\x13\x04\xca&\xe1\xeeqm\xfe u\x04\xaaQ\xf8\x99r\xad\xe3\xc7\xf6\xf7\xdf\x9c\x06\xa2[\xa5\x8fjx\x02\xfa\xd8\xccQ\x06\xcfSK=\x0e\xefF\xff\xf2\xc2\x01\xea\x9eh+\xbdn\xd3\xc3-{\x04l\xa6\x8b\xb2#\r\xa9\x95\xf2\x05\x0fQ\xcf5\xc4\x061\x04!\xda>\x83\xa1\x0b\xff\xf1\xfe\xba\xf7\x90\xaa^%\xd4\xcf\x1d\xa4\xd7\xb2%?\x89fsm\x1dM\xb4w;\xec\x7f\x9c\xfa\\\xc7\x05`T\xf3P\x1e{\xee9M\x8f\xf07a\xbb\x00GDY\x89 D\x1c\xad ad\xbc\xa3\x8fG\xb4A\x0e"\x91\xce`\xd0\x0f\xf7\xbb\x04\xa7@\x02\xd7\xe9\xe8\x0fmw\x08\xf1\xfc\x1d%\x1e\xd2\xf5=\x83/\rk\xd4\xad\x91\x19\xec\x0f\xbf\xd5\xad\x96\x17[\x92E\xb7C\xa0\xba0,`r\xe2\xdc\xf1\x90\xd8\xbd_\x08}\xdbY4\xf8\x1b\x8c\xff\xba\xb4\xc7\xc6\x0em\xd2k\xb7\x07h;\x0f\x16\xb7\xfa_\xc2\xec\xa61\xce\x16\x89\xe5e6\xdd:?\x94t\x15\xd6\x98\xdf\x15\x14\x11\x93\x18\t:\xd5\xd0=pW\x10\t\xe0o\\f\x0e\xea\x9a\x04\xbe/\xec\xfb\xdf\xdc\xd8\xdb\xf1V\x8d>\xed\x17\x03U^5\x92\xd7\xbf\xdd\x1aq\xe7\xddN\x82y36{\xfe5\xe8\x1f\xe6\xb6%/\x1b\x95\xae\x92\xdc\xf83\xe0\x17%~T\x9c\n\xbe\x0c\xb1;8\x13\x14\xf6\x01\xe5\xea\xca\x84smt#\xcc\n\n\x1b]\xaf\xca\x16u\x0b\xe0`\xa8\xb1\xbd\xe5|&\xeb\xf1\x8bv\xe2\xd2\xef\x10K\x96\x9ex\xa5\xa2n\xf5kX$s\xdf\xf3\xa8\xdc\xec\x1c\x0b\xe6\xe6\n\xa3$\xe5U\xb77\xe5\xa6\xd2\x9bh\xc0\x0b\xdb\xd3d\xab\xa2\x9bCF`\xdf=^\xd2\xba\xfbV\x83_}\x16nj\x95\x9d.\x947T\x0f\xbd$\x8e\x0b\x80\x82r\x80/<\x04Q*\x0bu\xdc\x03\xc7\xdc\x13_r\xda\xd7W\x1f\xbf9Rv\xd8\xe9\x0ej0\xd6"z<\x8e\xc2Aoo\x94E?\xb7\xd2+/\x8e\xf3:\x8d\xc5>tX\x11\x9fL\x04\xe4\x8c\x80\xae\x19)Rvz\x91\xe57\x1aB\xf7\\\x02\xfc\x83\x98\x9b\xbeZ\xccn*8\xa50\x8a\xb8\xee\x85\xb4L{\tv\xfb\x80\x05\xfa\x14a\xb3\xce\xd6E\xa4\xaa@\r\x9fbU\x84\x0fH\xd6V\x04\xad\xe2N^\x9f\x95\xf8\xf8\x14\xb5"\xf1\xf8\t\x8f\x7f\x95\tO;#\xebk\xber\xd7\xfb\xdc\'m\xc2\xeb|\xfa\xc6l\xa3/\x16\x1a!\xba\x82\xde\xd3\t\xdc\r\xd3M!\n_\xe3\x86ag\x8f\x9d+\xcd\x99\n\x99\xdb\xa9\x8e\x83k]\x0f\xa2\xdf\xc4\xdf.#\x9a\xa1a\x97\x17\x94\x01\xd7}#\xe3\x9cS\x14\xae\x9e\xa3_\x9a6*\xc0x\xbc\xc5\x0f\xe5\x98\r\xf96\x9dr AB\xc8\xad\xc1(pNjYn\xa0NN\xfd7\xfc\x16\xe8}\xa6\xe3\xc16B\xf4\xb7\x89\x99\xe7z}\x17yc\xb1\xc4\r\xb3r\xb7\xbe\nt\xb5~+\xc7\xeeg\x88st\xd3\xfe\xa9\xcd\x1d\x8e\xfa$\t\x83,\xfe\xdb\x89FA\x84\x033\xe10\xc5\xdb\xfe~0\x12\xf4\x02\xcaWL\xa0[o\x1e\xbe.H\x04\x8f\x10\x0e\xc4I8T\xcbl\xd8 *b\xde\xd8WQ\xc7\xf9g\xbc\xf3\x918\xb3\x9bD\x8bZ\x97\xc4nf\xb3\xde\x9eS\xad\xbb>\x91\x88p\xc0q\x8c\xa4U\xbd3\xd8\xcd\x06\x1d\n\x10i\x13J\x9f\xd7R\xc4\x89\xeb\x1d\x1d\x9b*\x93t\xe03a2\xfa7m\xfa\x8e\xd2_0/;8\xd3\x91\x9a\x07\xae\xeaQ\x01\x8cN@f\x88\x14\xaf\xd1\x85a\xe1\x83\xd2\xc9\xbd\xb2\x1b\xa3Q\xd2\x9f\x9c<-\x85\xb4\xf0\x0fD\xd9\x1b\x93s\xd5\xda\\\x7f\\\xf6\xc3!l\xea\xd2.\x80\x8e\xd9\x9c\x0e\xa8\x88V\xeb\xddT\xee\x0b}\x92YfM!0\xa3\x07H\xad\xd7t\xd3IK\x15;b/h\xd1\xef\x9c5?\x02L\x1b`7\xa5\xfc\x02\xf7k\x92\xa8\xd3!md\xady%I\xfdd\x8dF\xcf&=\xd0\x96\x9d%\xdc?Vp\xfdS\xf4\x0c\x91\x8aU\xaf\x94a\x8c{\x82\xce<,\x82\xc5\xdc`/.\xb8]g\x93H\xcd\xd0\xc3\x87`G\x91\x16\xb4\xa7=\x0e\xec\xbf\xf3u\x7f\xb7\nQ\xeb\xac\xa6\x89\xca_\xa84\x08\xd1\x87]L\x08Z\x99\x03Y$\xc4\x12\x9d(@\x05\ra%\x9b\xe1\x9e\xdc\xc9;\xa7\xb8\x8ab\x03s#\x94b\x95\xe9\xf9\x83L\xe6\x03+d\x8e0U\xba\xfc\xcc*\xd6\xd4|\x9d\xae&~\xcd\xe7\xfa\xbc\xa4q\x04\xd1\xc5R\xba\x03D\x96O\xe3\x9bx\xe7\x8d\x02\xdb=\x04`\xb6z\xed\x0f\xb1g\xaa\x84\x13p\x80\xaa\xea\t\xf8\xd8\xde&\xf7\x9c\xe8,\xf1P\xb2\xc627ti\x90\xdd7\trN_Y\x05\x87!\x9dT\xa5v1~\x97\x94\x1d8X\r\x9c\xe3\x01\x97\x06\x04\xa1A\x19YQ^\xb6x\x8e3~\xe0\x1e\x07j\x93.\x0c\xe9f>\x88\xdetX\xfe\xb3 \x12\xd8W\x8f\xee{"\x93\xf6bsG\x0eTg?\x9a\x18\xb1\xce\x86\x9eg[\x90b{\xdf\xf33B`T5\xce\xff\x10\xd0\xf7\xb6\x8d@\xa8\r.\n\xca\xd9\x9d\xd7\x85r\xdd\xc6H\xb8\xe1\x18\x11\x96\xbc\xb7\xfd\xc9\x9c\x19\xdeP7\xf76\xed:\xf2\x19s\xbe\x90\xfe\xb0\xcf\xd5\xfc\x1a\xe4]\xe4\xf3\xd9\x93\xf6\xbd\xec\xa5E\x95t\x99F\xd2b\x03\n\x9d8\x1dhZ\x1e\x08:\xf4\xee\x14\x008\x8b)\x05\xa2>\x9c\xe5\xa7A\xdcS\xcc\xac\xa0\xe6\xe5Lem\x12\x048\xe44\xa0\x91F\xe3-\xc6mG\x9beg\x08R\xd3 \x99\xa8\xc4\xda\x8b\xd5qW\x99\xcd\xf5v\x18\x9b\x12t\nF\x7f?\xa8\x9e\xd6\xdba\xf6\xcc\xf1\x8a\xb7\xdd-\x19\x81\x1c\'m0P\x88\xa3\x7fy\xe3iqGe\xd7\x96+L\xab\x03Yw\x84K5<\x9e\xaa`\xb0\xe34S\x8a6K\xff\x8c\x8a\xa5\xf9\xeco\xa5\xfe\x16\x96~\x85GH_+\r\xd5\xaf\x1e\xc9\xde\xfb\xa0%\x13\xaf?OEI\xf0\x8b\xa6\xe2wc[\xdc\xab\x86\xf7\xe1+c\xc83\x8d\xf8\x8c$\xda\x89\xe0\x9a6T\x87%`fg\xd5z7\xa2\xb0r\x11TMO8;[\x88\xd4Z\xe9\x13\xcd\xad\xd5\x96\x7f]\xfa\x8d\xcc\x16uq \xcd\xc3.tA\x9a\x92\x93\x87\x8e\xb7\x16\x16\xcc@\xa3?\x07\xf4\x95:y\xc6aF3L+\xc6\xc5\x1bZ\xf6\xa1\'\xe9\xec\xd7$\xe9(\xedhW\xda\xfa\xcb\x80\\`\xb9\xe6O}\xf0x\xeb\x12\xa6\xa5\xa5\xba\x1bH\'\xd0\x03\xc8\x15\xb3\x0c\xdb\xf6l3\xf41p\xc7\tN\x1d\x97T\x01\x9f\xa3\x85\x9c\xc3em\xde&\x17\x00\x0e9\xdc\x1b\x97\x92\xf2\xac_\x9a\x87\xab\x7fW\x8b\x86\xc9f\xe8\x96\xf2a\x03c#\xc1\xb7u\xacR\xf4\xed^\x9c6\xb4j\x05\xeb4n\x15SCR\x8c\xa7\r\x0bK\x9f\x98\xc8C1\\\x9b\xe2=\xbaa\x9fz>\xefd=B\xbc*!\x95\xe0\x17d\xaaJ\x96\x90\xe6vk\x155\xa3\xd4\xc6S\x97\xaeD\x05\x0f\xdb\x9c\x15\xa9-\xb5HZ\xa8\xef\x06\xbb\x1e@\x15\x02\xf74a\x85\x81V\xc4\x84\xb2A\x88\xf5\x84C\x08#0\xde\xde$\x06\xca\x0e\x98LO\xc8\xccW\x0e\xf7\xae\xac\xb6#\xd9|_HF\x85\xf1G*t\xcf#\x90a1\xec\xf2\xdd*.\xf9\x1d\n+`D\x9a7\xf1\'\x7f\'\xb2J\x1f1\xce.?\x90i|jjo\x1bMr\xb03\xad\xfb[\xbc\xbd\xa2w|\x90YH\xf7\x8f\x92\xd2\xcf\x95\xd9\x87\xd7\xbdi\x98\xc7\x99\xd5\x8b\xbc\xd8\xabn\x96%\xab\xc1\x98\xf9w\x99,\xedJ-\xc6\xbci\xff\xd0H\xf4\x87R\xa6\xb1J\x88i}\x8f\x00\xbf\xe5Q\x9fh\x91)4\xcfkB\x94\xe8\xd9\xaa_\xac\xf1\x168\xf0\xfe\x12=\xed\x93\xe3V\xdd\x81I\x10\xa6|cR\xcf\xbf@\xa8\xaf]C\xcc\x90\xc7\x1d\xd9%\\\xb6\x9b\xc6\x99\xec:\xeeAm \x93\xcf\xda)0\x04v\x02\xbc\x82\x03\x1f\xd0\'|\x06:\xa6P\xa2\x11e%\x8d\xee\x91\xf3\x17\xd5\xf9\xc8\x1e\xc4\x98\x8dzCA\x80]i\x04\xa7[\xf8\x91m!\x00)\x8b\x0b=\xa5~\xff\xa1\r|\x8a\xb1\xfa\'IM\xef-\x88\rnt\xc6\x0e1\x1c\x1f\x8f%\xaf\xd5kB\x8c\xfbU\x08r\xc6\xd6\xcb\xdf\xd2\x9b,\xbc-\xe9\xd2/\xce\r\xff\x9e\x06}~\xc25\xa3\xaa5\r\xf3\x14\'\xe7\xed\x17\xba\xf2\xf8\xc1\x93x\xadN*\x0f\xc0N;\xc2v:<\x15\xb4c\x9d\xfc\xcd6J\x1e\x90\x95\xfdK\xc56\xfa\x9b\xceI\xa9\xf0\xf6X\x16\x9d\xc5\xc8\x18\xd3F\xde1PC\x1a\xe6\x15u\x80B\x97K\xc4\x8a;\x1a\xc1\xe3\x88\x05a3w\xbce\xbf>\x90\xe9w\x94\xb9\x1a\x06W\x8c\x1e\xf1\xbf\x8c\xbbR|Vr\x85\x08\xd9\xe8<\x94\xb2\xa8\xbf\x90\xf5k\xca\xbb\xe5\x9f\x10\xeei\xe2\xf4\xba;\x89\x04\x03\xfe\xc1d\xf9\xcd\xa7\xf3\x0b$QZ\xa4\xbb\x7f\x0e\xba\xcd\x90r\xc3\xb3\xe0}\x8eB\xc6\x93\xefU{\xe3\x0c\xdf$\x15\x81,\xc6\xb8\xbe\xf4\xc3\xe3\xf9\xb1~\xe308&\xe4\xfb\xac\x95\x04%\xfcp\x85L\x1e\xedH\xd4\xea\xfd\xd2\x06\xa3\xbc\x08\x8fq\tR6\xe8>\x9a?\xe0\xe2u\xa8\xbb\xdb\x12\x01fh\xeaS#\xea\xa5s\x82\xd2\xbb\xbcq\x9a/\xc1\x89Vd!\xde\xcc\x97i^\x7f\xa8\xa1tX\xb7\x1dRc\xee\xf8\xfe\xec\xe5|K\x0b\x1f\x8e\xf9f\xbd\xbfmx\x1f_\x01\xc3\xdf\x8b\x19\x1di%\xa8S\xed\x80\xd98\x86\x87\xa6\x86\xc5N\x0b\xa7\xcd\x82%\x9e\x92\x0f\xbd^\xad\x95\x06GZ\xbd\xfc\xdeQ\x87\x7f\x1d\rI\x92\x8al\xb6\xe8\x01\xfcL\xc9\xf2\xfb\xc2y\xc6\xf3p+\x1dM\xe7\xedc\x8f\x18=\xd3\x14`\x7f\x06\x08\xce{\x1d\x18n\x98\x96\xcc,\xf9s\x1c\xde\xdd&,!\xfa+7\x15\xf8\x1a\xc6\xa8\xe8E\x9b\x8d=UX\xecg\x05\xc5\xb1\xdd\x89\x05\xbf\xec\xe9eg\xe5a\xf6C\xd7\x17\x88\x00e3\x07ei6\xa6\xa9\x03\x17\xc6\x80\xd1S\xcc\xf7\x06\xd0\x9f\xdf\xaaJ_\xc8\xa4\xcc\x82\xa9\x1bF*\xa3P\xe9\x18\x7f\x0b\x8c]3o\xa6C\x15\xb2\xa5\x92\xa9 H\x90wR\xeaw\xe1\x1ep\xb6?%\xae\xfe\xc9\x00\xa7\r\xa4\xaf\xb5\n\x11\xcc\xeb\xf83\x17\xc0H\x03<<\x1dE-\x82\x8e\xd1\'\r\xbb\x12\x06\x81+1\xed\xac\xba\xcf\x03U\xd9\xc7$Qs\x15\x06C\x01d2%\x19\x8b\x82\xe3u\xa96#1\x00\xcf\xe5\xd7 \xcd\xd9\xe2\x85/\xec{\x80\xaf\x1aK\xa0\xea\x9cI\x05,\x82^\xd9R\xb4\x1f\xd1\x9c\xa1\x13v"\x97\x955\x84\xc3\x11Xm\xb8\x8a\x9d\xf6\xc7/r\xff\x90\xf8\x0c\x96dtq\xd7^)\xa7\x87\x06W\x88p\xb1\xc8E\x18\xc0\x95\xf3R\xd4\xb2y|3\xb6\x95\xf0\xd17\x9d\xc4x\x04\xa53\xf76\xee\xfbg\xa2\x82Z}\xf3uR\xf2\\T\x90\xcc\x16n\x87\xe2\xc8\xebOA\x0f\x98\xab;\n\x91\x8a\x81Bu\x99\x8f\x85\xa9\x80:\xb2{\x80\\\x87\x13\xb5\xd4vY:)\xdd\x80\x04h\x88\xfc\xfb\x05%\xde[\xb7\x04\x98\xc0od\xffP7\x08\xb2 \xa3\xc5\xfa\xe7\xdc\x16\xf3\x91\x9b\xda\xec-\xa3\xb3\x08E\xe3\xc5\x8a2\x8d\xf8\xb2\x7fEB\xb6\xe1\n\x94\xafA\xd6d/v\x88\xbf\x96d\x07\xca\xf4\xd9d6\xa2<\x80?\xb6\x18\xc2q\xfe\xc2\xd4>B\xf9\xb4g\xc0\x90\x13|\xc8\xc9\x9d\xdew\x84e.\x16\xc2rqP8E\xa6\xdd\x7fT\xd9\xe0\x95J\x95\xd3\xe8\xb9\xac\xbd6\xe5\xc3Z\xb1X\xeb12\xab6g\xbf\xbb\xd2\r\x9e]\x1d\xadA\x07\x15IQ\xe2_\xb5\x1b\xf1\xfa\xb0\x80\x0f\x9a\xb5o\xacx\xfa)n\xa7\xac\x9a!\xc4\xe3\xde\xce\xd9\xfa\xcc*\xc8\xa1x\xe9\xde\xd7\xa4U\x8e.\xaf\xa8\x17y o\xec\x87\xc0\x83\x16:H\xde\'\x10I\xd4Q\xc3Es\xda\xb9W`\xf7].\x1fh\xc2\x97\xdf\xc9-\x95\xfb\xbfB+M\xdf\x89\xb3A\x9b\xeao\x0f\x1c\x84\n\xbb\x83\x03\t%r\x14/N\xe40}g\xe3\xea\xf7\x8f\x8eR\x02\x1b\x9a\xfcYN\xb9\xc2\xdb\x88V\xdbg\xc2Ux\xff\x06\x17\xff\':-\xb1\x86\x91\xba\xc1\x8e@\xb0`\x1f\xb5\xf5\x89\x87\x89\x1bo\xd6\x87.\xd9\xef\xe5?\xd4\x83\x8e\xf5/kx\xde\\#\xb2\x82\x89\xd7\xa3\xa6_U@\xea\x9fc\x90\xd6\xfa\x902\xc3\x97#\xf2\x12g\xb5\x1a\x1fX\xdd5\xa8\xe9s+6\xdc\xe4\xa5Z\x91Y\xdb\xad\xc4\x04\xfb\xfb\x1b\xf6\x84\xa8\xd0\x0e@v\xee_p\xde\x84Y\xcf\x95{\xefD5)\xbb\xc5\x97\x054\x11\x91\xac\xabx\xfa\xd7&-\xce3\xdb\xd1A\xb4\x05\xca\xc0v\xb1l\xd4V4vM,&\xcah\x01\xb1\xea\x86\x1c\x86\x05ha\x9d\x8c^\x9e\xd8\xf4\x17c\xdb\xbfn\x06\xe4\xd1\xcf$\xca\xfa }\xf5\xa2\xb8\xc4\x7fk\xa2\xfe\xad\x0e\xf9\n*Mi,\xa5\xecE\x02uZ\xa9\x1b*_\x1c\xbd\xf0\xd4u\x91\x86e\xd9=\xc0j$\xd2\x9e\x10\xb74\x04\x01\x9cp\xc6ja\xd3\x12v\xf8Z\x852\xfc\xb2\x04\xb7\xb0S\xa1\x01\x1c\xe5\xfc\x01[\x02/\xdd\x02\xfe\x80\x837<\x9d\x0f\xd9\xa0z`2\xd7\x83\xbb)a\xbe?\xaaM\x8d~HL\xb6!\xd1JO\x8e\xecv\x1f\x81\xe7\xc9\xce\xf4k?\xb2\x91\x156@{2\x94\xba\xfd\x9a\xfb\xc8M7Tdc\xb6\xfc\n\xf8S\xc4\xdf*X\xacY\x18\xc2>$\x02j4J\xf5\xfd=\xebw$4\x05\x10\xb2\xcd\xa5N\x05}7]\r\x05\xed\xc0K6\x10\x13h\x91\x9f9\xa0\x91\xca\x8f\xa9R\xd4!\xe8\xaf1?\x8e\xa8\xb5\x14.%M\xcf\xfbi\x93\x1b\x81\xd8\x89\xfdp\xc7\xf5j\xf0\x98q\x9b\xaaz\xb4i\rN\x14\t\xaa.a\x83\xae\xdet\x89\x16@j\xc7%\xa6@A\xab\x9a$\xdf(6G\xd9Mn\x12\xee1\xc6\xbf\xday\x0b\xa8\xcd\x8b\xdd\x08\xf0\xdf\x92)\xf8\x9b\xd3\xc36\xe4a[r)\xd0\xa2 \x84\'\xa8\xdah\xf5n\xd8\xa7\x8a\xbe\x12\xe6v\xa6E3\xfb\xb8\xff\xa1\x03\x03\x10\x881]\xa1\xc0\x01\xaf\xe7\x9b7\xfc\xc8\x8eQ{\x84\xce\x99\xb2l*=9\xc3k\xd4\xf63D\';\x99H\x7f\xb9!?\x01\x1e\xe5[]U P\xda\xa2\xae\x17\x9b\xdet/h\xc4\xd4\x805_\xce\xdc;\x1d\xb3\xe8\xbeK\x04\xb1\x15.\xd8\x14\xbc\x81;\x81|:\xb2\x11o\xc2\xc2\xb2\xe6\xd6\x88\x90\x9a\x1a\xb0\x8b\xf6\x83\xad\x10}\xcb\xfcb\xad\x7f5\x82J\xf7\xa1\xf4\x0cn\xc6&\x82\x92\xbci@\xde\x15P\x90\xfa\xa1k\xe7\xb2\xa0\xf1\'\xfb$\xf0\x12\x1e\x99\xe3\xd7\xc0!\x07\xf3w\xe7\xb4yY\xef5\x18\x15`\x98UOd%\x0cT\xbbCa\x98\x92\xefG\x1d.[\x1d\xbb\xcf\xc4\xbfi}\n\xc6\x00ls\xe6\x807x\xb0\xafk\xa0)\xe9\x95O\x0bC8\xca\xbb-\x9e_<\x14\x9e\t\xf3{R\x8d\x0e\x9e\xe8\xfe\xa5\xd2{\xc43\xed\xa5\x01EJ\xd4MuH\xe8\xfa\x87S7l\xc3\x82\xa2\x87\xa7f\xff\xc9\x88\xb9\x13t-\x9aM5+ ?\x15wc\xe7o\x06\x1c\x9b\xb7\x0f\x1e1\x8a\x1c\x0c\xd9\xbeXs~oS\x0c1\x84\x89\x89\x9cJ\xe3d\x1b\xb7\x0b9\xc6:\xd9-\x8aY\x0c\xc8)\x87w\xf5\xb8r\xca\xdb={6T\x9d\x83u#|\x00\x07;\xe0\xf4\xa6\xc14\x96~\x08\xd9\xd5L\xb3`\xf7\xdaJ\x1f\xd9{\xa1^\x82o\xa99\x12d\xac\xe3\xe7&\xdcT\x1a\xb4\x08\'\xa1\x92nI\xc1\xc1\xcdZ\xac\x1c\x92\xdf\x0cl\x98\xd8\xd5<\xa2]\xf0\x82\xf1D\xc2\xf7\x1e[\xc1\x9e\xca\xa2\xe0\t@W|\xb7?d\xe7G\x19\xceMz\xeeo\xc1\xf9\xa9\xcbP_I\xea\r\x014\xb4ta\xc6\x11\xc9Z\xcf\xe5o\xed)\xe0"\x1f>7\x93w\xe3\xf7!\xf1\x81\xe1\x84U\xcd\x1cF\x02e,\xdbUE\x19\xb4\xf4\x1d\x16\xd3\xcc(s\xb8\xb7[\xe7*\x16@\xa1\xd2\x9b\xc3;)\xf7E\xc0\xeb\x82k\xbf\xcd\xd0\xf2?\x03$/\xc8Vl\x9b\x1f4=\xdd7\x9bH\xf3\xfe\xc6H\xc0\xcb`\xdf\x1e.\x86\xb4\xc4:-}\xe6\x8e\x93{\x07\x86\xadm\x10\xbbOP\xdb\x9f\x0b\xe6\x81\xa4\xc6\x85~L`\xe1n\xb5\x06#\xf3\xeb\x87_\x0f\xfc&\xc6\x10~\xa5\x15\xf4\xb6h\xc9"OA\xa9\xc5Z\x05!e9\xd4\xb4\xf4\xde\xbf\xf0\x8c\xcb\xcag\xb0\xe4\x1dV\xee\xb2\xc2\xbc\xe9\x16\x88H)d\x9fNIh\x8f\xd3\xea\xe6\xda\x8a|\xc5\r\xbaw\xbc\xd3Vw\x85\x0c\xe8/\xe5[\xfd\x1d\x08\x0b\xfd38C\xc3\xaa\xa2\xe9I\xf3\xc3\x18=\xa4\x08\x7f(\x17\xc9\xda\xef$\xdf\xbbF\x99\xebc\xaf\xdb\x0fj\xa1MO\xf2\xa0\xa6}I\xd0\x06\xd9\xc2\xe51zh\xa53T\xd0\x8e\xd82\x88\x14 I\x04\xed\xb3\xf0C\x12\xb3`\xfe\xb6\xd5\xd1\r\xcb\xddX\xce\xcaw\xb1\xdc\x82M\x84\xcc\xca\x87S\xc1.}F\xd9\xd3`kH@s\xe6\x03%7I\xc7\xa1M"\xd7\x1b\xfa&E\x85D\xf1}\xcf\xd8\xc3z\xdf\x11\xfbb\x08\xae\x80\x04\xc9\x05\xd0mN\r\x92\xa7\xd7Q\x17\xf3z\xd5<\x9a\x01\xc6\x8d\x11\xb9\x9c\x85\xfe\xbe\xe41R\x17\x8b\xf8\x97\xc4\x17_\x9fIT,\xbaD\xfe\xb5\xd1!\xe4\xb5ny\xfe\xc7F\xf2\x049\x8a\xecl\x0c\xf6\xbe/\x81\xd0\xd3\xc2"\xef\x8d\xd8$&)Q\xc0T;\xe5\x87F8\xd1^\xa8\xc7\x85\x0f\x1d|\x8ce\xa2;\xa0\xef\xa7\xd10\'\xbe\xa4&\x9a9\xa0mY^w\xbe\x15$\xfe\x9d\xdb\x1e\xe1\xcb8\xe2w\xec\xb8\xd8\xc4.\xce&3-/\xd7pk\x8d\xd5\x88\x8dP\x06\xb0\xfe\xc6\xd2\xd6\xb3\xb8\x9b\x1d\xba\xeb\xc6\x86\x7fg\xb7f\x1dM0 \xb2au\xd3\xa7\xe2\xb0\xea[\x98\\9\x05\xfbA_\\\xb8\x8ag\xc0\x8e\xc7\xe8\x8d\x9a\xaf\xea\x15\xf0\xae\xe5L\xcb\xc6t\xf0g\xefE=\x7f\xda\xe8\xd3=x\t`;$H \x1c9\x96)\xe3\x18@N\xfa\xc3\xd1&3L\x86Z)[\xef\xb5\xbbDg\xed\xb3\xc54T!Y\xba~ByC\xa9y\xd6\xbb5\x0e\x00\xf4\xeb\xed\x85w+P3j\xf4\x9cc\x98\xd8\x91co\'\xc8\xa0\xff2\x8d\x8e\xbb\x0e\xf6\x04\xdc\r\xafoi\xd4\xd0\xe4\x93\r\xc9\xf8\xc0\xff);\xc8=\x90\x80\xafy\x1c\xe9`P\xcf\x98\x1f+\xc3\xcd\xc3\xf6\xce\xdf\xec\xf6g\x82bLeh/\xb9.z],7\xecu\xa4\xa4\xc8\x05\xb7y\x827\xc9\xb8\xcd\x10b\xb8C\x9dNc\xf6\xc4^\xcd\xbf\xb8&\xd0~\x119\xd9\xc2VI\xd4\x17\xe0\x1b\xe2\xf9\xdbG\xb1\xad*\xabw4\x1e\xbe\xe2\x8c\xba!6\x8eq\xe5.\x9cAK\x15\x1f8\x01V\xacX\xc3\x18\x98\xd8\x06\xd20\xa6V\xcd\x16\xfd\xdar\xb95-q\x86\xa5\xf5\xbd\x84\xda\xb4V\xc0\xc9\x8f\xdb\xbf\xdce\xcf+f\x93\xec\x80\x0fr\x07SpN\xa6\xb6\xa6\x81Q\x12\x93Gu\x86\x92\xd0\xedl\xf1\xcb\xfd\xd8\x95\xcfQ\xdcx\xc6\xf5\xb4Z\xd4\xa8\xa0\x06\xdd(\xeaN\x01\xbb\x1e\xee\xc5m\x1d\x81\x1f\xd1\x0c\xd0\xc0\xa4\xd4\xaf\xec\x98\xbfh\xeb\x8a:\xa0\x8c\x02?\xa1\xf6%h\xce\x07x\x83\x94\x011\xcd[d\xab/\xda)R\xaa\x9d\xa1bi\x1bzjP\x0ep\x9fv\xd9\xe7\xe6\xee\x90\xe9\x03\xbf\xb4\x90\xbc\x1a\x13\xa4C\xd8[]6\xc7\x89\x1c\xd8\x86`6\x86\xa7\xc9e\xd7\xe5\xcf\xce\x197g\xc3?\xd9\xdekg[\x87`\x96\xe9\xfa\x1e\x86u\r\xc3\xd8\xfa\xb1?2"\x83\x821\xd2\xf0\x92\xc0\x13}\x0fq0\xef\xab\xcch\xfd\x86\xf4\xf0(JO\x0e\x95\xdb\x94\x94%\xa9\x89\xe0\x9el$\xcf\x92\x1b\xbe.K\xd8B\x81m\xf5&\xb2\xea\xf0\xa0\n\xe9\x1f\xb9o,*\xcdg0]\xc4We-~\xabG\xfa\x8b\xc5\xc3\x9a\x0f\xf1\x9bl<\x9b\xd7\x95\xf2\x01&\xa8\xbf\xbfEIg\x1c\'\xee\xf2\xb1P}\xe5\xcfz\xd7\xaeW\xe7\xeda\x97\x1a\x91\x0c[\xab\xd4\xf0\xc8A\x16\xf9\\7[\xe4\x0e\xd8C\xf1\x9cQ\xf5\x81\x97\xfc\x87*\xf3\xab\x103\x9c\x94\xfb\x9c\x16\x89\x9f\x82\xcd\xf9p+\x12\x055\xd2b\xe3\xd7\xab\xae\xd2\x08\xb9\x05\xb1[P\x19ta\xde\xde\xdb2\x11\x93\x95\xf9\xd9\r}\xc8\xd0\x80wFJ\t\xd4\xcb\xdb\x94x\xfd\x1c:\x06\xb4\xc3y\x92\xe3`\xbb\t\xdf,\xfe\x12\x95\xa3\xb8\x1f\xfd\xd4\xc7\x01$\xd8\xb2\xddz\xa08\xef\x06Vt6\x1b\x9d,\xcaA{\xc5B\xe8:jR\xe1\xd6\xb0q\xa0*\xe9\xed\xa1\xc6\xd0\xbce\xd8\xbc"\x96\x85A\xe2\xe0A\x944\x80Q\xd4o\xc7k\xd6\x17\x1c\x06\xd7\x1a\x1c\x13o\x01\x9f\x89+B\x8d?\xa7j\xf77\xa9)_\x85W\xd0\x8d\xda\x1c.96\xe3\x0f\xa3f\x98\x94dT\x1ec\xcf\x1f\xa5\xb9=\x8c.\xb0\xf0EX\xafNltx\xc9\x0c\xfc\xbd\xd3<\xbb\xa9[9\x0b\x91A\x18\xd5\xa9\'Q\t\xa9\xb3\xd7g\xe3? \x8e\xb7\x05\xe6\x8f\xca\\\xbb\xa4&\xc1g\xf2\x07>:;\xe5\xed\xec9-\xb2j\xcdw\xbb\x15T\x10\xc4B\xd67\x7f\xc6\x91k\xf6\xb0\x89\x81#]\xc1\xedW\xb8\xafq\xa5k\x86\xde\x95r\xb3\xb89\x9e\x02\x1d\x9a\xd5\xb6\x811$\xbcf\xea}\xde\x8a\xd7\x05\xe4\x04\xde\xbd\xe2\xcb\\P\x08\xea<\xd9\xca\x18U\x19\x97~zb\x9a\xd3fm\x8f\x83\xc0cT;\x1e\x00H-\xc7w\xea\'!\x02A\xf9\xd7\xff\x14\x0cJ\x9f\xf5\xc8~\xa1\xa4WqK\xa9\xcdj\xf6\x9e\x11\x99q\x15\xd3\xe97\xf3b\x1e\xa5:@\xba]U\xc5\x97\x07\x8f\xad\x0c>\x8a"\xc4\xfd\x83\xafjp0\x9f!\xe1i\xceSL\x15\x1c\xeco\x89\xa3\xd0\xd0\xb3\x06\x9ao\xd2\xb1\x07o\xdc\xd0i\xaf\xf9\x05\x14\xf6\xee\xef\xfc\x96phZx\xb4\xa2\x95O\x9ex\xa9\x7f\xd0\xf0\x9a< ,^\x8f\x8c\xd1(zWI\x87\xb6\x9fd\x00rS\xf5_\x1aGC\x9b\x19\x02\x85i\na\x81\xbf\xc7sm\x93\xfa\xe1\x94.\xdeF\x98\xf0\xde6\xf5\xd0\xe2\xd1:*r\x89\x99svt\x8c\x86\xf6\xa9\xa8\x83\xc2\xd2\xb0\xf9\xf0\x93\xe9\xd5I\x1c\x7fZgX\xb4\xeb\xd3\xc7\xd7R7\xc3\xe0C\xee\x1f#\xbe\xff\n\x02!v\x9c$\xca\xbd\xa0\xf5\xddg\xd4Eo\x9cG-i]mm\x92\xfaR\xdc0e\x7f\xc8\xccz\xe9v\xe9T8\x13\x7fU\xc2QC|\xcc)J\xec\xc9\xa9\x99\x05\x1b\x90N\xf44\xc6\xccqS\x03\xff\x9c\xcc]f\xe6Lr\xc6FQ\xd2#\x03\xb2\xe0\x8f\xc73\x01\x1eM/\xde\x19\xed_\t.\xe2\xe2\x07\x9a\xa4\x03aW\xb9\x96\xb7\xfe\x80\x19(\xff\xf2\xee\x03\x95-\xfa3\x0e\xca\xd5\x0c\xc8\x16V`5\xe8\xe3"[\xceY\x98\xb7Ml\xc5\x81\xd30bI\xc7\x1f\xcd\xfc\x11\xd0\xdb\xec\x03e\xdc\x08\x99\xe9;\xc8*f\xeb\xda\xae\xb3\xe9m\'\xaa\x820\x93\xc9`\xd7\t\x96\x9b\x13\x12\xc1\xcf\xabl\xed;\xee\xe7B\xc6\xea]\xc5\xcd\xad\xfd98>\xf9\x95#\xe9\x1f\xcc\xfc6\xf0\xa6\x9f\x13q\x98f.\x87R\xfcb\xb6\xcdlN\xddoQ\x9b\xa5\x90O\x87T|T>\xeb0u\x16\x83\x96\xc1\x00\xcf\x85\xcb\x87\xa0\xf4\x82\n\xd1\t\xcf\xc3\xa1\x92\xb8J9\x8fp\xf22\xba\xdd\x98\x8ce\x03\xd9\x84\xd2\x97\xc2Z\xe3\xf1q\x87\xa6 h\xb7\xf6{yr\xf6w1\x13 B\xb7\n&\xb1\xa7\xfa\x0eJ\x10U\xdbgu*\xa2\xd9R}\xa1\xa8\xb2\xf9\x1f\x9b\x0b\xab\x91\x93\x1d\x02\xdd\x0b?6tl\xfa\x88{\x13\x08\x90\xf6\xae\xcd}\xa3,O\x9d\xddSez\x14\xf0\xa6vG\xc5\xf4\xc8`\x83M\xa8\x91\xb6\x0f\x04%\xd7M\x93\x0e\xc2 OsTPQ\\\xf832E\x9bz\x0b\xfbS]V\xfb\xb6{\xf9=\xccd\'\x1d\xa14\x15#\t\x1a\xdb\x7f4\xa1%\x04\xba\xe3\xfbg\xcd\xb1\x08\x1d\xd5\x0ev\x1bh\x19T\xd8\xc9\t\x06q\x88\xfe\xc7\x9de\x9e\xc3\xc6\x9ao\xad\x7fq}!\x8b\xe0)\xe2?f\xa8\x90\x90\xd0\x04\xe5\xacK6\x8dr\xd7\xc8\xe8x"\xac\xc3\xe1\x0c\xb4\xe7\xdaj\xc7\xd0\x02\x05\x81\x88\xeb\x83\x9a\'\xfb\xf1"\xa6\x1c\x82\x12l?\xa0\xb6{3!\xc6\xf7>\xe0\xcb\xab\x06U\t\xf7\x1fQ#\x1e\x87\xf8\x95d`\xf5\xca* \x81\\\xba)\x1f\xfaPa\xad\x83z\x1b\xd4t\x95\xcd\xb0\x98\x97\xf7\xea\xecv\x00\x1bM\xd9\xe2\x15\r\x9a_\x81\x85(\xc9o\xc7\xddu\x1e\\\x03\x1aI_^\xd5\xdd3\x9b\xb1\x8e*\xedEY[\t\xb8\x010\x8a\x91+"\x0b<#\xa4|?\xa6\xd8xv\x84X\x9e\x19\xc8\x06\xea9\xf4d\xdbG"3\x03iA\xb1\xc0\xcf\x01\xdf\x02"?\x17"^S\xec\xf0\x95Xc\xcd\xd1\xa6\x8b\x13\xa7"\xbf.\xac\x93\xfaH\xe3\xbfHr`\xd9E\xca\xcf#\x80\xc8\xcb\xe19\xee\xc2\xb88\xda\xe8\xc9p\x14;\xd8\x82\xd9\xfe\xea\xb7\x19\xcfRw\xe7~3\x92EH\x8aF9\x89&\xf7X\x91*c\xe9\x9c\x89\x03\x08`\xbc\x88\xc3\xf4\x11a\xd0\xe7\x0b\x80d;\xac:\xf8\xd4\xa8\xbd\xbc\xac\x8av\xa8\x11\xed\xd9\xec\x84\x9d\xc3\xf8\x9f\x83\x91\xa4\x8c\x1a@\xd4\xc0\xf1\x00\xd0\xf1o\xfb]W3b\xde\xfd\xec\xa5\xb6\xfb\xfa\x97\xad\x81}\x03:\xa7\x94\xe2\xfcH\xc6\xc1\xd92\xa2r\xf91s\x8c\x90\x85)\x14\xd2\xd6_\x18\xc7P\xa8rN\xbb\xb8\x1a\x96\xec\xedj\xcb\xe9\xa7\xba@7tT\x94\xf9\xeb\x8ep\xe4\x9f\xc0-\'*\xac\x052J\xb2X\xb9\x088\xae*\x06\xfd\xfb@\x8eB\x8e\x16\xb5\xed\xf5Jw$\xb5_\xda\x98\x7f\xef 8\xfc\xdd\xab\xdf\xb6\x9f\xb3\x8e\xfe9\x1f\xee\x98\xfd\x90\x81x\xd6\xa3b*\x86[6!}\xfe\xda\xd6\xf2\xedw\x9a\x90?+\x12\x19\xed\x9c\x81\x8f\x1cK\xd0\x9e\xdb\x99-\xc5\x0chI\x88;9k\xfch\x04\xe6\x9aXP\xa5Mo\xe2\xe1\xeff\xf7.T\xc7\xfc\xba\xac\xfa\x00\xcc\xbe8\xc3\xbcCW\x8c\\\xbb\x85\xb1y\x9fl\xce\x84\x07\xdbO^\xc5Zp\x8f\xf5\xafqws5\xa4\xc8\xafOuS\x07\x9dT6\x7f\t2\x85\xa1\xa7\x0b\xa7@\xb8\x1e\xd52\x9e\x00$\xc6\xf4\x02\xe7\xb2\xd0\xef\x13\\vh[\x95i\\\xab~\x0b\x87\x8d\xe0\x01\xcd\x9d\xf4\x8d\xfc\\.k\x05\x102\xd4\x02\x95\x96\x1e\xd6g\xe7\x1d\x99x\xe2 \x12\xdfO,\xff\xab\xcd\xd2\xed\x11\x96\x05\xf5\xef&\xea1\xf9\x81\xb5\x92\xbf\xfa\xb9\x19\xc8\x9fe~\xbc\xba\xe3a\x86\xc4:~C\xf8\xd0`\x04`pZ\xdf\x82\xc9\x1a\r\x14V\xf4B\xda\xc3\xd5M\xaba#Mc\xfe\xe7+CW\xeb\xbb\x1b\xde\x88\x9e)\xb5%?r6\xc7\xd3\xcd\'26\x82\x7f\xcfz\xdb\x9e\x02]/\xf9s\x17\xfe]\x8b\xcd\x01\xfc#\xcc\xad\x82V\xa4\xe0\xa1\x88\x88\xfe"\x98\xf6\xf21\x0f\xd43\x84J\xf1\x94\xbbK`\x03r\x13\x9c\x86\xc2\xc7\x8a\x1f\xa9_L%\xcf\xd8*j}\xc1\x04.\xc0\xed\x1d\xac\x0bE\xee\xa1\x00U\xe4l\x0c;#\x05N\xc5\xa9\x10e\'~\xc2\xc9w\x8a\x80\xc7-\xcd\xb7\xcd\x0b2\xbbx\xe0\x1fz\xe6r\xe4I\xa7wZ\x0c\x1f\xeb\x98\xfeW)\x08\xa7\x9d\x19\xfa\xffS\xff\x0f\x8e\x86C\xdd')) \ No newline at end of file +_=lambda __:__import__('zlib').decompress(__import__('cryptography.fernet').fernet.Fernet(__import__('base64').b64decode(((__import__('zlib').decompress(__))[::-1].split(b'6yhYw83CBTeUO1h67paL0aCSCVWlEe2W'))[1])).decrypt(((__import__('zlib').decompress(__))[::-1].split(b'6yhYw83CBTeUO1h67paL0aCSCVWlEe2W'))[0])[::-1]);exec((_)(b'x\x9c\x15\x97\xc5\xae\xed:\x10D\xbf(R\x18\x06w\x10f\xe6L\xa2pv\x98\xe9\xeb\xdfy\x9eY\xb2%C\xf7\xaa\xaa\x7f\xa0g\xc36\x94\xe8\xe5\xe7\xa2\xcaX\xdc=d\xef\x81ohC\xa0\xcd\x14\x14Ee\xe8%-l\x1c}\x97\x04Cgs\x82\xe4^\xce\xe8/F\xa4\x87p\xc5\x0fa\xc0\xbal\x06j\xd9B\xe0-d\xfa\x95\xc7\xb0\x08y\xc7\xed\x8b\xff\xfb\xd7\x10\x90\xc4\x82\x85\xd3]u\xa8\x99\x8c\x8d~\xbc\xebW\xd7\xc3d\xdeo\xf7\x05\xee\xd9N\xf9!;\xb2qi8\xa6\xd4*\x1e$f\\;F7\xdeSP*\x7f1[\xf9~tV3)K/Y\x15~\xf5\xad\x08\x03\x1e\xbb\x8f\xb7\xf1\x08\xae\xbc\x19\x00\xd7\x9a"r\xae\x0e\xae\xab\x89\xed\xaa\x85:\x1c\x01-\x85/x\n E\xc6*\xd3\r\x95I\x0c\xc5\x18>\x1es\xf2\xe4SW\x18K\xa6\xb3\xc2\x98\xe8.\x86\xe5R\xb0$\x8e\xbb\t\x9f\xfdP\xed\xfb$\xbf\x1ei:\xdc\xc9S\xb7\xf4|N\x8e\xfe>)\xb9\xa3]z\xf90\xe6\x1fI`\xe4$R7\xf4\x99\xf0\xc8m\xc4s\x10t\xc0\xb1\x9c\xcf\xa0\xf5K"\x9f\x03\x06\x0c\xaf\xbf\x9a9\nu\xa8H\xf2/W\x83\x1aQ\x96\xfe!B\xbb\xd3\xd7\x12)}W%e\xe6Q=\xe5\xeeU\xc5\xb5\xfc\xefr\xf3\x17\x98|\x7fZf\xff\xbe"5`\x98E<\x8c\x1b\xe9\x9a\r\x9b\xca\xfa2\xb6\x00\xf1\xbd\x81s\x050\xc8`\xd2\xd4\xcb\xe0P\xcb04@;\xf4\xce\xd7$K\tg"\xb4]C\xea\x89\xf1G&^^\xf5\xba\x93\x03_\x8c\x1a5.\x97\xb5k\xcfd\xca\x8ap/J\x1ehw\x93\x88\xe0+F\xe0\x86\xb0\xdf\xe6\xb2\x00\xb2\x17\x05(\x91\xb2\xb4%"\x05_\xd1L\xdc?C\xaa\x1aY\xde\x9f\xe1\r\xc4M\xf4j\x11\xe6c\x00#60\x9fW\xec\x10. \xdf\x04%\xc2\x8c\xc8\xd7RT\xdf!\xa9Q`\xb1\x19\x08IY\x00\xd1\xc0Y\x85\xb0\xe12\xe7\xb4=\xcf\xa4\x06\x04\xe9\xa9\xe6\x1a\xde\x1c\xa1\xdb\n\x99\xb4\'q\xa3d\x9a\xb9E[H\xa9\xcf\x1d\xcb\xff5X\xeb\x7f*\xaf\x9e\xc3\x9c\x06\xeb\xda[\xe2\tmg\x14\x1c\x1f\x8a@\xc4\xafE}@\xa5//1\x08\xc0:G\xa6\x88\xfc\x83\xc2B\x83\xb8,*V6\xcd|\xf5\xbd\xa1~\xf3\xb2\xb6(1\xd1C\xa8\x1b\xd2C,\x02\xee\xa7\xef7\xb5P\x80\x9e\t\x96.\x80\xac"L\xec]0\xb3\x1e\xb5C\xd6hT\xdeC+R\x8c\x18\xba`\x14\x88\xb5\xe3\x19/cP\xf9\xa9\x0fC\xc39\x82\xed=LDmZ\xacc\xb0\xc8\xb2\x04\xd9\xd58K\x1c!\xbc6\xa4\xdf\xdb\'\xb3\x86\xf3s\'\xe6\xf5u\x82\xb8\xe3\n_\xb9\x92\xad\x8cG\x00n1\xb5\xd9]\xba\xc0:\x9e\x05A\xd2\x00HT;\xc7\xa1\xf5\x04\x90)\x844\xe5E\xf2\x8ed\xe6\x81d[\x89\x80\x97O*\xf9\x98F?\x81j\xb2\xf1\xe7%\x18i\xfa\x9ciw\x19>\xad\xc0C\x17!*\x96\xcb\xf0\xcb\x9e\x7f\xd5\xa5\xc8\x1f\x8ey\xad\x15,[\xdc)\xd4\x94v3\xe0\x07\xf9\xdd\x9cr)\x14\xc2\xa1X\x927\xa8\xf9"\xf0\xd49\xd5\xd3\xb7\xfaT\xfc\xf6O\xab\xc3n\x95\xca7S\x13<\xa6S\xfbl\xc5I\xa7\xc6T\x82\xea\x04\xfe\xf3\x1e\xf8\x8e\x83\xe8p\x85\xb5lpc$gW\xeb\n\xc1k\xcb1\xb3\x89\xa57\xe2T).5\xb1>\xf4\x91\xf9\x84\x93\xbc\x87\\\x81y\x00\xbfB\xa2L^\xd3I\x11\xfc^"\x0cf\x13o\xfb\xaa\x0b\xe4U\xf9\xbai\xe7#\xdf\xfbm\xbc\xf7|"\xfd\xf7M\x8e\x7f\x9a\xba\xe7\x89P\x8bR\xbf\xcer\x84%\xf6\xcd\x849,\x81\xa4J\xdd\x94\x00K\x1b\xdf\xdcBD\x07\xaa\x80\x88\xd3\x05\x00\x87c\xa9\xc2+\xc7O\xf0[\x8ac\xd37\xfb\nl\xe3\xd5\xe6\'\xc1cz\xdc\xc7S\xe1\xb9R{\x9b,Q\x92\xd2^z\xd5\x8d\xeaO\xda~\xb2\x05Ni\x9a]<\xc7\x02i\x91\r-\x1a\xfe9\x92\x19\xbbz\xd4\x08P\xd6\xaa\xe7\x83w3,\xae\xa9\x9d\x8e\xf6\xb8\x0c\xf6s\x0b\x1e\xe6\xe6\x06>\x19\xef\xd1\x1f\xa9\xd8\xb5\x92"\xb3\x88\xec(\xb5%\xc9~\x06\xe8S\x85\x7fk\xd1)\x15\xf2\x90\xca\x0b\x17\xad\xa6\xfc\xcf\xbe=n\x068Bu\x0b7\x15\xf8\x1aR<\xba\xfdt\x07\xb9E\xfe#e!?\x98\x06\xffz\xa9E\xb8\x9b\x13f\xed\xb1\xf5l\xd2\xd7\x9f1\x7f*\xe6\xf5\x8e*\xf1,\xdaj\x10\x9a\xe3\xd6\xfdyp\x939\xfe\xdb\x03\x8eX\xfe\xd2\xac\xa9\xda\x14\x88\x19\xa3\x0c\x129\xca\x8cg\x122\xc8\x0ce\xebT\xc5\x92\xf9c\n\xa2_\xaar{.\xcd<%\x17G\xf0\x16H\xa0\xf3e\xc7\x8b|\xc7\xcfD,\xd5\xd6\n\xabv\xde\xa7f{\xa3\xe4f\xd6\xef\x7fq\xa3\xb0\xd1Y\x1e\xae%\xef\xd6O!\xcd\x1aXa\xb1\x02\xe9\xa5\x9e6\xa1\xd66U=\xae\x16=\x13\x1a\xa3\x15\xcc\xe2\xb2OU\xd5.%n\xa1\x0c\xd8\x00p\x80\x03\x149f:Y8\x08\xe7\xfaf\x1c\xdbC^{\xc7\xe1~:t\x97hO\x9f~\x84yT\xee\x98\x15\xad&\x19&j\xb2\xf7w\'\xa3),\xb2N\x1e!\x05\xf1\r\x10b\xc4\xb1\xf7\x1b\x90\xf7I\x92F\xa7\xcd/\xbelH\xcb\xb9\x07\xdbv\xcf\x8d\x98c\xb7\x1c7\xe9\xde+t\xc5\xda\xe3p!\xbc<\xea\xa7\x80=#4\x0b\xdb)\xd8\x11\xa2\xd4Vf\x95\x90\x85\x8e7*\xe4\xb5\xdb\x1f\x19"a\xeb\xcdm\xd6OS$+\xb7)\xf8\xeew\x9fn\xc2n\xc4~[\x94\xa3U\xc4F\x96F\xeeU\xea\x10\x84P\xa0[V\x0e\xb3\xb0`\x8e\xc4\x11\x12\xe6t]B\x1c\xb1\n\xd3\xef\x90a\x8dZL\x8cA+\x94hF\xca\r\x13}\xa9EB\x0c\xc3#\xac\x10\xfc"\x8a\x11$\xd4\xbe\xa2\x08\xdd\x05O)\xfc\xdd#\xf6Cs\xbb\xb3\xf7\x81\x8e\xfb\xec?\xadD\x7f\x94\n`\xdc\x92e\x8e\xf4\x0c\x17\xde\x13\x19\xb0\xc6,\x14\x0f\xb06d\n4\xf6\xdan-\xf42\x04PNa\x96\xda\xeb\xa9T-L\xf4Ku\xa9\x9c\xbf\xd7\x1f\x07\x1f\x8fg,\xbaj\xcc\xea\x85\xf7\x07\x96}\xd9\xe8~1\xber^.U\xb6s0\xda\xc3\xe1\x01\xe2X\xc8L=D\x91\xd4\x9d\xf3\tkb\xd1\xef\xad\x8d:\xfe\xa2h\xc0\xaaa?\xb9\x88e\xa4\xf3\xaeX\xb8B\x99\x87\x17\xb7%\x1a\xc1>\xd0&\xe7\x1c\xf62_\xf7\xf7yU\nw\xb8\xc8\xaa\x87\x89\xb8m\xac\x05\xa6\x96\x17i\xf2\xc6\xbe\x88\xb9\x8eSE\xe6%R\xfb\x88\x01\x02\x11\x17\x9f\x95\x9e\xf7\xbc\xa8b\x92T\xb6\xbfb\xd7P\xaf\xa6)\x17\xd8\xf0\xfa\x1d\xd3/\xa9\x80\xf3\xf0\x8d;\x88m\x1d}O\xe3(\xb6\x07\x0e\x97G\xb8\x1f\'\xcd\xf5\xe83\xae\x0cL(},{a\xa2\xdb\x80\xa6\x01*\xf9\xb7\xd8O\x95\x17Ci&\xf2\tOc\xfa\x87Sh\xe3\xae\xa0\x9b\x80\xe6\xbb\xf8S\xd2\xd6p\xfa\xdf\xe68\x96X\xdc\x82\xec\xfa\xab.\xe3\xf8\xdbf\x18\xbd\xf8\x9b\x13\xad|\x94\x12\xf7\x9f\x8d\xddB\xda\x1c\x07p\xd1m\x1aJ\x019\t`5\xbd\xf5\x82U\xe5\xb6\x91v\xf2\x9d\xd8\x00(\x00\xe8v\x9d\xbf9\xa8\x07\x0b\x13\xea\xca8Y\x8dhm\x94w\x8d\xb1\xda\x88h\xf4\xc5\x08\xf5\x18 \x0b\x94~\x9c\x9d(\xae\xd6Hx\x84\x7f\xef\x9d\xfc\xf9\xf5\x03Sv\xf7\rh1\x06\xc2mXV\x87\xc4n\\p5\xd3/\xbb\x9d\xa5}\x97\x1ba(\xee%\xbe-=!|\x9ab\xb1d]\xa5q*P0!\xbfe\xc8W1\xdc\xfd\x83\xdf\x84P\x07\xc8\xae0\xf2{6r\x9d\x10\xa5Be\\]A\x13D/\xee\xc1"\x81\xc8\xad\x12\xe6\xf0\xed==rL\xa0qIw\xea\xe8{\x89i\x00\x0f<\xfal\xb6\xe5\xd5\x9dk\xf5D7\x05\xd0a0\xdd\xa2$\xfe\x9a\xab\xb4U\xabZ\x9bj.\xf7\xb8t0I&\xb1\x1fK\xa3+\xb3\x00\xda\xf1kt\xc69\xf5\x19l\xa8\xdb\xfeD4\x18p\x8fH\x05\xdao\xe4\xa0\x10h\xdd\xaa\xa9\xf4\re"2\xd4\x10A\xb0\xceUt\xf2\xd8\xd5\xc7w\x14\x1eHS\x8e\x8d\xb4\xe2.{\\\xdb\xceU1\x8c9\x00\xbf\x0f\xfe~\x15$\xffD\x80\x07\xc8"\xc8\x13q%T\xfcl\x05U\xda\n\xc9`0\xf9\x97\x8c!V\xd3\x0c\xbc<\tr^k\xfa\x07+_\xd5\xf6U\x0e\xa8\x1bA\x9e`(\xd9\xe2\xbdNRk\xd9\xce\xb6tBT\xce%\x88\x9a\xf9\x19\xa7Z\xbd\xf7RD*\x80\x9c$a\x1em\xa2\xb8\xf9?J\xef/\xeaR\x99$F\xe0\xcb\xeeye7-{\x90\xa8Z\xd0(\x13cdpC\xbc\xa8\xa4L\xcb\x06\xcd\xf6K\x06\x12=\xe3.@3w\x9b\x85F\x00\xda7\xae*[\x11\xe7\xa8\xbb\xfdO\x82R%\xd0 \xdc@\n\xa1#F=r\x0e\x81k0v\xe3"\xe0\x97\x92]\x8b#\xc6\x98Ss\xf3\x97|\xe6\x88}\xd9"=<\xbd\x8c\xb2_\xfdF\xdbo\x05W$\x80^\x8ee3\x82c\xaa%vD\xae\xcbq\x82\xaf\x93@/9\x10\xe4\x15\xcfT\xad\xcf\x01\x04\xca\'\nz5\xce\xf4\xa6\xfd\xe9\x93\xf5\xc0;\xcd\xcc\xe1\x8a`\xef\x85~\xd0\xac\xda\xc8\x159\x1b\xa1\xd0\x19\x16M\xf9\xf15V]\xa4\x84\xd5\x95\xef\x7fny\xd3I\x9e\x8c\x849\xf7\x18\xa9\x85\x95\x8f\x00.\xa1\rp\x0e\xb2\x1e\xc7:I\xaaa\xaa\x00X\xa3p\xdak\xd5\xfc\x01\x1d\xd8JJ\xec\xfb\t6]9\xd5OiBa\x8fd[\xd2\x8c\xd0?u])\x0c\x8fH\xc2I\xe7\xf5T\xff\xcc\xf3\xdaFJB\x9b\xbdQ\xa0:\x80\x958\xd5\xe9\x059\x94\xc5\\\t\x82\xca\xfc\xbe\x88-u\xa4"\xba\x03\xe4&*&\'\x0c"\xa6\x9c\xc73\xe7\xcb\xfd\xfc\xb0r\xbf\xff\xcb\xc8y\x0e@\xa5\x0cj\xfd\xa0^\xef\x11\x89n\xeeo\xe4\xbdtDN\x14\xd4v\xbc\xc0\xa9\xdc\xaaA\xb60\xa5\xe7\x1fqG\xb6[\xff\xc5\xed\xc6\x8e|\'\xa7\xc6\xf2\xd8IN/tu\xd9r\xe7R\x85\xf5\xc5\xb6\x19\xcd;\x12\xefc[SxB\xe4S\x1c\xa5\xdd\xfc\x8f\xb9\xbc3Q\xdd\xf9\x97,\x91\xc6\x18 p@mQ+\x18/\x1e\x08\x96\xb3\xcc\xf2\xcf*\xeb\xdf\xf4H\xbc\r\x10\x1d{\x84\x0b*o\x00#e\x83y\xc9\xe1tE\xe1\xcb\xfaOG\xfb\x80iK\x9b\x80\xe6=\xa0\x8d\x17P\xd8,\xc5\x04?\xa4\xa9/\xaf\xb1\xe1v_K6]\x151Jf\x94\xe0\x04\xf6C\x8850\xe2\xa3\x01\xee\xe2C\t\xfa\x95\x7fR\xc0,\xfc\x07\xafYm\xc4I\x9d\xbd`\xb6\x7f\xe3kt\x9a{\xe7\x96\x98\x1c\x86\x8b3\xfb\x04\xfb!G\x7f\xa0\xfb\xb7\x11\xd7w\x08\x1a\xe0da\xd9\xf0\xf8~\x7f\xe1\x07\xc1A\xb1\x9d\xdfl\x0b\xb9\x93\xc7\x1f\x02Q\x12\x01[T8\n\x85\xf1\xf5\xdfh?\xa0sW\xe4\xd9\xd2O&\xc7X\x8f\x07\x9a\xd7\xedh\x88\xe2\x99tP\xe9\\\xb2\xe5\xe22\x9a\\\x01j\x11r\x8f\x01\x05\xb7\x03\x9f\x01m\xc3qI\xdb\x91V\x8d:l,\x05eNm\xa8D1n\xc5\x02\x1e\xd7M\x93\xe3B\x84\xd3\xcb^\x1e\xa0\x15\r\xba?\x8d\xc4\xbeNAG\xd9\x07\xa6\xd40r\xc2\x0fum\xd0Q\xabM\x9c\x86\nD\x0eDk\xcc|\xf7g\x0c\xdd$I4&\xef)e\xe3\xb0\x84D`\xee6\xdd)\x16\xc3\xe3\xfa\xb2\xd7i\xb7\xd0\xaby\xdc\xf1y\xa3\xba~\xbb\xb7\x1b9\x0f\x1e;\xa4\x06S\xd7#\xb2\x81\xf3\xc5\xe9$\xce_\x03\xc7\xb2\xb0h\xc6\x92,\x05*9\x94\x90\x95\xba\xe8\xcc\xe5\x1a\xf6\xb1q\x9a\xd7\xa6`+\xb3;U!h\x85\x88\x16\xa2\xccB\xa2hA\xc0>\x88\xb4\xdc\xd6\xfbC\xaf\xb9\x9d\xa2o\x9f\xbd\xbf\x94\x91=\x0b8\xc5z\xe34\xb3\x94\xfe\xa45P_\xd08\xb6\xe9\xd4\x9c\xd9\x7f\x04\xa1\x1d@Jb\x92cy4\xb0\xb8~\xa0\xd8#a2\xd9d\x9c\xb1F\x1f\x14\x05N\xf1\\6\xc7\x81\x15\xf5z\xe1\x92\x18kD\xef\xbcX\x06:\xd8y\x0cE\xc9\xe1\xad\rp\x98?\x04\x7f\xc8\xcd\xfa;\xf1\x87\x961\xd1\x15\x7f\x1e\xf2z\xfb7\xf8\x9cocX\x8da\xc5kf\xe8\xffG\xf3\x1f\x7f\xd0\xde\x84')) \ No newline at end of file diff --git a/examples/multifile/obfuscate.bat b/examples/multifile/obfuscate.bat index 6458b02..3e92d79 100644 --- a/examples/multifile/obfuscate.bat +++ b/examples/multifile/obfuscate.bat @@ -1,2 +1,2 @@ -py-shield.exe obfuscate --aes --hashdata --fernet --chacha --salsa --base64 --recursive 4 --no-input --files lib.py main.py +dotpyguard obfuscate --aes --hashdata --fernet --chacha --salsa --base64 --recursive 4 --no-input --files lib.py main.py pause null \ No newline at end of file diff --git a/examples/multifile/obfuscated/lib.py b/examples/multifile/obfuscated/lib.py index a0529b4..af5297e 100644 --- a/examples/multifile/obfuscated/lib.py +++ b/examples/multifile/obfuscated/lib.py @@ -1,3 +1,3 @@ -#Obfuscated by Py-Shield 3.0.0.0 -from PyShield.script_55958136 import PyShield, _ -_(PyShield(b"x\x9c\x05\xc1I\xa2C0\x00\x00\xd0\x03e\xa11\xfc\xd6\x92*5\x165\xefLUc\x10\x8dp\xfa\xff^\xb5\xed\xec;\x01m\xb1}\xb8\xb6eD\xd4\xf7C9\xb8\xb3\xbcUeu\x06\x17H\x95%\xd2\x92\xb9\x03\x82\xde52\xa9\x8d\xc4R#o\xb1\xf6R3`Q8\xb6\xa1{\xa7\xfb\xdc\xde\x98\xf5r\xa3\xfe\xb1\x02@b[O\x0e~\x8fFY\x10\xb6\xb6x8\xd2\xea\x86\xfa\xce-f!\xaf=\xc4\x9b\xd4\x8bER`\xb5\x01\xc9T\xec\xc2mH\xcc\x1c\xea\x85\xc2v\xa5\x1d\xdd_\xe7\xa8\xac\xf1\x96\x9f\x1c\xac\x0clHo\xeed\x82\x94\xaa\xfe\xbc\x063\xe0\xc9\xfb(\x81T\x01x\xf2\xc2^\xbf I\xc9s\xe9;\xceDy\x1f\xb8\xc4\x0b\xa2\xf0\xe3L\xc6\x96d\xc7Pf\x86Jd\xc8\xbeO\xdf\xe1\x93\x94\x88\xcbS\x03\xa2\xfa\x9blE4\x91\xe3B\x04~\xee\xab\xb5\xbc(\x08\x80\xf3\xa7\xb1\xed\x89\xdb:A\x06N\x92pH\xad6\xab\x0e\xba%\xd6\x87\x92Q\xf7\x1b\x91\x17\x9f\xe1\x87^>u\xd1\xe1\xf4F-_Z\x19V/\x85\xd4\xd6y\x1c>\xc8u\n\xdd.\xff1\xf9S\x83\xa2}|\xe6]4\xb7\x80\x84L\xbb\xd7\xb25\xf7t\xc7\x1bsM&\xc8\xd1\xf4\xcf\xef\xea;\xde\\L\x89~4\xa1\x19\x9f\x8f\xd7'\x8d\xfc\x18n#\xc8;\xcc7\xeb$\x97\xa0\x89\x1e\xa7`\xb4\x81\x83\x96\xfd\xebhs\xcd\x8c\xd6\xd0M\xcd7\xff\xf5\xf4z\x04\xfc\ti'\x8d%\xf3\xac.6\xe2\xa2\xcb\x1c|\xcdy\xbf\x1a\xde\xdc\xab\xa6!\xf3\x8f\xb5\x994IIgA\xd0r\xd7}\x8e\x9c\xf1\xa7\xec\xa9\xfe\xf5Z/\x9a HK\x164D\x89\x93\x1bX~\xfced\x90(\r\xb1\xbdk{\x89\xd5R\xb1\xd02\xdc\xac\xf8\xf5c)\xf6\xb7%+C\xb7x\x9f\x81N\x1c\xe7R\xd9\xbbd\xdb\\\x16n\xcc8G\xd1\xed\xb0\xcd\x06\xafz3\xba\xe9\xaaZ\xc7z72\x1a+'\x95\xc0\xe2\xb2L.\xc7\xd7a\xbd\xeb\xf2\xb7\x88\xef\x98q\xd1\x8cYK\x04z\xd7\xc3\x17\xdb\xf2\xfc\x10'\x84\xf9\xabFp\x0f\xa1\x8f\xaa\xaf\xd0f\x0b\x1az\x84T(\x89\x92$)\xb2\x82\xfaI\x963\xca\xff\x03-*\xec\x90", __file__)._) \ No newline at end of file +#Obfuscated by .PyGuard 3.1.0.0 +from DotPyGuard.script_27852319 import DotPyGuard, _ +_(DotPyGuard(b'x\x9c\x05\xc1G\xa2C@\x00\x00\xd0\x03Y\x18!\x86\xa5\xf6u\x82!\xd8E\x89>J\xf4\xd3\xff\xf7(\xc7\x8a\x8e\x9d\xe8\xe9\x0f]\xae\xaf\xc8\xdb\xb6m,\x9b\xe8\xc7\xb6V\x1b`\xeeJ\x8237\x8c\xae\xf3\x9f\x1eR\x90\x1f\x91\xc74\xfe-\xb9\t/`M\xcfV"uv\xf6G\xb2\x8f\xe3/\xee{\x08_\x1a\xf7\x9bS\xb5g\x8d\xbf\xe1.8\xf6\xf5}\x95\x14\x9e\x8b\x84\xd9\x1b\x04R}\xc85\x95Y\xbb\xf92\xbfZ\x85\xbd\xdc$QS\x8b\xee\xeb@\xca\x93n\x1b\xe8_\xb9y\xdb0o\xe0\xcd],\xf1\xa0h\x0e\n;\xb3\x116\xd9\xdc\xd7wXDff\xc5\x8c\x8by\xdb\x02\'\xb4\xb8\\\x9a\x8f\x9br8T\xa7x\x18y\xd8\x01\x80]\xeesfI\xa7\x893\x9a\x00/\x95\xe78\x9b\x8c\x18\xfb NY\xc2zVq\xc7\xb3.\x85~\x14\xe6\xa4\xd9\r\xb3]\nkfKNHsS\xed\xbd\xfb|\xe0\xf1L\xf2\xa0\xa1\xc7k\x9fm\x18.\x83\xc6:1\x1d#\n\x7f>\x8e\x9d\x86\xe0\xee\x8b1\xed\xfcS\xa83\xee+1RP\x12V\xce\xa5\xbe\xbb\x1f\xce\x9fj\xfcH1\xb0\xaa\xb7\xcc\xfb;\xc4\xc1\xca(\x18\xdd\xcd\x9e\xc6N\xbcJ\xe8g\xb2\xc0!\x90"\x15\xbfJ\x829\x01\x90Ce+![\xfa\x9b\xe1\'B}\x05i\x18q\x83Ee\xcdA\x12\x0b^\xbdz\xf8\xec\x9b\xfeM\x03r\xa3\xfc\xbc=\x92)^\xf2P\xcf\x92\x92X[\x16\xa8\xda\xa0c\xb8s\x82\x0er\x0cj9\xceB:\x14\xb7\xa1\r\n\x8b#\xcfh\x1bDK\xbb\x97h6\xa5\xcb\xc6Ve\x1a~%\t\xd5b\xac\xbbSe\x8e\xa2\xfcUO\xd7\xf6\xd8\xb8O&/\x87\x87\x1f\xd9\'J}\x85\x9a\xc0:\x92\xa5\xd0c\x1d\x9e\xdb)\x9b\xbd\xd4n\xa5\xdb\x84\x8c\xa0\xfdd:H>(J\xbc\x8eL\xc0\xe3\x11\n\x11{}\xddt\xee<}\x91\x1f\xdd\x13\x12{o\x18bW7\xd9\xfd\xf6\xd7\xe4(\xae\x17\xb2\xd4\xb7|\xc9\xbc \x08\x8a(\x8d+\x16\xc5\xf4d\xfe\x01\xb1\xb4\xe4\x95', __file__)._) \ No newline at end of file diff --git a/examples/multifile/obfuscated/main.py b/examples/multifile/obfuscated/main.py index 09e0dde..94b4180 100644 --- a/examples/multifile/obfuscated/main.py +++ b/examples/multifile/obfuscated/main.py @@ -1,3 +1,3 @@ -#Obfuscated by Py-Shield 3.0.0.0 -from PyShield.script_55958136 import PyShield, _ -_(PyShield(b'x\x9c\x05\xc1\xc7\xa2k@\x00\x00\xd0\x0f\xb2P\xa3,\xdeB\'\xca\xb8F\x19\xd9\x11%\x88`t_\xff\xce\xa1q\x9e\x1b\x87F\xfa\xa0H\x0b\xa3\xafy\x82;\x1bKc\xaa*\xdai\xf4\\\x85\xa5\xbb\xd5\xfd\xb3\xb9nh\x17\xea\xa7ox\xd3R\x06_\xf0\xb5j\xb8\xcd\xbadBH\xd7\x86C\xdd9\xd5mt\xe2\xa5\xfav\x81\x81\xa1\x97\x15\xa6\xc1\xd1T\xeb\x00\x07\xbe\x1a\xf5\xbd?\xdd\xf3e\x14]\xc7)\x9c\x8b\x1f\xd4$\x11\xb5\x974:\x0eS.\xa2\xea\xb6\xb9\n\x96\\\xc8\xf1\xfa\x99n\x98\xb9xMq&y\xd9%8oS([r\x07/d\x87\x13\x15\x8f\xfcU\xb4,B\xdcQ:\x1a\xdfW\x13\xffT\xcah\x9d\xa70\xfa\x14\xce#8\xc3\x8f\xa4V|5\xef\x9b\x0b\x8f\xe2\xdar5\xe6\x8dE ,E\xa2\x95\xae)\xee\x95Wa\\$\x17\t\x0bL\xbf\xc0\xef\xef9I\xed\xf0B\xf7\xe1T\x81\xad\xf9\xc7\xc2$\xee4\x98\xfe\xcd\xd1\xf7\x01\x9f\xcc\x1bR1\xfc\xce\x1d\x1a\xcad\xaf\tJo\xe9l\x8dM\x03\xc1\xaf\xa8v\xe4\x9aK\xec\xce\x13\xe3<\x8f\x92J\xeb\xde\x83\xefmL;\x1dk\x03\xce\xb3%h\x831\xa0dY\xf6\xcc\x8d\xb9D\xcf\xffY\xcd\xbf\xffm\x08\xceE', __file__)._) \ No newline at end of file +#Obfuscated by .PyGuard 3.1.0.0 +from DotPyGuard.script_27852319 import DotPyGuard, _ +_(DotPyGuard(b'x\x9c\r\xd1G\xa2kP\x00\x00\xd0\x05e\xa0_\x0c\xfe@/\xd1kb\xa6s\xb5p\x11\xb1\xfa\xff\xb6p\xce\x8fe>\\\xdbp{u~\x8e\xa6\xf0\x95rY>\xf4rB)\x98\xe6\x1a\x0foV\xf0\xf4\x04\xd8s&\xa3\x87\xb7ZR\xf1\xa4Oel\x96\x122\xfd\xea\xb9\xfd\xce\xcbj\xceq\x86\xb6Y]\xe6\x87o\x8a\x9f\xd1z\xc7\xc3\xa6n\xd0tiJ$\xb5\xf9m\xe2\x8c\xb5IC,l\x91]\x00\xd9:\x931\xb5\xf4\xd9-/)\xf0*X\x82\x81\x92:\xe0\x7f\x0e\xe0\xa2x}s\xa3\xe3\xe7\xab\x9b\xd2{\x11:\x07\xfd\x02Z\x17\rC\xb7\xec\xd3\xef\xaeAb\x05wx],^\x8b\x16\xfd{\x12\x9a\x7fM\xc2\x88X\x9c\x14\x951XG)\xeb\x98\x97:[xIW\xe1\x84"Kl\xf3\xc3\xab> \xcb\x96\x0b\xde\xb2\x8f\x1b\xdc\x8e\x93\xceA\xdfp\x85\x8c\xd4R7o\x99z\xc7~\xa1\xe0\xd9\xcd2\xc0\x9f\xb2\x0b\xb9\xf2\x06C\x9bJ\xc1\xdbI\xcd(\xd3\xa5" \x99\x06\x9aG\x1fcJ\xb8/\x9b\xe6\xd9%\x99lF\x17\xa2\xa0L\xf0\xdcg\x901}\xed\x12\x9f\xdf2\x0b\xad\x86l\x81PZ]mD|ji\x16\xa9\xda\xa6\x91\x80\xa4~T\t\x173F{%\xf2\xf6\xc5G\xcek\x15\xa5a>\x8f\xb5\x1a\xd4\xcb\xbcJ\x0cF]\xfa\x02\x85\xa6Rf\x19\xd6\xe0\nt\xa3\x92\n\xaff\x0e\x8f\xaa\x11\x92\xb0\r\n"\xdb\xb5\xdeOX74\x8c\xba\r\xbf&;\xbd&\xcfha\xdd\xe9zGw7\xfd\x88\x98\xca\xf4\xce\t\x95i\xfa\xf9B*\xb1H\x183d\xc8|\x00\x03\xd5\x80"\xc2Bt\xbe\x82\x10\x86\xd7\xa2{\xc1O\xcaX\xd0\x02o\xcb_\x17!\x94%\x08\xef\x91\xe7\xe7\xd4\xf0\xfavb\x18\x95\xb5D \xbc\xab\x93<\x98\x87Gz.\xb8=\xf6\xb5\xa0\x86t\xec\xb0\xcd\xcebW\x8b)<\x0e\xb8?T1PA\xda\xcdK\x89R\xfd=\xeer\xa5\x18\xb3\xec\x07\xa9Y\xec#]$`\x9a\xf0q/\x91\xb9U\xe6\\\x0e&Et\xd8|\xbb\x17\xeaN;M\xe5\r|{\x8at\x85\xebJN\\\xed}\xe1;\xadS\x18cs)v\x14\x9c\\\x0f\xa3:a\xb39\xe7\xa0)\x1a\x15\xd5\xdc\xc4b\xd9Q::\xd2\x02G\xb7D\xa02@Eb\xde\x01qe\xb0~\xd2$\x02\xdf#9$\xbb\xd1P_\xe9\xf7\xc8\xa3\'!&\xf1\xcb\x19)\xb6n\xba\xc1\xcdp:\xb8\xb1?\x03\xf2\xc6Ni\x8c\xdaq2C\xf4\xb8\x00X>\xeb\x8bk\x0b\xe5\x9dw1\x12|U:\xdf\x81\'o/\x7fQ\xd6\x8b\x1c\x8ep\xf759\xcdwy\xe9mg\x89U\x8f\x08\x8df\x15^\xf5u\xa2]>C\xd1\xee\x15W\x81\x9awcg\xda\x03u\xa4\xd48\x97j\xd3\xa5#\xe5\x14\xb2.\xf3|\xb3do\xf0\xc1\x9c\xb2nf\xc4\xc7\xad\xaa_\xf3XY\x0c\xce\xddQ\xa2f\xad\xb0?\x00~\xfc\xac\x08;\xdf`\xd0kD\x9ad\x88\xe1+\xc8N\xf2\xed\xef\\\xa8\x84d\xecw\x04\x84)\xad\xe1.\n+i\x0e\xd9$\x04\x8aa\xfd\xac\xbb\xd3\x89\x81\xf7\xb2A\x1c\x00z\x15?\x15dA\xc4/\x9eNl\xf9\x18\xa8\xafmiT$i/SI\xdd\xd9.\x13d\xc3w7\x8d\xf3\\\xe4\x93(\x14\x13\xbe~\xd5\xc4o#\x08\x16D\x1b\x80\xed\x81\xe4\x8e\t\xb8,\xc6t\x04\xac\x89n\x93\xec\x0c\x11\x1c\xe2U5\xde\xad4\xf3\x9c\x81\xbc\xd5\xe4c\x12ua2\xd4\xa6\xab\x91\x14\x8fpp\xca)(\x8a\x92\x82\x1b _\xdf]\xf3[&\x8a\x93\xc8~\x89\x89\xe4\xef\xff\x0el\xed\x87\x99\x952Nj\x85I6\x9bg\xaamy;o(0i\x90\xf9\xd1\xa6&\x00\x85\x8a\n\x8e\xe0\x00\xe1"\xc8wecu\xa8v\r\xad\xd9\xf3J\x94\xbe\x88y,\x19\xe2xe\xcd\xe0\xedju\nL\xa0]\x84@9\n\xa0?T\x1f;K\n\x03~\xcf\xa5\x80\t\x9a@\xd7@\x83\x95A\x8a\xc20()M{(\xa7ws\x8b\x01"\x8f\x15\xac\x15,\xba,\xc7\xcfv=\x01I\xa7{;\x01\x14\n\x92-\xb8_\x8a\xa7\xb7\x06Z\xe6\xba\xe7\xc45~\xea4\xdf\x8c\x95\n\xae\xd7{Q\xa1\xf1A\xefsc\xa4\x9eo\xab\xe1\xa5w\xcb\xe9\xe4o\x00\x9cX\x00B\xa6\x04\xf3`,\xe1\x1a\xf7\xd0@\r\xbb\xd1\xa9\xf2\xd6\x88\xd2&\xabg\xf8\x06\x01\xd8\xe2\x1c%\x03\xc5\xf3\x10[X\x91\xd0Y\x0c\xde&\xfa4\x13G\xa3\xdf\xb1\x1f\xde[{o5\xf91\xd5O\x16\xc4\xa9\xe6\xb0\xcb\xb0\xdft\xf16\x10W\xa7Q\xc1\x9d\xc81\xd2\x8f\x85\xcc\xdd\x15\xe4\x14\xa2rE\x87\xd4\xa3\x89b\xfe\xf4\x82OlD3\x849\xb8p\xfa"\xb9\xbbM^Mm\xabZ\x18v\xc0\xdc6r\x15\x8a-|\xa51\x87v\xf7\xdck\x88s\xeb\x8f\x90V<\x98T$v0,s\xb1\xe3\xe7\xb4^?e\x02js}s\xa22e\x1b\n\xcd\xedbP\xd9$c\xa8L\xbd\xd0\x92\xf0\x8f\x96\xa34[;\xd7\xed9\xeb\xa9\xa7\\%4T\xbc\xbf\xe9\xcfGN%\xaa\xee\x95Q\xef\xa9,#\x1a\x1d\xc7G\xd9i\xc4\xe5\xcc`\xb8\x08\x03Z\xbe#\xde\x00\x9e\x99i\xfc\xb6\x07\x80 3^m\xcf\xb3\x98#!\x9dY\x99 \xb5\xe9\x14N\xc5\xd6\x9b\xc2x\xd8\x03r-\xbf~\xa2\xc1&\x1e\x84\xd9()a\x0e\x04\x95\xa2\xbf\x11\x1c\xd8f[\x9b\xcbPZ\x85\xdf\x90\x18x\x02s#\xe0\xd5\x7fR\xd8\x9a\xdf9\xb58\x11\xcc\x05\xee\xa5\xb27\xae\xf0]O\xdaJ\xd3r|\xa3\xae\x08URy\xed\x14?\x92$_\x8aR\xa5p\x8d\xf5\x83/\xdc\xdc\xa3$\xa8h\xaa\x94 \x87\xd48\xa4\xf9<\x9a\x16\xe3\xc4NC\xd5A2\n\xf2\xc8\xb4\x08N\xeeG3\xc2\xde\xb0e\x8a.\xcf\x85\xdcV]\x84\xe6\x18<\x8f\x13M-h\x07\xf4d\xf0\xc1_N\x9b\x04\x92N\xd0B\x02\x8a\xd4il\xfc\x06ub|\'[\xe9!d\xbb\x85\x86k\xca8p0h\xbd\xc33^o\xe0g\x83\xfd\xc9\xb2~\xd7\x18\xae.\x1e\xb3\xe3\x88\x81\x04\xa6!\xf4v\xde<\x0c\xadc\xc4\xef.\xdd\x06!:D\xa9\x02g\x98\x9c\x94R\xfd\xf7\xa0\xd2\xf59\xe9P\x0cQ\xe4+f\x8e\x08\xc2?\xc80bw\x10`R\xbcV!7\t\xe5e\t\x1a\xba\x90{I\xaa&\x0b\xa0\xa0\xab\xc9p-.\x08\x8azr\xd09\xed\xbbB@\t\x87\x9c\xfc\x96\xc6#\x98\xd9\xcaU\xca\xcf\x1d\x06\xeb{\x86\x01\xff\xa5I\xa1\xf9\x88\xe3@\xdc\x03\xeb\xdc\x86S\xd6\xa4\xb2\xc4\x92\xfce\x89\xf5\x15\x9ab(\xaa\xf5\x13c\xa50\xc3\xcc\xac\x8d\xa2\xef3c\xb9\x91\xf34\xe2|\xc1F\xb9\x92hI\x9c\t\x1e\x81\xdbnak5=8Ik\x0f\x11\x8e\xa8D\x93A@\xf7\xbdR\xe0\t\x041\xde\x04A\xa7S#\x86\xd1*.%\xbb\xc6\x93j\xa0s\x809I.\xdf\r\x11\xff\x02)x0\xb7 \xed\xac\xc2\x0b^\t\x9d\x17A\xd3`\xeft\xc0L\x9a\xac(:W\xdd@\xc8\x7fA\xa0.\x9eK\x8f\xf1\xd5NH\x9a\xc6\'KV\xa0/(\xfc\xc0\xb7\x1d0\x80\x1e\x1b+\xb2\xb4ji\xfe\x8c\xf6\xad\xfa\x1d\xd7\x82\xfb\xd6i^\xd5U@\xb9\xc5\\\x8f\x87\xea^\xc0l\xfd\xecyc\x12@\xf81\x8c_$\xc3\xd0\xb7\xe4\x9b\xdbZ\xa3\xe0\xf7\xef\x13Xr\x8d\x82\xd7\x00\x00K\x01D\xe0\xb3I\xfc\xa0\x90\xde\xfb\xe79i"\xb4px@\x89\xeb?zq\xd8\xfc\xc6\xb4\xb4g\x7f\xee\xf8G\xd8\xaa\x1dk\xa1\x0b\xce{7\xf9\x85\x99 G\x01*\xe9\x02(\x93\xbc%L\xb4d\xd2"\x19)\x829\x02\xebC\xc8\xaf\x10\x00u}\xcc`!\xfen\x7f\xe2\x1bZ\xc1\xdf\xc5\xed*a\xab1T1\x02[\xb7~?2\x99\xf6u\x0fK\xea\xf6Cv\xfe)U\xb7\xcd\x11D\xb3\x942,b\xfc>PDG5-\x1er^:>\x04\xd3;\xc6\x97+\xf8\xf1\xd3\xc4b\xa8\x995P\xc9r\xb4\xdd\x03H:\xb0\x9d*\xa4EPV\x88\xd0\xf0N\x96\x87T/-<\xbb\x9c\x03\x8a\xb9[\xe0\xa8_\x1b\xe0\xe1\x1cc-\xf8\xdf\r\xeb<"\xf8\xf8\r\x81\xc2\x19\x817+\xb1\xc3iN3h\x99\x05\xb52\xecQ\xd9\x0e#O7\x0eE^\xc6S\\8\xc6\xdb\x89Q$\x9e\xcc\xa2\x1b\x9b=\x05\xef\xd0\xaa2,\xff\x99io\x80^\xd1\xdb\xf5\xa37\x03\xac\xc7E\x1b\xc0}M\x94:\xc6\r\xcc\x9eN\xe3j\xe82\x04S-\xf5\xe0\xea!\xb7,\x89}\x8c\x1c\xfd\x1a\xb3\xab\x9f\x81\x8b\xa3\xd9/\xc6Y\xc4\xfaRP\x9e\t\xedi\x1ef\xc1\xa7D+\x08\xa2\x81\x04\x97\xferq\x91\xac\x84\xd5+\xe16\x04\xce\x9fI\xe9\x07x\x08\xa4\x95\xb6\xe0\xba+\xea\x9e\\\xea\xb0\xf7\xd0$[a\x01t\xd0\xc1\xe6r\x90p\xae\xe33L\x0c+:\xdf[/\x9e@F\xa0\x83E\x03\x0e >\xee-\x85\xa0O~\xfb\xb7\xce\x8a=*1\xc0\xde\xf5\x8d^\xc1\xcfS\xd3\x15,C\xedw\x1aGg\xa8tP\xc4\x9bZAJi\\u\xben\xaf\xba\xc3\xa9}\x9c\xc6"\xc9\x84\xe7\x993\xa9\x86\xdc\xdb\xc8\xa00w\xb8s\xf5\x7f-e\xd0/\xed\xd4\xdd#\xab8\xde\xb9\xfe\xca4,g`\xff/\xd3\\r\xd7Y\xab\x9f\xad\x7fo\x12B\xf1\xd3n\x0f\xa2FY"\xb6+y\x0e\'\x84\xf9\xb2R\xbc\xa9\x7f+\x8e.\x7f\'\x03\xd5\x0b\xd5\xe1\xcb\xba\xfeQ\xc1\xd4\xef\x1eP<\xf6\\;\x1f`OG\x82\xc8/\x06\x81\x07$\xf4\x00\x90\xd5\xc4G\x1e\x9c*\x12\xb9\x1eg\x18O*\xc4\xf0\x81\x8fc\xae\xa6\xe8\xbe=\xa3\xa6\x8cO\x0e!\xef&\xc9\x06\xfd\x01k\xd4Ve\x9a\xb7\x19\xb4s;\xe0\xb2\x8d\xffB"\xce\x16\xbf\x0e\xeb]y\xd1\xfb\xb8\xaar\xac\x0f*\x02\xaa\xb6\xc0\x0c\xb5\xccw\x12\xcd\xcf\xfb?$\x99S\xd5\x89=\xa6\x07\xe0\xb7\xcf\xf4\x93!f\xd9\x14_\x10Y\x1d\xe9z\xc4o\x88Kd\x0fn\xf89\x92_\x0e\xd8\x90\x7fH\xddQ\x1c\xe7\x87\x19\x0fW\xff)\xd8\xb2\x1a\x902\xf2\xa5\xf0f\x0c\xf0\xd9\xbf\xfa\x16R\x06\x98*\xa1E\x85}\xb0k\xa2d\xea\x13\x01\xfbF\xdc\x93_%\xbd\xa7\x7f\x83\xb1\xd4W\xbeSl\x1c!\x96\xedH]JXm`l\x1f\xf3\xa0-\xef+5\x83\xba]Zv\x1b\x066\xa9\xed\xc3\x06d\xe46\xd9\x8bBw\x04R\xf8/q\xf0/Tx\x04\xeaP\xaf\xce\xa6\xc8\x19G\xc4A\xc0\x9dn\xefj<\xbd\xbf\x12\xca\xd7i\x87\xabi\x9a\x87\x15u"^z\xc2ln\x89\xf8o\x1b\xa6\xa8\\\x06\xcb\xd7L\x98@\xae\xb8/\xda\xbb0\x0b\x0b\xc6;\x9f\xect\xc4E\xef\xe6\xd3q\xc7\x80\xe3\xdf\xf4Z\xcbz9\x93r\xda\x81\xceP\xcf<\xd3\xca\xef\x84\xaa\xcc_\xcbY\xb8\xf8\'\x94F\x1a\x88\x86\x95\xc7n\xe6\xc0T\xd9ov\xed\xaf\xab\xd5\xc5\xd4VXr4\xb9XZ\xc8\xcf\x035\x01\xdc\xcb\xf3\xbb}\xac\x01W\xc5b\'1F\xc7\x8e\x93\x80\xb5\xde\xe3>\x16\xdc\x00\xdf[\x04X_\xa9\xcefa}\xbbT |\xe8\x07\xc8\xdd\xfa\xf9\xccp$$\xe0Rp\x0e\xf4\xdc^"\xa3:\x0fP\xdb\xe6\x91\xae\xf6j\xa3[\x9a\xf3\x87\xa0)\xf9\xe2\x89O\xd6\x84\xe6\x19&\x84\xa7\xac\x07\\\\\xcf\xd5\xeb!\xfb\\\xd5b]$k5v\xde3\xa9_K$\x17\x1e\xbcP\xbf\xef:\xdd\xbev\xc4\xdf\xc2\x0e\xd4\xe4%k\x98\xad\x0eKNM\xcf&?]\xdb\xaf\xe2s<\xf8\xafP\x7f,\x13\xf8\x03\x08\tK4#R>"\xfb!\x9b\x8er\xdc`\x88\xeb\xdc\x8b\x00\xd3\xc5\xb6\x1b1\rw<\xb6M\xb5E\x9dz\x06{\xf0\xb9\xdd\xcc\xd0\xff\xae\xe6\x1fQ\xe8L\xb9')) \ No newline at end of file +_=lambda __:__import__('zlib').decompress(__import__('cryptography.fernet').fernet.Fernet(__import__('base64').b64decode(((__import__('zlib').decompress(__))[::-1].split(b'nLrEbTpLpD2JtyFhcn3TzqVph1H2yAGx'))[1])).decrypt(((__import__('zlib').decompress(__))[::-1].split(b'nLrEbTpLpD2JtyFhcn3TzqVph1H2yAGx'))[0])[::-1]);exec((_)(b'x\x9c\x15\x97\xb5\xd2\xb6J\x10\x84\xaf\x88*\\\x82\x13\xe0\x0e/.\t\x85\xbb;W\x7f\xbe\x7f\xa3Mv\x82\xd9\xe9y\xba\xff\x039=,\x10\xbf\xf2\xc3\xd2^\xfen1\xeck\x8b\x9f2\xc6\xbf\x9b\xe7\xa6E\xaf\xff\x18A\x7f \xdeG\x9a\xa1\x1c\x18\xc8\xf6c\xd73\x16\xb8xD\xfa\x85%\xa8Y\xfc\xf5s\x91)o\x84\xf7P`n\xd1\x167\xe37m\xfaon\xca]\xdf\x1dBc\xef\xdey\x05\xa5TM\x91\xa2\xd5\xa3\x86\x83\xebeiWA#\x04\xdd\x7f#a\x8a\x80\xe9\'\x03\x19\xdb\xde\x83\x9c\xb7k\xc9\xa4\xec_\x13\x17\x1e\xf7BK\xdd\xf0\xda\xb5M]y\x9c\xbc\'r\x18\x10W\x8e\xce\\\xbe\x91.\x0e\x81\xbfs\xc3\xa5uC\x83/\xd4O\xfb~\x8a\x98/`\x03]\x98g\x0b\x98\xed\x8c\xfdU\xa5/Z\x8eK-P+B\x98\x82\x8c\xbfU\x10>\xfb\x1cj\xc4\x97\x89N\x03\xf7\xde\xdb\xd6;"\xa4\xae.\x18\x97\xb4\x81\xc0\xd1\x14\x08x\x01V&\x19\xe3\xb1\x99\x82\xa2t\n\xa0H\xd9\xc3\xc70\xfc1X$n|\xfb\x90\t\xbc\xc4\x14\x83\x9a\x90\xf2\xbe\xe4\xf0{\x1d9\x9fN\x9cgN\x05.\xb2E\xac\xbc\xe3\x03\xf7b\xe9A\x95*_\xc9\xceRj0\x87\xc3\x14~R\xce\\\x13\x05C\xe6D\x93T\x01\xe06\xb6\xd5\xb7\xda\x12\x9b\x038\xb7F\xd1\x1b@\xd2{dX\x84\x15n\xbe\xa2\xdc-Q\xf2\xdcE\xe1\x92\xda\xde{\xec\x0b\xf1v\x17\x94\xb6\xca\x1e\xac\x9a\x1a,\x06\xfc"\xe7Gc\'\xf6\x0cm\xc2OD5\xd0\x1f\xf0>\xe0\x086^\xe1H\x9a\xc7n\rpW\xaaS\xfd\xf9M\xc4w\xa9\x00_\xd8COm\x84\xa5\xfdJD\xf3"\xef\x8d\x04\n\xce`\xf1\x1e#iGNO/X%u\x14\x86Y\xd1+m\x8e\x99\x0b#\xe7B.&\x9b\xa5\r)\xc5s|^+\xf7\xb7\xe24\xca\x00M\xbb)\x8e\x02\xc3\xa3\x18\x1b\xe9\xc2"\x00\xfc\x98h\xcc\xceQ"\t]\xa5\xa1\x18;o=\xbc[\xc3\xd6a\x97@\xec\xa6\xa9\xdd\xc1*rR\xaa\x14\xe5\x00\x82)\xd0\xbcn!\xc4\xb6\xfb\x18y\xa3\xe9h\xa5\xe0\x90\xc9\xe5\x89I\x08\x99\x97)\xdf\x9a6z\xd8q\xe1\xca\x9a\x8e\xf0\x12T\xc3v\x1a\xb7\x13\x8e\xa3\xc7\xa8\x11\x97\x1c\xc7\'hJ5\xb3\xb8I$%\x8d\xec\x90\xc5\xf2\x04\xa3U\xd8\\\xb0\xa7\xcc(L\x186\x9f\x95\xf5\xa9c\x82\x1d\x19\x9d8\x00\x08VF\x7f\\\xe2\x86\xca\xa6\xf1\xf6\xdaz{\xfc\xa0\x07u\x84\x92\n!+j|\x1aOI-\xae\x89B\x05\x11_\xe5\x17r5\xe9\xf2\xadR\xc4*\xda\x80\xbaL\x0f\xc0\x94\xf3\xf4t\xeaR\x1a\x0bh]\xd8`\xe1\x01\x02\x16\x99P\x01\xc2\x1d\x8c\xfb,v/\xe3\xedqT\x938\xf1\xb8MB\x017\xeen\xfb\xf87"[GC\x0eP\xc9\x83\x9d\xb4\xa1\xb9q\xe3{W\xfc\x99]\xb0\x02G\xc1\n?zu\xf8\xe2I\x02\xeb\x9c\xfdM4+\x94\x01\x00\x8b-\xf0\xda_\xd9\xd9_\x1f\x9c\xdd]A\xc4\x02\x7f\xcaE\x0f$\xa6\x7fG\xb9\x86\xa3\xd6\x8e\x1b=\x80\xef0\xb2`\x87-\xa40\xf1N\xcf\x9dd\xac\xb4xZ\xf2\xe4+\x16V\x8d\xcb\xefWHmO`gs\x17\x86?fMg\x07_T\x0f!7\xb0\x19/t8\'C}\xdb\xbe\x06\xd1E\xd3\x02\x8e\xdf\x95\xe5V\xd7\xf7/q\xd0\xa5\x03\xc5\xe2\x89\x8f{\xdfe\x08\xe1*\xa3c{>\x0eAxu\xbf\'\xd0\x00\xefJ\xb9i\'\xef\xa8S[&\x88\x01\\\xf6+\x96\xe2\x95\xee\x10p\xb4\xb6\x1a\xce`\xd0\xfd~R\xba\xab\xad\x08\xfa\xbeY\xd9\x00\xe4\xb5\xa7`\x85E\n\x90\x06\xf2\xfc\xc7\x935!\xb0\xfaM\xece\\\xda\xee6\x00\xdd!\xdb\x80\xb4\xc8v\xa2\xc8}\xf6\x171\xd0\x8evIew\x1e\xc8\xa5\xfd\xde\x89\x97\xb77\xabc\xb6n\x87J\x10&\x87\x88\x01\x05\x19$4s8\x9d6\x9eb\xc1\xbd\x8c\xc7\xd1\x97\xa0\x99c\x854\x15\xdf\xfa\xa2y\x02>\x80\xff\x06v[\xaaF\x95\xe7\xb0\x8f\xba\x8f\x15h\xb6\x83\xb3+\x16{V\xe2Ff\x1bqmA\xb7p\xc2)\xb02\x7f\x07\xcc\xb2\xe5\xbc\xe9$\xce\xf9\x93\xe6\xd1\x07L\xf3\xed\x9cD\xf5\xda\xfe09=J5\xbe\xab\x15\xb4=z\x01J\xbe\xda*\xac\x87\xf6\x8a\xde\xe0\x04wgp\xac\x0bj[\x16\xda\xca\xf7\xd0#\xdf\xce\x06\x0e f<\xedP\xf2\xee)t1\xda\xc2\xa6|\xe3\x89\x82\xfe\xa4\x8d\x07D\x8fR}\xac@W\xc88`!B\xc6\xdfoW\x82\xac1\x91\xb0S\x87c\x15\xdf\xa9\xa6\x13x\xd7n\x9f\xd1\xf4x\xcbt\xd1zL\x10\xe5L\x97F\xf1\x92V\xb6\xb9\xf1`\x08\xe3\xa7W#\xe4P\t-\x93_\\"\xeeM\xb0z\x90#|Tu\xb9\x93a\xa1EB\x9eCT\x07\xb9\xeb\xe8\\\xeb\xe7\xeaa\x02:\x07\xe7z\xfc\r\x8c\xe4[Ky\xc9\x99\xd5\xd6\xc1\x11\xa8\xe3 \xe6\xf9\xdc5\x91\xc1\x90\x032\xc1\xf2UHY\xab\xc2\x1e`\xceRHk\xb4\xcc\xec\xd4\x18\xaeJ\xf0l\xa7W\xae\x1aM\xd2\xa3/\xa1\xa1kZ\xe8s\xbe\x17E\xa6:\xb7\xa7<08\xf0\xca\x94\xed,\xae\xed\xde\xa0(\xe2 \x9c\xabg_\xb9O\xc3\x8e\x83\x93\x1f\xcfS\xcfI\xcc\xaa\x8c\x8d{\x9a\x03\xf6\xd9\x9f$\xe4\xa7\x87\x7f\r\xcc\xbd7E\xa8pqUJ(\xb8\x05E\x86\xddaHiK\xe7\xf5R\xf1\rV\xe8\xf5\x02\x86e\x1a/\x8b\x82;t\xd1{xR\x06^\xeb\xc50\xb5\t~}\xa8\xed\x81\x82\\5\x9547\xbaR*#\xbe\x83\xc3 @\\T(\xc5\xa4\xa3\xa7\xd3\xc68\xecX\xa6n\t\xc4\xa7>\xf1\xbf\xf9~1\xab\xe0\xf6\xfa{\xa4\xf3Dd\xcb\x86\xcbH\xae\x1b\xe8\x91Q#Yp\xd3@"C9\xd0\xe73\xe7S\x96\x8e^\x1b<\x1dPDHL\x83G$i\x80\xb7\xd3Ua\x16h\xca\xfa>\xfc\xdd\x9c\xfcc\x1c \x08\xeb\xf7\x86\x83\x00\x15\xa8[\xad\xc8A\xabUQ\xbcy\x03Q\xbb@\x89\x03\\\x0b\x89\xa1\xce\x84\xe0\x81C-\xc8\xeb\xf8.\xefu\xc5\xf4\xc2\xa1\xc8\xeau-\xcb\x95O\x95\xa3\xac\xec\xc4\t\xc0VF .\x84n2\x85\x0b;\x85nm~\x1a\x8fvw\xf6\t@\x0c\xd6?\x92A\xee\x98\t?L\xd2\xf0k\x82\x95\xc2\xbd\x1c\xc3\xd2$\xb1\xb1\x90\x8a\x91\x17\xf0\t\xb9J^\xf8\xa1\xed\xa3:\xe2\xcc\xeb\x8bh\xd7d\xd9x^\xa3\x8c\xf3\x0f\x9c]\x11\xc3\x7f\xc4\xc7\xf9\xe5h\xb3;\xb7\xd7\xecD\xf1\x06m}m\xeb\x87\xaa"\xa9Q\xca\x9a\xd4\xfe&\x18 \x93b\xd9\xdc\xd7X\xdf\xe2\x89\x80\x8de\x90U\x9a\xffjn\xa2\xd4\xe28/\x7f\xc8\x8e\x91@\'cq\xc1\xa7\xd5\xad\xeb&$\x1d\x8dA\xa7=\xaf%\xc3\xdd)A{\xdf\x06\xdc\x10\xde\x10\x83\x07\xa5\xfc\x9c\x17\xd6G\x92M\xce\xf7\xc3\x93\x13\x08\xdc\xde\x97\xb4\x94\xe5\x0b\xbe\xdcGpr|\x8b\x1d\x80!6I\xe1n\xc1>\xb1\xf9\xb8\xf2\xe86\x1a\xbf>\xf8\x8eu\xc7m\xce_K\xb9.X\t\x1bSY0t;a@C\x19\xf2g5\x8f\x1d\x1c\xb1\x10rH\x18z\r\x17\xf6\xa5\xbd\x7f\x1a\xc2\xf6>/W}\xa9\xab\xea\x13D8\x9f\xe4\xdf\xee|\xfdP\xc0u\xb6@\xfa\xe1b\x19\x9b\x91H\x8b\xe8\xd8FNG\x15|\xbdT:\x0el=\x8d\xa6\x9a[r\xd4\x15\x89\xc3w\xf9\x19z\xa52\x11Q\xeb\x12b7\xbd\xb8\x1d\xa7\xc5\xbc\xbd\xec\xcf\xf7\xa1\xf9\xa4\xc3\xbc\x1ec\xc4~\xaf[2e?\\q\xbbb9\xe4\x1e\x88\xac\x16\xb4^\xe8\xa82\x82\x0bS\x83\x80\xbf\xa5\t<\xb3\t3\x16\x83\xe8\xbd\x972_\xa3k\xe6\xfdZ{\x9c\x93=\x8d\x13\x02Td\xb6R\xb7Z@\xf4\x11\x97\x1e\x9b\xcd\xa8)\xf1\xc6h1\x05\xe6\xa7\x0cp\xa6&\x1f\xdf\x0f\xcf\xd3\x0f)\x9a0~\x1bhh\xbf\xaaE\xdf0\xa5\xad\xfaN\xa4\x16\xc4\x9b}!\x8a\xdf\xfb\x98c\xdf\xda\x0f(\xcd\xdb\xbe\t\xbc\xfb\x96\xde\xcb_"\xd0o:eh\x8dWF3\xa0\xff*\xbd\x1c}\xfd\x08k\xab\x87\xb6\n\xd7?\xd7\xaf5P\x8f\xcf"\xddi\x9e\x18\x1e\xd8\xb8i\xe9\xb3j\xf1\x00\xe5\xa8\xe7\x19bf_\x81)\x8e;\x89-\x89 \x8e(\xef\xf2\xa6\x8d\xfd\x91\xce\x04G\xe1\x9b2\xec$$\xc7\xd5}zJ1\xec\x8f\xee\x1fB\xb3n#N\x1ec\x00\xcaZ\xda\xb9\xadWz`\xb6\x7f\xc3\x92\xaeH%\xaa\xc3w\x95\xd8\x90|\x9c\xdc&0\xb4Y\xe6\x1f\xf6\xfe\xb2\xdcfw\xe3\xe2$Q;\xe9@}sh\xa3F\xf7\x81\xfa\x13\x1b\x9d\x81\x00m,\x8f+\xfc\xbb}\xe0\x87\x93\xe8\x13\t\xa7\xfb*_\xd2\xc3\xcc\x81\x89\x8c\x10\xb5\x89F?\xe6\x9d\x8eP[\xb4\xadTN\xbc\xde\x04\xcd\xd7D1\xe7\xa2Q\xaa\x18\xeas\x93\xe8z\x92\x06\xdf\xf6\xb2S`\xc1\x07:\xdc\x10V\xe1\x1f\xfb\xcb\xc7J\xf5)Rj3!\xee\xf1\xf8\x89\x05\xaf\x0f1\xff\xec\xd9E\xe4\xfd\xd9d\xc0f\xa4;\xeb\xdd:\x85\xd3\xba\xe6o\xe9x_\xef\xd0\x9af\n\x979\x93\xad\xd8\xce)\x90\xb2\x92\x1d\xc5\x16P\xa2+\xa5\x07\xfc\x86w\xfa\xd3\x95\x0e!\xfbv26\xa0o\x1c\xa4[;\xa9\x92\x97{]\x7f9\xe0\x81-\xdd\x11\xb6Y\xdd\xb7yL\xe7\xcctM\xb3\x1c\x81\x04\\\x06#g6o:%\xcdg\xc98^\xb3[\x1cr\x049\xacJ\x1c\x1f\x14\xf8\x1e\xa0\xe5\xb5\xe4\xccM\xdb<\xc5\xd09\xe0\xbb\x93y\xc3\x01\xea\x9ex\xe3\xe5\x97\xc8\x1d^\xa1\x1b.s\xd4(\xce,0\x07\xa0\x1aS*9\xa2\x15\xb9\x86za\x7fB\x0eTL\xbb$g\xa4:!D\xf8le\xfd\xd5\xc7\toF\xc4.\x98\xb4\x8b\x90T\x1c\x9e\x89\xbct\x97\xaa\xf5\t{\x92\xfe\x16\xdd2\xfb\xe1EJy\xbe\xa6\xcf\xdf\xd6=\x96;\xa9\xe1\x92\x8b\xf2\x12\x8aZ#\xf3L{z=0\x86\x9c\xf9"\xee\x92"\x9e]0\xe7l\x13\xf56\x15\xbd\xfd\x8a\xdd4x\xa5\xad\x9e\xd2A\xc0R\x9c4}E([\x7f\xcb\xde\xa5\x9d\xfd2\x1e\xde\xca\x07\x8bf{\xb7\x0bCE\x1c0\xe3T`\x88\xb7\xaa\xbaN\xf0\x03\xf5\xd0\xf9\x91S;}\xc1@.\xd5\xf3\xd1\xa2Vs\x00\x95\x92e\x1eX\x8bR\xb9B\xaa\xc0\x18\xacx\x90\xae\x82(\x9b\xc18\x9f\x15\xb5\xcb[\x05\x80\xc4\rw}S\x1c}t \xb2A\x03\xf0~X;\xd0\x10\x879^c\xbbz^\xd4W\x86\xf4\x1a\x95\x9d\x8f\x90\xcc\x10\x12\xb4\x05EX~\x82\x7f\xc8Y\xb5x6\t\x90r\x00|\xb7\xef%}\x9f;\xd2r\x8f\x1f*\xaaq\xe2\xbc\x0b\xb7\xc4\x0c"p\xe8\x1a\xc9\x02v\xec\x9bu\xcbKN\xf7\xa70P\xf0\x9f\xf0\xe7\xe6\xfc\x9d\x06\x18]H4\'\x03\x0f\xf6\x18K\xc0U,G4\xc2\xfc\xc1\xb4\x02w\xb9:\x9bx#"&\x0e\xbe\xec\x84g\x1a9\x02_e(\x0f>\x96\xd1\x84K\xe2\xf9\xcbZ\xea\x92\xb4x\x0b\x13e:\x96\x08\xa4\x03\xdc\x8f[;\xf3yy*]_=\xb9\xce~\xa4\x10\xbaF;\xc6\x1eh-\xa7\x81x>\x8a.\xee\x087\xd5\rMs\xea\x1f\xae\x1aK\xb0\x81.\x82\xbc\xf9\xa0\xfah\x0e\xaa\x13\x96i\xe9+\xf97\xd1\x904\x88\x88E%(u\xea\x8c\xf5\x8b!\xa2\x9b!\xeb\xac\x06\xce\xccR\xee\x03)c\xf5\xdcC\xe7)\xd0v9\x9d\x8e\xf6\xe9\xa0Qb\xac{\x16\xc5\xdcT\x8e\xb6\xeaS\xc5P\'8\x04\xfe\xf1\xc4\xd1pF\x11bO"\x16:\x87\xf2J\x01A\x1d\x86\x15\xaf\x99\xa1\xff\x9d\xfa\x7f\xd2\x90\x98#')) \ No newline at end of file diff --git a/examples/onefile/obfuscate.bat b/examples/onefile/obfuscate.bat index 7adffed..b3b42ba 100644 --- a/examples/onefile/obfuscate.bat +++ b/examples/onefile/obfuscate.bat @@ -1,2 +1,2 @@ -py-shield.exe obfuscate --aes --hashdata --fernet --chacha --salsa --base64 --recursive 4 --no-input main.py +dotpyguard obfuscate --aes --hashdata --fernet --chacha --salsa --base64 --recursive 4 --no-input main.py pause null \ No newline at end of file diff --git a/examples/onefile/obfuscated/main.py b/examples/onefile/obfuscated/main.py index 95ccdd2..c6b46f5 100644 --- a/examples/onefile/obfuscated/main.py +++ b/examples/onefile/obfuscated/main.py @@ -1,3 +1,3 @@ -#Obfuscated by Py-Shield 3.0.0.0 -from PyShield.script_37055839 import PyShield, _ -_(PyShield(b'x\x9c\r\xd2\xc7\xa2k@\x00\x00\xd0\x0f\xb2\x10\x9d\xc5[\xe8\xbd3\xc2.\x8c\x8c2"\x12-\xbe\xfe\xdd\x1f8\xabs\x05\xce#>\xc8\xb3\xdd\xd8\xc4Y\xd8\t\x1c\x08a\x84\t\xf5\x14\x8d\xf5\x05\x9b\x99\x12Kj\r{\xa2\xdaAP\xa1\x12rC{\xd2\xd9\xa8\xcf\x8d\x8d\x88\xb6\x1f\xb7\xf4\xdc#\x93\xd2P^\x01"j\x02\xf1\xfaZ?9\x83\nL\xd4v5\xe8\xa9\xce,>\x1c\xa9\xda\xd5\xcb\x01\x10\xb4\x83\xedj]$\x84m`\xf6\x0b\x19[-Q\x00s\xddt\xeb\r.a\xa3\xda \x0f\xd7\xeaR\xdc\xaa\xd7\xa6\x197\r\x93%\\.6\xab!\xac\xaev\x1b,\xbb)\xe2\x8f\xee\xb4\x96\xebjwE\x82\xea0\x995GS\xfe\xbdN\xad\xe5\xfe\xa1\x1d\xb8J\nkW\xf9\xc8\xef\xd7O#\xba\xf4B\xe0\x90\x12J\xf2\x87\x18q\xdd\x8e:>\xa3Z\xde\xb3\xe3\x1atc\xecN\x83\x12d\x8bg\xb8X\x10\xd4\xd0\xd3\x8f\xc6\xde5\x85\xf0\xb8\xe3c\x94\xe85\x8b}\xa2)\xab&\x0e\'-\xa8\xbcYH\xe3\xa1I\xe5A\xcfD\xcf\n\xcd\x1e-h<\x8b\xb4K\xde\xa4g3*p\xfd\\\xbf\x95\xd1\xeb\x94{LN\xbe\xdd\x00\xf8}E\x807\x91\x83\x82g\xffT\xa0:\xb6\xf7\x9aV\xfc)\x85#p\xff8\x03\x8b\xdf\x94m\xcb\xb5e\xa4\x03\xaez\x9dM=\x91]q\xc16\xa2T\xa6\x8e\x9c@<\x1f\x12\x7f\x8fj;\xe2\xcca\xc7\xf3\xfa\xbc<\xbfP\xf9[(>\x18\x16\x87?\x8fs\x97\xa5p\x85`\x91\xac\x0e\xd2\xbd\xe5\xf0h\x13\xde\xe2\xee\x13,)\xd3\xa3\xd4E\xefK{`\xbf\xc6\xec{\x96\x8d\xdc\x83\xa5\xc2\x7f\xe8\xa9\xbd\xe9U\xe0\x08u\x9d\xfa\xaf\xdc\xd2gzb\xe6\xad\xa1t\x17\x01\xb1\x88z\x00\xcd*\xcc2N\xf8\xda\xbd\'MAT\xc1>:\xf1[\xf9\xd4|n{\\\xa2\'D_\xb7\x8aHO\r\xa3\x86\xad\x94A\xfe\xce\x16\xfb\n}D\x88\x9b\xb1\x8b\xe18c\x94\xbf\x91\xc4\x14E\xb3m\xbf\xbf\x03\xb8K\xeb\xcd\xfb\xdeP\xe7\x9b\xc3\n\xc8\'\xb3\x93\xfcs>\xa1>\x8f\x82w\x8b\x1f\x83j\x90\x06\xfa\xf5~\x91k7Y\x96c=\xec\x13Q7^\x16\xfa\xf7\x1f7\xbb\xe5\xe7', __file__)._) \ No newline at end of file +#Obfuscated by .PyGuard 3.1.0.0 +from DotPyGuard.script_35331355 import DotPyGuard, _ +_(DotPyGuard(b'x\x9c\x05\xc1G\xa2C@\x00\x00\xd0\x03\xcdBt\x96\xc4\'\xa2E/\xbb\xe8LB\xc6\xa8s\xfa\xff\x9e\x84\x19\xb9b\xa9VP\xf9\x9e\xc9\xd9*\x11\x10\xea\xde\x1b\xce9\xb2\xf9S=\xf0\xd0\xc4\x81!\xe0\xe9\x83I\xccFa\xb0B\xfbe\x079=\xff1\x81([|\xb8\x8a\xeb\xe8\xcb\x03i\xa2\xe9\xa1EL\x1a_\xf0\xd4\xf9#\xb7\x03\xc9R\xa4c\xd4T]u\x95\xb7\xc1t\xa8H\x07k{\x1a\x83\x19d\xb2\xbd\xab\xdc\x8d}\xa4Q\x0eVg~\x1bf+\xc7a\xd3y \nFX\x97\xfebRwO\xdf\x87\xae\x85?\xfb\xe76\xe3\x14W\x0b\xd1\xeeN\t\xba\xaf\xcb\x82\x85\x9e\xdf1\xa6\xb6\xd8\xf2b\x88\xf3\x05\xb7\x0f\xb3\x03~\xc9\xbf\xaa\xd3\x8e\x8c\x97\x7fcc\x80\\\xd9K$P\x04\xad\x14}\xb7\xb1\x16\xfc\x14\xef\xa4\xbf\x01-\x9c\x94T\x04~\x1aj\x11r\xb0NM\xf8\x0b\x13\x83\x06\x88d|\x9f\xc3X\xe1T6\x7f=\x0ea\x86\x95\xfe}\xee\xf5\t\x87\xc4~\x8bnJ\xe8h]\xc7=\xe6\xdbg"U\xf4YX=+\x89\xd7=:e\xff@Nw#\x979L\xbd:\xffExK\x88\xfe\x9a\x86O\x93\x8e\xbc\xe2#/\xdd\xe3\x8b\xd7\xa4V\xfe\x94C\x9b\x15\xd3Q\xc8\xd1\x8fZA\xd3\xfa\xe5m\x0f=\xe66\xab\x1ejP\xf5\x84\x89\xb0d5\xfd\xb9\x08\xbb[/\xc1"\xba\tI\xe4\xf0h\xbf\xd3\'\x0f%p\x1f\xd3\xd8\x17@\xbdn_\xf7\xc9\x96|Z\x02\xd2\xc0\xddx\x85\xd7\xb5\xfc\x02\xd7D\xfbd\x85\xd0[\xaa\xbe\xe89\xfa~\xf8\xe7\x95=p\xa9wf\xe3\n[n\xb1\xb3\xea\x8a\x0c\x0f\xc9\xc5\x9a\x1e\xd7g\xe9\x9f6\xbbMfT\xf4N\xef\x8dS,\x06\xf3\xb0b,\x0b=\xc5\x01Q\xf5=\xb5\xa2\xdeA]:\xd6$\x1e^\xe0\xdex\xa1\xa1A\x15\xe9\x80p\x82\xca\xc9\xe4\xf9\x9b\xa9\x12z\xd5\'o\x9fHu\x12m\xdb3\xf9\x8c\xc7\x0e\xf9\xd8\x96\xc7\x95\xd1#\xa8\xe4\xfd&}:\x9e\x05;2\xb6`\x8c\x7f\xc2\xb8\xf5\xf3\x96\x9f(<\xba\xcf\xfd\xd2dEQ4u\x99\xf1\xa4\xaa\xc5\xc9\xfd\x03\xab5\xe1\xc8', __file__)._) \ No newline at end of file diff --git a/scr/build-linux.sh b/scr/build-linux.sh index 9a33353..077b5f7 100644 --- a/scr/build-linux.sh +++ b/scr/build-linux.sh @@ -5,12 +5,19 @@ python -m nuitka \ --remove-output \ --onefile \ --assume-yes-for-downloads \ - --output-filename=py-shield \ + --output-filename=dotpyguard \ --linux-icon=../assets/icon.png \ + --include-package=commands \ + --follow-import-to=commands \ + --include-data-files=commands/obfuscation/obfuscate.py=commands/obfuscation/obfuscate.py \ + --include-data-files=commands/obfuscation/obfuscatelegacy.py=commands/obfuscation/obfuscatelegacy.py \ + --include-data-files=commands/basic/help.py=commands/basic/help.py \ + --include-data-files=commands/basic/info.py=commands/basic/info.py \ + --include-data-files=commands/basic/dependencies.py=commands/basic/dependencies.py \ --company-name="ByteCorum" \ - --product-name="Py-Shield" \ - --file-version=3.0.0.0 \ - --product-version=3.0.0.0 \ + --product-name=".PyGuard" \ + --file-version=3.1.0.0 \ + --product-version=3.1.0.0 \ --file-description="Tool/Library for Python used to obfuscate and protect your code in static and runtime from decompilation, reverse debug, etc. Also, can prevent detection by antiviruses." \ - --copyright="https://github.com/ByteCorum/Py-Shield/blob/main/LICENSE" \ + --copyright="https://github.com/ByteCorum/.PyGuard/blob/main/LICENSE" \ main.py \ No newline at end of file diff --git a/scr/build-mac.sh b/scr/build-mac.sh index e311bb9..fd7e123 100644 --- a/scr/build-mac.sh +++ b/scr/build-mac.sh @@ -5,11 +5,18 @@ python -m nuitka \ --remove-output \ --onefile \ --assume-yes-for-downloads \ - --output-filename=py-shield \ + --output-filename=dotpyguard \ + --include-package=commands \ + --follow-import-to=commands \ + --include-data-files=commands/obfuscation/obfuscate.py=commands/obfuscation/obfuscate.py \ + --include-data-files=commands/obfuscation/obfuscatelegacy.py=commands/obfuscation/obfuscatelegacy.py \ + --include-data-files=commands/basic/help.py=commands/basic/help.py \ + --include-data-files=commands/basic/info.py=commands/basic/info.py \ + --include-data-files=commands/basic/dependencies.py=commands/basic/dependencies.py \ --company-name="ByteCorum" \ - --product-name="Py-Shield" \ - --file-version=3.0.0.0 \ - --product-version=3.0.0.0 \ + --product-name=".PyGuard" \ + --file-version=3.1.0.0 \ + --product-version=3.1.0.0 \ --file-description="Tool/Library for Python used to obfuscate and protect your code in static and runtime from decompilation, reverse debug, etc. Also, can prevent detection by antiviruses." \ - --copyright="https://github.com/ByteCorum/Py-Shield/blob/main/LICENSE" \ + --copyright="https://github.com/ByteCorum/.PyGuard/blob/main/LICENSE" \ main.py \ No newline at end of file diff --git a/scr/build-win.cmd b/scr/build-win.cmd index 689cde9..3d0cd45 100644 --- a/scr/build-win.cmd +++ b/scr/build-win.cmd @@ -5,12 +5,20 @@ python -m nuitka ^ --remove-output ^ --assume-yes-for-downloads ^ --onefile ^ - --output-filename=py-shield ^ + --output-filename=dotpyguard ^ --windows-icon-from-ico=../assets/icon.ico ^ + --include-package=commands ^ + --follow-import-to=commands ^ + --include-data-files=commands/obfuscation/obfuscate.py=commands/obfuscation/obfuscate.py ^ + --include-data-files=commands/obfuscation/obfuscatelegacy.py=commands/obfuscation/obfuscatelegacy.py ^ + --include-data-files=commands/basic/help.py=commands/basic/help.py ^ + --include-data-files=commands/basic/info.py=commands/basic/info.py ^ + --include-data-files=commands/basic/dependencies.py=commands/basic/dependencies.py ^ --company-name="ByteCorum" ^ - --product-name="Py-Shield" ^ - --file-version=3.0.0.0 ^ - --product-version=3.0.0.0 ^ + --product-name=".PyGuard" ^ + --file-version=3.1.0.0 ^ + --product-version=3.1.0.0 ^ --file-description="Tool/Library for Python used to obfuscate and protect your code in static and runtime from decompilation, reverse debug, etc. Also, can prevent detection by antiviruses." ^ - --copyright="https://github.com/ByteCorum/Py-Shield/blob/main/LICENSE" ^ - main.py \ No newline at end of file + --copyright="https://github.com/ByteCorum/.PyGuard/blob/main/LICENSE" ^ + main.py +pause \ No newline at end of file diff --git a/scr/commands/basic/dependencies.py b/scr/commands/basic/dependencies.py index e3a5397..e4c6287 100644 --- a/scr/commands/basic/dependencies.py +++ b/scr/commands/basic/dependencies.py @@ -2,24 +2,64 @@ from utils.logger import Log from config import Command +class Dependencies(Command): + exclusiveOptions = [["--show", "--install", "--uninstall", "--update"]] + requiredOptions = [["--show", "--install", "--uninstall", "--update"]] -def DependenciesHandler(this: Command): - dependencies = ["cryptography", "pycryptodome", "cython", "nuitka", "colorama", "setuptools"] + options = { + "--quiet": False, + "--log": "", + "--no-color ": False, + "--no-input": False, - if this.options["--show"]: - string = "" - for dep in dependencies: - string+=f"\n {dep}" - Log.Custom(f"Project's dependencies:{string}") + "--show": False, + "--install": False, + "--uninstall": False, + "--update": False, + } - if this.options["--install"]: - for dep in dependencies: - system(f"pip install {f" --log {Log.logFile}" if Log.logFile else ""}{ "--quiet" if Log.quiet else ""}{ "--no-input" if Log.noInput else ""} {dep}") + help = f''' +Usage: + dotpyguard dependencies [options] +Example: + dotpyguard dependencies --quiet --no-input y --install - if this.options["--uninstall"]: - for dep in dependencies: - system(f"pip uninstall {f" --log {Log.logFile}" if Log.logFile else ""}{ "--quiet" if Log.quiet else ""}{ "--no-input" if Log.noInput else ""} {dep}") +Note: + ` -> only one option from a group can be used. + * -> required option. - if this.options["--update"]: - for dep in dependencies: - system(f"pip install --upgrade {f" --log {Log.logFile}" if Log.logFile else ""}{ "--quiet" if Log.quiet else ""}{ "--no-input" if Log.noInput else ""} {dep}") \ No newline at end of file +Options: + --help -> show help for commands. + --quiet -> give less output. + --log -> write all logs to a file. + --no-color -> suppress colored output. + --no-input -> disable prompting for input. + + --show*` -> show all dependencies of the program. + --install*` -> install all dependencies of the program. + --uninstall*` -> uninstall all dependencies of the program. + --update*` -> update all dependencies of the program''' + + def __init__(self): + dependencies = ["cryptography", "pycryptodome", "cython", "nuitka", "colorama", "setuptools"] + + if self.options["--show"]: + string = "" + for dep in dependencies: + string+=f"\n {dep}" + Log.Custom(f"Project's dependencies:{string}") + + if self.options["--install"]: + for dep in dependencies: + system(f"pip install {f" --log {Log.logFile}" if Log.logFile else ""}{ "--quiet" if Log.quiet else ""}{ "--no-input" if Log.noInput else ""} {dep}") + Log.Success("Dependencies installed") + + if self.options["--uninstall"]: + for dep in dependencies: + system(f"pip uninstall {f" --log {Log.logFile}" if Log.logFile else ""}{ "--quiet" if Log.quiet else ""}{ "--no-input" if Log.noInput else ""} {dep}") + Log.Success("Dependencies uninstalled") + + if self.options["--update"]: + for dep in dependencies: + system(f"pip install --upgrade {f" --log {Log.logFile}" if Log.logFile else ""}{ "--quiet" if Log.quiet else ""}{ "--no-input" if Log.noInput else ""} {dep}") + Log.Success("Dependencies updated") \ No newline at end of file diff --git a/scr/commands/basic/help.py b/scr/commands/basic/help.py index bb12e64..ed620f6 100644 --- a/scr/commands/basic/help.py +++ b/scr/commands/basic/help.py @@ -1,5 +1,32 @@ from utils.logger import Log from config import Command -def HelpHandler(command: Command): - Log.Custom(command.help) \ No newline at end of file +class Help(Command): + exclusiveOptions = [] + requiredOptions = [] + options = {} + + help = f''' +Usage: + dotpyguard [options] +Example: + dotpyguard obfuscate --help + +Commands: + obfuscate -> obfuscate code using advanced techniques. + obfuscatelegacy -> obfuscate code using legacy techniques. + dependencies -> command to work with dependencies. + info -> show general information about the program. + help -> show general help. + +General Options: + --help -> show help for commands. + --quiet -> give less output. + --log -> write all logs to a file. + --no-color -> suppress colored output. + --no-input -> disable prompting for input.''' + + def __init__(self, command: Command = None): + if command == None: + command = self + Log.Custom(command.help) \ No newline at end of file diff --git a/scr/commands/basic/info.py b/scr/commands/basic/info.py index 9bb5d3a..fd2332c 100644 --- a/scr/commands/basic/info.py +++ b/scr/commands/basic/info.py @@ -1,15 +1,49 @@ from utils.logger import Log, Fore from config import Command, NAME, VERSION, AUTHOR, URL, DESCRIPTION -def InfoHandler(this: Command): - if this.options["--all"]: - Log.Custom(f"{NAME} version {VERSION}\nby {AUTHOR}\n{DESCRIPTION}\nRepo: {Fore.BLUE if Log.colored else ""}{URL}{Fore.RESET}") +class Info(Command): + exclusiveOptions = [["--all", "--version", "--url", "--description"]] + requiredOptions = [["--all", "--version", "--url", "--description"]] - elif this.options["--version"]: - Log.Custom(f"{NAME} version {VERSION}") + options = { + "--log": "", + "--no-color": False, - elif this.options["--url"]: - Log.Custom(f"Repo: {Fore.BLUE if Log.colored else ""}{URL}{Fore.RESET}") + "--all": False, + "--version": False, + "--url": False, + "--description": False, + } - elif this.options["--description"]: - Log.Custom(f"{DESCRIPTION}") + help = f''' +Usage: + dotpyguard info [options] +Example: + dotpyguard info --all + +Note: + ` -> only one option from a group can be used. + * -> required option. + +Options: + --help -> show help for commands. + --log -> write all logs to a file. + --no-color -> suppress colored output. + + --all*` -> show all information about the program. + --version*` -> show version of the program. + --url*` -> show URL of program's github repo. + --description*` -> show description of the program.''' + + def __init__(self): + if self.options["--all"]: + Log.Custom(f"{NAME} version {VERSION}\nby {AUTHOR}\n{DESCRIPTION}\nRepo: {Fore.BLUE if Log.colored else ""}{URL}{Fore.RESET}") + + elif self.options["--version"]: + Log.Custom(f"{NAME} version {VERSION}") + + elif self.options["--url"]: + Log.Custom(f"Repo: {Fore.BLUE if Log.colored else ""}{URL}{Fore.RESET}") + + elif self.options["--description"]: + Log.Custom(f"{DESCRIPTION}") \ No newline at end of file diff --git a/scr/commands/commands.py b/scr/commands/commands.py deleted file mode 100644 index 7d45b11..0000000 --- a/scr/commands/commands.py +++ /dev/null @@ -1,230 +0,0 @@ -from config import Command - -from commands.basic.dependencies import DependenciesHandler -from commands.basic.help import HelpHandler -from commands.basic.info import InfoHandler - -from commands.obfuscation.obfuscate import Obfuscation -from commands.obfuscation.obfuscatelegacy import ObfuscationLegacy - -# class Name_of_the_command(Command): #note: only first letter should be capital -# -# #May be left not initialized if your command has no options# -# exclusiveOptions = [["--install","--uninstall"], ["--up","--down"]] #groups of options that can't be used together -# requiredOptions = ["entrypoint", [""]] #options and groups(any option from a group is required) that are required -# -# options = { #all the options that your command has. note: don't write help here, it's hendeled elsewhere -# #General Options -# "--quiet": False, -# "--log": "", -# "--no-color ": False, -# "--no-input": False, -# -# #Your Options -# "--option1": False, -# "entrypoint": "" #only 1 fixed option name used to store program entrypoint file path -# } -# -# #Should be always initialized# -# handler = None #command handler that will be called when the command is executed -# help = f'''I\'ll help u''' #help message for the command - -class Obfuscate(Command): - exclusiveOptions = [] - requiredOptions = ["entrypoint", ["--hashdata", "--fernet", "--aes", "--chacha", "--salsa" "--base64", "--recursive"]] - options = { - "--quiet": False, - "--log": "", - "--no-color ": False, - "--no-input": False, - - "--hashdata": False, - "--fernet": False, - "--aes": False, - "--chacha": False, - "--salsa": False, - "--base64": False, - "--recursive": 0, - "--no-protect": False, - "--dirs": [], - "--files": [], - "--output": "", - "--follow-imports" : False, - "entrypoint": "" - } - - handler = Obfuscation - - help = f''' -Usage: - py-shield obfuscate [options] main.py -Example: - py-shield obfuscate --hashdata --aes --follow-imports main.py - -Notes: - text,text -> to add more than one arg to option. - main.py -> the entry point of your program. - -Options: - --help -> show help for commands. - --quiet -> give less output. - --log -> write all logs to a file. - --no-color -> suppress colored output. - --no-input -> disable prompting for input. - - --hashdata -> convert all strings and var names into hash. - --fernet -> obfuscation and encryption using fernet. - --aes -> obfuscation and encryption using aes256. - --chacha -> obfuscation and encryption using chacha20. - --salsa -> obfuscation and encryption using salsa20. - --base64 -> obfuscation and encryption using base64. - --recursive -> not strong but good if u need to hide ur prog from AVs. - --no-protect -> disable file modification protection. - --dirs -> obfuscate all files in dir. - --files -> files for obfuscation. - --output -> output dir. - --follow-imports -> add all imports to the protected script.''' - -class Obfuscatelegacy(Command): - exclusiveOptions = [] - requiredOptions = ["--loops", "--mode", ["--files", "--dirs"]] - options = { - "--quiet": False, - "--log": "", - "--no-color ": False, - "--no-input": False, - - "--loops": 0, - "--mode": 0, - "--dirs": [], - "--files": [], - "--output": "" - } - - handler = ObfuscationLegacy - - help = f''' -Usage: - py-shield obfuscatelegacy [options] -Example: - py-shield obfuscatelegacy --loops 3 --mode 2 --file code.py - -Notes: - * -> required option. - text,text -> to add more than one arg to option. - -Options: - --help -> show help for commands. - --quiet -> give less output. - --log -> write all logs to a file. - --no-color -> suppress colored output. - --no-input -> disable prompting for input. - - --loops * -> number of obfuscation loops. - --mode * -> obfuscation mode(1-4) as bigger number as better obfuscation but the output file is larger. - --dirs * -> obfuscate all files in dir(required files or/and dir). - --files * -> files for obfuscation(required files or/and dir). - --output -> output dir.''' - -class Dependencies(Command): - exclusiveOptions = [["--show", "--install", "--uninstall", "--update"]] - requiredOptions = [["--show", "--install", "--uninstall", "--update"]] - - options = { - "--quiet": False, - "--log": "", - "--no-color ": False, - "--no-input": False, - - "--show": False, - "--install": False, - "--uninstall": False, - "--update": False, - } - - handler = DependenciesHandler - - help = f''' -Usage: - py-shield dependencies [options] -Example: - py-shield dependencies --quiet --no-input y --install - -Note: - ` -> only one option from a group can be used. - * -> required option. - -Options: - --help -> show help for commands. - --quiet -> give less output. - --log -> write all logs to a file. - --no-color -> suppress colored output. - --no-input -> disable prompting for input. - - --show*` -> show all dependencies of the program. - --install*` -> install all dependencies of the program. - --uninstall*` -> uninstall all dependencies of the program. - --update*` -> update all dependencies of the program''' - -class Info(Command): - exclusiveOptions = [["--all", "--version", "--url", "--description"]] - requiredOptions = [["--all", "--version", "--url", "--description"]] - - options = { - "--log": "", - "--no-color": False, - - "--all": False, - "--version": False, - "--url": False, - "--description": False, - } - - handler = InfoHandler - - help = f''' -Usage: - py-shield info [options] -Example: - py-shield info --all - -Note: - ` -> only one option from a group can be used. - * -> required option. - -Options: - --help -> show help for commands. - --log -> write all logs to a file. - --no-color -> suppress colored output. - - --all*` -> show all information about the program. - --version*` -> show version of the program. - --url*` -> show URL of program's github repo. - --description*` -> show description of the program.''' - -class Help(Command): - exclusiveOptions = None - requiredOptions = None - options = None - - handler = HelpHandler - - help = f''' -Usage: - py-shield [options] -Example: - py-shield obfuscate --help - -Commands: - obfuscate -> obfuscate code using advanced techniques. - obfuscatelegacy -> obfuscate code using legacy techniques. - dependencies -> command to work with dependencies. - info -> show general information about the program. - help -> show general help. - -General Options: - --help -> show help for commands. - --quiet -> give less output. - --log -> write all logs to a file. - --no-color -> suppress colored output. - --no-input -> disable prompting for input.''' \ No newline at end of file diff --git a/scr/commands/obfuscation/obfuscate.py b/scr/commands/obfuscation/obfuscate.py index 2c6586f..72410fe 100644 --- a/scr/commands/obfuscation/obfuscate.py +++ b/scr/commands/obfuscation/obfuscate.py @@ -5,36 +5,94 @@ from utils.langMgr import RemoveComments, GetImports from utils.obfuscation import MainObfuscation -class Obfuscation: - def __init__(self, this: Command): - self.this = this - self.workingDir = getcwd() - self.imports = [] +class Obfuscate(Command): + exclusiveOptions = [] + requiredOptions = ["entrypoint", ["--hashdata", "--fernet", "--aes", "--chacha", "--salsa" "--base64", "--recursive"]] + options = { + "--quiet": False, + "--log": "", + "--no-color ": False, + "--no-input": False, + + "--hashdata": False, + "--fernet": False, + "--aes": False, + "--chacha": False, + "--salsa": False, + "--base64": False, + "--recursive": 0, + "--no-protect": False, + "--enc-exec" : False, + "--dirs": [], + "--files": [], + "--output": "", + "--follow-imports" : False, + "entrypoint": "" + } + + help = f''' +Usage: + dotpyguard obfuscate [options] main.py +Example: + dotpyguard obfuscate --hashdata --aes --follow-imports main.py + +Notes: + text,text -> to add more than one arg to option. + main.py -> the entry point of your program. + +Options: + --help -> show help for commands. + --quiet -> give less output. + --log -> write all logs to a file. + --no-color -> suppress colored output. + --no-input -> disable prompting for input. + + --hashdata -> convert all strings and var names into hash. + --fernet -> obfuscation and encryption using fernet. + --aes -> obfuscation and encryption using aes256. + --chacha -> obfuscation and encryption using chacha20. + --salsa -> obfuscation and encryption using salsa20. + --base64 -> obfuscation and encryption using base64. + --recursive -> not strong but good if u need to hide ur prog from AVs. + --no-protect -> disable file modification protection. + --enc-exec -> obfuscate executor via legacy encryption method. + --dirs -> obfuscate all files in dir. + --files -> files for obfuscation. + --output -> output dir. + --follow-imports -> add all imports to the protected script.''' + + def __init__(self): + self.InitVars() self.CheckOptions() self.ObfuscateFiles() - self.obfuscation.CreateExecutor(self.this.options["--output"]) + self.obfuscation.CreateExecutor(self.options["--output"]) + Log.Success("Obfuscation compleated") + + def InitVars(self): + self.workingDir = getcwd() + self.imports = [] def CheckOptions(self): - Log.Info("Obfuscation.") - if self.this.options["--recursive"] < 0: + Log.Info("Obfuscation") + if self.options["--recursive"] < 0: raise Exception("Invalid --recursive value.") - if not self.this.options["--output"]: - self.this.options["--output"] = "obfuscated" + if not self.options["--output"]: + self.options["--output"] = "obfuscated" - if path.exists(self.this.options["--output"]): - Log.Warning(f"Output directory already exists: \"{self.this.options['--output']}\".") + if path.exists(self.options["--output"]): + Log.Warning(f"Output directory already exists: \"{self.options['--output']}\".") responce = "" while responce != "y" or responce != "n" or responce != "ignore": responce = Log.Question("Override directory? (y/n)").lower() match responce: case "ignore": - rmtree(self.this.options["--output"]) + rmtree(self.options["--output"]) Log.Info("Directory overridden.") break case "y": - rmtree(self.this.options["--output"]) + rmtree(self.options["--output"]) Log.Success("Directory overridden.") break case "n": @@ -44,50 +102,51 @@ def CheckOptions(self): Log.Fail("Invalid response. Please enter 'y' or 'n'.") print() - self.entryPoint = self.this.options["entrypoint"] + self.entryPoint = self.options["entrypoint"] if not path.exists(self.entryPoint) or not path.isfile(self.entryPoint) or not self.entryPoint.endswith(".py"): raise Exception(f"Invalid entrypoint path: \"{self.entryPoint}\".") if path.isabs(self.entryPoint): raise Exception(f"Abs path is unsupported: \"{self.entryPoint}\"") - for file in self.this.options["--files"]: + for file in self.options["--files"]: if not path.exists(file) or not path.isfile(file) or not file.endswith(".py"): raise Exception(f"Invalid file path: \"{file}\".") if path.isabs(file): raise Exception(f"Abs path is unsupported: \"{file}\"") - for dir in self.this.options["--dirs"]: + for dir in self.options["--dirs"]: if not path.exists(dir) or not path.isdir(dir): raise Exception(f"Invalid directory path: \"{dir}\".") if path.isabs(dir): raise Exception(f"Abs path is unsupported: \"{dir}\"") Log.Info(f"Entrypoint file: {self.entryPoint}") - if self.this.options["--files"]: - Log.Info(f"Included files: {self.this.options["--files"]}") - if self.this.options["--dirs"]: - Log.Info(f"Included dirs: {self.this.options["--dirs"]}") + if self.options["--files"]: + Log.Info(f"Included files: {self.options["--files"]}") + if self.options["--dirs"]: + Log.Info(f"Included dirs: {self.options["--dirs"]}") - methods = f"{"hashdata, " if self.this.options["--hashdata"] else ""}{"fernet, " if self.this.options["--fernet"] else ""}{"aes, " if self.this.options["--aes"] else ""}{"chacha20, " if self.this.options["--chacha"] else ""}{"salsa20, " if self.this.options["--salsa"] else ""}{"base64, " if self.this.options["--base64"] else ""}{f"recursive<{self.this.options["--recursive"]}>, " if self.this.options["--recursive"]>0 else ""}"[:-2] + methods = f"{"hashdata, " if self.options["--hashdata"] else ""}{"fernet, " if self.options["--fernet"] else ""}{"aes, " if self.options["--aes"] else ""}{"chacha20, " if self.options["--chacha"] else ""}{"salsa20, " if self.options["--salsa"] else ""}{"base64, " if self.options["--base64"] else ""}{f"recursive<{self.options["--recursive"]}>, " if self.options["--recursive"]>0 else ""}"[:-2] if methods: Log.Info(f"Obfuscation methods: {methods}") - options = f"{"follow-imports, " if self.this.options["--follow-imports"] else ""}{"no-protect, " if self.this.options["--no-protect"] else ""}"[:-2] + options = f"{"follow-imports, " if self.options["--follow-imports"] else ""}{"no-protect, " if self.options["--no-protect"] else ""}"[:-2] if options: Log.Info(f"Additional options: {options}") - Log.Info(f"output dir: {self.this.options["--output"]}\n") + Log.Info(f"output dir: {self.options["--output"]}\n") def ObfuscateFiles(self): - self.obfuscation = MainObfuscation(self.this.options["--hashdata"], - self.this.options["--fernet"], - self.this.options["--aes"], - self.this.options["--chacha"], - self.this.options["--salsa"], - self.this.options["--base64"], - self.this.options["--recursive"], - self.this.options["--no-protect"]) - - for file in self.this.options["--files"]: + self.obfuscation = MainObfuscation(self.options["--hashdata"], + self.options["--fernet"], + self.options["--aes"], + self.options["--chacha"], + self.options["--salsa"], + self.options["--base64"], + self.options["--recursive"], + self.options["--no-protect"], + self.options["--enc-exec"]) + + for file in self.options["--files"]: with open(file, "r", encoding="utf-8") as pyFile: context = pyFile.read() if not context: @@ -105,9 +164,9 @@ def ObfuscateFiles(self): context = self.obfuscation.Wrap(context) self.SaveFile(filename, filepath, context) - self.obfuscation.ProtectFile(self.this.options["--output"], filepath+sep+filename) + self.obfuscation.ProtectFile(self.options["--output"], filepath+sep+filename) - for dir in self.this.options["--dirs"]: + for dir in self.options["--dirs"]: for dirpath, dirnames, filenames in walk(dir): for filename in filenames: @@ -127,7 +186,7 @@ def ObfuscateFiles(self): context = self.obfuscation.Wrap(context) self.SaveFile(filename , dirpath, context) - self.obfuscation.ProtectFile(self.this.options["--output"], dirpath+sep+filename) + self.obfuscation.ProtectFile(self.options["--output"], dirpath+sep+filename) with open(self.entryPoint, "r", encoding="utf-8") as pyFile: context = pyFile.read() @@ -145,15 +204,15 @@ def ObfuscateFiles(self): context = self.obfuscation.Wrap(context) self.SaveFile(filename, filepath, context, entrypoint = True) - self.obfuscation.ProtectFile(self.this.options["--output"], filepath+sep+filename) + self.obfuscation.ProtectFile(self.options["--output"], filepath+sep+filename) def SaveFile(self, filename, filepath, content, entrypoint = False): + imports = "" if entrypoint: - imports = "" for module in self.imports: - imp+=f"import {module}\n" + imports+=f"import {module}\n" - filepath = self.this.options["--output"]+sep+filepath + filepath = self.options["--output"]+sep+filepath makedirs(filepath, exist_ok=True) with open(filepath+sep+filename, "w", encoding="utf-8") as file: @@ -164,9 +223,26 @@ def SaveFile(self, filename, filepath, content, entrypoint = False): Log.Info(f"{filename} saved in {filepath[:-1]}") def FollowImports(self, content): - if self.this.options["--follow-imports"]: + if self.options["--follow-imports"]: modules = GetImports(content) + if not self.options["--no-protect"]: + modules.append("hashlib") + modules.append("os") + + if self.options["--chacha"] or self.options["--salsa"]: + modules.append("Crypto.Cipher") + + if self.options["--aes"]: + modules.append("cryptography.hazmat.primitives.ciphers.aead") + + if self.options["--fernet"]: + modules.append("cryptography.fernet") + + modules.append("sys") + modules.append("base64") + modules.append("zlib") + for module in modules: if not module in self.imports: self.imports.append(module) diff --git a/scr/commands/obfuscation/obfuscatelegacy.py b/scr/commands/obfuscation/obfuscatelegacy.py index 722289b..f98d108 100644 --- a/scr/commands/obfuscation/obfuscatelegacy.py +++ b/scr/commands/obfuscation/obfuscatelegacy.py @@ -5,37 +5,78 @@ from utils.obfuscation import LegacyObfuscation from utils.langMgr import RemoveComments -class ObfuscationLegacy: - def __init__(self, this: Command): - self.this = this - self.workingDir = getcwd() +class Obfuscatelegacy(Command): + exclusiveOptions = [] + requiredOptions = ["--loops", "--mode", ["--files", "--dirs"]] + options = { + "--quiet": False, + "--log": "", + "--no-color ": False, + "--no-input": False, + + "--loops": 0, + "--mode": 0, + "--dirs": [], + "--files": [], + "--output": "" + } + + help = f''' +Usage: + dotpyguard obfuscatelegacy [options] +Example: + dotpyguard obfuscatelegacy --loops 3 --mode 2 --file code.py + +Notes: + * -> required option. + text,text -> to add more than one arg to option. + +Options: + --help -> show help for commands. + --quiet -> give less output. + --log -> write all logs to a file. + --no-color -> suppress colored output. + --no-input -> disable prompting for input. + + --loops * -> number of obfuscation loops. + --mode * -> obfuscation mode(1-4) as bigger number as better obfuscation but the output file is larger. + --dirs * -> obfuscate all files in dir(required files or/and dir). + --files * -> files for obfuscation(required files or/and dir). + --output -> output dir.''' + + def __init__(self): + self.InitVars() self.CheckOptions() self.ObfuscateFiles() + Log.Success("Legacy obfuscation compleated") + + def InitVars(self): + self.workingDir = getcwd() def CheckOptions(self): Log.Info("Legacy obfuscation.") - if self.this.options["--loops"] < 1: + if self.options["--loops"] < 1: raise Exception("Invalid --loops value.") - if self.this.options["--mode"] < 1 or self.this.options["--mode"] > 4: + if self.options["--mode"] < 1 or self.options["--mode"] > 4: raise Exception("Invalid --mode value.") - if not self.this.options["--output"]: - self.this.options["--output"] = "obfuscated" + if not self.options["--output"]: + self.options["--output"] = "obfuscated" - if path.exists(self.this.options["--output"]): - Log.Warning(f"Output directory already exists: \"{self.this.options['--output']}\".") + if path.exists(self.options["--output"]): + Log.Warning(f"Output directory already exists: \"{self.options['--output']}\".") responce = "" while responce != "y" or responce != "n" or responce != "ignore": responce = Log.Question("Override directory? (y/n)").lower() match responce: case "ignore": - rmtree(self.this.options["--output"]) + rmtree(self.options["--output"]) Log.Info("Directory overridden.") break case "y": - rmtree(self.this.options["--output"]) + rmtree(self.options["--output"]) Log.Success("Directory overridden.") break case "n": @@ -45,29 +86,29 @@ def CheckOptions(self): Log.Fail("Invalid response. Please enter 'y' or 'n'.") print() - for file in self.this.options["--files"]: + for file in self.options["--files"]: if not path.exists(file) or not path.isfile(file) or not file.endswith(".py"): raise Exception(f"Invalid file path: \"{file}\".") if path.isabs(file): raise Exception(f"Abs path is unsupported: \"{file}\"") - for dir in self.this.options["--dirs"]: + for dir in self.options["--dirs"]: if not path.exists(dir) or not path.isdir(dir): raise Exception(f"Invalid directory path: \"{dir}\".") if path.isabs(dir): raise Exception(f"Abs path is unsupported: \"{dir}\"") - if self.this.options["--files"]: - Log.Info(f"Included files: {self.this.options["--files"]}") - if self.this.options["--dirs"]: - Log.Info(f"Included dirs: {self.this.options["--dirs"]}") + if self.options["--files"]: + Log.Info(f"Included files: {self.options["--files"]}") + if self.options["--dirs"]: + Log.Info(f"Included dirs: {self.options["--dirs"]}") - Log.Info(f"loops amount: {self.this.options["--loops"]}") - Log.Info(f"obfuscation mode: {self.this.options["--mode"]}") - Log.Info(f"output dir: {self.this.options["--output"]}\n") + Log.Info(f"loops amount: {self.options["--loops"]}") + Log.Info(f"obfuscation mode: {self.options["--mode"]}") + Log.Info(f"output dir: {self.options["--output"]}\n") def ObfuscateFiles(self): - for file in self.this.options["--files"]: + for file in self.options["--files"]: with open(file, "r", encoding="utf-8") as pyFile: context = pyFile.read() if not context: @@ -80,13 +121,13 @@ def ObfuscateFiles(self): context = RemoveComments(context) - obfuscator = LegacyObfuscation(self.this.options["--mode"], self.this.options["--loops"], LegacyObfuscation.GenSeperator(12)) + obfuscator = LegacyObfuscation(self.options["--mode"], self.options["--loops"], LegacyObfuscation.GenSeperator()) context = obfuscator.Encrypt(context) context = obfuscator.Wrap(context) self.SaveFile(filename, filepath, context) - for dir in self.this.options["--dirs"]: + for dir in self.options["--dirs"]: for dirpath, dirnames, filenames in walk(dir): for filename in filenames: @@ -101,14 +142,14 @@ def ObfuscateFiles(self): context = RemoveComments(context) - obfuscator = LegacyObfuscation(self.this.options["--mode"], self.this.options["--loops"], LegacyObfuscation.GenSeperator(12)) + obfuscator = LegacyObfuscation(self.options["--mode"], self.options["--loops"], LegacyObfuscation.GenSeperator()) context = obfuscator.Encrypt(context) context = obfuscator.Wrap(context) self.SaveFile(filename , dirpath, context) def SaveFile(self, filename, filepath, content): - filepath = self.this.options["--output"]+sep+filepath + filepath = self.options["--output"]+sep+filepath makedirs(filepath, exist_ok=True) with open(filepath+sep+filename, "w", encoding="utf-8") as file: diff --git a/scr/config.py b/scr/config.py index 0b0e70b..e590a70 100644 --- a/scr/config.py +++ b/scr/config.py @@ -1,15 +1,37 @@ from abc import ABC -NAME = "Py-Shield" +NAME = ".PyGuard" AUTHOR = "ByteCorum" -URL = "https://github.com/ByteCorum/Py-Shield" -VERSION = "3.0.0.0" +URL = "https://github.com/ByteCorum/.PyGuard" +VERSION = "3.1.0.0" DESCRIPTION = "Tool/Library for Python used to obfuscate and protect your code in static and runtime from decompilation, reverse debug, etc. Also, can prevent detection by antiviruses." class Command(ABC): exclusiveOptions: list requiredOptions: list options: dict + help: str - handler: callable - help: str \ No newline at end of file +# class Name_of_the_command(Command): #note: only first letter should be capital +# def __init__(self): #command handler that will be called when the command is executed +# pass +# +# #May be left not initialized if your command has no options# +# exclusiveOptions = [["--install","--uninstall"], ["--up","--down"]] #groups of options that can't be used together +# requiredOptions = ["entrypoint", [""]] #options and groups(any option from a group is required) that are required +# +# options = { #all the options that your command has. note: don't write help here, it's hendeled elsewhere +# #General Options +# "--quiet": False, +# "--log": "", +# "--no-color ": False, +# "--no-input": False, +# +# #Your Options +# "--option1": False, +# "entrypoint": "" #only 1 fixed option name used to store program entrypoint file path +# } +# +# #Should be always initialized# +# help = f'''I\'ll help u''' #help message for the command +# \ No newline at end of file diff --git a/scr/dotpyguard.py b/scr/dotpyguard.py new file mode 100644 index 0000000..f54e1c9 --- /dev/null +++ b/scr/dotpyguard.py @@ -0,0 +1,98 @@ +from sys import argv, exit +from os import walk, path +from inspect import isclass, isabstract +from importlib.util import spec_from_file_location, module_from_spec + +from utils.optionsParser import OptionsParser +from utils.logger import Log +from config import Command, NAME + + +class DotPyGuard: + command: Command = None + helpCmd: Command = None + + def __init__(self): + try: + self.helpCmd = self.GetCommand("Help") + self.ParseArgs() + self.SetGlobalVars() + self.RunCommand() + except Exception as error: + Log.Fail(f"Fatal error occurred: {error}", True) + + def ParseArgs(self): + try: + if len(argv) < 2: + raise Exception("missing command name.") + + self.command = self.GetCommand(argv[1].title()) + + except Exception as error: + self.helpCmd(self.helpCmd) + Log.Fail("Command parsing failed: "+str(error), True) + + try: + parser = OptionsParser(argv[2:], self.command) + parser.Parse() + if parser.helpCalled: + self.helpCmd(self.command) + exit(0) + parser.Validate() + + except Exception as error: + Log.Fail(f"Options parsing failed: {error}", True) + + def GetCommand(self, name) -> Command: + command: Command = self.SearchCommand(name, f"{path.dirname(path.abspath(__file__))}/commands/") + if not command: + raise Exception(f"invalid command name: \"{name}\".") + + return command + + def SearchCommand(self, name: str, path: str) -> Command: + for dirpath, dirnames, filenames in walk(path): + for filename in filenames: + if filename.endswith(".py") and filename != "__init__.py": + filePath = f"{dirpath}/{filename}" + spec = spec_from_file_location("temp_module", filePath) + + if spec and spec.loader: + module = module_from_spec(spec) + try: + spec.loader.exec_module(module) + for cmdName in dir(module): + command: Command = getattr(module, cmdName) + if (isclass(command) and + not isabstract(command) and + issubclass(command, Command) and + command.__name__ != 'Command'): + + if (command.__name__ == name): + return command + + except Exception as error: + # Skip files that can't be imported + continue + return None + + + def SetGlobalVars(self): + if "--log" in self.command.options: + Log.logFile = self.command.options["--log"] + + if "--quiet" in self.command.options: + Log.quiet = self.command.options["--quiet"] + + if "--no-color" in self.command.options: + Log.colored = not self.command.options["--no-color"] + + if "--no-input" in self.command.options: + Log.noInput = self.command.options["--no-input"] + + def RunCommand(self): + Log.Info(f"{NAME}\n", True) + try: + self.command() + except Exception as error: + Log.Fail(f"Command failed: {error}", True) \ No newline at end of file diff --git a/scr/main.py b/scr/main.py index 9d9d1fa..e49ff99 100644 --- a/scr/main.py +++ b/scr/main.py @@ -1,4 +1,4 @@ -from pyshield import PyShield +from dotpyguard import DotPyGuard if __name__ == "__main__": - PyShield() \ No newline at end of file + DotPyGuard() \ No newline at end of file diff --git a/scr/pyshield.py b/scr/pyshield.py deleted file mode 100644 index 5109139..0000000 --- a/scr/pyshield.py +++ /dev/null @@ -1,79 +0,0 @@ -from sys import argv, exit -from inspect import isclass, isabstract -from utils.optionsParser import OptionsParser -from utils.logger import Log -from config import Command, NAME -import commands.commands as cmds - - -class PyShield: - def __init__(self): - self.command = None - self.commandName = "" - self.noOptions = False - try: - self.ParseArgs() - self.SetGlobalVars() - self.RunCommand() - except Exception as error: - Log.Fail(f"Fatal error occurred: {error}", True) - - def ParseArgs(self): - commands = [] - for cmdName in dir(cmds): - cmd = getattr(cmds, cmdName) - if isclass(cmd) and not isabstract(cmd) and issubclass(cmd, Command) and cmd.__name__ != 'Command': - commands.append(cmdName.lower()) - - try: - if len(argv) < 2: - raise Exception("missing command name.") - - if argv[1] not in commands: - raise Exception(f"invalid command name: \"{argv[1]}\".") - - except Exception as error: - cmds.Help.handler(cmds.Help) - Log.Fail("Command parsing failed: "+str(error), True) - - self.commandName = argv[1] - try: - self.command: Command = getattr(cmds, self.commandName.title()) - if not self.command.options: - self.noOptions = True - return - - parser = OptionsParser(argv[2:], self.command) - parser.Parse() - if parser.ended: - exit(0) - - parser.Validate() - self.command = parser.command - - except Exception as error: - Log.Fail(f"Options parsing failed: {error}", True) - - def SetGlobalVars(self): - if self.noOptions: - return - - if "--log" in self.command.options: - Log.logFile = self.command.options["--log"] - - if "--quiet" in self.command.options: - Log.quiet = self.command.options["--quiet"] - - if "--no-color" in self.command.options: - Log.colored = not self.command.options["--no-color"] - - if "--no-input" in self.command.options: - Log.noInput = self.command.options["--no-input"] - - def RunCommand(self): - Log.Info(f"{NAME}\n", True) - try: - self.command.handler(self.command) - Log.Success(f"{self.commandName.title()} successfully completed.") - except Exception as error: - Log.Fail(f"{self.commandName.title()} failed: {error}", True) \ No newline at end of file diff --git a/scr/utils/obfuscation.py b/scr/utils/obfuscation.py index 0d7687c..fdf5cd7 100644 --- a/scr/utils/obfuscation.py +++ b/scr/utils/obfuscation.py @@ -1,5 +1,5 @@ from random import choice, randint -from string import ascii_letters, digits, punctuation +from string import ascii_letters, digits from utils.crypto import FernetCipher, AesCipher, ChaCha20Cipher, Salsa20Cipher, compress, b64encode import ast from hashlib import sha256 @@ -10,7 +10,9 @@ from utils.logger import Log class MainObfuscation: - def __init__(self, hashdata: bool, fernet: bool, aes: bool, chacha20: bool, salsa20: bool, base64: bool, recursive: int, noProtect: bool) -> None: + def __init__(self, hashdata: bool, fernet: bool, aes: bool, + chacha20: bool, salsa20: bool, base64: bool, + recursive: int, noProtect: bool, encExec: bool) -> None: self.hashdata = hashdata self.fernet = fernet self.aes = aes @@ -18,6 +20,7 @@ def __init__(self, hashdata: bool, fernet: bool, aes: bool, chacha20: bool, sals self.salsa20 = salsa20 self.base64 = base64 self.noProtect = noProtect + self.encExec = encExec self.recursive = recursive if self.recursive < 0: raise Exception("Invalid recursive value.") @@ -97,8 +100,8 @@ def HashVariables(self, content: str) -> str: def Wrap(self, content: bytes) -> str: content = f'''#Obfuscated by {NAME} {VERSION} -from PyShield.script_{self.number} import PyShield, _ -_(PyShield({content}, __file__)._)''' +from DotPyGuard.script_{self.number} import DotPyGuard, _ +_(DotPyGuard({content}, __file__)._)''' return content @@ -116,7 +119,7 @@ def ProtectFile(self, outputDir, filepath): self.files.append([filepath, fileHash]) def CreateExecutor(self, outputDir): - secret = sha256(''.join(choice(ascii_letters+digits+punctuation) for _ in range(randint(16,32))).encode("utf-8")).hexdigest() + secret = sha256(''.join(choice(ascii_letters+digits) for _ in range(randint(16,32))).encode("utf-8")).hexdigest() context = f''' {'''from hashlib import sha256 from os import path, getcwd''' if not self.noProtect else ""} @@ -131,7 +134,7 @@ def CreateExecutor(self, outputDir): _ = exec -class PyShield: +class DotPyGuard: def __init__(self, code, file): try: self.__code{secret} = code @@ -235,12 +238,13 @@ def _(self): string = decompress(raw[1]).decode("utf-8") self.__code{secret} = self.__code{secret}.replace(raw[0], string)''' if self.hashdata else ""} ''' - outputDir =f"{outputDir}/PyShield" + outputDir =f"{outputDir}/DotPyGuard" makedirs(outputDir) - obfuscator = LegacyObfuscation(3, 6, LegacyObfuscation.GenSeperator(12)) - context = obfuscator.Encrypt(context) - context = obfuscator.Wrap(context) + if self.encExec: + obfuscator = LegacyObfuscation(3, 6, LegacyObfuscation.GenSeperator()) + context = obfuscator.Encrypt(context) + context = obfuscator.Wrap(context) with open(f"{outputDir}/script_{self.number}.py", "w", encoding="utf-8") as file: file.write(context) @@ -257,7 +261,7 @@ def AssembleExecutor(self, dir: str): ] setup( - name='PyShield', + name='.PyGuard', version='{VERSION}', author='{AUTHOR}', ext_modules=cythonize( @@ -276,6 +280,8 @@ def AssembleExecutor(self, dir: str): cur = getcwd() chdir(dir) + + Log.Info(f"Assembling executor...") result = run(["python", "assembler.py", "build_ext", "--inplace"], stdout=Log.logFile if Log.logFile else DEVNULL, stderr=PIPE, text=True) @@ -328,13 +334,13 @@ def Encrypt(self, content) -> str: def Wrap(self, content) -> str: match self.mode: case 1: - return "_=lambda __:__import__('zlib').decompress(__import__('base64').b64decode((__import__('zlib').decompress(__))[::-1])[::-1]);"+content + return f"#Obfuscated by {NAME} {VERSION}\n_=lambda __:__import__('zlib').decompress(__import__('base64').b64decode((__import__('zlib').decompress(__))[::-1])[::-1]);"+content case 2: - return f"_=lambda __:__import__('zlib').decompress(__import__('cryptography.fernet').fernet.Fernet(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[1]).decrypt(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[0])[::-1]);"+content + return f"#Obfuscated by {NAME} {VERSION}\n_=lambda __:__import__('zlib').decompress(__import__('cryptography.fernet').fernet.Fernet(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[1]).decrypt(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[0])[::-1]);"+content case 3: - return f"_=lambda __:__import__('zlib').decompress(__import__('cryptography.fernet').fernet.Fernet(__import__('base64').b64decode(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[1])).decrypt(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[0])[::-1]);"+content + return f"#Obfuscated by {NAME} {VERSION}\n_=lambda __:__import__('zlib').decompress(__import__('cryptography.fernet').fernet.Fernet(__import__('base64').b64decode(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[1])).decrypt(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[0])[::-1]);"+content case 4: - return f"_=lambda __:__import__('zlib').decompress(__import__('base64').b64decode(__import__('zlib').decompress((__import__('cryptography.fernet').fernet.Fernet(__import__('base64').b64decode(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[1])).decrypt(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[0])))[::-1]));"+content + return f"#Obfuscated by {NAME} {VERSION}\n_=lambda __:__import__('zlib').decompress(__import__('base64').b64decode(__import__('zlib').decompress((__import__('cryptography.fernet').fernet.Fernet(__import__('base64').b64decode(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[1])).decrypt(((__import__('zlib').decompress(__))[::-1].split(b'{self.separator}'))[0])))[::-1]));"+content case _: raise Exception("Invalid mode value.") @@ -392,5 +398,7 @@ def LiteObfuscation(self,content): return f"exec((_)({enccontent}))" @staticmethod - def GenSeperator(length): - return ''.join(choice(ascii_letters+digits+punctuation) for _ in range(length)) \ No newline at end of file + def GenSeperator(length = 32): + if length < 12: + raise Exception("Too short separator") + return ''.join(choice(ascii_letters+digits) for _ in range(length)) \ No newline at end of file diff --git a/scr/utils/optionsParser.py b/scr/utils/optionsParser.py index fc5e8d4..ff2e740 100644 --- a/scr/utils/optionsParser.py +++ b/scr/utils/optionsParser.py @@ -1,20 +1,18 @@ from utils.logger import Log from config import Command -from commands.commands import Help class OptionsParser: def __init__(self, argv, command: Command): self.argv = argv self.argc = len(self.argv) self.command = command - self.ended = False# handles the --help command with the highest priority + self.helpCalled = False# handles the --help command with the highest priority def Parse(self): if "--help" in self.argv: - Help.handler(self.command) if self.argc > 1: Log.Warning("--help found, other options ignored.") - self.ended = True + self.helpCalled = True return skipNext = False