PE-sieve
Scans all running processes. Recognizes and dumps a variety of potentially malicious implants (replaced/implanted PEs, shellcodes, hooks, in-memory patches).
Loading...
Searching...
No Matches
pesieve.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3import ctypes
4import os
5
6PESIEVE_MIN_VER = 0x030800 # minimal version of the PE-sieve DLL to work with this wrapper
7PESIEVE_MAX_VER = 0x030800 # maximal version of the PE-sieve DLL to work with this wrapper
8
9ERROR_SCAN_FAILURE = -1
10MAX_PATH = 260
11
12def version_to_str(version_val):
13 major = (version_val >> 24) & 0xFF
14 minor = (version_val >> 16) & 0xFF
15 patch = (version_val >> 8) & 0xFF
16 build = version_val & 0xFF
17 return f"{major}.{minor}.{patch}.{build}"
18
19
20
21class t_output_filter(ctypes.c_int):
22 OUT_FULL = 0
23 OUT_NO_DUMPS = 1
24 OUT_NO_DIR = 2
25 OUT_FILTERS_COUNT = 3
26
27class t_shellc_mode(ctypes.c_int):
28 SHELLC_NONE = 0
29 SHELLC_PATTERNS = 1
30 SHELLC_STATS = 2
31 SHELLC_PATTERNS_OR_STATS = 3
32 SHELLC_PATTERNS_AND_STATS = 4
33 SHELLC_COUNT = 5
34
35class t_obfusc_mode(ctypes.c_int):
36 OBFUSC_NONE = 0
37 OBFUSC_STRONG_ENC = 1
38 OBFUSC_WEAK_ENC = 2
39 OBFUSC_ANY = 3
40 OBFUSC_COUNT = 4
41
42class t_imprec_mode(ctypes.c_int):
43 PE_IMPREC_NONE = 0
44 PE_IMPREC_AUTO = 1
45 PE_IMPREC_UNERASE = 2
46 PE_IMPREC_REBUILD0 = 3
47 PE_IMPREC_REBUILD1 = 4
48 PE_IMPREC_REBUILD2 = 5
49 PE_IMPREC_MODES_COUNT = 6
50
51class t_dump_mode(ctypes.c_int):
52 PE_DUMP_AUTO = 0
53 PE_DUMP_VIRTUAL = 1
54 PE_DUMP_UNMAP = 2
55 PE_DUMP_REALIGN = 3
56 PE_DUMP_MODES_COUNT = 4
57
58class t_iat_scan_mode(ctypes.c_int):
59 PE_IATS_NONE = 0
60 PE_IATS_CLEAN_SYS_FILTERED = 1
61 PE_IATS_ALL_SYS_FILTERED = 2
62 PE_IATS_UNFILTERED = 3
63 PE_IATS_MODES_COUNT = 4
64
65class t_dotnet_policy(ctypes.c_int):
66 PE_DNET_NONE = 0
67 PE_DNET_SKIP_MAPPING = 1
68 PE_DNET_SKIP_SHC = 2
69 PE_DNET_SKIP_HOOKS = 3
70 PE_DNET_SKIP_ALL = 4
71 PE_DNET_COUNT = 5
72
73class t_data_scan_mode(ctypes.c_int):
74 PE_DATA_NO_SCAN = 0
75 PE_DATA_SCAN_DOTNET = 1
76 PE_DATA_SCAN_NO_DEP = 2
77 PE_DATA_SCAN_ALWAYS = 3
78 PE_DATA_SCAN_INACCESSIBLE = 4
79 PE_DATA_SCAN_INACCESSIBLE_ONLY = 5
80 PE_DATA_COUNT = 6
81
82class t_json_level(ctypes.c_int):
83 JSON_BASIC = 0
84 JSON_DETAILS = 1
85 JSON_DETAILS2 = 2
86 JSON_LVL_COUNT = 3
87
88class t_report_type(ctypes.c_int):
89 REPORT_NONE = 0
90 REPORT_SCANNED = 1
91 REPORT_DUMPED = 2
92 REPORT_ALL = 3
93
94class PARAM_STRING(ctypes.Structure):
95 _fields_ = [
96 ('length', ctypes.c_ulong),
97 ('buffer', ctypes.c_char_p)
98 ]
99
100class t_params(ctypes.Structure):
101 _fields_ = [
102 ('pid', ctypes.c_ulong),
103 ('dotnet_policy', t_dotnet_policy),
104 ('imprec_mode', t_imprec_mode),
105 ('quiet', ctypes.c_bool),
106 ('out_filter', t_output_filter),
107 ('no_hooks', ctypes.c_bool),
108 ('shellcode', t_shellc_mode),
109 ('obfuscated', t_obfusc_mode),
110 ('threads', ctypes.c_bool),
111 ('iat', t_iat_scan_mode),
112 ('data', t_data_scan_mode),
113 ('minidump', ctypes.c_bool),
114 ('dump_mode', t_dump_mode),
115 ('json_output', ctypes.c_bool),
116 ('make_reflection', ctypes.c_bool),
117 ('use_cache', ctypes.c_bool),
118 ('json_lvl', t_json_level),
119 ('output_dir', ctypes.c_char * (MAX_PATH + 1)),
120 ('modules_ignored', PARAM_STRING)
121 ]
122
123class t_report(ctypes.Structure):
124 _fields_ = [
125 ('pid', ctypes.c_ulong),
126 ('is_managed', ctypes.c_bool),
127 ('is_64bit', ctypes.c_bool),
128 ('is_reflection', ctypes.c_bool),
129 ('scanned', ctypes.c_ulong),
130 ('suspicious', ctypes.c_ulong),
131 ('replaced', ctypes.c_ulong),
132 ('hdr_mod', ctypes.c_ulong),
133 ('unreachable_file', ctypes.c_ulong),
134 ('patched', ctypes.c_ulong),
135 ('iat_hooked', ctypes.c_ulong),
136 ('implanted', ctypes.c_ulong),
137 ('implanted_pe', ctypes.c_ulong),
138 ('implanted_shc', ctypes.c_ulong),
139 ('other', ctypes.c_ulong),
140 ('skipped', ctypes.c_ulong),
141 ('errors', ctypes.c_ulong)
142 ]
143
144lib = None
145PESieve_version = None
146
147def init():
148 global lib
149 global PESieve_version
150 ptr_size = ctypes.sizeof(ctypes.c_voidp)
151 if ptr_size == 4:
152 pesieve_dll = "pe-sieve32.dll"
153 else:
154 pesieve_dll = "pe-sieve64.dll"
155
156 if 'PESIEVE_DIR' in os.environ:
157 pesieve_dir = os.environ.get('PESIEVE_DIR')
158 else:
159 pesieve_dir = os.path.abspath(os.getcwd())
160 pesieve_path = pesieve_dir + os.path.sep + pesieve_dll
161 lib = ctypes.cdll.LoadLibrary(pesieve_path)
162 PESieve_version = ctypes.cast(lib.PESieve_version, ctypes.POINTER(ctypes.c_uint32)).contents.value
163 if (PESieve_version < PESIEVE_MIN_VER or PESieve_version > PESIEVE_MAX_VER):
164 dll_version_str = version_to_str(PESieve_version)
165 exception_msg = f"Version mismatch: the PE-sieve.dll version ({dll_version_str}) doesn't match the bindings version"
166 raise Exception(exception_msg)
167
169 if not lib:
170 init()
171 lib.PESieve_help()
172
173def PESieve_scan(params: t_params) -> t_report:
174 if not lib:
175 init()
176 if (not isinstance(params, t_params)):
177 raise TypeError
178
179 params_size = ctypes.sizeof(t_params)
180 pp = ctypes.create_string_buffer(bytes(params), params_size)
181 pr = ctypes.create_string_buffer(ctypes.sizeof(t_report))
182 lib.PESieve_scan(pr, pp)
183 report = t_report.from_buffer(pr)
184 return report
185
186def PESieve_scan_ex(params: t_params, rtype: t_report_type, buf_size: int) -> (t_report, str, int):
187 if not lib:
188 init()
189 if (not isinstance(params, t_params)):
190 raise TypeError
191
192 pp = ctypes.create_string_buffer(bytes(params), ctypes.sizeof(t_params))
193 pr = ctypes.create_string_buffer(ctypes.sizeof(t_report))
194 out_size = ctypes.c_ulong(0)
195 json_buf = ctypes.create_string_buffer(buf_size)
196 lib.PESieve_scan_ex(pr, pp, rtype, json_buf, buf_size, ctypes.byref(out_size))
197 report = t_report.from_buffer(pr)
198 if (out_size.value):
199 json_str = json_buf.value.decode('UTF-8')
200 else:
201 json_str = ""
202 return (report, json_str, out_size.value)
PESieve_help()
Definition pesieve.py:168
version_to_str(version_val)
Definition pesieve.py:12
(t_report, str, int) PESieve_scan_ex(t_params params, t_report_type rtype, int buf_size)
Definition pesieve.py:186
t_report PESieve_scan(t_params params)
Definition pesieve.py:173