{% extends "base.html" %}
{% block title %}AUTARCH — Exploit Dev{% endblock %}

{% block content %}
<div class="page-header">
    <h1>Exploit Development</h1>
    <p style="margin:0;font-size:0.85rem;color:var(--text-secondary)">
        Shellcode generation, payload encoding, ROP chain building, cyclic patterns, and assembly.
    </p>
</div>

<!-- Tab Bar -->
<div class="tab-bar">
    <button class="tab active" data-tab-group="xdev" data-tab="shellcode" onclick="showTab('xdev','shellcode')">Shellcode</button>
    <button class="tab" data-tab-group="xdev" data-tab="encoder" onclick="showTab('xdev','encoder')">Encoder</button>
    <button class="tab" data-tab-group="xdev" data-tab="rop" onclick="showTab('xdev','rop')">ROP</button>
    <button class="tab" data-tab-group="xdev" data-tab="patterns" onclick="showTab('xdev','patterns')">Patterns</button>
</div>

<!-- ==================== SHELLCODE TAB ==================== -->
<div class="tab-content active" data-tab-group="xdev" data-tab="shellcode">

<div class="section">
    <h2>Shellcode Generator</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Generate architecture-specific shellcode from built-in templates. Supports host/port patching.
    </p>
    <div class="form-row">
        <div class="form-group">
            <label>Shell Type</label>
            <select id="sc-type">
                <option value="reverse_shell">Reverse Shell</option>
                <option value="bind_shell">Bind Shell</option>
                <option value="execve" selected>Exec Command (/bin/sh)</option>
            </select>
        </div>
        <div class="form-group">
            <label>Architecture</label>
            <select id="sc-arch">
                <option value="x86">x86 (32-bit)</option>
                <option value="x64" selected>x64 (64-bit)</option>
                <option value="arm">ARM</option>
            </select>
        </div>
        <div class="form-group">
            <label>Platform</label>
            <select id="sc-platform">
                <option value="linux" selected>Linux</option>
                <option value="windows">Windows</option>
            </select>
        </div>
    </div>
    <div class="form-row">
        <div class="form-group">
            <label>Host (reverse/bind)</label>
            <input type="text" id="sc-host" placeholder="127.0.0.1">
        </div>
        <div class="form-group">
            <label>Port (reverse/bind)</label>
            <input type="text" id="sc-port" placeholder="4444">
        </div>
    </div>
    <div class="form-row">
        <div class="form-group" style="max-width:180px">
            <label>Output Format</label>
            <select id="sc-format">
                <option value="hex">Hex</option>
                <option value="c_array">C Array</option>
                <option value="python">Python</option>
                <option value="nasm">NASM</option>
                <option value="raw">Raw Bytes</option>
            </select>
        </div>
        <div class="form-group" style="max-width:130px;display:flex;align-items:flex-end;padding-bottom:6px">
            <label style="display:flex;align-items:center;gap:6px;cursor:pointer">
                <input type="checkbox" id="sc-staged" style="width:auto"> Staged
            </label>
        </div>
    </div>
    <div class="tool-actions">
        <button id="btn-sc-gen" class="btn btn-primary" onclick="scGenerate()">Generate Shellcode</button>
        <button class="btn btn-small" onclick="scListTemplates()">List Templates</button>
        <button class="btn btn-small" onclick="scCopy()">Copy Output</button>
    </div>
    <div id="sc-meta" style="display:none;margin-top:12px;padding:10px;background:var(--bg-input);border-radius:var(--radius);font-size:0.82rem;color:var(--text-secondary)"></div>
    <pre class="output-panel scrollable" id="sc-output" style="margin-top:10px;min-height:80px">No shellcode generated yet.</pre>
</div>

</div>

<!-- ==================== ENCODER TAB ==================== -->
<div class="tab-content" data-tab-group="xdev" data-tab="encoder">

