diff --git a/.gitignore b/.gitignore index 3a0d9dc8..f78e9d06 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ tests/running_report .DS_Store ._* .vscode/* +.vs/* diff --git a/include/common.h b/include/common.h index f3e82595..758398e7 100644 --- a/include/common.h +++ b/include/common.h @@ -48,6 +48,7 @@ #include "config.h" #include "output.h" #include "plugins.h" +#include "error_handling.h" #define UNUSED(x) (void)(sizeof((x))) @@ -85,3 +86,28 @@ void *calloc_s(size_t nmemb, size_t size); plugins_unload_all(); \ pev_cleanup_config(config); \ } while (0) + +static inline char* pev_strdup(const char* str) +{ + const size_t len = strlen(str); + char* dest = malloc(len + 1); + + if (!dest) + { + PEV_FATAL("it was not possible to allocate %zu bytes in the heap, " + "reason: memory exhausted", len + 1); + } + + return memcpy(dest, str, len + 1); +} + +static inline void pev_fclose(FILE * restrict fptr, bool on_exit) +{ + if (fclose(fptr) == EOF) + { + if (on_exit) + PEV_FATAL("Cannot close file handle: %p", (void*)fptr); + else + PEV_WARN("Cannot close file handle: %p", (void*)fptr); + } +} diff --git a/include/error_handling.h b/include/error_handling.h new file mode 100644 index 00000000..6f9d7ec6 --- /dev/null +++ b/include/error_handling.h @@ -0,0 +1,47 @@ +#ifndef PEV_ERROR_HANDLING_H +#define PEV_ERROR_HANDLING_H + +#include +#include + +#define PEV_WARN_IO_HANDLE stderr +#define PEV_FATAL_IO_HANDLE stderr +#define PEV_INFO_IO_HANDLE stdout + +#define PEV_FATAL(...) \ + do \ + { \ + fprintf(PEV_FATAL_IO_HANDLE, "[FATAL][%s:%d]: ", __FILE__, __LINE__); \ + fprintf(PEV_FATAL_IO_HANDLE, __VA_ARGS__); \ + fputc('\n', PEV_FATAL_IO_HANDLE); \ + exit(EXIT_FAILURE); \ + } while (0) + +#define PEV_WARN(...) \ + do \ + { \ + fprintf(PEV_WARN_IO_HANDLE, "[WARNING][%s:%d]: ", __FILE__, __LINE__); \ + fprintf(PEV_WARN_IO_HANDLE, __VA_ARGS__); \ + fputc('\n', PEV_WARN_IO_HANDLE); \ + } while (0) + +#define PEV_INFO(...) \ + do \ + { \ + fprintf(PEV_INFO_IO_HANDLE, "[INFO][%s:%d]: ", __FILE__, __LINE__); \ + fprintf(PEV_INFO_IO_HANDLE, __VA_ARGS__); \ + fputc('\n', PEV_INFO_IO_HANDLE); \ + } while (0) + +#define PEV_FATAL_IF(cond, ...) \ + do { if ((cond)) PEV_FATAL(__VA_ARGS__); } while (0) + +#define GLUE(cond) #cond + +#ifndef NDEBUG + #define PEV_ASSERT(cond) if (!(cond)) PEV_FATAL("Assertion \"%s\" failed", GLUE((cond))) +#else + #define PEV_ASSERT(cond) +#endif + +#endif \ No newline at end of file diff --git a/include/stack.h b/include/stack.h index 13189289..46e60a06 100644 --- a/include/stack.h +++ b/include/stack.h @@ -28,6 +28,7 @@ #pragma once #include +#include "error_handling.h" #define STACK_PASTE_2_(_1,_2) _1 ## _2 #define STACK_PASTE_2(_1,_2) STACK_PASTE_2_(_1, _2) @@ -74,7 +75,7 @@ static int STACK_API(stack_peek)(STACK_TYPE *stack, STACK_ELEMENT_TYPE *element) STACK_TYPE * STACK_API(stack_alloc)(uint16_t capacity) { STACK_TYPE *stack = calloc(1, sizeof(STACK_TYPE)); if (stack == NULL) { - fprintf(stderr, "stack: failed to allocate\n"); + PEV_WARN("failed to allocate %zu bytes", sizeof(STACK_TYPE)); return NULL; } @@ -90,10 +91,8 @@ STACK_TYPE * STACK_API(stack_alloc)(uint16_t capacity) { } void STACK_API(stack_dealloc)(STACK_TYPE *stack) { - assert(stack != NULL); - if (stack == NULL) { - fprintf(stderr, "stack: attempt to deallocate NULL stack\n"); + PEV_WARN("attempt to deallocate NULL stack"); return; } @@ -105,16 +104,18 @@ void STACK_API(stack_dealloc)(STACK_TYPE *stack) { } uint16_t STACK_API(stack_count)(STACK_TYPE *stack) { - assert(stack != NULL); + PEV_ASSERT(stack != NULL); return stack->used; } int STACK_API(stack_grow)(STACK_TYPE *stack, uint16_t capacity) { - assert(stack != NULL); - assert(capacity > stack->capacity); + PEV_ASSERT(stack != NULL); + + // wtf?? + //PEV_ASSERT(capacity > stack->capacity); if (capacity <= stack->capacity) { - fprintf(stderr, "stack: capacity cannot be decreased\n"); + PEV_WARN("capacity cannot be decreased"); return -1; } @@ -123,7 +124,7 @@ int STACK_API(stack_grow)(STACK_TYPE *stack, uint16_t capacity) { STACK_ELEMENT_TYPE *temp = realloc(stack->elements, new_size); if (temp == NULL) { - fprintf(stderr, "stack: failed to allocate requested capacity\n"); + PEV_WARN("failed to allocate requested capacity"); return -2; } @@ -134,26 +135,30 @@ int STACK_API(stack_grow)(STACK_TYPE *stack, uint16_t capacity) { } int STACK_API(stack_push)(STACK_TYPE *stack, STACK_ELEMENT_TYPE element) { - assert(stack != NULL); + PEV_ASSERT(stack != NULL); // Stack is full? if (stack->used >= stack->capacity) { // TODO(jweyrich): We could call `stack_grow` instead of failing miserably. Make this behavior adjustable? - fprintf(stderr, "stack: stack is full - failed to push\n"); - return -1; + // TODO(garcia): run tests + int retcode = STACK_GROW(stack, stack->capacity << 1); + if (retcode != 0) + { + PEV_WARN("failed to push"); + return -1; + } } stack->elements[stack->used++] = element; - return 0; } int STACK_API(stack_pop)(STACK_TYPE *stack, STACK_ELEMENT_TYPE *element) { - assert(stack != NULL); + PEV_ASSERT(stack != NULL); // Stack is empty? if (stack->used == 0) { - fprintf(stderr, "stack: stack is empty - failed to pop\n"); + PEV_WARN("stack is empty - failed to pop"); return -1; } @@ -169,7 +174,7 @@ int STACK_API(stack_peek)(STACK_TYPE *stack, STACK_ELEMENT_TYPE *element) { // Stack is empty? if (stack->used == 0) { - fprintf(stderr, "stack: stack is empty - failed to peek\n"); + PEV_WARN("stack is empty - failed to peek"); return -1; } diff --git a/lib/libpe b/lib/libpe index 6b6c8684..19c4ea43 160000 --- a/lib/libpe +++ b/lib/libpe @@ -1 +1 @@ -Subproject commit 6b6c86846d7c3f9d0f025675e551afaaf3866f4a +Subproject commit 19c4ea43ac4c9ddc784113ac96a39814aa82d575 diff --git a/src/config.c b/src/config.c index 72132b01..e25c18ff 100644 --- a/src/config.c +++ b/src/config.c @@ -34,16 +34,18 @@ files in the program, then also delete it here. */ -#include "config.h" #include #include #include #include #include +#include "config.h" +#include "../include/common.h" + #if defined(__linux__) -#include // FIXME: Why? + #include // FIXME: Why? #elif defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__CYGWIN__) -#include + #include #endif #define DEFAULT_CONFIG_FILENAME "pev.conf" @@ -57,11 +59,19 @@ #define DEFAULT_PLUGINS_PATH PLUGINSDIR #endif +#ifndef PEV_VA_COPY + #if (__STDC_VERSION__ >= 199901L) || defined(_MSC_VER) + #define PEV_VA_COPY(dest, src) va_copy(dest, src) + #else + #define PEV_VA_COPY(dest, src) (dest) = (src) + #endif +#endif + static bool _load_config_cb(pev_config_t * const config, const char *name, const char *value) { //fprintf(stderr, "DEBUG: %s=%s\n", name, value); if (!strcmp("plugins_dir", name)) { - config->plugins_path = strdup(value); + config->plugins_path = pev_strdup(value); return true; } @@ -74,6 +84,12 @@ static int _load_config_and_parse(pev_config_t * const config, const char *path, if (fp == NULL) return 0; + if (ferror(fp)) + { + pev_fclose(fp, false); // (on_exit = false) -> print only the warning + return 0; + } + char *p, *line = NULL; size_t size = 0; @@ -104,36 +120,67 @@ static int _load_config_and_parse(pev_config_t * const config, const char *path, size = 0; } - fclose(fp); - + // do we need to exit the program if it is not possible to close the file handle? + // by default, is set to true (print error message and exit) + pev_fclose(fp, true); return 1; } #ifdef USE_MY_ASPRINTF -int asprintf( char **pp, char *fmt, ... ) +static int asprintf(char** ppstr, const char* fmt, ...) { - char *p; - int size; + PEV_ASSERT(ppstr && fmt); + va_list args; + va_list args2; + bool failed = false; - va_start( args, fmt ); + va_start(args, fmt); - // Just get the string size. - if ( ( size = vsnprintf( NULL, 0, fmt, args ) ) < 0 ) + PEV_VA_COPY(args2, args); + int size = vsnprintf(NULL, 0, fmt, args2); + va_end(args2); + + if (size < 0) { - va_end( args ); + va_end(args); return -1; } - if ( ! ( p = malloc( size + 1 ) ) ) + if (*ppstr) + { + size_t len = strlen(*ppstr); + if (len < (size_t)size) + { + char* temp = (char*) realloc(*ppstr, size + 1); + + if (!temp) + { + failed = true; + free(*ppstr); + } + else + *ppstr = temp; + } + } + else { - va_end( args ); + if (!(*ppstr = (char*) malloc(size + 1))) + failed = true; + } + + if (failed) + { + errno = ENOMEM; + va_end(args); return -1; - } + } - vsprintf( *pp = p, fmt, args ); + int writted = vsprintf(*ppstr, fmt, args); + PEV_ASSERT(writted == size); - va_end( args ); + *(ppstr + size) = 0; + va_end(args); return size; } @@ -155,19 +202,21 @@ int pev_load_config(pev_config_t * const config) { ret = pe_utils_is_file_readable(buff); if (ret == LIBPE_E_OK) - if ( ! _load_config_and_parse(config, buff, _load_config_cb) ) + { + if (!_load_config_and_parse(config, buff, _load_config_cb)) { - free( buff ); + free(buff); return -1; } + } - free( buff ); + free(buff); // // Default values // if (config->plugins_path == NULL) - config->plugins_path = strdup(DEFAULT_PLUGINS_PATH); + config->plugins_path = pev_strdup(DEFAULT_PLUGINS_PATH); return 0; } diff --git a/src/dylib.c b/src/dylib.c index dbc95fe0..ea87f82b 100644 --- a/src/dylib.c +++ b/src/dylib.c @@ -51,45 +51,56 @@ #define dylib_error(...) dlerror() int dylib_load(dylib_t *lib, const char *path) { + + // debug check sanitizer + PEV_ASSERT(lib && path && *path); + if (lib->handle) { - fprintf(stderr, "Can't load library because it's already loaded: %s\n", lib->path); + PEV_WARN("Can't load library because it's already loaded: %s", lib->path); return -1; } + lib->handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL); - if ( ! lib->handle ) { - fprintf(stderr, "Failed to load library %s: %s\n", path, dylib_error(lib)); + if (!lib->handle) { + PEV_WARN("Failed to load library %s: %s", path, dylib_error(lib)); return -1; } - lib->path = strdup(path); + + lib->path = pev_strdup(path); return 0; } int dylib_unload(dylib_t *lib) { - int ret; - if ( !lib->handle ) { - fprintf(stderr, "Can't unload library '%s' because it's not loaded\n", lib->path); + PEV_ASSERT(lib); + + if (!lib->handle) { + PEV_WARN("Can't unload library '%s' because it's not loaded", lib->path); return -1; } - ret = dlclose(lib->handle); + + int ret = dlclose(lib->handle); if (ret != 0) { - fprintf(stderr, "Failed to unload library %s: %s\n", lib->path, dylib_error(lib)); + PEV_WARN("Failed to unload library %s: %s", lib->path, dylib_error(lib)); return -1; } + lib->handle = NULL; free(lib->path); lib->path = NULL; + return 0; } -void *dylib_get_symbol(dylib_t *lib, const char *symbol) { - void *addr = dlsym(lib->handle, symbol); - if (addr == NULL) { - fprintf(stderr, "Symbol '%s' not found in '%s': %s\n", symbol, lib->path, dylib_error(lib)); - } +void* dylib_get_symbol(dylib_t* lib, const char* symbol) { + PEV_ASSERT(lib && symbol && *symbol); + + void* addr = dlsym(lib->handle, symbol); + if (!addr) + PEV_WARN("Symbol \"%s\" not found in \"%s\": %s", symbol, lib->path, dylib_error(lib)); + return addr; } int dylib_has_symbol(dylib_t *lib, const char *symbol) { - void *addr = dlsym(lib->handle, symbol); - return addr != NULL; -} + return !!dylib_get_symbol(lib, symbol); +} \ No newline at end of file diff --git a/src/malloc_s.c b/src/malloc_s.c index 1d08798f..69ca5715 100644 --- a/src/malloc_s.c +++ b/src/malloc_s.c @@ -10,7 +10,7 @@ void *malloc_s(size_t size) { if (!new_mem) { fprintf(stderr, "fatal: memory exhausted (malloc of %zu bytes)\n", size); - exit(-1); + exit(EXIT_FAILURE); } return new_mem; diff --git a/src/ofs2rva.c b/src/ofs2rva.c index be06cddf..995b0253 100644 --- a/src/ofs2rva.c +++ b/src/ofs2rva.c @@ -109,7 +109,7 @@ int main(int argc, char *argv[]) errno = 0; ofs = strtoull(argv[1], NULL, 0); if ( !ofs || errno == ERANGE ) - EXIT_ERROR("invalid offset"); + PEV_FATAL("invalid offset"); err = pe_parse(&ctx); if (err != LIBPE_E_OK) { @@ -118,12 +118,18 @@ int main(int argc, char *argv[]) } if (!pe_is_pe(&ctx)) - EXIT_ERROR("not a valid PE file"); + PEV_FATAL("not a valid PE file"); printf("%#"PRIx64"\n", pe_ofs2rva(&ctx, ofs)); // libera a memoria - pe_unload(&ctx); + + err = pe_unload(&ctx); + if (err != LIBPE_E_OK) + { + pe_error_print(stderr, err); + return EXIT_FAILURE; + } //PEV_FINALIZE(); diff --git a/src/output.c b/src/output.c index b7a2f130..c8c7e6cd 100644 --- a/src/output.c +++ b/src/output.c @@ -135,9 +135,8 @@ void output_term(void) { g_cmdline = NULL; const uint16_t scope_depth = STACK_COUNT(g_scope_stack); - if (scope_depth > 0) { - fprintf(stderr, "output: terminating the output while there are open scopes will cause memory leaks"); - } + if (scope_depth > 0) + PEV_WARN("output: terminating the output while there are open scopes will cause memory leaks"); // TODO(jweyrich): Should we loop to pop + close + output every scope? if (g_scope_stack != NULL) @@ -157,10 +156,8 @@ void output_set_cmdline(int argc, char *argv[]) { free(g_cmdline); g_cmdline = pe_utils_str_array_join(g_argv, g_argc, ' '); - if (g_cmdline == NULL) { - fprintf(stderr, "output: allocation failed for pe_utils_str_array_join\n"); - abort(); - } + PEV_FATAL_IF(g_cmdline == NULL, "output: allocation failed for pe_utils_str_array_join"); + //fprintf(stderr, "DEBUG: cmdline = %s\n", g_cmdline); } @@ -239,9 +236,10 @@ void output_open_document(void) { } void output_open_document_with_name(const char *document_name) { - assert(g_format != NULL); + PEV_ASSERT(g_format != NULL); + // Cannot open a new document while there's one already open. - assert(!g_is_document_open); + PEV_ASSERT(!g_is_document_open); const char *key = document_name; const output_scope_type_e scope_type = OUTPUT_SCOPE_TYPE_DOCUMENT; @@ -251,28 +249,25 @@ void output_open_document_with_name(const char *document_name) { } void output_close_document(void) { - assert(g_format != NULL); + PEV_ASSERT(g_format != NULL); // Closing a document without first opening it is an error. - assert(g_is_document_open); + PEV_ASSERT(g_is_document_open); const output_scope_t *scope = NULL; int ret = STACK_PEEK(g_scope_stack, (void *)&scope); - if (ret < 0) { - fprintf(stderr, "output: cannot close a scope that has not been opened.\n"); - abort(); - } - if (scope->type != OUTPUT_SCOPE_TYPE_DOCUMENT) { - fprintf(stderr, "output: trying to close a document, but the current scope is of a different type.\n"); - abort(); - } + PEV_FATAL_IF(ret < 0, "output: cannot close a scope that has not been opened."); + + PEV_FATAL_IF(scope->type != OUTPUT_SCOPE_TYPE_DOCUMENT, + "output: trying to close a document, but the current scope is " + "of a different type."); output_close_scope(); g_is_document_open = false; } void output_open_scope(const char *scope_name, output_scope_type_e scope_type) { - assert(g_format != NULL); + PEV_ASSERT(g_format != NULL); const char *key = scope_name; const char *value = NULL; @@ -298,19 +293,16 @@ void output_open_scope(const char *scope_name, output_scope_type_e scope_type) { g_format->output_fn(g_format, type, scope, key, value); int ret = STACK_PUSH(g_scope_stack, (void *)scope); - if (ret < 0) - abort(); // Abort because it failed miserably! + PEV_FATAL_IF(ret < 0, "Cannot push new element in stack"); } void output_close_scope(void) { - assert(g_format != NULL); + PEV_ASSERT(g_format != NULL); output_scope_t *scope = NULL; int ret = STACK_POP(g_scope_stack, (void *)&scope); - if (ret < 0) { - fprintf(stderr, "output: cannot close a scope that has not been opened.\n"); - abort(); - } + + PEV_FATAL_IF(ret < 0, "output: cannot close a scope that has not been opened."); const char *key = NULL; const char *value = NULL; @@ -325,7 +317,7 @@ void output_close_scope(void) { } void output_keyval(const char *key, const char *value) { - assert(g_format != NULL); + PEV_ASSERT(g_format != NULL); const uint16_t scope_depth = STACK_COUNT(g_scope_stack); const output_scope_t *scope = NULL; diff --git a/src/output_plugin.c b/src/output_plugin.c index 772d38fa..8744d209 100644 --- a/src/output_plugin.c +++ b/src/output_plugin.c @@ -34,9 +34,10 @@ files in the program, then also delete it here. */ -#include "output_plugin.h" #include #include +#include "output_plugin.h" +#include "../include/common.h" size_t escape_count_chars_ex(const char *str, size_t len, const entity_table_t entities) { size_t result = 0; @@ -82,41 +83,29 @@ static size_t escape_count_chars(const format_t *format, const char *str, size_t } #endif +char* escape_ex(const char* str, const entity_table_t entities); + char *escape_ex_quoted(const char *str, const entity_table_t entities) { if (str == NULL) return NULL; if (str[0] == '\0') - return strdup("\"\""); + return pev_strdup("\"\""); if (entities == NULL) return strdup_quoted(str); - const size_t old_length = strlen(str); - const size_t new_length = escape_count_chars_ex(str, old_length, entities) + 2; // Extra bytes for quotes - - char *new_str = malloc(new_length + 1); // Extra byte for NULL terminator - if (new_str == NULL) - abort(); - - new_str[0] = '"'; - new_str[new_length - 1] = '"'; - new_str[new_length] = '\0'; + char* ptemp = escape_ex(str, entities); + char* new_str = NULL; - // `consumed` starts in 1 because of the initial quote. - size_t consumed = 1; - for (size_t i = 0; i < old_length; i++) { - const unsigned char index = (unsigned char)str[i]; - const entity_t entity = entities[index]; - if (entity == NULL) { - new_str[consumed++] = str[i]; - } else { - const size_t entity_len = strlen(entity); - memcpy(new_str + consumed, entity, entity_len); - consumed += entity_len; - } + if (asprintf(&new_str, "\"%s\"", ptemp) < 0) + { + PEV_WARN("Error to allocate memory for \"new_str\""); + free(ptemp); + return NULL; } + free(ptemp); return new_str; } @@ -125,34 +114,30 @@ char *escape_ex(const char *str, const entity_table_t entities) { return NULL; if (str[0] == '\0') - return strdup(""); + return pev_strdup(""); if (entities == NULL) - return strdup(str); + return pev_strdup(str); const size_t old_length = strlen(str); const size_t new_length = escape_count_chars_ex(str, old_length, entities); - char *new_str = malloc(new_length + 1); // Extra byte for NULL terminator - if (new_str == NULL) - abort(); + char* new_str = malloc_s(new_length + 1); // Extra byte for NULL terminator - new_str[new_length] = '\0'; + // save pointer + char* psaved = new_str; - size_t consumed = 0; - for (size_t i = 0; i < old_length; i++) { - const unsigned char index = (unsigned char)str[i]; - const entity_t entity = entities[index]; - if (entity == NULL) { - new_str[consumed++] = str[i]; - } else { - const size_t entity_len = strlen(entity); - memcpy(new_str + consumed, entity, entity_len); - consumed += entity_len; - } + for (const char* p = str; *p; ++p) + { + const entity_t entity = entities[(uint8_t)(*p)]; + if (!entity) + *new_str++ = *p; + else + new_str += snprintf(new_str, new_length, "%s", entity); } - return new_str; + new_str[new_length] = '\0'; + return psaved; } char *escape(const format_t *format, const char *str) { diff --git a/src/pehash.c b/src/pehash.c index f2a33f43..90ca5f2f 100644 --- a/src/pehash.c +++ b/src/pehash.c @@ -34,6 +34,7 @@ files in the program, then also delete it here. */ +#include #include "common.h" #include "plugins.h" @@ -42,13 +43,13 @@ unsigned pefile_warn = 0; typedef struct { - bool all; - bool content; + unsigned all : 1; + unsigned content : 1; struct { - bool all; - bool dos; - bool coff; - bool optional; + unsigned all : 1; + unsigned dos : 1; + unsigned coff : 1; + unsigned optional : 1; } headers; struct { char *name; @@ -143,15 +144,19 @@ static options_t *parse_options(int argc, char *argv[]) options->all = false; options->headers.all = false; // TODO: How do we need to handle non-ascii names? - options->sections.name = strdup(optarg); + options->sections.name = pev_strdup(optarg); break; case 2: options->all = false; options->headers.all = false; - options->sections.index = strtol(optarg, NULL, 10); - if (options->sections.index < 1 || options->sections.index > MAX_SECTIONS) { - EXIT_ERROR("Bad argument for section-index,"); - } + + errno = 0; + long number = strtol(optarg, NULL, 10); + + if (number < 1 || number > MAX_SECTIONS || errno == ERANGE) + PEV_FATAL("Bad argument for section-index,"); + + options->sections.index = number; break; case 'V': printf("%s %s\n%s\n", PROGRAM, TOOLKIT, COPY); @@ -182,7 +187,11 @@ static void print_basic_hash(const unsigned char *data, size_t data_size) char *hash_value = malloc_s(hash_value_size); for (size_t i=0; i < sizeof(basic_hashes) / sizeof(char *); i++) { - pe_hash_raw_data(hash_value, hash_value_size, basic_hashes[i], data, data_size); + + bool state = pe_hash_raw_data(hash_value, hash_value_size, basic_hashes[i], + data, data_size); + + PEV_ASSERT(state); output(basic_hashes[i], hash_value); } @@ -218,7 +227,7 @@ int main(int argc, char *argv[]) } if (!pe_is_pe(&ctx)) - EXIT_ERROR("not a valid PE file"); + PEV_FATAL("not a valid PE file"); const IMAGE_SECTION_HEADER *section_ptr = NULL; const unsigned char *data = NULL; @@ -306,6 +315,7 @@ int main(int argc, char *argv[]) break; case MAGIC_PE32: if (!pe_can_read(&ctx, opt_hdr->_32, sizeof(IMAGE_OPTIONAL_HEADER_32))) { + PEV_WARN("Could not read file: \"%s\"", ctx.path); // TODO: Should we report something? break; } @@ -314,6 +324,7 @@ int main(int argc, char *argv[]) break; case MAGIC_PE64: if (!pe_can_read(&ctx, opt_hdr->_64, sizeof(IMAGE_OPTIONAL_HEADER_64))) { + PEV_WARN("Could not read file: \"%s\"", ctx.path); // TODO: Should we report something? break; } @@ -354,13 +365,13 @@ int main(int argc, char *argv[]) } else if (options->sections.name != NULL) { const IMAGE_SECTION_HEADER *section = pe_section_by_name(&ctx, options->sections.name); if (section == NULL) { - EXIT_ERROR("The requested section could not be found on this binary"); + PEV_FATAL("The requested section could not be found on this binary"); } section_ptr = section; } else if (options->sections.index > 0) { const uint16_t num_sections = pe_sections_count(&ctx); if (num_sections == 0 || options->sections.index > num_sections) { - EXIT_ERROR("The requested section could not be found on this binary"); + PEV_FATAL("The requested section could not be found on this binary"); } IMAGE_SECTION_HEADER ** const sections = pe_sections(&ctx); const IMAGE_SECTION_HEADER *section = sections[options->sections.index - 1]; @@ -374,7 +385,7 @@ int main(int argc, char *argv[]) // fprintf(stderr, "section_data_ptr = %p\n", section_data_ptr); // fprintf(stderr, "SizeOfRawData = %u\n", section_ptr->SizeOfRawData); if (!pe_can_read(&ctx, section_data_ptr, section_ptr->SizeOfRawData)) { - EXIT_ERROR("The requested section has an invalid size"); + PEV_FATAL("The requested section has an invalid size"); } data = (const unsigned char *)section_data_ptr; data_size = section_ptr->SizeOfRawData; diff --git a/src/pepack.c b/src/pepack.c index cacf5478..3dd871a0 100644 --- a/src/pepack.c +++ b/src/pepack.c @@ -34,6 +34,7 @@ files in the program, then also delete it here. */ +#include #include "common.h" #include "plugins.h" @@ -94,11 +95,11 @@ static options_t *parse_options(int argc, char *argv[]) usage(); exit(EXIT_SUCCESS); case 'd': - options->dbfile = strdup(optarg); + options->dbfile = pev_strdup(optarg); break; case 'f': if (output_set_format_by_name(optarg) < 0) - EXIT_ERROR("invalid format option"); + PEV_FATAL("invalid format option"); break; case 'V': printf("%s %s\n%s\n", PROGRAM, TOOLKIT, COPY); @@ -132,7 +133,7 @@ static bool generic_packer(pe_ctx_t *ctx, uint64_t entrypoint) }; // MEW never leave EP in .text section - if (memcmp(section->Name, ".text", 5) == 0) + if (!memcmp(section->Name, (const uint8_t *)".text", 5)) return false; unsigned short flags_count = 0; @@ -148,6 +149,8 @@ static bool generic_packer(pe_ctx_t *ctx, uint64_t entrypoint) // FIX: Changed function name 'cause this don't 'load' anything. static bool opendb(FILE **fp, const options_t *options) { + PEV_ASSERT(fp && options); + const char *dbfile = options->dbfile ? options->dbfile : "userdb.txt"; *fp = fopen(dbfile, "r"); @@ -185,7 +188,16 @@ static bool match_peid_signature(const unsigned char *data, char *sig) } memcpy(byte_str, sig, 2); + + errno = 0; byte = strtoul((char *) byte_str, NULL, 16); + if (errno == ERANGE) + { + PEV_WARN("cannot get number into \"bytestr\""); + + // should we really return? + return false; + } if (*data++ != byte) return false; @@ -200,44 +212,47 @@ static bool compare_signature(const unsigned char *data, uint64_t ep_offset, FIL if (!dbfile || !data) return false; - // FIX: 2 KiB buffer isn't a big deal and this function is single threaded. - static char buff[MAX_SIG_SIZE]; + char* line = NULL; + size_t len = 0; + ssize_t nread = 0; - //memset(buff, 0, MAX_SIG_SIZE); - while (fgets(buff, MAX_SIG_SIZE, dbfile)) + while ((nread = getline(&line, &len, dbfile)) != -1) { - // line length - size_t len = strlen(buff); - // ignore comments and blank lines - if (*buff == ';' || *buff == '\n' || *buff == '\r') + if (*line == ';' || *line == '\n' || *line == '\r') continue; - // remove newline from buffer - if (*(buff+len-1) == '\n') - *(buff+len-1) = '\0'; + // remove newline from line + char* p = strrchr(line, '\n'); + if (p) *p = '\0'; - // removing carriage return, if present - if (*(buff+len-2) == '\r') + p = strrchr(line, '\r'); + if (p) { - *(buff+len-2) = '\0'; - //*(buff+len-1) = '\0'; - len--; // update line length + *p = 0; + nread--; } // line have [packer name]? Fill packer_name pointer - if (*buff == '[' && *(buff+len-2) == ']') + if (*line == '[' && *(line + nread - 2) == ']') { - *(buff+len-2) = '\0'; // remove square brackets - strncpy(packer_name, buff+1, packer_name_len); - packer_name[packer_name_len-1] = '\0'; // Guarantee it's Null-terminated. + *(line + nread - 2) = '\0'; // remove square brackets + strncpy(packer_name, line + 1, packer_name_len); + packer_name[packer_name_len - 1] = '\0'; // Guarantee it's Null-terminated. } // check if signature match - if (!strncasecmp(buff, "signature", 9)) - if (match_peid_signature(data + ep_offset, buff+9)) + if (!strncasecmp(line, "signature", 9)) + { + if (match_peid_signature(data + ep_offset, line + 9)) + { + free(line); return true; + } + } } + + free(line); return false; } @@ -271,15 +286,15 @@ int main(int argc, char *argv[]) } if (!pe_is_pe(&ctx)) - EXIT_ERROR("not a valid PE file"); + PEV_FATAL("not a valid PE file"); const uint64_t ep_offset = pe_rva2ofs(&ctx, ctx.pe.entrypoint); if (ep_offset == 0) - EXIT_ERROR("unable to get entrypoint offset"); + PEV_FATAL("unable to get entrypoint offset"); - FILE *dbfile; + FILE* dbfile = NULL; if (!opendb(&dbfile, options)) - fprintf(stderr, "WARNING: without valid database file, %s will search in generic mode only\n", PROGRAM); + PEV_WARN("without valid database file, %s will search in generic mode only", PROGRAM); static char value[MAX_MSG + 1]; @@ -303,7 +318,7 @@ int main(int argc, char *argv[]) output_close_document(); // FIX: Already tested of openess. - fclose(dbfile); + pev_fclose(dbfile, true); // libera a memoria free_options(options);