Created
February 27, 2013 19:55
-
-
Save taviso/5051148 to your computer and use it in GitHub Desktop.
Quick tool to generate PMF files for process monitor without having to use the GUI.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <iconv.h> | |
#include <string.h> | |
#include <assert.h> | |
// Quick utility to generate Process Monitor filter sets for testing. | |
// Tavis Ormandy <taviso@cmpxchg8b.com> | |
#define PMF_FILTER_VERSION 0x01 | |
typedef enum { | |
PMF_RELATION_IS, | |
PMF_RELATION_IS_NOT, | |
PMF_RELATION_LESS_THAN, | |
PMF_RELATION_MORE_THAN, | |
PMF_RELATION_BEGINS_WITH, | |
PMF_RELATION_ENDS_WITH, | |
PMF_RELATION_CONTAINS, | |
PMF_RELATION_EXCLUDES, | |
} pmf_relation_t; | |
typedef enum { | |
PMF_ACTION_EXCLUDE, | |
PMF_ACTION_INCLUDE, | |
} pmf_action_t; | |
typedef enum { | |
PMF_COLUMN_DATE_TIME = 0x74, | |
PMF_COLUMN_PROCESS_NAME = 0x75, | |
PMF_COLUMN_PID = 0x76, | |
PMF_COLUMN_OPERATION = 0x77, | |
PMF_COLUMN_RESULT = 0x78, | |
PMF_COLUMN_DETAIL = 0x79, | |
PMF_COLUMN_SEQUENCE = 0x7A, | |
PMF_COLUMN_COMPANY = 0x80, | |
PMF_COLUMN_DESCRIPTION = 0x81, | |
PMF_COLUMN_COMMAND_LINE = 0x82, | |
PMF_COLUMN_USER = 0x83, | |
PMF_COLUMN_IMAGE_PATH = 0x84, | |
PMF_COLUMN_SESSION = 0x85, | |
PMF_COLUMN_PATH = 0x87, | |
PMF_COLUMN_TID = 0x88, | |
PMF_COLUMN_RELATIVE_TIME = 0x8c, | |
PMF_COLUMN_DURATION = 0x8d, | |
PMF_COLUMN_TIME_OF_DAY = 0x8e, | |
PMF_COLUMN_VERSION = 0x91, | |
PMF_COLUMN_EVENT_CLASS = 0x92, | |
PMF_COLUMN_AUTHENTICATION_ID = 0x93, | |
PMF_COLUMN_VIRTUALIZED = 0x94, | |
PMF_COLUMN_INTEGRITY = 0x95, | |
PMF_COLUMN_CATEGORY = 0x96, | |
PMF_COLUMN_PARENT_PID = 0x97, | |
PMF_COLUMN_ARCHITECTURE = 0x98, | |
} pmf_column_t; | |
struct filter { | |
uint8_t column; | |
uint8_t unknown_01; | |
uint8_t unknown_02; | |
uint8_t unknown_03; | |
uint8_t relation; | |
uint8_t unknown_05; | |
uint8_t unknown_06; | |
uint8_t unknown_07; | |
uint8_t action; | |
uint32_t length; | |
uint8_t data[]; | |
} __attribute__((packed)); | |
struct set { | |
uint32_t length; | |
uint8_t version; | |
uint8_t count; | |
uint8_t unknown_06; | |
uint8_t unknown_07; | |
uint8_t unknown_08; | |
} __attribute__((packed)); | |
struct pmf { | |
FILE *stream; | |
char *mode; | |
struct set header; | |
struct filter *filters; | |
struct filter *current; | |
size_t filtersize; | |
}; | |
static const char * pmf_column_to_string(uint8_t column) | |
{ | |
static char * names[UINT8_MAX] = { | |
[PMF_COLUMN_DATE_TIME] "PMF_COLUMN_DATE_TIME", | |
[PMF_COLUMN_PROCESS_NAME] "PMF_COLUMN_PROCESS_NAME", | |
[PMF_COLUMN_PID] "PMF_COLUMN_PID", | |
[PMF_COLUMN_OPERATION] "PMF_COLUMN_OPERATION", | |
[PMF_COLUMN_RESULT] "PMF_COLUMN_RESULT", | |
[PMF_COLUMN_DETAIL] "PMF_COLUMN_DETAIL", | |
[PMF_COLUMN_SEQUENCE] "PMF_COLUMN_SEQUENCE", | |
[PMF_COLUMN_COMPANY] "PMF_COLUMN_COMPANY", | |
[PMF_COLUMN_DESCRIPTION] "PMF_COLUMN_DESCRIPTION", | |
[PMF_COLUMN_COMMAND_LINE] "PMF_COLUMN_COMMAND_LINE", | |
[PMF_COLUMN_USER] "PMF_COLUMN_USER", | |
[PMF_COLUMN_IMAGE_PATH] "PMF_COLUMN_IMAGE_PATH", | |
[PMF_COLUMN_SESSION] "PMF_COLUMN_SESSION", | |
[PMF_COLUMN_PATH] "PMF_COLUMN_PATH", | |
[PMF_COLUMN_TID] "PMF_COLUMN_TID", | |
[PMF_COLUMN_RELATIVE_TIME] "PMF_COLUMN_RELATIVE_TIME", | |
[PMF_COLUMN_DURATION] "PMF_COLUMN_DURATION", | |
[PMF_COLUMN_TIME_OF_DAY] "PMF_COLUMN_TIME_OF_DAY", | |
[PMF_COLUMN_VERSION] "PMF_COLUMN_VERSION", | |
[PMF_COLUMN_EVENT_CLASS] "PMF_COLUMN_EVENT_CLASS", | |
[PMF_COLUMN_AUTHENTICATION_ID] "PMF_COLUMN_AUTHENTICATION_ID", | |
[PMF_COLUMN_VIRTUALIZED] "PMF_COLUMN_VIRTUALIZED", | |
[PMF_COLUMN_INTEGRITY] "PMF_COLUMN_INTEGRITY", | |
[PMF_COLUMN_CATEGORY] "PMF_COLUMN_CATEGORY", | |
[PMF_COLUMN_PARENT_PID] "PMF_COLUMN_PARENT_PID", | |
[PMF_COLUMN_ARCHITECTURE] "PMF_COLUMN_ARCHITECTURE", | |
}; | |
return names[column] ? names[column] : "Unknown Column"; | |
} | |
static const char * pmf_relation_to_string(uint8_t relation) | |
{ | |
static char * names[UINT8_MAX] = { | |
[PMF_RELATION_IS] "PMF_RELATION_IS", | |
[PMF_RELATION_IS_NOT] "PMF_RELATION_IS_NOT", | |
[PMF_RELATION_LESS_THAN] "PMF_RELATION_LESS_THAN", | |
[PMF_RELATION_MORE_THAN] "PMF_RELATION_MORE_THAN", | |
[PMF_RELATION_BEGINS_WITH] "PMF_RELATION_BEGINS_WITH", | |
[PMF_RELATION_ENDS_WITH] "PMF_RELATION_ENDS_WITH", | |
[PMF_RELATION_CONTAINS] "PMF_RELATION_CONTAINS", | |
[PMF_RELATION_EXCLUDES] "PMF_RELATION_EXCLUDES" | |
}; | |
return names[relation] ? names[relation] : "Unknown Relation"; | |
} | |
static const char * pmf_action_to_string(uint8_t action) | |
{ | |
static char * names[UINT8_MAX] = { | |
[PMF_ACTION_INCLUDE] "PMF_ACTION_INCLUDE", | |
[PMF_ACTION_EXCLUDE] "PMF_ACTION_EXCLUDE", | |
}; | |
return names[action] ? names[action] : "Unknown Action"; | |
} | |
static uint8_t pmf_string_to_column(const char *column) | |
{ | |
unsigned i; | |
for (i = 0; i < UINT8_MAX; i++) { | |
if (strcmp(pmf_column_to_string(i), column) == 0) { | |
return i; | |
} | |
} | |
abort(); | |
} | |
static uint8_t pmf_string_to_action(const char *action) | |
{ | |
unsigned i; | |
for (i = 0; i < UINT8_MAX; i++) { | |
if (strcmp(pmf_action_to_string(i), action) == 0) { | |
return i; | |
} | |
} | |
abort(); | |
} | |
static uint8_t pmf_string_to_relation(const char *relation) | |
{ | |
unsigned i; | |
for (i = 0; i < UINT8_MAX; i++) { | |
if (strcmp(pmf_relation_to_string(i), relation) == 0) { | |
return i; | |
} | |
} | |
abort(); | |
} | |
struct pmf * pmf_open(const char *filename, const char *mode) | |
{ | |
struct pmf *handle; | |
handle = calloc(sizeof(struct pmf), 1); | |
handle->filtersize = 0; | |
handle->mode = strdup(mode); | |
handle->stream = fopen(filename, handle->mode); | |
handle->header.length = sizeof(handle->header) - sizeof(uint32_t); | |
handle->header.version = PMF_FILTER_VERSION; | |
handle->header.count = 0; | |
if (strcmp(handle->mode, "r") == 0) { | |
// If we're reading a pmf file, populate structure. | |
fread(&handle->header, sizeof handle->header, 1, handle->stream); | |
// Now we know the size of the filter set. | |
handle->filtersize = handle->header.length - sizeof(handle->header) + sizeof(uint32_t); | |
handle->filters = malloc(handle->filtersize); | |
handle->current = handle->filters; | |
// Read in the filters | |
fread(handle->filters, handle->filtersize, 1, handle->stream); | |
} | |
return handle; | |
} | |
bool pmf_read(struct pmf *handle, uint8_t *column, uint8_t *relation, char **value, uint8_t *action) | |
{ | |
iconv_t rconv; | |
assert(strcmp(handle->mode, "r") == 0); | |
if (handle->header.count) { | |
unsigned i; | |
char *data = malloc(handle->current->length); | |
char *inbuf = handle->current->data; | |
char *outbuf = data; | |
size_t avail_in = handle->current->length; | |
size_t avail_out = handle->current->length; | |
rconv = iconv_open("US-ASCII", "UTF-16LE"); | |
*column = handle->current->column; | |
*relation = handle->current->relation; | |
*action = handle->current->action; | |
*value = data; | |
iconv(rconv, &inbuf, &avail_in, &outbuf, &avail_out); | |
handle->current = (struct filter *) &handle->current->data[handle->current->length + 8]; | |
handle->header.count--; | |
iconv_close(rconv); | |
return true; | |
} | |
return false; | |
} | |
void pmf_close(struct pmf *handle) | |
{ | |
// Adjust for header size. | |
if (strcmp(handle->mode, "w") == 0) { | |
size_t written; | |
size_t total; | |
if (fwrite(&handle->header, sizeof(handle->header), 1, handle->stream) != 1) { | |
fprintf(stderr, "error writing header to file, %m\n"); | |
return; | |
} | |
written = fwrite(handle->filters, 1, handle->filtersize, handle->stream); | |
fprintf(stderr, "wanted to write %d, only wrote %d\n", handle->filtersize, written); | |
} | |
fclose(handle->stream); | |
free(handle->mode); | |
free(handle->filters); | |
free(handle); | |
return; | |
} | |
bool pmf_write(struct pmf *handle, uint8_t column, uint8_t relation, char *value, uint8_t action) | |
{ | |
struct filter *filter; | |
struct filter *current; | |
size_t size; | |
iconv_t wconv; | |
size_t inbytes = strlen(value) + 1; | |
size_t outbytes = inbytes * sizeof(uint16_t); | |
char *string; | |
uint8_t *data; | |
assert(strcmp(handle->mode, "w") == 0); | |
size = sizeof(struct filter); | |
size += inbytes * sizeof(uint16_t); | |
size += 8; | |
filter = calloc(size, 1); | |
filter->column = column; | |
filter->relation = relation; | |
filter->action = action; | |
filter->unknown_01 = 0x9c; | |
filter->length = inbytes * sizeof(uint16_t); | |
wconv = iconv_open("UTF-16LE", "US-ASCII"); | |
handle->filters = realloc(handle->filters, handle->filtersize + size); | |
data = (void *) handle->filters; | |
current = (void *) data + handle->filtersize; | |
string = filter->data; | |
iconv(wconv, &value, &inbytes, &string, &outbytes); | |
memcpy(data + handle->filtersize, filter, size); | |
handle->header.length += size; | |
handle->filtersize += size; | |
handle->header.count++; | |
free(filter); | |
iconv_close(wconv); | |
return true; | |
} | |
extern int optind, opterr, optopt; | |
extern char *optarg; | |
int main(int argc, char **argv) | |
{ | |
struct pmf *handle; | |
char *value; | |
uint8_t column; | |
uint8_t relation; | |
uint8_t action; | |
int opt; | |
size_t n; | |
char *line = NULL; | |
char columnstr[128]; | |
char actionstr[128]; | |
char relationstr[128]; | |
char param[1024]; | |
// Parse commandline arguments. | |
while ((opt = getopt(argc, argv, "r:w:")) != -1) { | |
switch (opt) { | |
// Read mode, parameter is a PMF file to parse, and generate a plain text dump. | |
case 'r': | |
// Open the specified file | |
if ((handle = pmf_open(optarg, "r")) == NULL) { | |
fprintf(stderr, "failed to open file %s, %m\n", optarg); | |
return 1; | |
} | |
// Read each filter | |
while (pmf_read(handle, &column, &relation, &value, &action)) { | |
fprintf(stdout, "%s %s %s %s\n", | |
pmf_column_to_string(column), | |
pmf_relation_to_string(relation), | |
pmf_action_to_string(action), | |
value); | |
free(value); | |
} | |
// Close file. | |
pmf_close(handle); | |
return 0; | |
// Write mode, parameter is a PMF file to generate, and read a plaintext input. | |
case 'w': | |
// Open the specified file | |
if ((handle = pmf_open(optarg, "w")) == NULL) { | |
fprintf(stderr, "failed to open file %s, %m", optarg); | |
return 1; | |
} | |
// Parse the input rules. | |
while (fscanf(stdin, "%128s %128s %128s %1024[^\n]\n", columnstr, relationstr, actionstr, param) == 4) { | |
pmf_write(handle, pmf_string_to_column(columnstr), | |
pmf_string_to_relation(relationstr), | |
param, | |
pmf_string_to_action(actionstr)); | |
} | |
// Close file. | |
pmf_close(handle); | |
return 0; | |
default: goto error; | |
} | |
} | |
error: | |
fprintf(stderr, "$Id: $\n"); | |
fprintf(stderr, "usage: %s -r input.pmf > output.txt # dump text to stdout\n", argv[0]); | |
fprintf(stderr, "usage: %s -w output.pmf < input.txt # parse filter on stdin\n", argv[0]); | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment