十六进制文本码流转pcap(text2pcap)

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <base href="/">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <title>Hex to PCAP Converter</title>

    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            padding-top: 0;
            min-height: 100vh;
            background: rgb(251, 250, 250);
            display: flex;
            justify-content: center;
            align-items: flex-start;
        }

        .container {
            width: 80%;
            margin: 5px 0;
            min-height: 100vh;
            padding: 20px;
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        textarea {
            width: 80%;
            min-height: 250px;
            margin: 10px 0;
            font-family: monospace;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
        }
        button {
            background: #007bff;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            cursor: pointer;
            margin: 5px;
        }
        button:hover {
            background: #0056b3;
        }
        .output-container {
            margin-top: 20px;
        }
        .title {
            font-weight: bold;
            margin-bottom: 5px;
            color: #333;
        }
        .checkbox-container {
            margin: 10px 0;
        }
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0,0,0,0.5);
        }
        .modal-content {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            width: 400px;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }
        .modal input[type="text"] {
            width: 100%;
            padding: 8px;
            margin: 10px 0;
            border: 1px solid #ccc;
            border-radius: 4px;
        }
        .modal-buttons {
            display: flex;
            justify-content: space-between;
            margin-top: 15px;
        }
        .modal-buttons button {
            width: 170px;
        }
		
		@media (max-width: 768px) {
            .container {
                padding: 1rem;
                margin: 70px 1rem 1rem;
            }

            .button-container {
                flex-direction: column;
            }

            .modal-content {
                width: 95%;
                padding: 1.5rem;
            }
        }
    </style>
