mirror of
https://github.com/avast/retdec.git
synced 2025-02-21 14:21:25 +00:00
Unpacker plugins are now built directly into unpacker
We no longer load dynamic libraries as plugins. This features wasn't used and it is much more easier for us to maintain the unpacker this way.
This commit is contained in:
parent
b53a0b1a31
commit
853844800b
@ -1,137 +0,0 @@
|
||||
/**
|
||||
* @file include/retdec/unpacker/lib_loader.h
|
||||
* @brief Wrapper for multiplatform loading of dynamic libraries.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef RETDEC_UNPACKER_LIB_LOADER_H
|
||||
#define RETDEC_UNPACKER_LIB_LOADER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "retdec/utils/os.h"
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
namespace retdec {
|
||||
namespace unpackertool {
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
using LibHandle = HMODULE;
|
||||
using FuncHandle = FARPROC;
|
||||
|
||||
static inline LibHandle LOAD_LIBRARY(const std::string& path)
|
||||
{
|
||||
return LoadLibraryA(path.c_str());
|
||||
}
|
||||
|
||||
static inline FuncHandle GET_FUNCTION(LibHandle& lib, const std::string& name)
|
||||
{
|
||||
return GetProcAddress(lib, name.c_str());
|
||||
}
|
||||
|
||||
static inline void UNLOAD_LIBRARY(LibHandle& handle)
|
||||
{
|
||||
FreeLibrary(handle);
|
||||
}
|
||||
|
||||
static inline std::string GET_LAST_ERROR()
|
||||
{
|
||||
// @todo: Implement on windows
|
||||
return std::string();
|
||||
}
|
||||
#else
|
||||
using LibHandle = void*;
|
||||
using FuncHandle = void*;
|
||||
|
||||
static inline LibHandle LOAD_LIBRARY(const std::string& path)
|
||||
{
|
||||
return dlopen(path.c_str(), RTLD_NOW);
|
||||
}
|
||||
|
||||
static inline FuncHandle GET_FUNCTION(LibHandle& lib, const std::string& name)
|
||||
{
|
||||
return dlsym(lib, name.c_str());
|
||||
}
|
||||
|
||||
static inline void UNLOAD_LIBRARY(LibHandle& handle)
|
||||
{
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
static inline std::string GET_LAST_ERROR()
|
||||
{
|
||||
const char* errorMsg = dlerror();
|
||||
if (errorMsg == nullptr)
|
||||
return std::string();
|
||||
|
||||
return std::string(errorMsg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Abstract loader of dynamic libraries.
|
||||
*
|
||||
* Performs the multiplatform loading of dynamic libraries. It is required to have
|
||||
* LOAD_LIBRARY, GET_FUNCTION and UNLOAD_LIBRARY functions implemented on the targeted platform.
|
||||
* Also LibHandle and FuncHandle types need to be defined.
|
||||
*/
|
||||
class LibLoader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Loads the specified dynamic library.
|
||||
*
|
||||
* @param path Name of the dynamic library.
|
||||
*
|
||||
* @return The handle to the loaded library.
|
||||
*/
|
||||
static LibHandle loadLibrary(const std::string& path)
|
||||
{
|
||||
return LOAD_LIBRARY(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the specified function from the dynamic library.
|
||||
*
|
||||
* @tparam FuncType Type of the function loaded.
|
||||
*
|
||||
* @param handle Handle of the loaded library returned by @ref loadLibrary.
|
||||
* @param name The name of the function to load.
|
||||
*
|
||||
* @return The pointer to the loaded function.
|
||||
*/
|
||||
template <typename FuncType> static FuncType loadFunction(LibHandle& handle, const std::string& name)
|
||||
{
|
||||
return reinterpret_cast<FuncType>(reinterpret_cast<std::uint64_t>(GET_FUNCTION(handle, name.c_str())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unloads the specified dynamic library from memory.
|
||||
*
|
||||
* @param handle Handle to the loaded library.
|
||||
*/
|
||||
static void unloadLibrary(LibHandle handle)
|
||||
{
|
||||
UNLOAD_LIBRARY(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last error in case of error during the library loading.
|
||||
*
|
||||
* @return Error string.
|
||||
*/
|
||||
static std::string getLastError()
|
||||
{
|
||||
return GET_LAST_ERROR();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace unpackertool
|
||||
} // namespace retdec
|
||||
|
||||
#endif
|
@ -8,39 +8,17 @@
|
||||
#define RETDEC_UNPACKER_PLUGIN_H
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "retdec/unpacker/lib_loader.h"
|
||||
#include "retdec/unpacker/unpacker_exception.h"
|
||||
|
||||
#define plugin(T) retdec::unpackertool::Plugin::instance<T>()
|
||||
|
||||
namespace retdec {
|
||||
namespace unpackertool {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define REGISTER_PLUGIN_EXPORT_SPEC __declspec(dllexport)
|
||||
#else
|
||||
#define REGISTER_PLUGIN_EXPORT_SPEC
|
||||
#endif
|
||||
|
||||
#define EXPAND(id) #id
|
||||
#define MAKE_STRING(id) EXPAND(id)
|
||||
|
||||
#define REGISTER_PLUGIN_FUNCTION_ID registerPlugin
|
||||
#define REGISTER_PLUGIN_FUNCTION_NAME MAKE_STRING(REGISTER_PLUGIN_FUNCTION_ID)
|
||||
#define REGISTER_PLUGIN(PluginType) \
|
||||
Plugin* _plugin = nullptr; \
|
||||
extern "C" REGISTER_PLUGIN_EXPORT_SPEC Plugin* REGISTER_PLUGIN_FUNCTION_ID() { \
|
||||
if (_plugin != nullptr) return _plugin; \
|
||||
_plugin = new PluginType(); \
|
||||
return _plugin; \
|
||||
}
|
||||
#define MAKE_PLUGIN_SHARED(PluginType) \
|
||||
extern "C" REGISTER_PLUGIN_EXPORT_SPEC Plugin* REGISTER_PLUGIN_FUNCTION_ID(); \
|
||||
static inline PluginType* this_plugin() { \
|
||||
return static_cast<PluginType*>(REGISTER_PLUGIN_FUNCTION_ID()); \
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit code of the plugin from Plugin::unpack method.
|
||||
*/
|
||||
@ -61,15 +39,10 @@ enum PluginExitCode
|
||||
* 1. Create new folder for your plugin in unpackertool/plugins/ and add 'add_subdirectory(YOUR_PLUGIN)' into unpackertool/plugins/CMakeLists.txt.
|
||||
* 2. Create CMakeLists.txt in your new folder based on the template in unpackertool/plugins/example/ and uncomment install target.
|
||||
* 3. Subclass Plugin class while
|
||||
* - Providing all data in init() method to info attribute (see @ref Plugin::Info).
|
||||
* - Providing all data constructor to info attribute (see @ref Plugin::Info).
|
||||
* - Providing implementation of Plugin::prepare method.
|
||||
* - Providing implementation of Plugin::unpack method.
|
||||
* - Providing implementation of Plugin::cleanup method.
|
||||
* 4. Put macro REGISTER_PLUGIN(YOUR_PLUGIN_CLASS) below your Plugin class declaration.
|
||||
* - In case your Plugin class declaration & definition are separated (*.cpp & *.h file), you have to put it into *.cpp file
|
||||
* - In case you want to access your Plugin object from different parts of the code in your plugin, you have to separate your declaration & defintion
|
||||
* and put MAKE_PLUGIN_SHARED(YOUR_PLUGIN_CLASS) into *.h file below your declaration. You can then use inlined function @c this_plugin()
|
||||
* which is provided by the used macro.
|
||||
*/
|
||||
class Plugin
|
||||
{
|
||||
@ -172,11 +145,6 @@ public:
|
||||
return _cachedExitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pure virtual method that performs initialization of plugin after it is created.
|
||||
*/
|
||||
virtual void init() = 0;
|
||||
|
||||
/**
|
||||
* Pure virtual method that performs preparation of unpacking.
|
||||
*/
|
||||
@ -192,26 +160,6 @@ public:
|
||||
*/
|
||||
virtual void cleanup() = 0;
|
||||
|
||||
/**
|
||||
* Gets the library handle.
|
||||
*
|
||||
* @return The loaded library handle.
|
||||
*/
|
||||
LibHandle getHandle()
|
||||
{
|
||||
return _libHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the library handle.
|
||||
*
|
||||
* @param handle Handle of the loaded library.
|
||||
*/
|
||||
void setHandle(LibHandle handle)
|
||||
{
|
||||
_libHandle = handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the message on the standard output prepending the message with '[PLUGIN-NAME]'.
|
||||
* End of line is automatically inserted at the end of the message.
|
||||
@ -238,6 +186,19 @@ public:
|
||||
Plugin::logImpl(std::cerr, "[ERROR] [", getInfo()->name, "] ", args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the instance of specific type of plugin. This should be the only way
|
||||
* how plugin instances are obtained.
|
||||
*
|
||||
* @return Plugin instance.
|
||||
*/
|
||||
template <typename T>
|
||||
static T* instance()
|
||||
{
|
||||
static std::unique_ptr<T> pluginInstance = std::make_unique<T>();
|
||||
return pluginInstance.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
Plugin() : _cachedExitCode(PLUGIN_EXIT_UNPACKED) {}
|
||||
Plugin(const Plugin&);
|
||||
@ -247,7 +208,6 @@ protected:
|
||||
Plugin::Arguments startupArgs; ///< Startup arguments of the plugin.
|
||||
|
||||
private:
|
||||
LibHandle _libHandle; ///< Handle of the library that represents this plugin.
|
||||
PluginExitCode _cachedExitCode; ///< Cached exit code of the plugin for the unpacked file.
|
||||
|
||||
template <typename T, typename... Args> static void logImpl(std::ostream& out, const T& data, const Args&... args)
|
||||
|
@ -8,24 +8,8 @@ set(UNPACKERTOOL_SOURCES
|
||||
add_executable(retdec-unpackertool ${UNPACKERTOOL_SOURCES})
|
||||
set_target_properties(retdec-unpackertool PROPERTIES OUTPUT_NAME "retdec-unpacker")
|
||||
|
||||
# There are multiple cases for linking because of the plugin model and different behavior under Windows and Linux
|
||||
# 1. The libraries that are used only in the unpacker core are linked standardly
|
||||
# 2. The libraries that are used in plugins under Linux are linked as whole-archives
|
||||
# 3. The libraries that are used in plugins under Windows/macOS are linked to plugins themselves in plugins/*/CMakeLists.txt
|
||||
# 4. The libraries that are used both by core and plugins need to be linked as whole-archive under Linux, and under Windows/macOS like in 1 and 3 simultaneously
|
||||
target_link_libraries(retdec-unpackertool retdec-cpdetect)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
target_link_libraries(retdec-unpackertool -rdynamic
|
||||
-Wl,-force_load retdec-utils
|
||||
-Wl,-force_load retdec-unpacker
|
||||
-Wl,-force_load retdec-loader
|
||||
-Wl,-force_load retdec-pelib
|
||||
dl)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
target_link_libraries(retdec-unpackertool -rdynamic -Wl,-whole-archive retdec-utils retdec-unpacker retdec-loader pelib -Wl,-no-whole-archive dl)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
target_link_libraries(retdec-unpackertool shlwapi)
|
||||
endif()
|
||||
target_link_libraries(retdec-unpackertool retdec-unpacker retdec-loader retdec-cpdetect retdec-utils pelib)
|
||||
target_link_libraries(retdec-unpackertool retdec-unpacker-upx retdec-unpacker-mpress)
|
||||
|
||||
install(TARGETS retdec-unpackertool RUNTIME DESTINATION bin)
|
||||
|
||||
|
@ -7,128 +7,23 @@
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
|
||||
#include "retdec/utils/filesystem_path.h"
|
||||
#include "retdec/utils/string.h"
|
||||
#include "retdec/unpacker/lib_loader.h"
|
||||
#include "retdec/unpacker/plugin.h"
|
||||
#include "plugin_mgr.h"
|
||||
|
||||
#include "plugins/mpress/mpress.h"
|
||||
#include "plugins/upx/upx.h"
|
||||
|
||||
using namespace retdec::utils;
|
||||
|
||||
namespace retdec {
|
||||
namespace unpackertool {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
PluginMgr::PluginMgr() : _plugins()
|
||||
const std::vector<Plugin*> PluginMgr::plugins =
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
PluginMgr::~PluginMgr()
|
||||
{
|
||||
for (auto& pluginPair : _plugins)
|
||||
{
|
||||
for (auto& plugin : pluginPair.second)
|
||||
{
|
||||
// We need to unload the library after the plugin is destroyed
|
||||
// This cannot be done in Plugin destructor as we are destructing the heap
|
||||
// of the plugin, which resides in the library address space
|
||||
LibHandle handle = plugin->getHandle();
|
||||
delete plugin;
|
||||
LibLoader::unloadLibrary(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the plugin with the specified name.
|
||||
*
|
||||
* @param name The name of the plugin.
|
||||
*
|
||||
* @return True if the load was successful, otherwise false.
|
||||
*/
|
||||
bool PluginMgr::loadPlugin(const std::string& name)
|
||||
{
|
||||
// Load the library representing the plugin
|
||||
LibHandle lib = LibLoader::loadLibrary(name);
|
||||
if (!lib)
|
||||
{
|
||||
std::cerr << "Failed to load plugin '" << name << "'. Reason: " << LibLoader::getLastError() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the registration function
|
||||
CreatePluginFunc createPlugin;
|
||||
if ((createPlugin = LibLoader::loadFunction<CreatePluginFunc>(lib, REGISTER_PLUGIN_FUNCTION_NAME)) == nullptr)
|
||||
{
|
||||
LibLoader::unloadLibrary(lib);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Register the plugin
|
||||
Plugin* plugin = createPlugin();
|
||||
if (plugin == nullptr)
|
||||
{
|
||||
LibLoader::unloadLibrary(lib);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize
|
||||
plugin->init();
|
||||
|
||||
// Check whether initialization set Plugin::Info structure
|
||||
const Plugin::Info* pluginInfo = plugin->getInfo();
|
||||
if (pluginInfo->isUninitialized())
|
||||
{
|
||||
LibLoader::unloadLibrary(lib);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the handle to the library so we can properly free it
|
||||
plugin->setHandle(lib);
|
||||
|
||||
// Put it into table
|
||||
_plugins[pluginInfo->name].push_back(plugin);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all plugins recursively in the specified path.
|
||||
*
|
||||
* @param dirPath Path to traverse recursively.
|
||||
*/
|
||||
void PluginMgr::loadPlugins(const std::string& dirPath)
|
||||
{
|
||||
FilesystemPath path(dirPath);
|
||||
for (const auto& subpath : path)
|
||||
{
|
||||
// In case of directory, recursively call loadPlugins
|
||||
if (subpath->isDirectory())
|
||||
{
|
||||
loadPlugins(subpath->getPath());
|
||||
}
|
||||
else
|
||||
{
|
||||
// if PLUGIN_SUFFIX is at the end of the name of the file
|
||||
if (retdec::utils::endsWith(subpath->getPath(), PLUGIN_SUFFIX))
|
||||
loadPlugin(subpath->getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the table of registered plugins.
|
||||
*
|
||||
* @return The table of plugins.
|
||||
*/
|
||||
const PluginTable& PluginMgr::plugins() const
|
||||
{
|
||||
return _plugins;
|
||||
}
|
||||
mpress_plugin,
|
||||
upx_plugin
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the matching plugins in the registered plugins table.
|
||||
@ -138,30 +33,32 @@ const PluginTable& PluginMgr::plugins() const
|
||||
*
|
||||
* @return The list of matched plugins.
|
||||
*/
|
||||
PluginList PluginMgr::matchingPlugins(const std::string& packerName, const std::string& packerVersion) const
|
||||
PluginList PluginMgr::matchingPlugins(const std::string& packerName, const std::string& packerVersion)
|
||||
{
|
||||
// Find the packer name in plugin table to extract list of plugins for this packer
|
||||
PluginTable::const_iterator itr = _plugins.find(packerName);
|
||||
if (itr == _plugins.end())
|
||||
return PluginList();
|
||||
|
||||
// Iterate over all plugins for this packer name and match it against the used packer version
|
||||
PluginList matchedPlugins;
|
||||
const PluginList& pluginList = itr->second;
|
||||
for (const auto& plugin : plugins)
|
||||
{
|
||||
if (!utils::areEqualCaseInsensitive(plugin->getInfo()->name, packerName))
|
||||
continue;
|
||||
|
||||
matchedPlugins.push_back(plugin);
|
||||
}
|
||||
|
||||
// For wildcard just return the all versions of this packers
|
||||
if (packerVersion == WILDCARD_ALL_VERSIONS)
|
||||
return pluginList;
|
||||
return matchedPlugins;
|
||||
|
||||
for (const auto& plugin : pluginList)
|
||||
PluginList result;
|
||||
for (const auto& plugin : matchedPlugins)
|
||||
{
|
||||
// Non case-sensitive regular expressions to match against packerVersion
|
||||
std::regex versionRegex(plugin->getInfo()->packerVersion, std::regex::icase);
|
||||
if (std::regex_search(packerVersion, versionRegex))
|
||||
matchedPlugins.push_back(plugin);
|
||||
result.push_back(plugin);
|
||||
}
|
||||
|
||||
return matchedPlugins;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namepsace unpackertool
|
||||
|
@ -9,67 +9,18 @@
|
||||
|
||||
#include <cctype>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "retdec/utils/os.h"
|
||||
#include "singleton.h"
|
||||
|
||||
namespace retdec {
|
||||
namespace unpackertool {
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
#define PLUGIN_SUFFIX "dll"
|
||||
#define PLUGIN_SUFFIX_LEN 3
|
||||
#else
|
||||
#define PLUGIN_SUFFIX "so"
|
||||
#define PLUGIN_SUFFIX_LEN 2
|
||||
#endif
|
||||
|
||||
#define WILDCARD_ALL_VERSIONS ""
|
||||
|
||||
class Plugin;
|
||||
|
||||
/**
|
||||
* @brief Case-insensitive string comparison.
|
||||
*
|
||||
* The structure for case-insensitive string comparison.
|
||||
*/
|
||||
struct IcaseStringCompare
|
||||
{
|
||||
/**
|
||||
* Functor used as compare function.
|
||||
*
|
||||
* @param lhs Left-hand side of compare.
|
||||
* @param rhs Right-hand side of compare.
|
||||
*
|
||||
* @return True if the strings are case-insensitivelly equal, otherwise false.
|
||||
*/
|
||||
bool operator ()(const std::string& lhs, const std::string& rhs) const
|
||||
{
|
||||
if (lhs.length() < rhs.length())
|
||||
return true;
|
||||
else if (lhs.length() > rhs.length())
|
||||
return false;
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < lhs.length(); ++i)
|
||||
{
|
||||
// Cast to unsigned char required because of MSVC assert
|
||||
const unsigned char lc = lhs[i];
|
||||
const unsigned char rc = rhs[i];
|
||||
if (std::tolower(lc) != std::tolower(rc))
|
||||
return std::tolower(lc) < std::tolower(rc);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
using PluginList = std::vector<Plugin*>; ///< Type for list of plugins.
|
||||
using PluginTable = std::map<std::string, PluginList, IcaseStringCompare>; ///< Mapping of case-insensitive packer name to list of plugins.
|
||||
using CreatePluginFunc = Plugin* (*)(); ///< Type for plugin registration function.
|
||||
|
||||
/**
|
||||
* @brief The manager of unpacking plugins.
|
||||
@ -85,24 +36,16 @@ using CreatePluginFunc = Plugin* (*)(); ///< Type for plugin registration functi
|
||||
*/
|
||||
class PluginMgr
|
||||
{
|
||||
IS_SINGLETON(PluginMgr)
|
||||
public:
|
||||
~PluginMgr();
|
||||
PluginMgr(const PluginMgr&) = delete;
|
||||
|
||||
bool loadPlugin(const std::string& path);
|
||||
void loadPlugins(const std::string& dirPath);
|
||||
static const PluginList plugins;
|
||||
|
||||
const PluginTable& plugins() const;
|
||||
PluginList matchingPlugins(const std::string& packerName, const std::string& packerVersion) const;
|
||||
static PluginList matchingPlugins(const std::string& packerName, const std::string& packerVersion);
|
||||
|
||||
private:
|
||||
PluginMgr();
|
||||
PluginMgr(const PluginMgr&);
|
||||
PluginMgr& operator =(const PluginMgr&);
|
||||
|
||||
PluginTable _plugins; ///< Table of registered plugins.
|
||||
PluginMgr() = default;
|
||||
};
|
||||
#define sPluginMgr Singleton<PluginMgr>::instance()
|
||||
|
||||
} // namespace unpackertool
|
||||
} // namespace retdec
|
||||
|
@ -1,47 +1,3 @@
|
||||
|
||||
# Functions to get target's link libs and include dirs.
|
||||
function(GetLinkLibraries ret target)
|
||||
if(TARGET ${target})
|
||||
get_property(LIBS TARGET ${target} PROPERTY INTERFACE_LINK_LIBRARIES)
|
||||
set(RESULT "${target}")
|
||||
if(LIBS)
|
||||
foreach(LIB ${LIBS})
|
||||
GetLinkLibraries(SUB_LIBS ${LIB})
|
||||
if(SUB_LIBS)
|
||||
foreach(SUB_LIB ${SUB_LIBS})
|
||||
if(NOT ${SUB_LIB} IN_LIST RESULT)
|
||||
list(APPEND RESULT ${SUB_LIBS})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
set(${ret} ${RESULT} PARENT_SCOPE)
|
||||
endfunction()
|
||||
function(GetIncludeDirectories ret target)
|
||||
GetLinkLibraries(LIBS ${target})
|
||||
set(RESULT "")
|
||||
foreach(LIB ${LIBS})
|
||||
get_property(INCLUDES TARGET ${LIB} PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
|
||||
if(INCLUDES)
|
||||
foreach(INCL ${INCLUDES})
|
||||
if(NOT ${INCL} IN_LIST RESULT)
|
||||
list(APPEND RESULT ${INCL})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
set(${ret} ${RESULT} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# retdec-fileformat-headers target can be linked with targets to get fileformat's
|
||||
# includes without actually linking fileformat's libraries.
|
||||
GetIncludeDirectories(FILEFORMAT_HEADERS retdec-fileformat)
|
||||
add_library(retdec-fileformat-headers INTERFACE)
|
||||
target_include_directories(retdec-fileformat-headers INTERFACE ${FILEFORMAT_HEADERS})
|
||||
add_dependencies(retdec-fileformat-headers retdec-fileformat)
|
||||
|
||||
# Subdirectories.
|
||||
add_subdirectory(mpress)
|
||||
add_subdirectory(upx)
|
||||
|
@ -3,14 +3,6 @@ set(MPRESS_SOURCES
|
||||
mpress.cpp
|
||||
)
|
||||
|
||||
add_library(retdec-mpress SHARED ${MPRESS_SOURCES})
|
||||
target_link_libraries(retdec-mpress retdec-fileformat-headers)
|
||||
target_include_directories(retdec-mpress PUBLIC ${PROJECT_SOURCE_DIR}/src/)
|
||||
# Plugin related libraries are linked to the plugin on Windows
|
||||
if(MSVC OR APPLE)
|
||||
target_link_libraries(retdec-mpress retdec-unpacker)
|
||||
endif()
|
||||
install(TARGETS retdec-mpress
|
||||
LIBRARY DESTINATION bin/unpacker-plugins
|
||||
RUNTIME DESTINATION bin/unpacker-plugins
|
||||
)
|
||||
add_library(retdec-unpacker-mpress STATIC ${MPRESS_SOURCES})
|
||||
target_link_libraries(retdec-unpacker-mpress retdec-unpacker retdec-fileformat)
|
||||
target_include_directories(retdec-unpacker-mpress PUBLIC ${PROJECT_SOURCE_DIR}/src/)
|
||||
|
File diff suppressed because it is too large
Load Diff
123
src/unpackertool/plugins/mpress/mpress.h
Normal file
123
src/unpackertool/plugins/mpress/mpress.h
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @file src/unpackertool/plugins/mpress/mpress.h
|
||||
* @brief Unpacker plugin for MPRESS packer.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef UNPACKERTOOL_PLUGINS_MPRESS_MPRESS_H
|
||||
#define UNPACKERTOOL_PLUGINS_MPRESS_MPRESS_H
|
||||
|
||||
#include "retdec/loader/loader.h"
|
||||
#include "retdec/unpacker/dynamic_buffer.h"
|
||||
#include "retdec/unpacker/plugin.h"
|
||||
|
||||
#define mpress_plugin plugin(retdec::unpackertool::mpress::MpressPlugin)
|
||||
|
||||
namespace retdec {
|
||||
namespace unpackertool {
|
||||
namespace mpress {
|
||||
|
||||
enum Compression
|
||||
{
|
||||
COMPRESSION_LZMA,
|
||||
COMPRESSION_LZMAT,
|
||||
COMPRESSION_UNKNOWN
|
||||
};
|
||||
|
||||
enum MpressUnpackerStub
|
||||
{
|
||||
MPRESS_UNPACKER_STUB_101_105,
|
||||
MPRESS_UNPACKER_STUB_107_127,
|
||||
MPRESS_UNPACKER_STUB_201,
|
||||
MPRESS_UNPACKER_STUB_205_LZMA,
|
||||
MPRESS_UNPACKER_STUB_205_LZMAT,
|
||||
MPRESS_UNPACKER_STUB_212_219_LZMA,
|
||||
MPRESS_UNPACKER_STUB_212_219_LZMAT,
|
||||
MPRESS_UNPACKER_STUB_UNKNOWN
|
||||
};
|
||||
|
||||
enum MpressFixStub
|
||||
{
|
||||
MPRESS_FIX_STUB_10x,
|
||||
MPRESS_FIX_STUB_127_20x,
|
||||
MPRESS_FIX_STUB_21x,
|
||||
MPRESS_FIX_STUB_UNKNOWN
|
||||
};
|
||||
|
||||
struct MpressUnpackerStubData
|
||||
{
|
||||
std::uint32_t signature; // Offset written near the EP which tells where is the offset to the fix imports stub
|
||||
std::uint32_t packedContentOffset; // Offset of the section with the packed content
|
||||
std::uint32_t fixStubOffset; // Offset from the EP where the offset of Fix Imports Stub is written
|
||||
std::uint32_t relocOffset; // Offset from Fix Imports Stub where relocations are written
|
||||
std::uint32_t relocSizeOffset; // Offset from the EP where size of relocations is written
|
||||
Compression compression; // Compression method used while packing
|
||||
};
|
||||
|
||||
struct MpressFixStubData
|
||||
{
|
||||
std::uint32_t signature; // Byte at the beginning of fix imports stub
|
||||
std::uint32_t importHintsOffset; // Offset from Fix Imports Stub where Import Hints are stored
|
||||
std::uint32_t oepOffset; // Offset from Fix Imports Stub where the offset of OEP is written
|
||||
};
|
||||
|
||||
static MpressUnpackerStubData mpressUnpackerStubData[MPRESS_UNPACKER_STUB_UNKNOWN] =
|
||||
{
|
||||
{ 0x2B6, 0x2BC, 0x2B8, 0x2C8, 0x2C0, COMPRESSION_LZMAT }, // MPRESS_UNPACKER_STUB_101_105
|
||||
{ 0x29E, 0x2A4, 0x2A0, 0x2B0, 0x2A8, COMPRESSION_LZMAT }, // MPRESS_UNPACKER_STUB_107_127
|
||||
{ 0x299, 0x29F, 0x29B, 0x2AB, 0x2A3, COMPRESSION_LZMAT }, // MPRESS_UNPACKER_STUB_201
|
||||
{ 0xB57, 0xB5D, 0xB59, 0xB61, 0xB69, COMPRESSION_LZMA }, // MPRESS_UNPACKER_STUB_205_LZMA
|
||||
{ 0x29C, 0x2A2, 0x29E, 0x2A6, 0x2AE, COMPRESSION_LZMAT }, // MPRESS_UNPACKER_STUB_205_LZMAT
|
||||
{ 0xB5A, 0xB60, 0xB5C, 0xB64, 0xB6C, COMPRESSION_LZMA }, // MPRESS_UNPACKER_STUB_212_219_LZMA
|
||||
{ 0x29F, 0x2A5, 0x2A1, 0x2A9, 0x2B1, COMPRESSION_LZMAT } // MPRESS_UNPACKER_STUB_212_219_LZMAT
|
||||
};
|
||||
|
||||
static MpressFixStubData mpressFixStubData[MPRESS_FIX_STUB_UNKNOWN] =
|
||||
{
|
||||
{ 0x8B, 0xC1, 0xBD }, // MPRESS_FIX_STUB_10x
|
||||
{ 0x45, 0x138, 0x134 }, // MPRESS_FIX_STUB_127_20x
|
||||
{ 0x35, 0x128, 0x124 } // MPRESS_FIX_STUB_21x
|
||||
};
|
||||
|
||||
|
||||
class MpressPlugin : public Plugin
|
||||
{
|
||||
public:
|
||||
MpressPlugin();
|
||||
virtual ~MpressPlugin() override;
|
||||
|
||||
virtual void prepare() override;
|
||||
virtual void unpack() override;
|
||||
virtual void cleanup() override;
|
||||
|
||||
private:
|
||||
bool decompressData(unpacker::DynamicBuffer& compressedContent, unpacker::DynamicBuffer& decompressedContent);
|
||||
void decodeLzmaProperties(unpacker::DynamicBuffer& compressedContent, std::uint8_t& pb, std::uint8_t& lp, std::uint8_t& lc);
|
||||
std::uint32_t getFixStub();
|
||||
void fixJumpsAndCalls(unpacker::DynamicBuffer& buffer);
|
||||
void fixImportsAndEp(unpacker::DynamicBuffer& buffer);
|
||||
void offsetAnalysis(const unpacker::DynamicBuffer& buffer);
|
||||
void trailingBytesAnalysis(const unpacker::DynamicBuffer& buffer);
|
||||
void fixRelocations();
|
||||
MpressUnpackerStub detectUnpackerStubVersion();
|
||||
MpressFixStub detectFixStubVersion(unpacker::DynamicBuffer& unpackedContent);
|
||||
void saveFile(const std::string& fileName, unpacker::DynamicBuffer& content);
|
||||
void copySectionFromOriginalFile(std::uint32_t origSectIndex, const std::string& newFileName, std::uint32_t newSectIndex);
|
||||
|
||||
std::unique_ptr<retdec::loader::Image> _file;
|
||||
PeLib::PeFile32* _peFile;
|
||||
MpressUnpackerStub _unpackerStub;
|
||||
MpressFixStub _fixStub;
|
||||
const retdec::loader::Segment* _packedContentSect;
|
||||
std::uint32_t _addedSectionCount;
|
||||
|
||||
std::uint32_t _iatVa, _iatSize;
|
||||
std::uint32_t _oepVa;
|
||||
std::uint32_t _importHintsOffset;
|
||||
};
|
||||
|
||||
} // namespace mpress
|
||||
} // namespace unpackertool
|
||||
} // namespace retdec
|
||||
|
||||
#endif
|
@ -15,14 +15,6 @@ set(UPX_SOURCES
|
||||
elf/elf_upx_stub.cpp
|
||||
)
|
||||
|
||||
add_library(retdec-upx SHARED ${UPX_SOURCES})
|
||||
target_link_libraries(retdec-upx retdec-fileformat-headers)
|
||||
target_include_directories(retdec-upx PUBLIC ${PROJECT_SOURCE_DIR}/src/)
|
||||
# Plugin related libraries are linked to the plugin on Windows
|
||||
if(MSVC OR APPLE)
|
||||
target_link_libraries(retdec-upx retdec-utils retdec-unpacker)
|
||||
endif()
|
||||
install(TARGETS retdec-upx
|
||||
LIBRARY DESTINATION bin/unpacker-plugins
|
||||
RUNTIME DESTINATION bin/unpacker-plugins
|
||||
)
|
||||
add_library(retdec-unpacker-upx STATIC ${UPX_SOURCES})
|
||||
target_link_libraries(retdec-unpacker-upx retdec-unpacker retdec-fileformat retdec-utils)
|
||||
target_include_directories(retdec-unpacker-upx PUBLIC ${PROJECT_SOURCE_DIR}/src/)
|
||||
|
@ -40,9 +40,9 @@ void Decompressor::performDecompression(const std::weak_ptr<CompressedData>& com
|
||||
auto compressedData = compressedDataWptr.lock();
|
||||
if (!compressedData->decompress(unpackedData))
|
||||
{
|
||||
if (this_plugin()->getStartupArguments()->brute)
|
||||
if (upx_plugin->getStartupArguments()->brute)
|
||||
{
|
||||
this_plugin()->log("Bruteforcing compressed data with XOR.");
|
||||
upx_plugin->log("Bruteforcing compressed data with XOR.");
|
||||
|
||||
// If we failed, try to bruteforce the data with XOR
|
||||
DynamicBuffer originalData = compressedData->getBuffer();
|
||||
@ -54,7 +54,7 @@ void Decompressor::performDecompression(const std::weak_ptr<CompressedData>& com
|
||||
|
||||
if (compressedData->decompress(unpackedData))
|
||||
{
|
||||
this_plugin()->log("Bruteforcing compressed data with XOR succeeded on XOR value 0x", std::hex, i, std::dec, ".");
|
||||
upx_plugin->log("Bruteforcing compressed data with XOR succeeded on XOR value 0x", std::hex, i, std::dec, ".");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ template <int bits> void ElfUpxStub<bits>::unpack(const std::string& outputFile)
|
||||
AddressType segReadPos;
|
||||
DynamicBuffer unpackedData(_file->getFileFormat()->getEndianness());
|
||||
|
||||
this_plugin()->log("Unpacking block at file offset 0x", std::hex, firstBlockOffset + readPos, std::dec, ".");
|
||||
upx_plugin->log("Unpacking block at file offset 0x", std::hex, firstBlockOffset + readPos, std::dec, ".");
|
||||
unpackBlock(unpackedData, firstBlockOffset + readPos, segReadPos, originalProgHeaders[i].p_filesz);
|
||||
|
||||
retdec::utils::writeFile(output, unpackedData.getBuffer(), initialOffset + originalProgHeaders[i].p_offset);
|
||||
@ -170,7 +170,7 @@ template <int bits> void ElfUpxStub<bits>::unpack(const std::string& outputFile)
|
||||
|
||||
if (additionalDataBehindStub)
|
||||
{
|
||||
this_plugin()->log("Additional packed data detected at the end of the file.");
|
||||
upx_plugin->log("Additional packed data detected at the end of the file.");
|
||||
|
||||
// These data are always at the offset which is aligned by 4
|
||||
additionalDataPos = retdec::utils::alignUp(_file->getEpSegment()->getSize(), 4);
|
||||
@ -180,7 +180,7 @@ template <int bits> void ElfUpxStub<bits>::unpack(const std::string& outputFile)
|
||||
}
|
||||
else
|
||||
{
|
||||
this_plugin()->log("Additional packed data detected between LOAD segments.");
|
||||
upx_plugin->log("Additional packed data detected between LOAD segments.");
|
||||
|
||||
// We just continue reading where we ended up
|
||||
additionalDataPos = readPos + firstBlockOffset;
|
||||
@ -189,7 +189,7 @@ template <int bits> void ElfUpxStub<bits>::unpack(const std::string& outputFile)
|
||||
additionalDataSize = ep - additionalDataPos;
|
||||
}
|
||||
|
||||
this_plugin()->log("Additional data are at file offset 0x", std::hex, additionalDataPos,
|
||||
upx_plugin->log("Additional data are at file offset 0x", std::hex, additionalDataPos,
|
||||
" and have size of 0x", additionalDataSize, std::dec, ".");
|
||||
|
||||
std::vector<std::uint8_t> additionalDataBytes;
|
||||
@ -208,7 +208,7 @@ template <int bits> void ElfUpxStub<bits>::unpack(const std::string& outputFile)
|
||||
// If there is, unpack data into the gap
|
||||
DynamicBuffer unpackedData(_file->getFileFormat()->getEndianness());
|
||||
|
||||
this_plugin()->log("Unpacking block from additional data behind segment ", i, ".");
|
||||
upx_plugin->log("Unpacking block from additional data behind segment ", i, ".");
|
||||
unpackBlock(unpackedData, additionalData, readPos);
|
||||
retdec::utils::writeFile(output, unpackedData.getBuffer(), originalProgHeaders[i].p_offset + originalProgHeaders[i].p_filesz);
|
||||
|
||||
@ -221,7 +221,7 @@ template <int bits> void ElfUpxStub<bits>::unpack(const std::string& outputFile)
|
||||
{
|
||||
DynamicBuffer unpackedData(_file->getFileFormat()->getEndianness());
|
||||
|
||||
this_plugin()->log("Unpacking last block from additional data at the end of the file.");
|
||||
upx_plugin->log("Unpacking last block from additional data at the end of the file.");
|
||||
unpackBlock(unpackedData, additionalData, readPos);
|
||||
|
||||
output.seekp(0, std::ios::end);
|
||||
@ -486,7 +486,7 @@ template <int bits> void ElfUpxStub<bits>::unfilterBlock(const DynamicBuffer& pa
|
||||
if (!ret)
|
||||
throw UnsupportedFilterException(filterId);
|
||||
|
||||
this_plugin()->log("Unfiltering filter 0x", std::hex, static_cast<std::uint32_t>(filterId), std::dec, " with parameter ", static_cast<std::uint32_t>(filterParam), ".");
|
||||
upx_plugin->log("Unfiltering filter 0x", std::hex, static_cast<std::uint32_t>(filterId), std::dec, " with parameter ", static_cast<std::uint32_t>(filterParam), ".");
|
||||
}
|
||||
|
||||
// Explicit instantiation.
|
||||
|
@ -99,7 +99,7 @@ template <int bits> void MachOUpxStub<bits>::unpack(const std::string& outputFil
|
||||
}
|
||||
else
|
||||
{
|
||||
this_plugin()->log("Unpacking universal Mach-O.");
|
||||
upx_plugin->log("Unpacking universal Mach-O.");
|
||||
|
||||
std::vector<std::pair<std::uint32_t, std::uint32_t>> offsetAndSize;
|
||||
std::uint32_t offset = 0;
|
||||
@ -114,7 +114,7 @@ template <int bits> void MachOUpxStub<bits>::unpack(const std::string& outputFil
|
||||
else
|
||||
offset = retdec::utils::alignUp(output.tellp(), 0x1000);
|
||||
|
||||
this_plugin()->log("Unpacking architecture ", archToName(machoFormat->getTargetArchitecture()), " from universal Mach-O.");
|
||||
upx_plugin->log("Unpacking architecture ", archToName(machoFormat->getTargetArchitecture()), " from universal Mach-O.");
|
||||
|
||||
// This is not nice, but we have no other option. MachOUpxStub is templated class and therefore @c bits is set to 32 or 64 based on the bit width of the architecture.
|
||||
// Universal Mach-O binaries may contain both 32 and 64 bits binaries. If we want to get correct values out of MachOUpxStubTraits we need to create new versions of these
|
||||
@ -180,7 +180,7 @@ template <int bits> void MachOUpxStub<bits>::unpack(std::ifstream& inputFile, st
|
||||
// Move to the specific offset of the first packed block.
|
||||
inputFile.seekg(baseInputOffset + getFirstBlockOffset(inputFile), std::ios::beg);
|
||||
|
||||
this_plugin()->log("Unpacking original Mach-O header.");
|
||||
upx_plugin->log("Unpacking original Mach-O header.");
|
||||
|
||||
// First read packed original Mach-O header and unpack it.
|
||||
DynamicBuffer packedOriginalHeader = readNextBlock(inputFile);
|
||||
@ -223,7 +223,7 @@ template <int bits> void MachOUpxStub<bits>::unpack(std::ifstream& inputFile, st
|
||||
if (command.filesize == 0)
|
||||
continue;
|
||||
|
||||
this_plugin()->log("Unpacking block of load segment command with file offset 0x", std::hex, command.fileoff,
|
||||
upx_plugin->log("Unpacking block of load segment command with file offset 0x", std::hex, command.fileoff,
|
||||
" and file size 0x", command.filesize, std::dec, ".");
|
||||
|
||||
DynamicBuffer packedBlock = readNextBlock(inputFile);
|
||||
@ -327,7 +327,7 @@ template <int bits> void MachOUpxStub<bits>::unfilterBlock(const DynamicBuffer&
|
||||
if (!ret)
|
||||
throw UnsupportedFilterException(filterId);
|
||||
|
||||
this_plugin()->log("Unfiltering filter 0x", std::hex, static_cast<std::uint32_t>(filterId), std::dec, " with parameter ", static_cast<std::uint32_t>(filterParam), ".");
|
||||
upx_plugin->log("Unfiltering filter 0x", std::hex, static_cast<std::uint32_t>(filterId), std::dec, " with parameter ", static_cast<std::uint32_t>(filterParam), ".");
|
||||
}
|
||||
|
||||
// Explicit instantiation.
|
||||
|
@ -380,11 +380,11 @@ template <int bits> void PeUpxStub<bits>::detectUnfilter(const DynamicBuffer& un
|
||||
_filterId = FILTER_NONE;
|
||||
_filterCount = 0;
|
||||
_filterParam = 0;
|
||||
this_plugin()->log("No filter detected, or unknown filter present in the file.");
|
||||
upx_plugin->log("No filter detected, or unknown filter present in the file.");
|
||||
return;
|
||||
}
|
||||
|
||||
this_plugin()->log("Detected filter 0x", std::hex, _filterId, " with parameter 0x", _filterParam, " based on ", detectionBasedOn, ".");
|
||||
upx_plugin->log("Detected filter 0x", std::hex, _filterId, " with parameter 0x", _filterParam, " based on ", detectionBasedOn, ".");
|
||||
}
|
||||
|
||||
template <int bits> void PeUpxStub<bits>::unpackData(DynamicBuffer& unpackedData)
|
||||
@ -420,7 +420,7 @@ template <int bits> void PeUpxStub<bits>::unpackData(DynamicBuffer& unpackedData
|
||||
}
|
||||
}
|
||||
|
||||
this_plugin()->log("Unpacked data based on ", tryAgain ? "UPX metadata." : "signature.");
|
||||
upx_plugin->log("Unpacked data based on ", tryAgain ? "UPX metadata." : "signature.");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -574,7 +574,7 @@ template <int bits> UpxExtraData PeUpxStub<bits>::parseExtraData(retdec::unpacke
|
||||
throw OriginalHeaderCorruptedException();
|
||||
|
||||
originalHeader = DynamicBuffer(unpackedData, originalHeaderOffset, sectionHeadersEnd);
|
||||
this_plugin()->log("Original header found at address 0x", std::hex, originalHeaderOffset, std::dec, " in extra data.");
|
||||
upx_plugin->log("Original header found at address 0x", std::hex, originalHeaderOffset, std::dec, " in extra data.");
|
||||
|
||||
// Extra data starts right after original PE header
|
||||
std::uint32_t upxExtraDataOffset = originalHeaderOffset + sectionHeadersEnd;
|
||||
@ -587,7 +587,7 @@ template <int bits> UpxExtraData PeUpxStub<bits>::parseExtraData(retdec::unpacke
|
||||
{
|
||||
extraData.setImportsOffset(unpackedData.read<std::uint32_t>(upxExtraDataOffset));
|
||||
upxExtraDataOffset += 8;
|
||||
this_plugin()->log("Import hints address 0x", std::hex, extraData.getImportsOffset(), std::dec, " found in extra data.");
|
||||
upx_plugin->log("Import hints address 0x", std::hex, extraData.getImportsOffset(), std::dec, " found in extra data.");
|
||||
}
|
||||
|
||||
// If RVA in relocations directory is set (relocs RVA and size must be non-zero and RELOCS_STRIPPED flag cannot be set)
|
||||
@ -600,7 +600,7 @@ template <int bits> UpxExtraData PeUpxStub<bits>::parseExtraData(retdec::unpacke
|
||||
extraData.setRelocationsOffset(unpackedData.read<std::uint32_t>(upxExtraDataOffset));
|
||||
extraData.setRelocationsBigEndian(unpackedData.read<std::uint8_t>(upxExtraDataOffset + 4));
|
||||
upxExtraDataOffset += 5;
|
||||
this_plugin()->log("Relocations hints address 0x", std::hex, extraData.getRelocationsOffset(), std::dec, " found in extra data.");
|
||||
upx_plugin->log("Relocations hints address 0x", std::hex, extraData.getRelocationsOffset(), std::dec, " found in extra data.");
|
||||
}
|
||||
|
||||
return extraData;
|
||||
@ -800,7 +800,7 @@ template <int bits> void PeUpxStub<bits>::fixTls(const DynamicBuffer& originalHe
|
||||
if (tlsRva >= _newPeFile->peHeader().getSizeOfImage())
|
||||
throw InvalidDataDirectoryException("TLS");
|
||||
|
||||
this_plugin()->log("Original TLS directory found at RVA 0x", std::hex, tlsRva, " with size 0x", tlsSize, std::dec, ".");
|
||||
upx_plugin->log("Original TLS directory found at RVA 0x", std::hex, tlsRva, " with size 0x", tlsSize, std::dec, ".");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -816,7 +816,7 @@ template <int bits> void PeUpxStub<bits>::fixOep(const DynamicBuffer& originalHe
|
||||
_newPeFile->peHeader().setAddressOfEntryPoint(originalHeader.read<std::uint32_t>(0x28));
|
||||
_newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size());
|
||||
|
||||
this_plugin()->log("Original entry point address set to 0x", std::hex, _newPeFile->peHeader().getAddressOfEntryPoint(), std::dec, ".");
|
||||
upx_plugin->log("Original entry point address set to 0x", std::hex, _newPeFile->peHeader().getAddressOfEntryPoint(), std::dec, ".");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -852,7 +852,7 @@ template <int bits> void PeUpxStub<bits>::fixExports(const retdec::unpacker::Dyn
|
||||
if (exportsRva >= _newPeFile->peHeader().getSizeOfImage())
|
||||
throw InvalidDataDirectoryException("Exports");
|
||||
|
||||
this_plugin()->log("Original exports directory found at RVA 0x", std::hex, exportsRva, " with size 0x", exportsSize, std::dec, ".");
|
||||
upx_plugin->log("Original exports directory found at RVA 0x", std::hex, exportsRva, " with size 0x", exportsSize, std::dec, ".");
|
||||
|
||||
// Calculate the offset of exports in UPX2 section
|
||||
std::uint32_t exportsVa = _newPeFile->peHeader().rvaToVa(oldExportsRva);
|
||||
@ -938,7 +938,7 @@ template <int bits> void PeUpxStub<bits>::fixLoadConfiguration(const DynamicBuff
|
||||
if (loadConfigRva >= _newPeFile->peHeader().getSizeOfImage())
|
||||
throw InvalidDataDirectoryException("Load configuration");
|
||||
|
||||
this_plugin()->log("Original load configuration directory found at RVA 0x", std::hex, loadConfigRva, " with size 0x", loadConfigSize, std::dec, ".");
|
||||
upx_plugin->log("Original load configuration directory found at RVA 0x", std::hex, loadConfigRva, " with size 0x", loadConfigSize, std::dec, ".");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -973,7 +973,7 @@ template <int bits> void PeUpxStub<bits>::fixResources(const DynamicBuffer& unpa
|
||||
if (compressedRsrcRva >= _newPeFile->peHeader().getSizeOfImage())
|
||||
throw InvalidDataDirectoryException("Resources");
|
||||
|
||||
this_plugin()->log("Original resources directory found at RVA 0x", std::hex, compressedRsrcRva, " with size 0x", compressedRsrcSize, std::dec, ".");
|
||||
upx_plugin->log("Original resources directory found at RVA 0x", std::hex, compressedRsrcRva, " with size 0x", compressedRsrcSize, std::dec, ".");
|
||||
|
||||
unsigned long long imageBase = _file->getBaseAddress();
|
||||
|
||||
@ -1092,7 +1092,7 @@ template <int bits> void PeUpxStub<bits>::fixCoffSymbolTable()
|
||||
// MinGW files use COFF symbols even though it shouldn't be used for EXEs
|
||||
if (_newPeFile->peHeader().getPointerToSymbolTable() > 0) // Check whether COFF symbol table exists
|
||||
{
|
||||
this_plugin()->log("Detected COFF symbol table. Packed file may contain DWARF debug info.");
|
||||
upx_plugin->log("Detected COFF symbol table. Packed file may contain DWARF debug info.");
|
||||
|
||||
// Calculate the starting offset of COFF symbols by calculating raw sizes of all sections in packed file
|
||||
std::uint32_t totalSectionSize = _file->getSegment(0)->getSecSeg()->getOffset();
|
||||
@ -1114,7 +1114,7 @@ template <int bits> void PeUpxStub<bits>::fixCoffSymbolTable()
|
||||
_newPeFile->peHeader().setPointerToSymbolTable(newSymbolTablePointer);
|
||||
}
|
||||
else
|
||||
this_plugin()->log("Packed file seems to be truncated. Not copying DWARF debug info.");
|
||||
upx_plugin->log("Packed file seems to be truncated. Not copying DWARF debug info.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1134,7 +1134,7 @@ template <int bits> void PeUpxStub<bits>::fixCertificates()
|
||||
if (securityOffset == 0)
|
||||
return;
|
||||
|
||||
this_plugin()->log("Original certificates directory found at offset 0x", std::hex, securityOffset, " with size 0x", securitySize, std::dec, ".");
|
||||
upx_plugin->log("Original certificates directory found at offset 0x", std::hex, securityOffset, " with size 0x", securitySize, std::dec, ".");
|
||||
|
||||
// Calculate the offset of certificates in the overlay because certificates does not always begin
|
||||
// at the start of overlay.
|
||||
@ -1235,7 +1235,7 @@ template <int bits> void PeUpxStub<bits>::saveFile(const std::string& outputFile
|
||||
std::uint32_t overlaySize = static_cast<std::uint32_t>(_file->getFileFormat()->getLoadedFileLength() - _file->getFileFormat()->getDeclaredFileLength());
|
||||
std::vector<std::uint8_t> overlay(overlaySize);
|
||||
|
||||
this_plugin()->log("Packed file has overlay with size of 0x", std::hex, overlaySize, std::dec, " bytes. Copying into unpacked file.");
|
||||
upx_plugin->log("Packed file has overlay with size of 0x", std::hex, overlaySize, std::dec, " bytes. Copying into unpacked file.");
|
||||
|
||||
std::fstream inputFileHandle(_file->getFileFormat()->getPathToFile(), std::ios::binary | std::ios::in);
|
||||
retdec::utils::readFile(inputFileHandle, overlay, _file->getFileFormat()->getDeclaredFileLength(), overlaySize);
|
||||
|
@ -21,13 +21,15 @@ namespace retdec {
|
||||
namespace unpackertool {
|
||||
namespace upx {
|
||||
|
||||
REGISTER_PLUGIN(UpxPlugin)
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
UpxPlugin::UpxPlugin() : _file(), _stub()
|
||||
{
|
||||
info.name = "UPX";
|
||||
info.pluginVersion = "1.0";
|
||||
info.packerVersion = R"/(.*)/";
|
||||
info.author = "Marek Milkovic";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,17 +37,7 @@ UpxPlugin::UpxPlugin() : _file(), _stub()
|
||||
*/
|
||||
UpxPlugin::~UpxPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization of plugin providing @ref Plugin::Info data.
|
||||
*/
|
||||
void UpxPlugin::init()
|
||||
{
|
||||
info.name = "UPX";
|
||||
info.pluginVersion = "1.0";
|
||||
info.packerVersion = R"/(.*)/";
|
||||
info.author = "Marek Milkovic";
|
||||
cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "retdec/unpacker/plugin.h"
|
||||
#include "unpackertool/plugins/upx/upx_stub.h"
|
||||
|
||||
#define upx_plugin plugin(retdec::unpackertool::upx::UpxPlugin)
|
||||
|
||||
namespace retdec {
|
||||
namespace unpackertool {
|
||||
namespace upx {
|
||||
@ -33,7 +35,6 @@ public:
|
||||
UpxPlugin();
|
||||
virtual ~UpxPlugin();
|
||||
|
||||
virtual void init() override;
|
||||
virtual void prepare() override;
|
||||
virtual void unpack() override;
|
||||
virtual void cleanup() override;
|
||||
@ -43,8 +44,6 @@ private:
|
||||
std::shared_ptr<UpxStub> _stub; ///< Correct version of unpacking stub.
|
||||
};
|
||||
|
||||
MAKE_PLUGIN_SHARED(UpxPlugin)
|
||||
|
||||
} // namespace upx
|
||||
} // namespace unpackertool
|
||||
} // namespace retdec
|
||||
|
@ -277,7 +277,7 @@ std::shared_ptr<UpxStub> UpxStub::_createStubImpl(retdec::loader::Image* file, c
|
||||
else if (metadata.isDefined())
|
||||
detectionBasedOn = "metadata";
|
||||
|
||||
this_plugin()->log("Detected ", compressionName, " unpacking stub based on ", detectionBasedOn, ".");
|
||||
upx_plugin->log("Detected ", compressionName, " unpacking stub based on ", detectionBasedOn, ".");
|
||||
|
||||
UpxStub* stub = nullptr;
|
||||
switch (file->getFileFormat()->getFileFormat())
|
||||
|
@ -1,47 +0,0 @@
|
||||
/**
|
||||
* @file src/unpackertool/singleton.h
|
||||
* @brief Templated singleton declaration.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef UNPACKERTOOL_SINGLETON_H
|
||||
#define UNPACKERTOOL_SINGLETON_H
|
||||
|
||||
namespace retdec {
|
||||
namespace unpackertool {
|
||||
|
||||
#define IS_SINGLETON(CLASS) friend class Singleton<CLASS>;
|
||||
|
||||
/**
|
||||
* @brief Abstract singleton class.
|
||||
*
|
||||
* This abstract singleton class can be used for making
|
||||
* singletons from any class. You need to put IS_SINGLETON(ClassName)
|
||||
* in the class you want to make singleton.
|
||||
*/
|
||||
template <typename T> class Singleton
|
||||
{
|
||||
public:
|
||||
virtual ~Singleton() {}
|
||||
|
||||
/**
|
||||
* Returns the instance of the singleton.
|
||||
*
|
||||
* @return Singleton instance.
|
||||
*/
|
||||
static T& instance()
|
||||
{
|
||||
static T instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
private:
|
||||
Singleton();
|
||||
Singleton(const Singleton&);
|
||||
Singleton& operator =(const Singleton&);
|
||||
};
|
||||
|
||||
} // namespace unpackertool
|
||||
} // namespace retdec
|
||||
|
||||
#endif
|
@ -77,7 +77,7 @@ ExitCode unpackFile(const std::string& inputFile, const std::string& outputFile,
|
||||
ExitCode ret = EXIT_CODE_NOTHING_TO_DO;
|
||||
for (const auto& detectedPacker : detectedPackers)
|
||||
{
|
||||
PluginList plugins = sPluginMgr.matchingPlugins(detectedPacker.name, detectedPacker.versionInfo);
|
||||
PluginList plugins = PluginMgr::matchingPlugins(detectedPacker.name, detectedPacker.versionInfo);
|
||||
|
||||
if (plugins.empty())
|
||||
{
|
||||
@ -113,13 +113,6 @@ ExitCode processArgs(ArgHandler& handler, char argc, char** argv)
|
||||
return EXIT_CODE_OK;
|
||||
}
|
||||
|
||||
// First of all, load plugins
|
||||
// If -d|--dir argument isn't specified, take the current path from argv[0]
|
||||
std::string pluginsDir = FilesystemPath(argv[0]).getParentPath().append("/unpacker-plugins");
|
||||
if (handler["dir"]->used)
|
||||
pluginsDir = handler["dir"]->input;
|
||||
sPluginMgr.loadPlugins(pluginsDir);
|
||||
|
||||
bool brute = handler["brute"]->used;
|
||||
|
||||
// -h|--help
|
||||
@ -132,16 +125,12 @@ ExitCode processArgs(ArgHandler& handler, char argc, char** argv)
|
||||
{
|
||||
std::cout << "List of available plugins:" << std::endl;
|
||||
|
||||
const PluginTable& plugins = sPluginMgr.plugins();
|
||||
for (const auto& pluginPair : plugins)
|
||||
for (const auto& plugin : PluginMgr::plugins)
|
||||
{
|
||||
for (const auto& plugin : pluginPair.second)
|
||||
{
|
||||
const Plugin::Info* info = plugin->getInfo();
|
||||
std::cout << info->name << " " << info->pluginVersion
|
||||
<< " for packer '" << info->name << " " << info->packerVersion
|
||||
<< "' (" << info->author << ")" << std::endl;
|
||||
}
|
||||
const Plugin::Info* info = plugin->getInfo();
|
||||
std::cout << info->name << " " << info->pluginVersion
|
||||
<< " for packer '" << info->name << " " << info->packerVersion
|
||||
<< "' (" << info->author << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
// PACKED_FILE [-o|--output FILE]
|
||||
@ -178,7 +167,7 @@ int main(int argc, char** argv)
|
||||
" -h|--help Prints this help message.\n"
|
||||
"\n"
|
||||
"Listing group:\n"
|
||||
" -p|--plugins Prints the list of all available plugins in the plugin directory.\n"
|
||||
" -p|--plugins Prints the list of all available plugins.\n"
|
||||
"\n"
|
||||
"Unpacking group:\n"
|
||||
" PACKED_FILE Specifies the packed file, which is needed to be unpacked.\n"
|
||||
@ -186,9 +175,6 @@ int main(int argc, char** argv)
|
||||
" Default value is 'PACKED_FILE-unpacked'.\n"
|
||||
"\n"
|
||||
"Non-group optional arguments:\n"
|
||||
" -d|--dir DIR Specifies the directory that contains all the plugins as DIR.\n"
|
||||
" This directory is recursively searched. If no -d|--dir options is\n"
|
||||
" specified, the default search path is /path/to/unpacker/unpacker-plugins/.\n"
|
||||
" -b|--brute Tell unpacker to run plugins in the brute mode. Plugins may or may not\n"
|
||||
" implement brute methods for unpacking. They can completely ignore this argument."
|
||||
);
|
||||
@ -196,7 +182,6 @@ int main(int argc, char** argv)
|
||||
handler.registerArg('h', "help", false);
|
||||
handler.registerArg('o', "output", true);
|
||||
handler.registerArg('p', "plugins", false);
|
||||
handler.registerArg('d', "dir", true);
|
||||
handler.registerArg('b', "brute", false);
|
||||
|
||||
return processArgs(handler, argc, argv);
|
||||
|
Loading…
x
Reference in New Issue
Block a user