forked from WerWolv/ImHex-Patterns
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpf.hexpat
More file actions
161 lines (146 loc) · 4.81 KB
/
pf.hexpat
File metadata and controls
161 lines (146 loc) · 4.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#pragma author MrMcX
#pragma description Parse forensically relevant parts of Windows Prefetch(*.pf) (only uncompressed SCCA version)
/*
The pattern implements the uncompressed SCCA format which is used below Windows 10.
For the newer compressed file format starting with "MAM\x04" has to be decompressed first,
for example using the at https://gist.github.com/dfirfpi/113ff71274a97b489dfd
Thanks to Joachim Metz for his work that this pattern is heavily based on:
https://github.com/libyal/libscca/blob/main/documentation/Windows%20Prefetch%20File%20(PF)%20format.asciidoc
Unknown values commented with "jm:" refer to Joachim Metz' format analysis
*/
#pragma magic [0x54 0x43 0x43 0x41] @ 0x04
#pragma endian little
import std.mem;
import std.string;
import type.time;
import type.magic;
enum WinVer : u32 {
Windows11 = 31,
Windows10 = 30,
Windows8x = 26,
Windows7orVista = 23,
WindowsXPor2003 = 17
};
enum Flag : u32 {
Boot = 0x01,
Application =0x00
};
fn to_HexString32(u32 value) {
return std::string::to_upper(std::format("{:08x}", value));
};
using HexString32 = u32 [[format("to_HexString32")]];
struct Header {
WinVer version;
type::Magic<"SCCA"> signature;
u32;
u32 size;
char16 program_name[30];
HexString32 crc_hash;
Flag flag;
};
struct FileInformation {
u32 metrics_offset;
u32 metrics_entry_count;
u32 trace_chains_offset;
u32 trace_chains_entry_count;
u32 filenames_offset;
u32 filenames_size;
u32 volumes_information_offset;
u32 volumes_count;
u32 volumes_information_size;
if(header.version >= WinVer::Windows7orVista) {
padding[8];
}
// Times are in FILETIME format (now shown as unix timestamp)
type::FILETIME last_execution;
if(header.version >= WinVer::Windows8x) {
type::FILETIME prev_executions[7];
}
if(header.version <= WinVer::Windows10) {
u128;
} else {
u64;
}
u32 run_count;
u32;
u32 hash_string_offset = 0x0;
u32 hash_string_size = 0;
if(header.version >= WinVer::Windows10) {
u32;
u32 hash_string_offset;
u32 hash_string_size;
padding[76];
} else if(header.version == WinVer::Windows8x) {
u32;
padding[84];
} else if(header.version == WinVer::Windows7orVista) {
padding[80];
}
};
struct FileReference {
u48 mft_entry_index;
u16 sequence_number;
};
struct FileMetric {
u32; // jm: might be prefetch start time in ms or index into the trace chain array
u32; // jm: might be prefetch duration in ms or number of entries in the trace chain
if(header.version >= WinVer::Windows7orVista) {
u32; // jm: might be Average prefetch duration in ms?
}
u32 filename_string_offset;
u32 filename_string_length;
u32 flags;
if(header.version >= WinVer::Windows7orVista) {
FileReference file_reference;
}
};
struct TraceChain {
if(header.version <= WinVer::Windows8x) {
u32 next_array_entry_index;
}
u32 total_block_load_count;
u8;
u8; // jm: might be sample duration in ms
u16;
};
struct DirectoryString {
u16 length;
char16 value[length+1];
};
struct VolumeInformation {
auto vi_start = $;
u32 volume_device_path_offset;
u32 volume_device_path_length;
type::FILETIME volume_creation_time;
HexString32 volume_serial_number;
u32 file_references_offset;
u32 file_references_size;
u32 directory_strings_offset;
u32 directory_strings_count;
u32;
if(header.version >= WinVer::Windows7orVista) {
padding[(header.version >= WinVer::Windows10) ? 24 : 28];
u32; // jm: might be copy of the number of directory strings
padding[(header.version >= WinVer::Windows10) ? 24 : 28];
u32;
}
$ = vi_start + volume_device_path_offset;
char16 volume_device_path[volume_device_path_length];
$ = vi_start + file_references_offset;
u32 file_reference_version;
u32 file_reference_count;
if(header.version >= WinVer::Windows7orVista) {
u64;
}
FileReference file_references[file_reference_count];
$ = vi_start + directory_strings_offset;
DirectoryString directory_strings[directory_strings_count];
};
Header header @ 0x00;
FileInformation info @ 0x54;
FileMetric metrics[info.metrics_entry_count] @ info.metrics_offset;
TraceChain trace_chains[info.trace_chains_entry_count] @ info.trace_chains_offset;
std::string::NullString16 filenames[while(!std::mem::reached(info.hash_string_offset))] @ info.filenames_offset;
// executable_path should be empty below windows 10
char16 executable_path[(info.hash_string_size / 2) - 1] @ info.hash_string_offset;
VolumeInformation volume_informations[info.volumes_count] @ info.volumes_information_offset;