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

Packer Detection: Added more packers #607

Merged
merged 7 commits into from
Jul 10, 2019
Merged
Show file tree
Hide file tree
Changes from 6 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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
namespace retdec {
namespace cpdetect {

struct PeHeaderStyle
{
// Note: Having "(const) std::string" instead of "const char *" here makes MS Visual Studio 2017 compiler (v 15.9.8)
// exit with "fatal error C1001: An internal error has occurred in the compiler"
// const std::string headerStyle;
const char * headerStyle;
s3rvac marked this conversation as resolved.
Show resolved Hide resolved
uint16_t headerWords[0x0D];
};

/**
* PE-specific heuristics
*/
Expand Down Expand Up @@ -40,12 +49,18 @@ class PeHeuristics : public Heuristics

/// @name Heuristics for detection of used compiler or packer
/// @{
std::int32_t getInt32Unaligned(const std::uint8_t * codePtr);
const std::uint8_t * skip_NOP_JMP8_JMP32(const std::uint8_t * codeBegin, const std::uint8_t * codePtr, const std::uint8_t * codeEnd, std::size_t maxCount);
void getHeaderStyleHeuristics();
s3rvac marked this conversation as resolved.
Show resolved Hide resolved
void getSlashedSignatures();
void getMorphineHeuristics();
void getStarForceHeuristics();
void getSafeDiscHeuristics();
bool checkSecuROMSignature(const char * fileData, const char * fileDataEnd, uint32_t FileOffset);
void getSecuROMHeuristics();
void getMPRMMGVAHeuristics();
void getActiveMarkHeuristics();
void getPetiteHeuristics();
void getPelockHeuristics();
void getEzirizReactorHeuristics();
void getUpxHeuristics();
Expand Down
20 changes: 12 additions & 8 deletions include/retdec/cpdetect/cptypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ enum class DetectionMethod
COMMENT_H, ///< .comment section
NOTE_H, ///< .note section
MANIFEST_H, ///< manifest resource
HEADER_H, ///< MZ header
OTHER_H ///< other heuristic
};

Expand Down Expand Up @@ -175,16 +176,19 @@ struct ToolInformation
std::vector<DetectResult> detectedTools; ///< detected tools (compilers, packers...)
std::vector<DetectLanguage> detectedLanguages; ///< detected programming language(s)

bool entryPointOffset = false; ///< @c false if file has no has no or invalid EP offset
unsigned long long epOffset; ///< entry point offset
bool entryPointOffset = false; ///< @c false if file has no has no or invalid EP offset
unsigned long long epOffset; ///< entry point offset

bool entryPointAddress = false; ///< @c false if file has no has no or invalid EP address
unsigned long long epAddress; ///< entry point address
unsigned long long imageBase; ///< image base address
bool entryPointAddress = false; ///< @c false if file has no has no or invalid EP address
unsigned long long epAddress; ///< entry point address
unsigned long long imageBase; ///< image base address
s3rvac marked this conversation as resolved.
Show resolved Hide resolved

bool entryPointSection = false; ///< @c false if file has no or invalid EP section
retdec::fileformat::Section epSection; ///< entry point section
std::string epBytes; ///< hexadecimal representation of entry point bytes
unsigned long long overlayOffset; ///< offset of the file overlay. 0 if no overlay
size_t overlaySize = 0; ///< length of the file overlay. 0 if no overlay

bool entryPointSection = false; ///< @c false if file has no or invalid EP section
retdec::fileformat::Section epSection; ///< entry point section
std::string epBytes; ///< hexadecimal representation of entry point bytes

ToolInformation();
~ToolInformation();
Expand Down
6 changes: 6 additions & 0 deletions src/cpdetect/compiler_detector/compiler_detector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,12 @@ ReturnCode CompilerDetector::getAllInformation()
fileParser.getImageBaseAddress(toolInfo.imageBase);
toolInfo.entryPointAddress = fileParser.getEpAddress(toolInfo.epAddress);
toolInfo.entryPointOffset = fileParser.getEpOffset(toolInfo.epOffset);

if((toolInfo.overlaySize = fileParser.getOverlaySize()) != 0)
{
toolInfo.overlayOffset = fileParser.getDeclaredFileLength();
}

const bool invalidEntryPoint = !toolInfo.entryPointAddress || !toolInfo.entryPointOffset;
if (!fileParser.getHexEpBytes(toolInfo.epBytes, cpParams.epBytesCount)
&& !invalidEntryPoint && !fileParser.isInValidState())
Expand Down
162 changes: 154 additions & 8 deletions src/cpdetect/compiler_detector/heuristics/pe_heuristics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,17 @@ const std::vector<std::string> msvcRuntimeStrings =
toWide(msvcRuntimeString, 4)
};

