#define READ_INCREMENT 4096 #define REG_NONE 0UL /* No value type */ #define REG_SZ 1UL /* Unicode nul terminated string */ #define REG_EXPAND_SZ 2UL /* Unicode nul terminated string */ #define REG_BINARY 3UL /* Free form binary */ #define REG_DWORD 4UL /* 32-bit number */ #define REG_DWORD_LITTLE_ENDIAN 4UL /* 32-bit number (same as REG_DWORD) */ #define REG_DWORD_BIG_ENDIAN 5UL /* 32-bit number */ #define REG_LINK 6UL /* Symbolic Link (unicode) */ #define REG_MULTI_SZ 7UL /* Multiple Unicode strings */ #define REG_RESOURCE_LIST 8UL /* Resource list in the resource map */ #define REG_FULL_RESOURCE_DESCRIPTOR 9UL /* Resource list in the hardware description */ #define REG_RESOURCE_REQUIREMENTS_LIST 10UL #define REG_QWORD 11UL /* 64-bit number */ #define REG_QWORD_LITTLE_ENDIAN 11UL /* 64-bit number (same as REG_QWORD) */ #include #include #include #include #include #include static size_t buf_len = 0; static size_t pol_len = 0; static size_t pol_index = 0; static char *buf = NULL; static void cleanup(void) { if (buf) { free(buf); } } static const char *typestr(uint32_t type) { static char unknown_name[7]; switch (type) { case REG_NONE: return "REG_NONE"; case REG_SZ: return "REG_SZ"; case REG_EXPAND_SZ: return "REG_EXPAND_SZ"; case REG_BINARY: return "REG_BINARY"; case REG_DWORD: return "REG_DWORD"; case REG_DWORD_BIG_ENDIAN: return "REG_DWORD_BIG_ENDIAN"; case REG_LINK: return "REG_LINK"; case REG_MULTI_SZ: return "REG_MULTI_SZ"; case REG_RESOURCE_LIST: return "REG_RESOURCE_LIST"; case REG_FULL_RESOURCE_DESCRIPTOR: return "REG_FULL_RESOURCE_DESCRIPTOR"; case REG_RESOURCE_REQUIREMENTS_LIST: return "REG_RESOURCE_REQUIREMENTS_LIST"; case REG_QWORD: return "REG_QWORD"; default: { snprintf(unknown_name, sizeof(unknown_name), "0x%x", type); return unknown_name; } } } static char *bufget(size_t len, bool force, size_t *len_out) { char *buf_pre = buf + pol_index; if (len_out != NULL) { *len_out = len; } /* pol_index + len = the index to read in the NEXT call * This call reads buf[pol_index_pre, pol_index_pre + len - 1] */ if ((pol_index += len) >= (pol_len + 1)) { printf("NPI %u\n", pol_index); if (force) { fprintf(stderr, "Invalid registry policy file: Unexpected EOF at %u, require %u more bytes.\n", pol_index - len, len); exit(1); } else { pol_index = pol_len - 1; if (len_out != NULL) { *len_out = pol_index - (buf_pre - buf) /* pol_index pre */ + 1; } } } return buf_pre; } static void bufret(size_t len) { pol_index -= len; } static char *bufgetf(size_t len) { return bufget(len, true, NULL); } static char *bufgett(size_t len, size_t *len_out) { return bufget(len, false, len_out); } static char bufgetchr(void) { char *b = bufgetf(2); if (b[1] != 0) { fprintf(stderr, "Illegal char at %u\n", pol_index); exit(1); } return b[0]; } static void bufprintnstr(uint32_t len) { for (len - 1; len >= 0; len --) { char c = bufgetchr(); if (c == 0) { return; } printf("%c", c); } } static void bufprintstr(void) { bufprintnstr(UINT32_MAX); } static void bufasschr(char c) { const char a = bufgetchr(); if (a != c) { fprintf(stderr, "Expected a '%c' at %u, but got a '%c'\n", c, pol_index, a); exit(4); } } static uint32_t bufgetdword(void) { return (uint32_t) *bufgetf(4); } int main(int argc, char **argv) { atexit(cleanup); char *path; if (argc == 2) { path = argv[1]; } else if (argc == 1) { path = "Registry.pol"; } else { fprintf(stderr, "Usage: %s /path/to/Registry.pol\n", argv[0]); return 64; } FILE *pol = fopen(path, "r"); if (!pol) { fprintf(stderr, "Cannot open %s: %s\n", path, strerror(errno)); return errno; } for (; !feof(pol) && !ferror(pol); ) { void *b = realloc(buf, buf_len += READ_INCREMENT); if (!b) { fprintf(stderr, "Cannot allocate memory: %s\n", strerror(errno)); return errno; } buf = b; pol_len += fread((void *)(buf + pol_len), 1, READ_INCREMENT, pol); } if (ferror(pol)) { fprintf(strerror, "Cannot read the file: %s\n", strerror(ferror(pol))); return ferror(pol); } fclose(pol); pol = NULL; if (memcmp(bufgetf(4), "PReg", 4) != 0) { fprintf(stderr, "Not a valid registry policy file.\n"); return 1; } const uint32_t ver = bufgetdword(); if (ver != 1) { fprintf(stderr, "Unsupported format version: %u. Only supported version 1 at this time.\n", ver); return 1; } while (pol_index < pol_len) { bufasschr('['); /* key */ bufprintstr(); bufasschr(';'); printf(", Value = "); /* value */ bufprintstr(); bufasschr(';'); printf(" ("); /* type */ const uint32_t type = bufgetdword(); bufasschr(';'); printf("%s) ", typestr(type)); /* size */ const uint32_t size = bufgetdword(); bufasschr(';'); /* data */ const uint32_t endi = pol_index + size; switch (type) { case REG_SZ: case REG_EXPAND_SZ: { bufprintnstr(size); break; } case REG_DWORD: { if (size != 4) { fprintf(stderr, "Incorrect size of REG_DWORD at %d\n", pol_index); return 1; } printf("%d", bufgetdword()); break; } case REG_DWORD_BIG_ENDIAN: case REG_NONE: case REG_BINARY: case REG_LINK: case REG_MULTI_SZ: case REG_RESOURCE_LIST: case REG_FULL_RESOURCE_DESCRIPTOR: case REG_RESOURCE_REQUIREMENTS_LIST: case REG_QWORD: default: { /* seek */ bufgetf(size); break; } } bufasschr(']'); printf("\n"); } }