mirror of
https://github.com/zeek/zeek.git
synced 2025-10-15 04:58:21 +00:00
Moving the PE analyzer to the new plugin structure.
This commit is contained in:
parent
998cedb3b8
commit
1e098bae8d
6 changed files with 13 additions and 8 deletions
45
src/file_analysis/analyzer/pe/PE.cc
Normal file
45
src/file_analysis/analyzer/pe/PE.cc
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include <string>
|
||||
|
||||
#include "PE.h"
|
||||
#include "pe_pac.h"
|
||||
#include "util.h"
|
||||
#include "Event.h"
|
||||
|
||||
using namespace file_analysis;
|
||||
|
||||
PE::PE(RecordVal* args, File* file)
|
||||
: file_analysis::Analyzer(args, file)
|
||||
{
|
||||
conn = new binpac::PE::MockConnection(this);
|
||||
interp = new binpac::PE::File(conn);
|
||||
done=false;
|
||||
}
|
||||
|
||||
PE::~PE()
|
||||
{
|
||||
delete interp;
|
||||
}
|
||||
|
||||
bool PE::DeliverStream(const u_char* data, uint64 len)
|
||||
{
|
||||
try
|
||||
{
|
||||
interp->NewData(data, data + len);
|
||||
}
|
||||
catch ( const binpac::HaltParser &e )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch ( const binpac::Exception& e )
|
||||
{
|
||||
printf("Binpac exception: %s\n", e.c_msg());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PE::EndOfFile()
|
||||
{
|
||||
return false;
|
||||
}
|
35
src/file_analysis/analyzer/pe/PE.h
Normal file
35
src/file_analysis/analyzer/pe/PE.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef FILE_ANALYSIS_PE_H
|
||||
#define FILE_ANALYSIS_PE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Val.h"
|
||||
#include "../File.h"
|
||||
#include "pe_pac.h"
|
||||
|
||||
namespace file_analysis {
|
||||
|
||||
/**
|
||||
* An action to simply extract files to disk.
|
||||
*/
|
||||
class PE : public file_analysis::Analyzer {
|
||||
public:
|
||||
~PE();
|
||||
|
||||
static file_analysis::Analyzer* Instantiate(RecordVal* args, File* file)
|
||||
{ return new PE(args, file); }
|
||||
|
||||
virtual bool DeliverStream(const u_char* data, uint64 len);
|
||||
|
||||
virtual bool EndOfFile();
|
||||
|
||||
protected:
|
||||
PE(RecordVal* args, File* file);
|
||||
binpac::PE::File* interp;
|
||||
binpac::PE::MockConnection* conn;
|
||||
bool done;
|
||||
};
|
||||
|
||||
} // namespace file_analysis
|
||||
|
||||
#endif
|
5
src/file_analysis/analyzer/pe/events.bif
Normal file
5
src/file_analysis/analyzer/pe/events.bif
Normal file
|
@ -0,0 +1,5 @@
|
|||
event pe_dos_header%(f: fa_file, h: PE::DOSHeader%);
|
||||
event pe_dos_code%(f: fa_file, code: string%);
|
||||
event pe_file_header%(f: fa_file, h: PE::FileHeader%);
|
||||
event pe_optional_header%(f: fa_file, h: PE::OptionalHeader%);
|
||||
event pe_section_header%(f: fa_file, h: PE::SectionHeader%);
|
207
src/file_analysis/analyzer/pe/pe-analyzer.pac
Normal file
207
src/file_analysis/analyzer/pe/pe-analyzer.pac
Normal file
|
@ -0,0 +1,207 @@
|
|||
|
||||
%extern{
|
||||
#include "Event.h"
|
||||
#include "file_analysis/File.h"
|
||||
#include "file_analysis.bif.func_h"
|
||||
%}
|
||||
|
||||
refine flow File += {
|
||||
|
||||
function proc_the_file(): bool
|
||||
%{
|
||||
throw binpac::HaltParser();
|
||||
return true;
|
||||
%}
|
||||
|
||||
function characteristics_to_bro(c: uint32, len: uint8): TableVal
|
||||
%{
|
||||
uint64 mask = (len==16) ? 0xFFFF : 0xFFFFFFFF;
|
||||
TableVal* char_set = new TableVal(internal_type("count_set")->AsTableType());
|
||||
for ( uint16 i=0; i < len; ++i )
|
||||
{
|
||||
if ( ((c >> i) & 0x1) == 1 )
|
||||
{
|
||||
Val *ch = new Val((1<<i)&mask, TYPE_COUNT);
|
||||
char_set->Assign(ch, 0);
|
||||
Unref(ch);
|
||||
}
|
||||
}
|
||||
return char_set;
|
||||
%}
|
||||
|
||||
function proc_dos_header(h: DOS_Header): bool
|
||||
%{
|
||||
if ( pe_dos_header )
|
||||
{
|
||||
RecordVal* dh = new RecordVal(BifType::Record::PE::DOSHeader);
|
||||
dh->Assign(0, new StringVal(${h.signature}.length(), (const char*) ${h.signature}.data()));
|
||||
dh->Assign(1, new Val(${h.UsedBytesInTheLastPage}, TYPE_COUNT));
|
||||
dh->Assign(2, new Val(${h.FileSizeInPages}, TYPE_COUNT));
|
||||
dh->Assign(3, new Val(${h.NumberOfRelocationItems}, TYPE_COUNT));
|
||||
dh->Assign(4, new Val(${h.HeaderSizeInParagraphs}, TYPE_COUNT));
|
||||
dh->Assign(5, new Val(${h.MinimumExtraParagraphs}, TYPE_COUNT));
|
||||
dh->Assign(6, new Val(${h.MaximumExtraParagraphs}, TYPE_COUNT));
|
||||
dh->Assign(7, new Val(${h.InitialRelativeSS}, TYPE_COUNT));
|
||||
dh->Assign(8, new Val(${h.InitialSP}, TYPE_COUNT));
|
||||
dh->Assign(9, new Val(${h.Checksum}, TYPE_COUNT));
|
||||
dh->Assign(10, new Val(${h.InitialIP}, TYPE_COUNT));
|
||||
dh->Assign(11, new Val(${h.InitialRelativeCS}, TYPE_COUNT));
|
||||
dh->Assign(12, new Val(${h.AddressOfRelocationTable}, TYPE_COUNT));
|
||||
dh->Assign(13, new Val(${h.OverlayNumber}, TYPE_COUNT));
|
||||
dh->Assign(14, new Val(${h.OEMid}, TYPE_COUNT));
|
||||
dh->Assign(15, new Val(${h.OEMinfo}, TYPE_COUNT));
|
||||
dh->Assign(16, new Val(${h.AddressOfNewExeHeader}, TYPE_COUNT));
|
||||
|
||||
BifEvent::generate_pe_dos_header((Analyzer *) connection()->bro_analyzer(),
|
||||
connection()->bro_analyzer()->GetFile()->GetVal()->Ref(),
|
||||
dh);
|
||||
}
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_dos_code(code: bytestring): bool
|
||||
%{
|
||||
if ( pe_dos_code )
|
||||
{
|
||||
BifEvent::generate_pe_dos_code((Analyzer *) connection()->bro_analyzer(),
|
||||
connection()->bro_analyzer()->GetFile()->GetVal()->Ref(),
|
||||
new StringVal(code.length(), (const char*) code.data()));
|
||||
}
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_nt_headers(h: IMAGE_NT_HEADERS): bool
|
||||
%{
|
||||
if ( ${h.PESignature} != 17744 ) // Number is uint32 version of "PE\0\0"
|
||||
{
|
||||
return false;
|
||||
// FileViolation("PE Header signature is incorrect.");
|
||||
}
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_file_header(h: IMAGE_FILE_HEADER): bool
|
||||
%{
|
||||
if ( pe_file_header )
|
||||
{
|
||||
RecordVal* fh = new RecordVal(BifType::Record::PE::FileHeader);
|
||||
fh->Assign(0, new Val(${h.Machine}, TYPE_COUNT));
|
||||
fh->Assign(1, new Val(static_cast<double>(${h.TimeDateStamp}), TYPE_TIME));
|
||||
fh->Assign(2, new Val(${h.PointerToSymbolTable}, TYPE_COUNT));
|
||||
fh->Assign(3, new Val(${h.NumberOfSymbols}, TYPE_COUNT));
|
||||
fh->Assign(4, characteristics_to_bro(${h.Characteristics}, 16));
|
||||
BifEvent::generate_pe_file_header((Analyzer *) connection()->bro_analyzer(),
|
||||
connection()->bro_analyzer()->GetFile()->GetVal()->Ref(),
|
||||
fh);
|
||||
}
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_optional_header(h: IMAGE_OPTIONAL_HEADER): bool
|
||||
%{
|
||||
if ( ${h.magic} != 0x10b && // normal pe32 executable
|
||||
${h.magic} != 0x107 && // rom image
|
||||
${h.magic} != 0x20b ) // pe32+ executable
|
||||
{
|
||||
return false;
|
||||
// FileViolation("PE Optional Header magic is invalid.");
|
||||
}
|
||||
|
||||
if ( pe_optional_header )
|
||||
{
|
||||
RecordVal* oh = new RecordVal(BifType::Record::PE::OptionalHeader);
|
||||
|
||||
oh->Assign(0, new Val(${h.magic}, TYPE_COUNT));
|
||||
oh->Assign(1, new Val(${h.major_linker_version}, TYPE_COUNT));
|
||||
oh->Assign(2, new Val(${h.minor_linker_version}, TYPE_COUNT));
|
||||
oh->Assign(3, new Val(${h.size_of_code}, TYPE_COUNT));
|
||||
oh->Assign(4, new Val(${h.size_of_init_data}, TYPE_COUNT));
|
||||
oh->Assign(5, new Val(${h.size_of_uninit_data}, TYPE_COUNT));
|
||||
oh->Assign(6, new Val(${h.addr_of_entry_point}, TYPE_COUNT));
|
||||
oh->Assign(7, new Val(${h.base_of_code}, TYPE_COUNT));
|
||||
oh->Assign(8, new Val(${h.base_of_data}, TYPE_COUNT));
|
||||
oh->Assign(9, new Val(${h.image_base}, TYPE_COUNT));
|
||||
oh->Assign(10, new Val(${h.section_alignment}, TYPE_COUNT));
|
||||
oh->Assign(11, new Val(${h.file_alignment}, TYPE_COUNT));
|
||||
oh->Assign(12, new Val(${h.os_version_major}, TYPE_COUNT));
|
||||
oh->Assign(13, new Val(${h.os_version_minor}, TYPE_COUNT));
|
||||
oh->Assign(14, new Val(${h.major_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(17, new Val(${h.minor_subsys_version}, TYPE_COUNT));
|
||||
oh->Assign(18, new Val(${h.win32_version}, TYPE_COUNT));
|
||||
oh->Assign(19, new Val(${h.size_of_image}, TYPE_COUNT));
|
||||
oh->Assign(20, new Val(${h.size_of_headers}, TYPE_COUNT));
|
||||
oh->Assign(21, new Val(${h.checksum}, TYPE_COUNT));
|
||||
oh->Assign(22, new Val(${h.subsystem}, TYPE_COUNT));
|
||||
oh->Assign(23, characteristics_to_bro(${h.dll_characteristics}, 16));
|
||||
oh->Assign(24, new Val(${h.loader_flags}, TYPE_COUNT));
|
||||
oh->Assign(25, new Val(${h.number_of_rva_and_sizes}, TYPE_COUNT));
|
||||
BifEvent::generate_pe_optional_header((Analyzer *) connection()->bro_analyzer(),
|
||||
connection()->bro_analyzer()->GetFile()->GetVal()->Ref(),
|
||||
oh);
|
||||
}
|
||||
return true;
|
||||
%}
|
||||
|
||||
function proc_section_header(h: IMAGE_SECTION_HEADER): bool
|
||||
%{
|
||||
if ( pe_section_header )
|
||||
{
|
||||
RecordVal* section_header = new RecordVal(BifType::Record::PE::SectionHeader);
|
||||
|
||||
// Strip null characters from the end of the section name.
|
||||
u_char* first_null = (u_char*) memchr(${h.name}.data(), 0, ${h.name}.length());
|
||||
uint16 name_len;
|
||||
if ( first_null == NULL )
|
||||
name_len = ${h.name}.length();
|
||||
else
|
||||
name_len = first_null - ${h.name}.data();
|
||||
section_header->Assign(0, new StringVal(name_len, (const char*) ${h.name}.data()));
|
||||
|
||||
section_header->Assign(1, new Val(${h.virtual_size}, TYPE_COUNT));
|
||||
section_header->Assign(2, new Val(${h.virtual_addr}, TYPE_COUNT));
|
||||
section_header->Assign(3, new Val(${h.size_of_raw_data}, TYPE_COUNT));
|
||||
section_header->Assign(4, new Val(${h.ptr_to_raw_data}, TYPE_COUNT));
|
||||
section_header->Assign(5, new Val(${h.non_used_ptr_to_relocs}, TYPE_COUNT));
|
||||
section_header->Assign(6, new Val(${h.non_used_ptr_to_line_nums}, TYPE_COUNT));
|
||||
section_header->Assign(7, new Val(${h.non_used_num_of_relocs}, TYPE_COUNT));
|
||||
section_header->Assign(8, new Val(${h.non_used_num_of_line_nums}, TYPE_COUNT));
|
||||
section_header->Assign(9, characteristics_to_bro(${h.characteristics}, 32));
|
||||
|
||||
BifEvent::generate_pe_section_header((Analyzer *) connection()->bro_analyzer(),
|
||||
connection()->bro_analyzer()->GetFile()->GetVal()->Ref(),
|
||||
section_header);
|
||||
}
|
||||
return true;
|
||||
%}
|
||||
};
|
||||
|
||||
refine typeattr DOS_Header += &let {
|
||||
proc : bool = $context.flow.proc_dos_header(this);
|
||||
};
|
||||
|
||||
refine typeattr DOS_Code += &let {
|
||||
proc : bool = $context.flow.proc_dos_code(code);
|
||||
};
|
||||
|
||||
refine typeattr IMAGE_NT_HEADERS += &let {
|
||||
proc : bool = $context.flow.proc_nt_headers(this);
|
||||
};
|
||||
|
||||
refine typeattr IMAGE_FILE_HEADER += &let {
|
||||
proc : bool = $context.flow.proc_file_header(this);
|
||||
};
|
||||
|
||||
refine typeattr IMAGE_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 TheFile += &let {
|
||||
proc: bool = $context.flow.proc_the_file();
|
||||
};
|
134
src/file_analysis/analyzer/pe/pe-file.pac
Normal file
134
src/file_analysis/analyzer/pe/pe-file.pac
Normal file
|
@ -0,0 +1,134 @@
|
|||
|
||||
type TheFile(part: uint8) = record {
|
||||
dos_header : DOS_Header;
|
||||
dos_code : DOS_Code(dos_code_len);
|
||||
pe_header : IMAGE_NT_HEADERS;
|
||||
section_headers : IMAGE_SECTION_HEADER[] &length=pe_header.optional_header.size_of_headers;
|
||||
#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;
|
||||
} &let {
|
||||
dos_code_len: uint32 = dos_header.AddressOfNewExeHeader - 64;
|
||||
data_len: uint32 = pe_header.optional_header.size_of_init_data;
|
||||
} &byteorder=littleendian;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
type IMAGE_NT_HEADERS = record {
|
||||
PESignature : uint32;
|
||||
file_header : IMAGE_FILE_HEADER;
|
||||
optional_header : IMAGE_OPTIONAL_HEADER(file_header.SizeOfOptionalHeader) &length=file_header.SizeOfOptionalHeader;
|
||||
} &byteorder=littleendian &length=file_header.SizeOfOptionalHeader+offsetof(optional_header);
|
||||
|
||||
type IMAGE_FILE_HEADER = record {
|
||||
Machine : uint16;
|
||||
NumberOfSections : uint16;
|
||||
TimeDateStamp : uint32;
|
||||
PointerToSymbolTable : uint32;
|
||||
NumberOfSymbols : uint32;
|
||||
SizeOfOptionalHeader : uint16;
|
||||
Characteristics : uint16;
|
||||
};
|
||||
|
||||
type IMAGE_OPTIONAL_HEADER(len: 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 {
|
||||
0x0b01 -> i32 : MEM_INFO32;
|
||||
0x0b02 -> i64 : MEM_INFO64;
|
||||
default -> InvalidPEFile : empty;
|
||||
};
|
||||
loader_flags : uint32;
|
||||
number_of_rva_and_sizes : uint32;
|
||||
} &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 IMAGE_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;
|
||||
} &byteorder=littleendian &length=40;
|
||||
|
||||
|
||||
type IMAGE_DATA_DIRECTORY = record {
|
||||
virtual_address : uint32;
|
||||
size : uint16;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
type DATA_SECTIONS = record {
|
||||
blah: uint8;
|
||||
};
|
20
src/file_analysis/analyzer/pe/pe.pac
Normal file
20
src/file_analysis/analyzer/pe/pe.pac
Normal file
|
@ -0,0 +1,20 @@
|
|||
%include binpac.pac
|
||||
%include bro.pac
|
||||
|
||||
analyzer PE withcontext {
|
||||
connection: MockConnection;
|
||||
flow: File;
|
||||
};
|
||||
|
||||
connection MockConnection(bro_analyzer: BroFileAnalyzer) {
|
||||
upflow = File;
|
||||
downflow = File;
|
||||
};
|
||||
|
||||
%include pe-file.pac
|
||||
|
||||
flow File {
|
||||
flowunit = TheFile withcontext(connection, this);
|
||||
}
|
||||
|
||||
%include pe-analyzer.pac
|
Loading…
Add table
Add a link
Reference in a new issue