Skip to content

Hybrid Approaches

At a Glance

Category: Hybrid Analysis Key Tools: Frama-C, Triton, IKOS Maturity: Growing Core Value: Combine the scalability of static analysis with the precision of dynamic analysis to achieve stronger guarantees than either approach alone.

Overview

Static analysis and dynamic analysis each have fundamental trade-offs. Static analysis can reason about all possible program behaviors but must over-approximate, leading to false positives. Dynamic analysis observes concrete executions with high precision but can only cover the paths it actually runs, leaving potential bugs in unexplored code. Hybrid approaches aim to get the best of both worlds by combining these complementary techniques.

The combination takes several forms. Some tools use static analysis to guide dynamic execution (for example, identifying suspicious code paths statically and then generating test inputs to exercise them dynamically. Others use dynamic information to improve static analysis) for example, using runtime profiles to prune infeasible paths from static models. A third category interleaves the two techniques, alternating between symbolic reasoning and concrete execution in what is often called concolic (concrete + symbolic) execution.

The tools in this section represent different points in this design space. Frama-C brings formal verification with optional dynamic validation. Triton provides dynamic symbolic execution for binary analysis. IKOS applies abstract interpretation with mathematical soundness guarantees. Each demonstrates a different strategy for bridging the static-dynamic divide.

Key Tools

Frama-C

Frama-C (Framework for Modular Analysis of C programs) is an open-source platform for analysis of C source code, developed by CEA LIST and Inria in France. It is distinguished by its emphasis on formal methods and its plugin-based architecture that enables multiple analysis techniques to operate on the same codebase.

ACSL Annotations. Frama-C uses the ANSI/ISO C Specification Language (ACSL) for writing formal specifications as code annotations. Developers express function contracts (pre-conditions, post-conditions, and invariants) directly in source code comments using a structured syntax. These annotations serve as the ground truth against which analyses verify the code.

WP Plugin (Weakest Precondition). The WP plugin performs deductive verification, it generates proof obligations from ACSL-annotated code and discharges them using automated theorem provers such as Alt-Ergo, Z3, or CVC5. When all proof obligations are discharged, the code is mathematically proven to satisfy its specification. This provides the strongest correctness guarantees available but requires significant effort in writing and refining annotations.

Value Analysis (Eva). The Eva plugin performs abstract interpretation over C programs, computing an over-approximation of all possible values that each variable can take at each program point. This analysis is sound. if Eva reports that no runtime error can occur, then none will occur on any possible input. Eva can detect division by zero, buffer overflows, and other runtime errors without requiring annotations.

Dynamic Validation. Frama-C's E-ACSL plugin compiles ACSL annotations into runtime checks, enabling dynamic validation of specifications. This hybrid approach allows developers to test specifications against concrete executions before attempting full formal proof, catching specification errors early.

Strengths:

  • Mathematically rigorous formal verification capabilities
  • Plugin architecture allows combining multiple analysis techniques
  • Sound analysis (Eva) provides strong guarantees
  • Active research community with regular publications
  • Open-source (LGPL)

Weaknesses:

  • Significant expertise required for effective use (formal methods background)
  • Annotation burden for full verification can be very high
  • Limited to C (no C++ support)
  • Scalability challenges on very large codebases

Use Cases: Safety-critical software verification (aerospace, nuclear, automotive), formal proof of security properties, research in program verification, analysis of cryptographic implementations.

Community & Maintenance: Developed by CEA LIST and Inria with regular annual releases. Active research community with annual user workshops. Used in industrial contexts for safety-critical software certification.


Triton

Triton is a dynamic binary analysis library that provides dynamic symbolic execution (DSE), taint analysis, and an intermediate representation (IR) for binary code. Developed initially at Quarkslab, Triton combines runtime observation with symbolic reasoning to enable powerful binary analysis workflows.

Dynamic Symbolic Execution. Triton executes a program concretely while simultaneously building symbolic expressions that represent the constraints on program variables along the execution path. By collecting these path constraints and solving them with an SMT solver (typically Z3), Triton can generate new inputs that drive execution down previously unexplored paths. This technique (also known as concolic execution) systematically explores program behavior without requiring source code.

Taint Analysis. Triton's taint engine tracks data flow at the instruction level, marking registers and memory locations that are influenced by user-controlled input. This helps researchers identify which inputs affect which computations; critical for vulnerability analysis and exploit development.

