diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index e99feeef76..3150dfc9e0 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2489,43 +2489,67 @@ type irc_join_info: record { ## .. bro:see:: irc_join_message type irc_join_list: set[irc_join_info]; -type PEHeader: record { -# Machine : count; -# TimeDateStamp : time; -# magic : uint16; -# major_linker_version : uint8; -# minor_linker_version : uint8; -# size_of_code : uint32; -# size_of_init_data : uint32; -# size_of_uninit_data : uint32; -# addr_of_entry_point : uint32; -# base_of_code : uint32; -# base_of_data : uint32; -# image_base : uint32; -# section_alignment : uint32; -# file_alignment : uint32; -# os_version_major : uint16; -# os_version_minor : uint16; -# major_image_version : uint16; -# minor_image_version : uint16; -# major_subsys_version : uint16; -# minor_subsys_version : uint16; -# win32_version : uint32; -# size_of_image : uint32; -# checksum : uint32; -# subsystem : uint16; -# mem: case magic of { -# 0x0b01 -> i32 : MEM_INFO32; -# 0x0b02 -> i64 : MEM_INFO64; -# default -> InvalidPEFile : empty; -# }; -# loader_flags : uint32; -# number_of_rva_and_sizes : uint32; -# +module PE; +export { +type PE::DOSHeader: record { + signature : string; + used_bytes_in_last_page : count; + file_in_pages : count; + num_reloc_items : count; + header_in_paragraphs : count; + min_extra_paragraphs : count; + max_extra_paragraphs : count; + init_relative_ss : count; + init_sp : count; + checksum : count; + init_ip : count; + init_relative_cs : count; + addr_of_reloc_table : count; + overlay_num : count; + oem_id : count; + oem_info : count; + addr_of_new_exe_header : count; +}; + +type PE::FileHeader: record { + machine : count; + ts : time; + sym_table_ptr : count; + num_syms : count; + characteristics : set[count]; +}; + +type PE::OptionalHeader: record { + magic : count; + major_linker_version : count; + minor_linker_version : count; + size_of_code : count; + size_of_init_data : count; + size_of_uninit_data : count; + addr_of_entry_point : count; + base_of_code : count; + base_of_data : count; + image_base : count; + section_alignment : count; + file_alignment : count; + os_version_major : count; + os_version_minor : count; + major_image_version : count; + minor_image_version : count; + major_subsys_version : count; + minor_subsys_version : count; + win32_version : count; + size_of_image : count; + size_of_headers : count; + checksum : count; + subsystem : count; + dll_characteristics : set[count]; + loader_flags : count; + number_of_rva_and_sizes : count; }; ## Record for Portable Executable (PE) section headers. -type PESectionHeader: record { +type PE::SectionHeader: record { name : string; virtual_size : count; virtual_addr : count; @@ -2535,8 +2559,10 @@ type PESectionHeader: record { non_used_ptr_to_line_nums : count; non_used_num_of_relocs : count; non_used_num_of_line_nums : count; - characteristics : count; + characteristics : set[count]; }; +} +module GLOBAL; ## Deprecated. ## diff --git a/scripts/base/init-default.bro b/scripts/base/init-default.bro index 8b36899f10..ad66ab469b 100644 --- a/scripts/base/init-default.bro +++ b/scripts/base/init-default.bro @@ -44,4 +44,6 @@ @load base/protocols/ssl @load base/protocols/syslog +@load base/files/pe + @load base/misc/find-checksum-offloading diff --git a/src/event.bif b/src/event.bif index 7a99c20e37..30b3191734 100644 --- a/src/event.bif +++ b/src/event.bif @@ -7059,10 +7059,10 @@ event file_state_remove%(f: fa_file%); event file_hash%(f: fa_file, kind: string, hash: string%); -event file_pe_dosstub%(f: fa_file, checksum: count%); -event file_pe_timestamp%(f: fa_file, ts: time%); -event file_pe_section_header%(f: fa_file, h: PESectionHeader%); - +event pe_dos_header%(f: fa_file, h: PE::DOSHeader%); +event pe_file_header%(f: fa_file, h: PE::FileHeader%); +event pe_optional_header%(f: fa_file, h: PE::OptionalHeader%); +event pe_section_header%(f: fa_file, h: PE::SectionHeader%); ## Deprecated. Will be removed. event stp_create_endp%(c: connection, e: int, is_orig: bool%); diff --git a/src/file_analysis/analyzers/PE.cc b/src/file_analysis/analyzers/PE.cc index 662ea1f3e4..51db8fd232 100644 --- a/src/file_analysis/analyzers/PE.cc +++ b/src/file_analysis/analyzers/PE.cc @@ -41,7 +41,5 @@ bool PE::DeliverStream(const u_char* data, uint64 len) bool PE::EndOfFile() { - printf("end of file!\n"); - //throw binpac::HaltParser(); return false; } diff --git a/src/file_analysis/analyzers/pe-analyzer.pac b/src/file_analysis/analyzers/pe-analyzer.pac index fdba29a5bb..e6a39ae1dc 100644 --- a/src/file_analysis/analyzers/pe-analyzer.pac +++ b/src/file_analysis/analyzers/pe-analyzer.pac @@ -13,40 +13,156 @@ refine flow File += { return true; %} + function characteristics_to_bro(c: uint32, len: uint8): TableVal + %{ + uint64 mask = (len==16) ? 0xFFFF : 0xFFFFFFFF; + TableVal* char_set = new TableVal(internal_type("count_set")->AsTableType()); + for ( uint16 i=0; i < len; ++i ) + { + if ( ((c >> i) & 0x1) == 1 ) + { + Val *ch = new Val((1<Assign(ch, 0); + Unref(ch); + } + } + return char_set; + %} + function proc_dos_header(h: DOS_Header): bool %{ - BifEvent::generate_file_pe_dosstub((Analyzer *) connection()->bro_analyzer(), - connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), - ${h.AddressOfNewExeHeader}-64); + if ( pe_dos_header ) + { + RecordVal* dh = new RecordVal(BifType::Record::PE::DOSHeader); + dh->Assign(0, new StringVal(${h.signature}.length(), (const char*) ${h.signature}.data())); + dh->Assign(1, new Val(${h.UsedBytesInTheLastPage}, TYPE_COUNT)); + dh->Assign(2, new Val(${h.FileSizeInPages}, TYPE_COUNT)); + dh->Assign(3, new Val(${h.NumberOfRelocationItems}, TYPE_COUNT)); + dh->Assign(4, new Val(${h.HeaderSizeInParagraphs}, TYPE_COUNT)); + dh->Assign(5, new Val(${h.MinimumExtraParagraphs}, TYPE_COUNT)); + dh->Assign(6, new Val(${h.MaximumExtraParagraphs}, TYPE_COUNT)); + dh->Assign(7, new Val(${h.InitialRelativeSS}, TYPE_COUNT)); + dh->Assign(8, new Val(${h.InitialSP}, TYPE_COUNT)); + dh->Assign(9, new Val(${h.Checksum}, TYPE_COUNT)); + dh->Assign(10, new Val(${h.InitialIP}, TYPE_COUNT)); + dh->Assign(11, new Val(${h.InitialRelativeCS}, TYPE_COUNT)); + dh->Assign(12, new Val(${h.AddressOfRelocationTable}, TYPE_COUNT)); + dh->Assign(13, new Val(${h.OverlayNumber}, TYPE_COUNT)); + dh->Assign(14, new Val(${h.OEMid}, TYPE_COUNT)); + dh->Assign(15, new Val(${h.OEMinfo}, TYPE_COUNT)); + dh->Assign(16, new Val(${h.AddressOfNewExeHeader}, TYPE_COUNT)); + + BifEvent::generate_pe_dos_header((Analyzer *) connection()->bro_analyzer(), + connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), + dh); + } return true; %} - function proc_pe_header(h: IMAGE_NT_HEADERS): bool + function proc_nt_headers(h: IMAGE_NT_HEADERS): bool %{ - BifEvent::generate_file_pe_timestamp((Analyzer *) connection()->bro_analyzer(), - connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), - ${h.file_header.TimeDateStamp}); + if ( ${h.PESignature} != 17744 ) // Number is uint32 version of "PE\0\0" + { + return false; + // FileViolation("PE Header signature is incorrect."); + } return true; %} + function proc_file_header(h: IMAGE_FILE_HEADER): bool + %{ + if ( pe_file_header ) + { + RecordVal* fh = new RecordVal(BifType::Record::PE::FileHeader); + fh->Assign(0, new Val(${h.Machine}, TYPE_COUNT)); + fh->Assign(1, new Val(static_cast(${h.TimeDateStamp}), TYPE_TIME)); + fh->Assign(2, new Val(${h.PointerToSymbolTable}, TYPE_COUNT)); + fh->Assign(3, new Val(${h.NumberOfSymbols}, TYPE_COUNT)); + fh->Assign(4, characteristics_to_bro(${h.Characteristics}, 16)); + BifEvent::generate_pe_file_header((Analyzer *) connection()->bro_analyzer(), + connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), + fh); + } + + return true; + %} + + function proc_optional_header(h: IMAGE_OPTIONAL_HEADER): bool + %{ + if ( ${h.magic} != 0x10b && // normal pe32 executable + ${h.magic} != 0x107 && // rom image + ${h.magic} != 0x20b ) // pe32+ executable + { + return false; + // FileViolation("PE Optional Header magic is invalid."); + } + + if ( pe_optional_header ) + { + RecordVal* oh = new RecordVal(BifType::Record::PE::OptionalHeader); + + oh->Assign(0, new Val(${h.magic}, TYPE_COUNT)); + oh->Assign(1, new Val(${h.major_linker_version}, TYPE_COUNT)); + oh->Assign(2, new Val(${h.minor_linker_version}, TYPE_COUNT)); + oh->Assign(3, new Val(${h.size_of_code}, TYPE_COUNT)); + oh->Assign(4, new Val(${h.size_of_init_data}, TYPE_COUNT)); + oh->Assign(5, new Val(${h.size_of_uninit_data}, TYPE_COUNT)); + oh->Assign(6, new Val(${h.addr_of_entry_point}, TYPE_COUNT)); + oh->Assign(7, new Val(${h.base_of_code}, TYPE_COUNT)); + oh->Assign(8, new Val(${h.base_of_data}, TYPE_COUNT)); + oh->Assign(9, new Val(${h.image_base}, TYPE_COUNT)); + oh->Assign(10, new Val(${h.section_alignment}, TYPE_COUNT)); + oh->Assign(11, new Val(${h.file_alignment}, TYPE_COUNT)); + oh->Assign(12, new Val(${h.os_version_major}, TYPE_COUNT)); + oh->Assign(13, new Val(${h.os_version_minor}, TYPE_COUNT)); + oh->Assign(14, new Val(${h.major_image_version}, TYPE_COUNT)); + oh->Assign(15, new Val(${h.minor_image_version}, TYPE_COUNT)); + oh->Assign(16, new Val(${h.minor_subsys_version}, TYPE_COUNT)); + oh->Assign(17, new Val(${h.minor_subsys_version}, TYPE_COUNT)); + oh->Assign(18, new Val(${h.win32_version}, TYPE_COUNT)); + oh->Assign(19, new Val(${h.size_of_image}, TYPE_COUNT)); + oh->Assign(20, new Val(${h.size_of_headers}, TYPE_COUNT)); + oh->Assign(21, new Val(${h.checksum}, TYPE_COUNT)); + oh->Assign(22, new Val(${h.subsystem}, TYPE_COUNT)); + oh->Assign(23, characteristics_to_bro(${h.dll_characteristics}, 16)); + oh->Assign(24, new Val(${h.loader_flags}, TYPE_COUNT)); + oh->Assign(25, new Val(${h.number_of_rva_and_sizes}, TYPE_COUNT)); + BifEvent::generate_pe_optional_header((Analyzer *) connection()->bro_analyzer(), + connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), + oh); + } + return true; + %} function proc_section_header(h: IMAGE_SECTION_HEADER): bool %{ - RecordVal* section_header = new RecordVal(BifType::Record::PESectionHeader); - section_header->Assign(0, new StringVal(${h.name}.length(), (const char*) ${h.name}.data())); - section_header->Assign(1, new Val(${h.virtual_size}, TYPE_COUNT)); - section_header->Assign(2, new Val(${h.virtual_addr}, TYPE_COUNT)); - section_header->Assign(3, new Val(${h.size_of_raw_data}, TYPE_COUNT)); - section_header->Assign(4, new Val(${h.ptr_to_raw_data}, TYPE_COUNT)); - section_header->Assign(5, new Val(${h.non_used_ptr_to_relocs}, TYPE_COUNT)); - section_header->Assign(6, new Val(${h.non_used_ptr_to_line_nums}, TYPE_COUNT)); - section_header->Assign(7, new Val(${h.non_used_num_of_relocs}, TYPE_COUNT)); - section_header->Assign(8, new Val(${h.non_used_num_of_line_nums}, TYPE_COUNT)); - section_header->Assign(9, new Val(${h.characteristics}, TYPE_COUNT)); + if ( pe_section_header ) + { + RecordVal* section_header = new RecordVal(BifType::Record::PE::SectionHeader); - BifEvent::generate_file_pe_section_header((Analyzer *) connection()->bro_analyzer(), - connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), - section_header); + // Strip null characters from the end of the section name. + u_char* first_null = (u_char*) memchr(${h.name}.data(), 0, ${h.name}.length()); + uint16 name_len; + if ( first_null == NULL ) + name_len = ${h.name}.length(); + else + name_len = first_null - ${h.name}.data(); + section_header->Assign(0, new StringVal(name_len, (const char*) ${h.name}.data())); + + section_header->Assign(1, new Val(${h.virtual_size}, TYPE_COUNT)); + section_header->Assign(2, new Val(${h.virtual_addr}, TYPE_COUNT)); + section_header->Assign(3, new Val(${h.size_of_raw_data}, TYPE_COUNT)); + section_header->Assign(4, new Val(${h.ptr_to_raw_data}, TYPE_COUNT)); + section_header->Assign(5, new Val(${h.non_used_ptr_to_relocs}, TYPE_COUNT)); + section_header->Assign(6, new Val(${h.non_used_ptr_to_line_nums}, TYPE_COUNT)); + section_header->Assign(7, new Val(${h.non_used_num_of_relocs}, TYPE_COUNT)); + section_header->Assign(8, new Val(${h.non_used_num_of_line_nums}, TYPE_COUNT)); + section_header->Assign(9, characteristics_to_bro(${h.characteristics}, 32)); + + BifEvent::generate_pe_section_header((Analyzer *) connection()->bro_analyzer(), + connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), + section_header); + } return true; %} }; @@ -56,7 +172,15 @@ refine typeattr DOS_Header += &let { }; refine typeattr IMAGE_NT_HEADERS += &let { - proc : bool = $context.flow.proc_pe_header(this); + proc : bool = $context.flow.proc_nt_headers(this); +}; + +refine typeattr IMAGE_FILE_HEADER += &let { + proc : bool = $context.flow.proc_file_header(this); +}; + +refine typeattr IMAGE_OPTIONAL_HEADER += &let { + proc : bool = $context.flow.proc_optional_header(this); }; refine typeattr IMAGE_SECTION_HEADER += &let { diff --git a/src/file_analysis/analyzers/pe-file.pac b/src/file_analysis/analyzers/pe-file.pac index 84b26381b4..5c56775538 100644 --- a/src/file_analysis/analyzers/pe-file.pac +++ b/src/file_analysis/analyzers/pe-file.pac @@ -6,8 +6,10 @@ type TheFile = record { sections_table : IMAGE_SECTION_HEADER[] &length=pe_header.file_header.NumberOfSections*40 &transient; #pad : bytestring &length=offsetof(pe_header.data_directories + pe_header.data_directories[1].virtual_address); #data_sections : DATA_SECTIONS[pe_header.file_header.NumberOfSections]; + data_sections : DATA_SECTIONS[] &length=data_len; } &let { dos_code_len: uint32 = dos_header.AddressOfNewExeHeader - 64; + data_len: uint32 = pe_header.optional_header.size_of_init_data; } &byteorder=littleendian; type DOS_Header = record { @@ -33,10 +35,10 @@ type DOS_Header = record { } &byteorder=littleendian &length=64; type IMAGE_NT_HEADERS = record { - PESignature : uint32; - file_header : IMAGE_FILE_HEADER; - OptionalHeader : IMAGE_OPTIONAL_HEADER(file_header.SizeOfOptionalHeader); -} &byteorder=littleendian &length=file_header.SizeOfOptionalHeader+offsetof(OptionalHeader); + PESignature : uint32; + file_header : IMAGE_FILE_HEADER; + optional_header : IMAGE_OPTIONAL_HEADER(file_header.SizeOfOptionalHeader) &length=file_header.SizeOfOptionalHeader; +} &byteorder=littleendian &length=file_header.SizeOfOptionalHeader+offsetof(optional_header); type IMAGE_FILE_HEADER = record { Machine : uint16; @@ -124,5 +126,5 @@ type IMAGE_IMPORT_DIRECTORY = record { }; type DATA_SECTIONS = record { - blah: bytestring &length=10; + blah: uint8; }; \ No newline at end of file diff --git a/src/types.bif b/src/types.bif index ca84794865..f43abf9a81 100644 --- a/src/types.bif +++ b/src/types.bif @@ -163,8 +163,10 @@ type ModbusHeaders: record; type ModbusCoils: vector; type ModbusRegisters: vector; -type PEHeader: record; -type PESectionHeader: record; +type PE::DOSHeader: record; +type PE::FileHeader: record; +type PE::OptionalHeader: record; +type PE::SectionHeader: record; module Log;