<?php
/**
 * VMPFence Pattern Harvester
 * 
 * Automated pattern collection class for expanding malware detection database
 * Harvests patterns from public sources and optimizes performance
 * 
 * @package VMPFence
 * @since 1.0.0
 */

if (!defined('ABSPATH')) {
    exit;
}

class VMPFence_Pattern_Harvester {
    
    /**
     * Pattern categories
     */
    private $pattern_categories = array(
        'php_obfuscation',
        'webshells',
        'backdoors',
        'upload_exploits',
        'sql_injection',
        'xss_vectors',
        'code_injection',
        'eval_malware'
    );
    
    /**
     * Harvested patterns
     */
    private $harvested_patterns = array();
    
    /**
     * Common strings optimizer instance
     */
    private $common_strings_optimizer;
    
    public function __construct($common_strings_optimizer = null) {
        $this->common_strings_optimizer = $common_strings_optimizer;
        if (!$this->common_strings_optimizer) {
            $this->common_strings_optimizer = new VMPFence_Common_Strings_Optimizer();
        }
    }
    
    /**
     * Harvest YARA-style rules and convert to PHP regex
     * Simulates harvesting from public malware research
     * 
     * @return array Harvested YARA-based patterns
     */
    public function harvest_yara_rules() {
        $yara_patterns = array();
        
        // PHP Webshell Patterns (based on common YARA rules)
        $yara_patterns[] = array(
            'rule_id' => 'webshell_c99',
            'category' => 'webshells', 
            'pattern' => 'c99_.*shell|c99shell',
            'description' => 'C99 Shell webshell detection',
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'critical',
            'issue_type' => 'webshell',
            'common_string_indexes' => array(0, 6, 7), // eval, system, exec
            'custom_message' => 'C99 Shell webshell detected'
        );
        
        $yara_patterns[] = array(
            'rule_id' => 'webshell_r57',
            'category' => 'webshells',
            'pattern' => 'r57_.*shell|r57shell|RooT.*57',
            'description' => 'R57 Shell webshell detection', 
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'critical',
            'issue_type' => 'webshell',
            'common_string_indexes' => array(0, 6, 7, 8), // eval, system, exec, shell_exec
            'custom_message' => 'R57 Shell webshell detected'
        );
        
        $yara_patterns[] = array(
            'rule_id' => 'webshell_wso',
            'category' => 'webshells',
            'pattern' => 'wso.*shell|WSO.*Web.*Shell|Web.*Shell.*by.*oRb',
            'description' => 'WSO Shell webshell detection',
            'scan_type' => 'file_content', 
            'log_only' => false,
            'severity' => 'critical',
            'issue_type' => 'webshell',
            'common_string_indexes' => array(0, 1, 6, 7), // eval, base64_decode, system, exec
            'custom_message' => 'WSO Shell webshell detected'
        );
        
        // PHP Obfuscation Patterns
        $yara_patterns[] = array(
            'rule_id' => 'php_obfuscated_eval',
            'category' => 'php_obfuscation',
            'pattern' => 'eval\s*\(\s*(?:base64_decode|gzinflate|str_rot13|gzuncompress)',
            'description' => 'Obfuscated PHP eval with encoding functions',
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'high',
            'issue_type' => 'obfuscated_code',
            'common_string_indexes' => array(0, 1, 2, 3), // eval, base64_decode, gzinflate, str_rot13
            'custom_message' => 'Obfuscated PHP code detected using eval with encoding'
        );
        
        $yara_patterns[] = array(
            'rule_id' => 'php_hex_obfuscation',
            'category' => 'php_obfuscation',
            'pattern' => '\\\\x[0-9a-f]{2}.*\\\\x[0-9a-f]{2}.*\\\\x[0-9a-f]{2}.*(eval|exec|system|shell_exec)',
            'description' => 'PHP hex-encoded obfuscation with malicious functions',
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'medium',
            'issue_type' => 'obfuscated_code', 
            'common_string_indexes' => array(21, 5, 7, 6, 8), // \x hex pattern, eval, exec, system, shell_exec
            'custom_message' => 'Hex-encoded PHP obfuscation with suspicious functions detected'
        );
        
        // Backdoor Patterns
        $yara_patterns[] = array(
            'rule_id' => 'backdoor_create_function',
            'category' => 'backdoors',
            'pattern' => 'create_function\s*\(\s*[\'"][^\'\"]*[\'"]\s*,\s*[\'"].*(?:eval|system|exec)',
            'description' => 'PHP create_function backdoor pattern',
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'critical',
            'issue_type' => 'backdoor',
            'common_string_indexes' => array(0, 6, 7), // eval, system, exec
            'custom_message' => 'PHP create_function backdoor detected'
        );
        
        $yara_patterns[] = array(
            'rule_id' => 'backdoor_preg_replace_e',
            'category' => 'backdoors',
            'pattern' => 'preg_replace\s*\(\s*[\'"][^\'\"]*[\'"]\s*[imsxeADSUXJu]*e[imsxeADSUXJu]*[\'"]',
            'description' => 'PHP preg_replace /e modifier backdoor',
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'critical',
            'issue_type' => 'backdoor',
            'common_string_indexes' => array(0), // eval (executed via /e)
            'custom_message' => 'PHP preg_replace /e modifier backdoor detected'
        );
        
        // Upload Exploit Patterns  
        $yara_patterns[] = array(
            'rule_id' => 'upload_exploit_move',
            'category' => 'upload_exploits',
            'pattern' => 'move_uploaded_file\s*\([^)]*\$_(?:GET|POST|REQUEST)\s*\[[^]]+\]',
            'description' => 'Malicious file upload exploitation',
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'high',
            'issue_type' => 'upload_exploit',
            'common_string_indexes' => array(13, 22, 23, 24), // move_uploaded_file, $_GET, $_POST, $_REQUEST
            'custom_message' => 'Malicious file upload exploit detected'
        );
        
        $yara_patterns[] = array(
            'rule_id' => 'upload_exploit_bypass',
            'category' => 'upload_exploits',
            'pattern' => '(?:\.php|\.phtml|\.php3|\.php4|\.php5).*(?:\.jpg|\.png|\.gif|\.txt)',
            'description' => 'File upload extension bypass attempt',
            'scan_type' => 'filename',
            'log_only' => false,
            'severity' => 'medium',
            'issue_type' => 'upload_exploit',
            'common_string_indexes' => array(), // filename-based, no content strings
            'custom_message' => 'File upload extension bypass detected'
        );
        
        // SQL Injection Patterns
        $yara_patterns[] = array(
            'rule_id' => 'sqli_union_select',
            'category' => 'sql_injection',
            'pattern' => 'UNION\s+(?:ALL\s+)?SELECT.*(?:concat|group_concat|load_file)',
            'description' => 'SQL injection UNION SELECT attack',
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'high',
            'issue_type' => 'sql_injection',
            'common_string_indexes' => array(31, 32), // UNION, SELECT
            'custom_message' => 'SQL injection UNION SELECT attack detected'
        );
        
        // Add patterns to harvested collection
        $this->harvested_patterns = array_merge($this->harvested_patterns, $yara_patterns);
        
        return $yara_patterns;
    }
    
