diff --git a/scripts/base/files/pe/main.bro b/scripts/base/files/pe/main.bro index cb2004deff..bbe0846f04 100644 --- a/scripts/base/files/pe/main.bro +++ b/scripts/base/files/pe/main.bro @@ -29,10 +29,13 @@ export { section_names: vector of string &log &optional; }; - global set_file: hook(f: fa_file); } +redef record Info += { + confirmed: bool &default=F; +}; + redef record fa_file += { pe: Info &optional; }; @@ -75,6 +78,12 @@ event pe_file_header(f: fa_file, h: PE::FileHeader) &priority=5 event pe_optional_header(f: fa_file, h: PE::OptionalHeader) &priority=5 { hook set_file(f); + + if ( h$magic == 0x10b || h$magic == 0x20b ) + f$pe$confirmed = T; + else + return; + f$pe$os = os_versions[h$os_version_major, h$os_version_minor]; f$pe$subsystem = windows_subsystems[h$subsystem]; for ( c in h$dll_characteristics ) @@ -99,9 +108,9 @@ event pe_section_header(f: fa_file, h: PE::SectionHeader) &priority=5 f$pe$section_names[|f$pe$section_names|] = h$name; } -event file_state_remove(f: fa_file) +event file_state_remove(f: fa_file) &priority=-5 { - if ( f?$pe ) + if ( f?$pe && f$pe$confirmed ) Log::write(LOG, f$pe); } diff --git a/src/file_analysis/analyzer/pe/pe-analyzer.pac b/src/file_analysis/analyzer/pe/pe-analyzer.pac index 1baaf93947..1c61241684 100644 --- a/src/file_analysis/analyzer/pe/pe-analyzer.pac +++ b/src/file_analysis/analyzer/pe/pe-analyzer.pac @@ -98,8 +98,8 @@ refine flow File += { ${h.magic} != 0x107 && // rom image ${h.magic} != 0x20b ) // pe32+ executable { - return false; // FileViolation("PE Optional Header magic is invalid."); + return false; } if ( pe_optional_header ) @@ -173,24 +173,6 @@ refine flow File += { } return true; %} - - function proc_import_entry(module_name: bytestring, i: import_entry): bool - %{ - if ( pe_import_entry ) - { - StringVal* name; - if ( ${i.name}.length() > 1 ) - name = new StringVal(${i.name}.length() - 1, (const char*) ${i.name}.begin()); - else - name = new StringVal(0, (const char*) ${i.name}.begin()); - - BifEvent::generate_pe_import_entry((analyzer::Analyzer *) connection()->bro_analyzer(), - connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), - bytestring_to_val(${module_name}), - name); - } - return true; - %} }; refine typeattr DOS_Header += &let { @@ -216,7 +198,3 @@ refine typeattr Optional_Header += &let { refine typeattr Section_Header += &let { proc: bool = $context.flow.proc_section_header(this); }; - -refine typeattr import_entry += &let { - proc: bool = $context.flow.proc_import_entry($context.connection.get_module_name(), this) &if(!is_module); -}; diff --git a/src/file_analysis/analyzer/pe/pe-file-headers.pac b/src/file_analysis/analyzer/pe/pe-file-headers.pac index 05628917f4..adf0ce575d 100644 --- a/src/file_analysis/analyzer/pe/pe-file-headers.pac +++ b/src/file_analysis/analyzer/pe/pe-file-headers.pac @@ -136,9 +136,7 @@ refine connection MockConnection += { %{ if ( ${h.size_of_raw_data} + ${h.ptr_to_raw_data} > max_file_location_ ) max_file_location_ = ${h.size_of_raw_data} + ${h.ptr_to_raw_data}; - - if ( ${h.virtual_addr} > 0 && ${h.virtual_addr} <= import_table_rva_ && ( ${h.virtual_addr} + ${h.virtual_size} ) > import_table_rva_ ) - import_table_va_ = ${h.ptr_to_raw_data} + (import_table_rva_ - ${h.virtual_addr}); + return true; %} diff --git a/src/file_analysis/analyzer/pe/pe-file-idata.pac b/src/file_analysis/analyzer/pe/pe-file-idata.pac deleted file mode 100644 index d3ce2e9ffd..0000000000 --- a/src/file_analysis/analyzer/pe/pe-file-idata.pac +++ /dev/null @@ -1,171 +0,0 @@ -## Support for parsing the .idata section - -type import_directory = record { - rva_import_lookup_table : uint32; - time_date_stamp : uint32; - forwarder_chain : uint32; - rva_module_name : uint32; - rva_import_addr_table : uint32; -} &let { - is_null: bool = rva_module_name == 0; - proc: bool = $context.connection.proc_image_import_directory(this); -} &length=20; - -type import_lookup_attrs(pe32_format: uint8) = record { - is_pe32_plus: case pe32_format of { - PE32_PLUS -> attrs_64: uint64; - default -> attrs_32: uint32; - }; -} &let { - attrs: uint64 = (pe32_format == PE32_PLUS) ? attrs_64 : attrs_32; -} &length=(pe32_format == PE32_PLUS ? 8 : 4); - -type import_lookup_table = record { - attrs: import_lookup_attrs($context.connection.get_pe32_format())[] &until($element.attrs == 0); -} &let { - proc: bool = $context.connection.proc_import_lookup_table(this); -}; - -type import_entry(is_module: bool, pad_align: uint8) = record { - pad: bytestring &length=pad_align; - has_index: case is_module of { - true -> null: empty; - false -> index: uint16; - }; - name: null_terminated_string; -} &let { - proc_align: bool = $context.connection.proc_import_hint(name, is_module); -}; - -type idata = record { - directory_table : import_directory[] &until $element.is_null; - lookup_tables : import_lookup_table[] &until $context.connection.get_num_imports() <= 0; - hint_table : import_entry($context.connection.get_next_hint_type(), $context.connection.get_next_hint_align())[] &until($context.connection.imports_done()); -}; - -refine typeattr RVAS += &let { - proc: bool = $context.connection.proc_idata_rva(rvas[1]) &if (num > 1); -}; - -refine connection MockConnection += { - %member{ - uint8 num_imports_; // How many import tables will we have? - - uint32 import_table_rva_; // Used for finding the right section - uint32 import_table_va_; - uint32 import_table_len_; - - // We need to track the number of imports for each, to - // know when we've parsed them all. - vector imports_per_module_; - - // These are to determine the alignment of the import hints - uint32 next_hint_index_; - uint8 next_hint_align_; - bool next_hint_is_module_; - - // Track the module name, so we know what each import's for - bytestring module_name_; - %} - - %init{ - // It ends with a null import entry, so we'll set it to -1. - num_imports_ = -1; - - // First hint is a module name. - next_hint_is_module_ = true; - next_hint_index_ = 0; - next_hint_align_ = 0; - - module_name_ = bytestring(); - %} - - %cleanup{ - module_name_.free(); - %} - - # When we read the section header, store the relative virtual address and - # size of the .idata section, so we know when we get there. - function proc_idata_rva(r: RVA): bool - %{ - import_table_rva_ = ${r.virtual_address}; - import_table_len_ = ${r.size}; - - return true; - %} - - # Each import directory means another module we're importing from. - function proc_image_import_directory(i: import_directory): bool - %{ - num_imports_++; - return true; - %} - - # Store the number of functions imported in each module lookup table. - function proc_import_lookup_table(t: import_lookup_table): bool - %{ - --num_imports_; - imports_per_module_.push_back(${t.attrs}->size()); - return true; - %} - - # We need to calculate the length of the next padding field - function proc_import_hint(hint_name: bytestring, is_module: bool): bool - %{ - next_hint_align_ = ${hint_name}.length() % 2; - if ( is_module && ${hint_name}.length() > 1 ) - { - module_name_.clear(); - module_name_.init(${hint_name}.data(), ${hint_name}.length() - 1); - } - - return true; - %} - - # Functions have an index field, modules don't. Which one is this? - function get_next_hint_type(): bool - %{ - if ( next_hint_is_module_ ) - { - next_hint_is_module_ = false; - return true; - } - if ( --imports_per_module_[next_hint_index_] == 0) - { - ++next_hint_index_; - return true; - } - return false; - %} - - function imports_done(): bool - %{ - return next_hint_index_ == imports_per_module_.size(); - %} - - function get_module_name(): bytestring - %{ - return module_name_; - %} - - function get_import_table_addr(): uint32 - %{ - return import_table_va_ > 0 ? import_table_va_ : 0; - %} - - function get_import_table_len(): uint32 - %{ - return import_table_va_ > 0 ? import_table_len_ : 0; - %} - - function get_num_imports(): uint8 - %{ - return num_imports_; - %} - - function get_next_hint_align(): uint8 - %{ - return next_hint_align_; - %} - -}; \ No newline at end of file diff --git a/src/file_analysis/analyzer/pe/pe-file.pac b/src/file_analysis/analyzer/pe/pe-file.pac index 3d69256682..64902e9e9f 100644 --- a/src/file_analysis/analyzer/pe/pe-file.pac +++ b/src/file_analysis/analyzer/pe/pe-file.pac @@ -1,6 +1,5 @@ %include pe-file-types.pac %include pe-file-headers.pac -%include pe-file-idata.pac # The base record for a Portable Executable file type PE_File = case $context.connection.is_done() of { @@ -10,13 +9,10 @@ type PE_File = case $context.connection.is_done() of { type Portable_Executable = record { headers : Headers; - pad1 : Padding(iat_loc); - iat : idata &length=$context.connection.get_import_table_len(); - pad2 : Padding(restofdata); + pad : Padding(restofdata); } &let { unparsed_hdr_len: uint32 = headers.pe_header.optional_header.size_of_headers - headers.length; - iat_loc: uint64 = $context.connection.get_import_table_addr() - headers.pe_header.optional_header.size_of_headers + unparsed_hdr_len; - restofdata: uint64 = $context.connection.get_max_file_location() - $context.connection.get_import_table_addr() - $context.connection.get_import_table_len(); + restofdata: uint64 = $context.connection.get_max_file_location() - headers.pe_header.optional_header.size_of_headers + unparsed_hdr_len; proc: bool = $context.connection.proc_pe(this); } &byteorder=littleendian;