Skip to content

Commit

Permalink
Merge pull request #10 from JusticeRage/delayed_imports
Browse files Browse the repository at this point in the history
Adds support for delayed imports (fixes #6)
  • Loading branch information
JusticeRage committed May 21, 2016
2 parents 8b552a1 + 785ec58 commit 589b53f
Show file tree
Hide file tree
Showing 22 changed files with 754 additions and 136 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ include_directories(
)

add_definitions(-DWITH_MANACOMMONS) # Use functions from manacommons.
add_library(manape SHARED manape/pe.cpp manape/nt_values.cpp manape/utils.cpp manape/imports.cpp manape/resources.cpp manape/section.cpp)
add_library(manape SHARED manape/pe.cpp manape/nt_values.cpp manape/utils.cpp manape/imports.cpp manape/resources.cpp manape/section.cpp manape/imported_library.cpp)

add_library(manacommons SHARED manacommons/color.cpp manacommons/output_tree_node.cpp manacommons/escape.cpp manacommons/plugin_framework/result.cpp)

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) # Bundled plugins
plugins/plugins_yara.cpp plugins/plugin_packer_detection.cpp plugins/plugin_imports.cpp plugins/plugin_resources.cpp plugins/plugin_mitigation.cpp) # Bundled plugins

if (WIN32)
add_definitions(/D_CRT_SECURE_NO_WARNINGS) # Please don't complain about fopen()
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Usage:
-d [ --dump ] arg Dump PE information. Available choices are any
combination of: all, summary, dos (dos header), pe (pe
header), opt (pe optional header), sections, imports,
exports, resources, version, debug, tls
exports, resources, version, debug, tls, config, delay
--hashes Calculate various hashes of the file (may slow down the
analysis!)
-x [ --extract ] arg Extract the PE resources to the target directory.
Expand All @@ -87,6 +87,7 @@ Available plugins:
- packer: Tries to structurally detect packer presence.
- imports: Looks for suspicious imports.
- resources: Analyzes the program's resources.
- mitigation: Displays the enabled exploit mitigation techniques (DEP, ASLR, etc.).
- authenticode: Checks if the digital signature of the PE is valid.
- virustotal: Checks existing AV results on VirusTotal.
- all: Run all the available plugins.
Expand Down
12 changes: 10 additions & 2 deletions bin/yara_rules/suspicious_strings.yara
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ rule System_Tools
$a9 = "regmon.exe" nocase wide ascii
$a10 = "filemon.exe" nocase wide ascii
$a11 = "msconfig.exe" nocase wide ascii
$a12 = "vssadmin.exe" nocase wide ascii
$a13 = "bcdedit.exe" nocase wide ascii
condition:
any of them
}
Expand Down Expand Up @@ -523,8 +525,13 @@ rule VM_Generic_Detection : AntiVM
$a0 = "HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 0\\Scsi Bus 0\\Target Id 0\\Logical Unit Id 0" nocase wide ascii
$a1 = "HARDWARE\\Description\\System" nocase wide ascii
$redpill = {0F 01 0D 00 00 00 00 C3} // Copied from the Cuckoo project
// CLSIDs used to detect if speakers are present. Hoping this will not cause false positives.
$teslacrypt1 = { D1 29 06 E3 E5 27 CE 11 87 5D 00 60 8C B7 80 66 } // CLSID_AudioRender
$teslacrypt2 = { B3 EB 36 E4 4F 52 CE 11 9F 53 00 20 AF 0B A7 70 } // CLSID_FilterGraph
condition:
any of them
any of ($a*) or $redpill or all of ($teslacrypt*)
}

