2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Makes sure that all EXE and DLL files in the provided directory were built
9 In essense it runs a subset of BinScope tests ensuring that binaries have
10 /NXCOMPAT, /DYNAMICBASE and /SAFESEH.
17 # Find /third_party/pefile based on current directory and script path.
18 sys
.path
.append(os
.path
.join(os
.path
.dirname(__file__
), '..', '..',
19 'third_party', 'pefile'))
22 PE_FILE_EXTENSIONS
= ['.exe', '.dll']
23 DYNAMICBASE_FLAG
= 0x0040
24 NXCOMPAT_FLAG
= 0x0100
26 MACHINE_TYPE_AMD64
= 0x8664
28 # Please do not add your file here without confirming that it indeed doesn't
29 # require /NXCOMPAT and /DYNAMICBASE. Contact cpu@chromium.org or your local
30 # Windows guru for advice.
31 EXCLUDED_FILES
= ['chrome_frame_mini_installer.exe',
34 'xinput1_3.dll' # Microsoft DirectX redistributable.
38 return (os
.path
.isfile(path
) and
39 os
.path
.splitext(path
)[1].lower() in PE_FILE_EXTENSIONS
and
40 os
.path
.basename(path
) not in EXCLUDED_FILES
)
42 def main(options
, args
):
47 for file in os
.listdir(directory
):
48 path
= os
.path
.abspath(os
.path
.join(directory
, file))
49 if not IsPEFile(path
):
51 pe
= pefile
.PE(path
, fast_load
=True)
52 pe
.parse_data_directories(directories
=[
53 pefile
.DIRECTORY_ENTRY
['IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG']])
54 pe_total
= pe_total
+ 1
57 # Check for /DYNAMICBASE.
58 if pe
.OPTIONAL_HEADER
.DllCharacteristics
& DYNAMICBASE_FLAG
:
60 print "Checking %s for /DYNAMICBASE... PASS" % path
63 print "Checking %s for /DYNAMICBASE... FAIL" % path
65 # Check for /NXCOMPAT.
66 if pe
.OPTIONAL_HEADER
.DllCharacteristics
& NXCOMPAT_FLAG
:
68 print "Checking %s for /NXCOMPAT... PASS" % path
71 print "Checking %s for /NXCOMPAT... FAIL" % path
73 # Check for /SAFESEH. Binaries should meet one of the following
75 # 1) Have no SEH table as indicated by the DLL characteristics
76 # 2) Have a LOAD_CONFIG section containing a valid SEH table
77 # 3) Be a 64-bit binary, in which case /SAFESEH isn't required
79 # Refer to the following MSDN article for more information:
80 # http://msdn.microsoft.com/en-us/library/9a89h429.aspx
81 if (pe
.OPTIONAL_HEADER
.DllCharacteristics
& NO_SEH_FLAG
or
82 (hasattr(pe
, "DIRECTORY_ENTRY_LOAD_CONFIG") and
83 pe
.DIRECTORY_ENTRY_LOAD_CONFIG
.struct
.SEHandlerCount
> 0 and
84 pe
.DIRECTORY_ENTRY_LOAD_CONFIG
.struct
.SEHandlerTable
!= 0) or
85 pe
.FILE_HEADER
.Machine
== MACHINE_TYPE_AMD64
):
87 print "Checking %s for /SAFESEH... PASS" % path
90 print "Checking %s for /SAFESEH... FAIL" % path
92 # ASLR is weakened on Windows 64-bit when the ImageBase is below 4GB
93 # (because the loader will never be rebase the image above 4GB).
94 if pe
.FILE_HEADER
.Machine
== MACHINE_TYPE_AMD64
:
95 if pe
.OPTIONAL_HEADER
.ImageBase
<= 0xFFFFFFFF:
96 print("Checking %s ImageBase (0x%X < 4GB)... FAIL" %
97 (path
, pe
.OPTIONAL_HEADER
.ImageBase
))
100 print("Checking %s ImageBase (0x%X > 4GB)... PASS" %
101 (path
, pe
.OPTIONAL_HEADER
.ImageBase
))
105 pe_passed
= pe_passed
+ 1
107 print "Result: %d files found, %d files passed" % (pe_total
, pe_passed
)
108 if pe_passed
!= pe_total
:
111 if __name__
== '__main__':
112 usage
= "Usage: %prog [options] DIRECTORY"
113 option_parser
= optparse
.OptionParser(usage
=usage
)
114 option_parser
.add_option("-v", "--verbose", action
="store_true",
115 default
=False, help="Print debug logging")
116 options
, args
= option_parser
.parse_args()
118 option_parser
.print_help()