Python API. Triton exposes its full functionality through a Python API, making it accessible for scripting and prototyping. Researchers can write Python scripts that combine Triton's symbolic execution, taint tracking, and instruction-level analysis to build custom analysis pipelines.

Strengths:

  • Combines concrete and symbolic execution for thorough path exploration
  • Works on binaries without source code
  • Rich Python API for scripting custom analyses
  • Supports x86, x86-64, ARM32, and AArch64
  • Open-source (Apache 2.0)

Weaknesses:

  • Path explosion limits scalability on complex programs
  • SMT solver timeouts on complex constraints
  • Requires expertise in binary analysis and symbolic execution concepts
  • Smaller community compared to Frida or Angr

Use Cases: Binary vulnerability analysis, automated exploit generation, CTF challenges, reverse engineering of proprietary software, deobfuscation.

Community & Maintenance: Open-source with contributions from Quarkslab and the broader security research community. Active development with regular updates.


IKOS

IKOS (Inference Kernel for Open Static Analyzers) is an abstract interpretation-based static analyzer for C/C++ developed by NASA's Jet Propulsion Laboratory. It is designed to provide sound analysis, guaranteeing that if IKOS reports no bugs, then the analyzed class of bugs truly cannot occur.

IKOS works by translating C/C++ code into an intermediate representation and then computing abstract fixpoints using numerical abstract domains (intervals, octagons, polyhedra). It can detect buffer overflows, integer overflows, null pointer dereferences, division by zero, and other runtime errors. The tool is particularly relevant for safety-critical software where soundness guarantees are essential.

Strengths:

  • Sound analysis; no false negatives for modeled bug classes
  • Developed by NASA for safety-critical applications
  • Supports C and C++ via LLVM frontend
  • Open-source (custom NASA license)

Weaknesses:

  • Can produce false positives due to over-approximation
  • Limited scalability on very large codebases
  • Smaller community and less documentation than commercial tools
  • Narrow focus on numerical properties and runtime errors

Use Cases: Safety-critical software verification, NASA flight software analysis, research in abstract interpretation.

Community & Maintenance: Developed by NASA's Software Verification and Validation team. Open-source on GitHub. Updates are periodic and aligned with NASA's internal needs.

Practical Hybrid Workflows

Beyond specialized tools, the most impactful hybrid approach in practice is the static pre-filter, dynamic validation workflow. This pattern uses static analysis to identify candidate vulnerabilities quickly and then employs dynamic techniques to confirm or reject each finding.

Step 1: Static Triage. Run a fast static analyzer (e.g., Semgrep or CodeQL) to identify code locations that match known vulnerability patterns. This step produces a list of candidate findings, some of which will be true positives and some false positives.

Step 2: Dynamic Confirmation. For each candidate, generate test inputs (manually or via fuzzing) that exercise the suspicious code path. Run the program under sanitizers (ASan, UBSan) or Valgrind to determine whether the suspected bug manifests at runtime. Candidates that trigger sanitizer reports are confirmed true positives.

Step 3: Prioritization. Rank confirmed findings by severity and exploitability. Use taint analysis (Triton, Frida) to assess whether attacker-controlled input can reach the vulnerable code path.

This workflow dramatically reduces the false positive burden of static analysis while retaining its scalability advantage. Teams that adopt it report spending less time on triage and more time on remediation.

Tooling Integration Gap

Despite the clear benefits of hybrid workflows, few tools automate the full static-to-dynamic pipeline. Most teams stitch together separate tools with custom scripts. An integrated platform that seamlessly combines static scanning with dynamic confirmation (and automatically generates the test inputs needed for validation) represents a significant market opportunity. See Hybrid/Symbolic Fuzzing for related work on automated input generation.


tags: - glossary


Glossary

