From de44c33cd7ae586556dc2fd4808780538cad3c9d Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Thu, 8 Oct 2020 02:26:51 +0100 Subject: [PATCH 01/16] Added ability for pe module to scan memory mapped images --- libyara/include/yara/pe_utils.h | 37 ++- libyara/include/yara/types.h | 8 + libyara/modules/pe/pe.c | 297 ++++++++++++++++++++----- libyara/modules/pe/pe_utils.c | 13 +- libyara/proc/windows.c | 127 +++++++++++ windows/vs2017/libyara/libyara.vcxproj | 16 +- windows/vs2017/yara/yara.vcxproj | 9 +- 7 files changed, 432 insertions(+), 75 deletions(-) diff --git a/libyara/include/yara/pe_utils.h b/libyara/include/yara/pe_utils.h index 2e017a5308..14963a94f3 100644 --- a/libyara/include/yara/pe_utils.h +++ b/libyara/include/yara/pe_utils.h @@ -51,6 +51,8 @@ typedef struct _PE { const uint8_t* data; size_t data_size; + YR_MEMORY_REGION* region; + int memory; union { @@ -68,13 +70,42 @@ typedef struct _PE } PE; -#define fits_in_pe(pe, pointer, size) \ - ((size_t)(size) <= pe->data_size && (uint8_t*) (pointer) >= pe->data && \ - (uint8_t*) (pointer) <= pe->data + pe->data_size - (size)) +#define fits_in_pe(pe, pointer, size) \ +(pe->memory ? \ + ((size_t)size <= pe->region->data_size && \ + pe->region->block_count > 0 && \ + (uint8_t*)(pointer) >= (uint8_t*)pe->region->blocks[0].context && \ + (uint8_t*)(pointer) <= (uint8_t*)pe->region->blocks[0].context + pe->region->data_size - size) : \ + ((size_t)size <= pe->data_size && \ + (uint8_t*)(pointer) >= pe->data && \ + (uint8_t*)(pointer) <= pe->data + pe->data_size - size)) #define struct_fits_in_pe(pe, pointer, struct_type) \ fits_in_pe(pe, pointer, sizeof(struct_type)) +#define get_data_pointer_memory(pe, offset, value, type) \ +for (uint8_t i = 0; i < pe->region->block_count; i++) \ +{ \ + if (offset > pe->region->blocks[i].base && \ + offset < pe->region->blocks[i].base + pe->region->blocks[i].size) \ + { \ + value = (type)((uint8_t*)pe->region->blocks[i].context + (offset - pe->region->blocks[i].base)); \ + break; \ + } \ +} + +#define get_data_pointer_memory_with_size(pe, offset, value, type, maxsize) \ +for (uint8_t i = 0; i < pe->region->block_count; i++) \ +{ \ + if (offset > pe->region->blocks[i].base && \ + offset < pe->region->blocks[i].base + pe->region->blocks[i].size) \ + { \ + value = (type)((uint8_t*)pe->region->blocks[i].context + (offset - pe->region->blocks[i].base)); \ + maxsize = pe->region->blocks[i].size - (offset - pe->region->blocks[i].base); \ + break; \ + } \ +} + PIMAGE_NT_HEADERS32 pe_get_header(const uint8_t* data, size_t data_size); PIMAGE_DATA_DIRECTORY pe_get_directory_entry(PE* pe, int entry); diff --git a/libyara/include/yara/types.h b/libyara/include/yara/types.h index f1d63c6c63..351d883f6b 100644 --- a/libyara/include/yara/types.h +++ b/libyara/include/yara/types.h @@ -201,6 +201,7 @@ typedef struct YR_MODULE_IMPORT YR_MODULE_IMPORT; typedef struct YR_MEMORY_BLOCK YR_MEMORY_BLOCK; typedef struct YR_MEMORY_BLOCK_ITERATOR YR_MEMORY_BLOCK_ITERATOR; +typedef struct YR_MEMORY_REGION YR_MEMORY_REGION; typedef struct YR_MODIFIER YR_MODIFIER; @@ -718,6 +719,13 @@ struct YR_MEMORY_BLOCK_ITERATOR // only when they want to report an error. int last_error; }; +struct YR_MEMORY_REGION { + uint8_t block_count; + size_t data_size; + void* context; + YR_MEMORY_BLOCK blocks[32]; +}; + typedef int (*YR_CALLBACK_FUNC)( YR_SCAN_CONTEXT* context, diff --git a/libyara/modules/pe/pe.c b/libyara/modules/pe/pe.c index 3f2f1bf94b..ccf8dbdbb1 100644 --- a/libyara/modules/pe/pe.c +++ b/libyara/modules/pe/pe.c @@ -114,6 +114,12 @@ typedef int (*RESOURCE_CALLBACK_FUNC)( const IMAGE_RESOURCE_DIR_STRING_U* lang_string, void* cb_data); +YR_API YR_MEMORY_REGION* yr_process_fetch_memory_region_data( + YR_MEMORY_BLOCK* block); + +YR_API void* yr_process_fetch_primary_module_base( + YR_MEMORY_BLOCK_ITERATOR* iterator); + static size_t available_space(PE* pe, void* pointer) { if ((uint8_t*) pointer < pe->data) @@ -306,8 +312,14 @@ static void pe_parse_debug_directory(PE* pe) { int64_t pcv_hdr_offset = 0; - debug_dir = (PIMAGE_DEBUG_DIRECTORY)( - pe->data + debug_dir_offset + i * sizeof(IMAGE_DEBUG_DIRECTORY)); + if (pe->memory) + { + get_data_pointer_memory(pe, (debug_dir_offset + i * \ + sizeof(IMAGE_DEBUG_DIRECTORY)), debug_dir, PIMAGE_DEBUG_DIRECTORY); + if (debug_dir == NULL) break; + } + else debug_dir = (PIMAGE_DEBUG_DIRECTORY) \ + (pe->data + debug_dir_offset + i * sizeof(IMAGE_DEBUG_DIRECTORY)); if (!struct_fits_in_pe(pe, debug_dir, IMAGE_DEBUG_DIRECTORY)) break; @@ -333,7 +345,13 @@ static void pe_parse_debug_directory(PE* pe) if (pcv_hdr_offset <= 0) continue; - PCV_HEADER cv_hdr = (PCV_HEADER)(pe->data + pcv_hdr_offset); + PCV_HEADER cv_hdr; + if (pe->memory) + { + get_data_pointer_memory(pe, pcv_hdr_offset, cv_hdr, PCV_HEADER); + if (cv_hdr == NULL) continue; + } + else cv_hdr = (PCV_HEADER)(pe->data + pcv_hdr_offset); if (!struct_fits_in_pe(pe, cv_hdr, CV_HEADER)) continue; @@ -561,7 +579,12 @@ static int pe_iterate_resources( if (offset < 0) return 0; - rsrc_dir = (PIMAGE_RESOURCE_DIRECTORY)(pe->data + offset); + if (pe->memory) + { + get_data_pointer_memory(pe, offset, rsrc_dir, PIMAGE_RESOURCE_DIRECTORY); + if (rsrc_dir == NULL) return 0; + } + else rsrc_dir = (PIMAGE_RESOURCE_DIRECTORY) (pe->data + offset); if (struct_fits_in_pe(pe, rsrc_dir, IMAGE_RESOURCE_DIRECTORY)) { @@ -583,7 +606,7 @@ static int pe_iterate_resources( _pe_iterate_resources( pe, rsrc_dir, - pe->data + offset, + (uint8_t*)rsrc_dir, 0, &type, &id, @@ -616,7 +639,12 @@ static void pe_parse_version_info(PIMAGE_RESOURCE_DATA_ENTRY rsrc_data, PE* pe) if (version_info_offset < 0) return; - version_info = (PVERSION_INFO)(pe->data + version_info_offset); + if (pe->memory) + { + get_data_pointer_memory(pe, version_info_offset, version_info, PVERSION_INFO); + if (version_info == NULL) return; + } + else version_info = (PVERSION_INFO) (pe->data + version_info_offset); if (!struct_fits_in_pe(pe, version_info, VERSION_INFO)) return; @@ -810,7 +838,13 @@ static IMPORT_FUNCTION* pe_parse_import_descriptor( if (IS_64BITS_PE(pe)) { - PIMAGE_THUNK_DATA64 thunks64 = (PIMAGE_THUNK_DATA64)(pe->data + offset); + PIMAGE_THUNK_DATA64 thunks64; + if (pe->memory) + { + get_data_pointer_memory(pe, offset, thunks64, PIMAGE_THUNK_DATA64); + if (thunks64 == NULL) return NULL; + } + else thunks64 = (PIMAGE_THUNK_DATA64)(pe->data + offset); while (struct_fits_in_pe(pe, thunks64, IMAGE_THUNK_DATA64) && yr_le64toh(thunks64->u1.Ordinal) != 0 && @@ -827,14 +861,24 @@ static IMPORT_FUNCTION* pe_parse_import_descriptor( if (offset >= 0) { - PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME)( - pe->data + offset); + PIMAGE_IMPORT_BY_NAME import; + size_t imp_size; + if (pe->memory) + { + get_data_pointer_memory_with_size(pe, offset, import, PIMAGE_IMPORT_BY_NAME, imp_size); + if (import == NULL) continue; + } + else + { + import = (PIMAGE_IMPORT_BY_NAME)(pe->data + offset); + imp_size = available_space(pe, import->Name); + } if (struct_fits_in_pe(pe, import, IMAGE_IMPORT_BY_NAME)) { name = (char*) yr_strndup( (char*) import->Name, - yr_min(available_space(pe, import->Name), 512)); + yr_min(imp_size, 512)); } } } @@ -878,7 +922,13 @@ static IMPORT_FUNCTION* pe_parse_import_descriptor( } else { - PIMAGE_THUNK_DATA32 thunks32 = (PIMAGE_THUNK_DATA32)(pe->data + offset); + PIMAGE_THUNK_DATA32 thunks32; + if (pe->memory) + { + get_data_pointer_memory(pe, offset, thunks32, PIMAGE_THUNK_DATA32); + if (thunks32 == NULL) return NULL; + } + else thunks32 = (PIMAGE_THUNK_DATA32)(pe->data + offset); while (struct_fits_in_pe(pe, thunks32, IMAGE_THUNK_DATA32) && yr_le32toh(thunks32->u1.Ordinal) != 0 && @@ -895,14 +945,24 @@ static IMPORT_FUNCTION* pe_parse_import_descriptor( if (offset >= 0) { - PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME)( - pe->data + offset); + PIMAGE_IMPORT_BY_NAME import; + size_t imp_size; + if (pe->memory) + { + get_data_pointer_memory_with_size(pe, offset, import, PIMAGE_IMPORT_BY_NAME, imp_size); + if (import == NULL) continue; + } + else + { + import = (PIMAGE_IMPORT_BY_NAME)(pe->data + offset); + imp_size = available_space(pe, import->Name); + } if (struct_fits_in_pe(pe, import, IMAGE_IMPORT_BY_NAME)) { name = (char*) yr_strndup( (char*) import->Name, - yr_min(available_space(pe, import->Name), 512)); + yr_min(imp_size, 512)); } } } @@ -1056,7 +1116,13 @@ static IMPORTED_DLL* pe_parse_imports(PE* pe) if (offset < 0) return NULL; - imports = (PIMAGE_IMPORT_DESCRIPTOR)(pe->data + offset); + if (pe->memory) + { + get_data_pointer_memory(pe, offset, imports, PIMAGE_IMPORT_DESCRIPTOR); + if (imports == NULL) return NULL; + } + else imports = (PIMAGE_IMPORT_DESCRIPTOR) \ + (pe->data + offset); while (struct_fits_in_pe(pe, imports, IMAGE_IMPORT_DESCRIPTOR) && yr_le32toh(imports->Name) != 0 && num_imports < MAX_PE_IMPORTS) @@ -1067,9 +1133,20 @@ static IMPORTED_DLL* pe_parse_imports(PE* pe) { IMPORTED_DLL* imported_dll; - char* dll_name = (char*) (pe->data + offset); + char* dll_name; + size_t dll_name_max; + if (pe->memory) + { + get_data_pointer_memory_with_size(pe, offset, dll_name, char*, dll_name_max); + if (dll_name == NULL) return NULL; + } + else + { + dll_name = (char*)(pe->data + offset); + dll_name_max = pe->data_size - (size_t)offset; + } - if (!pe_valid_dll_name(dll_name, pe->data_size - (size_t) offset)) + if (!pe_valid_dll_name(dll_name, dll_name_max)) { imports++; continue; @@ -1453,7 +1530,12 @@ static void pe_parse_exports(PE* pe) export_start = offset; export_size = yr_le32toh(directory->Size); - exports = (PIMAGE_EXPORT_DIRECTORY)(pe->data + offset); + if (pe->memory) + { + get_data_pointer_memory(pe, offset, exports, PIMAGE_EXPORT_DIRECTORY); + if (exports == NULL) return; + } + else exports = (PIMAGE_EXPORT_DIRECTORY) (pe->data + offset); if (!struct_fits_in_pe(pe, exports, IMAGE_EXPORT_DIRECTORY)) return; @@ -1471,9 +1553,17 @@ static void pe_parse_exports(PE* pe) if (offset > 0) { remaining = pe->data_size - (size_t) offset; - name_len = strnlen((char*) (pe->data + offset), remaining); + char* name; + if (pe->memory) + { + get_data_pointer_memory(pe, offset, name, char*); + if (name == NULL) return; + } + else name = (char*)(pe->data + offset); + + name_len = strnlen(name, remaining); set_sized_string( - (char*) (pe->data + offset), name_len, pe->object, "dll_name"); + name, name_len, pe->object, "dll_name"); } if (number_of_exports * sizeof(DWORD) > pe->data_size - offset) @@ -1490,7 +1580,12 @@ static void pe_parse_exports(PE* pe) pe->data_size - offset) return; - names = (DWORD*) (pe->data + offset); + if (pe->memory) + { + get_data_pointer_memory(pe, offset, names, DWORD*); + if (names == NULL) return; + } + else names = (DWORD*)(pe->data + offset); } offset = pe_rva_to_offset(pe, yr_le32toh(exports->AddressOfNameOrdinals)); @@ -1498,9 +1593,18 @@ static void pe_parse_exports(PE* pe) if (offset < 0) return; - ordinals = (WORD*) (pe->data + offset); + if (pe->memory) + { + get_data_pointer_memory_with_size(pe, offset, ordinals, WORD*, remaining); + if (ordinals == NULL) return; + } + else + { + ordinals = (WORD*)(pe->data + offset); + remaining = available_space(pe, ordinals); + } - if (available_space(pe, ordinals) < sizeof(WORD) * number_of_exports) + if (remaining < sizeof(WORD) * number_of_exports) return; offset = pe_rva_to_offset(pe, yr_le32toh(exports->AddressOfFunctions)); @@ -1508,9 +1612,18 @@ static void pe_parse_exports(PE* pe) if (offset < 0) return; - function_addrs = (DWORD*) (pe->data + offset); + if (pe->memory) + { + get_data_pointer_memory_with_size(pe, offset, function_addrs, DWORD*, remaining); + if (function_addrs == NULL) return; + } + else + { + function_addrs = (DWORD*)(pe->data + offset); + remaining = available_space(pe, function_addrs); + } - if (available_space(pe, function_addrs) < sizeof(DWORD) * number_of_exports) + if (remaining < sizeof(DWORD) * number_of_exports) return; number_of_names = yr_min( @@ -1558,16 +1671,25 @@ static void pe_parse_exports(PE* pe) offset = pe_rva_to_offset(pe, yr_le32toh(function_addrs[i])); if (offset > export_start && offset < export_start + export_size) + { + char* name; + if (pe->memory) { - remaining = pe->data_size - (size_t) offset; - name_len = strnlen((char*) (pe->data + offset), remaining); + get_data_pointer_memory_with_size(pe, offset, name, char*, remaining); + if (name == NULL) return; + } + else + { + name = (char*)(pe->data + offset); + remaining = pe->data_size - (size_t)offset; + } + name_len = strnlen(name, remaining); - set_sized_string( - (char*) (pe->data + offset), - yr_min(name_len, MAX_EXPORT_NAME_LENGTH), - pe->object, - "export_details[%i].forward_name", - exp_sz); + set_sized_string( + name, + yr_min(name_len, MAX_EXPORT_NAME_LENGTH), + pe->object, + "export_details[%i].forward_name", exp_sz); } else { @@ -1584,11 +1706,21 @@ static void pe_parse_exports(PE* pe) if (offset > 0) { - remaining = pe->data_size - (size_t) offset; - name_len = strnlen((char*) (pe->data + offset), remaining); + char* name; + if (pe->memory) + { + get_data_pointer_memory_with_size(pe, offset, name, char*, remaining); + if (name == NULL) return; + } + else + { + name = (char*)(pe->data + offset); + remaining = pe->data_size - (size_t)offset; + } + name_len = strnlen(name, remaining); set_sized_string( - (char*) (pe->data + offset), + name, yr_min(name_len, MAX_EXPORT_NAME_LENGTH), pe->object, "export_details[%i].name", @@ -2311,19 +2443,22 @@ static void pe_parse_header(PE* pe, uint64_t base_address, int flags) // RawData + RawOffset of the last section on the physical file last_section_end = highest_sec_siz + highest_sec_ofs; - // For PE files that have overlaid data overlay.offset contains the offset - // within the file where the overlay starts and overlay.size contains the - // size. If the PE file doesn't have an overlay both fields are 0, if the - // file is not a PE file (or is a malformed PE) both fields are YR_UNDEFINED. - if (last_section_end && (pe->data_size > last_section_end)) + if (!pe->memory) { - set_integer(last_section_end, pe->object, "overlay.offset"); - set_integer(pe->data_size - last_section_end, pe->object, "overlay.size"); - } - else - { - set_integer(0, pe->object, "overlay.offset"); - set_integer(0, pe->object, "overlay.size"); + // For PE files that have overlaid data overlay.offset contains the offset + // within the file where the overlay starts and overlay.size contains the + // size. If the PE file doesn't have an overlay both fields are 0, if the + // file is not a PE file (or is a malformed PE) both fields are YR_UNDEFINED. + if (last_section_end && (pe->data_size > last_section_end)) + { + set_integer(last_section_end, pe->object, "overlay.offset"); + set_integer(pe->data_size - last_section_end, pe->object, "overlay.size"); + } + else + { + set_integer(0, pe->object, "overlay.offset"); + set_integer(0, pe->object, "overlay.size"); + } } } @@ -3144,7 +3279,7 @@ define_function(calculate_checksum) uint64_t csum = 0; size_t csum_offset; - if (pe == NULL) + if (pe == NULL || pe->memory) return_integer(YR_UNDEFINED); csum_offset = ((uint8_t*) &(pe->header->OptionalHeader) + @@ -3933,10 +4068,21 @@ int module_load( set_integer(0, module_object, "is_pe"); + PVOID base = NULL; + +#if defined(USE_WINDOWS_PROC) + + if ((context->flags & SCAN_FLAGS_PROCESS_MEMORY) > 0) + base = yr_process_fetch_primary_module_base(iterator); + +#endif + foreach_memory_block(iterator, block) { - block_data = block->fetch_data(block); + if (base && block->base != (uint64_t)base) continue; + block_data = block->fetch_data(block); + if (block_data == NULL) continue; @@ -3950,15 +4096,40 @@ int module_load( !(yr_le16toh(pe_header->FileHeader.Characteristics) & IMAGE_FILE_DLL)) { pe = (PE*) yr_malloc(sizeof(PE)); + pe->data_size = block->size; if (pe == NULL) return ERROR_INSUFFICIENT_MEMORY; - FAIL_ON_ERROR_WITH_CLEANUP( - yr_hash_table_create(17, &pe->hash_table), yr_free(pe)); +#if defined(USE_WINDOWS_PROC) + + if ((context->flags & SCAN_FLAGS_PROCESS_MEMORY) > 0) + { + pe->region = yr_process_fetch_memory_region_data(block); + if (pe->region == NULL) + return ERROR_INSUFFICIENT_MEMORY; + pe->memory = 1; + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_hash_table_create(17, &pe->hash_table), + yr_free(pe->region); yr_free(pe)); + } + else + { + FAIL_ON_ERROR_WITH_CLEANUP( + yr_hash_table_create(17, &pe->hash_table), + yr_free(pe)); + } + +#else + + FAIL_ON_ERROR_WITH_CLEANUP( + yr_hash_table_create(17, &pe->hash_table), + yr_free(pe)); + +#endif pe->data = block_data; - pe->data_size = block->size; pe->header = pe_header; pe->object = module_object; pe->resources = 0; @@ -3968,16 +4139,30 @@ int module_load( pe_parse_header(pe, block->base, context->flags); pe_parse_rich_signature(pe, block->base); + + if (pe->memory) + pe->data_size = pe->region->blocks[pe->region->block_count - 1].base + + pe->region->blocks[pe->region->block_count - 1].size; + + pe_iterate_resources( + pe, + (RESOURCE_CALLBACK_FUNC)pe_collect_resources, + (void*)pe); + + set_integer(pe->resources, pe->object, "number_of_resources"); + pe_parse_debug_directory(pe); -#if defined(HAVE_LIBCRYPTO) && !defined(BORINGSSL) - pe_parse_certificates(pe); -#endif + #if defined(HAVE_LIBCRYPTO) && !defined(BORINGSSL) + if (!pe->memory) pe_parse_certificates(pe); + #endif pe->imported_dlls = pe_parse_imports(pe); pe->delay_imported_dlls = pe_parse_delayed_imports(pe); pe_parse_exports(pe); + if (pe->region != NULL) yr_free(pe->region); + break; } } diff --git a/libyara/modules/pe/pe_utils.c b/libyara/modules/pe/pe_utils.c index 0b1d637c24..be75ba1418 100644 --- a/libyara/modules/pe/pe_utils.c +++ b/libyara/modules/pe/pe_utils.c @@ -133,9 +133,16 @@ int64_t pe_rva_to_offset(PE* pe, uint64_t rva) int alignment = 0; int rest = 0; - while (i < yr_min( - yr_le16toh(pe->header->FileHeader.NumberOfSections), - MAX_PE_SECTIONS)) +#if defined(USE_WINDOWS_PROC) + + if (pe->memory > 0) + { + return rva; + } + +#endif + + while(i < yr_min(yr_le16toh(pe->header->FileHeader.NumberOfSections), MAX_PE_SECTIONS)) { if (struct_fits_in_pe(pe, section, IMAGE_SECTION_HEADER)) { diff --git a/libyara/proc/windows.c b/libyara/proc/windows.c index 3668cff8a5..ed2d5246a5 100644 --- a/libyara/proc/windows.c +++ b/libyara/proc/windows.c @@ -30,6 +30,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if defined(USE_WINDOWS_PROC) #include +#include + +#include #include #include #include @@ -188,4 +191,128 @@ YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( return yr_process_get_next_memory_block(iterator); } + +YR_API YR_MEMORY_REGION* yr_process_fetch_memory_region_data( + YR_MEMORY_BLOCK* block) +{ + SIZE_T read; + + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*)block->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*)context->proc_info; + + MEMORY_BASIC_INFORMATION mbi; + PVOID address = (PVOID)(context->current_block.base); + PVOID allocBase = NULL; + SIZE_T allocSize = 0; + YR_MEMORY_REGION* region = yr_malloc(sizeof(YR_MEMORY_REGION)); + region->context = block->context; + + while (address < proc_info->si.lpMaximumApplicationAddress && + VirtualQueryEx(proc_info->hProcess, address, &mbi, sizeof(mbi)) != 0) + { + // mbi.RegionSize can overflow address while scanning a 64-bit process + // with a 32-bit YARA. + if ((uint8_t*)address + mbi.RegionSize <= (uint8_t*)address) + break; + + if (allocBase == NULL) allocBase = mbi.AllocationBase; + else if (allocBase != mbi.AllocationBase) break; + + if (mbi.State == MEM_COMMIT && ((mbi.Protect & PAGE_NOACCESS) == 0)) + { + allocSize += mbi.RegionSize; + if (region->block_count == 32) + return NULL; + + region->blocks[region->block_count].base = (size_t)mbi.BaseAddress; + region->blocks[region->block_count].size = mbi.RegionSize; + region->block_count++; + } + + address = (uint8_t*)address + mbi.RegionSize; + } + + if (context->buffer_size < allocSize) + { + if (context->buffer != NULL) + yr_free((void*)context->buffer); + + context->buffer = (const uint8_t*)yr_malloc(allocSize); + + if (context->buffer != NULL) context->buffer_size = allocSize; + else + { + context->buffer_size = 0; + return NULL; + } + } + + region->data_size = allocSize; + + allocSize = 0; + for (uint8_t i = 0; i < region->block_count; i++) + { + if (ReadProcessMemory( + proc_info->hProcess, + (LPCVOID)region->blocks[i].base, + (LPVOID)(context->buffer + allocSize), + (SIZE_T)region->blocks[i].size, + &read) == FALSE) + { + return NULL; + } + + region->blocks[i].base -= (size_t)allocBase; + region->blocks[i].context = (void*)(context->buffer + allocSize); + allocSize += region->blocks[i].size; + } + + return region; +} + + +YR_API void* yr_process_fetch_primary_module_base( + YR_MEMORY_BLOCK_ITERATOR* iterator) +{ + SIZE_T read; + PROCESS_BASIC_INFORMATION pbi = { 0 }; + + YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*)iterator->context; + YR_PROC_INFO* proc_info = (YR_PROC_INFO*)context->proc_info; + + ULONG_PTR wow64 = 0; + ULONG rlen = 0; + PVOID base = NULL; + + if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, ProcessWow64Information, &wow64, sizeof(wow64), &rlen)) && wow64) + { + if (ReadProcessMemory( + proc_info->hProcess, + (PVOID)((uint8_t*)wow64 + 0x8), + (LPVOID)(&base), + sizeof(base), + &read) == FALSE) + { + return NULL; + } + return base; + } + + if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &rlen)) && pbi.PebBaseAddress) + { + if (ReadProcessMemory( + proc_info->hProcess, + (PVOID)((uint8_t*)pbi.PebBaseAddress + 0x10), + (LPVOID)(&base), + sizeof(base), + &read) == FALSE) + { + return NULL; + } + return base; + } + + return NULL; +} + #endif diff --git a/windows/vs2017/libyara/libyara.vcxproj b/windows/vs2017/libyara/libyara.vcxproj index 27e3232963..84fc0deacc 100644 --- a/windows/vs2017/libyara/libyara.vcxproj +++ b/windows/vs2017/libyara/libyara.vcxproj @@ -90,7 +90,7 @@ _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC;YR_BUILDING_STATIC_LIB;YR_PROFILING_ENABLED ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x86.1.1.0\include;..\packages\YARA.OpenSSL.x86.1.1.1\include;%(AdditionalIncludeDirectories) - 4005;4273;4090 + 4005;4273;4090;4006 CompileAsC $(IntDir)/%(RelativeDir) ProgramDatabase @@ -99,7 +99,7 @@ $(OutDir)$(TargetName)$(TargetExt) - jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.dll;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true MachineX86 ..\packages\YARA.OpenSSL.x86.1.1.1\lib;..\packages\YARA.Jansson.x86.1.1.0\lib;%(AdditionalLibraryDirectories) @@ -117,7 +117,7 @@ _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC;YR_BUILDING_STATIC_LIBC;YR_PROFILING_ENABLED ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x64.1.1.0\include;..\packages\YARA.OpenSSL.x64.1.1.1\include;%(AdditionalIncludeDirectories) - 4005;4273;4090 + 4005;4273;4090;4006 CompileAsC $(IntDir)/%(RelativeDir) ProgramDatabase @@ -127,7 +127,7 @@ $(OutDir)$(TargetName)$(TargetExt) - crypt32.lib;ws2_32.lib;advapi32.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.lib;crypt32.lib;ws2_32.lib;advapi32.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true ..\packages\YARA.OpenSSL.x64.1.1.1\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) /IGNORE:4221 @@ -144,14 +144,14 @@ _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC;YR_BUILDING_STATIC_LIB ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x86.1.1.0\include;..\packages\YARA.OpenSSL.x86.1.1.1\include;%(AdditionalIncludeDirectories) - 4005;4273;4090 + 4005;4273;4090;4006 CompileAsC $(IntDir)/%(RelativeDir) MultiThreadedDLL - jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.dll;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true MachineX86 ..\packages\YARA.OpenSSL.x86.1.1.1\lib;..\packages\YARA.Jansson.x86.1.1.0\lib;%(AdditionalLibraryDirectories) @@ -169,7 +169,7 @@ _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC;YR_BUILDING_STATIC_LIB ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x64.1.1.0\include;..\packages\YARA.OpenSSL.x64.1.1.1\include;%(AdditionalIncludeDirectories) - 4005;4273;4090 + 4005;4273;4090;4006 CompileAsC $(IntDir)/%(RelativeDir) false @@ -177,7 +177,7 @@ MultiThreadedDLL - jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.dll;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true false ..\packages\YARA.OpenSSL.x64.1.1.1\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) diff --git a/windows/vs2017/yara/yara.vcxproj b/windows/vs2017/yara/yara.vcxproj index 93febb528c..453377b6f9 100644 --- a/windows/vs2017/yara/yara.vcxproj +++ b/windows/vs2017/yara/yara.vcxproj @@ -28,13 +28,13 @@ Application true - Unicode + MultiByte v141 Application true - Unicode + MultiByte true v141 @@ -42,14 +42,14 @@ Application false true - Unicode + MultiByte v141 Application false true - Unicode + MultiByte v141 @@ -175,7 +175,6 @@ - From 98680c32edd1bd6f0a7e65b2178d5c0f3b40bef8 Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Thu, 8 Oct 2020 19:00:50 +0100 Subject: [PATCH 02/16] Fix win process base module location to work with 32 bit builds --- libyara/proc/windows.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/libyara/proc/windows.c b/libyara/proc/windows.c index ed2d5246a5..ae721f26e0 100644 --- a/libyara/proc/windows.c +++ b/libyara/proc/windows.c @@ -284,6 +284,8 @@ YR_API void* yr_process_fetch_primary_module_base( ULONG rlen = 0; PVOID base = NULL; +#ifdef _WIN64 + if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, ProcessWow64Information, &wow64, sizeof(wow64), &rlen)) && wow64) { if (ReadProcessMemory( @@ -312,6 +314,24 @@ YR_API void* yr_process_fetch_primary_module_base( return base; } +#else + + if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &rlen)) && pbi.PebBaseAddress) + { + if (ReadProcessMemory( + proc_info->hProcess, + (PVOID)((uint8_t*)pbi.PebBaseAddress + 0x08), + (LPVOID)(&base), + sizeof(base), + &read) == FALSE) + { + return NULL; + } + return base; + } + +#endif + return NULL; } From 1a17386b2707eadae34338c9407eed0ec2e81e43 Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Thu, 8 Oct 2020 20:01:33 +0100 Subject: [PATCH 03/16] Do not attempt to get process module base address when running under WOW64 unless the target is also WOW64 --- libyara/proc/windows.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/libyara/proc/windows.c b/libyara/proc/windows.c index ae721f26e0..f4419e9c03 100644 --- a/libyara/proc/windows.c +++ b/libyara/proc/windows.c @@ -38,6 +38,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#ifndef _WIN64 + +typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + +BOOL _IsWow64() +{ + LPFN_ISWOW64PROCESS pIsWow64Process; + BOOL isWow64 = FALSE; + + pIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( + GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); + + if (pIsWow64Process != NULL && pIsWow64Process(GetCurrentProcess(), &isWow64)) + return isWow64; + + return FALSE; +} + +#endif + + typedef struct _YR_PROC_INFO { HANDLE hProcess; @@ -236,7 +257,7 @@ YR_API YR_MEMORY_REGION* yr_process_fetch_memory_region_data( { if (context->buffer != NULL) yr_free((void*)context->buffer); - + context->buffer = (const uint8_t*)yr_malloc(allocSize); if (context->buffer != NULL) context->buffer_size = allocSize; @@ -286,7 +307,8 @@ YR_API void* yr_process_fetch_primary_module_base( #ifdef _WIN64 - if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, ProcessWow64Information, &wow64, sizeof(wow64), &rlen)) && wow64) + if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, + ProcessWow64Information, &wow64, sizeof(wow64), &rlen)) && wow64) { if (ReadProcessMemory( proc_info->hProcess, @@ -300,7 +322,8 @@ YR_API void* yr_process_fetch_primary_module_base( return base; } - if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &rlen)) && pbi.PebBaseAddress) + if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, + ProcessBasicInformation, &pbi, sizeof(pbi), &rlen)) && pbi.PebBaseAddress) { if (ReadProcessMemory( proc_info->hProcess, @@ -316,7 +339,17 @@ YR_API void* yr_process_fetch_primary_module_base( #else - if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &rlen)) && pbi.PebBaseAddress) + if (_IsWow64()) //The pointer is likely to be truncated when running + //under WOW64, so return NULL to force a brute force + //search unless the target process is also WOW64 + { + if (!NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, + ProcessWow64Information, &wow64, sizeof(wow64), &rlen)) || !wow64) + return NULL; + } + + if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, + ProcessBasicInformation, &pbi, sizeof(pbi), &rlen)) && pbi.PebBaseAddress) { if (ReadProcessMemory( proc_info->hProcess, From feb2e7cded14cae0eb27a6077f72c49e6498a70f Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Thu, 8 Oct 2020 20:02:47 +0100 Subject: [PATCH 04/16] Return correct process memory region when an offset is on the upper boundary --- libyara/include/yara/pe_utils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libyara/include/yara/pe_utils.h b/libyara/include/yara/pe_utils.h index 14963a94f3..d08b9008b4 100644 --- a/libyara/include/yara/pe_utils.h +++ b/libyara/include/yara/pe_utils.h @@ -86,7 +86,7 @@ typedef struct _PE #define get_data_pointer_memory(pe, offset, value, type) \ for (uint8_t i = 0; i < pe->region->block_count; i++) \ { \ - if (offset > pe->region->blocks[i].base && \ + if (offset >= pe->region->blocks[i].base && \ offset < pe->region->blocks[i].base + pe->region->blocks[i].size) \ { \ value = (type)((uint8_t*)pe->region->blocks[i].context + (offset - pe->region->blocks[i].base)); \ @@ -97,7 +97,7 @@ for (uint8_t i = 0; i < pe->region->block_count; i++) \ #define get_data_pointer_memory_with_size(pe, offset, value, type, maxsize) \ for (uint8_t i = 0; i < pe->region->block_count; i++) \ { \ - if (offset > pe->region->blocks[i].base && \ + if (offset >= pe->region->blocks[i].base && \ offset < pe->region->blocks[i].base + pe->region->blocks[i].size) \ { \ value = (type)((uint8_t*)pe->region->blocks[i].context + (offset - pe->region->blocks[i].base)); \ From 3824f56f1d6f8c704062eb479cef357e12d79813 Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Thu, 8 Oct 2020 20:04:30 +0100 Subject: [PATCH 05/16] Avoid use after free when the block buffer is reallocated to fit the process binary --- libyara/modules/pe/pe.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libyara/modules/pe/pe.c b/libyara/modules/pe/pe.c index ccf8dbdbb1..f58683632a 100644 --- a/libyara/modules/pe/pe.c +++ b/libyara/modules/pe/pe.c @@ -572,7 +572,7 @@ static int pe_iterate_resources( if (yr_le32toh(directory->VirtualAddress) != 0) { - PIMAGE_RESOURCE_DIRECTORY rsrc_dir; + PIMAGE_RESOURCE_DIRECTORY rsrc_dir = NULL; offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress)); @@ -4106,10 +4106,17 @@ int module_load( if ((context->flags & SCAN_FLAGS_PROCESS_MEMORY) > 0) { pe->region = yr_process_fetch_memory_region_data(block); + if (pe->region == NULL) return ERROR_INSUFFICIENT_MEMORY; + + if (pe->region->block_count == 0) + continue; + pe->memory = 1; + pe_header = pe_get_header(pe->region->blocks[0].context, block->size); + FAIL_ON_ERROR_WITH_CLEANUP( yr_hash_table_create(17, &pe->hash_table), yr_free(pe->region); yr_free(pe)); From fda860716514aaff25357dfb0e636731af2e9e8a Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Thu, 8 Oct 2020 20:05:46 +0100 Subject: [PATCH 06/16] Fix typo in libyara vcxproj file --- windows/vs2017/libyara/libyara.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/windows/vs2017/libyara/libyara.vcxproj b/windows/vs2017/libyara/libyara.vcxproj index 84fc0deacc..e68410c010 100644 --- a/windows/vs2017/libyara/libyara.vcxproj +++ b/windows/vs2017/libyara/libyara.vcxproj @@ -99,7 +99,7 @@ $(OutDir)$(TargetName)$(TargetExt) - ntdll.dll;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true MachineX86 ..\packages\YARA.OpenSSL.x86.1.1.1\lib;..\packages\YARA.Jansson.x86.1.1.0\lib;%(AdditionalLibraryDirectories) @@ -151,7 +151,7 @@ MultiThreadedDLL - ntdll.dll;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true MachineX86 ..\packages\YARA.OpenSSL.x86.1.1.1\lib;..\packages\YARA.Jansson.x86.1.1.0\lib;%(AdditionalLibraryDirectories) @@ -177,7 +177,7 @@ MultiThreadedDLL - ntdll.dll;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true false ..\packages\YARA.OpenSSL.x64.1.1.1\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) @@ -272,4 +272,4 @@ - + \ No newline at end of file From 659507f1013b2fb49aa6999d0b9066d69b04305a Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Thu, 8 Oct 2020 21:56:29 +0100 Subject: [PATCH 07/16] Use correct size for WOW64 ImageBase in 64 bit build --- libyara/proc/windows.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libyara/proc/windows.c b/libyara/proc/windows.c index f4419e9c03..d87ce2981b 100644 --- a/libyara/proc/windows.c +++ b/libyara/proc/windows.c @@ -313,8 +313,8 @@ YR_API void* yr_process_fetch_primary_module_base( if (ReadProcessMemory( proc_info->hProcess, (PVOID)((uint8_t*)wow64 + 0x8), - (LPVOID)(&base), - sizeof(base), + (PDWORD)(&base), + sizeof(DWORD), &read) == FALSE) { return NULL; From 9d4212e47d269222986a063c0b8cc37e55735050 Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Thu, 8 Oct 2020 22:51:21 +0100 Subject: [PATCH 08/16] Fix bounds checks for memory region buffer data size --- libyara/modules/pe/pe.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libyara/modules/pe/pe.c b/libyara/modules/pe/pe.c index f58683632a..b31baf1cbf 100644 --- a/libyara/modules/pe/pe.c +++ b/libyara/modules/pe/pe.c @@ -4113,6 +4113,8 @@ int module_load( if (pe->region->block_count == 0) continue; + pe->data = pe->region->blocks[0].context; + pe->data_size = pe->region->data_size; pe->memory = 1; pe_header = pe_get_header(pe->region->blocks[0].context, block->size); @@ -4123,20 +4125,20 @@ int module_load( } else { + pe->data = block_data; FAIL_ON_ERROR_WITH_CLEANUP( yr_hash_table_create(17, &pe->hash_table), yr_free(pe)); } #else - + pe->data = block_data; FAIL_ON_ERROR_WITH_CLEANUP( yr_hash_table_create(17, &pe->hash_table), yr_free(pe)); #endif - pe->data = block_data; pe->header = pe_header; pe->object = module_object; pe->resources = 0; @@ -4147,10 +4149,6 @@ int module_load( pe_parse_header(pe, block->base, context->flags); pe_parse_rich_signature(pe, block->base); - if (pe->memory) - pe->data_size = pe->region->blocks[pe->region->block_count - 1].base + - pe->region->blocks[pe->region->block_count - 1].size; - pe_iterate_resources( pe, (RESOURCE_CALLBACK_FUNC)pe_collect_resources, @@ -4168,7 +4166,8 @@ int module_load( pe->delay_imported_dlls = pe_parse_delayed_imports(pe); pe_parse_exports(pe); - if (pe->region != NULL) yr_free(pe->region); + if (pe->region != NULL) + yr_free(pe->region); break; } From 75649979802acc9d10b9bb45fc39691e1a208400 Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Sun, 27 Jun 2021 14:22:20 +0100 Subject: [PATCH 09/16] Added vs2019 solution directory for Windows --- windows/vs2019/NuGet.Config | 9 + windows/vs2019/libyara/libyara.vcxproj | 274 +++++++++++++++++++++++++ windows/vs2019/libyara/packages.config | 7 + windows/vs2019/yara.sln | 64 ++++++ windows/vs2019/yara/yara.vcxproj | 184 +++++++++++++++++ windows/vs2019/yarac/yarac.vcxproj | 180 ++++++++++++++++ 6 files changed, 718 insertions(+) create mode 100644 windows/vs2019/NuGet.Config create mode 100644 windows/vs2019/libyara/libyara.vcxproj create mode 100644 windows/vs2019/libyara/packages.config create mode 100644 windows/vs2019/yara.sln create mode 100644 windows/vs2019/yara/yara.vcxproj create mode 100644 windows/vs2019/yarac/yarac.vcxproj diff --git a/windows/vs2019/NuGet.Config b/windows/vs2019/NuGet.Config new file mode 100644 index 0000000000..c695e4fe41 --- /dev/null +++ b/windows/vs2019/NuGet.Config @@ -0,0 +1,9 @@ + + + + + + + diff --git a/windows/vs2019/libyara/libyara.vcxproj b/windows/vs2019/libyara/libyara.vcxproj new file mode 100644 index 0000000000..eb4c10c0c8 --- /dev/null +++ b/windows/vs2019/libyara/libyara.vcxproj @@ -0,0 +1,274 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + Release + x64 + + + + {E236CE39-D8F3-4DB6-985C-F2794FF17746} + 10.0 + + + + StaticLibrary + true + v142 + + + StaticLibrary + true + v142 + + + StaticLibrary + false + v142 + + + false + v142 + StaticLibrary + + + false + v140 + StaticLibrary + + + + + + + + + + + + + + + + + + + $(ProjectName)32 + $(Configuration)\ + + + $(ProjectName)64 + $(Configuration)\ + $(Configuration)\ + + + $(ProjectName)32 + $(Configuration)\ + + + $(ProjectName)64 + $(Configuration)\ + $(Configuration)\ + + + + _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC;YR_BUILDING_STATIC_LIB;YR_PROFILING_ENABLED + ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x86.1.1.0\include;..\packages\YARA.OpenSSL.x86.1.1.1\include;%(AdditionalIncludeDirectories) + 4005;4273;4090;4006 + CompileAsC + $(IntDir)/%(RelativeDir) + ProgramDatabase + + MultiThreadedDLL + + + $(OutDir)$(TargetName)$(TargetExt) + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + true + MachineX86 + ..\packages\YARA.OpenSSL.x86.1.1.1\lib;..\packages\YARA.Jansson.x86.1.1.0\lib;%(AdditionalLibraryDirectories) + /IGNORE:4221 + + + false + + + advapi32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC;YR_BUILDING_STATIC_LIBC;YR_PROFILING_ENABLED + ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x64.1.1.0\include;..\packages\YARA.OpenSSL.x64.1.1.1\include;%(AdditionalIncludeDirectories) + 4005;4273;4090;4006 + CompileAsC + $(IntDir)/%(RelativeDir) + ProgramDatabase + false + + MultiThreadedDLL + + + $(OutDir)$(TargetName)$(TargetExt) + ntdll.lib;crypt32.lib;ws2_32.lib;advapi32.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + true + ..\packages\YARA.OpenSSL.x64.1.1.1\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) + /IGNORE:4221 + + + false + + + advapi32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC;YR_BUILDING_STATIC_LIB + ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x86.1.1.0\include;..\packages\YARA.OpenSSL.x86.1.1.1\include;%(AdditionalIncludeDirectories) + 4005;4273;4090;4006 + CompileAsC + $(IntDir)/%(RelativeDir) + + MultiThreadedDLL + + + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + true + MachineX86 + ..\packages\YARA.OpenSSL.x86.1.1.1\lib;..\packages\YARA.Jansson.x86.1.1.0\lib;%(AdditionalLibraryDirectories) + /IGNORE:4221 + + + advapi32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + false + + + + + _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC;YR_BUILDING_STATIC_LIB + ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x64.1.1.0\include;..\packages\YARA.OpenSSL.x64.1.1.1\include;%(AdditionalIncludeDirectories) + 4005;4273;4090;4006 + CompileAsC + $(IntDir)/%(RelativeDir) + false + + MultiThreadedDLL + + + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + true + false + ..\packages\YARA.OpenSSL.x64.1.1.1\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) + /IGNORE:4221 + + + advapi32.lib;%(AdditionalDependencies) + Default + No + + + false + + + + + _CRT_SECURE_NO_WARNINGS;CUCKOO_MODULE;HASH_MODULE;DOTNET_MODULE;HAVE_LIBCRYPTO;USE_WINDOWS_PROC;YR_BUILDING_STATIC_LIB;NDEBUG=1 + ..\..\..\libyara;..\..\..\libyara\include;..\..\..;..\packages\YARA.Jansson.x64.1.1.0\include;..\packages\YARA.OpenSSL.x64.1.1.1\include;%(AdditionalIncludeDirectories) + 4005;4273;4090 + CompileAsC + $(IntDir)/%(RelativeDir) + false + + MultiThreaded + + + jansson.lib;libcrypto.lib;%(AdditionalDependencies) + true + false + ..\packages\YARA.OpenSSL.x64.1.1.1\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) + /IGNORE:4221 + + + advapi32.lib;%(AdditionalDependencies) + Default + No + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/windows/vs2019/libyara/packages.config b/windows/vs2019/libyara/packages.config new file mode 100644 index 0000000000..8dd7fc89f4 --- /dev/null +++ b/windows/vs2019/libyara/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/windows/vs2019/yara.sln b/windows/vs2019/yara.sln new file mode 100644 index 0000000000..2fe5e924df --- /dev/null +++ b/windows/vs2019/yara.sln @@ -0,0 +1,64 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libyara", "libyara\libyara.vcxproj", "{E236CE39-D8F3-4DB6-985C-F2794FF17746}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yara", "yara\yara.vcxproj", "{DF8232C7-D8C1-4D05-9921-F8F504134410}" + ProjectSection(ProjectDependencies) = postProject + {E236CE39-D8F3-4DB6-985C-F2794FF17746} = {E236CE39-D8F3-4DB6-985C-F2794FF17746} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yarac", "yarac\yarac.vcxproj", "{7C72350B-AA5B-41AD-8957-CE3924A7F11B}" + ProjectSection(ProjectDependencies) = postProject + {E236CE39-D8F3-4DB6-985C-F2794FF17746} = {E236CE39-D8F3-4DB6-985C-F2794FF17746} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test-alignment", "..\vs2015\test-alignment\test-alignment.vcxproj", "{76A5B2B8-8844-4278-A33E-CE95261AF6A1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x64.ActiveCfg = Debug|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x64.Build.0 = Debug|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x86.ActiveCfg = Debug|Win32 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Debug|x86.Build.0 = Debug|Win32 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x64.ActiveCfg = Release|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x64.Build.0 = Release|x64 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x86.ActiveCfg = Release|Win32 + {E236CE39-D8F3-4DB6-985C-F2794FF17746}.Release|x86.Build.0 = Release|Win32 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Debug|x64.ActiveCfg = Debug|x64 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Debug|x64.Build.0 = Debug|x64 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Debug|x86.ActiveCfg = Debug|Win32 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Debug|x86.Build.0 = Debug|Win32 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Release|x64.ActiveCfg = Release|x64 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Release|x64.Build.0 = Release|x64 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Release|x86.ActiveCfg = Release|Win32 + {DF8232C7-D8C1-4D05-9921-F8F504134410}.Release|x86.Build.0 = Release|Win32 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Debug|x64.ActiveCfg = Debug|x64 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Debug|x64.Build.0 = Debug|x64 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Debug|x86.ActiveCfg = Debug|Win32 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Debug|x86.Build.0 = Debug|Win32 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Release|x64.ActiveCfg = Release|x64 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Release|x64.Build.0 = Release|x64 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Release|x86.ActiveCfg = Release|Win32 + {7C72350B-AA5B-41AD-8957-CE3924A7F11B}.Release|x86.Build.0 = Release|Win32 + {76A5B2B8-8844-4278-A33E-CE95261AF6A1}.Debug|x64.ActiveCfg = Debug|x64 + {76A5B2B8-8844-4278-A33E-CE95261AF6A1}.Debug|x64.Build.0 = Debug|x64 + {76A5B2B8-8844-4278-A33E-CE95261AF6A1}.Debug|x86.ActiveCfg = Debug|Win32 + {76A5B2B8-8844-4278-A33E-CE95261AF6A1}.Debug|x86.Build.0 = Debug|Win32 + {76A5B2B8-8844-4278-A33E-CE95261AF6A1}.Release|x64.ActiveCfg = Release|x64 + {76A5B2B8-8844-4278-A33E-CE95261AF6A1}.Release|x64.Build.0 = Release|x64 + {76A5B2B8-8844-4278-A33E-CE95261AF6A1}.Release|x86.ActiveCfg = Release|Win32 + {76A5B2B8-8844-4278-A33E-CE95261AF6A1}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/windows/vs2019/yara/yara.vcxproj b/windows/vs2019/yara/yara.vcxproj new file mode 100644 index 0000000000..17d761ce18 --- /dev/null +++ b/windows/vs2019/yara/yara.vcxproj @@ -0,0 +1,184 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {DF8232C7-D8C1-4D05-9921-F8F504134410} + Win32Proj + yara + 10.0 + + + + Application + true + MultiByte + v142 + + + Application + true + MultiByte + true + v142 + + + Application + false + true + MultiByte + v142 + + + Application + false + true + MultiByte + v142 + + + + + + + + + + + + + + + + + + + false + $(ProjectName)32 + + + $(ProjectName)64 + $(SolutionDir)\$(Configuration)\ + $(Configuration)\ + + + false + $(ProjectName)32 + + + false + $(ProjectName)64 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + + Level3 + NotUsing + Disabled + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..\cli;%(AdditionalIncludeDirectories) + false + CompileAsC + ProgramDatabase + MultiThreadedDLL + + + Console + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + + + + + Level3 + NotUsing + Disabled + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..\cli;%(AdditionalIncludeDirectories) + false + CompileAsC + ProgramDatabase + MultiThreadedDLL + + + Console + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + Default + + + + + Level3 + NotUsing + MaxSpeed + true + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..\cli;%(AdditionalIncludeDirectories) + CompileAsC + ProgramDatabase + MultiThreadedDLL + + + Console + true + true + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + No + + + false + + + + + Level3 + NotUsing + MaxSpeed + true + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..\cli;%(AdditionalIncludeDirectories) + CompileAsC + ProgramDatabase + MultiThreadedDLL + + + Console + true + true + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + No + + + + + + + + + + + \ No newline at end of file diff --git a/windows/vs2019/yarac/yarac.vcxproj b/windows/vs2019/yarac/yarac.vcxproj new file mode 100644 index 0000000000..24e61fcf61 --- /dev/null +++ b/windows/vs2019/yarac/yarac.vcxproj @@ -0,0 +1,180 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7C72350B-AA5B-41AD-8957-CE3924A7F11B} + Win32Proj + yarac + 10.0 + + + + Application + true + Unicode + v142 + + + Application + true + Unicode + v142 + + + Application + false + true + Unicode + v142 + + + Application + false + true + Unicode + v142 + + + + + + + + + + + + + + + + + + + false + $(ProjectName)32 + + + false + $(ProjectName)64 + $(SolutionDir)\$(Configuration)\ + $(Configuration)\ + + + false + $(ProjectName)32 + + + false + $(ProjectName)64 + $(SolutionDir)\$(Configuration)\ + $(Configuration)\ + + + + Level3 + NotUsing + Disabled + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..\cli;%(AdditionalIncludeDirectories) + false + CompileAsC + ProgramDatabase + MultiThreadedDLL + + + Console + true + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + + + + + Level3 + NotUsing + Disabled + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..\cli;%(AdditionalIncludeDirectories) + CompileAsC + ProgramDatabase + MultiThreadedDLL + + + Console + true + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + false + + + + + Level3 + NotUsing + MaxSpeed + true + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..\cli;%(AdditionalIncludeDirectories) + CompileAsC + ProgramDatabase + MultiThreadedDLL + + + Console + No + true + true + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + false + + + + + Level3 + NotUsing + MaxSpeed + true + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\..\libyara\include;..\..\..\cli;%(AdditionalIncludeDirectories) + CompileAsC + ProgramDatabase + MultiThreadedDLL + + + Console + No + true + true + ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) + ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) + false + + + + + + + + + + \ No newline at end of file From dc15092c9442b465a272afa021671027c39bfe38 Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Sun, 27 Jun 2021 18:46:22 +0100 Subject: [PATCH 10/16] Fix various uninitialised variables when scanning process memory --- libyara/modules/pe/pe.c | 30 ++++++++++++++++++++++++++++-- libyara/proc/windows.c | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/libyara/modules/pe/pe.c b/libyara/modules/pe/pe.c index b31baf1cbf..b98f1856a8 100644 --- a/libyara/modules/pe/pe.c +++ b/libyara/modules/pe/pe.c @@ -114,12 +114,16 @@ typedef int (*RESOURCE_CALLBACK_FUNC)( const IMAGE_RESOURCE_DIR_STRING_U* lang_string, void* cb_data); +#if defined(USE_WINDOWS_PROC) + YR_API YR_MEMORY_REGION* yr_process_fetch_memory_region_data( YR_MEMORY_BLOCK* block); YR_API void* yr_process_fetch_primary_module_base( YR_MEMORY_BLOCK_ITERATOR* iterator); +#endif + static size_t available_space(PE* pe, void* pointer) { if ((uint8_t*) pointer < pe->data) @@ -314,6 +318,7 @@ static void pe_parse_debug_directory(PE* pe) if (pe->memory) { + debug_dir = NULL; get_data_pointer_memory(pe, (debug_dir_offset + i * \ sizeof(IMAGE_DEBUG_DIRECTORY)), debug_dir, PIMAGE_DEBUG_DIRECTORY); if (debug_dir == NULL) break; @@ -348,6 +353,7 @@ static void pe_parse_debug_directory(PE* pe) PCV_HEADER cv_hdr; if (pe->memory) { + cv_hdr = NULL; get_data_pointer_memory(pe, pcv_hdr_offset, cv_hdr, PCV_HEADER); if (cv_hdr == NULL) continue; } @@ -641,8 +647,9 @@ static void pe_parse_version_info(PIMAGE_RESOURCE_DATA_ENTRY rsrc_data, PE* pe) if (pe->memory) { - get_data_pointer_memory(pe, version_info_offset, version_info, PVERSION_INFO); - if (version_info == NULL) return; + version_info = NULL; + get_data_pointer_memory(pe, version_info_offset, version_info, PVERSION_INFO); + if (version_info == NULL) return; } else version_info = (PVERSION_INFO) (pe->data + version_info_offset); @@ -841,6 +848,7 @@ static IMPORT_FUNCTION* pe_parse_import_descriptor( PIMAGE_THUNK_DATA64 thunks64; if (pe->memory) { + thunks64 = NULL; get_data_pointer_memory(pe, offset, thunks64, PIMAGE_THUNK_DATA64); if (thunks64 == NULL) return NULL; } @@ -865,6 +873,8 @@ static IMPORT_FUNCTION* pe_parse_import_descriptor( size_t imp_size; if (pe->memory) { + import = NULL; + imp_size = 0; get_data_pointer_memory_with_size(pe, offset, import, PIMAGE_IMPORT_BY_NAME, imp_size); if (import == NULL) continue; } @@ -925,6 +935,7 @@ static IMPORT_FUNCTION* pe_parse_import_descriptor( PIMAGE_THUNK_DATA32 thunks32; if (pe->memory) { + thunks32 = NULL; get_data_pointer_memory(pe, offset, thunks32, PIMAGE_THUNK_DATA32); if (thunks32 == NULL) return NULL; } @@ -949,6 +960,8 @@ static IMPORT_FUNCTION* pe_parse_import_descriptor( size_t imp_size; if (pe->memory) { + import = NULL; + imp_size = 0; get_data_pointer_memory_with_size(pe, offset, import, PIMAGE_IMPORT_BY_NAME, imp_size); if (import == NULL) continue; } @@ -1118,6 +1131,7 @@ static IMPORTED_DLL* pe_parse_imports(PE* pe) if (pe->memory) { + imports = NULL; get_data_pointer_memory(pe, offset, imports, PIMAGE_IMPORT_DESCRIPTOR); if (imports == NULL) return NULL; } @@ -1137,6 +1151,7 @@ static IMPORTED_DLL* pe_parse_imports(PE* pe) size_t dll_name_max; if (pe->memory) { + dll_name = NULL; get_data_pointer_memory_with_size(pe, offset, dll_name, char*, dll_name_max); if (dll_name == NULL) return NULL; } @@ -1532,6 +1547,7 @@ static void pe_parse_exports(PE* pe) if (pe->memory) { + exports = NULL; get_data_pointer_memory(pe, offset, exports, PIMAGE_EXPORT_DIRECTORY); if (exports == NULL) return; } @@ -1675,6 +1691,7 @@ static void pe_parse_exports(PE* pe) char* name; if (pe->memory) { + name = NULL; get_data_pointer_memory_with_size(pe, offset, name, char*, remaining); if (name == NULL) return; } @@ -4159,7 +4176,16 @@ int module_load( pe_parse_debug_directory(pe); #if defined(HAVE_LIBCRYPTO) && !defined(BORINGSSL) + + // Certificate data is stored in the PE overlay, outside the bounds + // of the mappable image. This is necessary otherwise signature verification + // algorithms would have to account for the presence of volatile certificate + // data within the image being verified. + // When an image is mapped into memory, the overlay is not included. As a + // result, it is not possible to extract PE signature information from a + // memory mapped image. if (!pe->memory) pe_parse_certificates(pe); + #endif pe->imported_dlls = pe_parse_imports(pe); diff --git a/libyara/proc/windows.c b/libyara/proc/windows.c index d87ce2981b..f3b35ed5f4 100644 --- a/libyara/proc/windows.c +++ b/libyara/proc/windows.c @@ -291,7 +291,19 @@ YR_API YR_MEMORY_REGION* yr_process_fetch_memory_region_data( return region; } - +// This function attempts to short circuit the discovery of a processes +// base module address using some internal windows functions and undocumented +// behaviors. +// Specifically, we are looking for an undocumented field in the partially +// documented PEB structure, ImageBaseAddress, which has been around +// since before NT 5.0. We also take advantage of the fact that calling +// NtQueryInformationProcess with the ProcessWow64Information information +// class will return the memory address of the processes 32 bit PEB or NULL +// if it is not a WOW64 process. ProcessWow64Information is officially +// documented only as returning a non-zero ULONG_PTR value when the process +// being queried is a WOW64 process, however, its implementation of returning +// the address of the 32 bit PEB has remained consistent since the information +// was first introduced. YR_API void* yr_process_fetch_primary_module_base( YR_MEMORY_BLOCK_ITERATOR* iterator) { @@ -307,9 +319,20 @@ YR_API void* yr_process_fetch_primary_module_base( #ifdef _WIN64 + // ProcessWow64Information is officially documented as returning + // zero if the process is not running under WOW64, otherwise it + // returns non-zero. + // In reality, it simply returns a the memory address of the + // processes 32 bit PEB structure if present, otherwise it returns + // NULL. We can use this to quickly get the WOW64 PEB and locate + // the ImageBaseAddress field. if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, ProcessWow64Information, &wow64, sizeof(wow64), &rlen)) && wow64) { + // Read the ImageBaseAddress pointer from the 32 bit WOW64 PEB. + // This field is undocumented but has been around since before + // NT 5.0. On 64 bit windows the filed is at offset 0x08 of the + // 32 bit PEB. if (ReadProcessMemory( proc_info->hProcess, (PVOID)((uint8_t*)wow64 + 0x8), @@ -325,6 +348,9 @@ YR_API void* yr_process_fetch_primary_module_base( if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &rlen)) && pbi.PebBaseAddress) { + // Read the ImageBaseAddress pointer from the PEB. This field is + // undocumented but has been around since before NT 5.0. On 64 bit + // windows the filed is at offset 0x10 of the PEB. if (ReadProcessMemory( proc_info->hProcess, (PVOID)((uint8_t*)pbi.PebBaseAddress + 0x10), @@ -339,10 +365,10 @@ YR_API void* yr_process_fetch_primary_module_base( #else - if (_IsWow64()) //The pointer is likely to be truncated when running - //under WOW64, so return NULL to force a brute force - //search unless the target process is also WOW64 + if (_IsWow64()) { + // Check to see if our target is also a WOW64 process. If it is, + // we can continue as if this were a 32 bit system. if (!NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, ProcessWow64Information, &wow64, sizeof(wow64), &rlen)) || !wow64) return NULL; @@ -351,6 +377,9 @@ YR_API void* yr_process_fetch_primary_module_base( if (NT_SUCCESS(NtQueryInformationProcess(proc_info->hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &rlen)) && pbi.PebBaseAddress) { + // Read the ImageBaseAddress pointer from the PEB. This field is + // undocumented but has been around since before NT 5.0. On 32 bit + // windows the filed is at offset 0x08 of the PEB. if (ReadProcessMemory( proc_info->hProcess, (PVOID)((uint8_t*)pbi.PebBaseAddress + 0x08), From 58b08a05c9e88112e347e92cf60063d15d1ed551 Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Sun, 27 Jun 2021 19:41:13 +0100 Subject: [PATCH 11/16] Set DLLs which are rarely used to delay load for better performance --- windows/vs2015/yara/yara.vcxproj | 4 ++++ windows/vs2017/yara/yara.vcxproj | 5 +++++ windows/vs2019/yara/yara.vcxproj | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/windows/vs2015/yara/yara.vcxproj b/windows/vs2015/yara/yara.vcxproj index fd5ca36a5e..89b590eb6a 100644 --- a/windows/vs2015/yara/yara.vcxproj +++ b/windows/vs2015/yara/yara.vcxproj @@ -104,6 +104,7 @@ ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll @@ -124,6 +125,7 @@ ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false Default + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll @@ -146,6 +148,7 @@ ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false No + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll false @@ -171,6 +174,7 @@ ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false No + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll diff --git a/windows/vs2017/yara/yara.vcxproj b/windows/vs2017/yara/yara.vcxproj index 453377b6f9..20eaf8b505 100644 --- a/windows/vs2017/yara/yara.vcxproj +++ b/windows/vs2017/yara/yara.vcxproj @@ -104,6 +104,7 @@ ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll @@ -124,6 +125,7 @@ ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false Default + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll @@ -146,6 +148,7 @@ ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false No + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll false @@ -171,10 +174,12 @@ ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false No + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll + diff --git a/windows/vs2019/yara/yara.vcxproj b/windows/vs2019/yara/yara.vcxproj index 17d761ce18..4d1fb7e8c7 100644 --- a/windows/vs2019/yara/yara.vcxproj +++ b/windows/vs2019/yara/yara.vcxproj @@ -104,6 +104,7 @@ ws2_32.lib;crypt32.lib;libyara$(PlatformArchitecture).lib;%(AdditionalDependencies) ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll @@ -124,6 +125,7 @@ ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false Default + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll @@ -146,6 +148,7 @@ ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false No + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll false @@ -171,6 +174,7 @@ ..\libyara\$(Configuration);%(AdditionalLibraryDirectories) false No + crypt32.dll;ws2_32.dll;bcrypt.dll;advapi32.dll;user32.dll From 3ae5bdab16f0c8731a9acb47cd49da67cc7f22ec Mon Sep 17 00:00:00 2001 From: Niall A Newman Date: Thu, 1 Jul 2021 20:46:33 +0100 Subject: [PATCH 12/16] Fix issue where certificate subject and issuer are truncated * The X509_NAME_oneline function was being used to extract the certificate issuer and subject. The function is being provided a static buffer which is only 254 chars in size, meaning that if either string is larger they will be truncated and essential information may be lost. * Increasing the buffer size or using a dynamic buffer could solve the issue, however the X509_NAME_oneline function is deprecated and its use is strongly discouraged. Instead, the issue can be fixed using the newer X509_NAME_print_ex function which will output the full string in a standard format. * Unicode data is escaped in the output string by default, so ASN1_STRFLGS_ESC_MSB is explicitly cleared to force the output of UTF8 encoded data. This allows matching unicode byte sequences in a more natural and expected manner. * This change has the side effect of addressing VirusTotal/yara#1392 --- libyara/modules/pe/pe.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/libyara/modules/pe/pe.c b/libyara/modules/pe/pe.c index b98f1856a8..b4ea128879 100644 --- a/libyara/modules/pe/pe.c +++ b/libyara/modules/pe/pe.c @@ -1776,6 +1776,8 @@ void _parse_pkcs7(PE* pe, PKCS7* pkcs7, int* counter) unsigned char thumbprint[YR_SHA1_LEN]; char thumbprint_ascii[YR_SHA1_LEN * 2 + 1]; + BIO* out = NULL; + BUF_MEM* buf; PKCS7_SIGNER_INFO* signer_info = NULL; PKCS7* nested_pkcs7 = NULL; ASN1_INTEGER* serial = NULL; @@ -1809,13 +1811,34 @@ void _parse_pkcs7(PE* pe, PKCS7* pkcs7, int* counter) "signatures[%i].thumbprint", *counter); - X509_NAME_oneline(X509_get_issuer_name(cert), buffer, sizeof(buffer)); - - set_string(buffer, pe->object, "signatures[%i].issuer", *counter); - - X509_NAME_oneline(X509_get_subject_name(cert), buffer, sizeof(buffer)); + if ((out = BIO_new(BIO_s_mem())) && + X509_NAME_print_ex( + out, + X509_get_issuer_name(cert), + 0, + XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB)) + { + BIO_write(out, "\0", 1); + BIO_get_mem_ptr(out, &buf); + set_string(buf->data, pe->object, "signatures[%i].issuer", *counter); + } + + if (out) BIO_free(out); + out = NULL; + + if ((out = BIO_new(BIO_s_mem())) && + X509_NAME_print_ex( + out, + X509_get_subject_name(cert), + 0, + XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB)) + { + BIO_write(out, "\0", 1); + BIO_get_mem_ptr(out, &buf); + set_string(buf->data, pe->object, "signatures[%i].subject", *counter); + } - set_string(buffer, pe->object, "signatures[%i].subject", *counter); + if (out) BIO_free(out); set_integer( X509_get_version(cert) + 1, // Versions are zero based, so add one. From 1046b5f10ba211bb3eabb6acd4932cc728d4e53e Mon Sep 17 00:00:00 2001 From: Niall Newman Date: Thu, 24 Feb 2022 16:45:37 +0000 Subject: [PATCH 13/16] Updated vs2019 project for new console module --- windows/vs2019/libyara/libyara.vcxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/vs2019/libyara/libyara.vcxproj b/windows/vs2019/libyara/libyara.vcxproj index eb4c10c0c8..4d2a57ec09 100644 --- a/windows/vs2019/libyara/libyara.vcxproj +++ b/windows/vs2019/libyara/libyara.vcxproj @@ -237,6 +237,7 @@ + From 6617f766db27c9384c1ea46eedee282d0b49410f Mon Sep 17 00:00:00 2001 From: Niall Newman Date: Thu, 24 Feb 2022 16:51:18 +0000 Subject: [PATCH 14/16] Switch from MultiByte to Unicode builds --- windows/vs2017/yara/yara.vcxproj | 8 ++++---- windows/vs2019/yara/yara.vcxproj | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/windows/vs2017/yara/yara.vcxproj b/windows/vs2017/yara/yara.vcxproj index 20eaf8b505..4a16d0fcc5 100644 --- a/windows/vs2017/yara/yara.vcxproj +++ b/windows/vs2017/yara/yara.vcxproj @@ -28,13 +28,13 @@ Application true - MultiByte + Unicode v141 Application true - MultiByte + Unicode true v141 @@ -42,14 +42,14 @@ Application false true - MultiByte + Unicode v141 Application false true - MultiByte + Unicode v141 diff --git a/windows/vs2019/yara/yara.vcxproj b/windows/vs2019/yara/yara.vcxproj index 4d1fb7e8c7..80350ced61 100644 --- a/windows/vs2019/yara/yara.vcxproj +++ b/windows/vs2019/yara/yara.vcxproj @@ -28,13 +28,13 @@ Application true - MultiByte + Unicode v142 Application true - MultiByte + Unicode true v142 @@ -42,14 +42,14 @@ Application false true - MultiByte + Unicode v142 Application false true - MultiByte + Unicode v142 From c0b0b7754f0eeb56aca75b615141d5ca345e579f Mon Sep 17 00:00:00 2001 From: Niall Newman Date: Thu, 24 Feb 2022 16:57:47 +0000 Subject: [PATCH 15/16] Fix build error due to use of windows typedef --- libyara/modules/pe/pe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libyara/modules/pe/pe.c b/libyara/modules/pe/pe.c index b4ea128879..e47bfcc8e0 100644 --- a/libyara/modules/pe/pe.c +++ b/libyara/modules/pe/pe.c @@ -4108,7 +4108,7 @@ int module_load( set_integer(0, module_object, "is_pe"); - PVOID base = NULL; + void* base = ((void *)0); #if defined(USE_WINDOWS_PROC) From 18dbd48586b2ddafe1d2f93daf8b9993edeec230 Mon Sep 17 00:00:00 2001 From: Niall Newman Date: Fri, 25 Feb 2022 09:21:10 +0000 Subject: [PATCH 16/16] Attempt to fix issues with CI build --- configure.ac | 1 + libyara/modules/pe/pe.c | 4 ++-- tests/test-pe.c | 2 +- windows/vs2015/libyara/libyara.vcxproj | 10 +++++----- windows/vs2017/libyara/libyara.vcxproj | 2 +- windows/vs2019/libyara/libyara.vcxproj | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 8df0c8f0c1..9d63d64bb3 100644 --- a/configure.ac +++ b/configure.ac @@ -52,6 +52,7 @@ case $host_os in proc_interface=mach jemalloc_prefix=je_ ;; mingw*|cygwin*) CFLAGS="$CFLAGS -DUSE_WINDOWS_PROC" + LDFLAGS="$LDFLAGS -lntdll" proc_interface=windows jemalloc_prefix= ;; linux*|netbsd*|dragonfly*|kfreebsd*) diff --git a/libyara/modules/pe/pe.c b/libyara/modules/pe/pe.c index e47bfcc8e0..2a5e725f0a 100644 --- a/libyara/modules/pe/pe.c +++ b/libyara/modules/pe/pe.c @@ -1569,7 +1569,7 @@ static void pe_parse_exports(PE* pe) if (offset > 0) { remaining = pe->data_size - (size_t) offset; - char* name; + char* name = NULL; if (pe->memory) { get_data_pointer_memory(pe, offset, name, char*); @@ -1723,7 +1723,7 @@ static void pe_parse_exports(PE* pe) if (offset > 0) { - char* name; + char* name = NULL; if (pe->memory) { get_data_pointer_memory_with_size(pe, offset, name, char*, remaining); diff --git a/tests/test-pe.c b/tests/test-pe.c index a33652b7be..4d588eacf8 100644 --- a/tests/test-pe.c +++ b/tests/test-pe.c @@ -324,7 +324,7 @@ int main(int argc, char** argv) condition: \ pe.number_of_signatures == 1 and \ pe.signatures[0].thumbprint == \"c1bf1b8f751bf97626ed77f755f0a393106f2454\" and \ - pe.signatures[0].subject == \"/C=US/ST=California/L=Menlo Park/O=Quicken, Inc./OU=Operations/CN=Quicken, Inc.\" \ + pe.signatures[0].subject == \"C = US, ST = California, L = Menlo Park, O = \"Quicken, Inc.\", OU = Operations, CN = \"Quicken, Inc.\"\" \ }", "tests/data/" "079a472d22290a94ebb212aa8015cdc8dd28a968c6b4d3b88acdd58ce2d3b885"); diff --git a/windows/vs2015/libyara/libyara.vcxproj b/windows/vs2015/libyara/libyara.vcxproj index 48dd401543..5a63e07ccc 100644 --- a/windows/vs2015/libyara/libyara.vcxproj +++ b/windows/vs2015/libyara/libyara.vcxproj @@ -100,7 +100,7 @@ $(OutDir)$(TargetName)$(TargetExt) - jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true MachineX86 ..\packages\YARA.OpenSSL.x86.1.1.1\lib;..\packages\YARA.Jansson.x86.1.1.0\lib;%(AdditionalLibraryDirectories) @@ -128,7 +128,7 @@ $(OutDir)$(TargetName)$(TargetExt) - crypt32.lib;ws2_32.lib;advapi32.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.lib;crypt32.lib;ws2_32.lib;advapi32.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true ..\packages\YARA.OpenSSL.x64.1.1.1\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) /IGNORE:4221 @@ -152,7 +152,7 @@ MultiThreadedDLL - jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true MachineX86 ..\packages\YARA.OpenSSL.x86.1.1.1\lib;..\packages\YARA.Jansson.x86.1.1.0\lib;%(AdditionalLibraryDirectories) @@ -178,7 +178,7 @@ MultiThreadedDLL - jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true false ..\packages\YARA.OpenSSL.x64.1.1.1\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) @@ -205,7 +205,7 @@ MultiThreaded - jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true false ..\packages\YARA.OpenSSL.x64.1.1.0\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) diff --git a/windows/vs2017/libyara/libyara.vcxproj b/windows/vs2017/libyara/libyara.vcxproj index e68410c010..a4fbd65522 100644 --- a/windows/vs2017/libyara/libyara.vcxproj +++ b/windows/vs2017/libyara/libyara.vcxproj @@ -204,7 +204,7 @@ MultiThreaded - jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true false ..\packages\YARA.OpenSSL.x64.1.1.1\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories) diff --git a/windows/vs2019/libyara/libyara.vcxproj b/windows/vs2019/libyara/libyara.vcxproj index 4d2a57ec09..b3c16817d4 100644 --- a/windows/vs2019/libyara/libyara.vcxproj +++ b/windows/vs2019/libyara/libyara.vcxproj @@ -204,7 +204,7 @@ MultiThreaded - jansson.lib;libcrypto.lib;%(AdditionalDependencies) + ntdll.lib;jansson.lib;libcrypto.lib;%(AdditionalDependencies) true false ..\packages\YARA.OpenSSL.x64.1.1.1\lib;..\packages\YARA.Jansson.x64.1.1.0\lib;%(AdditionalLibraryDirectories)