Leuchtturm Plugin Cheat Blatt
Überblick
Lighthouse ist ein Code-Abdeckungs-Plugin für Demontagen, die Code-Abdeckungsdaten direkt innerhalb von IDA Pro und Ghidra visualisieren. Es ist besonders nützlich, um Fuzzing-Ergebnisse mit Demontage zu korrelieren, unbedeckte Codepfade zu identifizieren und Sicherheitsforschungsbemühungen zu leiten.
RECHT *Key Features: Echtzeit-Abdeckungsvisualisierung, Mehrfach-Abdeckungsformat-Unterstützung, Differential-Abdeckungsanalyse, Fuzzing-Integration und interaktive Deckungsexploration in Disassemblern.
Installation und Inbetriebnahme
IDA Pro Installation
```bash
Clone Lighthouse repository
git clone https://github.com/gaasedelen/lighthouse.git cd lighthouse
Install Python dependencies
pip install -r requirements.txt
For IDA Pro 7.x
cp -r lighthouse/ "$IDADIR/plugins/" cp lighthouse_plugin.py "$IDADIR/plugins/"
For IDA Pro 8.x
cp -r lighthouse/ "$IDADIR/plugins/" cp lighthouse_plugin.py "$IDADIR/plugins/"
Verify installation
Start IDA Pro and check Edit -> Plugins -> Lighthouse
Alternative: Install via pip (if available)
pip install lighthouse-ida
Manual installation verification
python -c " import sys sys.path.append('/path/to/ida/python') import lighthouse print('Lighthouse installed successfully') " ```_
Ghidra Installation
```bash
Clone Lighthouse repository
git clone https://github.com/gaasedelen/lighthouse.git cd lighthouse
Build Ghidra extension
cd ghidra_scripts
Copy scripts to Ghidra script directory
cp *.py "$GHIDRA_INSTALL_DIR/Ghidra/Features/Python/ghidra_scripts/"
Or use Ghidra's script manager
1. Open Ghidra
2. Window -> Script Manager
3. Script Directories -> Add
4. Select lighthouse/ghidra_scripts directory
Install Python dependencies for Ghidra
pip install coverage pip install pyqt5 # For GUI components
Verify installation in Ghidra
Window -> Script Manager -> Search for "lighthouse"
```_
Erfassung von Datenquellen Setup
```bash
Install coverage tools for different formats
Intel Pin (for DynamoRIO coverage)
wget https://software.intel.com/sites/landingpage/pintool/downloads/pin-3.21-98484-ge7cd811fd-gcc-linux.tar.gz tar -xzf pin-3.21-98484-ge7cd811fd-gcc-linux.tar.gz export PIN_ROOT=/path/to/pin
DynamoRIO
git clone https://github.com/DynamoRIO/dynamorio.git cd dynamorio mkdir build && cd build cmake .. make -j$(nproc)
AFL++ for fuzzing coverage
git clone https://github.com/AFLplusplus/AFLplusplus.git cd AFLplusplus make sudo make install
Frida for dynamic instrumentation
pip install frida-tools npm install frida
GCOV for compile-time coverage
Already available with GCC
gcc --coverage source.c -o binary
LLVM coverage
clang -fprofile-instr-generate -fcoverage-mapping source.c -o binary
Verify coverage tools
which afl-fuzz which frida which gcov which llvm-profdata ```_
Konfiguration und Setup
```python
Lighthouse configuration file (~/.lighthouse/config.json)
{ "coverage_formats": { "drcov": { "enabled": true, "color": "#FF6B6B" }, "intel_pin": { "enabled": true, "color": "#4ECDC4" }, "frida": { "enabled": true, "color": "#45B7D1" }, "lighthouse": { "enabled": true, "color": "#96CEB4" } }, "ui_settings": { "auto_load": true, "show_coverage_percentage": true, "highlight_uncovered": true, "coverage_threshold": 0.8 }, "performance": { "max_coverage_files": 100, "cache_coverage_data": true, "async_loading": true } } ```_
Grundlegende Deckungsanalyse
Laden von Coverage Daten
```python
IDA Pro - Load coverage data
import lighthouse
Load single coverage file
lighthouse.load_coverage("coverage.drcov")
Load multiple coverage files
coverage_files = [ "run1.drcov", "run2.drcov", "run3.drcov" ]
for coverage_file in coverage_files: lighthouse.load_coverage(coverage_file)
Load coverage directory
lighthouse.load_coverage_directory("/path/to/coverage/files/")
Load with specific format
lighthouse.load_coverage("coverage.log", format="intel_pin")
Load Frida coverage
lighthouse.load_coverage("frida_trace.json", format="frida")
Load GCOV coverage
lighthouse.load_coverage("coverage.gcov", format="gcov") ```_
Visualisierung von Covers
```python
Enable coverage visualization
lighthouse.show_coverage()
Hide coverage visualization
lighthouse.hide_coverage()
Toggle coverage display
lighthouse.toggle_coverage()
Set coverage colors
lighthouse.set_coverage_color(0xFF6B6B) # Red for covered lighthouse.set_uncovered_color(0x808080) # Gray for uncovered
Highlight specific coverage
lighthouse.highlight_coverage("run1.drcov")
Show coverage statistics
stats = lighthouse.get_coverage_stats() print(f"Total functions: {stats['total_functions']}") print(f"Covered functions: {stats['covered_functions']}") print(f"Coverage percentage: {stats['coverage_percentage']:.2f}%")
Navigate to uncovered code
lighthouse.goto_next_uncovered() lighthouse.goto_previous_uncovered()
Find uncovered functions
uncovered_functions = lighthouse.get_uncovered_functions() for func in uncovered_functions: print(f"Uncovered function: {func['name']} at 0x{func['address']:x}") ```_
Deckungsvergleich
```python
Compare two coverage runs
lighthouse.compare_coverage("baseline.drcov", "new_run.drcov")
Differential coverage analysis
diff_coverage = lighthouse.differential_coverage([ "run1.drcov", "run2.drcov", "run3.drcov" ])
Show only new coverage
lighthouse.show_new_coverage_only()
Show coverage intersection
lighthouse.show_coverage_intersection()
Show coverage union
lighthouse.show_coverage_union()
Export coverage comparison
lighthouse.export_coverage_diff("coverage_diff.json")
Generate coverage report
report = lighthouse.generate_coverage_report() with open("coverage_report.html", "w") as f: f.write(report) ```_
Erweiterte Deckungsanalyse
Fuzzing Integration
```python
AFL++ integration
import subprocess import time import os
class AFLLighthouseIntegration: def init(self, target_binary, afl_output_dir): self.target_binary = target_binary self.afl_output_dir = afl_output_dir self.coverage_files = []
def start_afl_fuzzing(self, input_dir, timeout=3600):
"""Start AFL fuzzing with coverage collection"""
# Prepare AFL command
afl_cmd = [
"afl-fuzz",
"-i", input_dir,
"-o", self.afl_output_dir,
"-t", "1000", # Timeout in ms
"-m", "none", # No memory limit
"--", self.target_binary, "@@"
]
print(f"Starting AFL fuzzing: {' '.join(afl_cmd)}")
# Start AFL in background
afl_process = subprocess.Popen(afl_cmd)
# Monitor for new test cases and collect coverage
start_time = time.time()
while time.time() - start_time < timeout:
self.collect_afl_coverage()
time.sleep(60) # Check every minute
# Stop AFL
afl_process.terminate()
return self.coverage_files
def collect_afl_coverage(self):
"""Collect coverage from AFL test cases"""
queue_dir = os.path.join(self.afl_output_dir, "default", "queue")
if not os.path.exists(queue_dir):
return
# Get new test cases
test_cases = [f for f in os.listdir(queue_dir) if f.startswith("id:")]
for test_case in test_cases:
test_path = os.path.join(queue_dir, test_case)
coverage_file = f"coverage_{test_case}.drcov"
if coverage_file not in self.coverage_files:
# Run test case with coverage collection
self.run_with_coverage(test_path, coverage_file)
self.coverage_files.append(coverage_file)
def run_with_coverage(self, input_file, coverage_file):
"""Run target with coverage collection using DynamoRIO"""
drrun_cmd = [
"drrun",
"-t", "drcov",
"-dump_text",
"-logdir", ".",
"-logprefix", coverage_file.replace(".drcov", ""),
"--", self.target_binary, input_file
]
try:
subprocess.run(drrun_cmd, timeout=10, capture_output=True)
except subprocess.TimeoutExpired:
pass # Timeout is expected for some test cases
Usage example
afl_integration = AFLLighthouseIntegration("./target_binary", "./afl_output") coverage_files = afl_integration.start_afl_fuzzing("./input_seeds", timeout=1800)
Load coverage in Lighthouse
for coverage_file in coverage_files: lighthouse.load_coverage(coverage_file) ```_
Sammlung von Zollbezügen
```python
Custom coverage collector using Frida
import frida import json
class FridaCoverageCollector: def init(self, target_process): self.target_process = target_process self.session = None self.script = None self.coverage_data = []
def attach_to_process(self):
"""Attach Frida to target process"""
try:
self.session = frida.attach(self.target_process)
print(f"Attached to process: {self.target_process}")
except frida.ProcessNotFoundError:
print(f"Process {self.target_process} not found")
return False
return True
def start_coverage_collection(self, module_name=None):
"""Start collecting coverage data"""
# Frida script for coverage collection
frida_script = """
var coverage_data = [];
var module_base = null;
var module_size = 0;
// Get module information
if ("%s") {
var module = Process.getModuleByName("%s");
module_base = module.base;
module_size = module.size;
console.log("Monitoring module: " + module.name + " at " + module_base);
} else {
// Monitor main module
var modules = Process.enumerateModules();
if (modules.length > 0) {
module_base = modules[0].base;
module_size = modules[0].size;
console.log("Monitoring main module: " + modules[0].name);
}
}
// Hook instruction execution
Interceptor.attach(module_base, {
onEnter: function(args) {
var address = this.context.pc;
if (address >= module_base && address < module_base.add(module_size)) {
coverage_data.push({
address: address.toString(),
timestamp: Date.now()
});
}
}
});
// Export coverage data
rpc.exports.getCoverageData = function() {
return coverage_data;
};
rpc.exports.clearCoverageData = function() {
coverage_data = [];
};
""" % (module_name or "", module_name or "")
self.script = self.session.create_script(frida_script)
self.script.load()
print("Coverage collection started")
def get_coverage_data(self):
"""Get collected coverage data"""
if self.script:
return self.script.exports.get_coverage_data()
return []
def save_coverage(self, output_file):
"""Save coverage data to file"""
coverage_data = self.get_coverage_data()
# Convert to Lighthouse format
lighthouse_format = {
"version": "1.0",
"type": "frida",
"coverage": []
}
for entry in coverage_data:
lighthouse_format["coverage"].append({
"address": entry["address"],
"hit_count": 1,
"timestamp": entry["timestamp"]
})
with open(output_file, "w") as f:
json.dump(lighthouse_format, f, indent=2)
print(f"Coverage saved to: {output_file}")
def detach(self):
"""Detach from process"""
if self.session:
self.session.detach()
print("Detached from process")
Usage example
collector = FridaCoverageCollector("target_process") if collector.attach_to_process(): collector.start_coverage_collection("main_module.exe")
# Let it run for some time
time.sleep(30)
# Save coverage
collector.save_coverage("frida_coverage.json")
collector.detach()
# Load in Lighthouse
lighthouse.load_coverage("frida_coverage.json", format="frida")
```_
Coverage-Guided Analysis
```python
Coverage-guided vulnerability research
class CoverageGuidedAnalysis: def init(self, binary_path): self.binary_path = binary_path self.coverage_data = {} self.interesting_functions = [] self.uncovered_paths = []
def analyze_coverage_gaps(self):
"""Analyze coverage gaps to find interesting code paths"""
# Get all functions in binary
all_functions = lighthouse.get_all_functions()
covered_functions = lighthouse.get_covered_functions()
# Find uncovered functions
uncovered_functions = []
for func in all_functions:
if func not in covered_functions:
uncovered_functions.append(func)
# Analyze uncovered functions for interesting patterns
for func in uncovered_functions:
func_analysis = self.analyze_function(func)
if func_analysis["interesting"]:
self.interesting_functions.append({
"function": func,
"reason": func_analysis["reason"],
"priority": func_analysis["priority"]
})
# Sort by priority
self.interesting_functions.sort(key=lambda x: x["priority"], reverse=True)
return self.interesting_functions
def analyze_function(self, function):
"""Analyze function for interesting characteristics"""
analysis = {
"interesting": False,
"reason": [],
"priority": 0
}
# Get function disassembly
disasm = lighthouse.get_function_disassembly(function)
# Check for interesting patterns
if "strcpy" in disasm or "sprintf" in disasm:
analysis["interesting"] = True
analysis["reason"].append("Potentially unsafe string operations")
analysis["priority"] += 30
if "malloc" in disasm or "free" in disasm:
analysis["interesting"] = True
analysis["reason"].append("Memory management operations")
analysis["priority"] += 20
if "system" in disasm or "exec" in disasm:
analysis["interesting"] = True
analysis["reason"].append("System command execution")
analysis["priority"] += 40
if "crypto" in disasm.lower() or "encrypt" in disasm.lower():
analysis["interesting"] = True
analysis["reason"].append("Cryptographic operations")
analysis["priority"] += 25
# Check for error handling paths
if "error" in disasm.lower() or "exception" in disasm.lower():
analysis["interesting"] = True
analysis["reason"].append("Error handling code")
analysis["priority"] += 15
# Check for network operations
if "socket" in disasm or "connect" in disasm or "send" in disasm:
analysis["interesting"] = True
analysis["reason"].append("Network operations")
analysis["priority"] += 35
return analysis
def generate_test_cases(self, target_function):
"""Generate test cases to reach uncovered function"""
# Analyze function parameters and calling conventions
func_info = lighthouse.get_function_info(target_function)
# Generate inputs based on function signature
test_cases = []
if func_info["parameters"]:
for param_type in func_info["parameters"]:
if param_type == "string":
test_cases.extend([
"A" * 10,
"A" * 100,
"A" * 1000,
"../../../etc/passwd",
"%s%s%s%s",
"\x00\x01\x02\x03"
])
elif param_type == "integer":
test_cases.extend([
0, 1, -1, 0x7FFFFFFF, 0x80000000,
0xFFFFFFFF, 0x100000000
])
return test_cases
def guided_fuzzing_campaign(self):
"""Run coverage-guided fuzzing campaign"""
# Analyze current coverage gaps
interesting_functions = self.analyze_coverage_gaps()
print(f"Found {len(interesting_functions)} interesting uncovered functions")
for func_info in interesting_functions[:10]: # Top 10 priority
func = func_info["function"]
print(f"Targeting function: {func['name']} (Priority: {func_info['priority']})")
# Generate test cases for this function
test_cases = self.generate_test_cases(func)
# Run fuzzing campaign targeting this function
self.run_targeted_fuzzing(func, test_cases)
# Check if we achieved coverage
if lighthouse.is_function_covered(func):
print(f"Successfully covered function: {func['name']}")
else:
print(f"Failed to cover function: {func['name']}")
def run_targeted_fuzzing(self, target_function, test_cases):
"""Run fuzzing campaign targeting specific function"""
# Create input files for test cases
input_dir = f"inputs_{target_function['name']}"
os.makedirs(input_dir, exist_ok=True)
for i, test_case in enumerate(test_cases):
input_file = os.path.join(input_dir, f"input_{i:04d}")
with open(input_file, "wb") as f:
if isinstance(test_case, str):
f.write(test_case.encode())
else:
f.write(bytes([test_case]))
# Run AFL with coverage feedback
afl_cmd = [
"afl-fuzz",
"-i", input_dir,
"-o", f"output_{target_function['name']}",
"-t", "1000",
"-m", "none",
"--", self.binary_path, "@@"
]
# Run for limited time
process = subprocess.Popen(afl_cmd)
time.sleep(300) # 5 minutes
process.terminate()
# Collect and load new coverage
self.collect_campaign_coverage(f"output_{target_function['name']}")
Usage example
analysis = CoverageGuidedAnalysis("./target_binary") analysis.guided_fuzzing_campaign() ```_
Coverage Reporting und Metriken
Umfassende Coverage Reports
```python
Generate detailed coverage reports
class LighthouseCoverageReporter: def init(self): self.coverage_data = {} self.metrics = {}
def generate_comprehensive_report(self, output_file="coverage_report.html"):
"""Generate comprehensive HTML coverage report"""
# Collect coverage metrics
self.collect_coverage_metrics()
# Generate HTML report
html_content = self.create_html_report()
with open(output_file, "w") as f:
f.write(html_content)
print(f"Coverage report generated: {output_file}")
def collect_coverage_metrics(self):
"""Collect comprehensive coverage metrics"""
# Basic coverage statistics
self.metrics["basic"] = lighthouse.get_coverage_stats()
# Function-level coverage
all_functions = lighthouse.get_all_functions()
covered_functions = lighthouse.get_covered_functions()
self.metrics["functions"] = {
"total": len(all_functions),
"covered": len(covered_functions),
"uncovered": len(all_functions) - len(covered_functions),
"coverage_percentage": (len(covered_functions) / len(all_functions)) * 100
}
# Basic block coverage
all_blocks = lighthouse.get_all_basic_blocks()
covered_blocks = lighthouse.get_covered_basic_blocks()
self.metrics["basic_blocks"] = {
"total": len(all_blocks),
"covered": len(covered_blocks),
"uncovered": len(all_blocks) - len(covered_blocks),
"coverage_percentage": (len(covered_blocks) / len(all_blocks)) * 100
}
# Instruction coverage
all_instructions = lighthouse.get_all_instructions()
covered_instructions = lighthouse.get_covered_instructions()
self.metrics["instructions"] = {
"total": len(all_instructions),
"covered": len(covered_instructions),
"uncovered": len(all_instructions) - len(covered_instructions),
"coverage_percentage": (len(covered_instructions) / len(all_instructions)) * 100
}
# Coverage by module
self.metrics["modules"] = {}
modules = lighthouse.get_modules()
for module in modules:
module_coverage = lighthouse.get_module_coverage(module)
self.metrics["modules"][module["name"]] = module_coverage
# Coverage hotspots (most frequently hit)
self.metrics["hotspots"] = lighthouse.get_coverage_hotspots(limit=20)
# Coverage timeline
self.metrics["timeline"] = lighthouse.get_coverage_timeline()
def create_html_report(self):
"""Create HTML coverage report"""
html_template = """
Lighthouse Coverage Report
Generated on: {timestamp}
Binary: {binary_name}
Coverage Summary
Function Coverage
{covered_functions}/{total_functions} functions ({function_coverage:.1f}%)
Basic Block Coverage
{covered_blocks}/{total_blocks} blocks ({block_coverage:.1f}%)
Instruction Coverage
{covered_instructions}/{total_instructions} instructions ({instruction_coverage:.1f}%)
Module Coverage
Module | Functions | Coverage | Progress |
---|
Coverage Hotspots
Address | Function | Hit Count | Percentage |
---|
Uncovered Functions
Address | Function Name | Size | Complexity |
---|
Coverage Timeline
"""
# Format template with metrics
return html_template.format(
timestamp=time.strftime("%Y-%m-%d %H:%M:%S"),
binary_name=lighthouse.get_binary_name(),
function_coverage=self.metrics["functions"]["coverage_percentage"],
covered_functions=self.metrics["functions"]["covered"],
total_functions=self.metrics["functions"]["total"],
block_coverage=self.metrics["basic_blocks"]["coverage_percentage"],
covered_blocks=self.metrics["basic_blocks"]["covered"],
total_blocks=self.metrics["basic_blocks"]["total"],
instruction_coverage=self.metrics["instructions"]["coverage_percentage"],
covered_instructions=self.metrics["instructions"]["covered"],
total_instructions=self.metrics["instructions"]["total"],
module_rows=self.generate_module_rows(),
hotspot_rows=self.generate_hotspot_rows(),
uncovered_rows=self.generate_uncovered_rows(),
timeline_labels=json.dumps([t["timestamp"] for t in self.metrics["timeline"]]),
timeline_data=json.dumps([t["coverage"] for t in self.metrics["timeline"]])
)
def generate_module_rows(self):
"""Generate HTML rows for module coverage table"""
rows = []
for module_name, coverage in self.metrics["modules"].items():
progress_width = coverage["coverage_percentage"]
row = f"""
<tr>
<td>{module_name}</td>
<td>{coverage["covered"]}/{coverage["total"]}</td>
<td>{coverage["coverage_percentage"]:.1f}%</td>
<td>
<div class="progress-bar">
<div class="progress-fill" style="width: {progress_width}%"></div>
</div>
</td>
</tr>
"""
rows.append(row)
return "".join(rows)
def generate_hotspot_rows(self):
"""Generate HTML rows for coverage hotspots"""
rows = []
for hotspot in self.metrics["hotspots"]:
row = f"""
<tr>
<td>0x{hotspot["address"]:x}</td>
<td>{hotspot["function_name"]}</td>
<td>{hotspot["hit_count"]}</td>
<td>{hotspot["percentage"]:.2f}%</td>
</tr>
"""
rows.append(row)
return "".join(rows)
def generate_uncovered_rows(self):
"""Generate HTML rows for uncovered functions"""
uncovered_functions = lighthouse.get_uncovered_functions()
rows = []
for func in uncovered_functions[:50]: # Limit to top 50
row = f"""
<tr>
<td>0x{func["address"]:x}</td>
<td>{func["name"]}</td>
<td>{func["size"]} bytes</td>
<td>{func["complexity"]}</td>
</tr>
"""
rows.append(row)
return "".join(rows)
def export_coverage_data(self, format="json"):
"""Export coverage data in various formats"""
if format == "json":
output_file = "coverage_data.json"
with open(output_file, "w") as f:
json.dump(self.metrics, f, indent=2)
elif format == "csv":
import csv
# Export function coverage
with open("function_coverage.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["Address", "Function", "Covered", "Hit Count"])
for func in lighthouse.get_all_functions():
coverage_info = lighthouse.get_function_coverage(func)
writer.writerow([
f"0x{func['address']:x}",
func["name"],
coverage_info["covered"],
coverage_info["hit_count"]
])
elif format == "xml":
import xml.etree.ElementTree as ET
root = ET.Element("coverage_report")
# Add summary
summary = ET.SubElement(root, "summary")
for key, value in self.metrics["functions"].items():
elem = ET.SubElement(summary, key)
elem.text = str(value)
# Add functions
functions = ET.SubElement(root, "functions")
for func in lighthouse.get_all_functions():
func_elem = ET.SubElement(functions, "function")
func_elem.set("address", f"0x{func['address']:x}")
func_elem.set("name", func["name"])
coverage_info = lighthouse.get_function_coverage(func)
func_elem.set("covered", str(coverage_info["covered"]))
func_elem.set("hit_count", str(coverage_info["hit_count"]))
tree = ET.ElementTree(root)
tree.write("coverage_data.xml")
print(f"Coverage data exported to {format} format")
Usage example
reporter = LighthouseCoverageReporter() reporter.generate_comprehensive_report("detailed_coverage_report.html") reporter.export_coverage_data("json") reporter.export_coverage_data("csv") ```_
Integration von CI/CD
Automatische Deckungsanalyse
```bash
!/bin/bash
CI/CD integration script for Lighthouse coverage analysis
set -e
BINARY_PATH="$1" COVERAGE_DIR="$2" OUTPUT_DIR="$3" THRESHOLD="$4"
| if [ -z "$BINARY_PATH" ] | | [ -z "$COVERAGE_DIR" ] | | [ -z "$OUTPUT_DIR" ]; then |
echo "Usage: $0
THRESHOLD=${THRESHOLD:-80} # Default 80% coverage threshold
echo "Starting automated coverage analysis..." echo "Binary: $BINARY_PATH" echo "Coverage directory: $COVERAGE_DIR" echo "Output directory: $OUTPUT_DIR" echo "Coverage threshold: $THRESHOLD%"
mkdir -p "$OUTPUT_DIR"
Generate coverage report
python3 << EOF import sys sys.path.append('/path/to/lighthouse') import lighthouse
Load binary in headless mode
lighthouse.load_binary("$BINARY_PATH")
Load all coverage files
import os coverage_files = [] for root, dirs, files in os.walk("$COVERAGE_DIR"): for file in files: if file.endswith(('.drcov', '.cov', '.gcov')): coverage_files.append(os.path.join(root, file))
print(f"Found {len(coverage_files)} coverage files")
for coverage_file in coverage_files: try: lighthouse.load_coverage(coverage_file) print(f"Loaded: {coverage_file}") except Exception as e: print(f"Failed to load {coverage_file}: {e}")
Generate metrics
stats = lighthouse.get_coverage_stats() function_coverage = stats['function_coverage_percentage'] block_coverage = stats['block_coverage_percentage']
print(f"Function coverage: {function_coverage:.2f}%") print(f"Block coverage: {block_coverage:.2f}%")
Generate reports
lighthouse.export_coverage_report("$OUTPUT_DIR/coverage_report.html") lighthouse.export_coverage_data("$OUTPUT_DIR/coverage_data.json")
Check threshold
if function_coverage < $THRESHOLD: print(f"ERROR: Coverage {function_coverage:.2f}% below threshold {$THRESHOLD}%") sys.exit(1) else: print(f"SUCCESS: Coverage {function_coverage:.2f}% meets threshold {$THRESHOLD}%")
Generate uncovered functions list
uncovered = lighthouse.get_uncovered_functions() with open("$OUTPUT_DIR/uncovered_functions.txt", "w") as f: for func in uncovered: f.write(f"0x{func['address']:x} {func['name']}\n")
print(f"Found {len(uncovered)} uncovered functions") EOF
Generate summary for CI
cat > "$OUTPUT_DIR/coverage_summary.txt" << EOF Coverage Analysis Summary ======================== Date: $(date) Binary: $BINARY_PATH Coverage Files: $(find "$COVERAGE_DIR" -name ".drcov" -o -name ".cov" -o -name "*.gcov" | wc -l) Threshold: $THRESHOLD%
Results: | - Function Coverage: $(grep "Function coverage:" "$OUTPUT_DIR/coverage_report.html" | sed 's/.: //' | sed 's/%.//')% | | - Block Coverage: $(grep "Block coverage:" "$OUTPUT_DIR/coverage_report.html" | sed 's/.: //' | sed 's/%.//')% | - Uncovered Functions: $(wc -l < "$OUTPUT_DIR/uncovered_functions.txt")
Status: $(if [ $? -eq 0 ]; then echo "PASS"; else echo "FAIL"; fi) EOF
echo "Coverage analysis complete!" echo "Results saved to: $OUTPUT_DIR" ```_
GitHub Aktionen Integration
```yaml
.github/workflows/coverage-analysis.yml
name: Coverage Analysis with Lighthouse
on: push: branches: [ main, develop ] pull_request: branches: [ main ]
jobs: coverage-analysis: runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake
# Install WABT for WASM analysis
sudo apt-get install wabt
# Install DynamoRIO for coverage collection
wget https: //github.com/DynamoRIO/dynamorio/releases/download/release_9.0.1/DynamoRIO-Linux-9.0.1.tar.gz
tar -xzf DynamoRIO-Linux-9.0.1.tar.gz
export DYNAMORIO_HOME=$PWD/DynamoRIO-Linux-9.0.1
# Install Lighthouse
pip install lighthouse-ida
# Install AFL++ for fuzzing
git clone https: //github.com/AFLplusplus/AFLplusplus.git
cd AFLplusplus
make
sudo make install
cd ..
- name: Build target binary
run: |
gcc -g -O0 --coverage src/main.c -o target_binary
- name: Run fuzzing campaign
run: |
mkdir -p input_seeds
echo "test input" > input_seeds/seed1
echo "another test" > input_seeds/seed2
# Run AFL for limited time
| timeout 300 afl-fuzz -i input_seeds -o afl_output -t 1000 -m none -- ./target_binary @@ | | true |
- name: Collect coverage data
run: |
mkdir -p coverage_data
# Collect AFL coverage
| find afl_output -name "id: *" | head -20 | while read testcase; do | coverage_file="coverage_data/$(basename "$testcase").drcov" $DYNAMORIO_HOME/bin64/drrun -t drcov -dump_text -logdir coverage_data -- ./target_binary "$testcase" done
# Collect GCOV coverage
gcov src/main.c
mv *.gcov coverage_data/
- name: Analyze coverage with Lighthouse
run: |
python3 scripts/lighthouse_analysis.py ./target_binary coverage_data coverage_results 75
- name: Upload coverage results
uses: actions/upload-artifact@v3
with:
name: coverage-results
path: coverage_results/
- name: Comment PR with coverage
if: github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const summary = fs.readFileSync('coverage_results/coverage_summary.txt', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## Coverage Analysis Results\n\n\`\`\`\n${summary}\n\`\`\``
});
- name: Fail if coverage below threshold
run: |
if grep -q "FAIL" coverage_results/coverage_summary.txt; then
echo "Coverage analysis failed!"
exit 1
fi
```_
Ressourcen und Dokumentation
Offizielle Mittel
- Lighthouse GitHub Repository - Hauptrepository und Dokumentation
- Lighthouse Wiki - Umfassende Nutzungsanleitung
- IDA Pro Plugin Development - IDA Python API Dokumentation
- Ghidra Scripting - Ghidra Scripting Guide
Integration von Covering Tools
- DynamoRIO - Dynamische binäre Instrumentierungsplattform
- Intel Pin - Binäre Instrumentierung
- AFL++ - Fortgeschrittener Fuzzing-Rahmen
- Frida - Dynamisches Instrumentarium
Forschung und Papiere
- Code Coverage in Reverse Engineering - Akademische Forschung zur Deckungsleitung RE
- Fuzzing with Code Coverage - AFL Fuzzing Methodologie
- Binary Analysis with Coverage - Bohrerpapier zur Deckungsgeleiteten Analyse
Gemeinschaftsmittel
- Lighthouse Users Group - Gemeinschaftsdiskussionen
- Reverse Engineering Stack Exchange - Q&A; für RE-Themen
- r/ReverseEngineering - Reddit Community
- Binary Analysis Discord - Echtzeit Community Chat