Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse various PE timestamps and export them out #1035

Merged
merged 4 commits into from
Oct 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/retdec/fileformat/fftypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define RETDEC_FILEFORMAT_FFTYPES_H

#include "retdec/fileformat/types/certificate_table/certificate_table.h"
#include "retdec/fileformat/types/pe_timestamps/pe_timestamps.h"
#include "retdec/fileformat/types/dotnet_headers/clr_header.h"
#include "retdec/fileformat/types/dotnet_headers/metadata_header.h"
#include "retdec/fileformat/types/dotnet_headers/stream.h"
Expand Down
2 changes: 2 additions & 0 deletions include/retdec/fileformat/file_format/pe/pe_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "retdec/fileformat/types/dotnet_headers/string_stream.h"
#include "retdec/fileformat/types/dotnet_headers/user_string_stream.h"
#include "retdec/fileformat/types/dotnet_types/dotnet_class.h"
#include "retdec/fileformat/types/pe_timestamps/pe_timestamps.h"
#include "retdec/fileformat/types/visual_basic/visual_basic_info.h"
#include "retdec/pelib/PeFile.h"

Expand Down Expand Up @@ -206,6 +207,7 @@ class PeFormat : public FileFormat
const std::string& getTypeRefhashSha256() const;
const VisualBasicInfo* getVisualBasicInfo() const;
std::vector<std::tuple<const std::uint8_t*, std::size_t>> getDigestRanges() const;
PeTimestamps getTimestamps() const;

/// @name Scanning methods
/// @{
Expand Down
35 changes: 35 additions & 0 deletions include/retdec/fileformat/file_format/pe/pe_format_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
#define RETDEC_FILEFORMAT_PE_FORMAT_PARSER_H

#include "retdec/common/range.h"
#include "retdec/pelib/DebugDirectory.h"
#include "retdec/pelib/DelayImportDirectory.h"
#include "retdec/pelib/ExportDirectory.h"
#include "retdec/pelib/ImportDirectory.h"
#include "retdec/pelib/ResourceDirectory.h"
#include "retdec/utils/alignment.h"
#include "retdec/utils/string.h"
#include "retdec/fileformat/fftypes.h"
Expand All @@ -32,6 +37,11 @@ class PeFormatParser

virtual ~PeFormatParser() = default;

const PeLib::PeFileT* getPefile()
{
return peFile;
}

/// @name Detection methods
/// @{

Expand Down Expand Up @@ -556,6 +566,31 @@ class PeFormatParser
return peFile->imageLoader().getDataDirSize(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY);
}

const PeLib::ImportDirectory& getImportDirectory() const
{
return peFile->impDir();
}

const PeLib::DebugDirectory& getDebugDirectory() const
{
return peFile->debugDir();
}

const PeLib::ResourceDirectory& getResourceDirectory() const
{
return peFile->resDir();
}

const PeLib::ExportDirectory& getExportDirectory() const
{
return peFile->expDir();
}

const PeLib::DelayImportDirectory& getDelayDirectory() const
{
return peFile->delayImports();
}