rule VMWare_Detection : AntiVM
Expand Down Expand Up @@ -713,6 +720,7 @@ rule Misc_Suspicious_Strings
$a3 = "exploit" nocase ascii wide
$a4 = "cmd.exe" nocase ascii wide
$a5 = "CWSandbox" nocase wide ascii // Found in some Zeus/Citadel samples
$a6 = "System32\\drivers\\etc\\hosts" nocase wide ascii
condition:
any of them
}
}
4 changes: 3 additions & 1 deletion docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ If you have managed to :doc:`obtain <obtaining-manalyze>` and :doc:`configure <i
-d [ --dump ] arg Dump PE information. Available choices are any
combination of: all, summary, dos (dos header), pe (pe
header), opt (pe optional header), sections, imports,
exports, resources, version, debug, tls
exports, resources, version, debug, tls, config, delay
--hashes Calculate various hashes of the file (may slow down the
analysis!)
-x [ --extract ] arg Extract the PE resources to the target directory.
Expand All @@ -31,6 +31,7 @@ If you have managed to :doc:`obtain <obtaining-manalyze>` and :doc:`configure <i
- packer: Tries to structurally detect packer presence.
- imports: Looks for suspicious imports.
- resources: Analyzes the program's resources.
- mitigation: Displays the enabled exploit mitigation techniques (DEP, ASLR, etc.).
- authenticode: Checks if the digital signature of the PE is valid.
- virustotal: Checks existing AV results on VirusTotal.
- all: Run all the available plugins.
Expand Down Expand Up @@ -91,6 +92,7 @@ The following plugins are available:
* **packer**: Applies PEiD signatures to try to detect if the file was packed. Warnings will also be raised based on unusual section names and a low number of imports (which can be set in the configuration file to better suit your needs).
* **imports**: Guesses a PE file's capabilities through its imported functions.
* **resources**: Analyzes a program's resources to see if it contains encrypted files and/or suspicious filetypes. This plugin also contains a couple of heuristic methods to determine if a file might be a `dropper <https://en.wikipedia.org/wiki/Dropper_%28malware%29>`_.
* **mitigation**: Checks which exploit mitigation techniques (/GS, SafeSEH, ASLR and DEP) are enabled in the binary.
* **authenticode**: Checks the validity of a PE file's signature. At the moment, this plugin is only available on Windows platforms, since it relies heavily on that operating system's API.
* **virustotal**: Submits the hash of the input file to VirusTotal to see if any antivirus engine detects it as malware.
* **all**: Run all plugins.
Expand Down
33 changes: 32 additions & 1 deletion docs/writing-plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ If you try to build the plugin right now, you'll see that the compiler is very a
return boost::make_shared<std::string>("A sample plugin.");
}