const std::vector<PeHeaderStyle> headerStyles =
{
// {"Unknown", { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }},
{"Microsoft", { 0x0090, 0x0003, 0x0000, 0x0004, 0x0000, 0xFFFF, 0x0000, 0x00B8, 0x0000, 0x0000, 0x0000, 0x0040, 0x0000 }},
{"Borland", { 0x0050, 0x0002, 0x0000, 0x0004, 0x000F, 0xFFFF, 0x0000, 0x00B8, 0x0000, 0x0000, 0x0000, 0x0040, 0x001A }},
{"PowerBasic", { 0x000A, 0x0002, 0x0000, 0x0004, 0x000F, 0xFFFF, 0x0000, 0x00C0, 0x0000, 0x0000, 0x0000, 0x0040, 0x0000 }},
{"Watcom", { 0x0080, 0x0001, 0x0000, 0x0004, 0x0000, 0xFFFF, 0x0000, 0x00B8, 0x0000, 0x0000, 0x0000, 0x0040, 0x0000 }},
{"IBM", { 0x0091, 0x0001, 0x0001, 0x0005, 0x0021, 0xFFFF, 0x0005, 0x0200, 0x68A3, 0x0000, 0x0003, 0x0040, 0x0000 }},
// {"Empty", { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0040, 0x0000 }}
};

/**
* Try to find string which indicates AutoIt programming language
* @param content Content of file
Expand Down Expand Up @@ -327,6 +338,79 @@ void PeHeuristics::getVisualBasicHeuristics()
}
}

std::int32_t PeHeuristics::getInt32Unaligned(const std::uint8_t * codePtr)
{
const std::int32_t * codePtrInt32 = reinterpret_cast<const std::int32_t *>(codePtr);

s3rvac marked this conversation as resolved.
Show resolved Hide resolved
return codePtrInt32[0];
}

/**
* Parses the code, follows NOPs or JMPs
*/
const std::uint8_t * PeHeuristics::skip_NOP_JMP8_JMP32(const std::uint8_t * codeBegin, const std::uint8_t * codePtr, const std::uint8_t * codeEnd, std::size_t maxCount)
{
while(codeBegin <= codePtr && codePtr < codeEnd && maxCount > 0)
{
ssize_t movePtrBy = 0;

switch (codePtr[0])
{
case 0x90: // NOP, move by 1 byte
movePtrBy = 1;
break;

case 0xEB: // JMP rel8
if ((codePtr + 2) > codeEnd || codePtr[1] == 0x80)
return nullptr;
movePtrBy = static_cast<int8_t>(codePtr[1]);
break;

case 0xE9:
if ((codePtr + 5) > codeEnd || getInt32Unaligned(codePtr+1) == 0x80000000)
return nullptr;
movePtrBy = getInt32Unaligned(codePtr + 1);
break;

default:
break;
}

// If no increment, it means there was no NOP/JMP and we are done
if (movePtrBy == 0)
break;

// Check whether we got into the code range
codePtr = codePtr + movePtrBy;
maxCount--;
}
return codePtr;
}

/**
* Detect header heuristics
*/
void PeHeuristics::getHeaderStyleHeuristics()
{
const auto &content = search.getPlainString();

// Must have at least IMAGE_DOS_HEADER
if (content.length() > 0x40)
{
const char * e_cblp = content.c_str() + 0x02;

for (size_t i = 0; i < headerStyles.size(); i++)
{
if (!std::memcmp(e_cblp, headerStyles[i].headerWords, sizeof(headerStyles[i].headerWords)))
{
addLinker(DetectionMethod::HEADER_H, DetectionStrength::MEDIUM, headerStyles[i].headerStyle);
}
}

}
}