    /**
     * Simulate harvesting patterns from GitHub malware samples
     * (In real implementation, would use GitHub API or web scraping)
     * 
     * @return array GitHub-sourced patterns
     */
    public function harvest_github_samples() {
        $github_patterns = array();
        
        // Simulated patterns from GitHub malware repositories
        $github_patterns[] = array(
            'rule_id' => 'github_php_mailer_exploit',
            'category' => 'code_injection',
            'pattern' => '(?:PHPMailer|SwiftMailer).*(?:addStringAttachment|attach).*(?:\$_GET|\$_POST).*(?:\.php|\.phtml)',
            'description' => 'PHP mailer exploit with file attachment',
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'high',
            'issue_type' => 'code_injection',
            'common_string_indexes' => array(22, 23), // $_GET, $_POST
            'custom_message' => 'PHP mailer exploit detected'
        );
        
        $github_patterns[] = array(
            'rule_id' => 'github_wordpress_user_creation',
            'category' => 'backdoors',
            'pattern' => 'wp_create_user\s*\([^)]*(?:admin|administrator).*(?:\$_GET|\$_POST|\$_REQUEST)',
            'description' => 'WordPress unauthorized admin user creation',
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'critical',
            'issue_type' => 'backdoor',
            'common_string_indexes' => array(26, 22, 23, 24), // wp_create_user, $_GET, $_POST, $_REQUEST
            'custom_message' => 'WordPress admin user creation backdoor detected'
        );
        
        $github_patterns[] = array(
            'rule_id' => 'github_reverse_shell',
            'category' => 'webshells',
            'pattern' => 'fsockopen\s*\([^)]*(?:\$_(?:GET|POST|REQUEST).*(?:system|exec|shell_exec|passthru))',
            'description' => 'PHP reverse shell connection',
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'critical',
            'issue_type' => 'webshell',
            'common_string_indexes' => array(38, 22, 23, 24, 6, 7, 8, 9), // fsockopen, $_*, system, exec, shell_exec, passthru
            'custom_message' => 'PHP reverse shell detected'
        );
        
        $github_patterns[] = array(
            'rule_id' => 'github_crypto_miner', 
            'category' => 'backdoors',
            'pattern' => '(?:cryptonight|monero|xmrig|cpuminer).*(?:stratum|pool).*(?:curl_exec|fsockopen)',
            'description' => 'Cryptocurrency miner malware',
            'scan_type' => 'file_content',
            'log_only' => false,
            'severity' => 'high',
            'issue_type' => 'crypto_miner',
            'common_string_indexes' => array(36, 38), // curl_exec, fsockopen
            'custom_message' => 'Cryptocurrency miner malware detected'
        );
        
        // Add to harvested collection
        $this->harvested_patterns = array_merge($this->harvested_patterns, $github_patterns);
        
        return $github_patterns;
    }
    
    /**
     * Validate harvested patterns for performance and accuracy
     * 
     * @param array $patterns Patterns to validate
     * @return array Validation results
     */
    public function validate_patterns($patterns = null) {
        if ($patterns === null) {
            $patterns = $this->harvested_patterns;
        }
        
        $validation_results = array(
            'total_patterns' => count($patterns),
            'valid_patterns' => 0,
            'invalid_patterns' => 0,
            'performance_warnings' => 0,
            'errors' => array()
        );
        
        foreach ($patterns as $index => $pattern) {
            $pattern_valid = true;
            $pattern_errors = array();
            
            // Validate required fields
            $required_fields = array('rule_id', 'category', 'pattern', 'description', 'severity', 'issue_type');
            foreach ($required_fields as $field) {
                if (!isset($pattern[$field]) || empty($pattern[$field])) {
                    $pattern_errors[] = "Missing required field: {$field}";
                    $pattern_valid = false;
                }
            }
            
            // Validate pattern syntax
            if (isset($pattern['pattern'])) {
                $test_result = @preg_match('/' . $pattern['pattern'] . '/i', 'test string');
                if ($test_result === false) {
                    $pattern_errors[] = "Invalid regex pattern: " . preg_last_error_msg();
                    $pattern_valid = false;
                }
            }
            
            // Check for performance issues
            if (isset($pattern['pattern'])) {
                // Check for catastrophic backtracking patterns
                if (preg_match('/\(\.\*.*\)\+|\(\.\+.*\)\*/', $pattern['pattern'])) {
                    $pattern_errors[] = "Potential catastrophic backtracking in pattern";
                    $validation_results['performance_warnings']++;
                }
                
                // Check pattern complexity
                if (strlen($pattern['pattern']) > 200) {
                    $pattern_errors[] = "Pattern may be too complex (>200 chars)";
                    $validation_results['performance_warnings']++;
                }
            }
            
            // Validate common string indexes
            if (isset($pattern['common_string_indexes']) && is_array($pattern['common_string_indexes'])) {
                $common_strings = $this->common_strings_optimizer->get_all_common_strings();
                foreach ($pattern['common_string_indexes'] as $index) {
                    if (!isset($common_strings[$index])) {
                        $pattern_errors[] = "Invalid common string index: {$index}";
                        $pattern_valid = false;
                    }
                }
            }
            
            if ($pattern_valid) {
                $validation_results['valid_patterns']++;
            } else {
                $validation_results['invalid_patterns']++;
                $validation_results['errors'][$pattern['rule_id'] ?? "pattern_{$index}"] = $pattern_errors;
            }
        }
        
        return $validation_results;
    }
    
