1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
31 #include <Availability.h>
34 #include "dyld_cache_format.h"
35 #include "Architectures.hpp"
36 #include "MachOFileAbstraction.hpp"
37 #include "CacheFileAbstraction.hpp"
39 #include "dsc_slider.h"
41 int update_dyld_shared_cache_load_address(const char* path
, void (*logProc
)(const char* format
, ...) )
43 int fd
= open(path
, O_RDONLY
, 0);
45 (*logProc
)("open(%s) failed, errno=%d\n", path
, errno
);
48 (void)fcntl(fd
, F_NOCACHE
, 1); // tell kernel to not cache file content
51 if ( read(fd
, buffer
, 4096) != 4096 ) {
52 (*logProc
)("read(%s) failed, errno=%d\n", path
, errno
);
56 bool has64BitPointers
= false;
57 bool isBigEndian
= false;
58 uint64_t startReadOnlySharedRegion
= 0;
59 uint64_t endReadOnlySharedRegion
= 0;
60 uint64_t startReadWriteSharedRegion
= 0;
61 uint64_t endReadWriteSharedRegion
= 0;
62 if ( strcmp((char*)buffer
, "dyld_v1 i386") == 0 ) {
63 has64BitPointers
= false;
66 else if ( strcmp((char*)buffer
, "dyld_v1 x86_64") == 0 ) {
67 has64BitPointers
= true;
69 startReadOnlySharedRegion
= 0x7FFF80000000LL
;
70 endReadOnlySharedRegion
= 0x7FFFC0000000LL
;
71 startReadWriteSharedRegion
= 0x7FFF70000000LL
;
72 endReadWriteSharedRegion
= 0x7FFF80000000LL
;
74 else if ( strcmp((char*)buffer
, "dyld_v1 ppc") == 0 ) {
75 has64BitPointers
= false;
78 else if ( strcmp((char*)buffer
, "dyld_v1 armv5") == 0 ) {
79 has64BitPointers
= false;
81 startReadOnlySharedRegion
= 0x30000000LL
;
82 endReadOnlySharedRegion
= 0x3E000000LL
;
83 startReadWriteSharedRegion
= 0x3E000000LL
;
84 endReadWriteSharedRegion
= 0x40000000LL
;
86 else if ( strcmp((char*)buffer
, "dyld_v1 armv6") == 0 ) {
87 has64BitPointers
= false;
89 startReadOnlySharedRegion
= 0x30000000LL
;
90 endReadOnlySharedRegion
= 0x3E000000LL
;
91 startReadWriteSharedRegion
= 0x3E000000LL
;
92 endReadWriteSharedRegion
= 0x40000000LL
;
94 else if ( strcmp((char*)buffer
, "dyld_v1 armv7") == 0 ) {
95 has64BitPointers
= false;
97 startReadOnlySharedRegion
= 0x30000000LL
;
98 endReadOnlySharedRegion
= 0x3E000000LL
;
99 startReadWriteSharedRegion
= 0x3E000000LL
;
100 endReadWriteSharedRegion
= 0x40000000LL
;
103 (*logProc
)("file %s is not a known dyld shared cache file\n", path
);
108 bool swap
= !isBigEndian
;
110 bool swap
= isBigEndian
;
113 const dyld_cache_header
* header
= (dyld_cache_header
*)buffer
;
114 uint32_t mappingOffset
= swap
? OSSwapInt32(header
->mappingOffset
) : header
->mappingOffset
;
115 if ( mappingOffset
< 0x48 ) {
116 (*logProc
)("dyld shared cache file %s is old format\n", path
);
121 uint32_t mappingCount
= swap
? OSSwapInt32(header
->mappingCount
) : header
->mappingCount
;
122 if ( mappingCount
!= 3 ) {
123 (*logProc
)("dyld shared cache file %s has wrong mapping count\n", path
);
128 uint64_t slidePointersOffset
= swap
? OSSwapInt64(header
->slidePointersOffset
) : header
->slidePointersOffset
;
129 uint64_t slidePointersSize
= swap
? OSSwapInt64(header
->slidePointersSize
) : header
->slidePointersSize
;
130 if ( (slidePointersOffset
== 0) || (slidePointersSize
== 0) ) {
131 (*logProc
)("dyld shared cache file %s is missing slide information\n", path
);
137 void* slideInfo
= malloc(slidePointersSize
);
138 if ( slideInfo
== NULL
) {
139 (*logProc
)("malloc(%llu) failed\n", slidePointersSize
);
143 int64_t amountRead
= pread(fd
, slideInfo
, slidePointersSize
, slidePointersOffset
);
144 if ( amountRead
!= (int64_t)slidePointersSize
) {
145 (*logProc
)("slide info pread(fd, buf, %llu, %llu) failed\n", slidePointersSize
, slidePointersOffset
);
151 const dyld_cache_mapping_info
* mappings
= (dyld_cache_mapping_info
*)&buffer
[mappingOffset
];
152 uint64_t dataFileOffset
= swap
? OSSwapInt64(mappings
[1].fileOffset
) : mappings
[1].fileOffset
;
153 uint64_t dataSize
= swap
? OSSwapInt64(mappings
[1].size
) : mappings
[1].size
;
154 uint8_t* data
= (uint8_t*)malloc(dataSize
);
155 amountRead
= pread(fd
, data
, dataSize
, dataFileOffset
);
156 if ( amountRead
!= (int64_t)dataSize
) {
157 (*logProc
)("data pread(fd, buf, %llu, %llu) failed\n", data
, dataSize
);
162 // close read-only file
165 // extract current slide
166 uint64_t headerDataUses
;
167 if ( has64BitPointers
) {
168 headerDataUses
= *((uint64_t*)data
);
170 headerDataUses
= OSSwapInt64(headerDataUses
);
173 uint32_t temp
= *((uint32_t*)data
);
175 temp
= OSSwapInt32(temp
);
176 headerDataUses
= temp
;
178 uint64_t textAddress
= swap
? OSSwapInt64(mappings
[0].address
) : mappings
[0].address
;
179 uint32_t currentSlide
= headerDataUses
- textAddress
;
180 (*logProc
)("currentSlide=0x%08X\n", currentSlide
);
182 // find read-only space
183 uint64_t linkeditAddress
= swap
? OSSwapInt64(mappings
[2].address
) : mappings
[2].address
;
184 uint64_t linkeditSize
= swap
? OSSwapInt64(mappings
[2].size
) : mappings
[2].size
;
185 uint64_t linkeditEnd
= linkeditAddress
+ linkeditSize
;
186 uint64_t roSpace
= endReadOnlySharedRegion
- linkeditEnd
;
187 (*logProc
)("ro space=0x%08llX\n", roSpace
);
189 // find read-write space
190 uint64_t dataAddress
= swap
? OSSwapInt64(mappings
[1].address
) : mappings
[1].address
;
191 uint64_t dataEnd
= dataAddress
+ dataSize
;
192 uint64_t rwSpace
= endReadWriteSharedRegion
- dataEnd
;
193 (*logProc
)("rw space=0x%08llX\n", rwSpace
);
195 // choose new random slide
196 uint32_t slideSpace
= rwSpace
;
197 if ( roSpace
< rwSpace
)
198 slideSpace
= roSpace
;
199 uint32_t newSlide
= (arc4random() % slideSpace
) & (-4096);
200 (*logProc
)("newSlide=0x%08X\n", newSlide
);
201 int32_t slideAdjustment
= newSlide
- currentSlide
;
203 // update DATA with slide info
204 uint64_t offsetInCacheFile
= 0;
205 const uint8_t* infoStart
= (uint8_t*)slideInfo
;
206 const uint8_t* infoEnd
= infoStart
+ slidePointersSize
;
207 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
); ) {
213 delta
|= ((byte
& 0x7F) << shift
);
216 offsetInCacheFile
+= delta
;
217 // verify in DATA range
218 if ( (offsetInCacheFile
< dataFileOffset
) || (offsetInCacheFile
> (dataFileOffset
+dataSize
)) ) {
219 (*logProc
)("pointer offset 0x%llX outside DATA range\n", offsetInCacheFile
);
222 uint32_t offsetInData
= offsetInCacheFile
- dataFileOffset
;
223 if ( has64BitPointers
) {
224 uint64_t value64
= *((uint64_t*)(&data
[offsetInData
]));
226 value64
= OSSwapInt64(value64
);
227 value64
+= slideAdjustment
;
229 value64
= OSSwapInt64(value64
);
230 *((uint64_t*)(&data
[offsetInData
])) = value64
;
233 uint64_t value32
= *((uint32_t*)(&data
[offsetInData
]));
235 value32
= OSSwapInt32(value32
);
236 value32
+= slideAdjustment
;
238 value32
= OSSwapInt32(value32
);
239 *((uint32_t*)(&data
[offsetInData
])) = value32
;
241 //(*logProc)("update pointer at offset 0x%08X", offsetInData);
249 // re-open cache file and overwrite DATA range
250 fd
= open(path
, O_RDWR
, 0);
252 (*logProc
)("open(%s) failed, errno=%d\n", path
, errno
);
255 (void)fcntl(fd
, F_NOCACHE
, 1); // tell kernel to not cache file content
256 uint64_t amountWrote
= pwrite(fd
, data
, dataSize
, dataFileOffset
);
257 if ( amountWrote
!= dataSize
) {
258 (*logProc
)("data pwrite(fd, buf, %llu, %llu) failed\n", data
, dataSize
);
264 // re-open and re-read to verify write
265 fd
= open(path
, O_RDONLY
, 0);
267 (*logProc
)("verify open(%s) failed, errno=%d\n", path
, errno
);
270 (void)fcntl(fd
, F_NOCACHE
, 1); // tell kernel to not cache file content
271 uint8_t* dataVerify
= (uint8_t*)malloc(dataSize
);
272 amountRead
= pread(fd
, dataVerify
, dataSize
, dataFileOffset
);
273 if ( amountRead
!= (int64_t)dataSize
) {
274 (*logProc
)("verify data pread(fd, buf, %llu, %llu) failed\n", data
, dataSize
);
279 if ( memcmp(data
, dataVerify
, dataSize
) != 0 ) {
280 (*logProc
)("data update verification failed\n");
293 static void logger(const char* format
, ...)
296 va_start(list
, format
);
297 fprintf(stderr
, "error: ");
298 vfprintf(stderr
, format
, list
);
302 int main(int argc
, const char* argv
[])
304 return update_dyld_shared_cache_load_address(argv
[1], logger
);