-
Notifications
You must be signed in to change notification settings - Fork 758
Architecture Overview
Understanding the internal architecture and design principles of Qiling Framework.
┌─────────────────────────────────────────────────────────────┐
│ User Application │
├─────────────────────────────────────────────────────────────┤
│ Qiling Framework API │
├─────────────────┬─────────────────┬─────────────────────────┤
│ Extensions │ Debugging │ Utilities │
│ - AFL Fuzzing │ - QDB │ - Coverage │
│ - Tracing │ - GDB Server │ - Sanitizers │
│ - Coverage │ - Breakpoints │ - Reporting │
├─────────────────┼─────────────────┼─────────────────────────┤
│ │ Core Qiling │ │
│ Hook System │ Engine │ Memory Manager │
│ - Code Hooks │ - Emulation │ - Memory Mapping │
│ - Memory Hooks │ - State Mgmt │ - Heap Management │
│ - API Hooks │ - Execution │ - Permission Control │
├─────────────────┼─────────────────┼─────────────────────────┤
│ Architecture │ OS Layer │ Loader │
│ - x86/x64 │ - Linux │ - ELF │
│ - ARM/ARM64 │ - Windows │ - PE │
│ - MIPS │ - macOS │ - Mach-O │
│ - RISC-V │ - UEFI/MCU │ - Raw Binary │
├─────────────────┴─────────────────┴─────────────────────────┤
│ Unicorn Engine │
├─────────────────────────────────────────────────────────────┤
│ Hardware/Host Operating System │
└─────────────────────────────────────────────────────────────┘
The central orchestrator that coordinates all components:
Location: qiling/core.py
class Qiling:
"""Main emulation engine
Coordinates all subsystems:
- Architecture abstraction
- Operating system emulation
- Memory management
- Binary loading
- Hook management
"""Key Responsibilities:
- Initialize and coordinate all subsystems
- Manage emulation lifecycle (start, stop, state)
- Provide unified API interface
- Handle cross-component communication
Abstracts CPU architectures and provides uniform interface:
Location: qiling/arch/
class QlArch:
"""Base architecture abstraction
Provides:
- Register management
- Instruction set abstraction
- Calling convention handling
- Assembly/disassembly
"""Supported Architectures:
- Intel: x86, x86_64, 8086
- ARM: ARM32, ARM64 (AArch64), Cortex-M
- RISC: RISC-V 32/64-bit
- MIPS: MIPS32
- PowerPC: PPC
Emulates target operating system environments:
Location: qiling/os/
class QlOs:
"""Base OS abstraction
Handles:
- System call emulation
- Process/thread management
- File system abstraction
- API function emulation
"""Supported Systems:
- POSIX: Linux, macOS, FreeBSD, QNX
- Windows: Win32/Win64 API emulation
- Firmware: UEFI, MCU (bare metal)
- Raw: Direct binary/shellcode execution
Sophisticated memory subsystem with multiple capabilities:
Location: qiling/os/memory.py
class QlMemoryManager:
"""Advanced memory management
Features:
- Virtual memory mapping
- Permission control
- Heap management
- Memory forensics
- Pattern searching
"""Memory Features:
- Virtual Memory: Full virtual address space emulation
- Permissions: Read/Write/Execute control
- Heap Management: malloc/free emulation with debugging
- Memory Mapping: File and anonymous mappings
- MMIO Support: Memory-mapped I/O for hardware emulation
Handles multiple binary formats and loading strategies:
Location: qiling/loader/
class QlLoader:
"""Multi-format binary loader
Supports:
- ELF (Linux/Unix)
- PE (Windows)
- Mach-O (macOS)
- Raw binary blobs
"""Loading Capabilities:
- Dynamic Linking: Automatic library resolution
- Relocations: Address space layout handling
- Import/Export: Symbol resolution
- Debug Information: Symbol table processing
Powerful instrumentation and analysis framework:
Location: qiling/core_hooks.py
class QlCoreHooks:
"""Comprehensive hooking system
Hook Types:
- Instruction-level hooks
- Memory access hooks
- Function call hooks
- API/syscall hooks
"""Hook Categories:
- Execution Hooks: Code, block, address-specific
- Memory Hooks: Read, write, fetch, invalid access
- API Hooks: Function interception and replacement
- System Hooks: Interrupts, exceptions, syscalls
# 1. Architecture Detection/Selection
arch = QlArch.create(archtype, endian)
# 2. OS Layer Initialization
os = QlOs.create(ostype, arch)
# 3. Memory Manager Setup
memory = QlMemoryManager(arch, os)
# 4. Loader Initialization
loader = QlLoader.create(binary_format)
# 5. Core Engine Assembly
ql = Qiling(arch, os, memory, loader)# 1. Binary Analysis
loader.analyze_binary(binary_path)
# 2. Memory Layout Planning
memory.plan_address_space(loader.segments)
# 3. Binary Loading
loader.load_binary_to_memory(memory)
# 4. Library Loading
loader.load_dependencies(rootfs)
# 5. Symbol Resolution
loader.resolve_symbols()# 1. Initial State Setup
os.setup_initial_state()
arch.setup_initial_registers()
# 2. Hook Installation
hook_system.install_hooks()
# 3. Execution Loop
while not_stopped:
# Execute instruction via Unicorn
uc.emu_step()
# Process hooks
hook_system.process_hooks()
# Handle system calls
os.handle_syscalls()
# Check stop conditions
check_stop_conditions()Each component is independently replaceable:
# Custom architecture implementation
class MyCustomArch(QlArch):
def __init__(self, ql):
super().__init__(ql)
# Custom implementation
# Plugin system
ql.arch = MyCustomArch(ql)Rich plugin and extension system:
# Custom OS implementation
class MyCustomOS(QlOs):
def handle_syscall(self, syscall_num):
# Custom syscall handling
pass
# Extension integration
from qiling.extensions.coverage import QlCoverage
coverage = QlCoverage(ql)Optimized for speed and memory efficiency:
- Lazy Loading: Components loaded on demand
- Caching: Instruction and library caching
- Native Speed: Unicorn engine provides near-native performance
- Memory Efficient: Smart memory management with copy-on-write
Built with security analysis in mind:
- Isolation: Complete process isolation
- Sandboxing: File system and network isolation
- Monitoring: Comprehensive instrumentation
- Safe Defaults: Secure configuration by default
# Architecture provides memory layout requirements
arch.setup_memory_layout(memory)
# Memory manager respects architecture constraints
memory.map_with_arch_constraints(addr, size, arch.alignment)
# Register access through architecture layer
value = arch.regs.read("rax")
arch.regs.write("rsp", stack_pointer)# OS provides loading context
loading_context = os.get_loading_context()
# Loader uses OS-specific loading logic
loader.load_with_context(loading_context)
# OS manages loaded modules
os.register_loaded_module(loader.main_module)# Hook system integrates with execution
def my_hook(ql, address, size):
# Hook receives full Qiling context
registers = ql.arch.regs.save()
memory_data = ql.mem.read(address, size)
# Hooks can modify execution state
def modification_hook(ql):
ql.arch.regs.rax = 0x1337 # Modify register
ql.mem.write(0x1000, b"patched") # Patch memoryComplete emulation state can be saved and restored:
# Save complete state
state = {
'memory': ql.mem.save(),
'registers': ql.arch.regs.save(),
'os_state': ql.os.save(),
'loader_state': ql.loader.save()
}
# Restore state
ql.mem.restore(state['memory'])
ql.arch.regs.restore(state['registers'])
ql.os.restore(state['os_state'])
ql.loader.restore(state['loader_state'])Native support for multi-threaded applications:
# Thread-aware emulation
ql = Qiling(['threaded_app'], 'rootfs', multithread=True)
# Thread-specific hooks
def thread_hook(ql):
thread_id = ql.os.current_thread.id
print(f"Hook in thread {thread_id}")
ql.hook_code(thread_hook)Support for microcontroller and embedded systems:
# MCU emulation with hardware peripherals
ql = Qiling(code=firmware,
archtype=QL_ARCH.CORTEX_M,
ostype=QL_OS.MCU,
profile="stm32f103.ql")
# Hardware peripheral access
ql.hw.gpio.set_pin(1, True)
uart_data = ql.hw.uart.read()Seamless integration with analysis tools:
# Coverage collection
from qiling.extensions.coverage import QlCoverage
cov = QlCoverage(ql)
# Fuzzing integration
from qiling.extensions.afl import ql_afl_fuzz
ql_afl_fuzz(ql, input_file, place_input, exits)
# Debugging integration
ql.debugger = "gdb:localhost:9999"- Near-native: 10-50% of native execution speed
- Architecture dependent: x86/ARM faster than exotic architectures
- Workload dependent: System call heavy workloads slower
- Base overhead: ~50-100MB for basic emulation
- Scales with: Target process memory usage
- Optimizations: Library caching, lazy loading
- Single process: Handles complex applications
- Multiple instances: Can run many concurrent emulations
- Resource limits: Configurable memory and execution limits
Multiple ways to extend Qiling:
- Custom Architecture: Implement new CPU architectures
- Custom OS: Add new operating system support
- Custom Loader: Support new binary formats
- Extensions: Add analysis capabilities
- Hooks: Runtime instrumentation
Consistent API patterns across components:
# All major components follow similar patterns
component.save() # Save state
component.restore() # Restore state
component.setup() # Initialize
component.cleanup() # CleanupComprehensive testing infrastructure:
- Unit Tests: Component-level testing
- Integration Tests: Cross-component testing
- Regression Tests: Prevent breaking changes
- Performance Tests: Monitor performance characteristics
This architecture enables Qiling to be both powerful and flexible, supporting everything from simple malware analysis to complex firmware research and vulnerability discovery.
For implementation details, see:
- API Reference - Complete API documentation
- Contributing - Development guidelines
- Custom Extensions - Building custom components
- Home
- Getting Started
- Core Concepts
- Usage
- Features
- Tutorials
- Development
- Resources