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

Issue #82 Adds -d and -V flags, Add unsupported RFG notice #83

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
60 changes: 60 additions & 0 deletions checksec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <ostream>
#include <vector>
#include <optional>
#include <string>

#include "vendor/json.hpp"
using json = nlohmann::json;
Expand Down Expand Up @@ -161,6 +162,65 @@ Checksec::operator json() const {
};
}

const std::string Checksec::detailedReport() const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we currently want this functionality: it'll be a little unwieldy to maintain (since we don't currently have a nice way to just enumerate all of our checks), and its existence on the main Checksec class is another place where we fail to isolate with CLI from the C++ public API.

I'm happy to merge the rest of this PR, though.

json j = toJson();
std::string s = "";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you mentioned not being experienced with C++: the idiomatic way to do this kind of function is with a std::stringstream, which you can then feed chunks with the stream-style << operator. You can then pull the ultimate std::string out of the stream with std::stringstream::str().

std::string sep = "";
std::vector<std::vector<std::string>> name_keys{
{"Dynamic Base", "dynamicBase"},
{"ASLR", "aslr"},
{"High Entropy VA", "highEntropyVA"},
{"Force Integrity", "forceIntegrity"},
{"Isolation", "isolation"},
{"NX", "nx"},
{"SEH", "seh"},
{"CFG", "cfg"},
{"RFG", "rfg"},
{"SafeSEH", "safeSEH"},
{"GS", "gs"},
{"Authenticode", "authenticode"},
{".NET", "dotNET"},
};

for (std::vector<std::string> name_key : name_keys) {
std::string name = name_key[0];
std::string key = name_key[1];

s += sep;
sep = "\n";
s += "Mitigation: " + name + "\n";
s += "Presence: " + std::string(j["mitigations"][key]["presence"]) + "\n";

std::string word = "";
size_t col = 0;
size_t max = 54;
s += "Description: ";

for (char c : std::string(j["mitigations"][key]["description"])) {
if (c == ' ') {
if (word.length() + col > max) {
s += "\n ";
col = word.length();
} else if (col == 0) {
col = word.length();
} else {
s += " ";
col += word.length();
}
s += word;
word = std::string("");
} else {
word += c;
}
}
s += ' ' + word + "\n";
if (!j["mitigations"][key]["explanation"].is_null()) {
s += "Explanation: " + std::string(j["mitigations"][key]["explanation"]) + "\n";
}
}
return s;
}

const MitigationReport Checksec::isDynamicBase() const {
if (dllCharacteristics_ & peparse::IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) {
return REPORT(Present, kDynamicBaseDescription);
Expand Down
7 changes: 5 additions & 2 deletions include/checksec.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ constexpr const char kAuthenticodeDescription[] =
"Binaries with Authenticode signatures are verified at load time.";

constexpr const char kRFGDescription[] =
"Binaries with RFG enabled have additional return-oriented-programming "
"protections.";
// https://www.techrepublic.com/article/windows-10-security-how-the-shadow-stack-will-help-to-keep-the-hackers-at-bay/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This link is pretty light on details, consider replacing it with this one: https://xlab.tencent.com/en/2016/11/02/return-flow-guard/

Also, please put it above the variable declaration 🙂

"(This was never released by Microsoft). Binaries with RFG enabled have "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIt: Remove the parens and put this sentence at the end of the description.

"additional return-oriented-programming protections.";

constexpr const char kSafeSEHDescription[] =
"Binaries with SafeSEH enabled have additional protections for stack-based "
Expand Down Expand Up @@ -143,6 +144,8 @@ class Checksec {

json toJson() const;

const std::string detailedReport() const;

/**
* @return a MitigationReport indicating whether the program can be loaded from a dynamic base
* address (i.e. `/DYNAMICBASE`)
Expand Down
14 changes: 13 additions & 1 deletion main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@
using namespace std;

void usage(char* argv[]) {
cerr << "Syntax : " << argv[0] << " [-j] <dll|exe>"
cerr << "Syntax : " << argv[0] << " [-j|d] <dll|exe>"
<< "\n";
cerr << "Syntax : " << argv[0] << " -V"
<< "\n";
cerr << "Example: " << argv[0] << " -j doom2.exe"
<< "\n";
cerr << " -j will output json to stdout "
<< "\n";
cerr << " -d will give a detaile report to stdout "
<< "\n";
cerr << " -V print the version and exit "
<< "\n";
}

void version() { cerr << "Winchecksec version " << WINCHECKSEC_VERSION << "\n"; }
Expand All @@ -22,6 +28,7 @@ int main(int argc, char* argv[]) {
}

bool jsonOutput = false;
bool detailedReport = false;
string path;

switch (argc) {
Expand All @@ -36,6 +43,9 @@ int main(int argc, char* argv[]) {
if (string(argv[1]) == "-j") {
jsonOutput = true;
path = argv[2];
} else if (string(argv[1]) == "-d") {
detailedReport = true;
path = argv[2];
} else {
usage(argv);
return -__LINE__;
Expand All @@ -51,6 +61,8 @@ int main(int argc, char* argv[]) {

if (jsonOutput) {
cout << csec.toJson() << "\n";
} else if (detailedReport) {
cout << csec.detailedReport() << "\n";
} else {
cout << csec << "\n";
}
Expand Down