da
Doxygen to Wiki / Build Doxygen and publish to Wiki (push) Failing after 1m0s

This commit is contained in:
2025-08-15 21:06:31 -07:00
parent 387c694efe
commit 69184c7cb8
16 changed files with 444 additions and 64 deletions
+7 -1
View File
@@ -1 +1,7 @@
# This file ensures that the transformers directory is treated as a Python package
"""
@file transformers/__init__.py
@brief Package initializer for the transformers module.
@details Groups AST transformers and analyzers used by OMG-Fuscator, including
renaming, control-flow flattening, class mapping, attribute handling,
and symbol tree utilities.
"""
+23 -9
View File
@@ -1,26 +1,36 @@
"""
@file transformers/attribute_transformer.py
@brief Attribute access transformer for consistent class member renaming.
@details Ensures references like self.method and self.attr are kept consistent
with class and attribute mappings produced by analysis.
"""
import ast
from typing import Dict, Optional
class AttributeTransformer(ast.NodeTransformer):
"""
Transforms attribute access expressions (obj.attr) consistently,
especially for class method calls and attribute accesses.
@brief Transform attribute access expressions for consistency.
@details Handles self.method and self.attr translations based on provided
mappings to keep calls and attributes aligned with obfuscated names.
"""
def __init__(self, class_attr_mapping: Dict[str, Dict[str, str]], class_renames: Dict[str, str]):
"""
Initialize with mapping dictionaries.
Args:
class_attr_mapping: Maps class_name -> {attr_name -> obfuscated_attr_name}
class_renames: Maps original_class_name -> obfuscated_class_name
@brief Initialize transformer with mapping dictionaries.
@param class_attr_mapping Maps class_name -> {attr_name -> obfuscated_attr_name}
@param class_renames Maps original_class_name -> obfuscated_class_name
"""
self.class_attr_mapping = class_attr_mapping
self.class_renames = class_renames
self.current_class: Optional[str] = None
def visit_ClassDef(self, node):
"""Keep track of the current class being processed"""
"""
@brief Track the current class and process its body.
@param node ast.ClassDef being visited.
@return ast.ClassDef Potentially modified node.
"""
old_class = self.current_class
# Get the obfuscated name for this class
@@ -38,7 +48,11 @@ class AttributeTransformer(ast.NodeTransformer):
return node
def visit_Attribute(self, node):
"""Transform attribute access like self.method to use consistent names"""
"""
@brief Transform attribute access for consistency within a class.
@param node ast.Attribute node to transform.
@return ast.AST Updated attribute node.
"""
# First process any nested attributes
node = self.generic_visit(node)
+37 -16
View File
@@ -1,9 +1,16 @@
"""
@file transformers/class_analyzer.py
@brief Class analysis utilities for consistent renaming.
@details Pre-analyzes classes, methods, attributes, and inheritance to build
consistent mappings used by obfuscation transformers.
"""
import ast
from typing import Dict, Set, Tuple, List
class ClassMethodMap:
"""Stores method name mappings for all classes in the code."""
"""
@brief Stores method and attribute mappings for all classes.
"""
def __init__(self):
# Maps: original_class_name -> {original_method_name -> obfuscated_method_name}
self.class_methods: Dict[str, Dict[str, str]] = {}
@@ -20,8 +27,8 @@ class ClassMethodMap:
class ClassAnalyzer(ast.NodeVisitor):
"""
Pre-analyzes classes to ensure consistent renaming of methods and attributes.
This is crucial for making self.method() calls match def method() definitions.
@brief Analyze classes for consistent method/attribute renaming.
@details Ensures self.method() calls match def method() definitions and records inheritance.
"""
def __init__(self, name_generator):
self.name_generator = name_generator
@@ -35,14 +42,21 @@ class ClassAnalyzer(ast.NodeVisitor):
self.method_calls: Dict[str, Set[str]] = {}
def analyze(self, tree: ast.AST) -> ClassMethodMap:
"""Analyzes the entire AST and returns populated method mappings."""
"""
@brief Analyze the entire AST and produce mappings.
@param tree Parsed AST of the input module.
@return ClassMethodMap Populated mappings.
"""
self.visit(tree)
self._resolve_inheritance()
self._ensure_consistent_method_mapping()
return self.method_map
def visit_ClassDef(self, node: ast.ClassDef):
"""Process a class definition and map its methods."""
"""
@brief Process a class definition and map methods/attrs.
@param node ast.ClassDef node being visited.
"""
prev_class = self.current_class
self.current_class = node.name
@@ -105,7 +119,10 @@ class ClassAnalyzer(ast.NodeVisitor):
self.current_class = prev_class
def visit_attribute_assign(self, node):
"""Process attribute assignments like self.attr = value"""
"""
@brief Process self.attr assignments within a class.
@param node ast.Assign node of the assignment.
"""
if not self.current_class:
return
@@ -122,7 +139,10 @@ class ClassAnalyzer(ast.NodeVisitor):
self.visit(node.value)
def visit_Attribute(self, node):
"""Track self.method references to ensure consistent naming"""
"""
@brief Track self.method references for consistency checks.
@param node ast.Attribute being visited.
"""
if self.current_class:
is_self_method, method_name = get_method_name(node)
if is_self_method:
@@ -134,8 +154,7 @@ class ClassAnalyzer(ast.NodeVisitor):
def _ensure_consistent_method_mapping(self):
"""
Make sure that all methods called via self.method() have a mapping,
even if they're not defined in the class.
@brief Ensure all self.method() calls have mappings, even if undefined in class.
"""
for class_name, method_calls in self.method_calls.items():
if class_name not in self.method_map.class_methods:
@@ -153,8 +172,8 @@ class ClassAnalyzer(ast.NodeVisitor):
def _resolve_inheritance(self):
"""
Ensure child classes inherit method mappings from parent classes.
This ensures that overridden methods use the same obfuscated name.
@brief Propagate method mappings along inheritance hierarchies.
@details Ensures overridden methods reuse the same obfuscated name.
"""
# Process inheritance depth-first to handle multi-level inheritance
def process_inheritance(class_name):
@@ -181,8 +200,9 @@ class ClassAnalyzer(ast.NodeVisitor):
def get_method_name(node: ast.Attribute) -> Tuple[bool, str]:
"""
Helper function to determine if an attribute is a self.method() call.
Returns (is_self_method, method_name)
@brief Determine if an attribute is a self.method() call.
@param node Attribute node to check.
@return Tuple[bool, str] (is_self_method, method_name)
"""
if isinstance(node.value, ast.Name) and node.value.id == 'self':
return True, node.attr
@@ -191,8 +211,9 @@ def get_method_name(node: ast.Attribute) -> Tuple[bool, str]:
def update_obfuscator_with_class_mappings(obfuscator, class_map: ClassMethodMap):
"""
Updates the main obfuscator with class method and attribute mappings
to ensure consistent renaming across the codebase.
@brief Update obfuscator with class/method/attribute mappings.
@param obfuscator AdvancedObfuscator instance to update.
@param class_map ClassMethodMap mappings produced by analysis.
"""
# Update class name mappings in global_var_renames
for orig_name, obf_name in class_map.class_renames.items():
+72 -16
View File
@@ -1,3 +1,10 @@
"""
@file transformers/class_mapper.py
@brief Class, method, and attribute mapping analyzer and transformer.
@details Builds consistent rename mappings across classes, resolves inheritance,
and applies the mappings back to the AST for coherent obfuscation.
"""
import ast
from typing import Dict, Set, List, Tuple, Optional
import logging
@@ -7,7 +14,11 @@ logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("ClassMapper")
class ClassMapping:
"""Stores all mappings related to classes in a centralized way."""
"""
@brief Stores all mappings related to classes in a centralized way.
@details Tracks class renames, method and attribute mappings, inheritance structure,
and seen method calls to ensure complete coverage.
"""
def __init__(self):
# Original class name -> obfuscated class name
@@ -49,7 +60,11 @@ class ClassMapping:
class ClassMapAnalyzer(ast.NodeVisitor):
"""Analyzes the AST to create a complete class mapping."""
"""
@brief Analyze the AST to create a complete class mapping.
@details Performs multi-pass analysis to collect classes, methods, attributes,
inheritance, and method-call references and builds consistent mappings.
"""
def __init__(self, name_generator):
self.name_generator = name_generator
@@ -59,7 +74,11 @@ class ClassMapAnalyzer(ast.NodeVisitor):
self.processed_classes: Set[str] = set()
def analyze(self, tree: ast.AST) -> ClassMapping:
"""Perform a complete analysis of the AST."""
"""
@brief Perform a complete analysis of the AST.
@param tree Parsed AST to analyze.
@return ClassMapping Aggregated mappings for class renaming and members.
"""
# First pass: collect all class definitions, methods, and inheritance
self.visit(tree)
@@ -73,7 +92,10 @@ class ClassMapAnalyzer(ast.NodeVisitor):
return self.mapping
def visit_ClassDef(self, node: ast.ClassDef):
"""Process a class definition."""
"""
@brief Process a class definition.
@param node ast.ClassDef node.
"""
prev_class = self.current_class
self.current_class = node.name
@@ -125,7 +147,10 @@ class ClassMapAnalyzer(ast.NodeVisitor):
self.current_class = prev_class
def visit_method_def(self, node: ast.FunctionDef):
"""Process a method definition in a class."""
"""
@brief Process a method definition in a class.
@param node ast.FunctionDef node.
"""
if not self.current_class:
return
@@ -147,7 +172,10 @@ class ClassMapAnalyzer(ast.NodeVisitor):
self.current_method = prev_method
def visit_assign_in_class(self, node: ast.Assign):
"""Process assignments in class body or methods."""
"""
@brief Process assignments in class body or methods.
@param node ast.Assign possibly containing self.attr writes.
"""
if not self.current_class:
return
@@ -166,7 +194,10 @@ class ClassMapAnalyzer(ast.NodeVisitor):
self.visit(node.value)
def visit_Attribute(self, node: ast.Attribute):
"""Process attribute access like self.method or self.attr."""
"""
@brief Process attribute access like self.method or self.attr.
@param node ast.Attribute node.
"""
if self.current_class and isinstance(node.value, ast.Name) and node.value.id == 'self':
# Record this access for later processing
method_name = node.attr
@@ -177,7 +208,10 @@ class ClassMapAnalyzer(ast.NodeVisitor):
self.generic_visit(node)
def visit_Assign(self, node: ast.Assign):
"""Process assignments that might contain self.attr references."""
"""
@brief Process assignments that might contain self.attr references.
@param node ast.Assign node.
"""
# Visit both sides of the assignment
for target in node.targets:
self.visit(target)
@@ -185,7 +219,8 @@ class ClassMapAnalyzer(ast.NodeVisitor):
def _resolve_inheritance(self):
"""
Ensure child classes inherit method mappings from parent classes.
@brief Ensure child classes inherit method mappings from parent classes.
@details Copies parent method mappings into children when not overridden.
"""
def process_inheritance(class_name):
if class_name not in self.mapping.inheritance:
@@ -211,8 +246,8 @@ class ClassMapAnalyzer(ast.NodeVisitor):
def _ensure_complete_method_mapping(self):
"""
Make sure all method calls have corresponding mappings.
This handles methods called but not defined in the class.
@brief Ensure all method calls have corresponding mappings.
@details Handles methods called but not defined in the class.
"""
for class_name, method_calls in self.mapping.seen_method_calls.items():
if class_name not in self.mapping.class_methods:
@@ -231,14 +266,22 @@ class ClassMapAnalyzer(ast.NodeVisitor):
class ClassTransformer(ast.NodeTransformer):
"""Transforms class-related nodes using the mapping."""
"""
@brief Transform class-related nodes using the mapping.
@details Renames class names, methods, and self.attr/self.method references
according to the analyzed mappings.
"""
def __init__(self, mapping: ClassMapping):
self.mapping = mapping
self.current_class: Optional[str] = None
def visit_ClassDef(self, node: ast.ClassDef):
"""Transform class name and process its body."""
"""
@brief Transform class name and process its body.
@param node ast.ClassDef node.
@return ast.ClassDef Transformed class node.
"""
prev_class = self.current_class
orig_name = node.name
self.current_class = orig_name
@@ -255,7 +298,11 @@ class ClassTransformer(ast.NodeTransformer):
return node
def visit_FunctionDef(self, node: ast.FunctionDef):
"""Transform method name."""
"""
@brief Transform method name.
@param node ast.FunctionDef node.
@return ast.FunctionDef Transformed method node.
"""
if self.current_class and node.name in self.mapping.class_methods.get(self.current_class, {}):
orig_name = node.name
node.name = self.mapping.class_methods[self.current_class][node.name]
@@ -266,7 +313,11 @@ class ClassTransformer(ast.NodeTransformer):
return node
def visit_Attribute(self, node: ast.Attribute):
"""Transform self.method and self.attr references."""
"""
@brief Transform self.method and self.attr references.
@param node ast.Attribute node.
@return ast.Attribute Transformed attribute node.
"""
# Process any child nodes first (for nested attributes)
node.value = self.visit(node.value)
@@ -288,7 +339,12 @@ class ClassTransformer(ast.NodeTransformer):
# Helper function to apply the class mapping transformation
def apply_class_mapping(tree: ast.AST, name_generator) -> ast.AST:
"""Analyze and transform classes consistently."""
"""
@brief Analyze and transform classes consistently.
@param tree Input AST.
@param name_generator Name generator used to create obfuscated identifiers.
@return Tuple[ast.AST, ClassMapping] Transformed AST and the mapping produced.
"""
# First pass: analyze all classes
analyzer = ClassMapAnalyzer(name_generator)
mapping = analyzer.analyze(tree)
+6
View File
@@ -1,3 +1,9 @@
"""
@file transformers/control_flow.py
@brief Control-flow flattening transformer.
@details Converts structured control flow into a state-machine with a while/dispatch
loop to hinder static analysis, and can emit debug telemetry in debug mode.
"""
import ast
import random
from typing import Dict, List, Set, Tuple, Any, Optional
+12
View File
@@ -1,3 +1,10 @@
"""
@file transformers/rename.py
@brief Identifier renaming and string literal encryption transformer.
@details Performs scoped variable/function renaming, consistent class/method/attribute
remapping, and in-place string encryption producing runtime decryption code.
"""
import ast
from utils.encryption import StringEncryptor
from utils.name_gen import NameGenerator
@@ -8,6 +15,11 @@ logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("RenameTransformer")
class RenameTransformer(ast.NodeTransformer):
"""
@brief AST transformer for renaming and string encryption.
@details Maintains scope stacks, global mappings, class method/attribute maps, and
collects key-setup code for runtime decryption. Can emit debug telemetry.
"""
def __init__(self, name_generator, global_var_renames, class_attr_mapping,
primary_key, secondary_key, salt, debug_mode=False):
self.name_generator = name_generator
+7
View File
@@ -1,3 +1,10 @@
"""
@file transformers/symbol_tree.py
@brief Global symbol tree and scope tracking.
@details Builds a hierarchical representation of scopes (module, class, function),
tracks symbols, imports, references, and inheritance; generates rename
mappings consumed by the obfuscation pipeline.
"""
import ast
from typing import Dict, Set, List, Optional, Union, Tuple
import logging