<div class="section">
    <h2>Payload Encoder</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Encode shellcode to evade signature detection. Supports XOR, AES-256, alphanumeric, and polymorphic encoding.
    </p>
    <div class="form-group">
        <label>Shellcode (hex)</label>
        <textarea id="enc-input" rows="4" placeholder="Paste shellcode hex bytes here, e.g. 31c050682f2f7368..."></textarea>
    </div>
    <div class="form-row">
        <div class="form-group">
            <label>Encoder</label>
            <select id="enc-type">
                <option value="xor" selected>XOR</option>
                <option value="aes">AES-256</option>
                <option value="alphanumeric">Alphanumeric</option>
                <option value="polymorphic">Polymorphic</option>
            </select>
        </div>
        <div class="form-group">
            <label>Key (optional, auto if empty)</label>
            <input type="text" id="enc-key" placeholder="Hex key or passphrase">
        </div>
        <div class="form-group" style="max-width:100px">
            <label>Iterations</label>
            <input type="number" id="enc-iters" value="1" min="1" max="10">
        </div>
    </div>
    <div class="tool-actions">
        <button id="btn-enc" class="btn btn-primary" onclick="encEncode()">Encode</button>
        <button class="btn btn-small" onclick="encCopy()">Copy Encoded</button>
    </div>
    <div id="enc-stats" style="display:none;margin-top:12px;padding:10px;background:var(--bg-input);border-radius:var(--radius);font-size:0.82rem">
        <div style="display:flex;gap:24px;flex-wrap:wrap">
            <div>Original: <strong id="enc-orig-sz">--</strong> bytes</div>
            <div>Encoded: <strong id="enc-new-sz">--</strong> bytes</div>
            <div>Increase: <strong id="enc-increase">--</strong></div>
            <div>Null-free: <strong id="enc-nullfree">--</strong></div>
            <div>Key: <code id="enc-key-used" style="font-size:0.8rem">--</code></div>
        </div>
    </div>
    <div style="margin-top:14px">
        <label style="font-size:0.85rem;color:var(--text-secondary)">Decoder Stub</label>
        <pre class="output-panel scrollable" id="enc-stub" style="min-height:60px"></pre>
    </div>
    <div style="margin-top:10px">
        <label style="font-size:0.85rem;color:var(--text-secondary)">Encoded Payload (hex)</label>
        <pre class="output-panel scrollable" id="enc-output" style="min-height:60px"></pre>
    </div>
</div>

</div>

<!-- ==================== ROP TAB ==================== -->
<div class="tab-content" data-tab-group="xdev" data-tab="rop">

<div class="section">
    <h2>ROP Gadget Finder</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Scan ELF/PE binaries for ROP gadgets. Uses ropper, ROPgadget, or objdump as backend.
    </p>
    <div class="form-row">
        <div class="form-group">
            <label>Binary Path</label>
            <input type="text" id="rop-binary" placeholder="/path/to/binary or /usr/bin/ls">
        </div>
        <div class="form-group" style="max-width:180px">
            <label>Gadget Type</label>
            <select id="rop-type">
                <option value="all">All</option>
                <option value="pop_ret">pop; ret</option>
                <option value="xchg">xchg</option>
                <option value="mov">mov</option>
                <option value="syscall">syscall / int 0x80</option>
                <option value="jmp_esp">jmp esp/rsp</option>
                <option value="call_reg">call reg</option>
            </select>
        </div>
    </div>
    <div class="form-row">
        <div class="form-group" style="max-width:250px">
            <label>Search Filter</label>
            <input type="text" id="rop-search" placeholder="Filter gadgets by text...">
        </div>
    </div>
    <div class="tool-actions">
        <button id="btn-rop-find" class="btn btn-primary" onclick="ropFind()">Find Gadgets</button>
        <button class="btn btn-small" onclick="ropExportChain()">Export Chain</button>
    </div>
    <div id="rop-summary" style="display:none;margin-top:12px;padding:10px;background:var(--bg-input);border-radius:var(--radius);font-size:0.82rem;color:var(--text-secondary)"></div>
    <div style="margin-top:14px;max-height:400px;overflow-y:auto">
        <table class="data-table" id="rop-table">
            <thead><tr><th style="width:140px">Address</th><th>Gadget</th><th style="width:90px">Type</th><th style="width:50px">Add</th></tr></thead>
            <tbody id="rop-tbody">
                <tr><td colspan="4" class="empty-state">Run gadget search to see results.</td></tr>
            </tbody>
        </table>
    </div>
