Skip to content

trailofbits/winchecksec

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

winchecksec

CI

winchecksec performs static detection of common Windows security features.

The following security features are currently detected:

  • ASLR:
    • /DYNAMICBASE with stripped relocation entries edge-case
    • /HIGHENTROPYVA for 64-bit systems
  • Code integrity/signing:
    • /INTEGRITYCHECK
    • Authenticode-signed with a valid (trusted, active) certificate (currently unsupported on Linux)
  • DEP (a.k.a. W^X, NX)
  • Manifest isolation via (/ALLOWISOLATION)
  • Structured Exception Handling and SafeSEH support
  • Control Flow Guard and Return Flow Guard instrumentation
  • Stack cookie (/GS) support

Building

winchecksec depends on pe-parse and uthenticode, which can be installed via vcpkg:

$ vcpkg install pe-parse uthenticode

NOTE: On Windows, vcpkg defaults to 32-bit builds. If you're doing a 64-bit winchecksec build, you'll need to explicitly build the dependencies as 64-bit:

$ vcpkg install pe-parse:x64-windows uthenticode:x64-windows

Building on Linux

$ git clone https://github.com/trailofbits/winchecksec.git
$ cd winchecksec
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release ..
$ cmake --build .
$ ./build/winchecksec

Building on Windows

> git clone https://github.com/trailofbits/winchecksec.git
> cd winchecksec
> mkdir build
> cd build
> cmake ..
> cmake --build . --config Release
> .\Release\winchecksec.exe C:\Windows\notepad.exe

Usage

As a command-line tool, winchecksec has two output modes: a plain-text mode for easy reading, and a JSON mode for consumption in other programs. The plain-text mode is the default; JSON output is enabled by passing --json or -j:

> .\Release\winchecksec.exe C:\Windows\notepad.exe

Dynamic Base    : "Present"
ASLR            : "Present"
High Entropy VA : "Present"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "Present"
SEH             : "Present"
CFG             : "NotPresent"
RFG             : "NotPresent"
SafeSEH         : "NotApplicable"
GS              : "Present"
Authenticode    : "NotPresent"
.NET            : "NotPresent"

> .\Release\winchecksec.exe -j C:\Windows\notepad.exe

[{
   "path": "C:\\Windows\\notepad.exe",
   "mitigations": {
      "dynamicBase": {
         "presence": "Present",
         "description": "Binaries with dynamic base support can be dynamically rebased, enabling ASLR."
      },
      "rfg": {
         "description": "Binaries with RFG enabled have additional return-oriented-programming protections.",
         "presence": "NotPresent"
      },
      "seh": {
         "description": "Binaries with SEH support can use structured exception handlers.",
         "presence": "Present"
      },
      // ...
   }
}]

winchecksec also provides a C++ API; documentation is hosted here.

Hacking

winchecksec is formatted with clang-format. You can use the clang-format target to auto-format it locally:

$ make clang-format

winchecksec also comes with a suite of unit tests that use pegoat as a reference for various security mitigations. To build the unit tests, pass -DBUILD_TESTS=1 to the CMake build.

Statistics for different flags across EXEs on Windows 10

Prevalence of various security features on a vanilla Windows 10 (1803) installation:

aslr authenticode cfg dynamicBase forceIntegrity gs highEntropyVA isolation nx rfg safeSEH seh
79% 37% 49% 79% 3% 65% 43% 100% 79% 6% 25% 91%