</head>
<body>

    <div class="container">
        <h1>Hex to PCAP Converter</h1>
        <div class="checkbox-container">
            <input type="checkbox" id="addHeaders" checked>
            <label for="addHeaders">Add MAC/IP/UDP Headers (GTP-C Port: 2123)</label>
        </div>

        <div class="input-container">
            <div class="title">Input Hex Stream:</div>
            <textarea id="inputHex" placeholder="Enter hex stream (space or newline separated)"></textarea>
            <div class="button-container">
                <button onclick="convertHex()">Convert to Wireshark Format</button>
                <button onclick="showExportDialog()">Export PCAP</button>
            </div>
        </div>
        
        <div class="output-container">
            <div class="title">Wireshark Compatible Format:</div>
            <textarea id="outputHex" readonly></textarea>
        </div>
    </div>

    <!-- Export Dialog -->
    <div id="exportDialog" class="modal">
        <div class="modal-content">
            <h2>Export PCAP</h2>
            <div>
                <label for="filename">FileName:</label>
                <input type="text" id="filename" value="packet.pcap">
            </div>
            <div class="modal-buttons">
                <button onclick="closeExportDialog()">Cancel</button>
                <button onclick="confirmExport()">Export</button>
            </div>
        </div>
    </div>

    <script>
        const MAC_IP_HEADER_LENGTH = 34;  // MAC + IP header length (不含UDP头)
        const UDP_HEADER_LENGTH = 8;      // UDP header length
        
        function getHeaderTemplate() {
            return [
                'FA', '16', '3E', '3C', 'F5', '10', 'FA', '16',
                '3E', '9F', 'B1', 'B4', '08', '00', '45', '00',
                '00', '00', // IP总长度 (占位)
                '15', '81', '00', '00', '80', '11',
                '00', '00', // IP校验和 (占位)
                '65', '26', '03', '6F', '65', '26',
                '03', 'D7', '08', '4B', '08', '4B',
                '00', '00', // UDP长度 (占位)
                '00', '00'  // UDP校验和 (占位,可选)
            ];
        }

        function calculateIPChecksum(header) {
            let sum = 0;
            for (let i = 14; i < 34; i += 2) {
                const value = (parseInt(header[i], 16) << 8) + parseInt(header[i + 1], 16);
                sum += value;
            }
            
            while (sum >> 16) {
                sum = (sum & 0xFFFF) + (sum >> 16);
            }
            
            return (~sum & 0xFFFF).toString(16).padStart(4, '0');
        }

        function processHexInput(input) {
            const cleaned = input.replace(/[\s\n\r]+/g, '').toUpperCase();
            const bytes = [];
            for (let i = 0; i < cleaned.length; i += 2) {
                bytes.push(cleaned.substr(i, 2));
            }
            return bytes;
        }

        function updateHeaders(headers, dataLength) {
            // 更新IP总长度 (IP头20字节 + UDP头8字节 + 数据长度)
            const ipTotalLength = (20 + 8 + dataLength).toString(16).padStart(4, '0');
            headers[16] = ipTotalLength.slice(0, 2);
            headers[17] = ipTotalLength.slice(2, 4);
            
            // 更新UDP长度 (UDP头8字节 + 数据长度)
            const udpLength = (8 + dataLength).toString(16).padStart(4, '0');
            headers[38] = udpLength.slice(0, 2);
            headers[39] = udpLength.slice(2, 4);
            
            // 更新IP校验和
            const ipChecksum = calculateIPChecksum(headers);
            headers[24] = ipChecksum.slice(0, 2);
            headers[25] = ipChecksum.slice(2, 4);
            
            return headers;
        }

        function convertHex() {
            let input = document.getElementById('inputHex').value;
            let bytes = processHexInput(input);
            
            if (document.getElementById('addHeaders').checked) {
                let headers = getHeaderTemplate();
                headers = updateHeaders(headers, bytes.length);
                bytes = [...headers, ...bytes];
            }
            
            let output = '';
            for (let i = 0; i < bytes.length; i += 16) {
                const offset = (i).toString(16).padStart(4, '0');
                output += offset + '   ';
                
                const lineBytes = bytes.slice(i, i + 16);
                output += lineBytes.join(' ');
                
                if (lineBytes.length < 16) {
                    output += '   '.repeat(16 - lineBytes.length);
                }
                
                output += '\n';
            }
            
            document.getElementById('outputHex').value = output;
        }

        function createPcapHeader() {
            const buffer = new ArrayBuffer(24);
            const view = new DataView(buffer);
            
            view.setUint32(0, 0xa1b2c3d4, false);
            view.setUint16(4, 2, false);
            view.setUint16(6, 4, false);
            view.setInt32(8, 0, false);
            view.setUint32(12, 0, false);
            view.setUint32(16, 65535, false);
            view.setUint32(20, 1, false);
            
            return new Uint8Array(buffer);
        }

        function createPacketHeader(length) {
            const buffer = new ArrayBuffer(16);
            const view = new DataView(buffer);
            const now = Math.floor(Date.now() / 1000);
            
            view.setUint32(0, now, false);
            view.setUint32(4, 0, false);
            view.setUint32(8, length, false);
            view.setUint32(12, length, false);
            
            return new Uint8Array(buffer);
        }

        function showExportDialog() {
            const now = new Date();
            const year = now.getFullYear();
            const month = String(now.getMonth() + 1).padStart(2, '0');
            const day = String(now.getDate()).padStart(2, '0');
            const hours = String(now.getHours()).padStart(2, '0');
            const minutes = String(now.getMinutes()).padStart(2, '0');
            
            const defaultFilename = `packet-${year}-${month}-${day}-${hours}-${minutes}.pcap`;
            document.getElementById('filename').value = defaultFilename;
            document.getElementById('exportDialog').style.display = 'block';
        }

        function closeExportDialog() {
            document.getElementById('exportDialog').style.display = 'none';
        }

        function confirmExport() {
            let filename = document.getElementById('filename').value.trim();
            if (!filename.endsWith('.pcap')) {
                filename += '.pcap';
            }
            exportPcap(filename);
            closeExportDialog();
        }

        function exportPcap(filename) {
            let input = document.getElementById('inputHex').value;
            let hexBytes = processHexInput(input);
            
            if (document.getElementById('addHeaders').checked) {
                let headers = getHeaderTemplate();
                headers = updateHeaders(headers, hexBytes.length);
                hexBytes = [...headers, ...hexBytes];
            }
            
            const packetData = new Uint8Array(hexBytes.map(hex => parseInt(hex, 16)));
            const pcapHeader = createPcapHeader();
            const packetHeader = createPacketHeader(packetData.length);
            
            const finalBuffer = new Uint8Array([
                ...pcapHeader,
                ...packetHeader,
                ...packetData
            ]);
            
            const blob = new Blob([finalBuffer], { type: 'application/octet-stream' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = filename;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }

        window.onload = function() {
            document.getElementById('inputHex').value = '';
        }
    </script>
</body>
</html>
相关推荐
摇光9310 分钟前
js高阶-响应式原理
前端·javascript·vue.js
丁总学Java32 分钟前
error Parsing error: invalid-first-character-of-tag-name vue/no-parsing-error
前端·javascript·vue.js
7_35Durant34 分钟前
vue3 跨级传递数据
前端·javascript·vue.js
马红权42 分钟前
pyautogui自动化鼠标键盘操作
前端·python
程序员海军1 小时前
腾讯混元3D更新:人人都可以轻松制作一个3D模型
前端·openai·unity3d
16年上任的CTO1 小时前
一文大白话讲清楚webpack基本使用——1——完成webpack的初步构建
前端·webpack·node.js
清风细雨_林木木1 小时前
Vue中设置报错页面和“Uncaught runtime errors”弹窗关闭
前端·javascript·vue.js
Zaly.1 小时前
【前端】CSS实战之音乐播放器
前端·css
孤客网络科技工作室1 小时前
不使用 JS 纯 CSS 获取屏幕宽高
开发语言·javascript·css
Nejosi_念旧1 小时前
包文件分析器 Webpack Bundle Analyzer
前端·webpack·node.js