• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eronnen / procmon-parser / 4247316153

pending completion
4247316153

push

github

GitHub
fix python2 missing enum.IntFlag (#26)

17 of 17 new or added lines in 2 files covered. (100.0%)

1502 of 1596 relevant lines covered (94.11%)

0.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.99
/procmon_parser/stream_logs_detail_format.py
1
from collections import namedtuple
1✔
2
from io import BytesIO
1✔
3
from struct import error, unpack
1✔
4

5
from procmon_parser.consts import EventClass, ProcessOperation, RegistryOperation, FilesystemOperation, \
1✔
6
    FilesystemSubOperations, FilesysemDirectoryControlOperation, RegistryTypes, RegistryKeyValueInformationClass, \
7
    RegistryKeyInformationClass, get_registry_access_mask_string, RegistryDisposition, RegistryKeySetInformationClass, \
8
    FilesystemQueryInformationOperation, get_filesystem_access_mask_string, FilesystemDisposition, \
9
    get_filesysyem_create_options, get_filesysyem_create_attributes, get_filesysyem_create_share_mode, \
10
    FilesystemOpenResult, get_filesysyem_io_flags, FilesystemPriority, get_ioctl_name, FileInformationClass, \
11
    get_filesystem_notify_change_flags, FilesystemSetInformationOperation, get_filesystem_createfilemapping_synctype, \
12
    PageProtection
13
from procmon_parser.stream_helper import read_u8, read_u16, read_u32, read_utf16, read_duration, \
1✔
14
    read_utf16_multisz, read_u64, read_filetime, read_s64
15

16
PmlMetadata = namedtuple('PmlMetadata', ['str_idx', 'process_idx', 'hostname_idx', 'port_idx', 'read_pvoid',
1✔
17
                                         'sizeof_pvoid', 'should_get_stacktrace', 'should_get_details'])
18

19

20
def get_enum_name_or(enum, val, default):
1✔
21
    try:
1✔
22
        return enum(val).name
1✔
23
    except ValueError:
×
24
        return default
×
25

26

27
def get_sid_string(sid):
1✔
28
    revision = unpack('B', sid[0:1])[0]
1✔
29
    if revision != 1:
1✔
30
        return ''  # Not 1 doesn't exist yet
×
31
    count = unpack('B', sid[1:2])[0]
1✔
32
    authority = unpack(">Q", b"\x00\x00" + sid[2:8])[0]
1✔
33
    sid_string = 'S-{}-{}'.format(revision, authority)
1✔
34
    binary = sid[8:]
1✔
35
    if len(binary) != 4 * count:
1✔
36
        return ''
×
37
    for i in range(count):
1✔
38
        value = unpack('<L', binary[4 * i:4 * (i + 1)])[0]
1✔
39
        sid_string += '-{}'.format(value)
1✔
40
    return sid_string
1✔
41

42

43
def read_detail_string_info(io):
1✔
44
    """Reads the info field about a detail string (contains is_ascii and number of characters)
45
    """
46
    flags = read_u16(io)
1✔
47
    return flags >> 15 == 1, flags & (2 ** 15 - 1)  # is_ascii, char_count
1✔
48

49

50
def read_detail_string(io, string_info):
1✔
51
    """Reads a string in the details that has an info field declared before
52
    """
53
    is_ascii, character_count = string_info
1✔
54
    if is_ascii:
1✔
55
        return io.read(character_count).decode("ascii")
1✔
56
    else:
57
        return read_utf16(io, character_count * 2)
1✔
58

59

60
def get_profiling_event_details(io, metadata, event, extra_detail_io):
1✔
61
    pass
×
62

63

64
def get_network_event_details(io, metadata, event, extra_detail_io):
1✔
65
    flags = read_u16(io)
1✔
66
    is_source_ipv4 = flags & 1 != 0
1✔
67
    is_dest_ipv4 = flags & 2 != 0
1✔
68
    is_tcp = flags & 4 != 0
1✔
69

70
    protocol = "TCP" if is_tcp else "UDP"
1✔
71
    event.operation = protocol + " " + event.operation
1✔
72

73
    io.seek(2, 1)  # Unknown field
1✔
74
    event.details['Length'] = read_u32(io)
1✔
75
    source_ip = io.read(16)
1✔
76
    dest_ip = io.read(16)
1✔
77
    source_port = read_u16(io)
1✔
78
    dest_port = read_u16(io)
1✔
79

80
    event.path = "{}:{} -> {}:{}".format(
1✔
81
        metadata.hostname_idx(source_ip, is_source_ipv4), metadata.port_idx(source_port, is_tcp),
82
        metadata.hostname_idx(dest_ip, is_dest_ipv4), metadata.port_idx(dest_port, is_tcp))
83

84
    extra_details = read_utf16_multisz(io)
1✔
85
    for i in range(len(extra_details) // 2):
1✔
86
        event.details[extra_details[i * 2]] = extra_details[i * 2 + 1]
1✔
87

88

89
def read_registry_data(io, reg_type_name, length=0):
1✔
90
    """Reads registry data (which is present in the Detail column in original Procmon) according to ``reg_type``
91
    """
92
    try:
1✔
93
        if reg_type_name == RegistryTypes.REG_DWORD.name:
1✔
94
            return read_u32(io)
1✔
95
        elif reg_type_name == RegistryTypes.REG_QWORD.name:
1✔
96
            return read_u64(io)
1✔
97
        elif reg_type_name == RegistryTypes.REG_EXPAND_SZ.name or reg_type_name == RegistryTypes.REG_SZ.name:
1✔
98
            return read_utf16(io)
1✔
99
        elif reg_type_name == RegistryTypes.REG_BINARY.name:
1✔
100
            # Assuming the stream ends at the end of the extra detail, so just read everything
101
            return io.read(length)
1✔
102
        elif reg_type_name == RegistryTypes.REG_MULTI_SZ.name:
1✔
103
            return read_utf16_multisz(io, length)
1✔
104
    except error:
×
105
        return ''
×
106

107
    return ''
1✔
108

109

110
def get_reg_type_name(reg_type_value):
1✔
111
    try:
1✔
112
        return RegistryTypes(reg_type_value).name
1✔
113
    except ValueError:
1✔
114
        return "<Unknown: {}>".format(reg_type_value)  # Don't know how to parse this
1✔
115

116

117
def get_registry_query_multiple_value_extra_details(metadata, event, extra_detail_io, details_info):
1✔
118
    event.category = "Read"
1✔
119

120

121
def get_registry_set_key_security_extra_details(metadata, event, extra_detail_io, details_info):
1✔
122
    event.category = "Write Metadata"
×
123

124

125
def get_registry_query_key_security_extra_details(metadata, event, extra_detail_io, details_info):
1✔
126
    event.category = "Read Metadata"
1✔
127

128

129
def get_registry_delete_key_or_value_extra_details(metadata, event, extra_detail_io, details_info):
1✔
130
    event.category = "Write"
1✔
131

132

133
def get_registry_load_or_rename_extra_details(metadata, event, extra_detail_io, details_info):
1✔
134
    new_path = read_detail_string(extra_detail_io, details_info["new_path_info"])
1✔
135
    if event.operation == RegistryOperation.RegLoadKey.name:
1✔
136
        event.details["Hive Path"] = new_path
1✔
137
    elif event.operation == RegistryOperation.RegRenameKey.name:
×
138
        event.category = "Write"
×
139
        event.details["New Name"] = new_path
×
140

141

142
def get_registry_query_or_enum_key_extra_details(metadata, event, extra_detail_io, details_info):
1✔
143
    event.category = "Read"  # RegQueryKey and RegEnumKey is always Read
1✔
144
    key_information_class = RegistryKeyInformationClass(details_info["information_class"])
1✔
145

146
    if event.operation == RegistryOperation.RegEnumKey.name:
1✔
147
        event.details["Index"] = details_info["index"]  # Only in enum
1✔
148
    elif event.operation == RegistryOperation.RegQueryKey.name:
1✔
149
        event.details["Query"] = key_information_class.name # Only in query
1✔
150

151
    if not extra_detail_io:
1✔
152
        #  There is no extra details
153
        event.details["Length"] = details_info["length"]
1✔
154
        return
1✔
155

156
    if key_information_class == RegistryKeyInformationClass.Name:
1✔
157
        # KEY_NAME_INFORMATION structure
158
        name_size = read_u32(extra_detail_io)
1✔
159
        event.details["Name"] = read_utf16(extra_detail_io, name_size)
1✔
160
    elif key_information_class == RegistryKeyInformationClass.HandleTags:
1✔
161
        event.details["HandleTags"] = read_u32(extra_detail_io)
1✔
162
    elif key_information_class == RegistryKeyInformationClass.Flags:
1✔
163
        event.details["UserFlags"] = read_u32(extra_detail_io)
1✔
164
    elif key_information_class == RegistryKeyInformationClass.Cached:
1✔
165
        # KEY_CACHED_INFORMATION structure
166
        event.details["LastWriteTime"] = read_filetime(extra_detail_io)
1✔
167
        event.details["TitleIndex"] = read_u32(extra_detail_io)
1✔
168
        event.details["SubKeys"] = read_u32(extra_detail_io)
1✔
169
        event.details["MaxNameLen"] = read_u32(extra_detail_io)
1✔
170
        event.details["Values"] = read_u32(extra_detail_io)
1✔
171
        event.details["MaxValueNameLen"] = read_u32(extra_detail_io)
1✔
172
        event.details["MaxValueDataLen"] = read_u32(extra_detail_io)
1✔
173
    elif key_information_class == RegistryKeyInformationClass.Basic:
1✔
174
        # KEY_BASIC_INFORMATION structure
175
        event.details["LastWriteTime"] = read_filetime(extra_detail_io)
1✔
176
        event.details["TitleIndex"] = read_u32(extra_detail_io)
1✔
177
        name_size = read_u32(extra_detail_io)
1✔
178
        event.details["Name"] = read_utf16(extra_detail_io, name_size)
1✔
179
    elif key_information_class == RegistryKeyInformationClass.Full:
1✔
180
        # KEY_FULL_INFORMATION structure
181
        event.details["LastWriteTime"] = read_filetime(extra_detail_io)
1✔
182
        event.details["TitleIndex"] = read_u32(extra_detail_io)
1✔
183
        event.details["ClassOffset"] = read_u32(extra_detail_io)
1✔
184
        event.details["ClassLength"] = read_u32(extra_detail_io)
1✔
185
        event.details["SubKeys"] = read_u32(extra_detail_io)
1✔
186
        event.details["MaxNameLen"] = read_u32(extra_detail_io)
1✔
187
        event.details["MaxClassLen"] = read_u32(extra_detail_io)
1✔
188
        event.details["Values"] = read_u32(extra_detail_io)
1✔
189
        event.details["MaxValueNameLen"] = read_u32(extra_detail_io)
1✔
190
        event.details["MaxValueDataLen"] = read_u32(extra_detail_io)
1✔
191
    elif key_information_class == RegistryKeyInformationClass.Node:
1✔
192
        # KEY_NODE_INFORMATION structure
193
        event.details["LastWriteTime"] = read_filetime(extra_detail_io)
1✔
194
        event.details["TitleIndex"] = read_u32(extra_detail_io)
1✔
195
        event.details["ClassOffset"] = read_u32(extra_detail_io)
1✔
196
        event.details["ClassLength"] = read_u32(extra_detail_io)
1✔
197
        name_size = read_u32(extra_detail_io)
1✔
198
        event.details["Name"] = read_utf16(extra_detail_io, name_size)
1✔
199

200

201
def get_registry_query_or_enum_value_extra_details(metadata, event, extra_detail_io, details_info):
1✔
202
    event.category = "Read"  # RegQueryValue and RegEnumValue are always Read
1✔
203
    key_value_information_class = RegistryKeyValueInformationClass(details_info["information_class"])
1✔
204

205
    if event.operation == RegistryOperation.RegEnumValue.name:
1✔
206
        event.details["Index"] = details_info["index"]  # Only in enum
1✔
207

208
    if not extra_detail_io:
1✔
209
        #  There is no extra details
210
        event.details["Length"] = details_info["length"]
1✔
211
        return
1✔
212

213
    extra_detail_io.seek(4, 1)  # Unknown field
1✔
214
    reg_type_name = get_reg_type_name(read_u32(extra_detail_io))
1✔
215

216
    if key_value_information_class == RegistryKeyValueInformationClass.KeyValueFullInformation:
1✔
217
        offset_to_data = read_u32(extra_detail_io)
1✔
218
        length_value = read_u32(extra_detail_io)
1✔
219
        name_size = read_u32(extra_detail_io)
1✔
220
        event.details["Name"] = read_utf16(extra_detail_io, name_size)
1✔
221
        extra_detail_io.seek(offset_to_data, 0)  # the stream starts at the start of the struct so the seek is good
1✔
222
    elif key_value_information_class == RegistryKeyValueInformationClass.KeyValuePartialInformation:
1✔
223
        length_value = read_u32(extra_detail_io)
1✔
224
    else:
225
        # Only KeyValuePartialInformation and KeyValueFullInformation have Data property
226
        event.details["Type"] = reg_type_name  # the Type is still known...
1✔
227
        return
1✔
228

229
    event.details["Type"] = reg_type_name  # I do this assignment here because "Name" comes before "Type"
1✔
230
    event.details["Length"] = length_value
1✔
231

232
    if length_value > 0:
1✔
233
        event.details["Data"] = read_registry_data(extra_detail_io, reg_type_name, length_value)
1✔
234

235

236
def get_registry_open_or_create_key_extra_details(metadata, event, extra_detail_io, details_info):
1✔
237
    event.category = "Read"
1✔
238
    if 0 == details_info["desired_access"]:
1✔
239
        return
×
240

241
    event.details["Desired Access"] = get_registry_access_mask_string(details_info["desired_access"])
1✔
242
    if not extra_detail_io:
1✔
243
        return
1✔
244

245
    if event.details["Desired Access"] == "Maximum Allowed":
1✔
246
        event.details["Granted Access"] = get_registry_access_mask_string(read_u32(extra_detail_io))
1✔
247
    else:
248
        extra_detail_io.seek(4, 1)
1✔
249

250
    disposition = read_u32(extra_detail_io)
1✔
251
    try:
1✔
252
        event.details["Disposition"] = RegistryDisposition(disposition).name
1✔
253
        if event.details["Disposition"] == RegistryDisposition.REG_CREATED_NEW_KEY.name:
1✔
254
            event.category = "Write"
1✔
255
    except ValueError:
1✔
256
        pass
1✔
257

258

259
def get_registry_set_info_key_extra_details(metadata, event, extra_detail_io, details_info):
1✔
260
    event.category = "Write Metadata"
1✔
261
    event.details["KeySetInformationClass"] = RegistryKeySetInformationClass.get(
1✔
262
        details_info["key_set_information_class"],
263
        "<Unknown: {}>".format(details_info["key_set_information_class"])
264
    )
265
    event.details["Length"] = details_info["length"]
1✔
266
    if details_info["length"] > 0:
1✔
267
        if event.details["KeySetInformationClass"] == "KeyWriteTimeInformation":
×
268
            event.details["LastWriteTime"] = read_filetime(extra_detail_io)
×
269
        elif event.details["KeySetInformationClass"] == "KeyWow64FlagsInformation":
×
270
            event.details["Wow64Flags"] = read_u32(extra_detail_io)
×
271
        elif event.details["KeySetInformationClass"] == "KeyWriteTimeInformation":
×
272
            event.details["HandleTags"] = read_u32(extra_detail_io)
×
273

274

275
def get_registry_set_value_extra_details(metadata, event, extra_detail_io, details_info):
1✔
276
    event.category = "Write"
1✔
277
    event.details["Type"] = get_reg_type_name(details_info["reg_type"])
1✔
278
    event.details["Length"] = details_info["length"]
1✔
279
    length = min(event.details["Length"], details_info["data_length"])
1✔
280
    if length > 0 and "Unknown" not in event.details["Type"]:
1✔
281
        event.details["Data"] = read_registry_data(extra_detail_io, event.details["Type"], length)
1✔
282

283

284
RegistryExtraDetailsHandler = {
1✔
285
    RegistryOperation.RegOpenKey.name: get_registry_open_or_create_key_extra_details,
286
    RegistryOperation.RegCreateKey.name: get_registry_open_or_create_key_extra_details,
287
    RegistryOperation.RegQueryKey.name: get_registry_query_or_enum_key_extra_details,
288
    RegistryOperation.RegSetValue.name: get_registry_set_value_extra_details,
289
    RegistryOperation.RegQueryValue.name: get_registry_query_or_enum_value_extra_details,
290
    RegistryOperation.RegEnumValue.name: get_registry_query_or_enum_value_extra_details,
291
    RegistryOperation.RegEnumKey.name: get_registry_query_or_enum_key_extra_details,
292
    RegistryOperation.RegSetInfoKey.name: get_registry_set_info_key_extra_details,
293
    RegistryOperation.RegDeleteKey.name: get_registry_delete_key_or_value_extra_details,
294
    RegistryOperation.RegDeleteValue.name: get_registry_delete_key_or_value_extra_details,
295
    RegistryOperation.RegLoadKey.name: get_registry_load_or_rename_extra_details,
296
    RegistryOperation.RegRenameKey.name: get_registry_load_or_rename_extra_details,
297
    RegistryOperation.RegQueryMultipleValueKey.name: get_registry_query_multiple_value_extra_details,
298
    RegistryOperation.RegSetKeySecurity.name: get_registry_set_key_security_extra_details,
299
    RegistryOperation.RegQueryKeySecurity.name: get_registry_query_key_security_extra_details,
300
}
301

302

303
def get_registry_event_details(io, metadata, event, extra_detail_io):
1✔
304
    path_info = read_detail_string_info(io)
1✔
305
    details_info = dict()  # information that is needed by the extra details structure
1✔
306

307
    if event.operation in [RegistryOperation.RegLoadKey.name, RegistryOperation.RegRenameKey.name]:
1✔
308
        details_info["new_path_info"] = read_detail_string_info(io)
1✔
309
        extra_detail_io = io  # the new path is a part of the details structure
1✔
310
    elif event.operation in [RegistryOperation.RegOpenKey.name, RegistryOperation.RegCreateKey.name]:
1✔
311
        io.seek(2, 1)  # Unknown field
1✔
312
        details_info["desired_access"] = read_u32(io)
1✔
313
    elif event.operation in [RegistryOperation.RegQueryKey.name, RegistryOperation.RegQueryValue.name]:
1✔
314
        io.seek(2, 1)  # Unknown field
1✔
315
        details_info["length"] = read_u32(io)
1✔
316
        details_info["information_class"] = read_u32(io)
1✔
317
    elif event.operation in [RegistryOperation.RegEnumValue.name, RegistryOperation.RegEnumKey.name]:
1✔
318
        io.seek(2, 1)  # Unknown field
1✔
319
        details_info["length"] = read_u32(io)
1✔
320
        details_info["index"] = read_u32(io)
1✔
321
        details_info["information_class"] = read_u32(io)
1✔
322
    elif event.operation == RegistryOperation.RegSetInfoKey.name:
1✔
323
        io.seek(2, 1)  # Unknown field
1✔
324
        details_info["key_set_information_class"] = read_u32(io)
1✔
325
        io.seek(4, 1)  # Unknown field
1✔
326
        details_info["length"] = read_u16(io)
1✔
327
        io.seek(2, 1)  # Unknown field
1✔
328
        extra_detail_io = io  # For RegSetInfoKey the data is in the details structure
1✔
329
    elif event.operation == RegistryOperation.RegSetValue.name:
1✔
330
        io.seek(2, 1)  # Unknown field
1✔
331
        details_info["reg_type"] = read_u32(io)
1✔
332
        details_info["length"] = read_u32(io)
1✔
333
        details_info["data_length"] = read_u32(io)
1✔
334
        extra_detail_io = io  # For RegSetValue the data is in the details structure
1✔
335

336
    event.path = read_detail_string(io, path_info)
1✔
337

338
    # Get the extra details structure
339
    if metadata.should_get_details and event.operation in RegistryExtraDetailsHandler:
1✔
340
        RegistryExtraDetailsHandler[event.operation](metadata, event, extra_detail_io, details_info)
1✔
341

342

343
def get_filesystem_read_metadata_details(io, metadata, event, details_io, extra_detail_io):
1✔
344
    event.category = "Read Metadata"
1✔
345

346

347
def get_filesystem_query_directory_details(io, metadata, event, details_io, extra_detail_io):
1✔
348
    event.category = "Read Metadata"
1✔
349
    directory_name_info = read_detail_string_info(io)
1✔
350
    directory_name = read_detail_string(io, directory_name_info)
1✔
351
    if directory_name:
1✔
352
        event.path = event.path + directory_name if event.path[-1] == "\\" else event.path + "\\" + directory_name
1✔
353
        event.details['Filter'] = directory_name
1✔
354

355
    details_io.seek(0x10, 1)
1✔
356
    if metadata.sizeof_pvoid == 8:
1✔
357
        details_io.seek(4, 1)  # Padding for 64 bit
1✔
358
    details_io.seek(0x4, 1)
1✔
359
    if metadata.sizeof_pvoid == 8:
1✔
360
        details_io.seek(4, 1)  # Padding for 64 bit
1✔
361

362
    file_information_class = FileInformationClass(read_u32(details_io))
1✔
363
    event.details["FileInformationClass"] = file_information_class.name
1✔
364

365
    if extra_detail_io and file_information_class in [FileInformationClass.FileDirectoryInformation,
1✔
366
                                                      FileInformationClass.FileFullDirectoryInformation,
367
                                                      FileInformationClass.FileBothDirectoryInformation,
368
                                                      FileInformationClass.FileNamesInformation,
369
                                                      FileInformationClass.FileIdBothDirectoryInformation,
370
                                                      FileInformationClass.FileIdFullDirectoryInformation]:
371
        extra_detail_length = len(extra_detail_io.getvalue())
1✔
372
        next_entry_offset = -1  # hack so the first iteration won't exit
1✔
373
        current_entry_offset = 1
1✔
374

375
        i = 0 if directory_name else -1
1✔
376
        while True:
1✔
377
            i += 1
1✔
378
            if next_entry_offset == 0 or (current_entry_offset + next_entry_offset) > extra_detail_length:
1✔
379
                break  # No more structures
1✔
380

381
            extra_detail_io.seek(current_entry_offset + next_entry_offset, 0)
1✔
382
            current_entry_offset = extra_detail_io.tell()
1✔
383
            next_entry_offset = read_u32(extra_detail_io)
1✔
384
            file_index = read_u32(extra_detail_io)
1✔
385
            if file_information_class == FileInformationClass.FileNamesInformation:
1✔
386
                # FILE_NAMES_INFORMATION structure
387
                file_name_length = read_u32(extra_detail_io)
×
388
                event.details[str(i)] = read_utf16(extra_detail_io, file_name_length)
×
389
                continue
×
390
            creation_time = read_filetime(extra_detail_io)
1✔
391
            last_access_time = read_filetime(extra_detail_io)
1✔
392
            last_write_time = read_filetime(extra_detail_io)
1✔
393
            change_time = read_filetime(extra_detail_io)
1✔
394
            end_of_file = read_u64(extra_detail_io)
1✔
395
            allocation_size = read_u64(extra_detail_io)
1✔
396
            file_attributes = read_u32(extra_detail_io)
1✔
397
            file_name_length = read_u32(extra_detail_io)
1✔
398
            if file_information_class == FileInformationClass.FileDirectoryInformation:
1✔
399
                # FILE_DIRECTORY_INFORMATION structure
400
                event.details[str(i)] = read_utf16(extra_detail_io, file_name_length)
1✔
401
                continue
1✔
402
            ea_size = read_u32(extra_detail_io)
1✔
403
            if file_information_class == FileInformationClass.FileFullDirectoryInformation:
1✔
404
                # FILE_FULL_DIR_INFORMATION structure
405
                event.details[str(i)] = read_utf16(extra_detail_io, file_name_length)
1✔
406
                continue
1✔
407
            if file_information_class == FileInformationClass.FileIdFullDirectoryInformation:
1✔
408
                # FILE_ID_FULL_DIR_INFORMATION structure
409
                file_id = read_u64(extra_detail_io)
×
410
                event.details[str(i)] = read_utf16(extra_detail_io, file_name_length)
×
411
                continue
×
412
            short_name_length = read_u8(extra_detail_io)
1✔
413
            extra_detail_io.seek(1, 1)  # Padding
1✔
414
            short_name = extra_detail_io.read(12 * 2)
1✔
415
            if file_information_class == FileInformationClass.FileBothDirectoryInformation:
1✔
416
                # FILE_BOTH_DIR_INFORMATION structure
417
                event.details[str(i)] = read_utf16(extra_detail_io, file_name_length)
1✔
418
                continue
1✔
419

420
            # FILE_ID_BOTH_DIR_INFORMATION structure
421
            extra_detail_io.seek(2, 1)  # Padding
1✔
422
            file_id = read_u64(extra_detail_io)
1✔
423
            event.details[str(i)] = read_utf16(extra_detail_io, file_name_length)
1✔
424
            continue
1✔
425

426

427
def get_filesystem_notify_change_directory_details(io, metadata, event, details_io, extra_detail_io):
1✔
428
    event.category = "Read Metadata"
1✔
429

430
    details_io.seek(0x10, 1)
1✔
431
    if metadata.sizeof_pvoid == 8:
1✔
432
        details_io.seek(4, 1)  # Padding for 64 bit
1✔
433

434
    event.details["Filter"] = get_filesystem_notify_change_flags(read_u32(details_io))
1✔
435

436

437
def get_filesystem_create_file_details(io, metadata, event, details_io, extra_detail_io):
1✔
438
    event.details["Desired Access"] = get_filesystem_access_mask_string(read_u32(io))
1✔
439
    impersonating_sid_length = read_u8(io)
1✔
440
    io.seek(0x3, 1)  # padding
1✔
441

442
    details_io.seek(0x10, 1)
1✔
443
    if metadata.sizeof_pvoid == 8:
1✔
444
        details_io.seek(4, 1)  # Padding for 64 bit
1✔
445

446
    disposition_and_options = read_u32(details_io)
1✔
447
    disposition = disposition_and_options >> 0x18
1✔
448
    options = disposition_and_options & 0xffffff
1✔
449
    if metadata.sizeof_pvoid == 8:
1✔
450
        details_io.seek(4, 1)  # Padding for 64 bit
1✔
451
    attributes = read_u16(details_io)
1✔
452
    share_mode = read_u16(details_io)
1✔
453

454
    event.details["Disposition"] = get_enum_name_or(FilesystemDisposition, disposition, "<unknown>")
1✔
455
    event.details["Options"] = get_filesysyem_create_options(options)
1✔
456
    event.details["Attributes"] = get_filesysyem_create_attributes(attributes)
1✔
457
    event.details["ShareMode"] = get_filesysyem_create_share_mode(share_mode)
1✔
458

459
    details_io.seek(0x4 + metadata.sizeof_pvoid * 2, 1)
1✔
460
    allocation = read_u32(details_io)
1✔
461
    allocation_value = allocation if disposition in [FilesystemDisposition.Supersede, FilesystemDisposition.Create,
1✔
462
                                                     FilesystemDisposition.OpenIf,
463
                                                     FilesystemDisposition.OverwriteIf] else "n/a"
464
    event.details["AllocationSize"] = allocation_value
1✔
465

466
    if impersonating_sid_length:
1✔
467
        event.details["Impersonating"] = get_sid_string(io.read(impersonating_sid_length))
1✔
468

469
    open_result = None
1✔
470
    if extra_detail_io:
1✔
471
        open_result = read_u32(extra_detail_io)
1✔
472
        event.details["OpenResult"] = get_enum_name_or(FilesystemOpenResult, open_result, "<unknown>")
1✔
473

474
    if open_result in [FilesystemOpenResult.Superseded, FilesystemOpenResult.Created, FilesystemOpenResult.Overwritten]:
1✔
475
        event.category = "Write"
1✔
476
    elif open_result in [FilesystemOpenResult.Opened, FilesystemOpenResult.Exists, FilesystemOpenResult.DoesNotExist]:
1✔
477
        pass
1✔
478
    elif event.details["Disposition"] in ["Open", "<unknown>"]:
1✔
479
        pass
1✔
480
    else:
481
        event.category = "Write"
1✔
482

483

484
def get_filesystem_create_file_mapping(io, metadata, event, details_io, extra_detail_io):
1✔
485
    """Get detailed information about a FileSystem CreateFileMapping event.
486

487
    Notes:
488
         The CreateFileMapping event is basically the results of the IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION IRP, but
489
         without the FS_FILTER_SECTION_SYNC_OUTPUT output information. Only SyncType and PageProtection are available.
490
         See: https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/flt-parameters-for-irp-mj-acquire-for-section-synchronization
491
    """
492
    # Only two fields are read from the details (there's also the detail string which is already read in the caller, see
493
    # get_filesystem_event_details() function). Besides those, all other fields seem to be completely ignored.
494
    details_io.seek(0x0C, 1)  # skip 0xC bytes from the beginning of details.
1✔
495
    sync_type = read_u32(details_io)  # note: asm uses 'movsxd', so it's signed with sign extension.
1✔
496
    page_protection = read_u32(details_io)
1✔
497
    event.details["SyncType"] = get_filesystem_createfilemapping_synctype(sync_type)
1✔
498

499
    if page_protection & PageProtection.PAGE_READONLY:
1✔
500
        event.details["PageProtection"] = PageProtection.PAGE_READONLY.name
1✔
501
    elif page_protection & PageProtection.PAGE_READWRITE:
1✔
502
        event.details["PageProtection"] = PageProtection.PAGE_READWRITE.name
1✔
503
    elif page_protection & PageProtection.PAGE_WRITECOPY:
1✔
504
        event.details["PageProtection"] = PageProtection.PAGE_WRITECOPY.name
1✔
505
    elif page_protection & PageProtection.PAGE_EXECUTE:
1✔
506
        event.details["PageProtection"] = PageProtection.PAGE_EXECUTE.name
1✔
507
    elif page_protection & PageProtection.PAGE_EXECUTE_READ:
1✔
508
        event.details["PageProtection"] = PageProtection.PAGE_EXECUTE_READ.name
1✔
509
    elif page_protection & PageProtection.PAGE_EXECUTE_READWRITE:
1✔
510
        event.details["PageProtection"] = PageProtection.PAGE_EXECUTE_READWRITE.name
×
511

512
    if page_protection & PageProtection.PAGE_NOCACHE and "PageProtection" in event.details:
1✔
513
        event.details["PageProtection"] += "|PAGE_NOCACHE"
×
514

515

516
def get_filesystem_read_write_file_details(io, metadata, event, details_io, extra_detail_io):
1✔
517
    event.category = "Read" if event.operation == "ReadFile" else "Write"
1✔
518
    details_io.seek(0x4, 1)
1✔
519
    io_flags_and_priority = read_u32(details_io)
1✔
520
    io_flags = io_flags_and_priority & 0xe000ff
1✔
521
    priority = (io_flags_and_priority >> 0x11) & 7
1✔
522
    details_io.seek(0x4, 1)
1✔
523
    length = read_u32(details_io)
1✔
524
    if metadata.sizeof_pvoid == 8:
1✔
525
        details_io.seek(4, 1)  # Padding for 64 bit
1✔
526
    details_io.seek(0x4, 1)
1✔
527
    if metadata.sizeof_pvoid == 8:
1✔
528
        details_io.seek(4, 1)  # Padding for 64 bit
1✔
529
    offset = read_s64(details_io)
1✔
530

531
    event.details["Offset"] = offset
1✔
532
    if extra_detail_io:
1✔
533
        length = read_u32(extra_detail_io)
1✔
534
    event.details["Length"] = length
1✔
535

536
    if io_flags != 0:
1✔
537
        event.details["I/O Flags"] = get_filesysyem_io_flags(io_flags)
1✔
538

539
    if priority != 0:
1✔
540
        event.details["Priority"] = FilesystemPriority.get(priority, "0x{:x}".format(priority))
1✔
541

542

543
def get_filesystem_ioctl_details(io, metadata, event, details_io, extra_detail_io):
1✔
544
    details_io.seek(0x8, 1)
1✔
545
    write_length = read_u32(details_io)
1✔
546
    read_length = read_u32(details_io)
1✔
547
    if metadata.sizeof_pvoid == 8:
1✔
548
        details_io.seek(4, 1)  # Padding for 64 bit
1✔
549

550
    details_io.seek(0x4, 1)
1✔
551
    if metadata.sizeof_pvoid == 8:
1✔
552
        details_io.seek(4, 1)  # Padding for 64 bit
1✔
553

554
    ioctl = read_u32(details_io)
1✔
555
    event.details["Control"] = get_ioctl_name(ioctl)
1✔
556
    if event.details["Control"] in ["FSCTL_OFFLOAD_READ", "FSCTL_GET_REPARSE_POINT", "FSCTL_READ_RAW_ENCRYPTED"]:
1✔
557
        event.category = "Read"
1✔
558
    elif event.details["Control"] in ["FSCTL_OFFLOAD_WRITE", "FSCTL_MOVE_FILE", "FSCTL_DELETE_REPARSE_POINT",
1✔
559
                                      "FSCTL_WRITE_RAW_ENCRYPTED", "FSCTL_PIPE_TRANSCEIVE",
560
                                      "FSCTL_PIPE_INTERNAL_TRANSCEIVE"]:
561
        event.category = "Write"
×
562
    elif event.details["Control"] in ["FSCTL_SET_COMPRESSION", "FSCTL_WRITE_PROPERTY_DATA", "FSCTL_SET_OBJECT_ID",
1✔
563
                                      "FSCTL_DELETE_OBJECT_ID", "FSCTL_SET_REPARSE_POINT", "FSCTL_SET_SPARSE",
564
                                      "FSCTL_SET_ENCRYPTION", "FSCTL_CREATE_USN_JOURNAL",
565
                                      "FSCTL_WRITE_USN_CLOSE_RECORD", "FSCTL_EXTEND_VOLUME",
566
                                      "FSCTL_DELETE_USN_JOURNAL"]:
567
        event.category = "Write Metadata"
1✔
568
    elif event.details["Control"] in ["FSCTL_QUERY_RETRIEVAL_POINTERS", "FSCTL_GET_COMPRESSION",
1✔
569
                                      "FSCTL_QUERY_FAT_BPB", "FSCTL_QUERY_FAT_BPB",
570
                                      "FSCTL_FILESYSTEM_GET_STATISTICS", "FSCTL_GET_NTFS_VOLUME_DATA",
571
                                      "FSCTL_GET_NTFS_FILE_RECORD", "FSCTL_GET_VOLUME_BITMAP",
572
                                      "FSCTL_GET_RETRIEVAL_POINTERS", "FSCTL_IS_VOLUME_DIRTY",
573
                                      "FSCTL_READ_PROPERTY_DATA", "FSCTL_FIND_FILES_BY_SID", "FSCTL_GET_OBJECT_ID",
574
                                      "FSCTL_READ_USN_JOURNAL", "FSCTL_SET_OBJECT_ID_EXTENDED",
575
                                      "FSCTL_CREATE_OR_GET_OBJECT_ID", "FSCTL_READ_FILE_USN_DATA",
576
                                      "FSCTL_QUERY_USN_JOURNAL"]:
577
        event.category = "Read Metadata"
1✔
578

579
    if event.operation == "FileSystemControl":
1✔
580
        if event.details["Control"] == "FSCTL_PIPE_INTERNAL_WRITE":
1✔
581
            event.details["Length"] = write_length
×
582
        elif event.details["Control"] == "FSCTL_OFFLOAD_READ":
1✔
583
            details_io.seek(0x8, 1)
1✔
584
            event.details["Offset"] = read_s64(io)
1✔
585
            event.details["Length"] = read_u64(io)
1✔
586
        elif event.details["Control"] == "FSCTL_OFFLOAD_WRITE":
1✔
587
            event.details["Offset"] = read_s64(io)
×
588
            event.details["Length"] = read_u64(io)
×
589
        elif event.details["Control"] == "FSCTL_PIPE_INTERNAL_READ":
1✔
590
            event.details["Length"] = read_length
×
591
        elif event.details["Control"] in ["FSCTL_PIPE_TRANSCEIVE", "FSCTL_PIPE_INTERNAL_TRANSCEIVE"]:
1✔
592
            event.details["WriteLength"] = write_length
×
593
            event.details["ReadLength"] = read_length
×
594

595

596
def get_filesystem_setdispositioninformation_details(io, metadata, event, details_io, extra_detail_io):
1✔
597
    is_delete = bool(read_u8(io))
1✔
598
    io.seek(3, 1)  # Padding
1✔
599

600
    if is_delete:
1✔
601
        event.details["Delete"] = "True"
1✔
602
        event.category = "Write"
1✔
603
    else:
604
        event.details["Delete"] = "False"
×
605

606

607
FilesystemSubOperationHandler = {
1✔
608
    FilesystemOperation.CreateFile.name: get_filesystem_create_file_details,
609
    FilesystemOperation.ReadFile.name: get_filesystem_read_write_file_details,
610
    FilesystemOperation.WriteFile.name: get_filesystem_read_write_file_details,
611
    FilesystemOperation.FileSystemControl.name: get_filesystem_ioctl_details,
612
    FilesysemDirectoryControlOperation.QueryDirectory.name: get_filesystem_query_directory_details,
613
    FilesysemDirectoryControlOperation.NotifyChangeDirectory.name: get_filesystem_notify_change_directory_details,
614
    FilesystemOperation.DeviceIoControl.name: get_filesystem_ioctl_details,
615
    FilesystemQueryInformationOperation.QueryIdInformation.name: get_filesystem_read_metadata_details,
616
    FilesystemQueryInformationOperation.QueryRemoteProtocolInformation.name: get_filesystem_read_metadata_details,
617
    FilesystemSetInformationOperation.SetDispositionInformationFile.name:
618
        get_filesystem_setdispositioninformation_details,
619
    FilesystemOperation.CreateFileMapping.name: get_filesystem_create_file_mapping,
620
}
621

622

623
def get_filesystem_event_details(io, metadata, event, extra_detail_io):
1✔
624
    sub_operation = read_u8(io)
1✔
625
    io.seek(0x3, 1)  # padding
1✔
626

627
    # fix operation name if there is more specific sub operation
628
    if 0 != sub_operation and FilesystemOperation[event.operation] in FilesystemSubOperations:
1✔
629
        try:
1✔
630
            event.operation = FilesystemSubOperations[FilesystemOperation[event.operation]](sub_operation).name
1✔
631
        except ValueError:
1✔
632
            event.operation += " <Unknown>"
1✔
633

634
    details_io = BytesIO(io.read(metadata.sizeof_pvoid * 5 + 0x14))
1✔
635
    path_info = read_detail_string_info(io)
1✔
636
    io.seek(2, 1)  # Padding
1✔
637
    event.path = read_detail_string(io, path_info)
1✔
638
    if metadata.should_get_details and event.operation in FilesystemSubOperationHandler:
1✔
639
        FilesystemSubOperationHandler[event.operation](io, metadata, event, details_io, extra_detail_io)
1✔
640

641

642
def get_process_created_details(io, metadata, event, extra_detail_io):
1✔
643
    io.seek(4, 1)  # Unknown fields
1✔
644
    event.details["PID"] = read_u32(io)
1✔
645
    io.seek(0x24, 1)  # Unknown fields
1✔
646
    unknown_size1 = read_u8(io)
1✔
647
    unknown_size2 = read_u8(io)
1✔
648
    path_info = read_detail_string_info(io)
1✔
649
    command_line_info = read_detail_string_info(io)
1✔
650
    io.seek(2 + unknown_size1 + unknown_size2, 1)  # Unknown fields
1✔
651
    event.path = read_detail_string(io, path_info)
1✔
652
    event.details["Command line"] = read_detail_string(io, command_line_info)
1✔
653

654

655
def get_process_started_details(io, metadata, event, extra_detail_io):
1✔
656
    event.details["Parent PID"] = read_u32(io)
1✔
657
    command_line_info = read_detail_string_info(io)
1✔
658
    current_directory_info = read_detail_string_info(io)
1✔
659
    environment_character_count = read_u32(io)
1✔
660
    event.details["Command line"] = read_detail_string(io, command_line_info)
1✔
661
    event.details["Current directory"] = read_detail_string(io, current_directory_info)
1✔
662
    event.details["Environment"] = read_utf16_multisz(io, environment_character_count * 2)
1✔
663

664

665
def get_process_exit_details(io, metadata, event, extra_details_io):
1✔
666
    event.details["Exit Status"] = read_u32(io)
1✔
667
    kernel_time = read_duration(io)
1✔
668
    user_time = read_duration(io)
1✔
669
    working_set = read_u64(io)
1✔
670
    peak_working_set = read_u64(io)
1✔
671
    private_bytes = read_u64(io)
1✔
672
    peak_private_bytes = read_u64(io)
1✔
673

674
    event.details["User Time"] = user_time
1✔
675
    event.details["Kernel Time"] = kernel_time
1✔
676
    event.details["Private Bytes"] = private_bytes
1✔
677
    event.details["Peak Private Bytes"] = peak_private_bytes
1✔
678
    event.details["Working Set"] = working_set
1✔
679
    event.details["Peak Working Set"] = peak_working_set
1✔
680

681

682
def get_load_image_details(io, metadata, event, extra_detail_io):
1✔
683
    event.details["Image Base"] = metadata.read_pvoid(io)
1✔
684
    event.details["Image Size"] = read_u32(io)
1✔
685
    path_info = read_detail_string_info(io)
1✔
686
    io.seek(2, 1)  # Unknown field
1✔
687
    event.path = read_detail_string(io, path_info)
1✔
688

689

690
def get_thread_create_details(io, metadata, event, extra_detail_io):
1✔
691
    event.details["Thread ID"] = read_u32(io)
1✔
692

693

694
def get_thread_exit_details(io, metadata, event, extra_detail_io):
1✔
695
    event.details["Thread ID"] = event.tid
1✔
696
    io.seek(4, 1)  # Unknown fields
1✔
697
    kernel_time = read_duration(io)
1✔
698
    user_time = read_duration(io)
1✔
699
    event.details["User Time"] = user_time
1✔
700
    event.details["Kernel Time"] = kernel_time
1✔
701

702

703
ProcessSpecificOperationHandler = {
1✔
704
    ProcessOperation.Process_Defined.name: get_process_created_details,
705
    ProcessOperation.Process_Create.name: get_process_created_details,
706
    ProcessOperation.Process_Exit.name: get_process_exit_details,
707
    ProcessOperation.Thread_Create.name: get_thread_create_details,
708
    ProcessOperation.Thread_Exit.name: get_thread_exit_details,
709
    ProcessOperation.Load_Image.name: get_load_image_details,
710
    ProcessOperation.Process_Start.name: get_process_started_details,
711
    ProcessOperation.Process_Statistics.name: get_process_exit_details,
712
}
713

714

715
def get_process_event_details(io, metadata, event, extra_detail_io):
1✔
716
    if event.operation in ProcessSpecificOperationHandler:
1✔
717
        ProcessSpecificOperationHandler[event.operation](io, metadata, event, extra_detail_io)
1✔
718

719

720
ClassEventDetailsHandler = {
1✔
721
    EventClass.Process: get_process_event_details,
722
    EventClass.Registry: get_registry_event_details,
723
    EventClass.File_System: get_filesystem_event_details,
724
    EventClass.Profiling: get_profiling_event_details,
725
    EventClass.Network: get_network_event_details
726
}
727

728

729
def get_event_details(detail_stream, metadata, event, extra_detail_stream):
1✔
730
    """Calculates the specific details of the event in the stream. The stream should be after the common
731
    information of the event.
732

733
    :param detail_stream: the stream of the details structure.
734
    :param metadata: metadata of the PML file.
735
    :param event: the event object to fill.
736
    :param extra_detail_stream: the stream of the extra details structure.
737
    """
738
    ClassEventDetailsHandler[event.event_class](detail_stream, metadata, event, extra_detail_stream)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc