Giter Club home page Giter Club logo

mad-cat-lon / jargonaut Goto Github PK

View Code? Open in Web Editor NEW
36.0 2.0 4.0 22.83 MB

Python <3.10 src2src obfuscation engine built on LibCST with a library of fun obfuscation techniques, including polynomial MBAs, runtime bytecode patching, etc.

License: GNU General Public License v3.0

Python 98.30% Shell 1.70%
obfuscation obfuscator python python-obfuscation python-obfuscator reverse-engineering security-tools mixed-boolean-arithmetic anti-reversing python-bytecode

jargonaut's Introduction

My GitHub stats

Top Langs

jargonaut's People

Contributors

mad-cat-lon avatar mustwey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

jargonaut's Issues

Optimized mba.py (im using numpy instead of z3)

import numpy as np
import ast
import random
import unicloak.utils.mba.primitives as primitives
from functools import singledispatch

NUM_TERMS = 10

truth_table = np.array([
    [0, 0, 0, 1],  # x & y
    [0, 0, 1, 0],  # x & ~y
    [0, 0, 1, 1],  # x 
    [0, 1, 0, 0],  # ~x & y
    [0, 1, 0, 1],  # y
    [0, 1, 1, 0],  # x ^ y
    [0, 1, 1, 1],  # x | y
    [1, 0, 0, 0],  # ~(x | y)
    [1, 0, 0, 1],  # ~(x ^ y)
    [1, 0, 1, 0],  # ~y
    [1, 0, 1, 1],  # x | ~y
    [1, 1, 0, 0],  # ~x
    [1, 1, 0, 1],  # ~x | y
    [1, 1, 1, 0],  # ~(x & y)
    [1, 1, 1, 1],  # -1
])

func_list = [
    primitives.x_and_y,
    primitives.x_and_not_y,
    primitives.x,
    primitives.not_x_and_y,
    primitives.y,
    primitives.x_xor_y,
    primitives.x_or_y,
    primitives.not_inc_x_or_y,
    primitives.not_inc_x_xor_y,
    primitives.not_y,
    primitives.x_or_not_y,
    primitives.not_x,
    primitives.not_x_or_y,
    primitives.not_inc_x_and_y,
    primitives.min_one
]


def generate_terms(expr_number):
    while True:
        coeffs = np.zeros(15, dtype=np.int64)
        expr_selector = np.array(
            [random.randint(0, expr_number - 1) for _ in range(expr_number)]
        )

        A = truth_table[expr_selector, :].T
        b = np.zeros(4)
        n = len(A[0])
        m = len(b)
        X = [np.int64(0) for _ in range(n)]

        try:
            sol = np.linalg.solve(A, b)
            if not any(np.isclose(sol, 0)):  # Ensure that the solution is not a zero vector
                for i in range(expr_number):
                    coeffs[expr_selector[i]] += int(sol[i])
                return coeffs
        except np.linalg.LinAlgError:
            continue  # Retry if no solution is found


@singledispatch
def generate_linear_mba(expr):
    return expr


@generate_linear_mba.register
def _(expr: ast.BinOp):
    final_expr = []
    primitive_expr = None
    terms_to_edit = None
    if isinstance(expr.op, ast.Add):
        terms_to_edit = [(2, 1), (4, 1)]
    elif isinstance(expr.op, ast.Sub):
        terms_to_edit = [(2, 1), (4, -1)]
    elif isinstance(expr.op, ast.BitXor):
        terms_to_edit = [(5, 1)]
    elif isinstance(expr.op, ast.BitAnd):
        terms_to_edit = [(0, 1)]
    elif isinstance(expr.op, ast.BitOr):
        terms_to_edit = [(6, 1)]

    if (
        isinstance(expr.left, ast.Name)
        and isinstance(expr.right, ast.Name)
    ):
        terms = generate_terms(NUM_TERMS)
        if terms_to_edit is None:
            return expr
        for idx, val in terms_to_edit:
            terms[idx] += val
        x = expr.left.id
        y = expr.right.id
        for i in range(15):
            primitive_expr = func_list[i](x=x, y=y)
            if terms[i] != 0:
                final_expr.append(
                    f"({terms[i]})*({ast.unparse(primitive_expr)})"
                )
        final_expr = '+'.join(final_expr)
        return ast.parse(final_expr).body[0].value
    else:
        return expr


@generate_linear_mba.register
def _(const: ast.Constant):
    final_expr = []
    primitive_expr = None
    terms = generate_terms(NUM_TERMS)
    terms[14] -= int(const.value)
    x = "1337"
    y = "1984"
    for i in range(15):
        primitive_expr = func_list[i](x=x, y=y)
        if terms[i] != 0:
            final_expr.append(
                f"({terms[i]})*({ast.unparse(primitive_expr)})"
            )
    final_expr = '+'.join(final_expr)
    return ast.parse(final_expr).body[0]

Optimized mba.py (im using numpy instead of z3) Take # 2

import numpy as np
import ast
import random
import unicloak.utils.mba.primitives as primitives
from functools import singledispatch

NUM_TERMS = 10

truth_table = np.array([
    [0, 0, 0, 1],
    [0, 0, 1, 0],
    [0, 0, 1, 1],
    [0, 1, 0, 0],
    [0, 1, 0, 1],
    [0, 1, 1, 0],
    [0, 1, 1, 1],
    [1, 0, 0, 0],
    [1, 0, 0, 1],
    [1, 0, 1, 0],
    [1, 0, 1, 1],
    [1, 1, 0, 0],
    [1, 1, 0, 1],
    [1, 1, 1, 0],
    [1, 1, 1, 1],
])

func_list = [
    primitives.x_and_y,
    primitives.x_and_not_y,
    primitives.x,
    primitives.not_x_and_y,
    primitives.y,
    primitives.x_xor_y,
    primitives.x_or_y,
    primitives.not_inc_x_or_y,
    primitives.not_inc_x_xor_y,
    primitives.not_y,
    primitives.x_or_not_y,
    primitives.not_x,
    primitives.not_x_or_y,
    primitives.not_inc_x_and_y,
    primitives.min_one
]

def generate_terms(expr_number):
    while True:
        coeffs = np.zeros(15, dtype=np.int64)
        expr_selector = np.array(
            [random.randint(0, expr_number - 1) for _ in range(expr_number)]
        )

        A = truth_table[expr_selector, :].T
        b = np.zeros(4)
        n = len(A[0])
        m = len(b)
        X = [np.int64(0) for _ in range(n)]

        sol, _, _, _ = np.linalg.lstsq(A, b, rcond=None)
        if not any(np.isclose(sol, 0)):  # Ensure that the solution is not a zero vector
            for i in range(expr_number):
                coeffs[expr_selector[i]] += int(sol[i])
            return coeffs

@singledispatch
def generate_linear_mba(expr):
    return expr

@generate_linear_mba.register
def _(expr: ast.BinOp):
    final_expr = []
    primitive_expr = None
    terms_to_edit = None
    if isinstance(expr.op, ast.Add):
        terms_to_edit = [(2, 1), (4, 1)]
    elif isinstance(expr.op, ast.Sub):
        terms_to_edit = [(2, 1), (4, -1)]
    elif isinstance(expr.op, ast.BitXor):
        terms_to_edit = [(5, 1)]
    elif isinstance(expr.op, ast.BitAnd):
        terms_to_edit = [(0, 1)]
    elif isinstance(expr.op, ast.BitOr):
        terms_to_edit = [(6, 1)]

    if (
        isinstance(expr.left, ast.Name)
        and isinstance(expr.right, ast.Name)
    ):
        terms = generate_terms(NUM_TERMS)
        if terms_to_edit is None:
            return expr
        for idx, val in terms_to_edit:
            terms[idx] += val
        x = expr.left.id
        y = expr.right.id
        for i in range(15):
            primitive_expr = func_list[i](x=x, y=y)
            if terms[i] != 0:
                final_expr.append(
                    f"({terms[i]})*({ast.unparse(primitive_expr)})"
                )
        final_expr = '+'.join(final_expr)
        return ast.parse(final_expr).body[0].value
    else:
        return expr

@generate_linear_mba.register
def _(const: ast.Constant):
    final_expr = []
    primitive_expr = None
    terms = generate_terms(NUM_TERMS)
    terms[14] -= int(const.value)
    x = "1337"
    y = "1984"
    for i in range(15):
        primitive_expr = func_list[i](x=x, y=y)
        if terms[i] != 0:
            final_expr.append(
                f"({terms[i]})*({ast.unparse(primitive_expr)})"
            )
    final_expr = '+'.join(final_expr)
    return ast.parse(final_expr).body[0]


