CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pefile

Python PE parsing module for analyzing Portable Executable (PE) files with comprehensive header, section, and directory entry support

Pending
Overview
Eval results
Files

packer-detection.mddocs/

Packer Detection

Utilities for detecting packed executables and identifying packers/compilers using signature databases. The peutils module provides sophisticated packer detection capabilities.

Capabilities

SignatureDatabase Class

Manage and query PEiD signature databases for packer identification.

class SignatureDatabase:
    def __init__(self, filename=None, data=None):
        """
        Initialize signature database.
        
        Args:
            filename (str, optional): Path to PEiD signature file or URL
            data (str, optional): Raw signature data
        """
    
    def load(self, filename=None, data=None):
        """
        Load additional signature file.
        
        Args:
            filename (str, optional): Path to signature file or URL
            data (str, optional): Raw signature data
            
        Note:
            Can be called multiple times to combine signatures from
            different sources. Supports loading from URLs.
        """
    
    def match(self, pe, ep_only=True, section_start_only=False):
        """
        Find exact signature matches for PE file.
        
        Args:
            pe: PE file object
            ep_only (bool): Only check entry point signatures
            section_start_only (bool): Only check section start signatures
            
        Returns:
            str or list: Packer name (ep_only=True) or list of (offset, name) tuples
        """
    
    def match_all(self, pe, ep_only=True, section_start_only=False):
        """
        Find all likely signature matches.
        
        Args:
            pe: PE file object  
            ep_only (bool): Only check entry point signatures
            section_start_only (bool): Only check section start signatures
            
        Returns:
            list: All matching signatures instead of just most precise
        """
    
    def match_data(self, code_data, ep_only=True, section_start_only=False):
        """
        Match raw code data against signatures.
        
        Args:
            code_data (bytes): Raw code data to analyze
            ep_only (bool): Use entry point signatures
            section_start_only (bool): Use section start signatures
            
        Returns:
            str or list: Match results similar to match()
        """
    
    def generate_ep_signature(self, pe, name, sig_length=512):
        """
        Generate entry point signature for PE file.
        
        Args:
            pe: PE file object
            name (str): Name for the signature
            sig_length (int): Length of signature to generate
            
        Returns:
            str: Generated signature in PEiD format
        """
    
    def generate_section_signatures(self, pe, name, sig_length=512):
        """
        Generate signatures for all sections in PE file.
        
        Args:
            pe: PE file object
            name (str): Base name for signatures
            sig_length (int): Length of signatures to generate
            
        Returns:
            str: Generated signatures for all sections
        """

Utility Functions

High-level functions for packer and malware detection.

def is_probably_packed(pe):
    """
    Determine if PE file is likely packed using entropy analysis.
    
    Args:
        pe: PE file object
        
    Returns:
        bool: True if file appears to be packed
        
    Note:
        Uses entropy analysis with empirical thresholds:
        - Section entropy > 7.4
        - Compressed data ratio > 20%
    """

def is_suspicious(pe):
    """
    Analyze PE file for suspicious characteristics.
    
    Args:
        pe: PE file object
        
    Returns:
        bool: True if file has suspicious characteristics
        
    Note:
        Checks for unusual import locations, unrecognized sections,
        long ASCII strings, and relocations at entry point.
    """

def is_valid(pe):
    """
    Validate PE file structure.
    
    Args:
        pe: PE file object
        
    Returns:
        bool: True if PE structure is valid
        
    Note:
        Currently a placeholder function.
    """

Usage Examples

Basic Packer Detection

import pefile
import peutils

# Load PE file
with pefile.PE('suspected_packed.exe') as pe:
    # Quick entropy-based packer detection
    if peutils.is_probably_packed(pe):
        print("File is probably packed")
    else:
        print("File does not appear to be packed")
    
    # Check for suspicious characteristics
    if peutils.is_suspicious(pe):
        print("File has suspicious characteristics")

Signature-Based Packer Detection

import pefile
import peutils

# Load signature database
sig_db = peutils.SignatureDatabase('userdb.txt')

# Can also load from URL
# sig_db = peutils.SignatureDatabase('https://example.com/signatures.txt')

# Load additional signatures
sig_db.load('additional_sigs.txt')

