diff --git a/scripts/base/files/pe/__load__.bro b/scripts/base/files/pe/__load__.bro new file mode 100644 index 0000000000..0098b81a7a --- /dev/null +++ b/scripts/base/files/pe/__load__.bro @@ -0,0 +1,2 @@ +@load ./consts +@load ./main \ No newline at end of file diff --git a/scripts/base/files/pe/consts.bro b/scripts/base/files/pe/consts.bro new file mode 100644 index 0000000000..4dc21ec179 --- /dev/null +++ b/scripts/base/files/pe/consts.bro @@ -0,0 +1,149 @@ + +module PE; + +export { + const machine_types: table[count] of string = { + [0x00] = "UNKNOWN", + [0x1d3] = "AM33", + [0x8664] = "AMD64", + [0x1c0] = "ARM", + [0x1c4] = "ARMNT", + [0xaa64] = "ARM64", + [0xebc] = "EBC", + [0x14c] = "I386", + [0x200] = "IA64", + [0x9041] = "M32R", + [0x266] = "MIPS16", + [0x366] = "MIPSFPU", + [0x466] = "MIPSFPU16", + [0x1f0] = "POWERPC", + [0x1f1] = "POWERPCFP", + [0x166] = "R4000", + [0x1a2] = "SH3", + [0x1a3] = "SH3DSP", + [0x1a6] = "SH4", + [0x1a8] = "SH5", + [0x1c2] = "THUMB", + [0x169] = "WCEMIPSV2" + } &default=function(i: count):string { return fmt("unknown-%d", i); }; + + const file_characteristics: table[count] of string = { + [0x1] = "RELOCS_STRIPPED", + [0x2] = "EXECUTABLE_IMAGE", + [0x4] = "LINE_NUMS_STRIPPED", + [0x8] = "LOCAL_SYMS_STRIPPED", + [0x10] = "AGGRESSIVE_WS_TRIM", + [0x20] = "LARGE_ADDRESS_AWARE", + [0x80] = "BYTES_REVERSED_LO", + [0x100] = "32BIT_MACHINE", + [0x200] = "DEBUG_STRIPPED", + [0x400] = "REMOVABLE_RUN_FROM_SWAP", + [0x800] = "NET_RUN_FROM_SWAP", + [0x1000] = "SYSTEM", + [0x2000] = "DLL", + [0x4000] = "UP_SYSTEM_ONLY", + [0x8000] = "BYTES_REVERSED_HI" + } &default=function(i: count):string { return fmt("unknown-%d", i); }; + + const dll_characteristics: table[count] of string = { + [0x40] = "DYNAMIC_BASE", + [0x80] = "FORCE_INTEGRITY", + [0x100] = "NX_COMPAT", + [0x200] = "NO_ISOLATION", + [0x400] = "NO_SEH", + [0x800] = "NO_BIND", + [0x2000] = "WDM_DRIVER", + [0x8000] = "TERMINAL_SERVER_AWARE" + } &default=function(i: count):string { return fmt("unknown-%d", i); }; + + const windows_subsystems: table[count] of string = { + [0] = "UNKNOWN", + [1] = "NATIVE", + [2] = "WINDOWS_GUI", + [3] = "WINDOWS_CUI", + [7] = "POSIX_CUI", + [9] = "WINDOWS_CE_GUI", + [10] = "EFI_APPLICATION", + [11] = "EFI_BOOT_SERVICE_DRIVER", + [12] = "EFI_RUNTIME_
DRIVER", + [13] = "EFI_ROM", + [14] = "XBOX" + } &default=function(i: count):string { return fmt("unknown-%d", i); }; + + const section_characteristics: table[count] of string = { + [0x8] = "TYPE_NO_PAD", + [0x20] = "CNT_CODE", + [0x40] = "CNT_INITIALIZED_DATA", + [0x80] = "CNT_UNINITIALIZED_DATA", + [0x100] = "LNK_OTHER", + [0x200] = "LNK_INFO", + [0x800] = "LNK_REMOVE", + [0x1000] = "LNK_COMDAT", + [0x8000] = "GPREL", + [0x20000] = "MEM_16BIT", + [0x40000] = "MEM_LOCKED", + [0x80000] = "MEM_PRELOAD", + [0x100000] = "ALIGN_1BYTES", + [0x200000] = "ALIGN_2BYTES", + [0x300000] = "ALIGN_4BYTES", + [0x400000] = "ALIGN_8BYTES", + [0x500000] = "ALIGN_16BYTES", + [0x600000] = "ALIGN_32BYTES", + [0x700000] = "ALIGN_64BYTES", + [0x800000] = "ALIGN_128BYTES", + [0x900000] = "ALIGN_256BYTES", + [0xa00000] = "ALIGN_512BYTES", + [0xb00000] = "ALIGN_1024BYTES", + [0xc00000] = "ALIGN_2048BYTES", + [0xd00000] = "ALIGN_4096BYTES", + [0xe00000] = "ALIGN_8192BYTES", + [0x1000000] = "LNK_NRELOC_OVFL", + [0x2000000] = "MEM_DISCARDABLE", + [0x4000000] = "MEM_NOT_CACHED", + [0x8000000] = "MEM_NOT_PAGED", + [0x10000000] = "MEM_SHARED", + [0x20000000] = "MEM_EXECUTE", + [0x40000000] = "MEM_READ", + [0x80000000] = "MEM_WRITE" + } &default=function(i: count):string { return fmt("unknown-%d", i); }; + + const os_versions: table[count, count] of string = { + [6,2] = "Windows 8", + [6,1] = "Windows 7", + [6,0] = "Windows Vista", + [5,2] = "Windows XP 64-Bit Edition", + [5,1] = "Windows XP", + [5,0] = "Windows 2000", + [4,90] = "Windows Me", + [4,1] = "Windows 98", + [4,0] = "Windows NT 4.0", + } &default=function(i: count, j: count):string { return fmt("unknown-%d.%d", i, j); }; + + const section_descs: table[string] of string = { + [".bss"] = "Uninitialized data", + [".cormeta"] = "CLR metadata that indicates that the object file contains managed code", + [".data"] = "Initialized data", + [".debug$F"] = "Generated FPO debug information", + [".debug$P"] = "Precompiled debug types", + [".debug$S"] = "Debug symbols", + [".debug$T"] = "Debug types", + [".drective"] = "Linker options", + [".edata"] = "Export tables", + [".idata"] = "Import tables", + [".idlsym"] = "Includes registered SEH to support IDL attributes", + [".pdata"] = "Exception information", + [".rdata"] = "Read-only initialized data", + [".reloc"] = "Image relocations", + [".rsrc"] = "Resource directory", + [".sbss"] = "GP-relative uninitialized data", + [".sdata"] = "GP-relative initialized data", + [".srdata"] = "GP-relative read-only data", + [".sxdata"] = "Registered exception handler data", + [".text"] = "Executable code", + [".tls"] = "Thread-local storage", + [".tls$"] = "Thread-local storage", + [".vsdata"] = "GP-relative initialized data", + [".xdata"] = "Exception information", + } &default=function(i: string):string { return fmt("unknown-%s", i); }; + +} diff --git a/scripts/base/files/pe/main.bro b/scripts/base/files/pe/main.bro new file mode 100644 index 0000000000..76ba04fc8c --- /dev/null +++ b/scripts/base/files/pe/main.bro @@ -0,0 +1,86 @@ + +module PE; + +export { + redef enum Log::ID += { LOG }; + + type Info: record { + ts: time &log; + fuid: string &log; + machine: string &log &optional; + compile_ts: time &log &optional; + os: string &log &optional; + subsystem: string &log &optional; + characteristics: set[string] &log &optional; + section_names: vector of string &log &optional; + }; + + + global set_file: hook(f: fa_file); +} + +redef record fa_file += { + pe: Info &optional; +}; + +event bro_init() &priority=5 + { + Log::create_stream(LOG, [$columns=Info]); + } + +hook set_file(f: fa_file) &priority=5 + { + if ( ! f?$pe ) + { + local c: set[string] = set(); + f$pe = [$ts=network_time(), $fuid=f$id, $characteristics=c]; + } + } + +event pe_dos_header(f: fa_file, h: PE::DOSHeader) &priority=5 + { + hook set_file(f); + } + +event pe_file_header(f: fa_file, h: PE::FileHeader) &priority=5 + { + hook set_file(f); + f$pe$compile_ts = h$ts; + f$pe$machine = machine_types[h$machine]; + for ( c in h$characteristics ) + add f$pe$characteristics[PE::file_characteristics[c]]; + } + +event pe_optional_header(f: fa_file, h: PE::OptionalHeader) &priority=5 + { + hook set_file(f); + f$pe$os = os_versions[h$os_version_major, h$os_version_minor]; + f$pe$subsystem = windows_subsystems[h$subsystem]; + } + +event pe_section_header(f: fa_file, h: PE::SectionHeader) &priority=5 + { + hook set_file(f); + + print h; + if ( ! f$pe?$section_names ) + f$pe$section_names = vector(); + f$pe$section_names[|f$pe$section_names|] = h$name; + } + +event file_state_remove(f: fa_file) + { + if ( f?$pe ) + Log::write(LOG, f$pe); + } + +event file_new(f: fa_file) + { + if ( f?$mime_type && f$mime_type == /application\/x-dosexec.*/ ) + { + #print "found a windows executable"; + FileAnalysis::add_analyzer(f, [$tag=FileAnalysis::ANALYZER_PE]); + #FileAnalysis::add_analyzer(f, [$tag=FileAnalysis::ANALYZER_EXTRACT, + # $extract_filename=fmt("exe-%d", ++blah_counter)]); + } + } diff --git a/src/file_analysis/analyzer/CMakeLists.txt b/src/file_analysis/analyzer/CMakeLists.txt index bfafcd2894..67929b77fd 100644 --- a/src/file_analysis/analyzer/CMakeLists.txt +++ b/src/file_analysis/analyzer/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(data_event) add_subdirectory(extract) add_subdirectory(hash) +add_subdirectory(pe) diff --git a/src/file_analysis/analyzer/pe/CMakeLists.txt b/src/file_analysis/analyzer/pe/CMakeLists.txt new file mode 100644 index 0000000000..7fc89bfd51 --- /dev/null +++ b/src/file_analysis/analyzer/pe/CMakeLists.txt @@ -0,0 +1,10 @@ +include(BroPlugin) + +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}) + +bro_plugin_begin(Bro PE) +bro_plugin_cc(PE.cc Plugin.cc) +bro_plugin_bif(events.bif) +bro_plugin_pac(pe.pac pe-file.pac pe-analyzer.pac) +bro_plugin_end() diff --git a/src/file_analysis/analyzer/pe/Plugin.cc b/src/file_analysis/analyzer/pe/Plugin.cc new file mode 100644 index 0000000000..1cc33b5759 --- /dev/null +++ b/src/file_analysis/analyzer/pe/Plugin.cc @@ -0,0 +1,29 @@ +#include "plugin/Plugin.h" +#include "file_analysis/Component.h" + +#include "PE.h" + +namespace plugin { namespace Bro_PE { + +class Plugin : public plugin::Plugin { +protected: + void InitPreScript() + { + SetName("Bro::PE"); + SetVersion(-1); + SetAPIVersion(BRO_PLUGIN_API_VERSION); + SetDynamicPlugin(false); + + SetDescription("Portable Executable analyzer"); + + AddComponent(new ::file_analysis::Component("PE", + ::file_analysis::PE::Instantiate)); + + extern std::list > __bif_events_init(); + AddBifInitFunction(&__bif_events_init); + } +}; + +Plugin __plugin; + +} } diff --git a/src/file_analysis/analyzer/pe/pe-analyzer.pac b/src/file_analysis/analyzer/pe/pe-analyzer.pac index 341a3efbec..045f71c479 100644 --- a/src/file_analysis/analyzer/pe/pe-analyzer.pac +++ b/src/file_analysis/analyzer/pe/pe-analyzer.pac @@ -3,6 +3,7 @@ #include "Event.h" #include "file_analysis/File.h" #include "file_analysis.bif.func_h" +#include "events.bif.h" %} refine flow File += { @@ -52,7 +53,7 @@ refine flow File += { 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(), + BifEvent::generate_pe_dos_header((analyzer::Analyzer *) connection()->bro_analyzer(), connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), dh); } @@ -63,7 +64,7 @@ refine flow File += { %{ if ( pe_dos_code ) { - BifEvent::generate_pe_dos_code((Analyzer *) connection()->bro_analyzer(), + BifEvent::generate_pe_dos_code((analyzer::Analyzer *) connection()->bro_analyzer(), connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), new StringVal(code.length(), (const char*) code.data())); } @@ -90,7 +91,7 @@ refine flow File += { 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(), + BifEvent::generate_pe_file_header((analyzer::Analyzer *) connection()->bro_analyzer(), connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), fh); } @@ -138,7 +139,7 @@ refine flow File += { 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(), + BifEvent::generate_pe_optional_header((analyzer::Analyzer *) connection()->bro_analyzer(), connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), oh); } @@ -170,7 +171,7 @@ refine flow File += { 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(), + BifEvent::generate_pe_section_header((analyzer::Analyzer *) connection()->bro_analyzer(), connection()->bro_analyzer()->GetFile()->GetVal()->Ref(), section_header); } diff --git a/src/file_analysis/analyzer/pe/pe-file.pac b/src/file_analysis/analyzer/pe/pe-file.pac index ab7cdf5f8a..03a25ce150 100644 --- a/src/file_analysis/analyzer/pe/pe-file.pac +++ b/src/file_analysis/analyzer/pe/pe-file.pac @@ -1,5 +1,5 @@ -type TheFile(part: uint8) = record { +type TheFile = record { dos_header : DOS_Header; dos_code : DOS_Code(dos_code_len); pe_header : IMAGE_NT_HEADERS;