</div>

<div class="section">
    <h2>ROP Chain Builder</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Build a ROP chain by adding gadgets from the table above or manually specifying addresses.
    </p>
    <div style="max-height:250px;overflow-y:auto;margin-bottom:10px">
        <table class="data-table">
            <thead><tr><th style="width:30px">#</th><th style="width:140px">Address</th><th>Gadget</th><th style="width:120px">Value</th><th style="width:50px">Rm</th></tr></thead>
            <tbody id="chain-tbody">
                <tr id="chain-empty"><td colspan="5" class="empty-state">Add gadgets from the results above.</td></tr>
            </tbody>
        </table>
    </div>
    <div class="tool-actions">
        <button class="btn btn-small" onclick="chainAddManual()">+ Manual Entry</button>
        <button class="btn btn-small" onclick="chainClear()">Clear Chain</button>
        <button class="btn btn-primary btn-small" onclick="chainBuild()">Build Chain</button>
    </div>
    <pre class="output-panel scrollable" id="chain-output" style="margin-top:10px;min-height:60px"></pre>
</div>

</div>

<!-- ==================== PATTERNS TAB ==================== -->
<div class="tab-content" data-tab-group="xdev" data-tab="patterns">

<div class="section">
    <h2>Cyclic Pattern Generator</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Generate De Bruijn / cyclic patterns for buffer overflow offset discovery (like pattern_create).
    </p>
    <div class="form-row">
        <div class="form-group" style="max-width:200px">
            <label>Pattern Length</label>
            <input type="number" id="pat-length" value="500" min="1" max="20280">
        </div>
        <div class="form-group" style="display:flex;align-items:flex-end;padding-bottom:6px">
            <button id="btn-pat-create" class="btn btn-primary btn-small" onclick="patCreate()">Generate Pattern</button>
            <button class="btn btn-small" style="margin-left:6px" onclick="patCopyPattern()">Copy</button>
        </div>
    </div>
    <pre class="output-panel scrollable" id="pat-output" style="min-height:60px;word-break:break-all">No pattern generated yet.</pre>
</div>

<div class="section">
    <h2>Pattern Offset Finder</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Find the exact offset of a value within a cyclic pattern (like pattern_offset).
        Accepts hex (0x41326241), integer, or raw string.
    </p>
    <div class="form-row">
        <div class="form-group">
            <label>Value (hex / int / string)</label>
            <input type="text" id="pat-value" placeholder="0x41326241 or Ab3A">
        </div>
        <div class="form-group" style="max-width:160px">
            <label>Pattern Length</label>
            <input type="number" id="pat-off-length" value="20000" min="1" max="20280">
        </div>
        <div class="form-group" style="display:flex;align-items:flex-end;padding-bottom:6px">
            <button id="btn-pat-offset" class="btn btn-primary btn-small" onclick="patOffset()">Find Offset</button>
        </div>
    </div>
    <pre class="output-panel" id="pat-offset-result" style="min-height:40px"></pre>
</div>

<div class="section">
    <h2>Format String Exploitation</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Generate format string test payloads for offset discovery and write-what-where attacks.
    </p>
    <div class="form-row">
        <div class="form-group" style="max-width:140px">
            <label>Test Count</label>
            <input type="number" id="fmt-count" value="20" min="1" max="100">
        </div>
        <div class="form-group" style="display:flex;align-items:flex-end;padding-bottom:6px">
            <button class="btn btn-primary btn-small" onclick="fmtOffset()">Generate Probes</button>
        </div>
    </div>
    <pre class="output-panel scrollable" id="fmt-offset-result" style="min-height:60px"></pre>

    <h3 style="margin-top:18px">Write-What-Where</h3>
    <div class="form-row">
        <div class="form-group">
            <label>Target Address (hex)</label>
            <input type="text" id="fmt-addr" placeholder="0x08049724">
        </div>
        <div class="form-group">
            <label>Value to Write (hex)</label>
            <input type="text" id="fmt-val" placeholder="0xdeadbeef">
        </div>
        <div class="form-group" style="max-width:100px">
            <label>Offset</label>
            <input type="number" id="fmt-off" value="7" min="1" max="200">
        </div>
        <div class="form-group" style="display:flex;align-items:flex-end;padding-bottom:6px">
            <button class="btn btn-primary btn-small" onclick="fmtWrite()">Generate Payload</button>
        </div>
    </div>
    <pre class="output-panel scrollable" id="fmt-write-result" style="min-height:60px"></pre>
