mirror of
https://github.com/zeek/zeek.git
synced 2025-10-06 16:48:19 +00:00
Documentation and a bit of overall cleanup.
This commit is contained in:
parent
a2eff14e05
commit
d4bd5672c0
7 changed files with 375 additions and 56 deletions
|
@ -1,48 +1,75 @@
|
||||||
|
|
||||||
module PE;
|
module PE;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
redef enum Log::ID += { LOG };
|
redef enum Log::ID += { LOG };
|
||||||
|
|
||||||
type Info: record {
|
type Info: record {
|
||||||
|
## Current timestamp.
|
||||||
ts: time &log;
|
ts: time &log;
|
||||||
fuid: string &log;
|
|
||||||
|
## File id of this portable executable file.
|
||||||
|
id: string &log;
|
||||||
|
|
||||||
|
## The target machine that the file was compiled for.
|
||||||
machine: string &log &optional;
|
machine: string &log &optional;
|
||||||
|
|
||||||
|
## The time that the file was created at.
|
||||||
compile_ts: time &log &optional;
|
compile_ts: time &log &optional;
|
||||||
|
|
||||||
|
## The required operating system.
|
||||||
os: string &log &optional;
|
os: string &log &optional;
|
||||||
|
|
||||||
|
## The subsystem that is required to run this file.
|
||||||
subsystem: string &log &optional;
|
subsystem: string &log &optional;
|
||||||
|
|
||||||
is_exe: bool &log &default=F;
|
## Is the file an executable, or just an object file?
|
||||||
is_dll: bool &log &default=F;
|
is_exe: bool &log &default=T;
|
||||||
|
|
||||||
|
## Is the file a 64-bit executable?
|
||||||
is_64bit: bool &log &default=T;
|
is_64bit: bool &log &default=T;
|
||||||
|
|
||||||
|
## Does the file support Address Space Layout Randomization?
|
||||||
uses_aslr: bool &log &default=F;
|
uses_aslr: bool &log &default=F;
|
||||||
|
|
||||||
|
## Does the file support Data Execution Prevention?
|
||||||
uses_dep: bool &log &default=F;
|
uses_dep: bool &log &default=F;
|
||||||
|
|
||||||
|
## Does the file enforce code integrity checks?
|
||||||
uses_code_integrity: bool &log &default=F;
|
uses_code_integrity: bool &log &default=F;
|
||||||
|
|
||||||
|
## Does the file use structured exception handing?
|
||||||
uses_seh: bool &log &default=T;
|
uses_seh: bool &log &default=T;
|
||||||
|
|
||||||
|
## Does the file have an import table?
|
||||||
has_import_table: bool &log &optional;
|
has_import_table: bool &log &optional;
|
||||||
|
|
||||||
|
## Does the file have an export table?
|
||||||
has_export_table: bool &log &optional;
|
has_export_table: bool &log &optional;
|
||||||
|
|
||||||
|
## Does the file have an attribute certificate table?
|
||||||
has_cert_table: bool &log &optional;
|
has_cert_table: bool &log &optional;
|
||||||
|
|
||||||
|
## Does the file have a debug table?
|
||||||
has_debug_data: bool &log &optional;
|
has_debug_data: bool &log &optional;
|
||||||
|
|
||||||
|
## The names of the sections, in order.
|
||||||
section_names: vector of string &log &optional;
|
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);
|
global set_file: hook(f: fa_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
redef record Info += {
|
|
||||||
confirmed: bool &default=F;
|
|
||||||
};
|
|
||||||
|
|
||||||
redef record fa_file += {
|
redef record fa_file += {
|
||||||
pe: Info &optional;
|
pe: Info &optional;
|
||||||
};
|
};
|
||||||
|
|
||||||
event bro_init() &priority=5
|
event bro_init() &priority=5
|
||||||
{
|
{
|
||||||
Log::create_stream(LOG, [$columns=Info]);
|
Log::create_stream(LOG, [$columns=Info, $ev=log_pe]);
|
||||||
}
|
}
|
||||||
|
|
||||||
hook set_file(f: fa_file) &priority=5
|
hook set_file(f: fa_file) &priority=5
|
||||||
|
@ -50,7 +77,7 @@ hook set_file(f: fa_file) &priority=5
|
||||||
if ( ! f?$pe )
|
if ( ! f?$pe )
|
||||||
{
|
{
|
||||||
local c: set[string] = set();
|
local c: set[string] = set();
|
||||||
f$pe = [$ts=network_time(), $fuid=f$id];
|
f$pe = [$ts=network_time(), $id=f$id];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,26 +89,20 @@ event pe_dos_header(f: fa_file, h: PE::DOSHeader) &priority=5
|
||||||
event pe_file_header(f: fa_file, h: PE::FileHeader) &priority=5
|
event pe_file_header(f: fa_file, h: PE::FileHeader) &priority=5
|
||||||
{
|
{
|
||||||
hook set_file(f);
|
hook set_file(f);
|
||||||
|
f$pe$is_exe = h$optional_header_size > 0;
|
||||||
f$pe$compile_ts = h$ts;
|
f$pe$compile_ts = h$ts;
|
||||||
f$pe$machine = machine_types[h$machine];
|
f$pe$machine = machine_types[h$machine];
|
||||||
for ( c in h$characteristics )
|
for ( c in h$characteristics )
|
||||||
{
|
{
|
||||||
if ( c == 0x2 )
|
|
||||||
f$pe$is_exe = T;
|
|
||||||
if ( c == 0x100 )
|
if ( c == 0x100 )
|
||||||
f$pe$is_64bit = F;
|
f$pe$is_64bit = F;
|
||||||
if ( c == 0x2000 )
|
|
||||||
f$pe$is_dll = T;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event pe_optional_header(f: fa_file, h: PE::OptionalHeader) &priority=5
|
event pe_optional_header(f: fa_file, h: PE::OptionalHeader) &priority=5
|
||||||
{
|
{
|
||||||
hook set_file(f);
|
hook set_file(f);
|
||||||
|
if ( ! f$pe$is_exe )
|
||||||
if ( h$magic == 0x10b || h$magic == 0x20b )
|
|
||||||
f$pe$confirmed = T;
|
|
||||||
else
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
f$pe$os = os_versions[h$os_version_major, h$os_version_minor];
|
f$pe$os = os_versions[h$os_version_major, h$os_version_minor];
|
||||||
|
@ -98,15 +119,17 @@ event pe_optional_header(f: fa_file, h: PE::OptionalHeader) &priority=5
|
||||||
f$pe$uses_seh = F;
|
f$pe$uses_seh = F;
|
||||||
}
|
}
|
||||||
|
|
||||||
f$pe$has_export_table = (|h$rvas| > 0 && h$rvas[0] > 0);
|
f$pe$has_export_table = (|h$table_sizes| > 0 && h$table_sizes[0] > 0);
|
||||||
f$pe$has_import_table = (|h$rvas| > 1 && h$rvas[1] > 0);
|
f$pe$has_import_table = (|h$table_sizes| > 1 && h$table_sizes[1] > 0);
|
||||||
f$pe$has_cert_table = (|h$rvas| > 4 && h$rvas[4] > 0);
|
f$pe$has_cert_table = (|h$table_sizes| > 4 && h$table_sizes[4] > 0);
|
||||||
f$pe$has_debug_data = (|h$rvas| > 6 && h$rvas[6] > 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
|
event pe_section_header(f: fa_file, h: PE::SectionHeader) &priority=5
|
||||||
{
|
{
|
||||||
hook set_file(f);
|
hook set_file(f);
|
||||||
|
if ( ! f$pe$is_exe )
|
||||||
|
return;
|
||||||
|
|
||||||
if ( ! f$pe?$section_names )
|
if ( ! f$pe?$section_names )
|
||||||
f$pe$section_names = vector();
|
f$pe$section_names = vector();
|
||||||
|
@ -115,7 +138,7 @@ event pe_section_header(f: fa_file, h: PE::SectionHeader) &priority=5
|
||||||
|
|
||||||
event file_state_remove(f: fa_file) &priority=-5
|
event file_state_remove(f: fa_file) &priority=-5
|
||||||
{
|
{
|
||||||
if ( f?$pe && f$pe$confirmed )
|
if ( f?$pe )
|
||||||
Log::write(LOG, f$pe);
|
Log::write(LOG, f$pe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2550,74 +2550,137 @@ type irc_join_list: set[irc_join_info];
|
||||||
module PE;
|
module PE;
|
||||||
export {
|
export {
|
||||||
type PE::DOSHeader: record {
|
type PE::DOSHeader: record {
|
||||||
|
## The magic number of a portable executable file ("MZ").
|
||||||
signature : string;
|
signature : string;
|
||||||
|
## The number of bytes in the last page that are used.
|
||||||
used_bytes_in_last_page : count;
|
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;
|
file_in_pages : count;
|
||||||
|
## Number of relocation entries stored after the header.
|
||||||
num_reloc_items : count;
|
num_reloc_items : count;
|
||||||
|
## Number of paragraphs in the header.
|
||||||
header_in_paragraphs : count;
|
header_in_paragraphs : count;
|
||||||
|
## Number of paragraps of additional memory that the program will need.
|
||||||
min_extra_paragraphs : count;
|
min_extra_paragraphs : count;
|
||||||
|
## Maximum number of paragraphs of additional memory.
|
||||||
max_extra_paragraphs : count;
|
max_extra_paragraphs : count;
|
||||||
|
## Relative value of the stack segment.
|
||||||
init_relative_ss : count;
|
init_relative_ss : count;
|
||||||
|
## Initial value of the SP register.
|
||||||
init_sp : count;
|
init_sp : count;
|
||||||
|
## Checksum. The 16-bit sum of all words in the file should be 0. Normally not set.
|
||||||
checksum : count;
|
checksum : count;
|
||||||
|
## Initial value of the IP register.
|
||||||
init_ip : count;
|
init_ip : count;
|
||||||
|
## Initial value of the CS register (relative to the initial segment).
|
||||||
init_relative_cs : count;
|
init_relative_cs : count;
|
||||||
|
## Offset of the first relocation table.
|
||||||
addr_of_reloc_table : count;
|
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;
|
overlay_num : count;
|
||||||
|
## OEM identifier.
|
||||||
oem_id : count;
|
oem_id : count;
|
||||||
|
## Additional OEM info, specific to oem_id.
|
||||||
oem_info : count;
|
oem_info : count;
|
||||||
|
## Address of the new EXE header.
|
||||||
addr_of_new_exe_header : count;
|
addr_of_new_exe_header : count;
|
||||||
};
|
};
|
||||||
|
|
||||||
type PE::FileHeader: record {
|
type PE::FileHeader: record {
|
||||||
|
## The target machine that the file was compiled for.
|
||||||
machine : count;
|
machine : count;
|
||||||
|
## The time that the file was created at.
|
||||||
ts : time;
|
ts : time;
|
||||||
|
## Pointer to the symbol table.
|
||||||
sym_table_ptr : count;
|
sym_table_ptr : count;
|
||||||
|
## Number of symbols.
|
||||||
num_syms : count;
|
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];
|
characteristics : set[count];
|
||||||
};
|
};
|
||||||
|
|
||||||
type PE::OptionalHeader: record {
|
type PE::OptionalHeader: record {
|
||||||
|
## PE32 or PE32+ indicator.
|
||||||
magic : count;
|
magic : count;
|
||||||
|
## The major version of the linker used to create the PE.
|
||||||
major_linker_version : count;
|
major_linker_version : count;
|
||||||
|
## The minor version of the linker used to create the PE.
|
||||||
minor_linker_version : count;
|
minor_linker_version : count;
|
||||||
|
## Size of the .text section.
|
||||||
size_of_code : count;
|
size_of_code : count;
|
||||||
|
## Size of the .data section.
|
||||||
size_of_init_data : count;
|
size_of_init_data : count;
|
||||||
|
## Size of the .bss section.
|
||||||
size_of_uninit_data : count;
|
size_of_uninit_data : count;
|
||||||
|
## The relative virtual address (RVA) of the entry point.
|
||||||
addr_of_entry_point : count;
|
addr_of_entry_point : count;
|
||||||
|
## The relative virtual address (RVA) of the .text section.
|
||||||
base_of_code : count;
|
base_of_code : count;
|
||||||
|
## The relative virtual address (RVA) of the .data section.
|
||||||
base_of_data : count &optional;
|
base_of_data : count &optional;
|
||||||
|
## Preferred memory location for the image to be based at.
|
||||||
image_base : count;
|
image_base : count;
|
||||||
|
## The alignment (in bytes) of sections when they're loaded in memory.
|
||||||
section_alignment : count;
|
section_alignment : count;
|
||||||
|
## The alignment (in bytes) of the raw data of sections.
|
||||||
file_alignment : count;
|
file_alignment : count;
|
||||||
|
## The major version of the required OS.
|
||||||
os_version_major : count;
|
os_version_major : count;
|
||||||
|
## The minor version of the required OS.
|
||||||
os_version_minor : count;
|
os_version_minor : count;
|
||||||
|
## The major version of this image.
|
||||||
major_image_version : count;
|
major_image_version : count;
|
||||||
|
## The minor version of this image.
|
||||||
minor_image_version : count;
|
minor_image_version : count;
|
||||||
|
## The major version of the subsystem required to run this file.
|
||||||
major_subsys_version : count;
|
major_subsys_version : count;
|
||||||
|
## The minor version of the subsystem required to run this file.
|
||||||
minor_subsys_version : count;
|
minor_subsys_version : count;
|
||||||
win32_version : count;
|
## The size (in bytes) of the iamge as the image is loaded in memory.
|
||||||
size_of_image : count;
|
size_of_image : count;
|
||||||
|
## The size (in bytes) of the headers, rounded up to file_alignment.
|
||||||
size_of_headers : count;
|
size_of_headers : count;
|
||||||
|
## The image file checksum.
|
||||||
checksum : count;
|
checksum : count;
|
||||||
|
## The subsystem that's required to run this image.
|
||||||
subsystem : count;
|
subsystem : count;
|
||||||
|
## Bit flags that determine how to execute or load this file.
|
||||||
dll_characteristics : set[count];
|
dll_characteristics : set[count];
|
||||||
loader_flags : count;
|
## A vector with the sizes of various tables and strings that are
|
||||||
rvas : vector of count;
|
## 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.
|
## Record for Portable Executable (PE) section headers.
|
||||||
type PE::SectionHeader: record {
|
type PE::SectionHeader: record {
|
||||||
|
## The name of the section
|
||||||
name : string;
|
name : string;
|
||||||
|
## The total size of the section when loaded into memory.
|
||||||
virtual_size : count;
|
virtual_size : count;
|
||||||
|
## The relative virtual address (RVA) of the section.
|
||||||
virtual_addr : count;
|
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;
|
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;
|
ptr_to_raw_data : count;
|
||||||
non_used_ptr_to_relocs : count;
|
## The file pointer to the beginning of relocation entries for
|
||||||
non_used_ptr_to_line_nums : count;
|
## the section.
|
||||||
non_used_num_of_relocs : count;
|
ptr_to_relocs : count;
|
||||||
non_used_num_of_line_nums : 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];
|
characteristics : set[count];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,57 @@
|
||||||
|
## A :abbr:`PE (Portable Executable)` file DOS header was parsed.
|
||||||
|
## This is the top-level header and contains information like the
|
||||||
|
## size of the file, initial value of registers, etc.
|
||||||
|
##
|
||||||
|
## f: The file.
|
||||||
|
##
|
||||||
|
## h: The parsed DOS header information.
|
||||||
|
##
|
||||||
|
## .. bro:see:: pe_dos_code pe_file_header pe_optional_header pe_section_header
|
||||||
event pe_dos_header%(f: fa_file, h: PE::DOSHeader%);
|
event pe_dos_header%(f: fa_file, h: PE::DOSHeader%);
|
||||||
|
|
||||||
|
## A :abbr:`PE (Portable Executable)` file DOS stub was parsed.
|
||||||
|
## The stub is a valid application that runs under MS-DOS, by default
|
||||||
|
## to inform the user that the program can't be run in DOS mode.
|
||||||
|
##
|
||||||
|
## f: The file.
|
||||||
|
##
|
||||||
|
## code: The DOS stub
|
||||||
|
##
|
||||||
|
## .. bro:see:: pe_dos_header pe_file_header pe_optional_header pe_section_header
|
||||||
event pe_dos_code%(f: fa_file, code: string%);
|
event pe_dos_code%(f: fa_file, code: string%);
|
||||||
|
|
||||||
|
## A :abbr:`PE (Portable Executable)` file file header was parsed.
|
||||||
|
## This header contains information like the target machine,
|
||||||
|
## the timestamp when the file was created, the number of sections, and
|
||||||
|
## pointers to other parts of the file.
|
||||||
|
##
|
||||||
|
## f: The file.
|
||||||
|
##
|
||||||
|
## h: The parsed file header information.
|
||||||
|
##
|
||||||
|
## .. bro:see:: pe_dos_header pe_dos_code pe_optional_header pe_section_header
|
||||||
event pe_file_header%(f: fa_file, h: PE::FileHeader%);
|
event pe_file_header%(f: fa_file, h: PE::FileHeader%);
|
||||||
|
|
||||||
|
## A :abbr:`PE (Portable Executable)` file optional header was parsed.
|
||||||
|
## This header is required for executable files, but not for object files.
|
||||||
|
## It contains information like OS requirements to execute the file, the
|
||||||
|
## original entry point address, and information needed to load the file
|
||||||
|
## into memory.
|
||||||
|
##
|
||||||
|
## f: The file.
|
||||||
|
##
|
||||||
|
## h: The parsed optional header information.
|
||||||
|
##
|
||||||
|
## .. bro:see:: pe_dos_header pe_dos_code pe_file_header pe_section_header
|
||||||
event pe_optional_header%(f: fa_file, h: PE::OptionalHeader%);
|
event pe_optional_header%(f: fa_file, h: PE::OptionalHeader%);
|
||||||
|
|
||||||
|
## A :abbr:`PE (Portable Executable)` file section header was parsed.
|
||||||
|
## This header contains information like the section name, size, address,
|
||||||
|
## and characteristics.
|
||||||
|
##
|
||||||
|
## f: The file.
|
||||||
|
##
|
||||||
|
## h: The parsed section header information.
|
||||||
|
##
|
||||||
|
## .. bro:see:: pe_dos_header pe_dos_code pe_file_header pe_optional_header
|
||||||
event pe_section_header%(f: fa_file, h: PE::SectionHeader%);
|
event pe_section_header%(f: fa_file, h: PE::SectionHeader%);
|
||||||
|
|
||||||
event pe_import_entry%(f: fa_file, m: string, name: string%);
|
|
|
@ -98,7 +98,8 @@ refine flow File += {
|
||||||
fh->Assign(1, new Val(static_cast<double>(${h.TimeDateStamp}), TYPE_TIME));
|
fh->Assign(1, new Val(static_cast<double>(${h.TimeDateStamp}), TYPE_TIME));
|
||||||
fh->Assign(2, new Val(${h.PointerToSymbolTable}, TYPE_COUNT));
|
fh->Assign(2, new Val(${h.PointerToSymbolTable}, TYPE_COUNT));
|
||||||
fh->Assign(3, new Val(${h.NumberOfSymbols}, TYPE_COUNT));
|
fh->Assign(3, new Val(${h.NumberOfSymbols}, TYPE_COUNT));
|
||||||
fh->Assign(4, characteristics_to_bro(${h.Characteristics}, 16));
|
fh->Assign(4, new Val(${h.SizeOfOptionalHeader}, TYPE_COUNT));
|
||||||
|
fh->Assign(5, characteristics_to_bro(${h.Characteristics}, 16));
|
||||||
BifEvent::generate_pe_file_header((analyzer::Analyzer *) connection()->bro_analyzer(),
|
BifEvent::generate_pe_file_header((analyzer::Analyzer *) connection()->bro_analyzer(),
|
||||||
connection()->bro_analyzer()->GetFile()->GetVal()->Ref(),
|
connection()->bro_analyzer()->GetFile()->GetVal()->Ref(),
|
||||||
fh);
|
fh);
|
||||||
|
@ -142,15 +143,13 @@ refine flow File += {
|
||||||
oh->Assign(15, new Val(${h.minor_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(16, new Val(${h.minor_subsys_version}, TYPE_COUNT));
|
||||||
oh->Assign(17, 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(18, new Val(${h.size_of_image}, TYPE_COUNT));
|
||||||
oh->Assign(19, new Val(${h.size_of_image}, TYPE_COUNT));
|
oh->Assign(19, new Val(${h.size_of_headers}, TYPE_COUNT));
|
||||||
oh->Assign(20, new Val(${h.size_of_headers}, TYPE_COUNT));
|
oh->Assign(20, new Val(${h.checksum}, TYPE_COUNT));
|
||||||
oh->Assign(21, new Val(${h.checksum}, TYPE_COUNT));
|
oh->Assign(21, new Val(${h.subsystem}, TYPE_COUNT));
|
||||||
oh->Assign(22, new Val(${h.subsystem}, TYPE_COUNT));
|
oh->Assign(22, characteristics_to_bro(${h.dll_characteristics}, 16));
|
||||||
oh->Assign(23, characteristics_to_bro(${h.dll_characteristics}, 16));
|
|
||||||
oh->Assign(24, new Val(${h.loader_flags}, TYPE_COUNT));
|
|
||||||
|
|
||||||
oh->Assign(25, process_rvas(${h.rvas}, ${h.number_of_rva_and_sizes}));
|
oh->Assign(23, process_rvas(${h.rvas}, ${h.number_of_rva_and_sizes}));
|
||||||
|
|
||||||
BifEvent::generate_pe_optional_header((analyzer::Analyzer *) connection()->bro_analyzer(),
|
BifEvent::generate_pe_optional_header((analyzer::Analyzer *) connection()->bro_analyzer(),
|
||||||
connection()->bro_analyzer()->GetFile()->GetVal()->Ref(),
|
connection()->bro_analyzer()->GetFile()->GetVal()->Ref(),
|
||||||
|
|
|
@ -39,9 +39,14 @@ type DOS_Code(len: uint32) = record {
|
||||||
type NT_Headers = record {
|
type NT_Headers = record {
|
||||||
PESignature : uint32;
|
PESignature : uint32;
|
||||||
file_header : File_Header;
|
file_header : File_Header;
|
||||||
optional_header : Optional_Header &length=file_header.SizeOfOptionalHeader;
|
have_opt_header : case file_header.SizeOfOptionalHeader of {
|
||||||
|
0 -> none: empty;
|
||||||
|
default -> optional_header : Optional_Header &length=file_header.SizeOfOptionalHeader;
|
||||||
|
};
|
||||||
} &let {
|
} &let {
|
||||||
length: uint32 = file_header.SizeOfOptionalHeader+offsetof(optional_header);
|
length: uint32 = file_header.SizeOfOptionalHeader + offsetof(have_opt_header);
|
||||||
|
is_exe: bool = file_header.SizeOfOptionalHeader > 0;
|
||||||
|
size_of_headers: uint32 = is_exe ? optional_header.size_of_headers : 0;
|
||||||
} &length=length;
|
} &length=length;
|
||||||
|
|
||||||
# The file header is mainly self-describing
|
# The file header is mainly self-describing
|
||||||
|
|
183
src/file_analysis/analyzer/pe/pe-file-idata.pac
Normal file
183
src/file_analysis/analyzer/pe/pe-file-idata.pac
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
## 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 {
|
||||||
|
import_by_ordinal: bool = (pe32_format == PE32_PLUS) ? (attrs_64 & 0x8000000000000000) > 1: (attrs_32 & 0x80000000) > 1;
|
||||||
|
attrs: uint64 = (pe32_format == PE32_PLUS) ? attrs_64 : attrs_32;
|
||||||
|
ordinal: uint16 = attrs & 0xff;
|
||||||
|
hint_rva: uint32 = attrs & 0xffff;
|
||||||
|
proc9000: bool = $context.connection.proc_import_lookup_attrs(this);
|
||||||
|
} &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_import_table: 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<uint32> 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
|
||||||
|
%{
|
||||||
|
printf("Parsed import directory. name@%x, IAT@%x\n", ${i.rva_module_name}, ${i.rva_import_addr_table});
|
||||||
|
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;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_import_lookup_attrs(t: import_lookup_attrs): bool
|
||||||
|
%{
|
||||||
|
printf("Parsed import lookup attrs. Hints @%x\n", ${t.hint_rva});
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# We need to calculate the length of the next padding field
|
||||||
|
function proc_import_hint(hint_name: bytestring, is_module: bool): bool
|
||||||
|
%{
|
||||||
|
printf("Parsed import hint\n");
|
||||||
|
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_;
|
||||||
|
%}
|
||||||
|
|
||||||
|
};
|
|
@ -11,8 +11,8 @@ type Portable_Executable = record {
|
||||||
headers : Headers;
|
headers : Headers;
|
||||||
pad : Padding(restofdata);
|
pad : Padding(restofdata);
|
||||||
} &let {
|
} &let {
|
||||||
unparsed_hdr_len: uint32 = headers.pe_header.optional_header.size_of_headers - headers.length;
|
unparsed_hdr_len: uint32 = headers.pe_header.size_of_headers - headers.length;
|
||||||
restofdata: uint64 = $context.connection.get_max_file_location() - headers.pe_header.optional_header.size_of_headers + unparsed_hdr_len;
|
restofdata: uint64 = headers.pe_header.is_exe ? $context.connection.get_max_file_location() - headers.pe_header.size_of_headers + unparsed_hdr_len : 0;
|
||||||
proc: bool = $context.connection.proc_pe(this);
|
proc: bool = $context.connection.proc_pe(this);
|
||||||
} &byteorder=littleendian;
|
} &byteorder=littleendian;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue