From 7e15f19dcfb5153af8fbad88fde91acf89e5b62a Mon Sep 17 00:00:00 2001 From: Anton Cherepanov Date: Wed, 19 Feb 2020 22:44:59 +0100 Subject: [PATCH 1/3] Add check for reproducible build in PE module --- docs/modules/pe.rst | 7 +++++++ libyara/include/yara/pe.h | 6 ++++++ libyara/modules/pe/pe.c | 12 ++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/modules/pe.rst b/docs/modules/pe.rst index 2f53961ec0..335311434a 100644 --- a/docs/modules/pe.rst +++ b/docs/modules/pe.rst @@ -820,6 +820,13 @@ Reference Path of the PDB file for this PE if present. * Example: pe.pdb_path == "D:\\workspace\\2018_R9_RelBld\\target\\checkout\\custprof\\Release\\custprof.pdb" + +.. c:type:: is_reproducible_build + + .. versionadded:: 3.13.0 + + Value that indicates if the PE is build using compiler settings to achieve reproducibility. + .. c:function:: exports(function_name) diff --git a/libyara/include/yara/pe.h b/libyara/include/yara/pe.h index 8158be64c4..e6ee388441 100644 --- a/libyara/include/yara/pe.h +++ b/libyara/include/yara/pe.h @@ -465,7 +465,13 @@ typedef struct _IMAGE_RESOURCE_DIRECTORY { #define IMAGE_DEBUG_TYPE_MISC 4 #define IMAGE_DEBUG_TYPE_EXCEPTION 5 #define IMAGE_DEBUG_TYPE_FIXUP 6 +#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 +#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 #define IMAGE_DEBUG_TYPE_BORLAND 9 +#define IMAGE_DEBUG_TYPE_RESERVED10 10 +#define IMAGE_DEBUG_TYPE_CLSID 11 +#define IMAGE_DEBUG_TYPE_REPRO 16 +#define IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS 20 typedef struct _IMAGE_DEBUG_DIRECTORY { DWORD Characteristics; diff --git a/libyara/modules/pe/pe.c b/libyara/modules/pe/pe.c index 45f7ddde09..59e20d682e 100644 --- a/libyara/modules/pe/pe.c +++ b/libyara/modules/pe/pe.c @@ -291,6 +291,8 @@ static void pe_parse_debug_directory( size_t pdb_path_len; char* pdb_path = NULL; + set_integer(0, pe->object, "is_reproducible_build"); + data_dir = pe_get_directory_entry( pe, IMAGE_DIRECTORY_ENTRY_DEBUG); @@ -321,6 +323,12 @@ static void pe_parse_debug_directory( if (!struct_fits_in_pe(pe, debug_dir, IMAGE_DEBUG_DIRECTORY)) break; + + if (yr_le32toh(debug_dir->Type) == IMAGE_DEBUG_TYPE_REPRO) + { + set_integer(1, pe->object, "is_reproducible_build"); + continue; + } if (yr_le32toh(debug_dir->Type) != IMAGE_DEBUG_TYPE_CODEVIEW) continue; @@ -359,7 +367,6 @@ static void pe_parse_debug_directory( if (pdb_path_len > 0 && pdb_path_len < MAX_PATH) { set_sized_string(pdb_path, pdb_path_len, pe->object, "pdb_path"); - break; } } } @@ -2631,7 +2638,8 @@ begin_declarations; declare_integer("number_of_symbols"); declare_integer("size_of_optional_header"); declare_integer("characteristics"); - + declare_integer("is_reproducible_build"); + declare_integer("entry_point"); declare_integer("image_base"); declare_integer("number_of_rva_and_sizes"); From 3e1029e3e6ab8ba7e18c60cde390fd9f058835d7 Mon Sep 17 00:00:00 2001 From: Anton Cherepanov Date: Tue, 3 Mar 2020 10:08:32 +0100 Subject: [PATCH 2/3] Add test for is_reproducible_build --- tests/test-pe.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test-pe.c b/tests/test-pe.c index d33affa05b..1f97826a82 100644 --- a/tests/test-pe.c +++ b/tests/test-pe.c @@ -279,6 +279,14 @@ int main(int argc, char** argv) }", "tests/data/mtxex.dll"); + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.is_reproducible_build == 1 \ + }", + "tests/data/mtxex.dll"); + assert_true_rule_file( "import \"pe\" \ rule test { \ From d923c6e897fe7098ea1b357a5186252382c044c6 Mon Sep 17 00:00:00 2001 From: Anton Cherepanov Date: Fri, 10 Apr 2020 14:05:59 +0200 Subject: [PATCH 3/3] Additional improvements for is_reproducible_build Handle cases when the is_reproducible_build should be YR_UNDEFINED instead of 0 --- docs/modules/pe.rst | 2 +- libyara/modules/pe/pe.c | 25 ++++++++++++++----------- tests/test-pe.c | 8 ++++++++ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/docs/modules/pe.rst b/docs/modules/pe.rst index 88e45ff35b..4458014bbe 100644 --- a/docs/modules/pe.rst +++ b/docs/modules/pe.rst @@ -823,7 +823,7 @@ Reference .. c:type:: is_reproducible_build - .. versionadded:: 3.13.0 + .. versionadded:: 4.0.0 Value that indicates if the PE is build using compiler settings to achieve reproducibility. diff --git a/libyara/modules/pe/pe.c b/libyara/modules/pe/pe.c index 0c1c4a7312..0efab1b9fc 100644 --- a/libyara/modules/pe/pe.c +++ b/libyara/modules/pe/pe.c @@ -289,26 +289,24 @@ static void pe_parse_debug_directory( int64_t debug_dir_offset; int64_t pcv_hdr_offset; int i, dcount; + int repro = 0; size_t pdb_path_len; char* pdb_path = NULL; - set_integer(0, pe->object, "is_reproducible_build"); - data_dir = pe_get_directory_entry( pe, IMAGE_DIRECTORY_ENTRY_DEBUG); - if (data_dir == NULL) - return; - - if (yr_le32toh(data_dir->Size) == 0) - return; + if (data_dir == NULL || + yr_le32toh(data_dir->Size) == 0 || + yr_le32toh(data_dir->VirtualAddress) == 0) + { + set_integer(0, pe->object, "is_reproducible_build"); + return; + } if (yr_le32toh(data_dir->Size) % sizeof(IMAGE_DEBUG_DIRECTORY) != 0) return; - if (yr_le32toh(data_dir->VirtualAddress) == 0) - return; - debug_dir_offset = pe_rva_to_offset( pe, yr_le32toh(data_dir->VirtualAddress)); @@ -327,7 +325,7 @@ static void pe_parse_debug_directory( if (yr_le32toh(debug_dir->Type) == IMAGE_DEBUG_TYPE_REPRO) { - set_integer(1, pe->object, "is_reproducible_build"); + repro = 1; continue; } @@ -375,6 +373,11 @@ static void pe_parse_debug_directory( } } + if (repro == 1) + set_integer(1, pe->object, "is_reproducible_build"); + else if (i == dcount) + set_integer(0, pe->object, "is_reproducible_build"); + return; } diff --git a/tests/test-pe.c b/tests/test-pe.c index 1f97826a82..b9b0280d22 100644 --- a/tests/test-pe.c +++ b/tests/test-pe.c @@ -287,6 +287,14 @@ int main(int argc, char** argv) }", "tests/data/mtxex.dll"); + assert_true_rule_file( + "import \"pe\" \ + rule test { \ + condition: \ + pe.is_reproducible_build == 0 \ + }", + "tests/data/079a472d22290a94ebb212aa8015cdc8dd28a968c6b4d3b88acdd58ce2d3b885"); + assert_true_rule_file( "import \"pe\" \ rule test { \