Skip to content

Contributing

xwings edited this page Jul 6, 2025 · 2 revisions

Contributing to Qiling Framework

Welcome to the Qiling Framework community! This guide will help you contribute effectively to this world-class open-source emulation framework.

Overview

Qiling Framework thrives on community contributions. Whether you're fixing bugs, adding features, improving documentation, or helping other users, your contributions make Qiling better for everyone.

Ways to Contribute

  • 🐛 Bug Reports & Fixes
  • New Features & Enhancements
  • 📚 Documentation Improvements
  • 🧪 Testing & Quality Assurance
  • 🎯 Performance Optimizations
  • 🌍 Platform Support Extensions
  • 🔧 Developer Tools & Utilities
  • 💬 Community Support

Getting Started

Prerequisites

Development Environment:

# Required tools
git --version          # Git 2.20+
python --version       # Python 3.8+
pip --version          # Latest pip

# Development dependencies
sudo apt install build-essential cmake  # Linux
# or
brew install cmake                       # macOS

Setting Up Development Environment:

# 1. Fork the repository on GitHub
# 2. Clone your fork
git clone https://github.com/YOUR_USERNAME/qiling.git
cd qiling

# 3. Add upstream remote
git remote add upstream https://github.com/qilingframework/qiling.git

# 4. Create development environment
python -m venv qiling-dev
source qiling-dev/bin/activate  # Linux/macOS
# or qiling-dev\Scripts\activate  # Windows

# 5. Install in development mode
pip install -e .
pip install -r requirements-dev.txt  # If available

# 6. Install pre-commit hooks
pip install pre-commit
pre-commit install

Development Workflow

Standard Git Workflow:

# 1. Sync with upstream
git fetch upstream
git checkout master
git merge upstream/master

# 2. Create feature branch
git checkout -b feature/your-feature-name
git checkout -b fix/issue-number
git checkout -b docs/improvement-description

# 3. Make your changes
# ... code, test, commit ...

# 4. Push and create PR
git push origin feature/your-feature-name
# Create Pull Request on GitHub

Code Contribution Guidelines

Code Style and Standards

Python Code Style:

# Follow PEP 8 with these specifications:
# - Line length: 88 characters (Black formatter)
# - Use type hints for new code
# - Comprehensive docstrings for public APIs

from typing import Optional, Union, List, Dict, Any
from qiling import Qiling
from qiling.const import QL_ARCH, QL_OS

class ExampleAnalyzer:
    """Example analyzer following Qiling coding standards.
    
    This class demonstrates proper code style, documentation,
    and type annotations for Qiling Framework contributions.
    
    Args:
        ql: Qiling instance to analyze
        config: Optional configuration dictionary
        
    Example:
        >>> analyzer = ExampleAnalyzer(ql, {"verbose": True})
        >>> results = analyzer.analyze()
    """
    
    def __init__(self, ql: Qiling, config: Optional[Dict[str, Any]] = None) -> None:
        self.ql = ql
        self.config = config or {}
        self._results: List[Dict[str, Any]] = []
        
    def analyze(self, timeout: Optional[int] = None) -> Dict[str, Any]:
        """Perform analysis on the Qiling instance.
        
        Args:
            timeout: Optional timeout in seconds
            
        Returns:
            Dictionary containing analysis results
            
        Raises:
            QilingAnalysisError: If analysis fails
        """
        try:
            # Implementation here
            return {"status": "success", "results": self._results}
        except Exception as e:
            raise QilingAnalysisError(f"Analysis failed: {e}") from e
    
    def _internal_method(self) -> bool:
        """Private methods start with underscore."""
        return True

# Function style
def analyze_binary(
    binary_path: str, 
    rootfs_path: str,
    *,  # Force keyword-only arguments
    architecture: Optional[QL_ARCH] = None,
    os_type: Optional[QL_OS] = None,
    verbose: bool = False
) -> Dict[str, Any]:
    """Analyze binary with Qiling Framework.
    
    Args:
        binary_path: Path to binary file
        rootfs_path: Path to root filesystem
        architecture: Target architecture (auto-detected if None)
        os_type: Target OS type (auto-detected if None)  
        verbose: Enable verbose output
        
    Returns:
        Analysis results dictionary
        
    Example:
        >>> results = analyze_binary("malware.exe", "rootfs/", verbose=True)
        >>> print(results["execution_time"])
    """
    # Implementation
    pass

Code Quality Tools:

# Format code with Black
black qiling/ tests/ examples/

# Sort imports with isort
isort qiling/ tests/ examples/

# Type checking with mypy
mypy qiling/

# Linting with flake8
flake8 qiling/ tests/

# Security checking with bandit
bandit -r qiling/

Testing Requirements

Test Structure:

