Strip Debug Symbols
| Plan | Platforms | MASVS |
|---|---|---|
| Team | iOS | MASVS-RESILIENCE-3 |
Overview
StripDebugSymbols removes debug symbols, function names, variable names, and DWARF debug information from compiled iOS binaries during the build pipeline. This control operates at build time to eliminate identifying metadata from the shipped binary, making reverse engineering significantly more difficult while maintaining full runtime functionality.
The control applies the strip command to all Mach-O binaries in the application bundle (main executable, frameworks, dynamic libraries, and app extensions) after compilation but before packaging. Debug symbols are never used at runtime, so their removal has zero performance or functional impact.
How It Works
StripDebugSymbols is a build-time control that runs during AppTego protected build processing after the application has been compiled but before it is packaged into an IPA. The control scans the extracted .app bundle and identifies all Mach-O binaries:
- Main executable (
AppName.app/AppName) - Framework binaries (
Frameworks/*.framework/*) - Dynamic libraries (
Frameworks/*.dylib) - App extension binaries (
PlugIns/*.appex/*)
For each binary, the control invokes the macOS strip command with the following strategy:
- Primary Method (
strip -x):
- Removes local symbols (function names, variable names, file paths)
- Strips DWARF debug information (line numbers, type definitions, source references)
- Preserves global/exported symbols required for dynamic linking
- Maintains Objective-C and Swift runtime metadata needed for reflection
- Fallback Method (
strip -S):
- Applied if
strip -xfails (rare, typically with bitcode-enabled binaries) - Removes only debug symbols, leaving the symbol table intact
- Less aggressive but still eliminates DWARF information
The stripped binaries are written back to the .app bundle, replacing the originals. No debug symbols or dSYM files are included in the final IPA delivered to the App Store or distributed to end users.
Build Pipeline Integration
The control runs alongside other iOS obfuscation and metadata-reduction controls before signing and packaging. MobileDefender production frameworks are also shipped without debug symbols.
Threats Mitigated
- Reverse Engineering via Symbol Tables: Without function and variable names, attackers cannot use tools like
nm,otool, orclass-dumpto extract meaningful API structures, class hierarchies, or method signatures from the binary. - Source Code Path Disclosure: Debug symbols often contain absolute file paths from the build environment (e.g.,
/Users/developer/SecretProject/CreditCardHandler.m), revealing internal project structure and file organization. Stripping eliminates this metadata leakage. - Debugging with Standard Tools: Debuggers rely on debug symbols to map machine code back to source lines, set breakpoints by function name, and inspect variables. Stripped binaries cannot be symbolicated in real-time debugging sessions.
- Class and Method Name Harvesting: While Objective-C and Swift runtime metadata remains intact (necessary for reflection and dynamic dispatch), the control removes C/C++ symbols and file-level metadata that would otherwise aid static analysis.
Caveats
Crash Symbolication Requires dSYM Upload
Crash logs from stripped binaries contain only memory addresses, not human-readable function names or file/line numbers. To symbolicate these crashes, you must:
- Retain dSYM files generated during the Xcode archive process
- Upload dSYM files to your crash reporting service (Firebase Crashlytics, Sentry, Bugsnag, etc.)
- Match dSYM UUIDs to crash reports—each build produces a unique UUID embedded in both the binary and the dSYM
Important: The MobileDefender build pipeline does not include dSYM files in the final IPA. You must upload them separately to your crash reporting backend immediately after each build.
Objective-C and Swift Runtime Metadata Preserved
The control does not remove:
- Objective-C class names, method selectors, and protocol definitions (required for
objc_msgSenddynamic dispatch) - Swift type metadata and protocol conformance tables (required for generics and existentials)
- Exported symbols required for dynamic linking between frameworks and the main executable
Attackers can still use tools like class-dump or swift-demangle to extract high-level class structures from stripped binaries. For deeper obfuscation of class names, consider enabling ObfuscateClassNames (automatically included when StripDebugSymbols is enabled).
Build-Time Only
This control operates during the build pipeline and cannot be toggled at runtime. Once an IPA is built with debug symbols stripped, they cannot be restored. Enabling or disabling the control requires rebuilding the application.
Simulator Builds Unaffected
Debug symbols remain intact in simulator-focused development builds to preserve development workflow. Production protected builds are stripped when this control is enabled.
Support Matrix
| Platform | Minimum Version | Notes |
|---|---|---|
| iOS | iOS 12.0+ | Supported. Applied during protected build processing. |
| Android | — | Not supported. Android apps use ProGuard/R8 for bytecode shrinking and obfuscation. |
Related Controls
- ObfuscateClassNames (TEAM): Replaces Objective-C class names with randomized strings of equal length, further obfuscating the binary structure. Automatically enabled when StripDebugSymbols is configured.
- StripBitcode (TEAM): Removes embedded LLVM bitcode from binaries, reducing IPA size and eliminating intermediate representation metadata.
- StripNSLog (TEAM): NOPs out
NSLogcalls in compiled binaries, preventing debug logging from executing in production builds. - AppTamperCheck (TEAM): Detects binary modifications at runtime via SHA-256 integrity checks. Works in conjunction with StripDebugSymbols to harden against tampering.
How to Enable the Control
Navigate to Code Obfuscation from the AppTego portal, and expand the Metadata Reduction section. Under this section you will find the Strip Debug Symbols control. Click Enable to apply it to the next protected build.
API Configuration Example
{
"StripDebugSymbols": {
"protection": true
}
}
Configuration Keys
protection: true— Enable debug symbol stripping in the build pipelineprotection: false— Disable stripping; binaries retain debug symbols (default for development builds)