PyObfuscator (version 0.1.5)
index
pyobfuscator.py

This module obfuscates python code.
 
>>> with open("code.py", "w") as f: n = f.write("print('Hello world !')")
>>> Obfuscator("code.py", deobfuscate=False).default_obfuscation()
>>> with open("code_obfu.py") as f: exec(f.read())
Hello world !
>>> from os import remove; remove("code.py"); remove("code_obfu.py")
 
Tests:
 - python3.11 -m doctest -v PyObfuscator.py
    22 tests in 58 items.
    22 passed and 0 failed.
    Test passed.
 - python3.11 -m unittest discover -s tests -p Test*.py -v
    ................................
    ----------------------------------------------------------------------
    Ran 39 tests in 0.150s
    OK
 - python3.11 -m coverage report
    Name                        Stmts   Miss  Cover
    -----------------------------------------------
    PyObfuscator.py               400      1    99%
    -----------------------------------------------
    TOTAL                         400      1    99%

 
Modules
       
builtins

 
Classes
       
ast.NodeTransformer(ast.NodeVisitor)
Obfuscator
builtins.object
DocLevels
DocPassword
Name

 
class DocLevels(builtins.object)
    Level is an integer to define obfuscation level.
 
if level equal 1:
    - variable name change (using Obfuscator.change_variables_name function)
        variables is less understandable
    - doc and signature is deleted
        function, class
if level equal 2:
    - level 1
    - strings are encrypted (using Obfuscator.crypt_strings function)
        the strings become illegible but execution is longer
if level equal 3:
    - level 2
    - code is compressed using GZIP
        the code structure becomes invisible but execution is longer
if level equal 4:
    - level 3
    - encrypt the code but execution is longer
if level equal 5:
    - level 4
    - encode code using base85
        bigger file size and execution is longer
if level equal 6:
    - level 5
    - encode your code as hexadecimal escape ('a' become '\x061')
        file size * 4
 
  Methods defined here:
print_the_doc() -> None

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

 
class DocPassword(builtins.object)
    Password is a string to encrypt python code with xor.
 
if password is None:
    - random password is define and write in python file
    code is independent but it's easy to reverse this obfuscation
if password is a string:
    - password is not written in python file, to run
    the code you must enter the password (console mode)
 
Note: this password is not use if you don't use
Obfuscator.xor function or Level is less than 4.
 
  Methods defined here:
print_the_doc() -> None

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

 
class Name(builtins.object)
    Name(name: str, obfuscation: str, is_defined: bool, namespace_name: str) -> None
 
Dataclass with default name, obfuscation name, definition and namespace.
 
name(str): default variable name
obfuscation(str): variable name after obfuscation (a random name)
is_defined(bool): a boolean representing the definition in file
namespace_name(str): the namespace (None or <class name> or <class name>.<function name>)
 
  Methods defined here:
__eq__(self, other)
Return self==value.
__init__(self, name: str, obfuscation: str, is_defined: bool, namespace_name: str) -> None
Initialize self.  See help(type(self)) for accurate signature.
__repr__(self)
Return repr(self).

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

Data and other attributes defined here:
__annotations__ = {'is_defined': <class 'bool'>, 'name': <class 'str'>, 'namespace_name': <class 'str'>, 'obfuscation': <class 'str'>}
__dataclass_fields__ = {'is_defined': Field(name='is_defined',type=<class 'bool'>,defa...appingproxy({}),kw_only=False,_field_type=_FIELD), 'name': Field(name='name',type=<class 'str'>,default=<da...appingproxy({}),kw_only=False,_field_type=_FIELD), 'namespace_name': Field(name='namespace_name',type=<class 'str'>,d...appingproxy({}),kw_only=False,_field_type=_FIELD), 'obfuscation': Field(name='obfuscation',type=<class 'str'>,defa...appingproxy({}),kw_only=False,_field_type=_FIELD)}
__dataclass_params__ = _DataclassParams(init=True,repr=True,eq=True,order=False,unsafe_hash=False,frozen=False)
__hash__ = None
__match_args__ = ('name', 'obfuscation', 'is_defined', 'namespace_name')

 
class Obfuscator(ast.NodeTransformer)
    Obfuscator(filename: str, output_filename: str = None, level: int = 6, names: Dict[str, PyObfuscator.Name] = {}, deobfuscate: bool = True, password: str = None, encoding: str = 'utf-8', names_size: int = 12)
 
This class obfuscates python code.
 
