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 = 0x040000 # minimal version of the PE-sieve DLL to work with this wrapper
7PESIEVE_MAX_VER = 0x040000 # 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_results_filter(ctypes.c_int):
89 SHOW_NONE = 0
90 SHOW_ERRORS = 1
91 SHOW_NOT_SUSPICIOUS = 2
92 SHOW_SUSPICIOUS = 4
93 SHOW_SUSPICIOUS_AND_ERRORS = 5
94 SHOW_SUCCESSFUL_ONLY = 6
95 SHOW_ALL = 7
96
97class t_report_type(ctypes.c_int):
98 REPORT_NONE = 0
99 REPORT_SCANNED = 1
100 REPORT_DUMPED = 2
101 REPORT_ALL = 3
102
103class PARAM_STRING(ctypes.Structure):
104 _fields_ = [
105 ('length', ctypes.c_ulong),
106 ('buffer', ctypes.c_char_p)
107 ]
108
109class t_params(ctypes.Structure):
110 _fields_ = [
111 ('pid', ctypes.c_ulong),
112 ('dotnet_policy', t_dotnet_policy),
113 ('imprec_mode', t_imprec_mode),
114 ('quiet', ctypes.c_bool),
115 ('out_filter', t_output_filter),
116 ('no_hooks', ctypes.c_bool),
117 ('shellcode', t_shellc_mode),
118 ('obfuscated', t_obfusc_mode),
119 ('threads', ctypes.c_bool),
120 ('iat', t_iat_scan_mode),
121 ('data', t_data_scan_mode),
122 ('minidump', ctypes.c_bool),
123 ('rebase', ctypes.c_bool),
124 ('dump_mode', t_dump_mode),
125 ('json_output', ctypes.c_bool),
126 ('make_reflection', ctypes.c_bool),
127 ('use_cache', ctypes.c_bool),
128 ('json_lvl', t_json_level),
129 ('results_filter', t_results_filter),
130 ('output_dir', ctypes.c_char * (MAX_PATH + 1)),
131 ('modules_ignored', PARAM_STRING),
132 ('pattern_file', PARAM_STRING)
133 ]
134
135class t_report(ctypes.Structure):
136 _fields_ = [
137 ('pid', ctypes.c_ulong),
138 ('is_managed', ctypes.c_bool),
139 ('is_64bit', ctypes.c_bool),
140 ('is_reflection', ctypes.c_bool),
141 ('scanned', ctypes.c_ulong),
142 ('suspicious', ctypes.c_ulong),
143 ('replaced', ctypes.c_ulong),
144 ('hdr_mod', ctypes.c_ulong),
145 ('unreachable_file', ctypes.c_ulong),
146 ('patched', ctypes.c_ulong),
147 ('iat_hooked', ctypes.c_ulong),
148 ('implanted', ctypes.c_ulong),
149 ('implanted_pe', ctypes.c_ulong),
150 ('implanted_shc', ctypes.c_ulong),
151 ('other', ctypes.c_ulong),
152 ('skipped', ctypes.c_ulong),
153 ('errors', ctypes.c_ulong)
154 ]
155
156lib = None
157PESieve_version = None
158
159def init():
160 global lib
161 global PESieve_version
162 ptr_size = ctypes.sizeof(ctypes.c_voidp)
163 if ptr_size == 4:
164 pesieve_dll = "pe-sieve32.dll"
165 else:
166 pesieve_dll = "pe-sieve64.dll"
167
168 if 'PESIEVE_DIR' in os.environ:
169 pesieve_dir = os.environ.get('PESIEVE_DIR')
170 else:
171 pesieve_dir = os.path.abspath(os.getcwd())
172 pesieve_path = pesieve_dir + os.path.sep + pesieve_dll
173 lib = ctypes.cdll.LoadLibrary(pesieve_path)
174 PESieve_version = ctypes.cast(lib.PESieve_version, ctypes.POINTER(ctypes.c_uint32)).contents.value
175 if (PESieve_version < PESIEVE_MIN_VER or PESieve_version > PESIEVE_MAX_VER):
176 dll_version_str = version_to_str(PESieve_version)
177 exception_msg = f"Version mismatch: the PE-sieve.dll version ({dll_version_str}) doesn't match the bindings version"
178 raise Exception(exception_msg)
179
181 if not lib:
182 init()
183 lib.PESieve_help()
184
185def PESieve_scan(params: t_params) -> t_report:
186 if not lib:
187 init()
188 if (not isinstance(params, t_params)):
189 raise TypeError
190
191 params_size = ctypes.sizeof(t_params)
192 pp = ctypes.create_string_buffer(bytes(params), params_size)
193 pr = ctypes.create_string_buffer(ctypes.sizeof(t_report))
194 lib.PESieve_scan(pr, pp)
195 report = t_report.from_buffer(pr)
196 return report
197
198def PESieve_scan_ex(params: t_params, rtype: t_report_type, buf_size: int) -> (t_report, str, int):
199 if not lib:
200 init()
201 if (not isinstance(params, t_params)):
202 raise TypeError
203
204 pp = ctypes.create_string_buffer(bytes(params), ctypes.sizeof(t_params))
205 pr = ctypes.create_string_buffer(ctypes.sizeof(t_report))
206 out_size = ctypes.c_ulong(0)
207 json_buf = ctypes.create_string_buffer(buf_size)
208 lib.PESieve_scan_ex(pr, pp, rtype, json_buf, buf_size, ctypes.byref(out_size))
209 report = t_report.from_buffer(pr)
210 if (out_size.value):
211 json_str = json_buf.value.decode('UTF-8')
212 else:
213 json_str = ""
214 return (report, json_str, out_size.value)
PESieve_help()
Definition pesieve.py:180
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:198
t_report PESieve_scan(t_params params)
Definition pesieve.py:185