Spaces:
Running
Running
import streamlit as st | |
import os | |
import zipfile | |
import tempfile | |
import pefile | |
import shutil | |
from pathlib import Path | |
st.set_page_config(page_title="File Analyzer", page_icon="π") | |
st.title("File Analysis Tool") | |
st.markdown(""" | |
This tool allows you to analyze various file types: | |
- Extract and view contents of .zip files | |
- Unpack .exe files to examine their contents | |
- View information about .dll files | |
""") | |
# No size limit | |
def unpack_exe(file_path, output_dir): | |
"""Extract information from an EXE file using pefile""" | |
try: | |
pe = pefile.PE(file_path) | |
# Create a basic info dictionary | |
info = { | |
"Machine": hex(pe.FILE_HEADER.Machine), | |
"TimeDateStamp": pe.FILE_HEADER.TimeDateStamp, | |
"NumberOfSections": pe.FILE_HEADER.NumberOfSections, | |
"Sections": [] | |
} | |
# Get section information | |
for section in pe.sections: | |
section_name = section.Name.decode('utf-8', errors='ignore').strip('\x00') | |
info["Sections"].append({ | |
"Name": section_name, | |
"VirtualAddress": hex(section.VirtualAddress), | |
"SizeOfRawData": section.SizeOfRawData, | |
"Entropy": section.get_entropy() | |
}) | |
# Get imports | |
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'): | |
info["Imports"] = [] | |
for entry in pe.DIRECTORY_ENTRY_IMPORT: | |
dll_name = entry.dll.decode('utf-8', errors='ignore') | |
imports = [] | |
for imp in entry.imports: | |
if imp.name: | |
imports.append(imp.name.decode('utf-8', errors='ignore')) | |
info["Imports"].append({ | |
"DLL": dll_name, | |
"Functions": imports | |
}) | |
# Extract resources if present | |
if hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'): | |
resource_dir = os.path.join(output_dir, "resources") | |
os.makedirs(resource_dir, exist_ok=True) | |
for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries: | |
if hasattr(resource_type, 'directory'): | |
for resource_id in resource_type.directory.entries: | |
if hasattr(resource_id, 'directory'): | |
for resource_lang in resource_id.directory.entries: | |
data = pe.get_data(resource_lang.data.struct.OffsetToData, resource_lang.data.struct.Size) | |
resource_filename = f"resource_{resource_type.id}_{resource_id.id}_{resource_lang.id}" | |
with open(os.path.join(resource_dir, resource_filename), 'wb') as f: | |
f.write(data) | |
return info | |
except Exception as e: | |
return {"Error": str(e)} | |
def analyze_dll(file_path): | |
"""Extract information from a DLL file using pefile""" | |
try: | |
pe = pefile.PE(file_path) | |
# Create a basic info dictionary | |
info = { | |
"Machine": hex(pe.FILE_HEADER.Machine), | |
"TimeDateStamp": pe.FILE_HEADER.TimeDateStamp, | |
"NumberOfSections": pe.FILE_HEADER.NumberOfSections, | |
"Characteristics": hex(pe.FILE_HEADER.Characteristics), | |
"DllCharacteristics": hex(pe.OPTIONAL_HEADER.DllCharacteristics), | |
"Sections": [] | |
} | |
# Get section information | |
for section in pe.sections: | |
section_name = section.Name.decode('utf-8', errors='ignore').strip('\x00') | |
info["Sections"].append({ | |
"Name": section_name, | |
"VirtualAddress": hex(section.VirtualAddress), | |
"SizeOfRawData": section.SizeOfRawData, | |
"Entropy": section.get_entropy() | |
}) | |
# Get exports if present | |
if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'): | |
info["Exports"] = [] | |
for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols: | |
if exp.name: | |
info["Exports"].append(exp.name.decode('utf-8', errors='ignore')) | |
# Get imports | |
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'): | |
info["Imports"] = [] | |
for entry in pe.DIRECTORY_ENTRY_IMPORT: | |
dll_name = entry.dll.decode('utf-8', errors='ignore') | |
imports = [] | |
for imp in entry.imports: | |
if imp.name: | |
imports.append(imp.name.decode('utf-8', errors='ignore')) | |
info["Imports"].append({ | |
"DLL": dll_name, | |
"Functions": imports | |
}) | |
return info | |
except Exception as e: | |
return {"Error": str(e)} | |
def process_zip_file(file_path, temp_dir): | |
"""Process a ZIP file and extract its contents""" | |
try: | |
with zipfile.ZipFile(file_path, 'r') as zip_ref: | |
# Get file list before extraction | |
file_list = zip_ref.namelist() | |
# Extract to temp directory | |
zip_ref.extractall(temp_dir) | |
# Check for nested executables | |
nested_files = {} | |
for root, _, files in os.walk(temp_dir): | |
for file in files: | |
full_path = os.path.join(root, file) | |
rel_path = os.path.relpath(full_path, temp_dir) | |
if file.endswith('.exe'): | |
exe_output_dir = os.path.join(temp_dir, f"{file}_unpacked") | |
os.makedirs(exe_output_dir, exist_ok=True) | |
nested_files[rel_path] = { | |
'type': 'exe', | |
'info': unpack_exe(full_path, exe_output_dir) | |
} | |
elif file.endswith('.dll'): | |
nested_files[rel_path] = { | |
'type': 'dll', | |
'info': analyze_dll(full_path) | |
} | |
return { | |
'file_list': file_list, | |
'nested_files': nested_files | |
} | |
except Exception as e: | |
return {'error': str(e)} | |
# Main app logic | |
uploaded_file = st.file_uploader("Upload a file (.zip, .exe, or .dll)", type=["zip", "exe", "dll"]) | |
if uploaded_file is not None: | |
# Process file without size check | |
with tempfile.TemporaryDirectory() as temp_dir: | |
# Save the uploaded file to the temporary directory | |
file_path = os.path.join(temp_dir, uploaded_file.name) | |
with open(file_path, "wb") as f: | |
f.write(uploaded_file.getbuffer()) | |
st.success(f"File uploaded: {uploaded_file.name}") | |
# Process based on file type | |
if uploaded_file.name.lower().endswith('.zip'): | |
st.subheader("ZIP File Contents") | |
output_dir = os.path.join(temp_dir, "extracted") | |
os.makedirs(output_dir, exist_ok=True) | |
result = process_zip_file(file_path, output_dir) | |
if 'error' in result: | |
st.error(f"Error processing ZIP file: {result['error']}") | |
else: | |
with st.expander("ZIP Contents", expanded=True): | |
st.write(f"Total files: {len(result['file_list'])}") | |
st.json(result['file_list']) | |
if result['nested_files']: | |
st.subheader("Detected Executable Files") | |
for file_path, file_info in result['nested_files'].items(): | |
with st.expander(f"{file_path} ({file_info['type'].upper()})"): | |
st.json(file_info['info']) | |
elif uploaded_file.name.lower().endswith('.exe'): | |
st.subheader("EXE File Analysis") | |
output_dir = os.path.join(temp_dir, "exe_unpacked") | |
os.makedirs(output_dir, exist_ok=True) | |
try: | |
exe_info = unpack_exe(file_path, output_dir) | |
st.json(exe_info) | |
# Check if resources were extracted | |
resource_dir = os.path.join(output_dir, "resources") | |
if os.path.exists(resource_dir) and os.listdir(resource_dir): | |
st.subheader("Extracted Resources") | |
for resource_file in os.listdir(resource_dir): | |
st.text(f"Resource: {resource_file}") | |
except Exception as e: | |
st.error(f"Error analyzing EXE file: {str(e)}") | |
elif uploaded_file.name.lower().endswith('.dll'): | |
st.subheader("DLL File Information") | |
try: | |
dll_info = analyze_dll(file_path) | |
st.json(dll_info) | |
except Exception as e: | |
st.error(f"Error analyzing DLL file: {str(e)}") |