</div>

<div class="section">
    <h2>Assembly / Disassembly</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Assemble NASM code to machine bytes or disassemble hex bytes to assembly instructions.
    </p>
    <div class="form-row">
        <div class="form-group" style="max-width:140px">
            <label>Architecture</label>
            <select id="asm-arch">
                <option value="x86">x86</option>
                <option value="x64" selected>x64</option>
                <option value="arm">ARM</option>
            </select>
        </div>
    </div>
    <div class="form-group">
        <label>Assembly Code / Hex Bytes</label>
        <textarea id="asm-input" rows="6" placeholder="Enter NASM assembly code to assemble, or hex bytes to disassemble.&#10;&#10;Example (assemble):&#10;  xor rax, rax&#10;  push rax&#10;  mov al, 0x3b&#10;&#10;Example (disassemble):&#10;  4831c0 50 b03b"></textarea>
    </div>
    <div class="tool-actions">
        <button id="btn-asm" class="btn btn-primary btn-small" onclick="asmAssemble()">Assemble</button>
        <button id="btn-disasm" class="btn btn-primary btn-small" onclick="asmDisassemble()">Disassemble</button>
        <button class="btn btn-small" onclick="asmCopy()">Copy Output</button>
    </div>
    <pre class="output-panel scrollable" id="asm-output" style="margin-top:10px;min-height:60px"></pre>
</div>

</div>

<script>
/* ================================================================
   Exploit Development — JavaScript
   ================================================================ */
var _ropGadgets = [];
var _chainItems = [];

/* ── Shellcode ── */
function scGenerate() {
    var btn = document.getElementById('btn-sc-gen');
    setLoading(btn, true);
    postJSON('/exploit-dev/shellcode', {
        type: document.getElementById('sc-type').value,
        arch: document.getElementById('sc-arch').value,
        platform: document.getElementById('sc-platform').value,
        host: document.getElementById('sc-host').value,
        port: document.getElementById('sc-port').value,
        staged: document.getElementById('sc-staged').checked,
        output_format: document.getElementById('sc-format').value
    }).then(function(data) {
        setLoading(btn, false);
        if (data.error) { renderOutput('sc-output', 'Error: ' + data.error); return; }
        renderOutput('sc-output', data.shellcode || data.hex || '(empty)');
        var meta = document.getElementById('sc-meta');
        meta.style.display = '';
        meta.innerHTML =
            '<strong>Template:</strong> ' + esc(data.template || '--') +
            ' &nbsp;|&nbsp; <strong>Length:</strong> ' + (data.length || 0) + ' bytes' +
            ' &nbsp;|&nbsp; <strong>Null-free:</strong> ' + (data.null_free ? 'Yes' : 'No') +
            ' &nbsp;|&nbsp; <strong>Arch:</strong> ' + esc(data.arch || '--') +
            ' &nbsp;|&nbsp; ' + esc(data.staging || '');
    }).catch(function() { setLoading(btn, false); });
}

function scListTemplates() {
    fetchJSON('/exploit-dev/shellcodes').then(function(data) {
        if (!data.shellcodes || !data.shellcodes.length) {
            renderOutput('sc-output', 'No templates available.');
            return;
        }
        var lines = ['=== Available Shellcode Templates ===', ''];
        data.shellcodes.forEach(function(sc) {
            lines.push(sc.name);
            lines.push('  ' + sc.description);
            lines.push('  Arch: ' + sc.arch + '  Platform: ' + sc.platform +
                        '  Length: ' + sc.length + '  Null-free: ' + (sc.null_free ? 'Yes' : 'No'));
            lines.push('');
        });
        renderOutput('sc-output', lines.join('\n'));
    });
}

function scCopy() {
    var text = document.getElementById('sc-output').textContent;
    if (text) navigator.clipboard.writeText(text);
}

