Skip to content

Commit 7e1b6fd

Browse files
committed
feat(handler): support NSIS Installers
Searches for "Nullsoft" in the manifest to avoid false positives. Possibly too strict. Fixes #1249
1 parent a5c01c1 commit 7e1b6fd

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

python/unblob/handlers/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@
3737
zlib,
3838
zstd,
3939
)
40-
from .executable import elf
40+
from .executable import (
41+
elf,
42+
pe
43+
)
4144
from .filesystem import (
4245
cramfs,
4346
extfs,
@@ -115,6 +118,7 @@
115118
zstd.ZSTDHandler,
116119
elf.ELF32Handler,
117120
elf.ELF64Handler,
121+
pe.PEHandler,
118122
zlib.ZlibHandler,
119123
engenius.EngeniusHandler,
120124
ecc.AutelECCHandler,
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
from typing import Optional
2+
3+
import io
4+
import lief
5+
6+
from structlog import get_logger
7+
8+
from unblob.extractors.command import Command
9+
10+
from ...models import (
11+
File,
12+
Handler,
13+
HandlerDoc,
14+
HandlerType,
15+
HexString,
16+
Reference,
17+
ValidChunk,
18+
)
19+
20+
lief.logging.disable()
21+
22+
logger = get_logger()
23+
24+
class PEHandler(Handler):
25+
NAME = "pe"
26+
27+
PATTERNS = [
28+
HexString(
29+
"""
30+
// MZ header
31+
4d 5a
32+
"""
33+
)
34+
]
35+
36+
EXTRACTOR = Command(
37+
"7z", "x", "-y", "{inpath}", "-o{outdir}"
38+
)
39+
40+
DOC = HandlerDoc(
41+
name="pe",
42+
description="The PE (Portable Executable) is a binary file format used for executable code on 32-bit and 64-bit Windows operating systems as well as in UEFI environments.",
43+
handler_type=HandlerType.EXECUTABLE,
44+
vendor=None,
45+
references=[
46+
Reference(
47+
title="PE Format",
48+
url="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format",
49+
),
50+
Reference(
51+
title="Portable Executable Wikipedia",
52+
url="https://en.wikipedia.org/wiki/Portable_Executable",
53+
),
54+
],
55+
limitations=[],
56+
)
57+
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+
73+
74+
def calculate_chunk(self, file: File, start_offset: int) -> Optional[ValidChunk]:
75+
file.seek(start_offset, io.SEEK_SET)
76+
77+
binary = lief.PE.parse(file)
78+
if not binary:
79+
return None
80+
81+
if not self.is_nsis(binary):
82+
return None
83+
84+
return ValidChunk(
85+
start_offset = start_offset,
86+
end_offset = start_offset + binary.original_size,
87+
)

0 commit comments

Comments
 (0)