Skip to content

Instantly share code, notes, and snippets.

@taviso
Created February 27, 2013 19:55
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save taviso/5051148 to your computer and use it in GitHub Desktop.
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.
#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