Removes Documentation, Comments, Whitespaces, Type Hints, __annotations__ and unnecessary paranthesis ( In the works )


import ast
import astunparse
import re

class UnnecessaryParenthesesRemover(ast.NodeTransformer):

    def visit_Expr(self, node):
        if (isinstance(node.value, ast.BinOp) or isinstance(node.value, ast.Compare)):
            node.value = self.visit(node.value)
        return node

    def visit_BinOp(self, node):
        if isinstance(node.left, ast.BinOp):
            node.left = self.visit(node.left)
        if isinstance(node.right, ast.BinOp):
            node.right = self.visit(node.right)
        return node

    def visit_Compare(self, node):
        if isinstance(node.left, ast.Compare):
            node.left = self.visit(node.left)
        for (i, comparator) in enumerate(node.comparators):
            if isinstance(comparator, ast.Compare):
                node.comparators[i] = self.visit(comparator)
        return node

def remove_unnecessary_parentheses(code):
    tree = ast.parse(code)
    tree = UnnecessaryParenthesesRemover().visit(tree)
    new_code = astunparse.unparse(tree)
    return new_code.replace("'", '"')


def remove_docstrings_and_comments(code):

    class DocstringAndCommentRemover(ast.NodeTransformer):

        def visit_Expr(self, node):
            if (isinstance(node.value, ast.Constant) and isinstance(node.value.value, str)):
                return None
            return node

        def visit_Module(self, node):
            self.generic_visit(node)
            node.body = [n for n in node.body if (n is not None)]
            return node

        def visit_While(self, node):
            self.generic_visit(node)
            node.body = [n for n in node.body if (n is not None)]
            return node

        def visit_Try(self, node):
            self.generic_visit(node)
            node.body = [n for n in node.body if (n is not None)]
            return node

        def visit_With(self, node):
            self.generic_visit(node)
            node.body = [n for n in node.body if (n is not None)]
            return node

        def visit_FunctionDef(self, node):
            node.returns = None
            for arg in node.args.args:
                arg.annotation = None
            self.generic_visit(node)
            return node

        def visit_AsyncFunctionDef(self, node):
            node.returns = None
            for arg in node.args.args:
                arg.annotation = None
            self.generic_visit(node)
            return node

        def visit_AnnAssign(self, node):
            return ast.Assign(targets=[node.target], value=node.value, type_comment=None)

        def visit_Assign(self, node):
            if (isinstance(node.targets[0], ast.Subscript) and isinstance(node.targets[0].value, ast.Name) and (node.targets[0].value.id == '__annotations__')):
                return None
            return node

        def visit_ClassDef(self, node):
            self.generic_visit(node)
            node.body = [n for n in node.body if (n is not None)]
            return node

        def visit_If(self, node):
            self.generic_visit(node)
            node.body = [n for n in node.body if (n is not None)]
            return node

        def visit_For(self, node):
            self.generic_visit(node)
            node.body = [n for n in node.body if (n is not None)]
            return node

        def visit_AsyncFor(self, node):
            self.generic_visit(node)
            node.body = [n for n in node.body if (n is not None)]
            return node

        def visit_Attribute(self, node):
            if isinstance(node.ctx, ast.Store):
                if hasattr(node.value, 'annotation'):
                    node.value.annotation = None
            self.generic_visit(node)
            return node
    tree = ast.parse(code)
    tree = DocstringAndCommentRemover().visit(tree)
    code_without_docstrings = astunparse.unparse(tree)
    return re.sub(r"(?m)^\s*#.*\n?", "", code_without_docstrings)

def remove_whitespace(code):
    code = re.sub('(?m)^(?!\\s*#)\\s*\\n', '', code)
    code = re.sub('\\s+$', '', code, flags=re.MULTILINE)
    return code

def clean_python_script(source_code):
    code = remove_docstrings_and_comments(source_code)
    code = remove_whitespace(code)
    code = remove_unnecessary_parentheses(code)
    return code

