Threat Hunting Methods for PE-files analysis

This commit is contained in:
BlackSnufkin
2025-01-02 01:53:03 -08:00
parent ef5fcc3bba
commit 06dcf32832
4 changed files with 538 additions and 93 deletions
+206 -47
View File
@@ -17,48 +17,8 @@ def allowed_file(filename, config):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in config['upload']['allowed_extensions']
def save_uploaded_file(file, upload_folder):
file_content = file.read()
file.close()
md5_hash = hashlib.md5(file_content).hexdigest()
sha256_hash = hashlib.sha256(file_content).hexdigest()
original_filename = secure_filename(file.filename)
extension = os.path.splitext(original_filename)[1].lower()
filename = f"{md5_hash}_{original_filename}"
os.makedirs(upload_folder, exist_ok=True)
filepath = os.path.join(upload_folder, filename)
with open(filepath, 'wb') as f:
f.write(file_content)
file_info = {
'original_name': original_filename,
'md5': md5_hash,
'sha256': sha256_hash,
'size': len(file_content),
'extension': extension,
'mime_type': mimetypes.guess_type(original_filename)[0] or 'application/octet-stream',
'upload_time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'entropy': calculate_entropy(file_content),
}
# Add specific file type information for PE files
if extension in ['.exe', '.dll', '.sys']:
file_info.update(get_pe_info(filepath))
# Add specific file type information for Office documents
if extension in ['.docx', '.xlsx', '.doc', '.xls', '.xlsm', '.docm']:
office_result = get_office_info(filepath)
if 'error' in office_result:
print(f"Warning: {office_result['error']}")
file_info.update(office_result)
return file_info
def calculate_entropy(data):
"""Calculate Shannon entropy of data"""
"""Calculate Shannon entropy of data with detection insights"""
if len(data) == 0:
return 0
@@ -80,18 +40,136 @@ def calculate_entropy(data):
return round(entropy, 2)
def get_pe_info(filepath):
"""Get PE file information"""
"""Enhanced PE file analysis with deep import analysis and detection vectors"""
try:
pe = pefile.PE(filepath)
# Enhanced section analysis
sections_info = []
suspicious_imports = []
high_risk_imports = {
'kernel32.dll': {
'createremotethread': 'Process Injection capability detected',
'virtualallocex': 'Memory allocation in remote process detected',
'writeprocessmemory': 'Process memory manipulation detected',
'getprocaddress': 'Dynamic API resolution - possible evasion technique',
'loadlibrarya': 'Dynamic library loading - possible evasion technique',
'openprocess': 'Process manipulation capability',
'createtoolhelp32snapshot': 'Process enumeration capability',
'process32first': 'Process enumeration capability',
'process32next': 'Process enumeration capability'
},
'user32.dll': {
'getasynckeystate': 'Potential keylogging capability',
'getdc': 'Screen capture capability',
'getforegroundwindow': 'Window/Process monitoring capability'
},
'wininet.dll': {
'internetconnect': 'Network communication capability',
'internetopen': 'Network communication capability',
'ftpputfile': 'FTP upload capability',
'ftpopenfile': 'FTP communication capability'
},
'urlmon.dll': {
'urldownloadtofile': 'File download capability'
}
}
"""
https://practicalsecurityanalytics.com/threat-hunting-with-function-imports/
"""
# Check imports for suspicious behavior
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
for entry in pe.DIRECTORY_ENTRY_IMPORT:
dll_name = entry.dll.decode().lower()
# Check each imported function
for imp in entry.imports:
if imp.name:
func_name = imp.name.decode().lower()
# Check if this is a high-risk import
if dll_name in high_risk_imports and func_name in high_risk_imports[dll_name]:
suspicious_imports.append({
'dll': dll_name,
'function': func_name,
'note': high_risk_imports[dll_name][func_name],
'hint': imp.hint if hasattr(imp, 'hint') else 0
})
"""
https://practicalsecurityanalytics.com/file-entropy/
"""
# Section Analysis with entropy
for section in pe.sections:
section_name = section.Name.decode().rstrip('\x00')
section_data = section.get_data()
section_entropy = calculate_entropy(section_data)
# Standard PE sections
standard_sections = ['.text', '.data', '.bss', '.rdata', '.edata', '.idata', '.pdata', '.reloc', '.rsrc', '.tls', '.debug']
is_standard = section_name in standard_sections
sections_info.append({
'name': section_name,
'entropy': section_entropy,
'size': len(section_data),
'characteristics': section.Characteristics,
'is_standard': is_standard,
'detection_notes': []
})
# Add section-specific detection notes
if section_entropy > 7.2:
sections_info[-1]['detection_notes'].append('High entropy may trigger detection')
if section_name == '.text' and section_entropy > 7.0:
sections_info[-1]['detection_notes'].append('Unusual entropy for code section')
if not is_standard:
sections_info[-1]['detection_notes'].append('Non-standard section name - may trigger detection')
"""
https://practicalsecurityanalytics.com/pe-checksum/
"""
# Check PE Checksum
is_valid_checksum = pe.verify_checksum()
calculated_checksum = pe.generate_checksum()
stored_checksum = pe.OPTIONAL_HEADER.CheckSum
info = {
'file_type': 'PE32+ executable' if pe.PE_TYPE == pefile.OPTIONAL_HEADER_MAGIC_PE_PLUS else 'PE32 executable',
'machine_type': pefile.MACHINE_TYPE[pe.FILE_HEADER.Machine].replace('IMAGE_FILE_MACHINE_', ''),
'compile_time': datetime.datetime.fromtimestamp(pe.FILE_HEADER.TimeDateStamp).strftime('%Y-%m-%d %H:%M:%S'),
'subsystem': pefile.SUBSYSTEM_TYPE[pe.OPTIONAL_HEADER.Subsystem].replace('IMAGE_SUBSYSTEM_', ''),
'entry_point': hex(pe.OPTIONAL_HEADER.AddressOfEntryPoint),
'sections': [section.Name.decode().rstrip('\x00') for section in pe.sections],
'imports': list(set(entry.dll.decode() for entry in getattr(pe, 'DIRECTORY_ENTRY_IMPORT', [])))
'sections': sections_info,
'imports': list(set(entry.dll.decode() for entry in getattr(pe, 'DIRECTORY_ENTRY_IMPORT', []))),
'suspicious_imports': suspicious_imports,
'detection_notes': [],
'checksum_info': {
'is_valid': is_valid_checksum,
'stored_checksum': hex(stored_checksum),
'calculated_checksum': hex(calculated_checksum),
'needs_update': calculated_checksum != stored_checksum
}
}
# Add overall detection insights
if not is_valid_checksum:
info['detection_notes'].append('Invalid PE checksum - Common in modified/packed files (~83% correlation with malware)')
if suspicious_imports:
info['detection_notes'].append(f'Found {len(suspicious_imports)} suspicious API imports - Review import analysis')
if any(section['entropy'] > 7.2 for section in sections_info):
info['detection_notes'].append('High entropy sections detected - Consider entropy reduction techniques')
if '.text' in [section['name'] for section in sections_info]:
text_section = next(s for s in sections_info if s['name'] == '.text')
if text_section['entropy'] > 7.0:
info['detection_notes'].append('Packed/encrypted code section may trigger heuristics')
if any(not section['is_standard'] for section in sections_info):
info['detection_notes'].append('Non-standard PE sections detected - May trigger static analysis')
pe.close()
return {'pe_info': info}
except Exception as e:
@@ -99,20 +177,101 @@ def get_pe_info(filepath):
return {'pe_info': None}
def get_office_info(filepath):
"""Get Office document information"""
"""Enhanced Office document analysis with detection insights"""
try:
vbaparser = VBA_Parser(filepath)
detection_notes = []
info = {
'file_type': 'Microsoft Office Document',
'has_macros': vbaparser.detect_vba_macros(),
'macro_info': vbaparser.analyze_macros() if vbaparser.detect_vba_macros() else None,
'macro_info': None,
'detection_notes': detection_notes
}
vbaparser.close() # Release the VBA Parser resource
if vbaparser.detect_vba_macros():
macro_analysis = vbaparser.analyze_macros()
info['macro_info'] = macro_analysis
# Analyze macros for detection vectors
macro_text = str(macro_analysis).lower()
detection_patterns = {
'shell': 'Shell command execution detected',
'wscript': 'WScript execution detected',
'powershell': 'PowerShell execution detected',
'http': 'Network communication detected',
'auto': 'Auto-execution mechanism detected',
'document_open': 'Document open auto-execution',
'windowshide': 'Hidden window execution',
'createobject': 'COM object creation detected'
}
for pattern, note in detection_patterns.items():
if pattern in macro_text:
detection_notes.append(note)
vbaparser.close()
return {'office_info': info}
except Exception as e:
print(f"Error analyzing Office file: {e}")
return {'office_info': None}
def save_uploaded_file(file, upload_folder):
file_content = file.read()
file.close()
md5_hash = hashlib.md5(file_content).hexdigest()
sha256_hash = hashlib.sha256(file_content).hexdigest()
original_filename = secure_filename(file.filename)
extension = os.path.splitext(original_filename)[1].lower()
filename = f"{md5_hash}_{original_filename}"
os.makedirs(upload_folder, exist_ok=True)
filepath = os.path.join(upload_folder, filename)
with open(filepath, 'wb') as f:
f.write(file_content)
entropy_value = calculate_entropy(file_content)
file_info = {
'original_name': original_filename,
'md5': md5_hash,
'sha256': sha256_hash,
'size': len(file_content),
'extension': extension,
'mime_type': mimetypes.guess_type(original_filename)[0] or 'application/octet-stream',
'upload_time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'entropy': entropy_value,
'entropy_analysis': {
'value': entropy_value,
'detection_risk': 'High' if entropy_value > 7.2 else
'Medium' if entropy_value > 6.8 else 'Low',
'notes': []
}
}
# Add entropy-based detection notes
if entropy_value > 7.2:
file_info['entropy_analysis']['notes'].append(
'High entropy indicates encryption/packing - consider entropy reduction')
elif entropy_value > 6.8:
file_info['entropy_analysis']['notes'].append(
'Moderate entropy - may trigger basic detection')
# Add specific file type information for PE files
if extension in ['.exe', '.dll', '.sys']:
file_info.update(get_pe_info(filepath))
# Add specific file type information for Office documents
if extension in ['.docx', '.xlsx', '.doc', '.xls', '.xlsm', '.docm']:
office_result = get_office_info(filepath)
if 'error' in office_result:
print(f"Warning: {office_result['error']}")
file_info.update(office_result)
return file_info
def find_file_by_hash(file_hash, upload_folder):
for filename in os.listdir(upload_folder):
if filename.startswith(file_hash):
+1 -1
View File
@@ -662,7 +662,7 @@ const tools = {
<div class="grid grid-cols-3 gap-4 mb-6">
<div class="bg-gray-900/30 rounded-lg border ${isClean ? 'border-green-500/30' : 'border-red-500/30'} p-4">
<div class="text-sm text-gray-500">Status</div>
<div class="text-xl font-semibold ${isClean ? 'text-green-500' : 'text-red-500'}">
<div class="text-base font-semibold ${isClean ? 'text-green-500' : 'text-red-500'}">
${isClean ? 'Clean' : (findings.initial_threat || 'Unknown Threat')}
</div>
</div>
+231 -39
View File
@@ -31,7 +31,25 @@ document.addEventListener('DOMContentLoaded', function() {
step2Circle: document.getElementById('step2Circle'),
step2Text: document.getElementById('step2Text'),
progressLine: document.getElementById('progressLine'),
toastContainer: document.getElementById('toastContainer')
toastContainer: document.getElementById('toastContainer'),
entropyBar: document.getElementById('entropyBar'),
entropyNotes: document.getElementById('entropyNotes'),
detectionRisk: document.getElementById('detectionRisk'),
peInfo: document.getElementById('peInfo'),
sectionsList: document.getElementById('sectionsList'),
detectionNotes: document.getElementById('detectionNotes'),
officeInfo: document.getElementById('officeInfo'),
macroStatus: document.getElementById('macroStatus'),
checksumInfo: document.getElementById('checksumInfo'),
checksumStatus: document.getElementById('checksumStatus'),
storedChecksum: document.getElementById('storedChecksum'),
calculatedChecksum: document.getElementById('calculatedChecksum'),
checksumNotes: document.getElementById('checksumNotes'),
// New suspicious imports elements
suspiciousImports: document.getElementById('suspiciousImports'),
suspiciousImportsList: document.getElementById('suspiciousImportsList'),
suspiciousImportsCount: document.getElementById('suspiciousImportsCount'),
suspiciousImportsSummary: document.getElementById('suspiciousImportsSummary')
};
let currentFileHash = null;
@@ -75,6 +93,38 @@ document.addEventListener('DOMContentLoaded', function() {
icon.classList.add('scale-110');
}
function updateEntropyAnalysis(fileInfo) {
if (fileInfo.entropy_analysis) {
const entropyPercentage = (fileInfo.entropy / 8) * 100;
elements.entropyBar.style.width = `${entropyPercentage}%`;
elements.entropyBar.className = `absolute h-full transition-all duration-300 ${
fileInfo.entropy_analysis.detection_risk === 'High' ? 'bg-red-500' :
fileInfo.entropy_analysis.detection_risk === 'Medium' ? 'bg-yellow-500' :
'bg-green-500'
}`;
elements.detectionRisk.className = `px-3 py-1 text-sm rounded-full ${
fileInfo.entropy_analysis.detection_risk === 'High' ? 'bg-red-500/10 text-red-500' :
fileInfo.entropy_analysis.detection_risk === 'Medium' ? 'bg-yellow-500/10 text-yellow-500' :
'bg-green-500/10 text-green-500'
}`;
elements.detectionRisk.textContent = `${fileInfo.entropy_analysis.detection_risk} Detection Risk`;
if (fileInfo.entropy_analysis.notes.length > 0) {
elements.entropyNotes.innerHTML = fileInfo.entropy_analysis.notes.map(note => `
<div class="flex items-center space-x-2">
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<span>${note}</span>
</div>
`).join('');
}
}
}
function unhighlight() {
const label = elements.dropZone.querySelector('label');
const icon = elements.dropZone.querySelector('.upload-icon');
@@ -153,13 +203,111 @@ document.addEventListener('DOMContentLoaded', function() {
elements.step2Text.classList.add('text-red-500');
}
}
// Add this function after your existing utility functions
function getDetectionRiskColor(risk) {
const colors = {
'High': 'bg-red-500/10 text-red-500',
'Medium': 'bg-yellow-500/10 text-yellow-500',
'Low': 'bg-green-500/10 text-green-500'
};
return colors[risk] || colors['Low'];
}
// File Info Functions
// Modify your renderFileTypeSpecificInfo function
function renderFileTypeSpecificInfo(fileInfo) {
let html = '';
// Hide both specific info sections by default
elements.peInfo.classList.add('hidden');
elements.officeInfo.classList.add('hidden');
elements.suspiciousImports.classList.add('hidden');
// Update entropy analysis
if (fileInfo.entropy_analysis) {
const entropyPercentage = (fileInfo.entropy / 8) * 100;
elements.entropyBar.style.width = `${entropyPercentage}%`;
elements.entropyBar.className = `absolute h-full transition-all duration-300 ${
fileInfo.entropy_analysis.detection_risk === 'High' ? 'bg-red-500' :
fileInfo.entropy_analysis.detection_risk === 'Medium' ? 'bg-yellow-500' : 'bg-green-500'
}`;
elements.detectionRisk.className = `px-3 py-1 text-sm rounded-full ${
getDetectionRiskColor(fileInfo.entropy_analysis.detection_risk)
}`;
elements.detectionRisk.textContent = `${fileInfo.entropy_analysis.detection_risk} Detection Risk`;
elements.entropyNotes.innerHTML = fileInfo.entropy_analysis.notes.map(note => `
<div class="flex items-center space-x-2">
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<span>${note}</span>
</div>
`).join('');
}
// Render PE-specific information
if (fileInfo.pe_info) {
elements.peInfo.classList.remove('hidden');
const pe = fileInfo.pe_info;
// Handle suspicious imports
if (pe.suspicious_imports && pe.suspicious_imports.length > 0) {
elements.suspiciousImports.classList.remove('hidden');
elements.suspiciousImportsCount.textContent = `${pe.suspicious_imports.length} Found`;
elements.suspiciousImportsList.innerHTML = pe.suspicious_imports.map(imp => `
<div class="border-b border-gray-800 last:border-b-0 pb-3">
<div class="flex items-center justify-between mb-2">
<div class="flex items-center space-x-2">
<span class="text-red-500 font-mono">${imp.dll}</span>
<span class="text-gray-400">→</span>
<span class="text-gray-300 font-mono">${imp.function}</span>
</div>
<span class="text-xs text-gray-500">Hint: ${imp.hint}</span>
</div>
<div class="flex items-center space-x-2">
<svg class="w-4 h-4 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
<span class="text-sm text-gray-400">${imp.note}</span>
</div>
</div>
`).join('');
elements.suspiciousImportsSummary.textContent =
`Found ${pe.suspicious_imports.length} potentially suspicious imports that may indicate malicious capabilities.`;
}
// Add checksum info display
if (pe.checksum_info) {
elements.checksumInfo.classList.remove('hidden');
elements.storedChecksum.textContent = pe.checksum_info.stored_checksum;
elements.calculatedChecksum.textContent = pe.checksum_info.calculated_checksum;
// Set checksum status
elements.checksumStatus.className = `px-3 py-1 text-sm rounded-full ${
pe.checksum_info.is_valid ? 'bg-green-500/10 text-green-500' : 'bg-red-500/10 text-red-500'
}`;
elements.checksumStatus.textContent = pe.checksum_info.is_valid ? 'Valid' : 'Invalid';
// Add checksum notes if needed
if (!pe.checksum_info.is_valid) {
elements.checksumNotes.innerHTML = `
<div class="flex items-center space-x-2">
<svg class="w-4 h-4 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
<span>Invalid checksum - Common in packed/modified payloads</span>
</div>
`;
}
} else {
elements.checksumInfo.classList.add('hidden');
}
// Original PE info display
html = `
<div class="space-y-4">
<div class="flex items-center justify-between">
@@ -187,11 +335,14 @@ document.addEventListener('DOMContentLoaded', function() {
<span class="text-sm text-gray-400">${pe.sections.length} sections</span>
</div>
<div class="flex flex-wrap gap-2">
${pe.sections.map(section => `
<span class="px-2 py-1 text-sm bg-gray-900/50 rounded-lg border border-gray-800 text-gray-400">
${section}
</span>
`).join('')}
${pe.sections.map(section => {
const isStandardSection = ['.text', '.data', '.bss', '.rdata', '.edata', '.idata', '.pdata', '.reloc', '.rsrc', '.tls', '.debug'].includes(section.name);
return `
<span class="px-2 py-1 text-sm ${isStandardSection ? 'bg-gray-900/50 text-gray-400' : 'bg-red-500/10 text-red-500'} rounded-lg border ${isStandardSection ? 'border-gray-800' : 'border-red-900/20'}">
${section.name}
</span>
`;
}).join('')}
</div>
</div>
${pe.imports && pe.imports.length > 0 ? `
@@ -211,40 +362,81 @@ document.addEventListener('DOMContentLoaded', function() {
` : ''}
</div>
`;
} else if (fileInfo.office_info) {
const office = fileInfo.office_info;
html = `
<div class="space-y-4">
<h6 class="text-base font-medium text-gray-300">Office Document Information</h6>
<div class="flex items-center space-x-4">
<div class="flex items-center space-x-2">
<span class="text-base text-gray-400">Macros:</span>
<span class="px-2 py-1 text-sm rounded-lg ${office.has_macros ?
'bg-red-500/10 text-red-500 border-red-900/20' :
'bg-gray-900/50 text-gray-400 border-gray-800'} border">
${office.has_macros ? 'Present' : 'None'}
</span>
elements.fileSpecificInfo.innerHTML = html;
// New section analysis display
elements.sectionsList.innerHTML = pe.sections.map(section => {
const isStandardSection = ['.text', '.data', '.bss', '.rdata', '.edata', '.idata', '.pdata', '.reloc', '.rsrc', '.tls', '.debug'].includes(section.name);
return `
<div class="border-b border-gray-800 pb-4 last:border-0">
<div class="flex items-center justify-between mb-2">
<div class="flex items-center space-x-3">
<span class="text-base ${isStandardSection ? 'text-gray-300' : 'text-red-500'}">${section.name}</span>
<span class="px-2 py-1 text-sm rounded ${
section.entropy > 7.2 ? 'text-red-500 bg-red-500/10' :
section.entropy > 6.8 ? 'text-yellow-500 bg-yellow-500/10' :
'text-green-500 bg-green-500/10'
}">
Entropy: ${section.entropy}
</span>
</div>
<span class="text-sm text-gray-400">${formatFileSize(section.size)}</span>
</div>
${section.detection_notes.length > 0 ? `
<div class="text-sm text-gray-400">
${section.detection_notes.map(note => `
<div class="flex items-center space-x-2">
<svg class="w-4 h-4 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
<span>${note}</span>
</div>
`).join('')}
</div>
` : ''}
</div>
${office.macro_info ? `
<div class="space-y-2">
<div class="text-base text-gray-400">Macro Information</div>
<pre class="text-base text-gray-300 bg-gray-900/50 rounded-lg p-4 overflow-x-auto">
${JSON.stringify(office.macro_info, null, 2)}
</pre>
</div>
` : ''}
</div>
`;
} else {
html = `
<div class="text-base text-gray-400 text-center py-4">
No specific file information available
</div>
`;
}
`;
}).join('');
elements.fileSpecificInfo.innerHTML = html;
// Render detection notes
if (fileInfo.pe_info.detection_notes.length > 0) {
elements.detectionNotes.innerHTML = fileInfo.pe_info.detection_notes.map(note => `
<div class="flex items-center space-x-2">
<svg class="w-4 h-4 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
<span>${note}</span>
</div>
`).join('');
}
}
// Render Office-specific information
else if (fileInfo.office_info) {
elements.officeInfo.classList.remove('hidden');
const office = fileInfo.office_info;
// Update macro status
elements.macroStatus.className = `px-3 py-1 text-sm rounded-full ${
office.has_macros ? 'bg-red-500/10 text-red-500' : 'bg-green-500/10 text-green-500'
}`;
elements.macroStatus.textContent = office.has_macros ? 'Macros Present' : 'No Macros';
// Show detection notes if any
if (office.detection_notes && office.detection_notes.length > 0) {
elements.macroDetectionNotes.innerHTML = office.detection_notes.map(note => `
<div class="flex items-center space-x-2">
<svg class="w-4 h-4 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
<span>${note}</span>
</div>
`).join('');
}
}
}
function updateFileInfo(fileInfo) {
+100 -6
View File
@@ -265,12 +265,29 @@
</div>
</div>
</div>
<!-- File Metrics -->
<div class="grid grid-cols-4 gap-4">
<div class="bg-gray-900/30 rounded-lg p-4">
<div class="text-base text-gray-300 mb-1">Entropy</div>
<div id="fileEntropy" class="text-lg font-semibold text-gray-300"></div>
<!-- Enhanced Entropy Analysis -->
<div class="bg-gray-900/30 rounded-lg p-4">
<div class="flex items-center justify-between mb-4">
<span class="text-base text-gray-300">Entropy Analysis</span>
<span id="detectionRisk" class="px-3 py-1 text-sm rounded-full"></span>
</div>
<div class="space-y-4">
<div class="flex items-center justify-between">
<span class="text-sm text-gray-400">Overall Entropy</span>
<div id="fileEntropy" class="text-lg font-semibold text-gray-300"></div>
</div>
<div class="relative h-2 bg-gray-800 rounded-full overflow-hidden">
<div id="entropyBar" class="absolute h-full transition-all duration-300"></div>
</div>
<div id="entropyNotes" class="text-sm text-gray-400 space-y-1">
<!-- Populated by JS -->
</div>
</div>
</div>
<!-- File Basic Info -->
<div class="grid grid-cols-3 gap-4">
<div class="bg-gray-900/30 rounded-lg p-4">
<div class="text-base text-gray-300 mb-1">Type</div>
<div id="fileCategory" class="text-lg font-semibold text-gray-300"></div>
@@ -285,7 +302,84 @@
</div>
</div>
<!-- File Type Specific Info -->
<!-- PE Checksum Info -->
<div id="checksumInfo" class="bg-gray-900/30 rounded-lg p-4 mb-4">
<div class="flex items-center justify-between mb-4">
<span class="text-base text-gray-300">PE Checksum Analysis</span>
<span id="checksumStatus" class="px-3 py-1 text-sm rounded-full"></span>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<div class="text-sm text-gray-400 mb-1">Stored Checksum</div>
<div id="storedChecksum" class="text-base font-mono text-gray-300"></div>
</div>
<div>
<div class="text-sm text-gray-400 mb-1">Calculated Checksum</div>
<div id="calculatedChecksum" class="text-base font-mono text-gray-300"></div>
</div>
</div>
<div id="checksumNotes" class="mt-4 text-sm text-gray-400 space-y-1">
<!-- Populated by JS -->
</div>
</div>
<!-- Suspicious Imports Analysis -->
<div id="suspiciousImports" class="bg-gray-900/30 rounded-lg p-4 mb-4 hidden">
<div class="flex items-center justify-between mb-4">
<span class="text-base text-gray-300">Suspicious Imports Analysis</span>
<span id="suspiciousImportsCount" class="px-3 py-1 text-sm bg-red-500/10 text-red-500 rounded-full">
<!-- Count populated by JS -->
</span>
</div>
<div id="suspiciousImportsList" class="space-y-4">
<!-- List populated by JS -->
</div>
<div class="border-t border-gray-800 pt-4 mt-4">
<div class="text-sm text-gray-400">
<div class="flex items-center space-x-2">
<svg class="w-4 h-4 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
<span id="suspiciousImportsSummary"></span>
</div>
</div>
</div>
</div>
<!-- PE File Specific Info -->
<div id="peInfo" class="bg-gray-900/30 rounded-lg p-4 hidden">
<div class="space-y-6">
<div class="text-base text-gray-300 mb-2">Section Analysis</div>
<div id="sectionsList" class="space-y-4">
<!-- Populated by JS -->
</div>
<div class="border-t border-gray-800 pt-4">
<div class="text-base text-gray-300 mb-2">Detection Notes</div>
<div id="detectionNotes" class="space-y-2 text-sm text-gray-400">
<!-- Populated by JS -->
</div>
</div>
</div>
</div>
<!-- Office File Specific Info -->
<div id="officeInfo" class="bg-gray-900/30 rounded-lg p-4 hidden">
<div class="space-y-4">
<div class="flex items-center justify-between">
<span class="text-base text-gray-300">Macro Analysis</span>
<span id="macroStatus" class="px-3 py-1 text-sm rounded-full"></span>
</div>
<div id="macroDetectionNotes" class="space-y-2 text-sm text-gray-400">
<!-- Populated by JS -->
</div>
<div id="macroInfo" class="text-sm text-gray-400">
<!-- Populated by JS -->
</div>
</div>
</div>
<!-- Generic File Info -->
<div id="fileSpecificInfo" class="bg-gray-900/30 rounded-lg p-4 text-base text-gray-300">
<!-- Dynamically populated based on file type -->
</div>