    /**
     * Optimize common strings for harvested patterns
     * 
     * @return array Optimization results
     */
    public function optimize_common_strings() {
        $optimization_results = array(
            'patterns_analyzed' => 0,
            'common_strings_added' => 0,
            'optimization_applied' => 0
        );
        
        foreach ($this->harvested_patterns as &$pattern) {
            $optimization_results['patterns_analyzed']++;
            
            // If pattern doesn't have common string indexes, try to auto-detect
            if (!isset($pattern['common_string_indexes']) || empty($pattern['common_string_indexes'])) {
                $detected_strings = $this->detect_common_strings_in_pattern($pattern['pattern']);
                if (!empty($detected_strings)) {
                    $pattern['common_string_indexes'] = $detected_strings;
                    $optimization_results['optimization_applied']++;
                }
            }
        }
        
        return $optimization_results;
    }
    
    /**
     * Detect common strings that appear in a pattern
     * 
     * @param string $pattern_regex Pattern to analyze
     * @return array Array of common string indexes found
     */
    private function detect_common_strings_in_pattern($pattern_regex) {
        $detected_indexes = array();
        $common_strings = $this->common_strings_optimizer->get_all_common_strings();
        
        foreach ($common_strings as $index => $string) {
            // Check if the common string appears literally in the pattern
            if (strpos(strtolower($pattern_regex), strtolower($string)) !== false) {
                $detected_indexes[] = $index;
            }
        }
        
        return $detected_indexes;
    }
    
    /**
     * Get all harvested patterns
     * 
     * @return array All harvested patterns
     */
    public function get_harvested_patterns() {
        return $this->harvested_patterns;
    }
    
    /**
     * Get patterns by category
     * 
     * @param string $category Category to filter by
     * @return array Patterns in the specified category
     */
    public function get_patterns_by_category($category) {
        $filtered_patterns = array();
        
        foreach ($this->harvested_patterns as $pattern) {
            if (isset($pattern['category']) && $pattern['category'] === $category) {
                $filtered_patterns[] = $pattern;
            }
        }
        
        return $filtered_patterns;
    }
    
    /**
     * Export patterns to WordPress database format
     * 
     * @return array Patterns ready for database insertion
     */
    public function export_patterns_for_database() {
        $db_patterns = array();
        
        foreach ($this->harvested_patterns as $pattern) {
            $db_patterns[] = array(
                'rule_id' => $pattern['rule_id'],
                'category' => $pattern['category'],
                'pattern' => $pattern['pattern'],
                'description' => $pattern['description'],
                'scan_type' => $pattern['scan_type'] ?? 'file_content',
                'log_only' => $pattern['log_only'] ?? false,
                'severity' => $pattern['severity'],
                'issue_type' => $pattern['issue_type'],
                'common_string_indexes' => isset($pattern['common_string_indexes']) ? 
                    json_encode($pattern['common_string_indexes']) : '[]',
                'custom_message' => $pattern['custom_message'] ?? '',
                'created_date' => current_time('mysql'),
                'is_active' => 1
            );
        }
        
        return $db_patterns;
    }
}
