Skip to content

Commit

Permalink
A new plugin checks/analyzes additional data after the end of the PE …
Browse files Browse the repository at this point in the history
…(overlay).

Fixed the tab problems in `nt_values.cpp` for better readability on GitHub.
Added RICH constants for the latest version of Visual Studio.
  • Loading branch information
JusticeRage committed Sep 29, 2018
1 parent 749d807 commit 7a5d980
Show file tree
Hide file tree
Showing 7 changed files with 733 additions and 566 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ add_library(manacommons SHARED manacommons/color.cpp manacommons/output_tree_nod

add_executable(manalyze src/main.cpp src/config_parser.cpp src/output_formatter.cpp src/dump.cpp src/import_hash.cpp
src/plugin_framework/dynamic_library.cpp src/plugin_framework/plugin_manager.cpp # Plugin system
plugins/plugins_yara.cpp plugins/plugin_packer_detection.cpp plugins/plugin_imports.cpp plugins/plugin_resources.cpp plugins/plugin_mitigation.cpp) # Bundled plugins
plugins/plugins_yara.cpp plugins/plugin_packer_detection.cpp plugins/plugin_imports.cpp plugins/plugin_resources.cpp plugins/plugin_mitigation.cpp plugins/plugin_overlay.cpp) # Bundled plugins

if (WIN32)
add_definitions(/D_CRT_SECURE_NO_WARNINGS) # Please don't complain about fopen()
Expand Down
2 changes: 2 additions & 0 deletions docs/writing-plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,8 @@ Miscellaneous
// Or access them directly:
if ((*bytes)[0] == 'M' && &(*bytes)[1] == 'Z') { ... }

``pe.get_overlay_bytes(size_t size)`` returns the ``size`` first bytes of the overlay data of the PE. If ``size`` is omitted, every byte from the overlay data is returned; and if the file contains no such data, ``nullptr`` is returned.

``nt::translate_to_flag`` and ``nt::translate_to_flags`` are two functions that come in handy when you need to expand flags (i.e. the ``Characteristics`` field of many structures). Use the first function for values which translate into a single flag, and the second one for values which are composed of multiple ones::

auto pType = nt::translate_to_flag(ppe_header->Machine, nt::MACHINE_TYPES);
Expand Down
2 changes: 1 addition & 1 deletion include/manape/nt_values.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ typedef boost::shared_ptr<std::string> pString;

namespace nt {

typedef std::map<std::string, int> flag_dict;
typedef std::map<std::string, unsigned int> flag_dict;

// Exported flag translation maps. Definition in nt_values.cpp.
extern const DECLSPEC flag_dict PE_CHARACTERISTICS;
Expand Down
14 changes: 14 additions & 0 deletions include/manape/pe.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,20 @@ class PE
*/
DECLSPEC shared_bytes get_raw_bytes(size_t size = INT_MAX) const;

/**
* @brief Returns the bytes of the file located after the PE.
*
* Some malware embed additional data at the end of the file, which can be accessed
* through this function.
* /!\ Warning: the whole file will be loaded in memory!
*
* @param boost::uint64_t size If specified, only the [size] first bytes of the file
* will be provided. By default, the whole file is read.
*
* @return A vector containing the bytes of the overlay.
*/
DECLSPEC shared_bytes get_overlay_bytes(size_t size = INT_MAX) const;

/**
* @brief The delete operator. "new" had to be re-implemented in order to make it private.
*
Expand Down
1,129 changes: 565 additions & 564 deletions manape/nt_values.cpp

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions manape/pe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,52 @@ shared_bytes PE::get_raw_bytes(size_t size) const

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

shared_bytes PE::get_overlay_bytes(size_t size) const
{
if (_file_handle == nullptr || !_ioh) {
return nullptr;
}

const auto sections = get_sections();
if (!sections) {
return nullptr;
}

// Find where the overlay data would be located.
boost::uint64_t max_offset = 0;

// If the binary is signed, look after the authenticode signature.
if (_ioh->directories[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress)
{
max_offset = _ioh->directories[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +
_ioh->directories[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
}
else // Otherwise, look after the last section.
{
for (const auto& it : *sections)
{
if (it->get_pointer_to_raw_data() + it->get_size_of_raw_data() > max_offset) {
max_offset = it->get_pointer_to_raw_data() + it->get_size_of_raw_data();
}
}
}

// The PE has no overlay data.
if (max_offset >= get_filesize()) {
return nullptr;
}

fseek(_file_handle.get(), max_offset, SEEK_SET);
if (size > _file_size - max_offset) {
size = static_cast<size_t>(_file_size - max_offset);
}
auto res = boost::make_shared<std::vector<boost::uint8_t> >(size);
fread(&(*res)[0], 1, size, _file_handle.get());
return res;
}

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

bool PE::_parse_dos_header()
{
if (_file_handle == nullptr) {
Expand Down
104 changes: 104 additions & 0 deletions plugins/plugin_overlay.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
This file is part of Manalyze.
Manalyze is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Manalyze is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Manalyze. If not, see <http://www.gnu.org/licenses/>.
*/

#include <sstream>
#include <set>

#include "yara/yara_wrapper.h"

// TODO: Remove when Yara doesn't mask get_object anymore
#undef get_object

#include "plugin_framework/plugin_interface.h"
#include "plugin_framework/auto_register.h"

namespace plugin {

class OverlayPlugin : public IPlugin
{
public:
int get_api_version() const override { return 1; }

pString get_id() const override {
return boost::make_shared<std::string>("overlay");
}

pString get_description() const override {
return boost::make_shared<std::string>("Analyzes data outside of the PE's boundaries.");
}

pResult analyze(const mana::PE& pe) override
{
pResult res = create_result();

const auto overlay_bytes = pe.get_overlay_bytes();
if (overlay_bytes == nullptr) {
return res;
}

res->raise_level(SUSPICIOUS);
res->set_summary("The file contains overlay data.");

// Try to detect the file type of the overlay data.
yara::Yara y;
if (!y.load_rules("yara_rules/magic.yara")) {
return res;
}
yara::const_matches matches = y.scan_bytes(*overlay_bytes);
if (!matches->empty())
{
for (size_t i = 0; i < matches->size(); ++i)
{
res->raise_level(MALICIOUS);
std::stringstream ss;
ss << "The file contains a " << matches->at(i)->operator[]("description") << " after the PE data.";
if (matches->size() > 1) {
ss << " It is also possibly a polyglot.";
}
res->add_information(ss.str());
}
}
// No magic found: check the entropy to see if the data is encrypted.
else
{
const auto entropy = utils::shannon_entropy(*overlay_bytes);
if (entropy > 7.)
{
res->raise_level(SUSPICIOUS);
std::stringstream ss;
ss << "The overlay data has an entropy of " << entropy << " and is possibly compressed or encrypted.";
res->add_information(ss.str());
}
}

// Look at the ratio of overlay data.
const double ratio = static_cast<double>(overlay_bytes->size()) / static_cast<double>(pe.get_filesize());
if (ratio > .75)
{
std::stringstream ss;
ss << "Overlay data amounts for " << ratio * 100 << "% of the executable.";
res->raise_level(SUSPICIOUS);
res->add_information(ss.str());
}

return res;
}
};

AutoRegister<OverlayPlugin> auto_register_overlay;

} // !namespace plugin

0 comments on commit 7a5d980

Please sign in to comment.