0
# Packer Detection
1
2
Utilities for detecting packed executables and identifying packers/compilers using signature databases. The peutils module provides sophisticated packer detection capabilities.
3
4
## Capabilities
5
6
### SignatureDatabase Class
7
8
Manage and query PEiD signature databases for packer identification.
9
10
```python { .api }
11
class SignatureDatabase:
12
def __init__(self, filename=None, data=None):
13
"""
14
Initialize signature database.
15
16
Args:
17
filename (str, optional): Path to PEiD signature file or URL
18
data (str, optional): Raw signature data
19
"""
20
21
def load(self, filename=None, data=None):
22
"""
23
Load additional signature file.
24
25
Args:
26
filename (str, optional): Path to signature file or URL
27
data (str, optional): Raw signature data
28
29
Note:
30
Can be called multiple times to combine signatures from
31
different sources. Supports loading from URLs.
32
"""
33
34
def match(self, pe, ep_only=True, section_start_only=False):
35
"""
36
Find exact signature matches for PE file.
37
38
Args:
39
pe: PE file object
40
ep_only (bool): Only check entry point signatures
41
section_start_only (bool): Only check section start signatures
42
43
Returns:
44
str or list: Packer name (ep_only=True) or list of (offset, name) tuples
45
"""
46
47
def match_all(self, pe, ep_only=True, section_start_only=False):
48
"""
49
Find all likely signature matches.
50
51
Args:
52
pe: PE file object
53
ep_only (bool): Only check entry point signatures
54
section_start_only (bool): Only check section start signatures
55
56
Returns:
57
list: All matching signatures instead of just most precise
58
"""
59
60
def match_data(self, code_data, ep_only=True, section_start_only=False):
61
"""
62
Match raw code data against signatures.
63
64
Args:
65
code_data (bytes): Raw code data to analyze
66
ep_only (bool): Use entry point signatures
67
section_start_only (bool): Use section start signatures
68
69
Returns:
70
str or list: Match results similar to match()
71
"""
72
73
def generate_ep_signature(self, pe, name, sig_length=512):
74
"""
75
Generate entry point signature for PE file.
76
77
Args:
78
pe: PE file object
79
name (str): Name for the signature
80
sig_length (int): Length of signature to generate
81
82
Returns:
83
str: Generated signature in PEiD format
84
"""
85
86
def generate_section_signatures(self, pe, name, sig_length=512):
87
"""
88
Generate signatures for all sections in PE file.
89
90
Args:
91
pe: PE file object
92
name (str): Base name for signatures
93
sig_length (int): Length of signatures to generate
94
95
Returns:
96
str: Generated signatures for all sections
97
"""
98
```
99
100
### Utility Functions
101
102
High-level functions for packer and malware detection.
103
104
```python { .api }
105
def is_probably_packed(pe):
106
"""
107
Determine if PE file is likely packed using entropy analysis.
108
109
Args:
110
pe: PE file object
111
112
Returns:
113
bool: True if file appears to be packed
114
115
Note:
116
Uses entropy analysis with empirical thresholds:
117
- Section entropy > 7.4
118
- Compressed data ratio > 20%
119
"""
120
121
def is_suspicious(pe):
122
"""
123
Analyze PE file for suspicious characteristics.
124
125
Args:
126
pe: PE file object
127
128
Returns:
129
bool: True if file has suspicious characteristics
130
131
Note:
132
Checks for unusual import locations, unrecognized sections,
133
long ASCII strings, and relocations at entry point.
134
"""
135
136
def is_valid(pe):
137
"""
138
Validate PE file structure.
139
140
Args:
141
pe: PE file object
142
143
Returns:
144
bool: True if PE structure is valid
145
146
Note:
147
Currently a placeholder function.
148
"""
149
```
150
151
## Usage Examples
152
153
### Basic Packer Detection
154
155
```python
156
import pefile
157
import peutils
158
159
# Load PE file
160
with pefile.PE('suspected_packed.exe') as pe:
161
# Quick entropy-based packer detection
162
if peutils.is_probably_packed(pe):
163
print("File is probably packed")
164
else:
165
print("File does not appear to be packed")
166
167
# Check for suspicious characteristics
168
if peutils.is_suspicious(pe):
169
print("File has suspicious characteristics")
170
```
171
172
### Signature-Based Packer Detection
173
174
```python
175
import pefile
176
import peutils
177
178
# Load signature database
179
sig_db = peutils.SignatureDatabase('userdb.txt')
180
181
# Can also load from URL
182
# sig_db = peutils.SignatureDatabase('https://example.com/signatures.txt')
183
184
# Load additional signatures
185
sig_db.load('additional_sigs.txt')
186
187
with pefile.PE('executable.exe') as pe:
188
# Check for packer signatures at entry point
189
matches = sig_db.match(pe, ep_only=True)
190
if matches:
191
print(f"Detected packer: {matches}")
192
else:
193
print("No packer signature found at entry point")
194
195
# Check section starts for packer signatures
196
section_matches = sig_db.match(pe, ep_only=False, section_start_only=True)
197
if section_matches:
198
print("Section signature matches:")
199
for offset, packer in section_matches:
200
print(f" Offset 0x{offset:08x}: {packer}")
201
202
# Get all possible matches
203
all_matches = sig_db.match_all(pe, ep_only=True)
204
if all_matches:
205
print("All possible matches:")
206
for match in all_matches:
207
print(f" {match}")
208
```
209
210
### Entropy Analysis
211
212
```python
213
import pefile
214
import peutils
215
216
def detailed_entropy_analysis(pe):
217
"""Perform detailed entropy analysis for packer detection."""
218
print("Entropy Analysis:")
219
print("-" * 40)
220
221
high_entropy_sections = 0
222
total_sections = len(pe.sections)
223
224
for section in pe.sections:
225
name = section.Name.decode('utf-8').strip('\x00')
226
entropy = section.get_entropy()
227
size = section.SizeOfRawData
228
229
print(f"{name:<10}: Entropy={entropy:.3f}, Size={size}")
230
231
if entropy > 7.4: # High entropy threshold
232
high_entropy_sections += 1
233
print(f" ^ High entropy section (possible packing/encryption)")
234
235
# Overall assessment
236
packed_ratio = high_entropy_sections / total_sections if total_sections > 0 else 0
237
238
print(f"\nSummary:")
239
print(f"High entropy sections: {high_entropy_sections}/{total_sections}")
240
print(f"Packed ratio: {packed_ratio:.2%}")
241
242
if packed_ratio > 0.2: # 20% threshold
243
print("Assessment: Likely packed")
244
else:
245
print("Assessment: Probably not packed")
246
247
return packed_ratio > 0.2
248
249
# Usage
250
with pefile.PE('executable.exe') as pe:
251
is_packed = detailed_entropy_analysis(pe)
252
253
# Compare with peutils assessment
254
peutils_assessment = peutils.is_probably_packed(pe)
255
print(f"\npeutils assessment: {peutils_assessment}")
256
```
257
258
### Signature Generation
259
260
```python
261
import pefile
262
import peutils
263
264
def generate_custom_signatures(pe_file, output_file):
265
"""Generate custom signatures for a PE file."""
266
sig_db = peutils.SignatureDatabase()
267
268
with pefile.PE(pe_file) as pe:
269
# Generate entry point signature
270
ep_sig = sig_db.generate_ep_signature(pe, "Custom_Sample", 256)
271
272
# Generate section signatures
273
section_sigs = sig_db.generate_section_signatures(pe, "Custom_Sample", 256)
274
275
# Save signatures
276
with open(output_file, 'w') as f:
277
f.write("// Entry Point Signature\n")
278
f.write(ep_sig)
279
f.write("\n\n// Section Signatures\n")
280
f.write(section_sigs)
281
282
print(f"Generated signatures saved to {output_file}")
283
284
# Usage
285
generate_custom_signatures('unique_packer.exe', 'custom_signatures.txt')
286
```
287
288
### Batch Packer Analysis
289
290
```python
291
import pefile
292
import peutils
293
import os
294
295
def batch_packer_analysis(directory, sig_db_path=None):
296
"""Analyze multiple PE files for packer detection."""
297
# Load signature database if provided
298
sig_db = None
299
if sig_db_path and os.path.exists(sig_db_path):
300
sig_db = peutils.SignatureDatabase(sig_db_path)
301
302
results = {}
303
304
# Analyze all PE files in directory
305
for filename in os.listdir(directory):
306
if filename.lower().endswith(('.exe', '.dll')):
307
filepath = os.path.join(directory, filename)
308
309
try:
310
with pefile.PE(filepath) as pe:
311
# Entropy-based detection
312
entropy_packed = peutils.is_probably_packed(pe)
313
suspicious = peutils.is_suspicious(pe)
314
315
# Signature-based detection
316
sig_match = None
317
if sig_db:
318
sig_match = sig_db.match(pe, ep_only=True)
319
320
results[filename] = {
321
'entropy_packed': entropy_packed,
322
'suspicious': suspicious,
323
'signature_match': sig_match
324
}
325
326
except Exception as e:
327
results[filename] = {'error': str(e)}
328
329
# Display results
330
print("Batch Packer Analysis Results:")
331
print("=" * 60)
332
print(f"{'Filename':<20} {'Entropy':<8} {'Suspicious':<10} {'Signature':<20}")
333
print("-" * 60)
334
335
for filename, result in results.items():
336
if 'error' in result:
337
print(f"{filename:<20} ERROR: {result['error']}")
338
else:
339
entropy = "PACKED" if result['entropy_packed'] else "clean"
340
suspicious = "YES" if result['suspicious'] else "no"
341
signature = result['signature_match'] or "none"
342
343
print(f"{filename:<20} {entropy:<8} {suspicious:<10} {signature:<20}")
344
345
# Usage
346
batch_packer_analysis('./samples', 'userdb.txt')
347
```
348
349
### Advanced Packer Detection
350
351
```python
352
import pefile
353
import peutils
354
355
def advanced_packer_detection(pe_file):
356
"""Comprehensive packer detection combining multiple techniques."""
357
print(f"Advanced Packer Detection: {pe_file}")
358
print("=" * 50)
359
360
with pefile.PE(pe_file) as pe:
361
# 1. Entropy analysis
362
print("1. Entropy Analysis:")
363
entropy_packed = peutils.is_probably_packed(pe)
364
print(f" Result: {'PACKED' if entropy_packed else 'NOT PACKED'}")
365
366
# 2. Suspicious characteristics
367
print("2. Suspicious Characteristics:")
368
suspicious = peutils.is_suspicious(pe)
369
print(f" Result: {'SUSPICIOUS' if suspicious else 'NORMAL'}")
370
371
# 3. Section analysis
372
print("3. Section Analysis:")
373
suspicious_sections = 0
374
for section in pe.sections:
375
name = section.Name.decode('utf-8').strip('\x00')
376
entropy = section.get_entropy()
377
378
# Check for suspicious section names
379
if name in ['.upx0', '.upx1', '.aspack', '.petite', '.packed']:
380
print(f" Known packer section: {name}")
381
suspicious_sections += 1
382
383
# Check for high entropy with executable characteristics
384
if entropy > 7.0 and section.Characteristics & 0x20000000: # Executable
385
print(f" High entropy executable section: {name} (entropy: {entropy:.2f})")
386
suspicious_sections += 1
387
388
# 4. Import table analysis
389
print("4. Import Analysis:")
390
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
391
import_count = sum(len(entry.imports) for entry in pe.DIRECTORY_ENTRY_IMPORT)
392
dll_count = len(pe.DIRECTORY_ENTRY_IMPORT)
393
394
print(f" DLLs: {dll_count}, Functions: {import_count}")
395
396
# Low import count might indicate packing
397
if import_count < 10:
398
print(" Low import count - possible packing")
399
suspicious_sections += 1
400
else:
401
print(" No imports found - highly suspicious")
402
suspicious_sections += 1
403
404
# 5. Entry point analysis
405
print("5. Entry Point Analysis:")
406
ep_rva = pe.OPTIONAL_HEADER.AddressOfEntryPoint
407
ep_section = pe.get_section_by_rva(ep_rva)
408
409
if ep_section:
410
section_name = ep_section.Name.decode('utf-8').strip('\x00')
411
print(f" Entry point in section: {section_name}")
412
413
# Entry point not in .text section is suspicious
414
if section_name not in ['.text', 'CODE']:
415
print(f" Entry point not in standard code section - suspicious")
416
suspicious_sections += 1
417
418
# Final assessment
419
print("\n6. Final Assessment:")
420
print("-" * 20)
421
422
confidence_score = 0
423
if entropy_packed:
424
confidence_score += 3
425
if suspicious:
426
confidence_score += 2
427
if suspicious_sections > 0:
428
confidence_score += suspicious_sections
429
430
if confidence_score >= 5:
431
assessment = "HIGHLY LIKELY PACKED"
432
elif confidence_score >= 3:
433
assessment = "POSSIBLY PACKED"
434
else:
435
assessment = "PROBABLY NOT PACKED"
436
437
print(f"Confidence Score: {confidence_score}")
438
print(f"Assessment: {assessment}")
439
440
# Usage
441
advanced_packer_detection('suspicious_file.exe')
442
```