/* ── Encoder ── */
function encEncode() {
    var btn = document.getElementById('btn-enc');
    setLoading(btn, true);
    postJSON('/exploit-dev/encode', {
        shellcode: document.getElementById('enc-input').value.trim(),
        encoder: document.getElementById('enc-type').value,
        key: document.getElementById('enc-key').value.trim(),
        iterations: parseInt(document.getElementById('enc-iters').value) || 1
    }).then(function(data) {
        setLoading(btn, false);
        if (data.error) {
            renderOutput('enc-output', 'Error: ' + data.error);
            return;
        }
        document.getElementById('enc-stats').style.display = '';
        document.getElementById('enc-orig-sz').textContent = data.original_length;
        document.getElementById('enc-new-sz').textContent = data.encoded_length;
        document.getElementById('enc-increase').textContent = data.size_increase;
        document.getElementById('enc-nullfree').textContent = data.null_free ? 'Yes' : 'No';
        document.getElementById('enc-nullfree').style.color = data.null_free ? 'var(--success,#4ade80)' : 'var(--danger)';
        document.getElementById('enc-key-used').textContent = data.key || '--';
        renderOutput('enc-stub', data.decoder_stub || '(no stub)');
        renderOutput('enc-output', data.encoded || '');
    }).catch(function() { setLoading(btn, false); });
}

function encCopy() {
    var text = document.getElementById('enc-output').textContent;
    if (text) navigator.clipboard.writeText(text);
}

/* ── ROP ── */
function ropFind() {
    var btn = document.getElementById('btn-rop-find');
    setLoading(btn, true);
    postJSON('/exploit-dev/rop/gadgets', {
        binary_path: document.getElementById('rop-binary').value.trim(),
        gadget_type: document.getElementById('rop-type').value
    }).then(function(data) {
        setLoading(btn, false);
        if (data.error) {
            document.getElementById('rop-tbody').innerHTML =
                '<tr><td colspan="4" class="empty-state">Error: ' + esc(data.error) + '</td></tr>';
            return;
        }
        _ropGadgets = data.gadgets || [];
        var summary = document.getElementById('rop-summary');
        summary.style.display = '';
        summary.innerHTML = 'Found <strong>' + data.count + '</strong> gadgets in ' +
            esc(data.binary || '--') + ' via <strong>' + esc(data.tool || '--') + '</strong>';
        ropRenderTable();
    }).catch(function() { setLoading(btn, false); });
}

function ropRenderTable() {
    var filter = document.getElementById('rop-search').value.toLowerCase();
    var filtered = _ropGadgets;
    if (filter) {
        filtered = _ropGadgets.filter(function(g) {
            return g.gadget.toLowerCase().indexOf(filter) !== -1 ||
                   g.address.toLowerCase().indexOf(filter) !== -1 ||
                   g.type.toLowerCase().indexOf(filter) !== -1;
        });
    }
    var html = '';
    if (!filtered.length) {
        html = '<tr><td colspan="4" class="empty-state">No matching gadgets.</td></tr>';
    } else {
        filtered.forEach(function(g, i) {
            html += '<tr>'
                + '<td><code style="font-size:0.8rem">' + esc(g.address) + '</code></td>'
                + '<td style="font-size:0.82rem">' + esc(g.gadget) + '</td>'
                + '<td><span class="badge" style="font-size:0.7rem">' + esc(g.type) + '</span></td>'
                + '<td><button class="btn btn-small" style="padding:2px 8px;font-size:0.7rem" onclick="chainAdd(' + i + ')">+</button></td>'
                + '</tr>';
        });
    }
    document.getElementById('rop-tbody').innerHTML = html;
}

/* live search filter */
document.addEventListener('DOMContentLoaded', function() {
    var el = document.getElementById('rop-search');
    if (el) el.addEventListener('input', ropRenderTable);
});

function chainAdd(gadgetIdx) {
    var g = _ropGadgets[gadgetIdx];
    if (!g) return;
    _chainItems.push({address: g.address, gadget: g.gadget, type: g.type, value: ''});
    chainRender();
}

function chainAddManual() {
    var addr = prompt('Gadget address (hex):', '0x');
    if (!addr) return;
    var instr = prompt('Gadget instruction:', 'pop rdi ; ret');
    _chainItems.push({address: addr, gadget: instr || '???', type: 'manual', value: ''});
    chainRender();
}