pResult analyze(const mana::PE& pe) override {
pResult analyze(const mana::PE& pe) override
{
pResult res = create_result();
res->add_information("Hello world from the plugin!");
return res;
Expand Down Expand Up @@ -407,6 +408,8 @@ You can also use the ``find_imports`` function if you're looking for something s
You can omit the latter two to look for the requested functions in any DLL with a case insensitive expression::

auto functions = pe.find_imports(".*bAsIc_OsTrEaM.*"); // Will search in any DLL, case insensitive
Finally, if you're interested in looking into the underlying structures, ``pe.get_imports`` returns ``ImportedLibrary`` objects which give direct access to the ``IMAGE_IMPORT_DESCRIPTOR`` and ``IMPORT_LOOKUP_TABLE``s.
Exports
-------
Expand Down Expand Up @@ -537,12 +540,40 @@ The structure returned by this function mirrors the one defined in the `MSDN <ht
boost::uint64_t SEHandlerTable;
boost::uint64_t SEHandlerCount;
} image_load_config_directory;
Delay Load Table
----------------

For PE files which have delayed imports, the ``DELAY_LOAD_DIRECTORY_TABLE`` can be retreived through ``get_delay_load_table``::

auto dldt = pe.get_delay_load_table();
if (dldt == nullptr) {
return; // No delayed imports.
}
std::cout << dldt->NameStr << " is delay-loaded!" << std::endl;

The function returns a pointer to the following structure::

typedef struct delay_load_directory_table_t
{
boost::uint32_t Attributes;
boost::uint32_t Name;
boost::uint32_t ModuleHandle;
boost::uint32_t DelayImportAddressTable;
boost::uint32_t DelayImportNameTable;
boost::uint32_t BoundDelayImportTable;
boost::uint32_t UnloadDelayImportTable;
boost::uint32_t TimeStamp;
std::string NameStr; // Non-standard!
} delay_load_directory_table;

Miscellaneous
-------------

``pe.get_filesize()`` returns the size of the input file in bytes.

``pe.get_architecture()`` returns either ``PE::x86`` or ``PE::x64`` depending on the program's target architecture.

``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
1 change: 1 addition & 0 deletions include/dump.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ void dump_tls(const mana::PE& pe, io::OutputFormatter& formatter);
void dump_config(const mana::PE&pe, io::OutputFormatter& formatter);
void dump_summary(const mana::PE& pe, io::OutputFormatter& formatter);
void dump_hashes(const mana::PE& pe, io::OutputFormatter& formatter);
void dump_dldt(const mana::PE& pe, io::OutputFormatter& formatter);

/**
* @brief Detects the filetype of a given resource based on magic numbers contained
Expand Down
93 changes: 93 additions & 0 deletions include/manape/imported_library.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
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/>.
*/

#pragma once

#include <vector>
#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

#include "manape/pe_structs.h"

#if defined BOOST_WINDOWS_API && !defined DECLSPEC
#ifdef MANAPE_EXPORT
#define DECLSPEC __declspec(dllexport)
#else
#define DECLSPEC __declspec(dllimport)
#endif
#elif !defined BOOST_WINDOWS_API && !defined DECLSPEC
#define DECLSPEC
#endif

namespace mana
{

typedef boost::shared_ptr<std::string> pString;
typedef boost::shared_ptr<std::vector<pimport_lookup_table> > pImports;

/**
* @brief This class represents a dynamic library (DLL) imported by the PE.
*
* In the past, we used to manipulate raw structures identical to the ones defined in
* the PE specification. The need to support delay-loaded libraries, which are declared
* in a totally different way, lead to the creation of this more generic object.
* This way, all imports can be queried through the same API calls. This makes sense
* because most users won't care how a DLL is loaded, they'll want to know whether
* a particular function is imported or not.
*/
class ImportedLibrary
{
public:
enum LOAD_TYPE { STANDARD, DELAY_LOADED };
virtual ~ImportedLibrary() {}
ImportedLibrary(const std::string& library_name, pimage_import_descriptor image_import_descriptor);

/**
* @brief This constructor is used for delay-loaded libraries which do not have an
* IMAGE_IMPORT_DESCRIPTOR structure.
*/
ImportedLibrary(const std::string& library_name);

DECLSPEC LOAD_TYPE get_type() const { return _load_type; }
DECLSPEC pString get_name() const { return boost::make_shared<std::string>(_library_name); }
DECLSPEC pImports get_imports() const { return _imported_functions; }

/**
* @brief Returns the underlying IMAGE_IMPORT_DESCRIPTOR structure.
*
* The structure doesn't exist for delay-loaded DLLs (< 0.1% of the cases), so if
* you need to access it, make sure that get_type() == STANDARD!
*
* @return A pointer to the corresponding IMAGE_IMPORT_DESCRIPTOR, or nullptr for
* delay-loaded DLLs.
*/
DECLSPEC pimage_import_descriptor get_image_import_descriptor() const { return _image_import_descriptor; }

void add_import(pimport_lookup_table import) { _imported_functions->push_back(import); }

private:
pimage_import_descriptor _image_import_descriptor;
std::vector<pimport_lookup_table> _lookup_table;
LOAD_TYPE _load_type;
std::string _library_name;
pImports _imported_functions;
};

typedef boost::shared_ptr<ImportedLibrary> pImportedLibrary;

} // !namespace mana
64 changes: 56 additions & 8 deletions include/manape/pe.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@
#include <boost/regex.hpp>
#include <boost/system/api_config.hpp>

#include "manape/nt_values.h" // Windows-related #defines flags are declared in this file.
#include "manape/pe_structs.h" // All typedefs and structs are over there
#include "manape/nt_values.h" // Windows-related #defines flags are declared in this file.
#include "manape/pe_structs.h" // All typedefs and structs are over there
#include "manape/utils.h"
#include "manape/resources.h" // Definition of the Resource class
#include "manape/section.h" // Definition of the Section class
#include "manape/color.h" // Colored output if available
#include "manape/resources.h" // Definition of the Resource class
#include "manape/section.h" // Definition of the Section class
#include "manape/imported_library.h" // Definition of the ImportedLibrary class
#include "manape/color.h" // Colored output if available

#if defined BOOST_WINDOWS_API && !defined DECLSPEC
#ifdef MANAPE_EXPORT
Expand All @@ -65,7 +66,9 @@ typedef boost::shared_ptr<const std::vector<pdebug_directory_entry> > shared_deb
typedef boost::shared_ptr<const std::vector<pimage_base_relocation> > shared_relocations;
typedef boost::shared_ptr<const image_tls_directory> shared_tls;
typedef boost::shared_ptr<const image_load_config_directory> shared_config;
typedef boost::shared_ptr<const delay_load_directory_table> shared_dldt;
typedef boost::shared_ptr<const std::vector<pwin_certificate> > shared_certificates;
typedef boost::shared_ptr<const std::vector<pImportedLibrary> > shared_imports;
typedef boost::shared_ptr<std::string> pString;
typedef boost::shared_ptr<FILE> pFile;

Expand Down Expand Up @@ -170,11 +173,20 @@ class PE
return (_initialized && _config) ? boost::make_shared<image_load_config_directory>(*_config) : shared_config();
}

DECLSPEC shared_dldt get_delay_load_table() const {
return (_initialized && _delay_load_directory_table) ?
boost::make_shared<delay_load_directory_table>(*_delay_load_directory_table) : shared_dldt();
}

DECLSPEC shared_certificates get_certificates() const {
return _initialized ? boost::make_shared<shared_certificates::element_type>(_certificates) :
boost::make_shared<shared_certificates::element_type>();
}

DECLSPEC shared_imports get_imports() const {
return (_initialized) ? boost::make_shared<std::vector<pImportedLibrary> >(_imports) : shared_imports();
}

/**
* @brief Extracts the resources of the PE and writes them to the disk.
*
Expand All @@ -195,6 +207,15 @@ class PE
*/
DECLSPEC bool extract_resources(const std::string& destination_folder);

enum PE_ARCHITECTURE { x86, x64 };

/**
* @brief Returns the architecture of the executable.
*
* @return Either x86 or x64.
*/
DECLSPEC PE_ARCHITECTURE get_architecture() const;

/**
* @brief Tells whether the PE could be parsed.
*
Expand Down Expand Up @@ -258,6 +279,20 @@ class PE
*/
bool _parse_directories();

/**
* @brief Parses a Hint/Name table.
*
* Implemented in imports.cpp.
*/
bool _parse_hint_name_table(pimport_lookup_table import) const;

/**
* @brief Parses an IMPORT_LOOKUP_TABLE.
*
* Implemented in imports.cpp.
*/
bool _parse_import_lookup_table(unsigned int offset, pImportedLibrary library) const;

/**
* @brief Parses the imports of a PE.
*
Expand All @@ -268,6 +303,16 @@ class PE
*/
bool _parse_imports();

/**
* @brief Parses the delayed imports of a PE.
*
* Included in the _parse_directories call.
* /!\ This relies on the information gathered in _parse_image_optional_header.
*
* Implemented in imports.cpp
*/
bool _parse_delayed_imports();

/**
* @brief Parses the exports of a PE.
*
Expand Down Expand Up @@ -303,7 +348,7 @@ class PE
bool _parse_tls();

/**
* @brief Parses the Configuration Table of a PE.
* @brief Parses the Load Configuration of a PE.
*
* Included in the _parse_directories call.
* /!\ This relies on the information gathered in _parse_pe_header.
Expand Down Expand Up @@ -376,9 +421,11 @@ class PE
* @param std::vector<pimage_library_descriptor>& destination The vector into which the result should be stored.
* @param bool case_sensitivity Whether the regular expression should be case sensitive (default is false).
*
* @return A vector of matching ImportedLibrary objects.
*
* Implementation is located in imports.cpp.
*/
std::vector<pimage_library_descriptor> _find_imported_dlls(const std::string& name_regexp, bool case_sensitivity = false) const;
std::vector<pImportedLibrary> _find_imported_dlls(const std::string& name_regexp, bool case_sensitivity = false) const;

std::string _path;
bool _initialized;
Expand All @@ -397,14 +444,15 @@ class PE
std::vector<pcoff_symbol> _coff_symbols; // This debug information is parsed (crudely) but
std::vector<pString> _coff_string_table; // not displayed, because that's IDA's job.
std::vector<pSection> _sections;
std::vector<pimage_library_descriptor> _imports;
std::vector<pImportedLibrary> _imports;
boost::optional<image_export_directory> _ied;
std::vector<pexported_function> _exports;
std::vector<pResource> _resource_table;
std::vector<pdebug_directory_entry> _debug_entries;
std::vector<pimage_base_relocation> _relocations; // Not displayed either, because of how big it is.
boost::optional<image_tls_directory> _tls;
boost::optional<image_load_config_directory> _config;
boost::optional<delay_load_directory_table> _delay_load_directory_table;
std::vector<pwin_certificate> _certificates;
};

Expand Down

0 comments on commit 589b53f

Please sign in to comment.