Spaces:
Running
Running
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,226 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import os
|
3 |
+
import zipfile
|
4 |
+
import tempfile
|
5 |
+
import pefile
|
6 |
+
import shutil
|
7 |
+
from pathlib import Path
|
8 |
+
|
9 |
+
st.set_page_config(page_title="File Analyzer", page_icon="🔍")
|
10 |
+
|
11 |
+
st.title("File Analysis Tool")
|
12 |
+
st.markdown("""
|
13 |
+
This tool allows you to analyze various file types:
|
14 |
+
- Extract and view contents of .zip files
|
15 |
+
- Unpack .exe files to examine their contents
|
16 |
+
- View information about .dll files
|
17 |
+
""")
|
18 |
+
|
19 |
+
# Maximum file size (10MB)
|
20 |
+
MAX_FILE_SIZE = 10 * 1024 * 1024
|
21 |
+
|
22 |
+
def unpack_exe(file_path, output_dir):
|
23 |
+
"""Extract information from an EXE file using pefile"""
|
24 |
+
try:
|
25 |
+
pe = pefile.PE(file_path)
|
26 |
+
|
27 |
+
# Create a basic info dictionary
|
28 |
+
info = {
|
29 |
+
"Machine": hex(pe.FILE_HEADER.Machine),
|
30 |
+
"TimeDateStamp": pe.FILE_HEADER.TimeDateStamp,
|
31 |
+
"NumberOfSections": pe.FILE_HEADER.NumberOfSections,
|
32 |
+
"Sections": []
|
33 |
+
}
|
34 |
+
|
35 |
+
# Get section information
|
36 |
+
for section in pe.sections:
|
37 |
+
section_name = section.Name.decode('utf-8', errors='ignore').strip('\x00')
|
38 |
+
info["Sections"].append({
|
39 |
+
"Name": section_name,
|
40 |
+
"VirtualAddress": hex(section.VirtualAddress),
|
41 |
+
"SizeOfRawData": section.SizeOfRawData,
|
42 |
+
"Entropy": section.get_entropy()
|
43 |
+
})
|
44 |
+
|
45 |
+
# Get imports
|
46 |
+
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
|
47 |
+
info["Imports"] = []
|
48 |
+
for entry in pe.DIRECTORY_ENTRY_IMPORT:
|
49 |
+
dll_name = entry.dll.decode('utf-8', errors='ignore')
|
50 |
+
imports = []
|
51 |
+
for imp in entry.imports:
|
52 |
+
if imp.name:
|
53 |
+
imports.append(imp.name.decode('utf-8', errors='ignore'))
|
54 |
+
info["Imports"].append({
|
55 |
+
"DLL": dll_name,
|
56 |
+
"Functions": imports
|
57 |
+
})
|
58 |
+
|
59 |
+
# Extract resources if present
|
60 |
+
if hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
|
61 |
+
resource_dir = os.path.join(output_dir, "resources")
|
62 |
+
os.makedirs(resource_dir, exist_ok=True)
|
63 |
+
|
64 |
+
for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries:
|
65 |
+
if hasattr(resource_type, 'directory'):
|
66 |
+
for resource_id in resource_type.directory.entries:
|
67 |
+
if hasattr(resource_id, 'directory'):
|
68 |
+
for resource_lang in resource_id.directory.entries:
|
69 |
+
data = pe.get_data(resource_lang.data.struct.OffsetToData, resource_lang.data.struct.Size)
|
70 |
+
resource_filename = f"resource_{resource_type.id}_{resource_id.id}_{resource_lang.id}"
|
71 |
+
with open(os.path.join(resource_dir, resource_filename), 'wb') as f:
|
72 |
+
f.write(data)
|
73 |
+
|
74 |
+
return info
|
75 |
+
except Exception as e:
|
76 |
+
return {"Error": str(e)}
|
77 |
+
|
78 |
+
def analyze_dll(file_path):
|
79 |
+
"""Extract information from a DLL file using pefile"""
|
80 |
+
try:
|
81 |
+
pe = pefile.PE(file_path)
|
82 |
+
|
83 |
+
# Create a basic info dictionary
|
84 |
+
info = {
|
85 |
+
"Machine": hex(pe.FILE_HEADER.Machine),
|
86 |
+
"TimeDateStamp": pe.FILE_HEADER.TimeDateStamp,
|
87 |
+
"NumberOfSections": pe.FILE_HEADER.NumberOfSections,
|
88 |
+
"Characteristics": hex(pe.FILE_HEADER.Characteristics),
|
89 |
+
"DllCharacteristics": hex(pe.OPTIONAL_HEADER.DllCharacteristics),
|
90 |
+
"Sections": []
|
91 |
+
}
|
92 |
+
|
93 |
+
# Get section information
|
94 |
+
for section in pe.sections:
|
95 |
+
section_name = section.Name.decode('utf-8', errors='ignore').strip('\x00')
|
96 |
+
info["Sections"].append({
|
97 |
+
"Name": section_name,
|
98 |
+
"VirtualAddress": hex(section.VirtualAddress),
|
99 |
+
"SizeOfRawData": section.SizeOfRawData,
|
100 |
+
"Entropy": section.get_entropy()
|
101 |
+
})
|
102 |
+
|
103 |
+
# Get exports if present
|
104 |
+
if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'):
|
105 |
+
info["Exports"] = []
|
106 |
+
for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:
|
107 |
+
if exp.name:
|
108 |
+
info["Exports"].append(exp.name.decode('utf-8', errors='ignore'))
|
109 |
+
|
110 |
+
# Get imports
|
111 |
+
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
|
112 |
+
info["Imports"] = []
|
113 |
+
for entry in pe.DIRECTORY_ENTRY_IMPORT:
|
114 |
+
dll_name = entry.dll.decode('utf-8', errors='ignore')
|
115 |
+
imports = []
|
116 |
+
for imp in entry.imports:
|
117 |
+
if imp.name:
|
118 |
+
imports.append(imp.name.decode('utf-8', errors='ignore'))
|
119 |
+
info["Imports"].append({
|
120 |
+
"DLL": dll_name,
|
121 |
+
"Functions": imports
|
122 |
+
})
|
123 |
+
|
124 |
+
return info
|
125 |
+
except Exception as e:
|
126 |
+
return {"Error": str(e)}
|
127 |
+
|
128 |
+
def process_zip_file(file_path, temp_dir):
|
129 |
+
"""Process a ZIP file and extract its contents"""
|
130 |
+
try:
|
131 |
+
with zipfile.ZipFile(file_path, 'r') as zip_ref:
|
132 |
+
# Get file list before extraction
|
133 |
+
file_list = zip_ref.namelist()
|
134 |
+
|
135 |
+
# Extract to temp directory
|
136 |
+
zip_ref.extractall(temp_dir)
|
137 |
+
|
138 |
+
# Check for nested executables
|
139 |
+
nested_files = {}
|
140 |
+
for root, _, files in os.walk(temp_dir):
|
141 |
+
for file in files:
|
142 |
+
full_path = os.path.join(root, file)
|
143 |
+
rel_path = os.path.relpath(full_path, temp_dir)
|
144 |
+
|
145 |
+
if file.endswith('.exe'):
|
146 |
+
exe_output_dir = os.path.join(temp_dir, f"{file}_unpacked")
|
147 |
+
os.makedirs(exe_output_dir, exist_ok=True)
|
148 |
+
nested_files[rel_path] = {
|
149 |
+
'type': 'exe',
|
150 |
+
'info': unpack_exe(full_path, exe_output_dir)
|
151 |
+
}
|
152 |
+
elif file.endswith('.dll'):
|
153 |
+
nested_files[rel_path] = {
|
154 |
+
'type': 'dll',
|
155 |
+
'info': analyze_dll(full_path)
|
156 |
+
}
|
157 |
+
|
158 |
+
return {
|
159 |
+
'file_list': file_list,
|
160 |
+
'nested_files': nested_files
|
161 |
+
}
|
162 |
+
except Exception as e:
|
163 |
+
return {'error': str(e)}
|
164 |
+
|
165 |
+
# Main app logic
|
166 |
+
uploaded_file = st.file_uploader("Upload a file (.zip, .exe, or .dll)", type=["zip", "exe", "dll"])
|
167 |
+
|
168 |
+
if uploaded_file is not None:
|
169 |
+
# Check file size
|
170 |
+
if uploaded_file.size > MAX_FILE_SIZE:
|
171 |
+
st.error(f"File too large. Maximum size is {MAX_FILE_SIZE/1024/1024}MB.")
|
172 |
+
else:
|
173 |
+
with tempfile.TemporaryDirectory() as temp_dir:
|
174 |
+
# Save the uploaded file to the temporary directory
|
175 |
+
file_path = os.path.join(temp_dir, uploaded_file.name)
|
176 |
+
with open(file_path, "wb") as f:
|
177 |
+
f.write(uploaded_file.getbuffer())
|
178 |
+
|
179 |
+
st.success(f"File uploaded: {uploaded_file.name}")
|
180 |
+
|
181 |
+
# Process based on file type
|
182 |
+
if uploaded_file.name.lower().endswith('.zip'):
|
183 |
+
st.subheader("ZIP File Contents")
|
184 |
+
output_dir = os.path.join(temp_dir, "extracted")
|
185 |
+
os.makedirs(output_dir, exist_ok=True)
|
186 |
+
|
187 |
+
result = process_zip_file(file_path, output_dir)
|
188 |
+
|
189 |
+
if 'error' in result:
|
190 |
+
st.error(f"Error processing ZIP file: {result['error']}")
|
191 |
+
else:
|
192 |
+
with st.expander("ZIP Contents", expanded=True):
|
193 |
+
st.write(f"Total files: {len(result['file_list'])}")
|
194 |
+
st.json(result['file_list'])
|
195 |
+
|
196 |
+
if result['nested_files']:
|
197 |
+
st.subheader("Detected Executable Files")
|
198 |
+
for file_path, file_info in result['nested_files'].items():
|
199 |
+
with st.expander(f"{file_path} ({file_info['type'].upper()})"):
|
200 |
+
st.json(file_info['info'])
|
201 |
+
|
202 |
+
elif uploaded_file.name.lower().endswith('.exe'):
|
203 |
+
st.subheader("EXE File Analysis")
|
204 |
+
output_dir = os.path.join(temp_dir, "exe_unpacked")
|
205 |
+
os.makedirs(output_dir, exist_ok=True)
|
206 |
+
|
207 |
+
try:
|
208 |
+
exe_info = unpack_exe(file_path, output_dir)
|
209 |
+
st.json(exe_info)
|
210 |
+
|
211 |
+
# Check if resources were extracted
|
212 |
+
resource_dir = os.path.join(output_dir, "resources")
|
213 |
+
if os.path.exists(resource_dir) and os.listdir(resource_dir):
|
214 |
+
st.subheader("Extracted Resources")
|
215 |
+
for resource_file in os.listdir(resource_dir):
|
216 |
+
st.text(f"Resource: {resource_file}")
|
217 |
+
except Exception as e:
|
218 |
+
st.error(f"Error analyzing EXE file: {str(e)}")
|
219 |
+
|
220 |
+
elif uploaded_file.name.lower().endswith('.dll'):
|
221 |
+
st.subheader("DLL File Information")
|
222 |
+
try:
|
223 |
+
dll_info = analyze_dll(file_path)
|
224 |
+
st.json(dll_info)
|
225 |
+
except Exception as e:
|
226 |
+
st.error(f"Error analyzing DLL file: {str(e)}")
|