<div id="bin-search-wrapper"> <ul id="bin-search-filters" class="function-list"> {% for function_pair in site.data.functions %} {% assign function_id = function_pair[0] %} {% assign function = function_pair[1] %} <li><a href="#+{{ function.label | downcase }}" data-title="{{ function.description | replace: '\n', ' ' }}">{{ function.label }}</a></li> {% endfor %} </ul> <input id="bin-search" type="text" placeholder="Search among {{ site.gtfobins | size }} binaries: <binary> +<function> ..."/> </div> <div id="bin-table-wrapper"> <table id="bin-table"> <thead> <tr> <th>Binary</th> <th>Functions</th> </tr> </thead> <tbody> {% for file in site.gtfobins %} <tr> <td><a href="{{ file.url }}" class="bin-name">{% include get_bin_name path=file.path %}</a></td> <td>{% include function_list.html bin=file %}</td> </tr> {% endfor %} </tbody> <tfoot> <tr><td id="search-message" colspan="2">No binary matches...</td></tr> </tfoot> </table> </div> <script> function filter(query) { var queryArray = query.toLowerCase().trim().split(/ *\+/); var binPattern = queryArray[0]; var functionPatterns = queryArray.splice(1); // filter rows var noResults = true; document.querySelectorAll('#bin-table tbody tr').forEach(function (row) { var show = true; var binName = row.children[0].firstElementChild.innerText.toLowerCase(); if (binName.indexOf(binPattern) === -1) { show = false; } if (show) { var functionElems = Array.from(row.children[1].firstElementChild.children); functionElems.forEach((item) => { item.className = ''; }); functionPatterns.forEach((pattern) => { // skip empty filters if (!pattern) { return; } // check against the pattern var noMatches = true; functionElems.forEach((item) => { if (item.innerText.toLowerCase().startsWith(pattern.toLowerCase())) { item.className = 'match'; noMatches = false; } }); // no function satisfies the pattern if (noMatches) { show = false; } }); } if (show) { row.style.display = ''; noResults = false; } else { row.style.display = 'none'; } }); // update the search message visibility var searchMessage = document.getElementById('search-message'); searchMessage.style.display = noResults ? 'table-cell' : 'none'; } function applyFilter() { // filter on load according to the URL var searchBox = document.getElementById('bin-search'); var query = decodeURIComponent(location.hash.slice(1)); filter(query); if (query) { searchBox.value = query; } } function setup() { var searchBox = document.getElementById('bin-search'); // ensure height during filtering var binTableWrapper = document.getElementById('bin-table-wrapper'); binTableWrapper.style.height = binTableWrapper.clientHeight + 'px'; // handle user input searchBox.addEventListener('input', function () { var query = searchBox.value; history.replaceState(null, null, '#' + query); applyFilter(); }); // handle shortcuts addEventListener('keydown', function (event) { // focus search box on valid keydown if (event.key.toLowerCase().match(/^[+a-z]$/) && !(event.ctrlKey || event.altKey || event.metaKey)) { searchBox.focus(); searchBox.parentElement.scrollIntoView(); } // clear filter on escape else if (event.key === 'Escape') { location.hash = searchBox.value = ''; searchBox.focus(); searchBox.parentElement.scrollIntoView(); } }); // handle URL changes window.onhashchange = applyFilter; // trigger filter on page load applyFilter(); } setup(); </script>