def test_clean_python_script():
    test_code = '''
# This is a comment

"""This is a module docstring"""

def test_function(a: int, b: int) -> int:
    """This is a function docstring"""
    return a + b

x: int = 5

__annotations__['y'] = float

def test_no_annotations(c, d):
    return c * d

class Example:
    """This is a class docstring"""
    
    def __init__(self, x: int) -> None:
        """This is the constructor docstring"""
        self.x = x

    def get_x(self) -> int:
        """This is a method docstring"""
        return self.x

# This is another comment

def outer_function():
    """This is an outer function docstring"""
    
    def inner_function():
        """This is an inner function docstring"""
        return "Hello, World!"
    
    return inner_function()

"""This is a multiline
docstring example
"""

async def async_function() -> None:
    """This is an async function docstring"""
    pass
    '''

    expected_output = '''def test_function(a, b):
    return (a + b)
x = 5
def test_no_annotations(c, d):
    return (c * d)
class Example:
    def __init__(self, x):
        self.x = x
    def get_x(self):
        return self.x
def outer_function():
    def inner_function():
        return "Hello, World!"
    return inner_function()
async def async_function():
    pass'''


    cleaned_code = clean_python_script(test_code)
    assert cleaned_code.strip() == expected_output.strip(), f'''Expected:
{expected_output}
Got:
{cleaned_code}'''

if __name__ == '__main__':
    # # Replace the file paths with your actual file paths.
    # input_file = 'input.py'
    # output_file = 'output.py'

    # with open(input_file, 'r', encoding='utf-8') as f:
    #     source_code = f.read()

    # cleaned_code = clean_python_script(source_code)

    # with open(output_file, 'w', encoding='utf-8') as f:
    #     f.write(cleaned_code + '\n')

    test_clean_python_script()

possible bugs/edge cases for jargonaut/transformations/control/patch_returns.py

Function Handling:

Nested Functions: Inability to correctly handle functions that are nested within other functions.
Generators: Lack of support for generator functions that use yield statements.
Exception Handling: No consideration for functions that throw exceptions, which could complicate control flow after transformation.
Non-Primitive Return Types: Assumption that the function's return value is easily replaceable, which might not be true for complex return types like lists, dictionaries, or custom objects.
Function Arguments: Lack of handling for functions that take arguments, especially those with default values, *args, or **kwargs.

Naming and Scoping:

Name Conflicts: Potential conflicts with existing variable and function names when generating random names.
Scope Conflicts: No checks for whether the injected code might conflict with variables in the parent scope.

Code Transformation:

Multiple Return Statements: Inability to handle functions with multiple return statements, especially those inside conditional or loop blocks.
Idempotence: Lack of idempotency, i.e., running the transformer multiple times on the same code could stack transformations and introduce bugs.

Compatibility and Performance:

Bytecode Compatibility: The transformation could break compatibility with tools like Nuitka that rely on specific bytecode structures.
Decorator Interactions: Potential conflicts with decorators that modify the function's bytecode or return value.

additional features to jargonaut/transformations/data/vm/mappings.py

Multi-Instruction Opcodes

custom opcodes to map to a sequence of actual Python opcodes.
basically generate random sequences of opcodes for the script specifically to call other opcodes which makes deob harder

Conditional Opcodes

add conditional opcodes and use them for this purpose :
generate at runtime extremely specific opcodes specifically for the script that is being obfuscated, make it that they call the multi instruction opcode

Dynamic Opcode Values

def generate_opcodes():
    counter = 0
    map = {}
    for key in OPCODE_MAP.keys():
        map[key] = []
        for sub_op in OPCODE_MAP[key]:
           map[key].append((sub_op[0], counter))
            counter += 1
    return map

OPCODE_MAP = generate_opcodes()
# Rather than hard-coding the integer values of your custom opcodes, you could generate them dynamically

if u plan on making it more complex, maybe add handler info for each opcode

"NOP": [
    {"name": "NOP", "code": 0, "handler": "handle_nop"},
],
# this is an example of how it could look, by code i just mean the integer code

If you want an idea on how to go about dead code insertion, here is some bad trashy ugly horrendus code i made

import random
import ast
import astor
import string
import keyword
from typing import Callable, List


# Constants
NOP_PROBABILITY = 1
UNREACHABLE_PROBABILITY = 1
BREAK_CONTINUE_PROBABILITY = 1


def is_statement(node) -> bool:
#   Checks if a given AST node is a statement.
    return isinstance(node, ast.stmt)


# def get_random_alias() -> str:
#     Generates a random string of 4 letters.
#     return ''.join(random.choice(string.ascii_letters) for _ in range(4))


def insert_statement_into_node(node, stmt):
#   Inserts a given statement into a given node.
    if isinstance(node, ast.Module):
        node.body.insert(random.randint(0, len(node.body)), stmt)
    elif isinstance(node, ast.FunctionDef):
        node.body.insert(random.randint(0, len(node.body)), stmt)


def insert_random_nop(func_ast: ast.Module) -> None:
#   Inserts random No-Operation (NOP) statements into a given function.
    def create_assign_nop():
        target = ast.Name(id='__unused', ctx=ast.Store())
        value = ast.Num(n=random.randint(0, 100))
        return ast.Assign(targets=[target], value=value)

    nop_types = [ast.Pass, ast.Expr(value=ast.Str(s="")), create_assign_nop]
    for node in ast.walk(func_ast):
        if is_statement(node):
            if random.random() < NOP_PROBABILITY:
                nop = random.choice(nop_types)
                if callable(nop):
                    nop = nop()
                insert_statement_into_node(node, nop)


def insert_random_break_continue(func_ast: ast.Module) -> None:
#   Inserts random break and continue statements into loop structures in a given function.
    loop_types = [ast.For, ast.While]
    for node in ast.walk(func_ast):
        if is_statement(node) and any(isinstance(node, loop_type) for loop_type in loop_types):
            if random.random() < BREAK_CONTINUE_PROBABILITY:
                break_continue = random.choice([ast.Break(), ast.Continue()])
                insert_statement_into_node(node, break_continue)


def insert_unreachable_code_blocks(func_ast: ast.Module) -> None:
#   Inserts unreachable code blocks into if statements in a given function.
    unreachable_code_types = [
        ast.Expr(value=ast.BinOp(left=ast.Num(n=1), op=ast.Add(), right=ast.Num(n=2))),
        ast.Expr(value=ast.Call(func=ast.Name(id='print', ctx=ast.Load()), args=[ast.Str(s="Unreachable")], keywords=[])),
        ast.Assign(targets=[ast.Name(id='unreachable_var', ctx=ast.Store())], value=ast.Num(n=42))
    ]
    for node in ast.walk(func_ast):
        if isinstance(node, ast.If):
            if random.random() < UNREACHABLE_PROBABILITY:
                unreachable_code = random.choice(unreachable_code_types)
                unreachable_if = ast.If(test=ast.NameConstant(value=False), body=[unreachable_code], orelse=[])
                node.body.insert(0, unreachable_if)

# def replace_variable_names(func_ast: ast.Module) -> None:
#     BROKEN BRUV
#     var_aliases = {}
#     for node in ast.walk(func_ast):
#         if isinstance(node, ast.Name) and isinstance(node.ctx, (ast.Store, ast.Load)):
#             if node.id not in var_aliases and not keyword.iskeyword(node.id):
#                 var_aliases[node.id] = get_random_alias()
#             node.id = var_aliases[node.id]

def obfuscate_code(code_str: str) -> str:
#   Obfuscates a given Python code by adding random code blocks that are syntactically valid but do not affect the output of the original code. The obfuscation techniques include inserting random No-Operation (NOP) statements, inserting unreachable code blocks, and inserting random break and continue statements in loop structures. The function returns the obfuscated code as a string.
    func_ast = ast.parse(code_str)
    obfuscation_techniques = [
        insert_random_nop,
        insert_unreachable_code_blocks,
        insert_random_break_continue,
#       replace_variable_names,
    ]
    for technique in obfuscation_techniques:
        technique(func_ast)
    return astor.to_source(func_ast)

if __name__ == "__main__":
    code = '''
def example_function():
    a = 5
    b = 10
    if a < b:
        print("a is smaller than b")
    else:
        print("b is smaller than a")
    c = a + b
    print("Sum of a and b is", c)
'''

    obfuscated_code = obfuscate_code(code)
    print(obfuscated_code)

adapt a new file structure

image

jargonaut -> src
name the dir to the src just src and not jargonaut

