Comprehensive application security can only be ensured if all code that it is going to execute is protected: any unprotected code, either from libraries or the application, becomes a potential attack surface. Compilers contain extensive suites of tools to aid in this, but require source availability that is often infeasible. Existing static and dynamic binary rewriting techniques that retrofit for security either lack in code coverage or soundness, or incur very high performance overhead.

We present a case for adopting hybrid static-dynamic mechanisms to ensure comprehensive security for binaries, providing sound and practical solutions. We highlight the limitations of existing hybrid tools in their use for security purposes, and provide insights to re-architect them to achieve comprehensive security. To demonstrate this in practice, we provide a framework implementation, Janitizer, that enables sound and comprehensive code coverage for entire applications. We present hybrid binary implementations for two important classes of security schemes; a memory sanitizer and a control flow integrity scheme. These implementations provide comprehensive code coverage equivalent to that of high-overhead dynamic techniques, while maintaining performance levels of low-coverage static techniques.