diff --git a/checksec.cpp b/checksec.cpp index 2ce04fc..4481c4c 100644 --- a/checksec.cpp +++ b/checksec.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "vendor/json.hpp" using json = nlohmann::json; @@ -161,6 +162,65 @@ Checksec::operator json() const { }; } +const std::string Checksec::detailedReport() const { + json j = toJson(); + std::string s = ""; + std::string sep = ""; + std::vector> 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 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); diff --git a/include/checksec.h b/include/checksec.h index 2941e61..8f7a47f 100644 --- a/include/checksec.h +++ b/include/checksec.h @@ -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/ + "(This was never released by Microsoft). Binaries with RFG enabled have " + "additional return-oriented-programming protections."; constexpr const char kSafeSEHDescription[] = "Binaries with SafeSEH enabled have additional protections for stack-based " @@ -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`) diff --git a/main.cpp b/main.cpp index 0a07e8b..9721ec8 100644 --- a/main.cpp +++ b/main.cpp @@ -3,12 +3,18 @@ using namespace std; void usage(char* argv[]) { - cerr << "Syntax : " << argv[0] << " [-j] " + cerr << "Syntax : " << argv[0] << " [-j|d] " + << "\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"; } @@ -22,6 +28,7 @@ int main(int argc, char* argv[]) { } bool jsonOutput = false; + bool detailedReport = false; string path; switch (argc) { @@ -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__; @@ -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"; }