diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 7f4d29d26b..8a82fb98b3 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2486,6 +2486,20 @@ type irc_join_info: record { ## .. bro:see:: irc_join_message type irc_join_list: set[irc_join_info]; +## Record for Portable Executable (PE) section headers. +type PESectionHeader: record { + name : string; + virtual_size : count; + virtual_addr : count; + size_of_raw_data : count; + ptr_to_raw_data : count; + non_used_ptr_to_relocs : count; + non_used_ptr_to_line_nums : count; + non_used_num_of_relocs : count; + non_used_num_of_line_nums : count; + characteristics : count; +}; + ## Deprecated. ## ## .. todo:: Remove. It's still declared internally but doesn't seem used anywhere diff --git a/src/event.bif b/src/event.bif index 08a2b64a84..fc9ca8df6a 100644 --- a/src/event.bif +++ b/src/event.bif @@ -7026,6 +7026,12 @@ event file_state_remove%(f: fa_file%); ## FileAnalysis::ACTION_SHA1 FileAnalysis::ACTION_SHA256 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%); + + ## Deprecated. Will be removed. event stp_create_endp%(c: connection, e: int, is_orig: bool%); diff --git a/src/file_analysis.bif b/src/file_analysis.bif index f7fbe14de9..b3e34f93d2 100644 --- a/src/file_analysis.bif +++ b/src/file_analysis.bif @@ -97,10 +97,3 @@ function set_file_handle%(handle: string%): any file_mgr->SetHandle(handle->CheckString()); return 0; %} - -# Define file analysis framework events. - -#event FileAnalysis::windows_pe_dosstub%(fi: FileAnalysis::Info, sig: string, checksum: count%); -event FileAnalysis::windows_pe_dosstub%(checksum: count%); -event FileAnalysis::windows_pe_timestamp%(ts: time%); - diff --git a/src/file_analysis/ActionSet.cc b/src/file_analysis/ActionSet.cc index fd7fa883eb..d8d057bec5 100644 --- a/src/file_analysis/ActionSet.cc +++ b/src/file_analysis/ActionSet.cc @@ -17,7 +17,7 @@ static ActionInstantiator action_factory[] = { file_analysis::SHA256::Instantiate, file_analysis::DataEvent::Instantiate, - PE_Analyzer::Instantiate, + file_analysis::PE_Analyzer::Instantiate, }; static void action_del_func(void* v) diff --git a/src/file_analysis/analyzers/PE.cc b/src/file_analysis/analyzers/PE.cc index daf679ce82..c15b6ba739 100644 --- a/src/file_analysis/analyzers/PE.cc +++ b/src/file_analysis/analyzers/PE.cc @@ -3,14 +3,16 @@ #include "PE.h" #include "pe_pac.h" #include "util.h" +#include "Event.h" using namespace file_analysis; -PE_Analyzer::PE_Analyzer(RecordVal* args, Info* info) - : Action(args, info) +PE_Analyzer::PE_Analyzer(RecordVal* args, File* file) + : Action(args, file) { conn = new binpac::PE::MockConnection(this); interp = new binpac::PE::File(conn); + done=false; } PE_Analyzer::~PE_Analyzer() @@ -18,23 +20,21 @@ PE_Analyzer::~PE_Analyzer() delete interp; } -Action* PE_Analyzer::Instantiate(RecordVal* args, Info* info) +Action* PE_Analyzer::Instantiate(RecordVal* args, File* file) { - using BifType::Record::FileAnalysis::Info; - //const char* field = "total_bytes"; - //Val* filesize = info->GetVal()->Lookup(Info->FieldOffset(field)); - //if ( ! filesize ) - // // TODO: this should be a reporter message? or better yet stop relying on the file size. - // return 0; -// - //bro_uint_t fsize = filesize->AsCount(); - return new PE_Analyzer(args, info); + return new PE_Analyzer(args, file); } bool PE_Analyzer::DeliverStream(const u_char* data, uint64 len) { - Action::DeliverStream(data, len); + printf("deliver stream\n"); + if (done) + { + printf("analyzer done\n"); + return false; + } + Action::DeliverStream(data, len); try { interp->NewData(data, data + len); @@ -47,3 +47,10 @@ bool PE_Analyzer::DeliverStream(const u_char* data, uint64 len) return true; } + +bool PE_Analyzer::EndOfFile() + { + printf("end of file!\n"); + done=true; + return false; + } diff --git a/src/file_analysis/analyzers/PE.h b/src/file_analysis/analyzers/PE.h index 34a76e7e00..6f25e19723 100644 --- a/src/file_analysis/analyzers/PE.h +++ b/src/file_analysis/analyzers/PE.h @@ -4,7 +4,7 @@ #include #include "Val.h" -#include "../Info.h" +#include "../File.h" #include "pe_pac.h" namespace file_analysis { @@ -14,16 +14,19 @@ namespace file_analysis { */ class PE_Analyzer : Action { public: - static Action* Instantiate(RecordVal* args, Info* info); + static Action* Instantiate(RecordVal* args, File* file); ~PE_Analyzer(); virtual bool DeliverStream(const u_char* data, uint64 len); + virtual bool EndOfFile(); + protected: - PE_Analyzer(RecordVal* args, Info* info); + PE_Analyzer(RecordVal* args, File* file); binpac::PE::File* interp; binpac::PE::MockConnection* conn; + bool done; }; } // namespace file_analysis diff --git a/src/file_analysis/analyzers/pe-analyzer.pac b/src/file_analysis/analyzers/pe-analyzer.pac index d0407f348a..18efc1d54a 100644 --- a/src/file_analysis/analyzers/pe-analyzer.pac +++ b/src/file_analysis/analyzers/pe-analyzer.pac @@ -1,26 +1,55 @@ %extern{ #include "Event.h" +#include "file_analysis/File.h" #include "file_analysis.bif.func_h" %} refine flow File += { - function proc_dos_header(h: DOS_Header) : bool + function proc_the_file(): bool %{ - BifEvent::FileAnalysis::generate_windows_pe_dosstub((Analyzer *) connection()->bro_analyzer(), - //(Val *) connection()->bro_analyzer()->GetInfo(), - //new StringVal(${h.signature}.length(), (const char*) ${h.signature}.begin()), - ${h.AddressOfNewExeHeader}-64); + printf("ending the flow!\n"); + connection()->bro_analyzer()->EndOfFile(); + connection()->FlowEOF(true); + connection()->FlowEOF(false); return true; %} - function proc_pe_header(h: IMAGE_NT_HEADERS) : bool + function proc_dos_header(h: DOS_Header): bool %{ - BifEvent::FileAnalysis::generate_windows_pe_timestamp((Analyzer *) connection()->bro_analyzer(), - //(Val *) connection()->bro_analyzer()->GetInfo(), - //new StringVal(${h.signature}.length(), (const char*) ${h.signature}.begin()), - ${h.FileHeader.TimeDateStamp}); + BifEvent::generate_file_pe_dosstub((Analyzer *) connection()->bro_analyzer(), + connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), + ${h.AddressOfNewExeHeader}-64); + return true; + %} + + function proc_pe_header(h: IMAGE_NT_HEADERS): bool + %{ + BifEvent::generate_file_pe_timestamp((Analyzer *) connection()->bro_analyzer(), + connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), + ${h.file_header.TimeDateStamp}); + 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)); + + BifEvent::generate_file_pe_section_header((Analyzer *) connection()->bro_analyzer(), + connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), + section_header); return true; %} }; @@ -33,3 +62,10 @@ refine typeattr IMAGE_NT_HEADERS += &let { proc : bool = $context.flow.proc_pe_header(this); }; +refine typeattr IMAGE_SECTION_HEADER += &let { + proc: bool = $context.flow.proc_section_header(this); +}; + +refine typeattr TheFile += &let { + proc: bool = $context.flow.proc_the_file(); +}; \ No newline at end of file diff --git a/src/file_analysis/analyzers/pe-file.pac b/src/file_analysis/analyzers/pe-file.pac index 5854fd2bd8..bedfb35204 100644 --- a/src/file_analysis/analyzers/pe-file.pac +++ b/src/file_analysis/analyzers/pe-file.pac @@ -1,12 +1,15 @@ type TheFile = record { - dos_header : DOS_Header; - dos_code : bytestring &length=(dos_header.AddressOfNewExeHeader - 64); - pe_header : IMAGE_NT_HEADERS; - pad : bytestring &length=1316134912 &transient; + dos_header : DOS_Header; + dos_code : bytestring &length=dos_code_len; + pe_header : IMAGE_NT_HEADERS; + 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]; + #pad : bytestring &restofdata; } &let { - dos_code_len: uint32 = (dos_header.AddressOfNewExeHeader - 64); -} &transient &byteorder=littleendian; + dos_code_len: uint32 = dos_header.AddressOfNewExeHeader - 64; +} &byteorder=littleendian; type DOS_Header = record { signature : bytestring &length=2; @@ -32,9 +35,9 @@ type DOS_Header = record { type IMAGE_NT_HEADERS = record { PESignature : uint32; - FileHeader : IMAGE_FILE_HEADER; - OptionalHeader : OPTIONAL_HEADER(FileHeader.SizeOfOptionalHeader); -} &byteorder=littleendian &length=FileHeader.SizeOfOptionalHeader+offsetof(OptionalHeader); + file_header : IMAGE_FILE_HEADER; + OptionalHeader : IMAGE_OPTIONAL_HEADER(file_header.SizeOfOptionalHeader); +} &byteorder=littleendian &length=file_header.SizeOfOptionalHeader+offsetof(OptionalHeader); type IMAGE_FILE_HEADER = record { Machine : uint16; @@ -46,16 +49,8 @@ type IMAGE_FILE_HEADER = record { Characteristics : uint16; }; -type OPTIONAL_HEADER(len: uint16) = record { - OptionalHeaderMagic : uint16; - Header : case OptionalHeaderMagic of { - 0x0b01 -> OptionalHeader32 : IMAGE_OPTIONAL_HEADER32; - 0x0b02 -> OptionalHeader64 : IMAGE_OPTIONAL_HEADER64; - default -> InvalidPEFile : bytestring &restofdata; - }; -} &length=len; - -type IMAGE_OPTIONAL_HEADER32 = record { +type IMAGE_OPTIONAL_HEADER(len: uint16) = record { + magic : uint16; major_linker_version : uint8; minor_linker_version : uint8; size_of_code : uint32; @@ -79,14 +74,56 @@ type IMAGE_OPTIONAL_HEADER32 = record { checksum : uint32; subsystem : uint16; dll_characteristics : uint16; - size_of_stack_reserve : uint32; - size_of_stack_commit : uint32; - size_of_heap_reserve : uint32; - size_of_heap_commit : uint32; + mem: case magic of { + 0x0b01 -> i32 : MEM_INFO32; + 0x0b02 -> i64 : MEM_INFO64; + default -> InvalidPEFile : bytestring &length=0; + }; loader_flags : uint32; number_of_rva_and_sizes : uint32; -} &byteorder=littleendian; +} &byteorder=littleendian &length=len; -type IMAGE_OPTIONAL_HEADER64 = record { +type MEM_INFO32 = record { + size_of_stack_reserve : uint32; + size_of_stack_commit : uint32; + size_of_heap_reserve : uint32; + size_of_heap_commit : uint32; +} &byteorder=littleendian &length=16; -} &byteorder=littleendian; +type MEM_INFO64 = record { + size_of_stack_reserve : uint64; + size_of_stack_commit : uint64; + size_of_heap_reserve : uint64; + size_of_heap_commit : uint64; +} &byteorder=littleendian &length=32; + +type IMAGE_SECTION_HEADER = record { + name : bytestring &length=8; + virtual_size : uint32; + virtual_addr : uint32; + size_of_raw_data : uint32; + ptr_to_raw_data : uint32; + non_used_ptr_to_relocs : uint32; + non_used_ptr_to_line_nums : uint32; + non_used_num_of_relocs : uint16; + non_used_num_of_line_nums : uint16; + characteristics : uint32; +} &byteorder=littleendian &length=40; + + +type IMAGE_DATA_DIRECTORY = record { + virtual_address : uint32; + size : uint16; +}; + +type IMAGE_IMPORT_DIRECTORY = record { + rva_import_lookup_table : uint32; + time_date_stamp : uint32; + forwarder_chain : uint32; + rva_module_name : uint32; + rva_import_addr_table : uint32; +}; + +type DATA_SECTIONS = record { + blah: bytestring &length=10; +}; \ No newline at end of file diff --git a/src/types.bif b/src/types.bif index b69239487b..4999e221e5 100644 --- a/src/types.bif +++ b/src/types.bif @@ -163,6 +163,8 @@ type ModbusHeaders: record; type ModbusCoils: vector; type ModbusRegisters: vector; +type PESectionHeader: record; + module Log; enum Writer %{ @@ -248,6 +250,9 @@ enum Action %{ ## Deliver the file contents to the script-layer in an event. ACTION_DATA_EVENT, + + ## Windows executable analyzer + ACTION_PE_ANALYZER, %} module GLOBAL;