retdec::common::RangeContainer<std::uint64_t> getImportDirectoryOccupiedAddresses() const
{
retdec::common::RangeContainer<std::uint64_t> result;
Expand Down
33 changes: 33 additions & 0 deletions include/retdec/fileformat/types/pe_timestamps/pe_timestamps.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @file src/fileinfo/fileformat/file_information_types/pe_timestamps.h
* @brief PE timestamps.
* @copyright (c) 2017 Avast Software, licensed under the MIT license
*/

#ifndef FILEINFO_FILE_INFORMATION_FILEFORMAT_TYPES_PE_TIMESTAMPS_H
#define FILEINFO_FILE_INFORMATION_FILEFORMAT_TYPES_PE_TIMESTAMPS_H

#include <cstdint>
#include <vector>

namespace retdec {
namespace fileformat {

/**
* Class for PE timestamps
*/
class PeTimestamps
{
public:
std::uint32_t coffTime;
std::uint32_t exportTime;
std::uint32_t configTime;
std::vector<std::uint32_t> resourceTime; // each Resource Directory
std::vector<std::uint32_t> debugTime; // each Debug Directory entry
std::vector<std::uint32_t> pdbTime; // each NB10 debug data
};

} // namespace fileformat
} // namespace retdec

#endif
30 changes: 30 additions & 0 deletions include/retdec/pelib/ConfigDirectory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @file include/retdec/pelib/ConfigDirectory.h
* @brief Class representing Load Config Directory of PE file
* @copyright (c) 2021 Avast Software, licensed under the MIT license
*/

#ifndef RETDEC_PELIB_CONFIGDIRECTORY_H
#define RETDEC_PELIB_CONFIGDIRECTORY_H

#include "retdec/pelib/ImageLoader.h"

namespace PeLib {
/// Class that handles the Debug directory.
class ConfigDirectory
{
protected:
PELIB_IMAGE_LOAD_CONFIG_DIRECTORY32 dir32 = { 0 };
PELIB_IMAGE_LOAD_CONFIG_DIRECTORY64 dir64 = { 0 };
bool is64bit = { 0 };

public:
virtual ~ConfigDirectory() = default;

int read(ImageLoader& imageLoader);

std::uint32_t getTimeDateStamp() const;
};
} // namespace PeLib

#endif
6 changes: 6 additions & 0 deletions include/retdec/pelib/PeFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "retdec/pelib/CoffSymbolTable.h"
#include "retdec/pelib/DelayImportDirectory.h"
#include "retdec/pelib/SecurityDirectory.h"
#include "retdec/pelib/ConfigDirectory.h"

namespace PeLib
{
Expand Down Expand Up @@ -122,6 +123,7 @@ namespace PeLib
DebugDirectory m_debugdir; ///< Debug directory of the current file.
DelayImportDirectory m_delayimpdir; ///< Delay import directory of the current file.
TlsDirectory m_tlsdir; ///< TLS directory of the current file.
ConfigDirectory m_configdir; ///< Load Config directory

public:

Expand Down Expand Up @@ -170,6 +172,7 @@ namespace PeLib
int readDelayImportDirectory() ;
/// Reads the security directory of the current file.
int readSecurityDirectory() ;
int readLoadConfigDirectory();

/// Checks the entry point code
LoaderError checkEntryPointErrors() const;
Expand Down Expand Up @@ -232,6 +235,9 @@ namespace PeLib
const TlsDirectory & tlsDir() const;
/// Accessor function for the TLS directory.
TlsDirectory & tlsDir();

const ConfigDirectory& configDir() const;
ConfigDirectory& configDir();
};
}

Expand Down
5 changes: 5 additions & 0 deletions include/retdec/pelib/PeLibAux.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@
#ifndef RETDEC_PELIB_PELIBAUX_H
#define RETDEC_PELIB_PELIBAUX_H

#include <cstdint>
#include <ios>
#include <numeric>
#include <string.h>
#include <string>
#include <vector>
#include <fstream>

#ifdef _MSC_VER // Reduces number of warnings under MS Visual Studio from ~100000 to zero
#pragma warning(disable:4267) // C4267: 'initializing': conversion from 'size_t' to '_Ty2', possible loss of data
Expand Down
1 change: 1 addition & 0 deletions include/retdec/utils/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ std::string getCurrentTime();
std::string getCurrentYear();
std::string timestampToDate(std::tm *tm);
std::string timestampToDate(std::time_t timestamp);
std::string timestampToGmtDatetime(std::time_t timestamp);

double getElapsedTime();

Expand Down
84 changes: 84 additions & 0 deletions src/fileformat/file_format/pe/pe_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <exception>
#include <iostream>
#include <map>
Expand Down Expand Up @@ -608,6 +609,7 @@ void PeFormat::initStructures(const std::string & dllListFile)
file->readSecurityDirectory();
file->readComHeaderDirectory();
file->readRelocationsDirectory();
file->readLoadConfigDirectory();

// Fill-in the loader error info from PE file
initLoaderErrorInfo();
Expand Down Expand Up @@ -1972,6 +1974,88 @@ void PeFormat::loadDotnetHeaders()
detectDotnetTypes();
}

