Skip to content

Commit

Permalink
Added support for Control Flow Guard fields introduced in Windows 8 /…
Browse files Browse the repository at this point in the history
… 10.

Mitigation plugin updated accordingly.
  • Loading branch information
JusticeRage committed Nov 24, 2017
1 parent 4211299 commit 713b32c
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 6 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ bin/manalyze-tests
# Compiled Yara rules + ClamAV rules and databases
*.yarac
bin/yara_rules/clamav.*
bin/yara_rules/daily.tar
bin/yara_rules/*.cvd
bin/yara_rules/*.ndb
bin/yara_rules/*.ldb

# Compiled Python scripts
bin/yara_rules/*.pyc
Expand All @@ -40,6 +43,8 @@ CMakeCache.txt
*.cmake
Makefile

# Linux compilation artifacts

# VS Files
*.vcxproj*
*.pdb
Expand All @@ -53,6 +58,8 @@ Makefile
Win32
Release
Debug
.vs
.vscode

# Intellij IDEA project files
.idea
Expand Down
1 change: 1 addition & 0 deletions include/manape/nt_values.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ extern const DECLSPEC flag_dict WIN_CERTIFICATE_REVISIONS;
extern const DECLSPEC flag_dict WIN_CERTIFICATE_TYPES;
extern const DECLSPEC flag_dict GLOBAL_FLAGS;
extern const DECLSPEC flag_dict HEAP_FLAGS;
extern const DECLSPEC flag_dict GUARD_FLAGS;

/**
* @brief Breaks down an integer given as input as a combination of flags.
Expand Down
20 changes: 20 additions & 0 deletions include/manape/pe_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,16 @@ typedef boost::shared_ptr<win_certificate> pwin_certificate;

// ----------------------------------------------------------------------------

typedef struct image_load_config_code_integrity_t
{
boost::uint16_t Flags;
boost::uint16_t Catalog;
boost::uint32_t CatalogOffset;
boost::uint32_t Reserved;
} image_load_config_code_integrity;

// ----------------------------------------------------------------------------

typedef struct image_load_config_directory_t
{
boost::uint32_t Size;
Expand All @@ -418,6 +428,16 @@ typedef struct image_load_config_directory_t
boost::uint64_t SecurityCookie;
boost::uint64_t SEHandlerTable;
boost::uint64_t SEHandlerCount;
boost::uint64_t GuardCFCheckFunctionPointer;
boost::uint64_t GuardCFDispatchFunctionPointer;
boost::uint64_t GuardCFFunctionTable;
boost::uint64_t GuardCFFunctionCount;
boost::uint32_t GuardFlags;
image_load_config_code_integrity CodeIntegrity;
boost::uint64_t GuardAddressTakenIatEntryTable;
boost::uint64_t GuardAddressTakenIatEntryCount;
boost::uint64_t GuardLongJumpTargetTable;
boost::uint64_t GuardLongJumpTargetCount;
} image_load_config_directory;

// ----------------------------------------------------------------------------
Expand Down
14 changes: 14 additions & 0 deletions manape/nt_values.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,20 @@ const flag_dict HEAP_FLAGS =

// ----------------------------------------------------------------------------

const flag_dict GUARD_FLAGS =
boost::assign::map_list_of ("IMAGE_GUARD_CF_INSTRUMENTED", 0x00000100)
("IMAGE_GUARD_CFW_INSTRUMENTED", 0x00000200)
("IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT", 0x00000400)
("IMAGE_GUARD_SECURITY_COOKIE_UNUSED", 0x00000800)
("IMAGE_GUARD_PROTECT_DELAYLOAD_IAT", 0x00001000)
("IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION", 0x00002000)
("IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT", 0x00004000)
("IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION", 0x00008000)
("IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT", 0x00010000)
("IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK ", 0xF0000000);

// ----------------------------------------------------------------------------

const_shared_strings translate_to_flags(int value, const flag_dict& dict)
{
auto res = boost::make_shared<std::vector<std::string> >();
Expand Down
52 changes: 50 additions & 2 deletions manape/pe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,38 @@ bool PE::_parse_tls()

// ----------------------------------------------------------------------------

/**
* @brief Helper function which simplifies the process of reading a field from
* the file's load configuration while checking if there are enough
* bytes available.
*
* @param config The structure that was read so far.
* @param source A pointer to the file to read from.
* @param destination Where the read value is to be put.
* @param field_size The size of the value to read.
* @param read_bytes The number of bytes read so far, will be incremented.
*
* @return Whether the value should be read. If false, EOF has been reached or
* the stucture has no more fields to read.
*/
bool read_config_field(const image_load_config_directory& config,
FILE* source,
void* destination,
unsigned int field_size,
unsigned int& read_bytes)
{
if (read_bytes + field_size > config.Size) {
return false;
}
if (1 != fread(destination, field_size, 1, source)) {
return false;
}
read_bytes += field_size;
return true;
}