filename(str):                 python filename to obfuscate
output_filename(str) = None:   obfuscate python filename
level(int) = 6:                obfuscation level (see DocLevels)
names(Dict[str, Name]) = {}:   names you need to know (define your obfuscation names for import)
    For exemple: to import class named 'Obfuscator' as 'Fdg6jsT_2', names must be
    "{'Obfuscator': Name('Obfuscator', 'Fdg6jsT_2', False, None)}".
deobfuscate(bool) = True:      save names in a JSON file to reverse name obfuscation
password(str) = None:          key for encryption (see DocPassword)
encoding(str) = 'utf-8':       python file encoding
names_size(int) = 12:          size to generate random variables names
 
 
Method resolution order:
Obfuscator
ast.NodeTransformer
ast.NodeVisitor
builtins.object

Methods defined here:
__init__(self, filename: str, output_filename: str = None, level: int = 6, names: Dict[str, PyObfuscator.Name] = {}, deobfuscate: bool = True, password: str = None, encoding: str = 'utf-8', names_size: int = 12)
Initialize self.  See help(type(self)) for accurate signature.
add_builtins(self) -> str
This function adds builtins obfuscation on the top of the code
and returns it.
 
This function raises RuntimeError if builtins are not obfuscate.
 
This function raises RuntimeError if self.code is None.
add_super_arguments(self, code: str = None) -> Tuple[str, ast.AST]
This function adds super arguments because super
can't defined it's arguments after obfuscation.
 
>>> code = "class A:\n\tdef __init__(self):super().__init__()"
>>> code, _ = Obfuscator("").add_super_arguments(code)
>>> code
'class A:\n\tdef __init__(self):super(self.__class__, self).__init__()'
>>>
base85(self, code: str = None) -> str
This function encodes python code with base85.
   (Level 5)
 
- if code is None this function use self.code
- self.code is set encoded code
- returns the base85 encoded code
 
>>> exec(Obfuscator("").base85("print('Hello World !')"))
Hello World !
>>>
default_obfuscation(self) -> None
This function starts the default obfuscation process.
 
- get the code
- initialize obfuscation
- obfuscate names and values
- obfuscate structure
- save obfuscation, configuration and names to reverse obfuscation
delete_annotations(self, element: ast.AST) -> ast.AST
This function deletes annotations in AST object.
delete_field(self, element: ast.AST, field: str) -> ast.AST
This function deletes field in AST object.
delete_returns(self, element: ast.AST) -> ast.AST
This function deletes returns in AST object.
get_attributes_from(self, new_ast: ast.AST, old_ast: ast.AST) -> ast.AST
This function adds attributes from default AST to obfuscate AST.
 
new_ast(AST): obfuscate AST without all attributes
old_ast(AST): default AST with all attributes
get_code(self) -> Tuple[str, ast.AST]
This function returns content and AST from python file.
get_random_name(self, first_name: str, is_defined: bool = False) -> PyObfuscator.Name
This function returns a random variable name.
 
>>> Obfuscator("").get_random_name("test").name
'test'
>>>
get_targets_and_value_for_import(self, module: str, elements: List[ast.alias], is_from_import: bool = True) -> Tuple[ast.Tuple, ast.Tuple]
This function obfuscates 'from ... import ...'.
gzip(self, code: str = None) -> str
This function compress python code with gzip.
   (Level 3)
 
- if code is None this function use self.code
- self.code is compressed using GZIP
- returns the compressed code
 
>>> code = "print('Hello World !')"
>>> obfu = Obfuscator("").gzip(code)
>>> code != obfu
True
>>> exec(obfu)
Hello World !
>>>
hexadecimal(self, code: str = None) -> str
This function encodes python code as hexadecimal ('a' become '\x61').
   (Level 6)
 
- if code is None this function use self.code
- self.code is encoded as hexadecimal
- returns the hexadecimal encoded code
 
>>> code = "print('Hello World !')"
>>> obfu = Obfuscator("").hexadecimal(code)
>>> code != obfu
True
>>> exec(obfu)
Hello World !
>>>
init_builtins(self) -> str
This function obfuscates default variables and builtins names.
init_crypt_strings(self, code: str = None) -> Tuple[str, ast.AST]
This function adds the decrypt function to decrypt obfuscated/encrypted strings.
 
code(str) = None: if code this function use this code else it use self.code
self.code is set to the new code
Return the new code and AST.
init_import(self, code: str = None) -> Tuple[str, ast.AST]
This function adds an import function to try module 'from <module>.<module> import <module>'.
 
code(str) = None: if code this function use this code else it use self.code
self.code is set to the new code
Return the new code and AST.
int_call_obfuscation(self) -> str
This method obfuscates int calls for int obfuscation.
set_namespace_name(self, name: str) -> str
This function sets current namespace name.
 