function chainRemove(idx) {
    _chainItems.splice(idx, 1);
    chainRender();
}

function chainClear() {
    _chainItems = [];
    chainRender();
    renderOutput('chain-output', '');
}

function chainRender() {
    var tbody = document.getElementById('chain-tbody');
    var empty = document.getElementById('chain-empty');
    if (!_chainItems.length) {
        tbody.innerHTML = '<tr id="chain-empty"><td colspan="5" class="empty-state">Add gadgets from the results above.</td></tr>';
        return;
    }
    var html = '';
    _chainItems.forEach(function(c, i) {
        html += '<tr>'
            + '<td>' + (i + 1) + '</td>'
            + '<td><code style="font-size:0.8rem">' + esc(c.address) + '</code></td>'
            + '<td style="font-size:0.82rem">' + esc(c.gadget) + '</td>'
            + '<td><input type="text" class="chain-val" data-idx="' + i + '" value="' + esc(c.value) + '" '
            + 'placeholder="0x..." style="font-size:0.78rem;padding:2px 6px;width:100px" '
            + 'onchange="chainUpdateVal(' + i + ', this.value)"></td>'
            + '<td><button class="btn btn-small" style="padding:2px 8px;font-size:0.7rem;color:var(--danger)" '
            + 'onclick="chainRemove(' + i + ')">X</button></td>'
            + '</tr>';
    });
    tbody.innerHTML = html;
}

function chainUpdateVal(idx, val) {
    if (_chainItems[idx]) _chainItems[idx].value = val;
}

function chainBuild() {
    if (!_chainItems.length) { alert('Add gadgets to the chain first.'); return; }
    var spec = _chainItems.map(function(c) {
        return {
            gadget_type: c.type === 'manual' ? 'pop_ret' : c.type,
            register: '',
            value: c.value || '0'
        };
    });
    var gadgets = _chainItems.map(function(c) {
        return {address: c.address, gadget: c.gadget, type: c.type === 'manual' ? 'pop_ret' : c.type};
    });
    postJSON('/exploit-dev/rop/chain', {gadgets: gadgets, chain_spec: spec}).then(function(data) {
        if (data.error) { renderOutput('chain-output', 'Error: ' + data.error); return; }
        var lines = ['=== ROP Chain (' + data.chain_length + ' bytes) ===', ''];
        lines.push(data.debug || '');
        lines.push('');
        lines.push('--- Hex ---');
        lines.push(data.chain_hex);
        lines.push('');
        lines.push('--- Python ---');
        lines.push(data.python || '');
        renderOutput('chain-output', lines.join('\n'));
    });
}

function ropExportChain() {
    var text = document.getElementById('chain-output').textContent;
    if (text) navigator.clipboard.writeText(text);
}

/* ── Patterns ── */
function patCreate() {
    var btn = document.getElementById('btn-pat-create');
    setLoading(btn, true);
    postJSON('/exploit-dev/pattern/create', {
        length: parseInt(document.getElementById('pat-length').value) || 500
    }).then(function(data) {
        setLoading(btn, false);
        if (data.error) { renderOutput('pat-output', 'Error: ' + data.error); return; }
        renderOutput('pat-output', data.pattern || '');
    }).catch(function() { setLoading(btn, false); });
}

function patCopyPattern() {
    var text = document.getElementById('pat-output').textContent;
    if (text && text !== 'No pattern generated yet.') navigator.clipboard.writeText(text);
}

function patOffset() {
    var btn = document.getElementById('btn-pat-offset');
    setLoading(btn, true);
    postJSON('/exploit-dev/pattern/offset', {
        value: document.getElementById('pat-value').value.trim(),
        length: parseInt(document.getElementById('pat-off-length').value) || 20000
    }).then(function(data) {
        setLoading(btn, false);
        if (data.error && data.offset === -1) {
            renderOutput('pat-offset-result', 'Not found: ' + data.error);
            return;
        }
        if (data.offset >= 0) {
            var lines = [
                'Exact offset: ' + data.offset,
                'Matched: ' + (data.matched || '--') + ' (' + (data.endian || '--') + ')',
                'Matched hex: ' + (data.matched_hex || '--'),
                'Pattern length searched: ' + (data.pattern_length || '--')
            ];
            renderOutput('pat-offset-result', lines.join('\n'));
        } else {
            renderOutput('pat-offset-result', data.error || 'Not found.');
        }
    }).catch(function() { setLoading(btn, false); });
}