// ----------------------------------------------------------------------------

bool PE::_parse_config()
{
if (!_ioh || _file_handle == nullptr) {
Expand Down Expand Up @@ -880,12 +912,13 @@ bool PE::_parse_config()
<< DEBUG_INFO_INSIDEPE << std::endl;
return true;
}
unsigned int read_bytes = 32 + 8 * field_size; // The number of bytes read so far

// SafeSEH information may not be present in some XP-era binaries.
// The MSDN page for IMAGE_LOAD_CONFIG_DIRECTORY specifies that their size must be 64
// (https://msdn.microsoft.com/en-us/library/windows/desktop/ms680328(v=vs.85).aspx).
// SafeSEH is also not present on 64 bit binaries.
if (config.Size > 64 && _ioh->Magic == nt::IMAGE_OPTIONAL_HEADER_MAGIC.at("PE32"))
// Those fields should be 0 in 64 bit binaries.
if (config.Size > read_bytes)
{
if (1 != fread(&config.SEHandlerTable, field_size, 1, _file_handle.get()) ||
1 != fread(&config.SEHandlerCount, field_size, 1, _file_handle.get()))
Expand All @@ -895,6 +928,21 @@ bool PE::_parse_config()
return true;
}
}
read_bytes += 2 * field_size;

// Read the remaining fields. The OR operator allows this code to stop whenever a read returns false,
// i.e. when trying to read more bytes than are available in the structure. This construction is necessary
// because fields are added to the structure as Windows evolves.
read_config_field(config, _file_handle.get(), &config.GuardCFCheckFunctionPointer, field_size, read_bytes) ||
read_config_field(config, _file_handle.get(), &config.GuardCFDispatchFunctionPointer, field_size, read_bytes) ||
read_config_field(config, _file_handle.get(), &config.GuardCFFunctionTable, field_size, read_bytes) ||
read_config_field(config, _file_handle.get(), &config.GuardCFFunctionCount, field_size, read_bytes) ||
read_config_field(config, _file_handle.get(), &config.GuardFlags, 4, read_bytes) ||
read_config_field(config, _file_handle.get(), &config.CodeIntegrity, 12, read_bytes) ||
read_config_field(config, _file_handle.get(), &config.GuardAddressTakenIatEntryTable, field_size, read_bytes) ||
read_config_field(config, _file_handle.get(), &config.GuardAddressTakenIatEntryCount, field_size, read_bytes) ||
read_config_field(config, _file_handle.get(), &config.GuardLongJumpTargetTable, field_size, read_bytes) ||
read_config_field(config, _file_handle.get(), &config.GuardLongJumpTargetCount, field_size, read_bytes);

_config.reset(config);
return true;
Expand Down
10 changes: 10 additions & 0 deletions plugins/plugin_mitigation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ class ExploitMitigationsPlugin : public IPlugin
if (res->get_information()->size() > 0) {
res->set_summary("The following exploit mitigation techniques have been detected");
}

