mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 23:58:20 +00:00
Checkpoint - Import Address Table being parsed.
This commit is contained in:
parent
b4498a4142
commit
fa7946ae7d
4 changed files with 277 additions and 65 deletions
|
@ -39,15 +39,15 @@ hook set_file(f: fa_file) &priority=5
|
|||
|
||||
event pe_dos_header(f: fa_file, h: PE::DOSHeader) &priority=5
|
||||
{
|
||||
print "DOS header";
|
||||
print h;
|
||||
# print "DOS header";
|
||||
# print h;
|
||||
hook set_file(f);
|
||||
}
|
||||
|
||||
event pe_file_header(f: fa_file, h: PE::FileHeader) &priority=5
|
||||
{
|
||||
print "File header";
|
||||
print h;
|
||||
# print "File header";
|
||||
# print h;
|
||||
hook set_file(f);
|
||||
f$pe$compile_ts = h$ts;
|
||||
f$pe$machine = machine_types[h$machine];
|
||||
|
@ -57,8 +57,8 @@ event pe_file_header(f: fa_file, h: PE::FileHeader) &priority=5
|
|||
|
||||
event pe_optional_header(f: fa_file, h: PE::OptionalHeader) &priority=5
|
||||
{
|
||||
print "Optional header";
|
||||
print h;
|
||||
# print "Optional header";
|
||||
# print h;
|
||||
hook set_file(f);
|
||||
f$pe$os = os_versions[h$os_version_major, h$os_version_minor];
|
||||
f$pe$subsystem = windows_subsystems[h$subsystem];
|
||||
|
@ -66,11 +66,10 @@ event pe_optional_header(f: fa_file, h: PE::OptionalHeader) &priority=5
|
|||
|
||||
event pe_section_header(f: fa_file, h: PE::SectionHeader) &priority=5
|
||||
{
|
||||
print "Section header";
|
||||
print h;
|
||||
# print "Section header";
|
||||
# print h;
|
||||
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;
|
||||
|
|
|
@ -7,12 +7,6 @@
|
|||
|
||||
refine flow File += {
|
||||
|
||||
function proc_the_file(): bool
|
||||
%{
|
||||
printf("Processed\n");
|
||||
return true;
|
||||
%}
|
||||
|
||||
function characteristics_to_bro(c: uint32, len: uint8): TableVal
|
||||
%{
|
||||
uint64 mask = (len==16) ? 0xFFFF : 0xFFFFFFFF;
|
||||
|
@ -70,7 +64,7 @@ refine flow File += {
|
|||
return true;
|
||||
%}
|
||||
|
||||
function proc_nt_headers(h: IMAGE_NT_HEADERS): bool
|
||||
function proc_nt_headers(h: NT_Headers): bool
|
||||
%{
|
||||
if ( ${h.PESignature} != 17744 ) // Number is uint32 version of "PE\0\0"
|
||||
{
|
||||
|
@ -80,7 +74,7 @@ refine flow File += {
|
|||
return true;
|
||||
%}
|
||||
|
||||
function proc_file_header(h: IMAGE_FILE_HEADER): bool
|
||||
function proc_file_header(h: File_Header): bool
|
||||
%{
|
||||
if ( pe_file_header )
|
||||
{
|
||||
|
@ -98,7 +92,7 @@ refine flow File += {
|
|||
return true;
|
||||
%}
|
||||
|
||||
function proc_optional_header(h: IMAGE_OPTIONAL_HEADER): bool
|
||||
function proc_optional_header(h: Optional_Header): bool
|
||||
%{
|
||||
if ( ${h.magic} != 0x10b && // normal pe32 executable
|
||||
${h.magic} != 0x107 && // rom image
|
||||
|
@ -145,7 +139,7 @@ refine flow File += {
|
|||
return true;
|
||||
%}
|
||||
|
||||
function proc_section_header(h: IMAGE_SECTION_HEADER): bool
|
||||
function proc_section_header(h: Section_Header): bool
|
||||
%{
|
||||
if ( pe_section_header )
|
||||
{
|
||||
|
@ -176,6 +170,14 @@ refine flow File += {
|
|||
}
|
||||
return true;
|
||||
%}
|
||||
|
||||
|
||||
function proc_pe_file(): bool
|
||||
%{
|
||||
printf("PE file processed\n");
|
||||
return true;
|
||||
%}
|
||||
|
||||
};
|
||||
|
||||
refine typeattr DOS_Header += &let {
|
||||
|
@ -186,23 +188,23 @@ refine typeattr DOS_Code += &let {
|
|||
proc : bool = $context.flow.proc_dos_code(code);
|
||||
};
|
||||
|
||||
refine typeattr IMAGE_NT_HEADERS += &let {
|
||||
refine typeattr NT_Headers += &let {
|
||||
proc : bool = $context.flow.proc_nt_headers(this);
|
||||
};
|
||||
|
||||
refine typeattr IMAGE_FILE_HEADER += &let {
|
||||
refine typeattr File_Header += &let {
|
||||
proc : bool = $context.flow.proc_file_header(this);
|
||||
};
|
||||
|
||||
refine typeattr IMAGE_OPTIONAL_HEADER += &let {
|
||||
refine typeattr Optional_Header += &let {
|
||||
proc : bool = $context.flow.proc_optional_header(this);
|
||||
};
|
||||
|
||||
refine typeattr IMAGE_SECTION_HEADER += &let {
|
||||
proc: bool = $context.flow.proc_section_header(this);
|
||||
refine typeattr Section_Header += &let {
|
||||
proc2: bool = $context.flow.proc_section_header(this);
|
||||
};
|
||||
|
||||
refine typeattr TheFile += &let {
|
||||
proc: bool = $context.flow.proc_the_file();
|
||||
refine typeattr PE_File += &let {
|
||||
proc: bool = $context.flow.proc_pe_file();
|
||||
};
|
||||
|
||||
|
|
|
@ -1,17 +1,27 @@
|
|||
|
||||
type TheFile = record {
|
||||
dos_header : DOS_Header;
|
||||
dos_code : DOS_Code(dos_code_len);
|
||||
pe_header : IMAGE_NT_HEADERS;
|
||||
section_headers : IMAGE_SECTIONS(pe_header.file_header.NumberOfSections);
|
||||
#pad : bytestring &length=offsetof(pe_header.data_directories + pe_header.data_directories[1].virtual_address);
|
||||
#data_sections : DATA_SECTIONS[pe_header.file_header.NumberOfSections];
|
||||
#data_sections : DATA_SECTIONS[] &length=data_len;
|
||||
# The base record for a Portable Executable file
|
||||
type PE_File = record {
|
||||
headers : Headers;
|
||||
pad : Padding(iat_loc);
|
||||
iat : IMPORT_ADDRESS_TABLE &length=$context.connection.get_import_table_len();
|
||||
} &let {
|
||||
dos_code_len: uint32 = dos_header.AddressOfNewExeHeader - 64;
|
||||
data_len: uint32 = pe_header.optional_header.size_of_init_data;
|
||||
unparsed_hdr_len: uint32 = headers.pe_header.optional_header.size_of_headers - headers.length;
|
||||
iat_loc: uint32 = $context.connection.get_import_table_addr() - headers.pe_header.optional_header.size_of_headers + unparsed_hdr_len;
|
||||
|
||||
} &byteorder=littleendian;
|
||||
|
||||
## Headers
|
||||
|
||||
type Headers = record {
|
||||
dos_header : DOS_Header;
|
||||
dos_code : DOS_Code(dos_code_len);
|
||||
pe_header : NT_Headers;
|
||||
section_headers : Section_Headers(pe_header.file_header.NumberOfSections);
|
||||
} &let {
|
||||
dos_code_len: uint32 = dos_header.AddressOfNewExeHeader > 64 ? dos_header.AddressOfNewExeHeader - 64 : 0;
|
||||
length: uint64 = 64 + dos_code_len + pe_header.length + section_headers.length;
|
||||
};
|
||||
|
||||
# The DOS header gives us the offset of the NT headers
|
||||
type DOS_Header = record {
|
||||
signature : bytestring &length=2;
|
||||
UsedBytesInTheLastPage : uint16;
|
||||
|
@ -38,13 +48,17 @@ type DOS_Code(len: uint32) = record {
|
|||
code : bytestring &length=len;
|
||||
};
|
||||
|
||||
type IMAGE_NT_HEADERS = record {
|
||||
# The NT headers give us the file and the optional headers.
|
||||
type NT_Headers = record {
|
||||
PESignature : uint32;
|
||||
file_header : IMAGE_FILE_HEADER;
|
||||
optional_header : IMAGE_OPTIONAL_HEADER(file_header.SizeOfOptionalHeader, file_header.NumberOfSections) &length=file_header.SizeOfOptionalHeader;
|
||||
} &byteorder=littleendian &length=file_header.SizeOfOptionalHeader+offsetof(optional_header);
|
||||
file_header : File_Header;
|
||||
optional_header : Optional_Header(file_header.SizeOfOptionalHeader, file_header.NumberOfSections) &length=file_header.SizeOfOptionalHeader;
|
||||
} &let {
|
||||
length: uint32 = file_header.SizeOfOptionalHeader+offsetof(optional_header);
|
||||
} &byteorder=littleendian &length=length;
|
||||
|
||||
type IMAGE_FILE_HEADER = record {
|
||||
# The file header is mainly self-describing
|
||||
type File_Header = record {
|
||||
Machine : uint16;
|
||||
NumberOfSections : uint16;
|
||||
TimeDateStamp : uint32;
|
||||
|
@ -54,7 +68,8 @@ type IMAGE_FILE_HEADER = record {
|
|||
Characteristics : uint16;
|
||||
};
|
||||
|
||||
type IMAGE_OPTIONAL_HEADER(len: uint16, number_of_sections: uint16) = record {
|
||||
# The optional header gives us DLL link information, and some structural information
|
||||
type Optional_Header(len: uint16, number_of_sections: uint16) = record {
|
||||
magic : uint16;
|
||||
major_linker_version : uint8;
|
||||
minor_linker_version : uint8;
|
||||
|
@ -80,34 +95,47 @@ type IMAGE_OPTIONAL_HEADER(len: uint16, number_of_sections: uint16) = record {
|
|||
subsystem : uint16;
|
||||
dll_characteristics : uint16;
|
||||
mem: case magic of {
|
||||
267 -> i32 : MEM_INFO32;
|
||||
268 -> i64 : MEM_INFO64;
|
||||
267 -> i32 : Mem_Info32;
|
||||
268 -> i64 : Mem_Info64;
|
||||
default -> InvalidPEFile : empty;
|
||||
};
|
||||
loader_flags : uint32;
|
||||
number_of_rva_and_sizes : uint32;
|
||||
rvas : IMAGE_RVAS(number_of_rva_and_sizes);
|
||||
rvas : RVAS(number_of_rva_and_sizes);
|
||||
} &byteorder=littleendian &length=len;
|
||||
|
||||
type MEM_INFO32 = 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;
|
||||
|
||||
type MEM_INFO64 = record {
|
||||
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_SECTIONS(num: uint16) = record {
|
||||
sections : IMAGE_SECTION_HEADER[num];
|
||||
} &length=num*40;
|
||||
type RVAS(num: uint32) = record {
|
||||
rvas : RVA[num];
|
||||
};
|
||||
|
||||
type IMAGE_SECTION_HEADER = record {
|
||||
type RVA = record {
|
||||
virtual_address : uint32;
|
||||
size : uint32;
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_rva(this);
|
||||
} &length=8;
|
||||
|
||||
type Section_Headers(num: uint16) = record {
|
||||
sections : Section_Header[num];
|
||||
} &let {
|
||||
length: uint32 = num*40;
|
||||
} &length=length;
|
||||
|
||||
type Section_Header = record {
|
||||
name : bytestring &length=8;
|
||||
virtual_size : uint32;
|
||||
virtual_addr : uint32;
|
||||
|
@ -118,31 +146,214 @@ type IMAGE_SECTION_HEADER = record {
|
|||
non_used_num_of_relocs : uint16;
|
||||
non_used_num_of_line_nums : uint16;
|
||||
characteristics : uint32;
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_section(this);
|
||||
} &byteorder=littleendian &length=40;
|
||||
|
||||
## The BinPAC padding type doens't work here.
|
||||
|
||||
type IMAGE_DATA_DIRECTORY = record {
|
||||
virtual_address : uint32;
|
||||
size : uint16;
|
||||
type Padding(length: uint32) = record {
|
||||
blah: bytestring &length=length &transient;
|
||||
};
|
||||
|
||||
## Support for parsing the .idata section
|
||||
|
||||
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;
|
||||
} &let {
|
||||
is_null: bool = rva_module_name == 0;
|
||||
proc: bool = $context.connection.proc_image_import_directory(this);
|
||||
} &length=20;
|
||||
|
||||
type IMPORT_LOOKUP_ATTRS = record {
|
||||
attrs: uint32;
|
||||
} &let {
|
||||
is_null: bool = attrs == 0;
|
||||
} &length=4;
|
||||
|
||||
type IMPORT_LOOKUP_TABLE = record {
|
||||
attrs: IMPORT_LOOKUP_ATTRS[] &until($element.is_null);
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_import_lookup_table(this);
|
||||
};
|
||||
|
||||
type IMAGE_RVAS(num: uint32) = record {
|
||||
rvas : IMAGE_RVA[num];
|
||||
} &length=num*8;
|
||||
#type null_terminated_string = RE/[^\x00]+\x00/;
|
||||
type null_terminated_string = RE/[A-Za-z0-9.]+\x00/;
|
||||
|
||||
type IMAGE_RVA = record {
|
||||
virtual_address : uint32;
|
||||
size : uint32;
|
||||
} &length=8;
|
||||
|
||||
type DATA_SECTIONS = record {
|
||||
blah: uint8;
|
||||
type IMPORT_ENTRY(is_module: bool, pad_align: uint8) = case is_module of {
|
||||
true -> module: IMPORT_MODULE(pad_align);
|
||||
false -> hint: IMPORT_HINT(pad_align);
|
||||
};
|
||||
|
||||
type IMPORT_MODULE(pad_align: uint8) = record {
|
||||
pad: bytestring &length=pad_align;
|
||||
name: null_terminated_string;
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_import_module(this);
|
||||
};
|
||||
|
||||
type IMPORT_HINT(pad_align: uint8) = record {
|
||||
pad: bytestring &length=pad_align;
|
||||
index: uint16;
|
||||
name: null_terminated_string;
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_import_hint(this);
|
||||
last: bool = sizeof(name) == 0;
|
||||
};
|
||||
|
||||
type IMPORT_ADDRESS_TABLE = record {
|
||||
directory_table : IMAGE_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());
|
||||
} &let {
|
||||
proc: bool = $context.connection.proc_iat(this);
|
||||
};
|
||||
|
||||
refine connection MockConnection += {
|
||||
%member{
|
||||
uint8 rvas_seen_;
|
||||
uint8 num_imports_;
|
||||
uint32 rva_offset_;
|
||||
|
||||
bool has_import_table_;
|
||||
uint32 import_table_va_;
|
||||
uint32 import_table_rva_;
|
||||
uint32 import_table_len_;
|
||||
vector<uint32> imports_per_module_;
|
||||
uint32 next_hint_index_;
|
||||
uint8 next_hint_align_;
|
||||
bool next_hint_is_module_;
|
||||
|
||||
bool has_export_table_;
|
||||
uint32 export_table_va_;
|
||||
uint32 export_table_rva_;
|
||||
%}
|
||||
|
||||
%init{
|
||||
rvas_seen_ = 0;
|
||||
rva_offset_ = 0;
|
||||
num_imports_ = -1;
|
||||
has_import_table_ = false;
|
||||
has_export_table_ = false;
|
||||
|
||||
next_hint_is_module_ = true;
|
||||
next_hint_index_ = 0;
|
||||
next_hint_align_ = 0;
|
||||
%}
|
||||
|
||||
function proc_rva(r: RVA): bool
|
||||
%{
|
||||
if ( rvas_seen_ == 1 )
|
||||
{
|
||||
has_import_table_ = ${r.virtual_address} > 0;
|
||||
if ( has_import_table_ ) {
|
||||
import_table_rva_ = ${r.virtual_address};
|
||||
import_table_len_ = ${r.size};
|
||||
}
|
||||
}
|
||||
if ( rvas_seen_ == 2 )
|
||||
{
|
||||
has_export_table_ = ${r.virtual_address} > 0;
|
||||
if ( has_export_table_ )
|
||||
export_table_rva_ = ${r.virtual_address};
|
||||
}
|
||||
++rvas_seen_;
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_section(h: Section_Header): bool
|
||||
%{
|
||||
if ( has_import_table_ && ${h.virtual_addr} == import_table_rva_ ){
|
||||
printf("Found import table %d\n", ${h.ptr_to_raw_data});
|
||||
rva_offset_ = ${h.virtual_addr} - ${h.ptr_to_raw_data};
|
||||
|
||||
import_table_va_ = ${h.ptr_to_raw_data};
|
||||
get_import_table_addr();
|
||||
}
|
||||
if ( has_export_table_ && ${h.virtual_addr} == export_table_rva_ )
|
||||
export_table_va_ = ${h.ptr_to_raw_data};
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_image_import_directory(i: IMAGE_IMPORT_DIRECTORY): bool
|
||||
%{
|
||||
num_imports_++;
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_iat(i: IMPORT_ADDRESS_TABLE): bool
|
||||
%{
|
||||
printf("IAT processed\n");
|
||||
return true;
|
||||
%}
|
||||
|
||||
function get_import_table_addr(): uint32
|
||||
%{
|
||||
return has_import_table_ ? import_table_va_ : 0;
|
||||
%}
|
||||
|
||||
function get_import_table_len(): uint32
|
||||
%{
|
||||
return has_import_table_ ? import_table_len_ : 0;
|
||||
%}
|
||||
|
||||
function get_rva_offset(): uint32
|
||||
%{
|
||||
return rva_offset_;
|
||||
%}
|
||||
|
||||
function get_num_imports(): uint8
|
||||
%{
|
||||
return num_imports_;
|
||||
%}
|
||||
|
||||
function get_next_hint_align(): uint8
|
||||
%{
|
||||
return next_hint_align_;
|
||||
%}
|
||||
|
||||
function proc_import_lookup_table(t: IMPORT_LOOKUP_TABLE): bool
|
||||
%{
|
||||
--num_imports_;
|
||||
imports_per_module_.push_back(${t.attrs}->size());
|
||||
return true;
|
||||
%}
|
||||
|
||||
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 proc_import_hint(h: IMPORT_HINT): bool
|
||||
%{
|
||||
printf(" Imported function '%s'\n", ${h.name}.data());
|
||||
next_hint_align_ = ${h.name}.length() % 2;
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_import_module(m: IMPORT_MODULE): bool
|
||||
%{
|
||||
printf("Imported module '%s'\n", ${m.name}.data());
|
||||
next_hint_align_ = ${m.name}.length() % 2;
|
||||
return true;
|
||||
%}
|
||||
};
|
|
@ -14,7 +14,7 @@ connection MockConnection(bro_analyzer: BroFileAnalyzer) {
|
|||
%include pe-file.pac
|
||||
|
||||
flow File {
|
||||
flowunit = TheFile withcontext(connection, this);
|
||||
flowunit = PE_File withcontext(connection, this);
|
||||
}
|
||||
|
||||
%include pe-analyzer.pac
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue