[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / llvm / test / tools / llvm-objcopy / MachO / Inputs / code-signature-check.py
blob2efcf80bdd41d44fd7e1962c162de80fe93e0a37
1 """Checks the validity of MachO binary signatures
3 MachO binaries sometimes include a LC_CODE_SIGNATURE load command
4 and corresponding section in the __LINKEDIT segment that together
5 work to "sign" the binary. This script is used to check the validity
6 of this signature.
8 Usage:
9 ./code-signature-check.py my_binary 800 300 0 800
11 Arguments:
12 binary - The MachO binary to be tested
13 offset - The offset from the start of the binary to where the code signature section begins
14 size - The size of the code signature section in the binary
15 code_offset - The point in the binary to begin hashing
16 code_size - The length starting from code_offset to hash
17 """
19 import argparse
20 import collections
21 import hashlib
22 import itertools
23 import struct
24 import sys
25 import typing
28 class CodeDirectoryVersion:
29 SUPPORTSSCATTER = 0x20100
30 SUPPORTSTEAMID = 0x20200
31 SUPPORTSCODELIMIT64 = 0x20300
32 SUPPORTSEXECSEG = 0x20400
35 class CodeDirectory:
36 @staticmethod
37 def make(
38 buf: memoryview,
39 ) -> typing.Union[
40 "CodeDirectoryBase",
41 "CodeDirectoryV20100",
42 "CodeDirectoryV20200",
43 "CodeDirectoryV20300",
44 "CodeDirectoryV20400",
46 _magic, _length, version = struct.unpack_from(">III", buf, 0)
47 subtype = {
48 CodeDirectoryVersion.SUPPORTSSCATTER: CodeDirectoryV20100,
49 CodeDirectoryVersion.SUPPORTSTEAMID: CodeDirectoryV20200,
50 CodeDirectoryVersion.SUPPORTSCODELIMIT64: CodeDirectoryV20300,
51 CodeDirectoryVersion.SUPPORTSEXECSEG: CodeDirectoryV20400,
52 }.get(version, CodeDirectoryBase)
54 return subtype._make(struct.unpack_from(subtype._format(), buf, 0))
57 class CodeDirectoryBase(typing.NamedTuple):
58 magic: int
59 length: int
60 version: int
61 flags: int
62 hashOffset: int
63 identOffset: int
64 nSpecialSlots: int
65 nCodeSlots: int
66 codeLimit: int
67 hashSize: int
68 hashType: int
69 platform: int
70 pageSize: int
71 spare2: int
73 @staticmethod
74 def _format() -> str:
75 return ">IIIIIIIIIBBBBI"
78 class CodeDirectoryV20100(typing.NamedTuple):
79 magic: int
80 length: int
81 version: int
82 flags: int
83 hashOffset: int
84 identOffset: int
85 nSpecialSlots: int
86 nCodeSlots: int
87 codeLimit: int
88 hashSize: int
89 hashType: int
90 platform: int
91 pageSize: int
92 spare2: int
94 scatterOffset: int
96 @staticmethod
97 def _format() -> str:
98 return CodeDirectoryBase._format() + "I"
101 class CodeDirectoryV20200(typing.NamedTuple):
102 magic: int
103 length: int
104 version: int
105 flags: int
106 hashOffset: int
107 identOffset: int
108 nSpecialSlots: int
109 nCodeSlots: int
110 codeLimit: int
111 hashSize: int
112 hashType: int
113 platform: int
114 pageSize: int
115 spare2: int
117 scatterOffset: int
119 teamOffset: int
121 @staticmethod
122 def _format() -> str:
123 return CodeDirectoryV20100._format() + "I"
126 class CodeDirectoryV20300(typing.NamedTuple):
127 magic: int
128 length: int
129 version: int
130 flags: int
131 hashOffset: int
132 identOffset: int
133 nSpecialSlots: int
134 nCodeSlots: int
135 codeLimit: int
136 hashSize: int
137 hashType: int
138 platform: int
139 pageSize: int
140 spare2: int
142 scatterOffset: int
144 teamOffset: int
146 spare3: int
147 codeLimit64: int
149 @staticmethod
150 def _format() -> str:
151 return CodeDirectoryV20200._format() + "IQ"
154 class CodeDirectoryV20400(typing.NamedTuple):
155 magic: int
156 length: int
157 version: int
158 flags: int
159 hashOffset: int
160 identOffset: int
161 nSpecialSlots: int
162 nCodeSlots: int
163 codeLimit: int
164 hashSize: int
165 hashType: int
166 platform: int
167 pageSize: int
168 spare2: int
170 scatterOffset: int
172 teamOffset: int
174 spare3: int
175 codeLimit64: int
177 execSegBase: int
178 execSegLimit: int
179 execSegFlags: int
181 @staticmethod
182 def _format() -> str:
183 return CodeDirectoryV20300._format() + "QQQ"
186 class CodeDirectoryBlobIndex(typing.NamedTuple):
187 type_: int
188 offset: int
190 @staticmethod
191 def make(buf: memoryview) -> "CodeDirectoryBlobIndex":
192 return CodeDirectoryBlobIndex._make(
193 struct.unpack_from(CodeDirectoryBlobIndex.__format(), buf, 0)
196 @staticmethod
197 def bytesize() -> int:
198 return struct.calcsize(CodeDirectoryBlobIndex.__format())
200 @staticmethod
201 def __format() -> str:
202 return ">II"
205 class CodeDirectorySuperBlob(typing.NamedTuple):
206 magic: int
207 length: int
208 count: int
209 blob_indices: typing.List[CodeDirectoryBlobIndex]
211 @staticmethod
212 def make(buf: memoryview) -> "CodeDirectorySuperBlob":
213 super_blob_layout = ">III"
214 super_blob = struct.unpack_from(super_blob_layout, buf, 0)
216 offset = struct.calcsize(super_blob_layout)
217 blob_indices = []
218 for idx in range(super_blob[2]):
219 blob_indices.append(CodeDirectoryBlobIndex.make(buf[offset:]))
220 offset += CodeDirectoryBlobIndex.bytesize()
222 return CodeDirectorySuperBlob(*super_blob, blob_indices)
225 def unpack_null_terminated_string(buf: memoryview) -> str:
226 b = bytes(itertools.takewhile(lambda b: b != 0, buf))
227 return b.decode()
230 def main():
231 parser = argparse.ArgumentParser()
232 parser.add_argument(
233 "binary", type=argparse.FileType("rb"), help="The file to analyze"
235 parser.add_argument(
236 "offset", type=int, help="Offset to start of Code Directory data"
238 parser.add_argument("size", type=int, help="Size of Code Directory data")
239 parser.add_argument(
240 "code_offset", type=int, help="Offset to start of code pages to hash"
242 parser.add_argument("code_size", type=int, help="Size of the code pages to hash")
244 args = parser.parse_args()
246 args.binary.seek(args.offset)
247 super_blob_bytes = args.binary.read(args.size)
248 super_blob_mem = memoryview(super_blob_bytes)
250 super_blob = CodeDirectorySuperBlob.make(super_blob_mem)
251 print(super_blob)
253 for blob_index in super_blob.blob_indices:
254 code_directory_offset = blob_index.offset
255 code_directory = CodeDirectory.make(super_blob_mem[code_directory_offset:])
256 print(code_directory)
258 ident_offset = code_directory_offset + code_directory.identOffset
259 print(
260 "Code Directory ID: "
261 + unpack_null_terminated_string(super_blob_mem[ident_offset:])
264 code_offset = args.code_offset
265 code_end = code_offset + args.code_size
266 page_size = 1 << code_directory.pageSize
267 args.binary.seek(code_offset)
269 hashes_offset = code_directory_offset + code_directory.hashOffset
270 for idx in range(code_directory.nCodeSlots):
271 hash_bytes = bytes(
272 super_blob_mem[hashes_offset : hashes_offset + code_directory.hashSize]
274 hashes_offset += code_directory.hashSize
276 hasher = hashlib.sha256()
277 read_size = min(page_size, code_end - code_offset)
278 hasher.update(args.binary.read(read_size))
279 calculated_hash_bytes = hasher.digest()
280 code_offset += read_size
282 print("%s <> %s" % (hash_bytes.hex(), calculated_hash_bytes.hex()))
284 if hash_bytes != calculated_hash_bytes:
285 sys.exit(-1)
288 if __name__ == "__main__":
289 main()