Skip to content

Commit d005709

Browse files
committed
feat(handler): improve PE handler
Create a PEExtractor to handle the logic for extracting from PEs.
1 parent 7e1b6fd commit d005709

File tree

1 file changed

+42
-21
lines changed
  • python/unblob/handlers/executable

1 file changed

+42
-21
lines changed

python/unblob/handlers/executable/pe.py

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from pathlib import Path
12
from typing import Optional
23

34
import io
@@ -8,6 +9,8 @@
89
from unblob.extractors.command import Command
910

1011
from ...models import (
12+
Extractor,
13+
ExtractResult,
1114
File,
1215
Handler,
1316
HandlerDoc,
@@ -21,6 +24,36 @@
2124

2225
logger = get_logger()
2326

27+
28+
class PEExtractor(Extractor):
29+
"""
30+
PEExtractor extracts files embedded within PEs such as installers.
31+
"""
32+
33+
def extract(self, inpath: Path, outdir: Path) -> Optional[ExtractResult]:
34+
binary = lief.PE.parse(inpath)
35+
if not binary:
36+
return None
37+
38+
if not self.is_nsis(binary):
39+
return None
40+
41+
return Command("7z", "x", "-y", "{inpath}", "-o{outdir}").extract(inpath, outdir)
42+
43+
44+
def is_nsis(self, binary: lief.PE.Binary) -> bool:
45+
"""
46+
Test if binary appears to be a Nullsoft Installer self-extracting archive
47+
48+
TODO: this series of tests is possibly too strict
49+
"""
50+
51+
return binary.has_resources and \
52+
binary.resources_manager.has_manifest and \
53+
"Nullsoft" in binary.resources_manager.manifest
54+
55+
56+
2457
class PEHandler(Handler):
2558
NAME = "pe"
2659

@@ -30,12 +63,18 @@ class PEHandler(Handler):
3063
// MZ header
3164
4d 5a
3265
"""
66+
),
67+
HexString(
68+
"""
69+
// PE header
70+
50 45 00 00
71+
"""
3372
)
3473
]
3574

36-
EXTRACTOR = Command(
37-
"7z", "x", "-y", "{inpath}", "-o{outdir}"
38-
)
75+
76+
EXTRACTOR = PEExtractor()
77+
3978

4079
DOC = HandlerDoc(
4180
name="pe",
@@ -55,21 +94,6 @@ class PEHandler(Handler):
5594
limitations=[],
5695
)
5796

58-
def is_nsis(self, binary: lief.PE.Binary) -> bool:
59-
"""
60-
Test if binary appears to be a Nullsoft Installer self-extracting archive
61-
62-
TODO: this series of tests is possibly too strict
63-
"""
64-
65-
if not binary.has_resources:
66-
return False
67-
68-
if not binary.resources_manager.has_manifest:
69-
return False
70-
71-
return "Nullsoft" in binary.resources_manager.manifest
72-
7397

7498
def calculate_chunk(self, file: File, start_offset: int) -> Optional[ValidChunk]:
7599
file.seek(start_offset, io.SEEK_SET)
@@ -78,9 +102,6 @@ def calculate_chunk(self, file: File, start_offset: int) -> Optional[ValidChunk]
78102
if not binary:
79103
return None
80104

81-
if not self.is_nsis(binary):
82-
return None
83-
84105
return ValidChunk(
85106
start_offset = start_offset,
86107
end_offset = start_offset + binary.original_size,

0 commit comments

Comments
 (0)