15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Usage: change_mach_o_flags.py [--executable-heap] [--no-pie] <executablepath> 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Arranges for the executable at |executable_path| to have its data (heap) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)pages protected to prevent execution on Mac OS X 10.7 ("Lion"), and to have 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the PIE (position independent executable) bit set to enable ASLR (address 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)space layout randomization). With --executable-heap or --no-pie, the 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)respective bits are cleared instead of set, making the heap executable or 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)disabling PIE/ASLR. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This script is able to operate on thin (single-architecture) Mach-O files 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)and fat (universal, multi-architecture) files. When operating on fat files, 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)it will set or clear the bits for each architecture contained therein. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NON-EXECUTABLE HEAP 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Traditionally in Mac OS X, 32-bit processes did not have data pages set to 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)prohibit execution. Although user programs could call mprotect and 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)mach_vm_protect to deny execution of code in data pages, the kernel would 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)silently ignore such requests without updating the page tables, and the 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hardware would happily execute code on such pages. 64-bit processes were 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)always given proper hardware protection of data pages. This behavior was 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)controllable on a system-wide level via the vm.allow_data_exec sysctl, which 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)is set by default to 1. The bit with value 1 (set by default) allows code 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)execution on data pages for 32-bit processes, and the bit with value 2 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(clear by default) does the same for 64-bit processes. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)In Mac OS X 10.7, executables can "opt in" to having hardware protection 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)against code execution on data pages applied. This is done by setting a new 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bit in the |flags| field of an executable's |mach_header|. When 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MH_NO_HEAP_EXECUTION is set, proper protections will be applied, regardless 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)of the setting of vm.allow_data_exec. See xnu-1699.22.73/osfmk/vm/vm_map.c 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)override_nx and xnu-1699.22.73/bsd/kern/mach_loader.c load_machfile. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The Apple toolchain has been revised to set the MH_NO_HEAP_EXECUTION when 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)producing executables, provided that -allow_heap_execute is not specified 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)at link time. Only linkers shipping with Xcode 4.0 and later (ld64-123.2 and 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)later) have this ability. See ld64-123.2.1/src/ld/Options.cpp 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Options::reconfigureDefaults() and 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ld64-123.2.1/src/ld/HeaderAndLoadCommands.hpp 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HeaderAndLoadCommandsAtom<A>::flags(). 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This script sets the MH_NO_HEAP_EXECUTION bit on Mach-O executables. It is 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)intended for use with executables produced by a linker that predates Apple's 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)modifications to set this bit itself. It is also useful for setting this bit 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)for non-i386 executables, including x86_64 executables. Apple's linker only 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sets it for 32-bit i386 executables, presumably under the assumption that 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the value of vm.allow_data_exec is set in stone. However, if someone were to 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)change vm.allow_data_exec to 2 or 3, 64-bit x86_64 executables would run 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)without hardware protection against code execution on data pages. This 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)script can set the bit for x86_64 executables, guaranteeing that they run 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)with appropriate protection even when vm.allow_data_exec has been tampered 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)with. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)POSITION-INDEPENDENT EXECUTABLES/ADDRESS SPACE LAYOUT RANDOMIZATION 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This script sets or clears the MH_PIE bit in an executable's Mach-O header, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enabling or disabling position independence on Mac OS X 10.5 and later. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Processes running position-independent executables have varying levels of 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ASLR protection depending on the OS release. The main executable's load 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)address, shared library load addresess, and the heap and stack base 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)addresses may be randomized. Position-independent executables are produced 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)by supplying the -pie flag to the linker (or defeated by supplying -no_pie). 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Executables linked with a deployment target of 10.7 or higher have PIE on 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)by default. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This script is never strictly needed during the build to enable PIE, as all 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)linkers used are recent enough to support -pie. However, it's used to 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)disable the PIE bit as needed on already-linked executables. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import optparse 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import struct 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# <mach-o/fat.h> 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FAT_MAGIC = 0xcafebabe 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FAT_CIGAM = 0xbebafeca 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# <mach-o/loader.h> 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MH_MAGIC = 0xfeedface 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MH_CIGAM = 0xcefaedfe 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MH_MAGIC_64 = 0xfeedfacf 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MH_CIGAM_64 = 0xcffaedfe 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MH_EXECUTE = 0x2 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MH_PIE = 0x00200000 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MH_NO_HEAP_EXECUTION = 0x01000000 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MachOError(Exception): 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A class for exceptions thrown by this module.""" 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CheckedSeek(file, offset): 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Seeks the file-like object at |file| to offset |offset| and raises a 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MachOError if anything funny happens.""" 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file.seek(offset, os.SEEK_SET) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_offset = file.tell() 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if new_offset != offset: 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise MachOError, \ 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'seek: expected offset %d, observed %d' % (offset, new_offset) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CheckedRead(file, count): 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Reads |count| bytes from the file-like |file| object, raising a 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MachOError if any other number of bytes is read.""" 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes = file.read(count) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(bytes) != count: 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise MachOError, \ 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'read: expected length %d, observed %d' % (count, len(bytes)) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return bytes 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ReadUInt32(file, endian): 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Reads an unsinged 32-bit integer from the file-like |file| object, 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) treating it as having endianness specified by |endian| (per the |struct| 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) module), and returns it as a number. Raises a MachOError if the proper 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length of data can't be read from |file|.""" 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes = CheckedRead(file, 4) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (uint32,) = struct.unpack(endian + 'I', bytes) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return uint32 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ReadMachHeader(file, endian): 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Reads an entire |mach_header| structure (<mach-o/loader.h>) from the 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file-like |file| object, treating it as having endianness specified by 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) |endian| (per the |struct| module), and returns a 7-tuple of its members 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) as numbers. Raises a MachOError if the proper length of data can't be read 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) from |file|.""" 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes = CheckedRead(file, 28) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \ 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct.unpack(endian + '7I', bytes) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ReadFatArch(file): 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Reads an entire |fat_arch| structure (<mach-o/fat.h>) from the file-like 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) |file| object, treating it as having endianness specified by |endian| 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (per the |struct| module), and returns a 5-tuple of its members as numbers. 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Raises a MachOError if the proper length of data can't be read from 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) |file|.""" 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes = CheckedRead(file, 20) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cputype, cpusubtype, offset, size, align = struct.unpack('>5I', bytes) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cputype, cpusubtype, offset, size, align 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def WriteUInt32(file, uint32, endian): 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Writes |uint32| as an unsinged 32-bit integer to the file-like |file| 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) object, treating it as having endianness specified by |endian| (per the 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) |struct| module).""" 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes = struct.pack(endian + 'I', uint32) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert len(bytes) == 4 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file.write(bytes) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def HandleMachOFile(file, options, offset=0): 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Seeks the file-like |file| object to |offset|, reads its |mach_header|, 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) and rewrites the header's |flags| field if appropriate. The header's 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) endianness is detected. Both 32-bit and 64-bit Mach-O headers are supported 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (mach_header and mach_header_64). Raises MachOError if used on a header that 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) does not have a known magic number or is not of type MH_EXECUTE. The 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MH_PIE and MH_NO_HEAP_EXECUTION bits are set or cleared in the |flags| field 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) according to |options| and written to |file| if any changes need to be made. 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) If already set or clear as specified by |options|, nothing is written.""" 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckedSeek(file, offset) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) magic = ReadUInt32(file, '<') 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if magic == MH_MAGIC or magic == MH_MAGIC_64: 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) endian = '<' 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif magic == MH_CIGAM or magic == MH_CIGAM_64: 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) endian = '>' 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise MachOError, \ 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'Mach-O file at offset %d has illusion of magic' % offset 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckedSeek(file, offset) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \ 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReadMachHeader(file, endian) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert magic == MH_MAGIC or magic == MH_MAGIC_64 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if filetype != MH_EXECUTE: 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise MachOError, \ 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'Mach-O file at offset %d is type 0x%x, expected MH_EXECUTE' % \ 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (offset, filetype) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) original_flags = flags 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if options.no_heap_execution: 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flags |= MH_NO_HEAP_EXECUTION 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flags &= ~MH_NO_HEAP_EXECUTION 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if options.pie: 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flags |= MH_PIE 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flags &= ~MH_PIE 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if flags != original_flags: 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckedSeek(file, offset + 24) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteUInt32(file, flags, endian) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def HandleFatFile(file, options, fat_offset=0): 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Seeks the file-like |file| object to |offset| and loops over its 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) |fat_header| entries, calling HandleMachOFile for each.""" 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckedSeek(file, fat_offset) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) magic = ReadUInt32(file, '>') 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert magic == FAT_MAGIC 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nfat_arch = ReadUInt32(file, '>') 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for index in xrange(0, nfat_arch): 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cputype, cpusubtype, offset, size, align = ReadFatArch(file) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert size >= 28 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # HandleMachOFile will seek around. Come back here after calling it, in 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # case it sought. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fat_arch_offset = file.tell() 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleMachOFile(file, options, offset) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckedSeek(file, fat_arch_offset) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main(me, args): 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parser = optparse.OptionParser('%prog [options] <executable_path>') 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parser.add_option('--executable-heap', action='store_false', 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='no_heap_execution', default=True, 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Clear the MH_NO_HEAP_EXECUTION bit') 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parser.add_option('--no-pie', action='store_false', 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='pie', default=True, 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Clear the MH_PIE bit') 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (options, loose_args) = parser.parse_args(args) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(loose_args) != 1: 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parser.print_usage() 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executable_path = loose_args[0] 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executable_file = open(executable_path, 'rb+') 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) magic = ReadUInt32(executable_file, '<') 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if magic == FAT_CIGAM: 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Check FAT_CIGAM and not FAT_MAGIC because the read was little-endian. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleFatFile(executable_file, options) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif magic == MH_MAGIC or magic == MH_CIGAM or \ 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) magic == MH_MAGIC_64 or magic == MH_CIGAM_64: 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleMachOFile(executable_file, options) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise MachOError, '%s is not a Mach-O or fat file' % executable_file 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executable_file.close() 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__': 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.exit(main(sys.argv[0], sys.argv[1:])) 274