mirror of
https://github.com/zeek/zeek.git
synced 2025-10-07 17:18:20 +00:00
Merge remote-tracking branch 'origin/topic/vladg/file-analysis-exe-analyzer'
* origin/topic/vladg/file-analysis-exe-analyzer: (31 commits) Tweak the PE OS versions based on real-world traffic. Update pe/main.bro to user register_for_mime_types, ensuring it will also work with the upcoming Files framework changes. A bit of final core-level cleanup. A bit of final script cleanup. Update baselines. Add a btest for the PE analyzer. Add a PE memleak test, and fix a memleak. Documentation and a bit of overall cleanup. Add data about which tables are present. Remove the .idata parsing, as it can be more complicated in some cases. Fix a PE analyzer failure where the IAT isn't aligned with a section boundary. PE: Rehash the log a bit. Make base_of_data optional. Fix support for PE32+ files. PE Analyzer cleanup. Checkpoint - Import Address Table being parsed. Some changes to fix PE analyzer on master. Parse PE section headers. Updated PE analyzer to work with changes in master. In progress checkpoint. Things are starting to work. ... BIT-1369 #merged
This commit is contained in:
commit
a9979d56a4
30 changed files with 1429 additions and 53 deletions
2
scripts/base/files/pe/__load__.bro
Normal file
2
scripts/base/files/pe/__load__.bro
Normal file
|
@ -0,0 +1,2 @@
|
|||
@load ./consts
|
||||
@load ./main
|
184
scripts/base/files/pe/consts.bro
Normal file
184
scripts/base/files/pe/consts.bro
Normal file
|
@ -0,0 +1,184 @@
|
|||
|
||||
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 directories: table[count] of string = {
|
||||
[0] = "Export Table",
|
||||
[1] = "Import Table",
|
||||
[2] = "Resource Table",
|
||||
[3] = "Exception Table",
|
||||
[4] = "Certificate Table",
|
||||
[5] = "Base Relocation Table",
|
||||
[6] = "Debug",
|
||||
[7] = "Architecture",
|
||||
[8] = "Global Ptr",
|
||||
[9] = "TLS Table",
|
||||
[10] = "Load Config Table",
|
||||
[11] = "Bound Import",
|
||||
[12] = "IAT",
|
||||
[13] = "Delay Import Descriptor",
|
||||
[14] = "CLR Runtime Header",
|
||||
[15] = "Reserved"
|
||||
} &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 = {
|
||||
[10,0] = "Windows 10",
|
||||
[6,4] = "Windows 10 Technical Preview",
|
||||
[6,3] = "Windows 8.1 or Server 2012 R2",
|
||||
[6,2] = "Windows 8 or Server 2012",
|
||||
[6,1] = "Windows 7 or Server 2008 R2",
|
||||
[6,0] = "Windows Vista or Server 2008",
|
||||
[5,2] = "Windows XP x64 or Server 2003",
|
||||
[5,1] = "Windows XP",
|
||||
[5,0] = "Windows 2000",
|
||||
[4,90] = "Windows Me",
|
||||
[4,10] = "Windows 98",
|
||||
[4,0] = "Windows 95 or NT 4.0",
|
||||
[3,51] = "Windows NT 3.51",
|
||||
[3,50] = "Windows NT 3.5",
|
||||
[3,2] = "Windows 3.2",
|
||||
[3,11] = "Windows for Workgroups 3.11",
|
||||
[3,10] = "Windows 3.1 or NT 3.1",
|
||||
[3,0] = "Windows 3.0",
|
||||
[2,11] = "Windows 2.11",
|
||||
[2,10] = "Windows 2.10",
|
||||
[2,0] = "Windows 2.0",
|
||||
[1,4] = "Windows 1.04",
|
||||
[1,3] = "Windows 1.03",
|
||||
[1,1] = "Windows 1.01",
|
||||
[1,0] = "Windows 1.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); };
|
||||
|
||||
}
|
137
scripts/base/files/pe/main.bro
Normal file
137
scripts/base/files/pe/main.bro
Normal file
|
@ -0,0 +1,137 @@
|
|||
module PE;
|
||||
|
||||
@load ./consts.bro
|
||||
|
||||
export {
|
||||
redef enum Log::ID += { LOG };
|
||||
|
||||
type Info: record {
|
||||
## Current timestamp.
|
||||
ts: time &log;
|
||||
## File id of this portable executable file.
|
||||
id: string &log;
|
||||
## The target machine that the file was compiled for.
|
||||
machine: string &log &optional;
|
||||
## The time that the file was created at.
|
||||
compile_ts: time &log &optional;
|
||||
## The required operating system.
|
||||
os: string &log &optional;
|
||||
## The subsystem that is required to run this file.
|
||||
subsystem: string &log &optional;
|
||||
## Is the file an executable, or just an object file?
|
||||
is_exe: bool &log &default=T;
|
||||
## Is the file a 64-bit executable?
|
||||
is_64bit: bool &log &default=T;
|
||||
## Does the file support Address Space Layout Randomization?
|
||||
uses_aslr: bool &log &default=F;
|
||||
## Does the file support Data Execution Prevention?
|
||||
uses_dep: bool &log &default=F;
|
||||
## Does the file enforce code integrity checks?
|
||||
uses_code_integrity: bool &log &default=F;
|
||||
## Does the file use structured exception handing?
|
||||
uses_seh: bool &log &default=T;
|
||||
## Does the file have an import table?
|
||||
has_import_table: bool &log &optional;
|
||||
## Does the file have an export table?
|
||||
has_export_table: bool &log &optional;
|
||||
## Does the file have an attribute certificate table?
|
||||
has_cert_table: bool &log &optional;
|
||||
## Does the file have a debug table?
|
||||
has_debug_data: bool &log &optional;
|
||||
## The names of the sections, in order.
|
||||
section_names: vector of string &log &optional;
|
||||
};
|
||||
|
||||
## Event for accessing logged records.
|
||||
global log_pe: event(rec: Info);
|
||||
|
||||
## A hook that gets called when we first see a PE file.
|
||||
global set_file: hook(f: fa_file);
|
||||
}
|
||||
|
||||
redef record fa_file += {
|
||||
pe: Info &optional;
|
||||
};
|
||||
|
||||
const pe_mime_types = { "application/x-dosexec" };
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Files::register_for_mime_types(Files::ANALYZER_PE, pe_mime_types);
|
||||
Log::create_stream(LOG, [$columns=Info, $ev=log_pe, $path="pe"]);
|
||||
}
|
||||
|
||||
hook set_file(f: fa_file) &priority=5
|
||||
{
|
||||
if ( ! f?$pe )
|
||||
f$pe = [$ts=network_time(), $id=f$id];
|
||||
}
|
||||
|
||||
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$machine = machine_types[h$machine];
|
||||
f$pe$compile_ts = h$ts;
|
||||
f$pe$is_exe = ( h$optional_header_size > 0 );
|
||||
|
||||
for ( c in h$characteristics )
|
||||
{
|
||||
if ( file_characteristics[c] == "32BIT_MACHINE" )
|
||||
f$pe$is_64bit = F;
|
||||
}
|
||||
}
|
||||
|
||||
event pe_optional_header(f: fa_file, h: PE::OptionalHeader) &priority=5
|
||||
{
|
||||
hook set_file(f);
|
||||
|
||||
# Only EXEs have optional headers
|
||||
if ( ! f$pe$is_exe )
|
||||
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 )
|
||||
{
|
||||
if ( dll_characteristics[c] == "DYNAMIC_BASE" )
|
||||
f$pe$uses_aslr = T;
|
||||
if ( dll_characteristics[c] == "FORCE_INTEGRITY" )
|
||||
f$pe$uses_code_integrity = T;
|
||||
if ( dll_characteristics[c] == "NX_COMPAT" )
|
||||
f$pe$uses_dep = T;
|
||||
if ( dll_characteristics[c] == "NO_SEH" )
|
||||
f$pe$uses_seh = F;
|
||||
}
|
||||
|
||||
f$pe$has_export_table = (|h$table_sizes| > 0 && h$table_sizes[0] > 0);
|
||||
f$pe$has_import_table = (|h$table_sizes| > 1 && h$table_sizes[1] > 0);
|
||||
f$pe$has_cert_table = (|h$table_sizes| > 4 && h$table_sizes[4] > 0);
|
||||
f$pe$has_debug_data = (|h$table_sizes| > 6 && h$table_sizes[6] > 0);
|
||||
}
|
||||
|
||||
event pe_section_header(f: fa_file, h: PE::SectionHeader) &priority=5
|
||||
{
|
||||
hook set_file(f);
|
||||
|
||||
# Only EXEs have section headers
|
||||
if ( ! f$pe$is_exe )
|
||||
return;
|
||||
|
||||
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) &priority=-5
|
||||
{
|
||||
if ( f?$pe && f$pe?$machine )
|
||||
Log::write(LOG, f$pe);
|
||||
}
|
||||
|
|
@ -2555,6 +2555,145 @@ type irc_join_info: record {
|
|||
## .. bro:see:: irc_join_message
|
||||
type irc_join_list: set[irc_join_info];
|
||||
|
||||
module PE;
|
||||
export {
|
||||
type PE::DOSHeader: record {
|
||||
## The magic number of a portable executable file ("MZ").
|
||||
signature : string;
|
||||
## The number of bytes in the last page that are used.
|
||||
used_bytes_in_last_page : count;
|
||||
## The number of pages in the file that are part of the PE file itself.
|
||||
file_in_pages : count;
|
||||
## Number of relocation entries stored after the header.
|
||||
num_reloc_items : count;
|
||||
## Number of paragraphs in the header.
|
||||
header_in_paragraphs : count;
|
||||
## Number of paragraps of additional memory that the program will need.
|
||||
min_extra_paragraphs : count;
|
||||
## Maximum number of paragraphs of additional memory.
|
||||
max_extra_paragraphs : count;
|
||||
## Relative value of the stack segment.
|
||||
init_relative_ss : count;
|
||||
## Initial value of the SP register.
|
||||
init_sp : count;
|
||||
## Checksum. The 16-bit sum of all words in the file should be 0. Normally not set.
|
||||
checksum : count;
|
||||
## Initial value of the IP register.
|
||||
init_ip : count;
|
||||
## Initial value of the CS register (relative to the initial segment).
|
||||
init_relative_cs : count;
|
||||
## Offset of the first relocation table.
|
||||
addr_of_reloc_table : count;
|
||||
## Overlays allow you to append data to the end of the file. If this is the main program,
|
||||
## this will be 0.
|
||||
overlay_num : count;
|
||||
## OEM identifier.
|
||||
oem_id : count;
|
||||
## Additional OEM info, specific to oem_id.
|
||||
oem_info : count;
|
||||
## Address of the new EXE header.
|
||||
addr_of_new_exe_header : count;
|
||||
};
|
||||
|
||||
type PE::FileHeader: record {
|
||||
## The target machine that the file was compiled for.
|
||||
machine : count;
|
||||
## The time that the file was created at.
|
||||
ts : time;
|
||||
## Pointer to the symbol table.
|
||||
sym_table_ptr : count;
|
||||
## Number of symbols.
|
||||
num_syms : count;
|
||||
## The size of the optional header.
|
||||
optional_header_size : count;
|
||||
## Bit flags that determine if this file is executable, non-relocatable, and/or a DLL.
|
||||
characteristics : set[count];
|
||||
};
|
||||
|
||||
type PE::OptionalHeader: record {
|
||||
## PE32 or PE32+ indicator.
|
||||
magic : count;
|
||||
## The major version of the linker used to create the PE.
|
||||
major_linker_version : count;
|
||||
## The minor version of the linker used to create the PE.
|
||||
minor_linker_version : count;
|
||||
## Size of the .text section.
|
||||
size_of_code : count;
|
||||
## Size of the .data section.
|
||||
size_of_init_data : count;
|
||||
## Size of the .bss section.
|
||||
size_of_uninit_data : count;
|
||||
## The relative virtual address (RVA) of the entry point.
|
||||
addr_of_entry_point : count;
|
||||
## The relative virtual address (RVA) of the .text section.
|
||||
base_of_code : count;
|
||||
## The relative virtual address (RVA) of the .data section.
|
||||
base_of_data : count &optional;
|
||||
## Preferred memory location for the image to be based at.
|
||||
image_base : count;
|
||||
## The alignment (in bytes) of sections when they're loaded in memory.
|
||||
section_alignment : count;
|
||||
## The alignment (in bytes) of the raw data of sections.
|
||||
file_alignment : count;
|
||||
## The major version of the required OS.
|
||||
os_version_major : count;
|
||||
## The minor version of the required OS.
|
||||
os_version_minor : count;
|
||||
## The major version of this image.
|
||||
major_image_version : count;
|
||||
## The minor version of this image.
|
||||
minor_image_version : count;
|
||||
## The major version of the subsystem required to run this file.
|
||||
major_subsys_version : count;
|
||||
## The minor version of the subsystem required to run this file.
|
||||
minor_subsys_version : count;
|
||||
## The size (in bytes) of the iamge as the image is loaded in memory.
|
||||
size_of_image : count;
|
||||
## The size (in bytes) of the headers, rounded up to file_alignment.
|
||||
size_of_headers : count;
|
||||
## The image file checksum.
|
||||
checksum : count;
|
||||
## The subsystem that's required to run this image.
|
||||
subsystem : count;
|
||||
## Bit flags that determine how to execute or load this file.
|
||||
dll_characteristics : set[count];
|
||||
## A vector with the sizes of various tables and strings that are
|
||||
## defined in the optional header data directories. Examples include
|
||||
## the import table, the resource table, and debug information.
|
||||
table_sizes : vector of count;
|
||||
|
||||
};
|
||||
|
||||
## Record for Portable Executable (PE) section headers.
|
||||
type PE::SectionHeader: record {
|
||||
## The name of the section
|
||||
name : string;
|
||||
## The total size of the section when loaded into memory.
|
||||
virtual_size : count;
|
||||
## The relative virtual address (RVA) of the section.
|
||||
virtual_addr : count;
|
||||
## The size of the initialized data for the section, as it is
|
||||
## in the file on disk.
|
||||
size_of_raw_data : count;
|
||||
## The virtual address of the initialized dat for the section,
|
||||
## as it is in the file on disk.
|
||||
ptr_to_raw_data : count;
|
||||
## The file pointer to the beginning of relocation entries for
|
||||
## the section.
|
||||
ptr_to_relocs : count;
|
||||
## The file pointer to the beginning of line-number entries for
|
||||
## the section.
|
||||
ptr_to_line_nums : count;
|
||||
## The number of relocation entries for the section.
|
||||
num_of_relocs : count;
|
||||
## The number of line-number entrie for the section.
|
||||
num_of_line_nums : count;
|
||||
## Bit-flags that describe the characteristics of the section.
|
||||
characteristics : set[count];
|
||||
};
|
||||
}
|
||||
module GLOBAL;
|
||||
|
||||
## Deprecated.
|
||||
##
|
||||
## .. todo:: Remove. It's still declared internally but doesn't seem used anywhere
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
@load base/protocols/syslog
|
||||
@load base/protocols/tunnels
|
||||
|
||||
@load base/files/pe
|
||||
@load base/files/hash
|
||||
@load base/files/extract
|
||||
@load base/files/unified2
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue