mirror of
https://github.com/zeek/zeek.git
synced 2025-10-05 08:08:19 +00:00
Fix a PE analyzer failure where the IAT isn't aligned with a section boundary.
This commit is contained in:
parent
da89837693
commit
546cbf50c9
7 changed files with 87 additions and 25 deletions
|
@ -18,6 +18,8 @@ PE::~PE()
|
||||||
|
|
||||||
bool PE::DeliverStream(const u_char* data, uint64 len)
|
bool PE::DeliverStream(const u_char* data, uint64 len)
|
||||||
{
|
{
|
||||||
|
if ( conn->is_done() )
|
||||||
|
return true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
interp->NewData(data, data + len);
|
interp->NewData(data, data + len);
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
event pe_dos_header%(f: fa_file, h: PE::DOSHeader%);
|
event pe_dos_header%(f: fa_file, h: PE::DOSHeader%);
|
||||||
|
|
||||||
event pe_dos_code%(f: fa_file, code: string%);
|
event pe_dos_code%(f: fa_file, code: string%);
|
||||||
|
|
||||||
event pe_file_header%(f: fa_file, h: PE::FileHeader%);
|
event pe_file_header%(f: fa_file, h: PE::FileHeader%);
|
||||||
|
|
||||||
event pe_optional_header%(f: fa_file, h: PE::OptionalHeader%);
|
event pe_optional_header%(f: fa_file, h: PE::OptionalHeader%);
|
||||||
|
|
||||||
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%);
|
|
@ -174,13 +174,23 @@ refine flow File += {
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
function proc_import_entry(module_name: bytestring, i: import_entry): bool
|
||||||
function proc_pe_file(): bool
|
|
||||||
%{
|
%{
|
||||||
printf("PE file processed\n");
|
if ( pe_import_entry )
|
||||||
|
{
|
||||||
|
StringVal* name;
|
||||||
|
if ( ${i.name}.length() > 1 )
|
||||||
|
name = new StringVal(${i.name}.length() - 1, (const char*) ${i.name}.begin());
|
||||||
|
else
|
||||||
|
name = new StringVal(0, (const char*) ${i.name}.begin());
|
||||||
|
|
||||||
|
BifEvent::generate_pe_import_entry((analyzer::Analyzer *) connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->GetFile()->GetVal()->Ref(),
|
||||||
|
bytestring_to_val(${module_name}),
|
||||||
|
name);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
refine typeattr DOS_Header += &let {
|
refine typeattr DOS_Header += &let {
|
||||||
|
@ -204,10 +214,9 @@ refine typeattr Optional_Header += &let {
|
||||||
};
|
};
|
||||||
|
|
||||||
refine typeattr Section_Header += &let {
|
refine typeattr Section_Header += &let {
|
||||||
proc2: bool = $context.flow.proc_section_header(this);
|
proc: bool = $context.flow.proc_section_header(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
refine typeattr PE_File += &let {
|
refine typeattr import_entry += &let {
|
||||||
proc: bool = $context.flow.proc_pe_file();
|
proc: bool = $context.flow.proc_import_entry($context.connection.get_module_name(), this) &if(!is_module);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ 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(file_header.SizeOfOptionalHeader, file_header.NumberOfSections) &length=file_header.SizeOfOptionalHeader;
|
optional_header : Optional_Header &length=file_header.SizeOfOptionalHeader;
|
||||||
} &let {
|
} &let {
|
||||||
length: uint32 = file_header.SizeOfOptionalHeader+offsetof(optional_header);
|
length: uint32 = file_header.SizeOfOptionalHeader+offsetof(optional_header);
|
||||||
} &length=length;
|
} &length=length;
|
||||||
|
@ -56,7 +56,7 @@ type File_Header = record {
|
||||||
};
|
};
|
||||||
|
|
||||||
# The optional header gives us DLL link information, and some structural information
|
# The optional header gives us DLL link information, and some structural information
|
||||||
type Optional_Header(len: uint16, number_of_sections: uint16) = record {
|
type Optional_Header = record {
|
||||||
magic : uint16;
|
magic : uint16;
|
||||||
major_linker_version : uint8;
|
major_linker_version : uint8;
|
||||||
minor_linker_version : uint8;
|
minor_linker_version : uint8;
|
||||||
|
@ -68,11 +68,11 @@ type Optional_Header(len: uint16, number_of_sections: uint16) = record {
|
||||||
have_base_of_data: case pe_format of {
|
have_base_of_data: case pe_format of {
|
||||||
PE32 -> base_of_data: uint32;
|
PE32 -> base_of_data: uint32;
|
||||||
default -> not_present: empty;
|
default -> not_present: empty;
|
||||||
};
|
} &requires(pe_format);
|
||||||
is_pe32: case pe_format of {
|
is_pe32: case pe_format of {
|
||||||
PE32_PLUS -> image_base_64: uint64;
|
PE32_PLUS -> image_base_64: uint64;
|
||||||
default -> image_base_32: uint32;
|
default -> image_base_32: uint32;
|
||||||
};
|
} &requires(pe_format);
|
||||||
section_alignment : uint32;
|
section_alignment : uint32;
|
||||||
file_alignment : uint32;
|
file_alignment : uint32;
|
||||||
os_version_major : uint16;
|
os_version_major : uint16;
|
||||||
|
@ -91,14 +91,14 @@ type Optional_Header(len: uint16, number_of_sections: uint16) = record {
|
||||||
PE32 -> i32: Mem_Info32;
|
PE32 -> i32: Mem_Info32;
|
||||||
PE32_PLUS -> i64: Mem_Info64;
|
PE32_PLUS -> i64: Mem_Info64;
|
||||||
default -> InvalidPEFile : empty;
|
default -> InvalidPEFile : empty;
|
||||||
};
|
} &requires(pe_format);
|
||||||
loader_flags : uint32;
|
loader_flags : uint32;
|
||||||
number_of_rva_and_sizes : uint32;
|
number_of_rva_and_sizes : uint32;
|
||||||
rvas : RVAS(number_of_rva_and_sizes);
|
rvas : RVAS(number_of_rva_and_sizes);
|
||||||
} &let {
|
} &let {
|
||||||
pe_format: uint8 = $context.connection.set_pe32_format(magic);
|
pe_format: uint8 = $context.connection.set_pe32_format(magic);
|
||||||
image_base: uint64 = pe_format == PE32_PLUS ? image_base_64 : image_base_32;
|
image_base: uint64 = pe_format == PE32_PLUS ? image_base_64 : image_base_32;
|
||||||
} &length=len;
|
};
|
||||||
|
|
||||||
type Section_Headers(num: uint16) = record {
|
type Section_Headers(num: uint16) = record {
|
||||||
sections : Section_Header[num];
|
sections : Section_Header[num];
|
||||||
|
@ -118,7 +118,7 @@ type Section_Header = record {
|
||||||
non_used_num_of_line_nums : uint16;
|
non_used_num_of_line_nums : uint16;
|
||||||
characteristics : uint32;
|
characteristics : uint32;
|
||||||
} &let {
|
} &let {
|
||||||
proc: bool = $context.connection.proc_section(this);
|
add_section: bool = $context.connection.add_section(this);
|
||||||
} &length=40;
|
} &length=40;
|
||||||
|
|
||||||
refine connection MockConnection += {
|
refine connection MockConnection += {
|
||||||
|
@ -132,13 +132,13 @@ refine connection MockConnection += {
|
||||||
pe32_format_ = UNKNOWN_VERSION;;
|
pe32_format_ = UNKNOWN_VERSION;;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
function proc_section(h: Section_Header): bool
|
function add_section(h: Section_Header): bool
|
||||||
%{
|
%{
|
||||||
if ( ${h.size_of_raw_data} + ${h.ptr_to_raw_data} > max_file_location_ )
|
if ( ${h.size_of_raw_data} + ${h.ptr_to_raw_data} > max_file_location_ )
|
||||||
max_file_location_ = ${h.size_of_raw_data} + ${h.ptr_to_raw_data};
|
max_file_location_ = ${h.size_of_raw_data} + ${h.ptr_to_raw_data};
|
||||||
|
|
||||||
if ( ${h.virtual_addr} > 0 && ${h.virtual_addr} == import_table_rva_ )
|
if ( ${h.virtual_addr} > 0 && ${h.virtual_addr} <= import_table_rva_ && ( ${h.virtual_addr} + ${h.virtual_size} ) > import_table_rva_ )
|
||||||
import_table_va_ = ${h.ptr_to_raw_data};
|
import_table_va_ = ${h.ptr_to_raw_data} + (import_table_rva_ - ${h.virtual_addr});
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
|
|
@ -29,12 +29,12 @@ type import_lookup_table = record {
|
||||||
type import_entry(is_module: bool, pad_align: uint8) = record {
|
type import_entry(is_module: bool, pad_align: uint8) = record {
|
||||||
pad: bytestring &length=pad_align;
|
pad: bytestring &length=pad_align;
|
||||||
has_index: case is_module of {
|
has_index: case is_module of {
|
||||||
true -> null: empty;
|
true -> null: empty;
|
||||||
false -> index: uint16;
|
false -> index: uint16;
|
||||||
};
|
};
|
||||||
name: null_terminated_string;
|
name: null_terminated_string;
|
||||||
} &let {
|
} &let {
|
||||||
proc: bool = $context.connection.proc_import_hint(name);
|
proc_align: bool = $context.connection.proc_import_hint(name, is_module);
|
||||||
};
|
};
|
||||||
|
|
||||||
type idata = record {
|
type idata = record {
|
||||||
|
@ -63,6 +63,9 @@ refine connection MockConnection += {
|
||||||
uint32 next_hint_index_;
|
uint32 next_hint_index_;
|
||||||
uint8 next_hint_align_;
|
uint8 next_hint_align_;
|
||||||
bool next_hint_is_module_;
|
bool next_hint_is_module_;
|
||||||
|
|
||||||
|
// Track the module name, so we know what each import's for
|
||||||
|
bytestring module_name_;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%init{
|
%init{
|
||||||
|
@ -73,6 +76,12 @@ refine connection MockConnection += {
|
||||||
next_hint_is_module_ = true;
|
next_hint_is_module_ = true;
|
||||||
next_hint_index_ = 0;
|
next_hint_index_ = 0;
|
||||||
next_hint_align_ = 0;
|
next_hint_align_ = 0;
|
||||||
|
|
||||||
|
module_name_ = bytestring();
|
||||||
|
%}
|
||||||
|
|
||||||
|
%cleanup{
|
||||||
|
module_name_.free();
|
||||||
%}
|
%}
|
||||||
|
|
||||||
# When we read the section header, store the relative virtual address and
|
# When we read the section header, store the relative virtual address and
|
||||||
|
@ -101,10 +110,15 @@ refine connection MockConnection += {
|
||||||
%}
|
%}
|
||||||
|
|
||||||
# We need to calculate the length of the next padding field
|
# We need to calculate the length of the next padding field
|
||||||
function proc_import_hint(hint_name: bytestring): bool
|
function proc_import_hint(hint_name: bytestring, is_module: bool): bool
|
||||||
%{
|
%{
|
||||||
next_hint_align_ = ${hint_name}.length() % 2;
|
next_hint_align_ = ${hint_name}.length() % 2;
|
||||||
printf("Imported %s\n", ${hint_name}.data());
|
if ( is_module && ${hint_name}.length() > 1 )
|
||||||
|
{
|
||||||
|
module_name_.clear();
|
||||||
|
module_name_.init(${hint_name}.data(), ${hint_name}.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
@ -129,6 +143,11 @@ refine connection MockConnection += {
|
||||||
return next_hint_index_ == imports_per_module_.size();
|
return next_hint_index_ == imports_per_module_.size();
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
function get_module_name(): bytestring
|
||||||
|
%{
|
||||||
|
return module_name_;
|
||||||
|
%}
|
||||||
|
|
||||||
function get_import_table_addr(): uint32
|
function get_import_table_addr(): uint32
|
||||||
%{
|
%{
|
||||||
return import_table_va_ > 0 ? import_table_va_ : 0;
|
return import_table_va_ > 0 ? import_table_va_ : 0;
|
||||||
|
|
|
@ -35,4 +35,3 @@ type Padding(length: uint64) = record {
|
||||||
};
|
};
|
||||||
|
|
||||||
type null_terminated_string = RE/[A-Za-z0-9.]+\x00/;
|
type null_terminated_string = RE/[A-Za-z0-9.]+\x00/;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,12 @@
|
||||||
%include pe-file-idata.pac
|
%include pe-file-idata.pac
|
||||||
|
|
||||||
# The base record for a Portable Executable file
|
# The base record for a Portable Executable file
|
||||||
type PE_File = record {
|
type PE_File = case $context.connection.is_done() of {
|
||||||
|
false -> PE : Portable_Executable;
|
||||||
|
true -> overlay : bytestring &length=1 &transient;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Portable_Executable = record {
|
||||||
headers : Headers;
|
headers : Headers;
|
||||||
pad1 : Padding(iat_loc);
|
pad1 : Padding(iat_loc);
|
||||||
iat : idata &length=$context.connection.get_import_table_len();
|
iat : idata &length=$context.connection.get_import_table_len();
|
||||||
|
@ -12,5 +17,27 @@ type PE_File = record {
|
||||||
unparsed_hdr_len: uint32 = headers.pe_header.optional_header.size_of_headers - headers.length;
|
unparsed_hdr_len: uint32 = headers.pe_header.optional_header.size_of_headers - headers.length;
|
||||||
iat_loc: uint64 = $context.connection.get_import_table_addr() - headers.pe_header.optional_header.size_of_headers + unparsed_hdr_len;
|
iat_loc: uint64 = $context.connection.get_import_table_addr() - headers.pe_header.optional_header.size_of_headers + unparsed_hdr_len;
|
||||||
restofdata: uint64 = $context.connection.get_max_file_location() - $context.connection.get_import_table_addr() - $context.connection.get_import_table_len();
|
restofdata: uint64 = $context.connection.get_max_file_location() - $context.connection.get_import_table_addr() - $context.connection.get_import_table_len();
|
||||||
|
proc: bool = $context.connection.proc_pe(this);
|
||||||
} &byteorder=littleendian;
|
} &byteorder=littleendian;
|
||||||
|
|
||||||
|
refine connection MockConnection += {
|
||||||
|
|
||||||
|
%member{
|
||||||
|
bool done_;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%init{
|
||||||
|
done_ = false;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_pe(p: Portable_Executable): bool
|
||||||
|
%{
|
||||||
|
done_ = true;
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function is_done(): bool
|
||||||
|
%{
|
||||||
|
return done_;
|
||||||
|
%}
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue