mirror of
https://github.com/zeek/zeek.git
synced 2025-10-05 08:08:19 +00:00
PE Analyzer cleanup.
This commit is contained in:
parent
fa7946ae7d
commit
575e22cfe7
4 changed files with 296 additions and 350 deletions
114
src/file_analysis/analyzer/pe/pe-file-headers.pac
Normal file
114
src/file_analysis/analyzer/pe/pe-file-headers.pac
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
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;
|
||||||
|
FileSizeInPages : uint16;
|
||||||
|
NumberOfRelocationItems : uint16;
|
||||||
|
HeaderSizeInParagraphs : uint16;
|
||||||
|
MinimumExtraParagraphs : uint16;
|
||||||
|
MaximumExtraParagraphs : uint16;
|
||||||
|
InitialRelativeSS : uint16;
|
||||||
|
InitialSP : uint16;
|
||||||
|
Checksum : uint16;
|
||||||
|
InitialIP : uint16;
|
||||||
|
InitialRelativeCS : uint16;
|
||||||
|
AddressOfRelocationTable : uint16;
|
||||||
|
OverlayNumber : uint16;
|
||||||
|
Reserved : uint16[4];
|
||||||
|
OEMid : uint16;
|
||||||
|
OEMinfo : uint16;
|
||||||
|
Reserved2 : uint16[10];
|
||||||
|
AddressOfNewExeHeader : uint32;
|
||||||
|
} &length=64;
|
||||||
|
|
||||||
|
type DOS_Code(len: uint32) = record {
|
||||||
|
code : bytestring &length=len;
|
||||||
|
};
|
||||||
|
|
||||||
|
# The NT headers give us the file and the optional headers.
|
||||||
|
type NT_Headers = record {
|
||||||
|
PESignature : uint32;
|
||||||
|
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);
|
||||||
|
} &length=length;
|
||||||
|
|
||||||
|
# The file header is mainly self-describing
|
||||||
|
type File_Header = record {
|
||||||
|
Machine : uint16;
|
||||||
|
NumberOfSections : uint16;
|
||||||
|
TimeDateStamp : uint32;
|
||||||
|
PointerToSymbolTable : uint32;
|
||||||
|
NumberOfSymbols : uint32;
|
||||||
|
SizeOfOptionalHeader : uint16;
|
||||||
|
Characteristics : uint16;
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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;
|
||||||
|
size_of_code : uint32;
|
||||||
|
size_of_init_data : uint32;
|
||||||
|
size_of_uninit_data : uint32;
|
||||||
|
addr_of_entry_point : uint32;
|
||||||
|
base_of_code : uint32;
|
||||||
|
base_of_data : uint32;
|
||||||
|
image_base : uint32;
|
||||||
|
section_alignment : uint32;
|
||||||
|
file_alignment : uint32;
|
||||||
|
os_version_major : uint16;
|
||||||
|
os_version_minor : uint16;
|
||||||
|
major_image_version : uint16;
|
||||||
|
minor_image_version : uint16;
|
||||||
|
major_subsys_version : uint16;
|
||||||
|
minor_subsys_version : uint16;
|
||||||
|
win32_version : uint32;
|
||||||
|
size_of_image : uint32;
|
||||||
|
size_of_headers : uint32;
|
||||||
|
checksum : uint32;
|
||||||
|
subsystem : uint16;
|
||||||
|
dll_characteristics : uint16;
|
||||||
|
mem: case magic of {
|
||||||
|
267 -> i32 : Mem_Info32;
|
||||||
|
268 -> i64 : Mem_Info64;
|
||||||
|
default -> InvalidPEFile : empty;
|
||||||
|
};
|
||||||
|
loader_flags : uint32;
|
||||||
|
number_of_rva_and_sizes : uint32;
|
||||||
|
rvas : RVAS(number_of_rva_and_sizes);
|
||||||
|
} &length=len;
|
||||||
|
|
||||||
|
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;
|
||||||
|
size_of_raw_data : uint32;
|
||||||
|
ptr_to_raw_data : uint32;
|
||||||
|
non_used_ptr_to_relocs : uint32;
|
||||||
|
non_used_ptr_to_line_nums : uint32;
|
||||||
|
non_used_num_of_relocs : uint16;
|
||||||
|
non_used_num_of_line_nums : uint16;
|
||||||
|
characteristics : uint32;
|
||||||
|
} &let {
|
||||||
|
proc: bool = $context.connection.proc_section(this);
|
||||||
|
} &length=40;
|
||||||
|
|
145
src/file_analysis/analyzer/pe/pe-file-idata.pac
Normal file
145
src/file_analysis/analyzer/pe/pe-file-idata.pac
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
## 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 = record {
|
||||||
|
attrs: uint32;
|
||||||
|
} &length=4;
|
||||||
|
|
||||||
|
type import_lookup_table = record {
|
||||||
|
attrs: import_lookup_attrs[] &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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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: 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_;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%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;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_idata_rva(r: RVA): bool
|
||||||
|
%{
|
||||||
|
import_table_rva_ = ${r.virtual_address};
|
||||||
|
import_table_len_ = ${r.size};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_section(h: Section_Header): bool
|
||||||
|
%{
|
||||||
|
if ( ${h.virtual_addr} > 0 && ${h.virtual_addr} == import_table_rva_ )
|
||||||
|
import_table_va_ = ${h.ptr_to_raw_data};
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_image_import_directory(i: import_directory): bool
|
||||||
|
%{
|
||||||
|
num_imports_++;
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
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_;
|
||||||
|
%}
|
||||||
|
|
||||||
|
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(hint_name: bytestring): bool
|
||||||
|
%{
|
||||||
|
next_hint_align_ = ${hint_name}.length() % 2;
|
||||||
|
printf("Import function: %s\n", ${hint_name}.data());
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
};
|
32
src/file_analysis/analyzer/pe/pe-file-types.pac
Normal file
32
src/file_analysis/analyzer/pe/pe-file-types.pac
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# Basic PE types
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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 RVAS(num: uint32) = record {
|
||||||
|
rvas : RVA[num];
|
||||||
|
};
|
||||||
|
|
||||||
|
type RVA = record {
|
||||||
|
virtual_address : uint32;
|
||||||
|
size : uint32;
|
||||||
|
} &length=8;
|
||||||
|
|
||||||
|
# The BinPAC padding type doesn't work here.
|
||||||
|
type Padding(length: uint32) = record {
|
||||||
|
pad: bytestring &length=length &transient;
|
||||||
|
};
|
||||||
|
|
||||||
|
type null_terminated_string = RE/[A-Za-z0-9.]+\x00/;
|
||||||
|
|
|
@ -1,359 +1,14 @@
|
||||||
|
%include pe-file-types.pac
|
||||||
|
%include pe-file-headers.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 = record {
|
||||||
headers : Headers;
|
headers : Headers;
|
||||||
pad : Padding(iat_loc);
|
pad : Padding(iat_loc);
|
||||||
iat : IMPORT_ADDRESS_TABLE &length=$context.connection.get_import_table_len();
|
iat : idata &length=$context.connection.get_import_table_len();
|
||||||
} &let {
|
} &let {
|
||||||
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: uint32 = $context.connection.get_import_table_addr() - headers.pe_header.optional_header.size_of_headers + unparsed_hdr_len;
|
iat_loc: uint32 = $context.connection.get_import_table_addr() - headers.pe_header.optional_header.size_of_headers + unparsed_hdr_len;
|
||||||
|
|
||||||
} &byteorder=littleendian;
|
} &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;
|
|
||||||
FileSizeInPages : uint16;
|
|
||||||
NumberOfRelocationItems : uint16;
|
|
||||||
HeaderSizeInParagraphs : uint16;
|
|
||||||
MinimumExtraParagraphs : uint16;
|
|
||||||
MaximumExtraParagraphs : uint16;
|
|
||||||
InitialRelativeSS : uint16;
|
|
||||||
InitialSP : uint16;
|
|
||||||
Checksum : uint16;
|
|
||||||
InitialIP : uint16;
|
|
||||||
InitialRelativeCS : uint16;
|
|
||||||
AddressOfRelocationTable : uint16;
|
|
||||||
OverlayNumber : uint16;
|
|
||||||
Reserved : uint16[4];
|
|
||||||
OEMid : uint16;
|
|
||||||
OEMinfo : uint16;
|
|
||||||
Reserved2 : uint16[10];
|
|
||||||
AddressOfNewExeHeader : uint32;
|
|
||||||
} &byteorder=littleendian &length=64;
|
|
||||||
|
|
||||||
type DOS_Code(len: uint32) = record {
|
|
||||||
code : bytestring &length=len;
|
|
||||||
};
|
|
||||||
|
|
||||||
# The NT headers give us the file and the optional headers.
|
|
||||||
type NT_Headers = record {
|
|
||||||
PESignature : uint32;
|
|
||||||
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;
|
|
||||||
|
|
||||||
# The file header is mainly self-describing
|
|
||||||
type File_Header = record {
|
|
||||||
Machine : uint16;
|
|
||||||
NumberOfSections : uint16;
|
|
||||||
TimeDateStamp : uint32;
|
|
||||||
PointerToSymbolTable : uint32;
|
|
||||||
NumberOfSymbols : uint32;
|
|
||||||
SizeOfOptionalHeader : uint16;
|
|
||||||
Characteristics : uint16;
|
|
||||||
};
|
|
||||||
|
|
||||||
# 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;
|
|
||||||
size_of_code : uint32;
|
|
||||||
size_of_init_data : uint32;
|
|
||||||
size_of_uninit_data : uint32;
|
|
||||||
addr_of_entry_point : uint32;
|
|
||||||
base_of_code : uint32;
|
|
||||||
base_of_data : uint32;
|
|
||||||
image_base : uint32;
|
|
||||||
section_alignment : uint32;
|
|
||||||
file_alignment : uint32;
|
|
||||||
os_version_major : uint16;
|
|
||||||
os_version_minor : uint16;
|
|
||||||
major_image_version : uint16;
|
|
||||||
minor_image_version : uint16;
|
|
||||||
major_subsys_version : uint16;
|
|
||||||
minor_subsys_version : uint16;
|
|
||||||
win32_version : uint32;
|
|
||||||
size_of_image : uint32;
|
|
||||||
size_of_headers : uint32;
|
|
||||||
checksum : uint32;
|
|
||||||
subsystem : uint16;
|
|
||||||
dll_characteristics : uint16;
|
|
||||||
mem: case magic of {
|
|
||||||
267 -> i32 : Mem_Info32;
|
|
||||||
268 -> i64 : Mem_Info64;
|
|
||||||
default -> InvalidPEFile : empty;
|
|
||||||
};
|
|
||||||
loader_flags : uint32;
|
|
||||||
number_of_rva_and_sizes : uint32;
|
|
||||||
rvas : RVAS(number_of_rva_and_sizes);
|
|
||||||
} &byteorder=littleendian &length=len;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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 RVAS(num: uint32) = record {
|
|
||||||
rvas : RVA[num];
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
size_of_raw_data : uint32;
|
|
||||||
ptr_to_raw_data : uint32;
|
|
||||||
non_used_ptr_to_relocs : uint32;
|
|
||||||
non_used_ptr_to_line_nums : uint32;
|
|
||||||
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 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 null_terminated_string = RE/[^\x00]+\x00/;
|
|
||||||
type null_terminated_string = RE/[A-Za-z0-9.]+\x00/;
|
|
||||||
|
|
||||||
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;
|
|
||||||
%}
|
|
||||||
};
|
|
Loading…
Add table
Add a link
Reference in a new issue