Overview
DeadCodePass is an obfuscation pass that inserts unreachable dead-code branches into procedure bodies to confuse static analysis and decompilers. These branches contain valid-looking code that will never execute, making it harder to understand the actual control flow.
The Dart VM optimizer eliminates these dead branches at runtime, so there is no performance impact on the final application.
Class Definition
lib/src/engine/passes/dead_code/dead_code_pass.dart:12
Constructor Parameters
Maximum number of dead-code branches to insert per procedure. Higher values increase obfuscation but also increase binary size.
How It Works
The pass insertsif (false) { ... } blocks into procedure bodies. Since the condition is always false, these branches are never executed but appear as valid code paths to static analyzers.
Insertion Strategy
Dead branches are inserted before existing statements, up to
maxInsertionsPerProcedure times per procedureRuntime Optimization
The Dart VM’s optimizer detects
if (false) patterns and removes them during compilation, resulting in zero runtime overheadTransformation Example
Before:maxInsertionsPerProcedure = 2):
Configuration
Maximum Insertions
Control how many dead branches are inserted per procedure:Filtering Rules
The pass automatically skips:- Dart SDK libraries (
dart:*procedures) - External packages (packages not matching the project package name)
- Empty procedure bodies (nothing to insert before)
- Non-block bodies (arrow functions, expression bodies)
- Libraries matching exclude patterns (configured via
excludeLibraryUriPatterns)
Methods
run()
- Resolves the
intclass fromdart:core(used for generating dummy code) - Creates a
DeadCodeTransformerwith the configured parameters - Transforms the component by inserting dead branches into procedures
The Dart kernel component to transform
Shared context containing options, symbol table, and name generator
Usage Example
Basic Usage
With PassRunner
Combined Obfuscation Pipeline
Testing
test/engine/passes/dead_code_pass_test.dart:29
Performance Impact
Binary Size
Increases proportionally to
maxInsertionsPerProcedure. Each dead branch adds a small amount to the compiled binary.Runtime Performance
Zero impact. The Dart VM optimizer removes dead branches during compilation, so they never execute.
Use Cases
Reverse Engineering Protection
Makes decompiled code harder to read by adding confusing control flow paths
Static Analysis Confusion
Causes static analysis tools to report false positives or miss actual code paths
Code Structure Obfuscation
Obscures the actual logic flow by interleaving dead code with real code
Intellectual Property Protection
Adds an additional layer of protection for proprietary algorithms
Best Practices
- Start with
maxInsertionsPerProcedure = 1and increase gradually - Monitor binary size impact, especially for mobile applications
- Combine with
RenamePassfor maximum obfuscation effectiveness - Test the obfuscated binary thoroughly to ensure no breakage
- Use in production builds only (keep debug builds unobfuscated)
Related
PassRunner
Orchestrates multiple passes
RenamePass
Rename identifiers to meaningless names
StringEncryptPass
Encrypt string literals with XOR encoding
RefractorEngine
Main obfuscation engine