/**
* @brief There are several places in the PE file that store some kind
* of Timestamp information, read all of them and return them
*/
PeTimestamps PeFormat::getTimestamps() const
{
// Inspiration: http://waleedassar.blogspot.com/2014/02/pe-timedatestamp-viewer.html
// 1. TimeDateStamp in COFF header
// 2. TimeDateStamp in Export Directory Table
// 3. TimeDateStamp in Resource Directory Table
// 4. TimeDateStamp in Debug Directory Table
// IF Debug Directory Table has Type == 0x2 - CODEVIEW,
// 5. then following PointerToRawData we can find another TimeDateStamp in Pdb 2.0 structure
// 6. TimeDateStamp in Load Configuration Directory
PeTimestamps timestamps = { 0 };

auto pefile = formatParser->getPefile();
if (!pefile)
return timestamps;

timestamps.coffTime = getTimeStamp();
timestamps.exportTime = pefile->expDir().getTimeDateStamp();
timestamps.configTime = pefile->configDir().getTimeDateStamp();
const DebugDirectory& debugDir = pefile->debugDir();

for (int i = 0; i < debugDir.calcNumberOfEntries(); ++i)
{
timestamps.debugTime.push_back(debugDir.getTimeDateStamp(i));

auto type = debugDir.getType(i);
// DebugDirectory only parses this type, but keep the check for clarity
if (type == PELIB_IMAGE_DEBUG_INFO_CODEVIEW)
{
/* Data structure if type == CodeView - PDB2.0
uint32 Signature = "NB10"
uint32 Offset
uint32 Timestamp
... */
std::vector<std::uint8_t> dataPtr = debugDir.getData(i);
if (dataPtr.size() < 12)
continue;

const std::uint8_t* signature = reinterpret_cast<const std::uint8_t*>("NB10");

if (!std::equal(dataPtr.begin(), dataPtr.begin() + 4, signature))
continue;

std::uint64_t timestamp;
if (get4ByteOffset(debugDir.getPointerToRawData(i) + 8, timestamp))
timestamps.pdbTime.push_back(timestamp);
}
}

/* Assume correct 3 level structure and only read through 3 levels */
auto root = formatParser->getResourceTreeRoot();
if (root)
{
timestamps.resourceTime.push_back(root->getTimeDateStamp());
for (std::size_t i = 0, e = root->getNumberOfChildren(); i < e; ++i)
{
const ResourceChild* child = root->getChild(i);
const ResourceNode* directory = dynamic_cast<const ResourceNode*>(child->getNode());
if (!directory)
continue;

timestamps.resourceTime.push_back((directory->getTimeDateStamp()));

for (int i = 0; i < directory->getNumberOfChildren(); i++)
{
const ResourceChild* second_child = directory->getChild(i);
const ResourceNode* second_directory = dynamic_cast<const ResourceNode*>(second_child->getNode());
if (!second_directory)
continue;

timestamps.resourceTime.push_back((second_directory->getTimeDateStamp()));
}
}
}

return timestamps;
}

/**
* Returns ranges that are used for digest calculation.
* This digest is used for signature verification.
Expand Down
7 changes: 6 additions & 1 deletion src/fileinfo/file_detector/pe_detector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,11 @@ void PeDetector::detectFileType()
fileInfo.setFileType(peParser->getTypeOfFile());
}

void PeDetector::getTimestamps()
{
fileInfo.pe_timestamps = peParser->getTimestamps();
}

void PeDetector::getAdditionalInfo()
{
getHeaderInfo();
Expand All @@ -511,7 +516,7 @@ void PeDetector::getAdditionalInfo()
getRelocationTableInfo();
getDotnetInfo();
getVisualBasicInfo();

getTimestamps();
/* In future we can detect more information about PE files:
- TimeDateStamp
- MajorLinkerVersion
Expand Down
1 change: 1 addition & 0 deletions src/fileinfo/file_detector/pe_detector.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class PeDetector : public FileDetector
void getSections();
void getDotnetInfo();
void getVisualBasicInfo();
void getTimestamps();
/// @}
protected:
/// @name Detection methods
Expand Down
1 change: 1 addition & 0 deletions src/fileinfo/file_information/file_information.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class FileInformation

public:
const retdec::fileformat::CertificateTable* certificateTable = nullptr; ///< information about signatures
retdec::fileformat::PeTimestamps pe_timestamps; ///< Various Timestamps stored in PE file
retdec::cpdetect::ToolInformation toolInfo; ///< detected tools
std::vector<std::string> messages; ///< error, warning and other messages

Expand Down
Loading