Reland the ULONG -> SIZE_T change from 317177
[chromium-blink-merge.git] / tools / checkbins / checkbins.py
blob213f30a303b2a3e93ce7cda11be47f748360f4b8
1 #!/usr/bin/env python
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
7 correctly.
9 In essense it runs a subset of BinScope tests ensuring that binaries have
10 /NXCOMPAT, /DYNAMICBASE and /SAFESEH.
11 """
13 import os
14 import optparse
15 import sys
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'))
20 import pefile
22 PE_FILE_EXTENSIONS = ['.exe', '.dll']
23 DYNAMICBASE_FLAG = 0x0040
24 NXCOMPAT_FLAG = 0x0100
25 NO_SEH_FLAG = 0x0400
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',
32 'mini_installer.exe',
33 'wow_helper.exe',
34 'xinput1_3.dll' # Microsoft DirectX redistributable.
37 def IsPEFile(path):
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):
43 directory = args[0]
44 pe_total = 0
45 pe_passed = 0
47 for file in os.listdir(directory):
48 path = os.path.abspath(os.path.join(directory, file))
49 if not IsPEFile(path):
50 continue
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
55 success = True
57 # Check for /DYNAMICBASE.
58 if pe.OPTIONAL_HEADER.DllCharacteristics & DYNAMICBASE_FLAG:
59 if options.verbose:
60 print "Checking %s for /DYNAMICBASE... PASS" % path
61 else:
62 success = False
63 print "Checking %s for /DYNAMICBASE... FAIL" % path
65 # Check for /NXCOMPAT.
66 if pe.OPTIONAL_HEADER.DllCharacteristics & NXCOMPAT_FLAG:
67 if options.verbose:
68 print "Checking %s for /NXCOMPAT... PASS" % path
69 else:
70 success = False
71 print "Checking %s for /NXCOMPAT... FAIL" % path
73 # Check for /SAFESEH. Binaries should meet one of the following
74 # criteria:
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):
86 if options.verbose:
87 print "Checking %s for /SAFESEH... PASS" % path
88 else:
89 success = False
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))
98 success = False
99 elif options.verbose:
100 print("Checking %s ImageBase (0x%X > 4GB)... PASS" %
101 (path, pe.OPTIONAL_HEADER.ImageBase))
103 # Update tally.
104 if success:
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:
109 sys.exit(1)
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()
117 if not args:
118 option_parser.print_help()
119 sys.exit(0)
120 main(options, args)