with pefile.PE('executable.exe') as pe:
    # Check for packer signatures at entry point
    matches = sig_db.match(pe, ep_only=True)
    if matches:
        print(f"Detected packer: {matches}")
    else:
        print("No packer signature found at entry point")
    
    # Check section starts for packer signatures
    section_matches = sig_db.match(pe, ep_only=False, section_start_only=True)
    if section_matches:
        print("Section signature matches:")
        for offset, packer in section_matches:
            print(f"  Offset 0x{offset:08x}: {packer}")
    
    # Get all possible matches
    all_matches = sig_db.match_all(pe, ep_only=True)
    if all_matches:
        print("All possible matches:")
        for match in all_matches:
            print(f"  {match}")

Entropy Analysis

import pefile
import peutils

def detailed_entropy_analysis(pe):
    """Perform detailed entropy analysis for packer detection."""
    print("Entropy Analysis:")
    print("-" * 40)
    
    high_entropy_sections = 0
    total_sections = len(pe.sections)
    
    for section in pe.sections:
        name = section.Name.decode('utf-8').strip('\x00')
        entropy = section.get_entropy()
        size = section.SizeOfRawData
        
        print(f"{name:<10}: Entropy={entropy:.3f}, Size={size}")
        
        if entropy > 7.4:  # High entropy threshold
            high_entropy_sections += 1
            print(f"  ^ High entropy section (possible packing/encryption)")
    
    # Overall assessment
    packed_ratio = high_entropy_sections / total_sections if total_sections > 0 else 0
    
    print(f"\nSummary:")
    print(f"High entropy sections: {high_entropy_sections}/{total_sections}")
    print(f"Packed ratio: {packed_ratio:.2%}")
    
    if packed_ratio > 0.2:  # 20% threshold
        print("Assessment: Likely packed")
    else:
        print("Assessment: Probably not packed")
    
    return packed_ratio > 0.2

# Usage
with pefile.PE('executable.exe') as pe:
    is_packed = detailed_entropy_analysis(pe)
    
    # Compare with peutils assessment
    peutils_assessment = peutils.is_probably_packed(pe)
    print(f"\npeutils assessment: {peutils_assessment}")

Signature Generation

import pefile
import peutils

def generate_custom_signatures(pe_file, output_file):
    """Generate custom signatures for a PE file."""
    sig_db = peutils.SignatureDatabase()
    
    with pefile.PE(pe_file) as pe:
        # Generate entry point signature
        ep_sig = sig_db.generate_ep_signature(pe, "Custom_Sample", 256)
        
        # Generate section signatures
        section_sigs = sig_db.generate_section_signatures(pe, "Custom_Sample", 256)
        
        # Save signatures
        with open(output_file, 'w') as f:
            f.write("// Entry Point Signature\n")
            f.write(ep_sig)
            f.write("\n\n// Section Signatures\n")
            f.write(section_sigs)
        
        print(f"Generated signatures saved to {output_file}")

# Usage
generate_custom_signatures('unique_packer.exe', 'custom_signatures.txt')

Batch Packer Analysis

import pefile
import peutils
import os

def batch_packer_analysis(directory, sig_db_path=None):
    """Analyze multiple PE files for packer detection."""
    # Load signature database if provided
    sig_db = None
    if sig_db_path and os.path.exists(sig_db_path):
        sig_db = peutils.SignatureDatabase(sig_db_path)
    
    results = {}
    
    # Analyze all PE files in directory
    for filename in os.listdir(directory):
        if filename.lower().endswith(('.exe', '.dll')):
            filepath = os.path.join(directory, filename)
            
            try:
                with pefile.PE(filepath) as pe:
                    # Entropy-based detection
                    entropy_packed = peutils.is_probably_packed(pe)
                    suspicious = peutils.is_suspicious(pe)
                    
                    # Signature-based detection
                    sig_match = None
                    if sig_db:
                        sig_match = sig_db.match(pe, ep_only=True)
                    
                    results[filename] = {
                        'entropy_packed': entropy_packed,
                        'suspicious': suspicious,
                        'signature_match': sig_match
                    }
                    
            except Exception as e:
                results[filename] = {'error': str(e)}
    
    # Display results
    print("Batch Packer Analysis Results:")
    print("=" * 60)
    print(f"{'Filename':<20} {'Entropy':<8} {'Suspicious':<10} {'Signature':<20}")
    print("-" * 60)
    
    for filename, result in results.items():
        if 'error' in result:
            print(f"{filename:<20} ERROR: {result['error']}")
        else:
            entropy = "PACKED" if result['entropy_packed'] else "clean"
            suspicious = "YES" if result['suspicious'] else "no"
            signature = result['signature_match'] or "none"
            
            print(f"{filename:<20} {entropy:<8} {suspicious:<10} {signature:<20}")