returns old namespace name
 
>>> obfu = Obfuscator("")
>>> obfu.set_namespace_name("Test")
>>> obfu.set_namespace_name("test")
'Test'
>>> obfu.current_class
'Test.test'
>>>
string_obfuscation(self, string: str, no_backlash: bool = False) -> str
This function obfuscate a string.
visit_AnnAssign(self, astcode: ast.AnnAssign) -> ast.Assign
This function obfuscates assignation.
 
astcode(AnnAssign): assign with annotation
return an Assign obfuscated
visit_AsyncFunctionDef(self, astcode: ast.AsyncFunctionDef) -> ast.AsyncFunctionDef
This methods obfuscates asynchronous function
using the function obfusction.
 
astcode(AsyncFunctionDef): asynchronous function to obfuscate
returns a AsyncFunctionDef with different name
visit_ClassDef(self, astcode: ast.ClassDef) -> ast.ClassDef
This function obfuscates the class name and delete the doc string.
 
astcode(ClassDef): the class to obfuscate
returns a ClassDef with different name without doc string
visit_Constant(self, astcode: ast.Constant) -> ast.Call
This function encrypts python constants data.
   (Level 2)
 
- self.astcode is set to obfuscate ast code
- returns the obfuscate ast code
visit_FunctionDef(self, astcode: ast.FunctionDef) -> ast.FunctionDef
This function obfuscates function name if isn't a magic method.
 
astcode(FunctionDef): function to obfuscate
returns a FunctionDef with different name
visit_Global(self, astcode: ast.Global) -> ast.Global
This function obfuscates global names
 
astcode(Global): AST object to obfuscate
returns a Global with different names
visit_Import(self, astcode: ast.Import) -> ast.Assign
This function obfuscates 'import ...'
visit_ImportFrom(self, astcode: ast.ImportFrom) -> ast.Assign
This function build a obfuscate 'from ... import ...'
visit_JoinedStr(self, astcode: ast.JoinedStr) -> ast.JoinedStr
This function changes the visit_Constant's behaviour.
visit_Module(self, astcode: ast.Module) -> ast.Module
This function deletes the Module doc string.
 
module(Module): module to obfuscate.
if this module have doc string, doc string is delete.
returns module.
visit_Name(self, astcode: ast.Name) -> ast.Name
This function obfuscates name.
 
astcode(Name): the name to obfuscate
returns a Name with different id
visit_arg(self, astcode: ast.arg) -> ast.arg
This function obfuscates AST arg
 
astcode(arg): the arg to obfuscate
returns a AST arg with different arg name
write_code(self) -> Tuple[str, ast.AST]
This function writes obfuscate code in output file
and returns the obfuscate code.
 
This function raises RuntimeError if self.code is None.
write_deobfuscate(self) -> None
This function saves configuration and the mapping between
variable names and obfuscation names.
xor(self, data: bytes) -> bytes
This function encrypts data.
 
data(bytes): data to encrypt
return encrypted bytes
xor_code(self, code: str = None, password: str = None) -> str
This function encrypts code using xor.
   (Level 4)
 
- if code is None this function use self.code
- if password is None this function use self.password
       (see the DocPassword's doc string for more information)
- if self.password is None this function generate a random password
       (see the DocPassword's doc string for more information)
- self.code is set to encrypted code
- returns the encrypted code
 
>>> exec(Obfuscator("").xor_code("print('Hello World !')"))
Hello World !
>>>

Static methods defined here:
delete_doc_string(astcode: ast.AST) -> ast.AST
This function deletes doc string in AST object.

Methods inherited from ast.NodeTransformer:
generic_visit(self, node)
Called if no explicit visitor function exists for a node.

Methods inherited from ast.NodeVisitor:
visit(self, node)
Visit a node.

Data descriptors inherited from ast.NodeVisitor:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

 
Functions
       
main() -> int
This function starts this tool from command line.

 
Data
        __all__ = ['Obfuscator', 'main', 'Name', 'DocPassword', 'DocLevels']
__author_email__ = 'mauricelambert434@gmail.com'
__copyright__ = '\nPyObfuscator Copyright (C) 2021, 2022, 2023 M...ome to redistribute it\nunder certain conditions.\n'
__description__ = 'This module obfuscates python code.'
__license__ = 'GPL-3.0 License'
__maintainer__ = 'Maurice Lambert'
__maintainer_email__ = 'mauricelambert434@gmail.com'
__url__ = 'https://github.com/mauricelambert/PyObfuscator/'

 
Author
        Maurice Lambert