Term Definition
AFL American Fuzzy Lop, coverage-guided fuzzer
ASan AddressSanitizer, memory error detector
CVE Common Vulnerabilities and Exposures
AFL++ Community-maintained successor to AFL, the de facto standard coverage-guided fuzzer
AEG Automatic Exploit Generation, automated creation of working exploits from vulnerability information
ANTLR ANother Tool for Language Recognition, parser generator used by grammar-aware fuzzers like Superion
AST Abstract Syntax Tree, tree representation of source code structure used by static analyzers
BOF Buffer Overflow, writing data beyond allocated memory bounds, a common memory safety vulnerability
CFG Control Flow Graph, directed graph representing all possible execution paths through a program
CGC Cyber Grand Challenge, DARPA competition for autonomous vulnerability detection and patching
ClusterFuzz Google's distributed fuzzing infrastructure that powers OSS-Fuzz
CodeQL GitHub's query-based static analysis engine that treats code as a queryable database
Concolic Concrete + Symbolic, execution that runs concrete values while tracking symbolic constraints
Corpus Collection of seed inputs used by a coverage-guided fuzzer as the basis for mutation
Coverity Synopsys commercial static analysis platform with deep interprocedural analysis
CPG Code Property Graph, unified representation combining AST, CFG, and data-flow graph, used by Joern
CVSS Common Vulnerability Scoring System, standard for rating vulnerability severity
CWE Common Weakness Enumeration, categorization of software weakness types
DAST Dynamic Application Security Testing, testing running applications for vulnerabilities
DBI Dynamic Binary Instrumentation, modifying program behavior at runtime without recompilation
DFG Data Flow Graph, graph representing how data values propagate through a program
DPA Differential Power Analysis, extracting cryptographic keys by analyzing power consumption variations
Frida Dynamic instrumentation toolkit for injecting scripts into running processes
Harness Glue code connecting a fuzzer to its target, defining how fuzzed input is delivered
HWASAN Hardware-assisted AddressSanitizer, ARM-based variant of ASan with lower overhead
IAST Interactive Application Security Testing, combines elements of SAST and DAST during testing
Infer Meta's open-source static analyzer based on separation logic and bi-abduction
KLEE Symbolic execution engine built on LLVM for automatic test generation
LLM Large Language Model, neural network trained on text/code, used for bug detection and code generation
LSAN LeakSanitizer, detector for memory leaks, often used alongside AddressSanitizer
Meltdown CPU vulnerability exploiting out-of-order execution to read kernel memory from user space
MITRE Non-profit organization that maintains CVE, CWE, and ATT&CK frameworks
MSan MemorySanitizer, detector for reads of uninitialized memory
NVD National Vulnerability Database, NIST-maintained repository of vulnerability data
NIST National Institute of Standards and Technology, US agency maintaining security standards and NVD
OSS-Fuzz Google's free continuous fuzzing service for open-source software
OWASP Open Worldwide Application Security Project, community producing security guides and tools
RCE Remote Code Execution, vulnerability allowing an attacker to run arbitrary code on a target system
RL Reinforcement Learning, ML paradigm where agents learn through reward-based feedback
S2E Selective Symbolic Execution, whole-system analysis platform combining QEMU with KLEE
SARIF Static Analysis Results Interchange Format, standard for exchanging static analysis findings
SAST Static Application Security Testing, analyzing source code for vulnerabilities without execution
SCA Software Composition Analysis, identifying known vulnerabilities in third-party dependencies
Seed Initial input provided to a fuzzer as the starting point for mutation
Semgrep Lightweight open-source static analysis tool using pattern-matching rules
Side-channel Attack vector exploiting physical implementation artifacts rather than algorithmic flaws
SMT Satisfiability Modulo Theories, solver used by symbolic execution to find inputs satisfying path constraints
Spectre Family of CPU vulnerabilities exploiting speculative execution to leak data across security boundaries
SQLi SQL Injection, injecting malicious SQL into queries via unsanitized user input
SSRF Server-Side Request Forgery, tricking a server into making requests to unintended destinations
SymCC Compilation-based symbolic execution tool that is 2--3 orders of magnitude faster than KLEE
Taint analysis Tracking the flow of untrusted data from sources to security-sensitive sinks
TOCTOU Time-of-Check-Time-of-Use, race condition between validating a resource and using it
TSan ThreadSanitizer, detector for data races in multithreaded programs
UAF Use-After-Free, accessing memory after it has been deallocated
UBSan UndefinedBehaviorSanitizer, detector for undefined behavior in C/C++
Valgrind Dynamic binary instrumentation framework for memory debugging and profiling
XSS Cross-Site Scripting, injecting malicious scripts into web pages viewed by other users
Fine-tuning Adapting a pre-trained ML model to a specific task using additional training data
Abstract interpretation Mathematical framework for approximating program behavior using abstract domains
Dataflow analysis Tracking how values propagate through a program to detect bugs like taint violations