testing
make a folder for testing, that will do tests in preprocessing separately and transformation separately/performance make sure it tests for each os, making sure they work properly on each os with their own methods(since win does not support pyre, that is why we need os dependant testing

config
make a folder for config, basically it will process it and direct it to the cli folder in a manner it can understand so that it can process it and save the settings in this folder

cli
`make a folder for cli which will support selective obfuscation and other useful cmds(for example they can choose to only apply a certain obfuscation, which is very useful for testing)

utilities
make a folder for utils, should include, encryption algors/file reading/file writing/logging/smart finder(will find all python files in the current dir and ask u which one to obf)/custom exceptions(there might be alot of these so its better to maybe just keep them all in one place/an api handler(to communicate with anti virus sites to do checks/ if ur going to convert code to and from ast or bytecode, might as well do it here, considering they are probably used in more than one file/make a func that returns strings or parts of code that are flagged to be malicious, then run them through an obf again, to avoid high entropy/hashings/random gens/key generator/memory/cpu usage tracker/retry mechanism for if a certain obf fails, it warns the user and asks it if it wants to retry with out it/constants like the mba data

output
maybe make a seperate folder for outputs, mainly meant for things to do after the output u have got like testing, and gathering data on it(hashes/entropy/resources usage/anti virus scans/obfuscation methods used(because of retry mechanism and overall more professional), then pasting it on screen
make sure to use the config folder/ cli to determine whether to print or save such info in a file

Exception: Cache is required for initializing TypeInferenceProvider

Command: python jargonaut.py -in_file jargonaut.py -out_file new_ jargonaut.py
Environment: Windows 10 x64; Python 3.10.11 64bit
I tried all my scripts (including source_1.py in the examples folder) and get exactly the same result

[!] Type inferencing with pyre is not enabled. Obfuscated code may not be reliable.
Traceback (most recent call last):
  File "F:\Downloads\jargonaut-master\jargonaut.py", line 190, in <module>
    main()
  File "F:\Downloads\jargonaut-master\jargonaut.py", line 120, in main
    tree = wrapper.visit(t)
  File "D:\Python310\lib\site-packages\libcst\metadata\wrapper.py", line 203, in visit
    with visitor.resolve(self):
  File "D:\Python310\lib\contextlib.py", line 135, in __enter__
    return next(self.gen)
  File "D:\Python310\lib\site-packages\libcst\_metadata_dependent.py", line 108, in resolve
    self.metadata = wrapper.resolve_many(self.get_inherited_dependencies())
  File "D:\Python310\lib\site-packages\libcst\metadata\wrapper.py", line 193, in resolve_many
    _resolve_impl(self, providers)
  File "D:\Python310\lib\site-packages\libcst\metadata\wrapper.py", line 94, in _resolve_impl
    initialized_batchable = [
  File "D:\Python310\lib\site-packages\libcst\metadata\wrapper.py", line 95, in <listcomp>
    p(wrapper._cache.get(p)) if p.gen_cache else p() for p in batchable
  File "D:\Python310\lib\site-packages\libcst\metadata\type_inference_provider.py", line 77, in __init__
    super().__init__(cache)
  File "D:\Python310\lib\site-packages\libcst\metadata\base_provider.py", line 69, in __init__
    raise Exception(
Exception: Cache is required for initializing TypeInferenceProvider.

mba improvements ( bad )

Mba Improvement 1 :

def apply_mba_on_operands(expr, depth=0, max_depth=2):
    """
    Applies the MBA obfuscation on the operands of the expression recursively up to a specified depth.

    :param expr: The expression on which to apply the MBA obfuscation.
    :param depth: The current depth of the recursion.
    :param max_depth: The maximum depth for the recursion.
    :return: The obfuscated expression.
    """
    if depth >= max_depth:
        return expr

    # Apply MBA obfuscation on the left operand and recurse if necessary.
    if isinstance(expr.left, ast.BinOp):
        expr.left = apply_mba_on_operands(expr.left, depth + 1, max_depth)
    elif isinstance(expr.left, ast.Constant) or isinstance(expr.left, ast.Name):
        expr.left = generate_linear_mba(expr.left)

    # Apply MBA obfuscation on the right operand and recurse if necessary.
    if isinstance(expr.right, ast.BinOp):
        expr.right = apply_mba_on_operands(expr.right, depth + 1, max_depth)
    elif isinstance(expr.right, ast.Constant) or isinstance(expr.right, ast.Name):
        expr.right = generate_linear_mba(expr.right)

    return expr

Mba Improvement 2 :

def custom_mba_function1(x, y):
    return (x ^ y) + (~(x | y))

def custom_mba_function2(x, y):
    return (x & y) | (~(x & ~y))

def custom_mba_function3(x, y):
    return (~x & y) ^ (x | ~y)

def custom_mba_function4(x, y):
    return (~(x & y)) ^ (x | y)

def custom_mba_function5(x, y):
    return (x & ~y) + (~x & y)

def custom_mba_function6(x, y):
    return (x ^ ~y) | (~x ^ y)

def custom_mba_function7(x, y):
    return (x ^ y) & (~(x & y))

def custom_mba_function8(x, y):
    return (x | y) + (~x & ~y)

def custom_mba_function9(x, y):
    return (~x | ~y) ^ (x & y)

def custom_mba_function10(x, y):
    return (x & y) + (x ^ ~y)

def custom_mba_function11(x, y):
    return ~(x | y) & (x ^ y)

def custom_mba_function12(x, y):
    return (x & ~y) ^ (~x & y)

def custom_mba_function13(x, y):
    return (~(x ^ y)) | (x & y)

def custom_mba_function14(x, y):
    return (x & ~y) + (~x | y)

def custom_mba_function15(x, y):
    return (~(x & y)) & (x | ~y)

def custom_mba_function16(x, y):
    return (x ^ y) | (~x & ~y)

func_list = [
    # ... (previous functions)
    custom_mba_function1,
    custom_mba_function2,
    custom_mba_function3,
    custom_mba_function4,
    custom_mba_function5,
    custom_mba_function6
    custom_mba_function7,
    custom_mba_function8,
    custom_mba_function9,
    custom_mba_function10,
    custom_mba_function11,
    custom_mba_function12,
    custom_mba_function13,
    custom_mba_function14,
    custom_mba_function15,
    custom_mba_function16
]

truth_table = np.array([
    # ... (previous rows)
    [0, 1, 1, 1],  # custom_mba_function1
    [1, 1, 0, 1],  # custom_mba_function2
    [1, 0, 0, 1],  # custom_mba_function3
    [1, 1, 1, 0],  # custom_mba_function4
    [0, 1, 1, 0],  # custom_mba_function5
    [1, 0, 1, 0],  # custom_mba_function6
    [0, 1, 1, 0],  # custom_mba_function7
    [1, 1, 0, 0],  # custom_mba_function8
    [1, 0, 0, 0],  # custom_mba_function9
    [0, 0, 0, 0],  # custom_mba_function10
    [1, 1, 1, 1],  # custom_mba_function11
    [1, 0, 1, 1],  # custom_mba_function12
    [0, 1, 0, 0],  # custom_mba_function13
    [1, 1, 0, 1],  # custom_mba_function14
    [1, 0, 1, 0],  # custom_mba_function15
    [0, 0, 1, 1],  # custom_mba_function16
])

@generate_linear_mba.register
def _(expr: ast.BinOp):
    """
    Generates linear MBA for BinOp nodes:
        class ast.Add
        class ast.Sub
        class ast.Mult
        class ast.Div
        class ast.FloorDiv
        class ast.Mod
        class ast.Pow
        class ast.LShift
        class ast.RShift
        class ast.BitOr
        class ast.BitXor
        class ast.BitAnd
        class ast.MatMult
    """
    final_expr = []
    primitive_expr = None
    terms_to_edit = None
    
    if isinstance(expr.op, ast.Add):
        terms_to_edit = [(2, 1), (4, 1)]
    elif isinstance(expr.op, ast.Sub):
        terms_to_edit = [(2, 1), (4, -1)]
    elif isinstance(expr.op, ast.BitXor):
        terms_to_edit = [(5, 1)]
    elif isinstance(expr.op, ast.BitAnd):
        terms_to_edit = [(0, 1)]
    elif isinstance(expr.op, ast.BitOr):
        terms_to_edit = [(6, 1)]

    if (
        isinstance(expr.left, ast.Name)
        and isinstance(expr.right, ast.Name)
    ):
        terms = generate_terms(NUM_TERMS + 10)  # Update the number of terms to reflect added custom functions
        if terms_to_edit is None:
            return expr
        for idx, val in terms_to_edit:
            terms[idx] += val
        x = expr.left.id
        y = expr.right.id
        for i in range(25):  # Update the range to reflect added custom functions
            primitive_expr = func_list[i](x=x, y=y)
            if terms[i] != 0:
                final_expr.append(
                    f"({terms[i]})*({ast.unparse(primitive_expr)})"
                )
        final_expr = '+'.join(final_expr)
        return ast.parse(final_expr).body[0].value
    else:
        return expr

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.