/* ── Format String ── */
function fmtOffset() {
    postJSON('/exploit-dev/format/offset', {
        test_count: parseInt(document.getElementById('fmt-count').value) || 20
    }).then(function(data) {
        if (data.error) { renderOutput('fmt-offset-result', 'Error: ' + data.error); return; }
        var lines = ['=== Format String Probes ===', ''];
        var payloads = data.payloads || {};
        Object.keys(payloads).forEach(function(key) {
            var p = payloads[key];
            lines.push('--- ' + key + ' ---');
            lines.push(p.description || '');
            lines.push(p.payload || '');
            lines.push('');
        });
        if (data.note) { lines.push(data.note); }
        renderOutput('fmt-offset-result', lines.join('\n'));
    });
}

function fmtWrite() {
    var addr = document.getElementById('fmt-addr').value.trim();
    var val = document.getElementById('fmt-val').value.trim();
    var off = document.getElementById('fmt-off').value;
    if (!addr || !val) { alert('Provide target address and value.'); return; }
    postJSON('/exploit-dev/format/write', {
        address: addr, value: val, offset: parseInt(off) || 7
    }).then(function(data) {
        if (data.error) { renderOutput('fmt-write-result', 'Error: ' + data.error); return; }
        var lines = ['=== Format String Write Payloads ===', ''];
        if (data.payload_32bit) {
            lines.push('--- 32-bit (%hn) ---');
            lines.push(data.payload_32bit.description || '');
            lines.push('Addresses: ' + (data.payload_32bit.addresses || ''));
            lines.push('Payload: ' + (data.payload_32bit.payload || ''));
            lines.push('');
        }
        if (data.payload_64bit) {
            lines.push('--- 64-bit (%hn) ---');
            lines.push(data.payload_64bit.description || '');
            lines.push('Payload: ' + (data.payload_64bit.payload || ''));
        }
        renderOutput('fmt-write-result', lines.join('\n'));
    });
}

/* ── Assembly / Disassembly ── */
function asmAssemble() {
    var btn = document.getElementById('btn-asm');
    setLoading(btn, true);
    postJSON('/exploit-dev/assemble', {
        code: document.getElementById('asm-input').value,
        arch: document.getElementById('asm-arch').value
    }).then(function(data) {
        setLoading(btn, false);
        if (data.error) { renderOutput('asm-output', 'Error: ' + data.error); return; }
        var lines = ['=== Assembly Result ===',
                     'Length: ' + data.length + ' bytes',
                     'Arch: ' + (data.arch || '--'),
                     '',
                     'Hex: ' + (data.hex || ''),
                     '',
                     'C array: ' + (data.c_array || ''),
                     '',
                     'Python: ' + (data.python || '')];
        renderOutput('asm-output', lines.join('\n'));
    }).catch(function() { setLoading(btn, false); });
}

function asmDisassemble() {
    var btn = document.getElementById('btn-disasm');
    setLoading(btn, true);
    postJSON('/exploit-dev/disassemble', {
        hex: document.getElementById('asm-input').value.trim(),
        arch: document.getElementById('asm-arch').value
    }).then(function(data) {
        setLoading(btn, false);
        if (data.error) { renderOutput('asm-output', 'Error: ' + data.error); return; }
        var lines = ['=== Disassembly (' + (data.count || 0) + ' instructions, via ' + (data.tool || '?') + ') ===', ''];
        lines.push(data.listing || '(no output)');
        if (data.note) { lines.push(''); lines.push('Note: ' + data.note); }
        renderOutput('asm-output', lines.join('\n'));
    }).catch(function() { setLoading(btn, false); });
}

function asmCopy() {
    var text = document.getElementById('asm-output').textContent;
    if (text) navigator.clipboard.writeText(text);
}
</script>
{% endblock %}
