OLD | NEW |
---|---|
1 #!/usr/bin/python | 1 #!/usr/bin/python |
M-A Ruel
2011/11/21 19:58:34
#!/usr/bin/env python
scherkus (not reviewing)
2011/11/21 20:33:58
Done.
| |
2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Makes sure that all EXE and DLL files in the provided directory were built | 6 """Makes sure that all EXE and DLL files in the provided directory were built |
7 correctly. | 7 correctly. |
8 | 8 |
9 Currently this tool will check that binaries were built with /NXCOMPAT and | 9 In essense it runs a subset of BinScope tests ensuring that binaries have |
10 /DYNAMICBASE set. | 10 /NXCOMPAT, /DYNAMICBASE and /SAFESEH. |
11 """ | 11 """ |
12 | 12 |
13 import os | 13 import os |
14 import optparse | 14 import optparse |
15 import sys | 15 import sys |
16 | 16 |
17 # Find /third_party/pefile based on current directory and script path. | 17 # Find /third_party/pefile based on current directory and script path. |
18 sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', | 18 sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', |
19 'third_party', 'pefile')) | 19 'third_party', 'pefile')) |
20 import pefile | 20 import pefile |
21 | 21 |
22 PE_FILE_EXTENSIONS = ['.exe', '.dll'] | 22 PE_FILE_EXTENSIONS = ['.exe', '.dll'] |
23 DYNAMICBASE_FLAG = 0x0040 | 23 DYNAMICBASE_FLAG = 0x0040 |
24 NXCOMPAT_FLAG = 0x0100 | 24 NXCOMPAT_FLAG = 0x0100 |
25 NO_SEH_FLAG = 0x0400 | |
25 | 26 |
26 # Please do not add your file here without confirming that it indeed doesn't | 27 # Please do not add your file here without confirming that it indeed doesn't |
27 # require /NXCOMPAT and /DYNAMICBASE. Contact cpu@chromium.org or your local | 28 # require /NXCOMPAT and /DYNAMICBASE. Contact cpu@chromium.org or your local |
28 # Windows guru for advice. | 29 # Windows guru for advice. |
29 EXCLUDED_FILES = ['chrome_frame_mini_installer.exe', | 30 EXCLUDED_FILES = ['chrome_frame_mini_installer.exe', |
30 'mini_installer.exe', | 31 'mini_installer.exe', |
31 'wow_helper.exe'] | 32 'wow_helper.exe'] |
32 | 33 |
33 def IsPEFile(path): | 34 def IsPEFile(path): |
34 return (os.path.isfile(path) and | 35 return (os.path.isfile(path) and |
35 os.path.splitext(path)[1].lower() in PE_FILE_EXTENSIONS and | 36 os.path.splitext(path)[1].lower() in PE_FILE_EXTENSIONS and |
36 os.path.basename(path) not in EXCLUDED_FILES) | 37 os.path.basename(path) not in EXCLUDED_FILES) |
37 | 38 |
38 def main(options, args): | 39 def main(options, args): |
39 directory = args[0] | 40 directory = args[0] |
40 pe_total = 0 | 41 pe_total = 0 |
41 pe_passed = 0 | 42 pe_passed = 0 |
42 | 43 |
43 for file in os.listdir(directory): | 44 for file in os.listdir(directory): |
44 path = os.path.abspath(os.path.join(directory, file)) | 45 path = os.path.abspath(os.path.join(directory, file)) |
45 if not IsPEFile(path): | 46 if not IsPEFile(path): |
46 continue | 47 continue |
47 pe = pefile.PE(path, fast_load=True) | 48 pe = pefile.PE(path, fast_load=True) |
49 pe.parse_data_directories(directories=[ | |
50 pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG']]) | |
48 pe_total = pe_total + 1 | 51 pe_total = pe_total + 1 |
49 success = True | 52 success = True |
50 | 53 |
51 # Check for /DYNAMICBASE. | 54 # Check for /DYNAMICBASE. |
52 if pe.OPTIONAL_HEADER.DllCharacteristics & DYNAMICBASE_FLAG: | 55 if pe.OPTIONAL_HEADER.DllCharacteristics & DYNAMICBASE_FLAG: |
53 if options.verbose: | 56 if options.verbose: |
54 print "Checking %s for /DYNAMICBASE... PASS" % path | 57 print "Checking %s for /DYNAMICBASE... PASS" % path |
55 else: | 58 else: |
56 success = False | 59 success = False |
57 print "Checking %s for /DYNAMICBASE... FAIL" % path | 60 print "Checking %s for /DYNAMICBASE... FAIL" % path |
58 | 61 |
59 # Check for /NXCOMPAT. | 62 # Check for /NXCOMPAT. |
60 if pe.OPTIONAL_HEADER.DllCharacteristics & NXCOMPAT_FLAG: | 63 if pe.OPTIONAL_HEADER.DllCharacteristics & NXCOMPAT_FLAG: |
61 if options.verbose: | 64 if options.verbose: |
62 print "Checking %s for /NXCOMPAT... PASS" % path | 65 print "Checking %s for /NXCOMPAT... PASS" % path |
63 else: | 66 else: |
64 success = False | 67 success = False |
65 print "Checking %s for /NXCOMPAT... FAIL" % path | 68 print "Checking %s for /NXCOMPAT... FAIL" % path |
66 | 69 |
70 # Check for /SAFESEH. Binaries should either have no SEH table | |
71 # (in which case a bit is set in the DLL characteristics section) | |
72 # or there should be a LOAD_CONFIG section present containing | |
73 # the SEH table. | |
74 if (pe.OPTIONAL_HEADER.DllCharacteristics & NO_SEH_FLAG or | |
75 hasattr(pe, "DIRECTORY_ENTRY_LOAD_CONFIG")): | |
Sigurður Ásgeirsson
2011/11/21 20:27:32
The load config, if present, also needs to have a
scherkus (not reviewing)
2011/11/21 20:33:58
Done.
| |
76 if options.verbose: | |
77 print "Checking %s for /SAFESEH... PASS" % path | |
78 else: | |
79 # TODO(scherkus): uncomment this code after we're confident that we | |
80 # won't cause unintentional failures on the build bots. | |
81 #success = False | |
82 print "Checking %s for /SAFESEH... FAIL" % path | |
83 | |
67 # Update tally. | 84 # Update tally. |
68 if success: | 85 if success: |
69 pe_passed = pe_passed + 1 | 86 pe_passed = pe_passed + 1 |
70 | 87 |
71 print "Result: %d files found, %d files passed" % (pe_total, pe_passed) | 88 print "Result: %d files found, %d files passed" % (pe_total, pe_passed) |
72 if pe_passed != pe_total: | 89 if pe_passed != pe_total: |
73 sys.exit(1) | 90 sys.exit(1) |
74 | 91 |
75 if __name__ == '__main__': | 92 if __name__ == '__main__': |
76 usage = "Usage: %prog [options] DIRECTORY" | 93 usage = "Usage: %prog [options] DIRECTORY" |
77 option_parser = optparse.OptionParser(usage=usage) | 94 option_parser = optparse.OptionParser(usage=usage) |
78 option_parser.add_option("-v", "--verbose", action="store_true", | 95 option_parser.add_option("-v", "--verbose", action="store_true", |
79 default=False, help="Print debug logging") | 96 default=False, help="Print debug logging") |
80 options, args = option_parser.parse_args() | 97 options, args = option_parser.parse_args() |
81 if not args: | 98 if not args: |
82 option_parser.print_help() | 99 option_parser.print_help() |
83 sys.exit(0) | 100 sys.exit(0) |
84 main(options, args) | 101 main(options, args) |
OLD | NEW |