/**
* Try to detect used compiler or packer based on slashed signatures
*/
Expand Down Expand Up @@ -442,7 +526,7 @@ void PeHeuristics::getStarForceHeuristics()
{
if (sections[noOfSections - 1]->getName() == ".ps4")
{
if(sections[0]->getName() == ".text" && sections[1]->getName() == ".data" && sections[2]->getName() == ".data" && sections[3]->getName() == ".share")
if (sections[0]->getName() == ".text" && sections[1]->getName() == ".data" && sections[2]->getName() == ".data" && sections[3]->getName() == ".share")
{
addPacker(DetectionMethod::COMBINED, DetectionStrength::MEDIUM, "StarForce.C");
return;
Expand Down Expand Up @@ -471,15 +555,15 @@ void PeHeuristics::getSafeDiscHeuristics()
for (std::size_t i = 0; i < noOfSections; i++)
{
// Note that original code does:
// if(!strncmp((char *)pSection->Name, "stxt371\0", sizeof("stxt371\0")))
// if (!strncmp((char *)pSection->Name, "stxt371\0", sizeof("stxt371\0")))
if (sections[i]->getName() == "stxt371")
{
addPacker(DetectionMethod::SECTION_TABLE_H, DetectionStrength::MEDIUM, "SafeDisc");
break;
}

// Note that original code does:
// if(!strncmp((char *)pSection->Name, ".txt\0", sizeof(".txt\0")) || !strncmp((char *)pSection->Name, ".txt2\0", sizeof(".txt2\0")))
// if (!strncmp((char *)pSection->Name, ".txt\0", sizeof(".txt\0")) || !strncmp((char *)pSection->Name, ".txt2\0", sizeof(".txt2\0")))
if (sections[i]->getName() == ".txt" || sections[i]->getName() == ".txt2")
{
addPacker(DetectionMethod::SECTION_TABLE_H, DetectionStrength::LOW, "SafeDisc");
Expand Down Expand Up @@ -527,7 +611,7 @@ void PeHeuristics::getSecuROMHeuristics()
bool foundSecuROM = false;

// There must be at least 0x2000 extra bytes beyond the last section,
// last data directory, last debug directory and digital signature.
// last data directory, last debug directory and digital signature.
if (peParser.getOverlaySize() >= 0x2000)
{
// The entire file must be loaded to memory
Expand All @@ -538,19 +622,77 @@ void PeHeuristics::getSecuROMHeuristics()
memcpy(&SecuromOffs, fileData + loadedLength - sizeof(uint32_t), sizeof(uint32_t));

// Verify it
if(checkSecuROMSignature(fileData, fileData + loadedLength, SecuromOffs - sizeof(uint32_t)))
if (checkSecuROMSignature(fileData, fileData + loadedLength, SecuromOffs - sizeof(uint32_t)))
foundSecuROM = true;
if(checkSecuROMSignature(fileData, fileData + loadedLength, loadedLength - (SecuromOffs - 0x0C)))
if (checkSecuROMSignature(fileData, fileData + loadedLength, loadedLength - (SecuromOffs - 0x0C)))
foundSecuROM = true;
if(foundSecuROM)

if (foundSecuROM)
{
addPacker(DetectionMethod::STRING_SEARCH_H, DetectionStrength::HIGH, "SecuROM");
}
}
}
}

/**
* Detection of MPRMMGVA packer
*/
void PeHeuristics::getMPRMMGVAHeuristics()
{
const auto &content = search.getPlainString();
const uint8_t * fileData = reinterpret_cast<const uint8_t *>(content.c_str());
const uint8_t * filePtr = fileData + toolInfo.epOffset;
const uint8_t * fileEnd = fileData + content.length();
unsigned long long offset1;

// Skip up to 8 NOPs or JMPs
filePtr = skip_NOP_JMP8_JMP32(fileData, filePtr, fileEnd, 8);
if (filePtr != nullptr)
s3rvac marked this conversation as resolved.
Show resolved Hide resolved
{
if (search.exactComparison("892504----00", toolInfo.epOffset))
{
offset1 = search.findUnslashedSignature("64FF3500000000", toolInfo.epOffset, toolInfo.epOffset + 0x80);
if (offset1 != 0)
{
if (search.findUnslashedSignature("64892500000000", toolInfo.epOffset + offset1, toolInfo.epOffset + offset1 + 0x40))
{
addPacker(DetectionMethod::STRING_SEARCH_H, DetectionStrength::HIGH, "MPRMMGVA");
}
}
}
}
}

/**
* Detection of ActiveMark packer
*/
void PeHeuristics::getActiveMarkHeuristics()
{
if (search.exactComparison("00544D53414D564F48A49BFDFF2624E9D7F1D6F0D6AEBEFCD6DFB5C1D01F07CE", toolInfo.overlayOffset))
{
addPacker(DetectionMethod::STRING_SEARCH_H, DetectionStrength::HIGH, "ActiveMark");
}
}

/**
* Detection of Petite packer
*/
void PeHeuristics::getPetiteHeuristics()
{
if (search.exactComparison("B8--------608DA800----FF68--------6A40680030000068------006A00FF90----00008944241CBB--0300008DB5------008BF850E80A00000074078B44", toolInfo.epOffset) ||
search.exactComparison("B8--------669C60508D905C0100006800004000833A000F84--------8B04248B0A0FBAF11F7313FD8BF08BF8037204037A08F3A583C20CFCEBD983C210", toolInfo.epOffset) ||
search.exactComparison("B8--------669C60508BD8030068--------6A00FF50148BCC8DA054BC0000508BC38D9010160000680000----51508004240850800424425080042461508004", toolInfo.epOffset) ||
search.exactComparison("B8--------669C60508BD8030068--------6A00FF501C894308680000----8B3C248B336681C780078D741E08893B538B5E10B880080000566A0250576A--6A", toolInfo.epOffset) ||
search.exactComparison("B8--------669C60508BD8030068--------6A00FF501C8943088BC303006870BC00006A00FF501C8BCC8DA070BC000089612E536800004000518B7C24048B33", toolInfo.epOffset) ||
search.exactComparison("B8--------669C60508D8800----008D90----00008BDC8BE1680000----53508004240850800424425080042461508004249D50800424BB833A000F84DC1400", toolInfo.epOffset) ||
search.exactComparison("B8--------68--------64FF350000000064892500000000669C6050", toolInfo.epOffset) ||
search.exactComparison("B8--------6A--68--------64FF350000000064892500000000669C60508BD8030068--------6A00FF50", toolInfo.epOffset))
{
addPacker(DetectionMethod::STRING_SEARCH_H, DetectionStrength::HIGH, "Petite");
}
}

/**
* Try to detect PELock packer
*/
Expand Down Expand Up @@ -1823,11 +1965,15 @@ void PeHeuristics::getFormatSpecificLanguageHeuristics()

void PeHeuristics::getFormatSpecificCompilerHeuristics()
{
getHeaderStyleHeuristics();
getSlashedSignatures();
getMorphineHeuristics();
getStarForceHeuristics();
getSafeDiscHeuristics();
getSecuROMHeuristics();
getMPRMMGVAHeuristics();
getActiveMarkHeuristics();
getPetiteHeuristics();
getPelockHeuristics();
getEzirizReactorHeuristics();
getUpxHeuristics();
Expand Down
6 changes: 5 additions & 1 deletion src/cpdetect/cptypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ DetectLanguage::~DetectLanguage()
ToolInformation::ToolInformation()
: epOffset(std::numeric_limits<unsigned long long>::max()),
epAddress(std::numeric_limits<unsigned long long>::max()),
imageBase(std::numeric_limits<unsigned long long>::max())
imageBase(std::numeric_limits<unsigned long long>::max()),
overlayOffset(0)
{

}
Expand Down Expand Up @@ -368,6 +369,9 @@ std::string detectionMetodToString(DetectionMethod method)
case DetectionMethod::MANIFEST_H:
return "manifest heuristic";

case DetectionMethod::HEADER_H:
return "dos header style";

case DetectionMethod::OTHER_H:
return "heuristic";

Expand Down