# tests/test_new_feature.py
import pytest
import tempfile
import os
from qiling import Qiling
from qiling.const import QL_ARCH, QL_OS
from qiling.exception import QilingError

class TestNewFeature:
    """Test suite for new feature implementation."""
    
    @pytest.fixture
    def sample_binary(self):
        """Provide sample binary for testing."""
        # Create or return path to test binary
        return "tests/samples/x8664_hello"
    
    @pytest.fixture  
    def rootfs_path(self):
        """Provide rootfs path for testing."""
        return "tests/rootfs/x8664_linux"
    
    def test_basic_functionality(self, sample_binary, rootfs_path):
        """Test basic functionality works correctly."""
        ql = Qiling([sample_binary], rootfs_path)
        
        # Test your feature
        result = ql.your_new_feature()
        
        assert result is not None
        assert isinstance(result, dict)
        assert "status" in result
    
    def test_error_handling(self, rootfs_path):
        """Test proper error handling."""
        with pytest.raises(QilingError):
            ql = Qiling(["nonexistent_file"], rootfs_path)
            ql.your_new_feature()
    
    def test_edge_cases(self, sample_binary, rootfs_path):
        """Test edge cases and boundary conditions."""
        ql = Qiling([sample_binary], rootfs_path)
        
        # Test with empty input
        result = ql.your_new_feature("")
        assert result["status"] == "empty_input"
        
        # Test with large input
        large_input = "A" * 10000
        result = ql.your_new_feature(large_input)
        assert result["status"] == "success"
    
    @pytest.mark.parametrize("arch,os_type", [
        (QL_ARCH.X86, QL_OS.LINUX),
        (QL_ARCH.X8664, QL_OS.LINUX),
        (QL_ARCH.ARM, QL_OS.LINUX),
    ])
    def test_multiple_architectures(self, arch, os_type):
        """Test feature across multiple architectures."""
        # Use shellcode for architecture testing
        shellcode = b'\x90\x90\x90\x90'  # NOP sled
        ql = Qiling(code=shellcode, archtype=arch, ostype=os_type)
        
        result = ql.your_new_feature()
        assert result["architecture"] == arch
    
    def test_performance(self, sample_binary, rootfs_path):
        """Test performance requirements."""
        import time
        
        ql = Qiling([sample_binary], rootfs_path)
        
        start_time = time.time()
        result = ql.your_new_feature()
        end_time = time.time()
        
        # Feature should complete within reasonable time
        assert (end_time - start_time) < 5.0  # 5 seconds max
        assert result["execution_time"] < 5.0

# Integration tests
class TestIntegration:
    """Integration tests for new feature."""
    
    def test_with_existing_features(self, sample_binary, rootfs_path):
        """Test integration with existing Qiling features."""
        ql = Qiling([sample_binary], rootfs_path)
        
        # Test with hooks
        hook_called = False
        def test_hook(ql, address, size):
            nonlocal hook_called
            hook_called = True
        
        ql.hook_code(test_hook)
        result = ql.your_new_feature()
        
        assert hook_called
        assert result["hooks_active"] == True

Running Tests:

# Run all tests
pytest

# Run specific test file
pytest tests/test_new_feature.py

# Run with coverage
pytest --cov=qiling tests/

# Run performance tests
pytest -m performance

# Run tests for specific architecture
pytest -k "x8664"

Documentation Standards

Code Documentation:

def complex_analysis_function(
    ql: Qiling,
    analysis_type: str,
    options: Dict[str, Any]
) -> Dict[str, Any]:
    """Perform complex analysis on Qiling instance.
    
    This function implements advanced analysis techniques for binary
    emulation, supporting multiple analysis types and configurations.
    
    Args:
        ql: Initialized Qiling instance
        analysis_type: Type of analysis to perform. Supported types:
            - "behavioral": Behavioral analysis
            - "static": Static analysis  
            - "dynamic": Dynamic analysis
            - "hybrid": Combined static + dynamic
        options: Analysis configuration options:
            - timeout (int): Analysis timeout in seconds (default: 60)
            - depth (int): Analysis depth level (1-10, default: 5)
            - output_format (str): Output format ("json", "xml", "text")
            - enable_hooks (bool): Enable API hooking (default: True)
    
    Returns:
        Dictionary containing analysis results with the following structure:
        {
            "status": "success" | "failed" | "timeout",
            "analysis_type": str,
            "execution_time": float,
            "results": {
                "api_calls": List[Dict],
                "memory_accesses": List[Dict], 
                "coverage": Dict,
                "artifacts": List[str]
            },
            "metadata": {
                "qiling_version": str,
                "timestamp": str,
                "configuration": Dict
            }
        }
    
    Raises:
        QilingAnalysisError: If analysis configuration is invalid
        QilingTimeoutError: If analysis exceeds timeout
        QilingMemoryError: If insufficient memory for analysis
    
    Example:
        >>> ql = Qiling(["malware.exe"], "rootfs/")
        >>> options = {"timeout": 120, "depth": 7}
        >>> results = complex_analysis_function(ql, "behavioral", options)
        >>> print(f"Found {len(results['results']['api_calls'])} API calls")
        
    Note:
        This function requires significant memory for complex analyses.
        Consider using streaming mode for large binaries.
        
    See Also:
        - simple_analysis_function(): For basic analysis needs
        - streaming_analysis(): For memory-efficient analysis
        
    .. versionadded:: 1.5.0
    .. versionchanged:: 1.6.0
       Added hybrid analysis support
    """
    # Implementation here
    pass

Wiki Documentation:

# New Feature Documentation

## Overview

Brief description of the new feature, its purpose, and benefits.

## Installation

Any additional installation steps required for the feature.

## Basic Usage

### Simple Example
\`\`\`python
from qiling import Qiling

ql = Qiling(["binary"], "rootfs/")
result = ql.new_feature()
print(result)
\`\`\`

### Advanced Example
\`\`\`python
# More complex usage example
\`\`\`

## API Reference

Detailed API documentation with parameters and return values.

## Configuration

Configuration options and their effects.

## Performance Considerations  

Performance implications and optimization tips.

## Troubleshooting

Common issues and solutions.

## Examples

Real-world usage examples and case studies.

Feature Development Process

Planning Phase

Feature Proposal:

  1. Create GitHub Issue: Describe the feature with use cases
  2. Design Discussion: Engage with maintainers and community
  3. API Design: Define the public API interface
  4. Implementation Plan: Break down into manageable tasks

Design Document Template:

# Feature Design: [Feature Name]

## Problem Statement
What problem does this feature solve?

## Proposed Solution
High-level description of the solution.

## API Design
```python
# Proposed API
def new_feature_api():
    pass

Implementation Details

Technical implementation approach.

Testing Strategy

How will this feature be tested?

Documentation Plan

What documentation needs to be created/updated?

Migration Guide

Any breaking changes or migration steps.

Alternatives Considered

Other approaches that were considered and why they were rejected.


### Implementation Phase

**Development Checklist:**
- [ ] Feature implementation
- [ ] Comprehensive tests (unit + integration)
- [ ] Performance benchmarks
- [ ] Documentation updates
- [ ] Example code
- [ ] Backward compatibility check
- [ ] Security review (if applicable)

**Code Review Guidelines:**
- Keep pull requests focused and manageable
- Write clear commit messages
- Include tests for all new functionality
- Update documentation alongside code changes
- Ensure CI/CD passes before requesting review

### Quality Assurance

**Pre-submission Checklist:**
```bash
# 1. Code formatting and linting
black .
isort .
flake8 .

# 2. Type checking
mypy qiling/

# 3. Security scanning
bandit -r qiling/

# 4. Test suite
pytest --cov=qiling

# 5. Performance regression tests
python benchmarks/performance_test.py

# 6. Documentation build
cd docs && make html

# 7. Integration tests
pytest tests/integration/

Platform and Architecture Support

Adding New Architecture Support

# qiling/arch/new_arch.py
from qiling.arch.arch import QlArch
from qiling.const import QL_ARCH

class QlArchNEWARCH(QlArch):
    """Support for NEW_ARCH architecture."""
    
    def __init__(self, ql):
        super().__init__(ql)
        self.type = QL_ARCH.NEW_ARCH
        self.bits = 32  # or 64
        self.big_endian = False  # or True
        
    def setup_register_table(self):
        """Set up architecture-specific register table."""
        self.ql_reg_table = {
            # Map register names to indices
            "r0": 0,
            "r1": 1,
            # ... more registers
        }
        
    def init_context(self):
        """Initialize architecture context."""
        # Set up initial register values
        # Set up stack pointer
        # Set up other architecture-specific initialization
        pass
        
    def disassembler(self, code, address):
        """Disassemble instruction for this architecture."""
        # Use capstone or other disassembler
        pass

Adding New OS Support

# qiling/os/new_os/new_os.py
from qiling.os.os import QlOs
from qiling.const import QL_OS

class QlOsNEWOS(QlOs):
    """Support for NEW_OS operating system."""
    
    def __init__(self, ql):
        super().__init__(ql)
        self.type = QL_OS.NEW_OS
        
    def setup_syscall_table(self):
        """Set up OS-specific system call table."""
        self.syscall_table = {
            1: self.syscall_exit,
            2: self.syscall_read,
            # ... more syscalls
        }
        
    def syscall_exit(self, exit_code):
        """Implement exit system call."""
        self.ql.emu_stop()
        self.ql.exit_code = exit_code
        
    def load_binary(self, filename):
        """Load binary file for this OS."""
        # Implement OS-specific binary loading
        pass

Performance Contributions

Benchmarking Framework

# benchmarks/performance_test.py
import time
import statistics
from typing import List, Dict, Any
from qiling import Qiling

class QilingBenchmark:
    """Benchmarking framework for Qiling performance testing."""
    
    def __init__(self):
        self.results: Dict[str, List[float]] = {}
        
    def benchmark_function(self, name: str, func, iterations: int = 10):
        """Benchmark a specific function."""
        times = []
        
        for _ in range(iterations):
            start_time = time.perf_counter()
            func()
            end_time = time.perf_counter()
            times.append(end_time - start_time)
        
        self.results[name] = times
        
    def report_results(self):
        """Generate benchmark report."""
        for name, times in self.results.items():
            mean_time = statistics.mean(times)
            std_dev = statistics.stdev(times) if len(times) > 1 else 0
            min_time = min(times)
            max_time = max(times)
            
            print(f"{name}:")
            print(f"  Mean: {mean_time:.4f}s")
            print(f"  Std Dev: {std_dev:.4f}s") 
            print(f"  Min: {min_time:.4f}s")
            print(f"  Max: {max_time:.4f}s")
            print()

def benchmark_emulation_speed():
    """Benchmark basic emulation speed."""
    def run_basic_emulation():
        ql = Qiling(["tests/samples/hello"], "tests/rootfs/")
        ql.run()
    
    benchmark = QilingBenchmark()
    benchmark.benchmark_function("basic_emulation", run_basic_emulation)
    benchmark.report_results()

if __name__ == "__main__":
    benchmark_emulation_speed()

Documentation Contributions

Wiki Contributions

Creating New Wiki Pages:

  1. Follow the established structure and style
  2. Use clear headings and consistent formatting
  3. Include practical examples and code snippets
  4. Add cross-references to related pages
  5. Keep content up-to-date with latest Qiling version

Improving Existing Pages:

  1. Fix typos and grammatical errors
  2. Update outdated information
  3. Add missing examples or clarifications
  4. Improve code formatting and syntax highlighting
  5. Add troubleshooting sections

API Documentation

Docstring Standards:

  • Use Google-style or NumPy-style docstrings
  • Include type hints for all parameters
  • Provide examples for complex functions
  • Document exceptions that may be raised
  • Include version information for new features

Community Contributions

Helping Other Users

Forum Participation:

  • Answer questions on GitHub Discussions
  • Help troubleshoot issues in Telegram chat
  • Create tutorials and blog posts
  • Present at conferences and meetups

Issue Triage:

  • Reproduce and verify bug reports
  • Add labels and categorize issues
  • Help gather additional information
  • Test proposed fixes

Mentoring New Contributors

Onboarding Support:

  • Help new contributors set up development environment
  • Guide them through their first contributions
  • Review and provide feedback on pull requests
  • Share knowledge about Qiling internals

Release Process

Preparing for Release

Pre-release Checklist:

  • All CI/CD checks pass
  • Documentation is up-to-date
  • Version numbers are updated
  • Changelog is complete
  • Migration guide is ready (if needed)
  • Performance regression tests pass

Release Testing:

  • Test on multiple platforms
  • Verify backwards compatibility
  • Test installation from PyPI
  • Validate example code still works

Recognition and Rewards

Contributor Recognition

Hall of Fame:

  • Major contributors are recognized in CREDITS.md
  • Significant contributions highlighted in release notes
  • Conference presentation opportunities
  • Recommendation letters for contributors

Badges and Achievements:

  • GitHub contributor badges
  • Special recognition for milestone contributions
  • Community contributor spotlights

Legal and Licensing

Contributor License Agreement

By contributing to Qiling Framework, you agree that:

  • Your contributions are your original work
  • You have the right to submit your contributions
  • Your contributions will be licensed under GPLv2
  • You understand the open-source nature of the project

Code Attribution

  • Maintain existing copyright notices
  • Add your copyright for substantial contributions
  • Credit external code sources properly
  • Respect third-party licenses

Getting Help

Where to Ask Questions

  1. GitHub Discussions: General questions and feature discussions
  2. Telegram Chat: Quick questions and real-time help
  3. GitHub Issues: Bug reports and specific problems
  4. Email: Sensitive security issues ([email protected])

Mentor Program

New contributors can request mentorship from experienced community members:

  • Code review and feedback
  • Architecture guidance
  • Best practices training
  • Career development advice

Thank you for contributing to Qiling Framework! Your contributions help make this project better for the entire cybersecurity community. Together, we're building the future of binary emulation and analysis.

Clone this wiki locally