// CFG
if (std::find(characteristics.begin(), characteristics.end(), "IMAGE_DLLCHARACTERISTICS_GUARD_CF") !=
characteristics.end()) {
res->add_information("CFG", "enabled");
}
else {
res->add_information("CFG", "disabled");
}

return res;
}
};
Expand Down
37 changes: 33 additions & 4 deletions src/dump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,12 +384,13 @@ void dump_tls(const mana::PE& pe, io::OutputFormatter& formatter)
void dump_config(const mana::PE& pe, io::OutputFormatter& formatter)
{
mana::shared_config config = pe.get_config();
if (config == nullptr) {
auto opt = pe.get_image_optional_header();
if (config == nullptr || !opt) {
return;
}

io::pNode config_node(new io::OutputTreeNode("Load Configuration", io::OutputTreeNode::LIST));
config_node->append(boost::make_shared<io::OutputTreeNode>("Size", config->Size, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("Size", config->Size));
config_node->append(boost::make_shared<io::OutputTreeNode>("TimeDateStamp", io::timestamp_to_string(config->TimeDateStamp)));
std::stringstream ss;
ss << config->MajorVersion << "." << config->MinorVersion;
Expand All @@ -408,8 +409,36 @@ void dump_config(const mana::PE& pe, io::OutputFormatter& formatter)
config_node->append(boost::make_shared<io::OutputTreeNode>("Reserved1", config->Reserved1, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("EditList", config->EditList, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("SecurityCookie", config->SecurityCookie, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("SEHandlerTable", config->SEHandlerTable, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("SEHandlerCount", config->SEHandlerCount));

// The SE Handler fields are only available on x86.
if (opt->Magic == nt::IMAGE_OPTIONAL_HEADER_MAGIC.at("PE32"))
{
config_node->append(boost::make_shared<io::OutputTreeNode>("SEHandlerTable", config->SEHandlerTable, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("SEHandlerCount", config->SEHandlerCount));
}

// Only show CFG fields if the binary was compiled with that option.
auto characteristics = *nt::translate_to_flags(opt->DllCharacteristics, nt::DLL_CHARACTERISTICS);
if (std::find(characteristics.begin(), characteristics.end(), "IMAGE_DLLCHARACTERISTICS_GUARD_CF") !=
characteristics.end())
{
config_node->append(boost::make_shared<io::OutputTreeNode>("GuardCFCheckFunctionPointer", config->GuardCFCheckFunctionPointer, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("GuardCFDispatchFunctionPointer", config->GuardCFDispatchFunctionPointer, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("GuardCFFunctionTable", config->GuardCFFunctionTable, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("GuardCFFunctionCount", config->GuardCFFunctionCount, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("GuardFlags", *nt::translate_to_flags(config->GuardFlags, nt::GUARD_FLAGS)));

config_node->append(boost::make_shared<io::OutputTreeNode>("CodeIntegrity.Flags", config->CodeIntegrity.Flags, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("CodeIntegrity.Catalog", config->CodeIntegrity.Catalog, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("CodeIntegrity.CatalogOffset", config->CodeIntegrity.CatalogOffset, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("CodeIntegrity.Reserved", config->CodeIntegrity.Reserved, io::OutputTreeNode::HEX));

config_node->append(boost::make_shared<io::OutputTreeNode>("GuardAddressTakenIatEntryTable", config->GuardAddressTakenIatEntryTable, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("GuardAddressTakenIatEntryCount", config->GuardAddressTakenIatEntryCount));
config_node->append(boost::make_shared<io::OutputTreeNode>("GuardLongJumpTargetTable", config->GuardLongJumpTargetTable, io::OutputTreeNode::HEX));
config_node->append(boost::make_shared<io::OutputTreeNode>("GuardLongJumpTargetCount", config->GuardLongJumpTargetCount));
}

formatter.add_data(config_node, *pe.get_path());
}

Expand Down

0 comments on commit 713b32c

Please sign in to comment.