# Usage
batch_packer_analysis('./samples', 'userdb.txt')

Advanced Packer Detection

import pefile
import peutils

def advanced_packer_detection(pe_file):
    """Comprehensive packer detection combining multiple techniques."""
    print(f"Advanced Packer Detection: {pe_file}")
    print("=" * 50)
    
    with pefile.PE(pe_file) as pe:
        # 1. Entropy analysis
        print("1. Entropy Analysis:")
        entropy_packed = peutils.is_probably_packed(pe)
        print(f"   Result: {'PACKED' if entropy_packed else 'NOT PACKED'}")
        
        # 2. Suspicious characteristics
        print("2. Suspicious Characteristics:")
        suspicious = peutils.is_suspicious(pe)
        print(f"   Result: {'SUSPICIOUS' if suspicious else 'NORMAL'}")
        
        # 3. Section analysis
        print("3. Section Analysis:")
        suspicious_sections = 0
        for section in pe.sections:
            name = section.Name.decode('utf-8').strip('\x00')
            entropy = section.get_entropy()
            
            # Check for suspicious section names
            if name in ['.upx0', '.upx1', '.aspack', '.petite', '.packed']:
                print(f"   Known packer section: {name}")
                suspicious_sections += 1
            
            # Check for high entropy with executable characteristics
            if entropy > 7.0 and section.Characteristics & 0x20000000:  # Executable
                print(f"   High entropy executable section: {name} (entropy: {entropy:.2f})")
                suspicious_sections += 1
        
        # 4. Import table analysis
        print("4. Import Analysis:")
        if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
            import_count = sum(len(entry.imports) for entry in pe.DIRECTORY_ENTRY_IMPORT)
            dll_count = len(pe.DIRECTORY_ENTRY_IMPORT)
            
            print(f"   DLLs: {dll_count}, Functions: {import_count}")
            
            # Low import count might indicate packing
            if import_count < 10:
                print("   Low import count - possible packing")
                suspicious_sections += 1
        else:
            print("   No imports found - highly suspicious")
            suspicious_sections += 1
        
        # 5. Entry point analysis
        print("5. Entry Point Analysis:")
        ep_rva = pe.OPTIONAL_HEADER.AddressOfEntryPoint
        ep_section = pe.get_section_by_rva(ep_rva)
        
        if ep_section:
            section_name = ep_section.Name.decode('utf-8').strip('\x00')
            print(f"   Entry point in section: {section_name}")
            
            # Entry point not in .text section is suspicious
            if section_name not in ['.text', 'CODE']:
                print(f"   Entry point not in standard code section - suspicious")
                suspicious_sections += 1
        
        # Final assessment
        print("\n6. Final Assessment:")
        print("-" * 20)
        
        confidence_score = 0
        if entropy_packed:
            confidence_score += 3
        if suspicious:
            confidence_score += 2
        if suspicious_sections > 0:
            confidence_score += suspicious_sections
        
        if confidence_score >= 5:
            assessment = "HIGHLY LIKELY PACKED"
        elif confidence_score >= 3:
            assessment = "POSSIBLY PACKED"
        else:
            assessment = "PROBABLY NOT PACKED"
        
        print(f"Confidence Score: {confidence_score}")
        print(f"Assessment: {assessment}")

# Usage
advanced_packer_detection('suspicious_file.exe')

Install with Tessl CLI

npx tessl i tessl/pypi-pefile

docs

data-access.md

debug.md

hashing.md

import-export.md

index.md

memory.md

ordinal-lookups.md

packer-detection.md

pe-parsing.md

resources.md

sections.md

tile.json