OLD | NEW |
1 /******************************************************************************* | 1 /******************************************************************************* |
2 mach_override.c | 2 mach_override.c |
3 Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzs
ch.com> | 3 Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzs
ch.com> |
4 Some rights reserved: <http://opensource.org/licenses/mit-licens
e.php> | 4 Some rights reserved: <http://opensource.org/licenses/mit-licens
e.php> |
5 | 5 |
6 ************************************************************************
***/ | 6 ************************************************************************
***/ |
7 | 7 |
8 #include "mach_override.h" | 8 #include "mach_override.h" |
9 | 9 |
10 #include <mach-o/dyld.h> | 10 #include <mach-o/dyld.h> |
11 #include <mach/mach_host.h> | 11 #include <mach/mach_host.h> |
12 #include <mach/mach_init.h> | 12 #include <mach/mach_init.h> |
13 #include <mach/vm_map.h> | 13 #include <mach/vm_map.h> |
14 #include <sys/mman.h> | 14 #include <sys/mman.h> |
15 | 15 |
16 #include <CoreServices/CoreServices.h> | 16 #include <CoreServices/CoreServices.h> |
17 | 17 |
18 /************************** | 18 /************************** |
19 * | 19 * |
20 * Constants | 20 * Constants |
21 * | 21 * |
22 **************************/ | 22 **************************/ |
23 #pragma mark - | 23 #pragma mark - |
24 #pragma mark (Constants) | 24 #pragma mark (Constants) |
25 | 25 |
26 #define kPageSize 4096 | |
27 #if defined(__ppc__) || defined(__POWERPC__) | 26 #if defined(__ppc__) || defined(__POWERPC__) |
28 | 27 |
29 long kIslandTemplate[] = { | 28 long kIslandTemplate[] = { |
30 0x9001FFFC, // stw r0,-4(SP) | 29 0x9001FFFC, // stw r0,-4(SP) |
31 0x3C00DEAD, // lis r0,0xDEAD | 30 0x3C00DEAD, // lis r0,0xDEAD |
32 0x6000BEEF, // ori r0,r0,0xBEEF | 31 0x6000BEEF, // ori r0,r0,0xBEEF |
33 0x7C0903A6, // mtctr r0 | 32 0x7C0903A6, // mtctr r0 |
34 0x8001FFFC, // lwz r0,-4(SP) | 33 0x8001FFFC, // lwz r0,-4(SP) |
35 0x60000000, // nop ; optionally replaced | 34 0x60000000, // nop ; optionally replaced |
36 0x4E800420 // bctr | 35 0x4E800420 // bctr |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, | 69 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
71 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, | 70 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
72 // Now the real jump instruction | 71 // Now the real jump instruction |
73 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, | 72 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, |
74 0x00, 0x00, 0x00, 0x00, | 73 0x00, 0x00, 0x00, 0x00, |
75 0x00, 0x00, 0x00, 0x00 | 74 0x00, 0x00, 0x00, 0x00 |
76 }; | 75 }; |
77 | 76 |
78 #endif | 77 #endif |
79 | 78 |
| 79 #define kAllocateHigh 1 |
| 80 #define kAllocateNormal 0 |
| 81 |
80 /************************** | 82 /************************** |
81 * | 83 * |
82 * Data Types | 84 * Data Types |
83 * | 85 * |
84 **************************/ | 86 **************************/ |
85 #pragma mark - | 87 #pragma mark - |
86 #pragma mark (Data Types) | 88 #pragma mark (Data Types) |
87 | 89 |
88 typedef struct { | 90 typedef struct { |
89 char instructions[sizeof(kIslandTemplate)]; | 91 char instructions[sizeof(kIslandTemplate)]; |
| 92 int allocatedHigh; |
90 } BranchIsland; | 93 } BranchIsland; |
91 | 94 |
92 /************************** | 95 /************************** |
93 * | 96 * |
94 * Funky Protos | 97 * Funky Protos |
95 * | 98 * |
96 **************************/ | 99 **************************/ |
97 #pragma mark - | 100 #pragma mark - |
98 #pragma mark (Funky Protos) | 101 #pragma mark (Funky Protos) |
99 | 102 |
100 mach_error_t | 103 mach_error_t |
101 allocateBranchIsland( | 104 allocateBranchIsland( |
102 BranchIsland **island, | 105 BranchIsland **island, |
| 106 int allocateHigh, |
103 void *originalFunctionAddress); | 107 void *originalFunctionAddress); |
104 | 108 |
105 mach_error_t | 109 mach_error_t |
106 freeBranchIsland( | 110 freeBranchIsland( |
107 BranchIsland *island ); | 111 BranchIsland *island ); |
108 | 112 |
109 #if defined(__ppc__) || defined(__POWERPC__) | 113 #if defined(__ppc__) || defined(__POWERPC__) |
110 mach_error_t | 114 mach_error_t |
111 setBranchIslandTarget( | 115 setBranchIslandTarget( |
112 BranchIsland *island, | 116 BranchIsland *island, |
(...skipping 10 matching lines...) Expand all Loading... |
123 void | 127 void |
124 atomic_mov64( | 128 atomic_mov64( |
125 uint64_t *targetAddress, | 129 uint64_t *targetAddress, |
126 uint64_t value ); | 130 uint64_t value ); |
127 | 131 |
128 static Boolean | 132 static Boolean |
129 eatKnownInstructions( | 133 eatKnownInstructions( |
130 unsigned char *code, | 134 unsigned char *code, |
131 uint64_t *newInstruction, | 135 uint64_t *newInstruction, |
132 int *howManyEaten, | 136 int *howManyEaten, |
133 » char» » » *originalInstructions, | 137 » char» » » *originalInstructions ); |
134 » int» » » » *originalInstructionCount, | |
135 » uint8_t»» » *originalInstructionSizes ); | |
136 | |
137 » static void | |
138 fixupInstructions( | |
139 void» » *originalFunction, | |
140 void» » *escapeIsland, | |
141 void» » *instructionsToFix, | |
142 » int» » » instructionCount, | |
143 » uint8_t»» *instructionSizes ); | |
144 #endif | 138 #endif |
145 | 139 |
146 /******************************************************************************* | 140 /******************************************************************************* |
147 * | 141 * |
148 * Interface | 142 * Interface |
149 * | 143 * |
150 *******************************************************************************/ | 144 *******************************************************************************/ |
151 #pragma mark - | 145 #pragma mark - |
152 #pragma mark (Interface) | 146 #pragma mark (Interface) |
153 | 147 |
154 #if defined(__i386__) || defined(__x86_64__) | 148 #if defined(__i386__) || defined(__x86_64__) |
155 mach_error_t makeIslandExecutable(void *address) { | 149 mach_error_t makeIslandExecutable(void *address) { |
156 mach_error_t err = err_none; | 150 mach_error_t err = err_none; |
157 uintptr_t page = (uintptr_t)address & ~(uintptr_t)(kPageSize-1); | 151 vm_size_t pageSize; |
| 152 host_page_size( mach_host_self(), &pageSize ); |
| 153 uintptr_t page = (uintptr_t)address & ~(uintptr_t)(pageSize-1); |
158 int e = err_none; | 154 int e = err_none; |
159 e |= mprotect((void *)page, kPageSize, PROT_EXEC | PROT_READ | PROT_WRITE); | 155 e |= mprotect((void *)page, pageSize, PROT_EXEC | PROT_READ | PROT_WRITE); |
160 e |= msync((void *)page, kPageSize, MS_INVALIDATE ); | 156 e |= msync((void *)page, pageSize, MS_INVALIDATE ); |
161 if (e) { | 157 if (e) { |
162 err = err_cannot_override; | 158 err = err_cannot_override; |
163 } | 159 } |
164 return err; | 160 return err; |
165 } | 161 } |
166 #endif | 162 #endif |
167 | 163 |
168 mach_error_t | 164 mach_error_t |
169 mach_override_ptr( | 165 mach_override_ptr( |
170 void *originalFunctionAddress, | 166 void *originalFunctionAddress, |
171 const void *overrideFunctionAddress, | 167 const void *overrideFunctionAddress, |
172 void **originalFunctionReentryIsland ) | 168 void **originalFunctionReentryIsland ) |
173 { | 169 { |
174 assert( originalFunctionAddress ); | 170 assert( originalFunctionAddress ); |
175 assert( overrideFunctionAddress ); | 171 assert( overrideFunctionAddress ); |
176 | 172 |
177 // this addresses overriding such functions as AudioOutputUnitStart() | 173 // this addresses overriding such functions as AudioOutputUnitStart() |
178 // test with modified DefaultOutputUnit project | 174 // test with modified DefaultOutputUnit project |
| 175 #if defined(__x86_64__) || defined(__i386__) |
| 176 for(;;){ |
| 177 if(*(unsigned char*)originalFunctionAddress==0xE9) // jmp .+0x?????
??? |
| 178 originalFunctionAddress=(void*)((char*)originalFunctionAddress+5+*(i
nt32_t *)((char*)originalFunctionAddress+1)); |
179 #if defined(__x86_64__) | 179 #if defined(__x86_64__) |
180 for(;;){ | 180 else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword nea
r [rip+0x????????] |
181 if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [ri
p+0x????????] | |
182 originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*
(int32_t *)((uint16_t*)originalFunctionAddress+1)); | 181 originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*
(int32_t *)((uint16_t*)originalFunctionAddress+1)); |
183 else break; | |
184 } | |
185 #elif defined(__i386__) | 182 #elif defined(__i386__) |
186 for(;;){ | 183 else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x??????
?? |
187 if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x???????? | |
188 originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddre
ss+1); | 184 originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddre
ss+1); |
| 185 #endif |
189 else break; | 186 else break; |
190 } | 187 } |
191 #endif | 188 #endif |
192 | 189 |
193 long *originalFunctionPtr = (long*) originalFunctionAddress; | 190 long *originalFunctionPtr = (long*) originalFunctionAddress; |
194 mach_error_t err = err_none; | 191 mach_error_t err = err_none; |
195 | 192 |
196 #if defined(__ppc__) || defined(__POWERPC__) | 193 #if defined(__ppc__) || defined(__POWERPC__) |
197 // Ensure first instruction isn't 'mfctr'. | 194 // Ensure first instruction isn't 'mfctr'. |
198 #define kMFCTRMask 0xfc1fffff | 195 #define kMFCTRMask 0xfc1fffff |
199 #define kMFCTRInstruction 0x7c0903a6 | 196 #define kMFCTRInstruction 0x7c0903a6 |
200 | 197 |
201 long originalInstruction = *originalFunctionPtr; | 198 long originalInstruction = *originalFunctionPtr; |
202 if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) ) | 199 if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) ) |
203 err = err_cannot_override; | 200 err = err_cannot_override; |
204 #elif defined(__i386__) || defined(__x86_64__) | 201 #elif defined(__i386__) || defined(__x86_64__) |
205 int eatenCount = 0; | 202 int eatenCount = 0; |
206 int originalInstructionCount = 0; | |
207 char originalInstructions[kOriginalInstructionsSize]; | 203 char originalInstructions[kOriginalInstructionsSize]; |
208 uint8_t originalInstructionSizes[kOriginalInstructionsSize]; | |
209 uint64_t jumpRelativeInstruction = 0; // JMP | 204 uint64_t jumpRelativeInstruction = 0; // JMP |
210 | 205 |
211 Boolean overridePossible = eatKnownInstructions ((unsigned char *)origin
alFunctionPtr, | 206 Boolean overridePossible = eatKnownInstructions ((unsigned char *)origin
alFunctionPtr, |
212 » » » » » » » » » »
&jumpRelativeInstruction, &eatenCount, | 207 » » » » » » » » » »
&jumpRelativeInstruction, &eatenCount, originalInstructions); |
213 » » » » » » » » » »
originalInstructions, &originalInstructionCount, | |
214 » » » » » » » » » »
originalInstructionSizes ); | |
215 if (eatenCount > kOriginalInstructionsSize) { | 208 if (eatenCount > kOriginalInstructionsSize) { |
216 //printf ("Too many instructions eaten\n"); | 209 //printf ("Too many instructions eaten\n"); |
217 overridePossible = false; | 210 overridePossible = false; |
218 } | 211 } |
219 if (!overridePossible) err = err_cannot_override; | 212 if (!overridePossible) err = err_cannot_override; |
220 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); | 213 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
221 #endif | 214 #endif |
222 | 215 |
223 // Make the original function implementation writable. | 216 // Make the original function implementation writable. |
224 if( !err ) { | 217 if( !err ) { |
225 err = vm_protect( mach_task_self(), | 218 err = vm_protect( mach_task_self(), |
226 (vm_address_t) originalFunctionPtr, 8, false, | 219 (vm_address_t) originalFunctionPtr, 8, false, |
227 (VM_PROT_ALL | VM_PROT_COPY) ); | 220 (VM_PROT_ALL | VM_PROT_COPY) ); |
228 if( err ) | 221 if( err ) |
229 err = vm_protect( mach_task_self(), | 222 err = vm_protect( mach_task_self(), |
230 (vm_address_t) originalFunctionPtr, 8, f
alse, | 223 (vm_address_t) originalFunctionPtr, 8, f
alse, |
231 (VM_PROT_DEFAULT | VM_PROT_COPY) ); | 224 (VM_PROT_DEFAULT | VM_PROT_COPY) ); |
232 } | 225 } |
233 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); | 226 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
234 | 227 |
235 // Allocate and target the escape island to the overriding function
. | 228 // Allocate and target the escape island to the overriding function
. |
236 BranchIsland *escapeIsland = NULL; | 229 BranchIsland *escapeIsland = NULL; |
237 if( !err ) | 230 if( !err ) |
238 » » err = allocateBranchIsland( &escapeIsland, originalFunctionAddre
ss ); | 231 » » err = allocateBranchIsland( &escapeIsland, kAllocateHigh, origin
alFunctionAddress ); |
239 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LI
NE__); | 232 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LI
NE__); |
240 | 233 |
241 | 234 |
242 #if defined(__ppc__) || defined(__POWERPC__) | 235 #if defined(__ppc__) || defined(__POWERPC__) |
243 if( !err ) | 236 if( !err ) |
244 err = setBranchIslandTarget( escapeIsland, overrideFunctionAddre
ss, 0 ); | 237 err = setBranchIslandTarget( escapeIsland, overrideFunctionAddre
ss, 0 ); |
245 | 238 |
246 // Build the branch absolute instruction to the escape island. | 239 // Build the branch absolute instruction to the escape island. |
247 long branchAbsoluteInstruction = 0; // Set to 0 just to silence warni
ng. | 240 long branchAbsoluteInstruction = 0; // Set to 0 just to silence warni
ng. |
248 if( !err ) { | 241 if( !err ) { |
(...skipping 15 matching lines...) Expand all Loading... |
264 if (!err) { | 257 if (!err) { |
265 uint32_t addressOffset = ((char*)escapeIsland - (char*)originalF
unctionPtr - 5); | 258 uint32_t addressOffset = ((char*)escapeIsland - (char*)originalF
unctionPtr - 5); |
266 addressOffset = OSSwapInt32(addressOffset); | 259 addressOffset = OSSwapInt32(addressOffset); |
267 | 260 |
268 jumpRelativeInstruction |= 0xE900000000000000LL; | 261 jumpRelativeInstruction |= 0xE900000000000000LL; |
269 jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff
) << 24; | 262 jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff
) << 24; |
270 jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
| 263 jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
|
271 } | 264 } |
272 #endif | 265 #endif |
273 | 266 |
274 » //» Optionally allocate & return the reentry island. This may contai
n relocated | 267 » //» Optionally allocate & return the reentry island. |
275 » // jmp instructions and so has all the same addressing reachability req
uirements | |
276 » // the escape island has to the original function, except the escape is
land is | |
277 » // technically our original function. | |
278 BranchIsland *reentryIsland = NULL; | 268 BranchIsland *reentryIsland = NULL; |
279 if( !err && originalFunctionReentryIsland ) { | 269 if( !err && originalFunctionReentryIsland ) { |
280 » » err = allocateBranchIsland( &reentryIsland, escapeIsland); | 270 » » err = allocateBranchIsland( &reentryIsland, kAllocateHigh, NULL)
; |
281 if( !err ) | 271 if( !err ) |
282 *originalFunctionReentryIsland = reentryIsland; | 272 *originalFunctionReentryIsland = reentryIsland; |
283 } | 273 } |
284 | 274 |
285 #if defined(__ppc__) || defined(__POWERPC__) | 275 #if defined(__ppc__) || defined(__POWERPC__) |
286 // Atomically: | 276 // Atomically: |
287 // o If the reentry island was allocated: | 277 // o If the reentry island was allocated: |
288 // o Insert the original instruction into the reentry islan
d. | 278 // o Insert the original instruction into the reentry islan
d. |
289 // o Target the reentry island at the 2nd instruction of th
e | 279 // o Target the reentry island at the 2nd instruction of th
e |
290 // original function. | 280 // original function. |
(...skipping 22 matching lines...) Expand all Loading... |
313 #elif defined(__i386__) || defined(__x86_64__) | 303 #elif defined(__i386__) || defined(__x86_64__) |
314 // Atomically: | 304 // Atomically: |
315 // o If the reentry island was allocated: | 305 // o If the reentry island was allocated: |
316 // o Insert the original instructions into the reentry isla
nd. | 306 // o Insert the original instructions into the reentry isla
nd. |
317 // o Target the reentry island at the first non-replaced | 307 // o Target the reentry island at the first non-replaced |
318 // instruction of the original function. | 308 // instruction of the original function. |
319 // o Replace the original first instructions with the jump relative
. | 309 // o Replace the original first instructions with the jump relative
. |
320 // | 310 // |
321 // Note that on i386, we do not support someone else changing the code u
nder our feet | 311 // Note that on i386, we do not support someone else changing the code u
nder our feet |
322 if ( !err ) { | 312 if ( !err ) { |
323 fixupInstructions(originalFunctionPtr, reentryIsland, originalIn
structions, | |
324 originalInstructionCount, originalInstru
ctionSizes ); | |
325 | |
326 if( reentryIsland ) | 313 if( reentryIsland ) |
327 err = setBranchIslandTarget_i386( reentryIsland, | 314 err = setBranchIslandTarget_i386( reentryIsland, |
328
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); | 315
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); |
329 // try making islands executable before planting the jmp | 316 // try making islands executable before planting the jmp |
330 #if defined(__x86_64__) || defined(__i386__) | 317 #if defined(__x86_64__) || defined(__i386__) |
331 if( !err ) | 318 if( !err ) |
332 err = makeIslandExecutable(escapeIsland); | 319 err = makeIslandExecutable(escapeIsland); |
333 if( !err && reentryIsland ) | 320 if( !err && reentryIsland ) |
334 err = makeIslandExecutable(reentryIsland); | 321 err = makeIslandExecutable(reentryIsland); |
335 #endif | 322 #endif |
(...skipping 18 matching lines...) Expand all Loading... |
354 * Implementation | 341 * Implementation |
355 * | 342 * |
356 *******************************************************************************/ | 343 *******************************************************************************/ |
357 #pragma mark - | 344 #pragma mark - |
358 #pragma mark (Implementation) | 345 #pragma mark (Implementation) |
359 | 346 |
360 /***************************************************************************//** | 347 /***************************************************************************//** |
361 Implementation: Allocates memory for a branch island. | 348 Implementation: Allocates memory for a branch island. |
362 | 349 |
363 @param island <- The allocated island. | 350 @param island <- The allocated island. |
| 351 @param allocateHigh -> Whether to allocate the island at the en
d of the |
| 352 address space (f
or use with the branch absolute |
| 353 instruction). |
364 @result <- mach_error_t | 354 @result <- mach_error_t |
365 | 355 |
366 ************************************************************************
***/ | 356 ************************************************************************
***/ |
367 | 357 |
368 mach_error_t | 358 mach_error_t |
369 allocateBranchIsland( | 359 allocateBranchIsland( |
370 BranchIsland **island, | 360 BranchIsland **island, |
| 361 int allocateHigh, |
371 void *originalFunctionAddress) | 362 void *originalFunctionAddress) |
372 { | 363 { |
373 assert( island ); | 364 assert( island ); |
374 » assert( sizeof( BranchIsland ) <= kPageSize ); | 365 » |
| 366 » mach_error_t» err = err_none; |
| 367 » |
| 368 » if( allocateHigh ) { |
| 369 » » vm_size_t pageSize; |
| 370 » » err = host_page_size( mach_host_self(), &pageSize ); |
| 371 » » if( !err ) { |
| 372 » » » assert( sizeof( BranchIsland ) <= pageSize ); |
| 373 #if defined(__x86_64__) |
| 374 » » » vm_address_t first = (uint64_t)originalFunctionAddress &
~(uint64_t)(((uint64_t)1 << 31) - 1) | ((uint64_t)1 << 31); // start in the mid
dle of the page? |
| 375 » » » vm_address_t last = 0x0; |
| 376 #else |
| 377 » » » vm_address_t first = 0xffc00000; |
| 378 » » » vm_address_t last = 0xfffe0000; |
| 379 #endif |
375 | 380 |
376 » vm_map_t task_self = mach_task_self(); | 381 » » » vm_address_t page = first; |
377 » vm_address_t original_address = (vm_address_t) originalFunctionAddress; | 382 » » » int allocated = 0; |
378 » static vm_address_t last_allocated = 0; | 383 » » » vm_map_t task_self = mach_task_self(); |
379 » vm_address_t address = | 384 » » » |
380 » » last_allocated ? last_allocated : original_address; | 385 » » » while( !err && !allocated && page != last ) { |
381 | 386 |
382 » for (;;) { | 387 » » » » err = vm_allocate( task_self, &page, pageSize, 0
); |
383 » » vm_size_t vmsize = 0; | 388 » » » » if( err == err_none ) |
384 » » memory_object_name_t object = 0; | 389 » » » » » allocated = 1; |
385 » » kern_return_t kr = 0; | 390 » » » » else if( err == KERN_NO_SPACE ) { |
386 » » vm_region_flavor_t flavor = VM_REGION_BASIC_INFO; | 391 #if defined(__x86_64__) |
387 » » // Find the page the address is in. | 392 » » » » » page -= pageSize; |
388 #if __WORDSIZE == 32 | |
389 » » vm_region_basic_info_data_t info; | |
390 » » mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT; | |
391 » » kr = vm_region(task_self, &address, &vmsize, flavor, | |
392 » » » (vm_region_info_t)&info, &info_count, &object); | |
393 #else | 393 #else |
394 » » vm_region_basic_info_data_64_t info; | 394 » » » » » page += pageSize; |
395 » » mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_6
4; | |
396 » » kr = vm_region_64(task_self, &address, &vmsize, flavor, | |
397 » » » » (vm_region_info_t)&info, &info_count, &object)
; | |
398 #endif | 395 #endif |
399 » » if (kr != KERN_SUCCESS) | 396 » » » » » err = err_none; |
400 » » » return kr; | 397 » » » » } |
401 | 398 » » » } |
402 » » // Don't underflow. This could be made to work, but this is a | 399 » » » if( allocated ) |
403 » » // convenient place to give up. | 400 » » » » *island = (BranchIsland*) page; |
404 » » assert((address & (kPageSize - 1)) == 0); | 401 » » » else if( !allocated && !err ) |
405 » » if (address == 0) | 402 » » » » err = KERN_NO_SPACE; |
406 » » » break; | |
407 | |
408 » » // Go back one page. | |
409 » » vm_address_t new_address = address - kPageSize; | |
410 #if __WORDSIZE == 64 | |
411 » » if(original_address - new_address - 5 > INT32_MAX) | |
412 » » » break; | |
413 #endif | |
414 » » address = new_address; | |
415 | |
416 » » // Try to allocate this page. | |
417 » » kr = vm_allocate(task_self, &address, kPageSize, 0); | |
418 » » if (kr == KERN_SUCCESS) { | |
419 » » » *island = (BranchIsland*) address; | |
420 » » » last_allocated = address; | |
421 » » » return err_none; | |
422 } | 403 } |
423 » » if (kr != KERN_NO_SPACE) | 404 » } else { |
424 » » » return kr; | 405 » » void *block = malloc( sizeof( BranchIsland ) ); |
| 406 » » if( block ) |
| 407 » » » *island = block; |
| 408 » » else |
| 409 » » » err = KERN_NO_SPACE; |
425 } | 410 } |
426 | 411 » if( !err ) |
427 » return KERN_NO_SPACE; | 412 » » (**island).allocatedHigh = allocateHigh; |
| 413 » |
| 414 » return err; |
428 } | 415 } |
429 | 416 |
430 /***************************************************************************//** | 417 /***************************************************************************//** |
431 Implementation: Deallocates memory for a branch island. | 418 Implementation: Deallocates memory for a branch island. |
432 | 419 |
433 @param island -> The island to deallocate. | 420 @param island -> The island to deallocate. |
434 @result <- mach_error_t | 421 @result <- mach_error_t |
435 | 422 |
436 ************************************************************************
***/ | 423 ************************************************************************
***/ |
437 | 424 |
438 mach_error_t | 425 mach_error_t |
439 freeBranchIsland( | 426 freeBranchIsland( |
440 BranchIsland *island ) | 427 BranchIsland *island ) |
441 { | 428 { |
442 assert( island ); | 429 assert( island ); |
443 assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] ); | 430 assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] ); |
444 » assert( sizeof( BranchIsland ) <= kPageSize ); | 431 » assert( island->allocatedHigh ); |
445 » return vm_deallocate( mach_task_self(), (vm_address_t) island, | 432 » |
446 » » » kPageSize ); | 433 » mach_error_t» err = err_none; |
| 434 » |
| 435 » if( island->allocatedHigh ) { |
| 436 » » vm_size_t pageSize; |
| 437 » » err = host_page_size( mach_host_self(), &pageSize ); |
| 438 » » if( !err ) { |
| 439 » » » assert( sizeof( BranchIsland ) <= pageSize ); |
| 440 » » » err = vm_deallocate( |
| 441 » » » » » mach_task_self(), |
| 442 » » » » » (vm_address_t) island, pageSize ); |
| 443 » » } |
| 444 » } else { |
| 445 » » free( island ); |
| 446 » } |
| 447 » |
| 448 » return err; |
447 } | 449 } |
448 | 450 |
449 /***************************************************************************//** | 451 /***************************************************************************//** |
450 Implementation: Sets the branch island's target, with an optional | 452 Implementation: Sets the branch island's target, with an optional |
451 instruction. | 453 instruction. |
452 | 454 |
453 @param island -> The branch island to insert target into. | 455 @param island -> The branch island to insert target into. |
454 @param branchTo -> The address of the target. | 456 @param branchTo -> The address of the target. |
455 @param instruction -> Optional instruction to execute prior to
branch. Set | 457 @param instruction -> Optional instruction to execute prior to
branch. Set |
456 to zero for nop. | 458 to zero for nop. |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 #if defined(__i386__) || defined(__x86_64__) | 540 #if defined(__i386__) || defined(__x86_64__) |
539 // simplistic instruction matching | 541 // simplistic instruction matching |
540 typedef struct { | 542 typedef struct { |
541 unsigned int length; // max 15 | 543 unsigned int length; // max 15 |
542 unsigned char mask[15]; // sequence of bytes in memory order | 544 unsigned char mask[15]; // sequence of bytes in memory order |
543 unsigned char constraint[15]; // sequence of bytes in memory order | 545 unsigned char constraint[15]; // sequence of bytes in memory order |
544 } AsmInstructionMatch; | 546 } AsmInstructionMatch; |
545 | 547 |
546 #if defined(__i386__) | 548 #if defined(__i386__) |
547 static AsmInstructionMatch possibleInstructions[] = { | 549 static AsmInstructionMatch possibleInstructions[] = { |
548 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },
// jmp 0x???????? | |
549 { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} },
// push %ebp; mov %esp,%ebp; leave; ret | 550 { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} },
// push %ebp; mov %esp,%ebp; leave; ret |
550 { 0x1, {0xFF}, {0x90} },
// nop | 551 { 0x1, {0xFF}, {0x90} },
// nop |
551 { 0x1, {0xFF}, {0x55} },
// push %esp | 552 { 0x1, {0xFF}, {0x55} },
// push %esp |
552 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },
// mov %esp,%ebp | 553 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },
// mov %esp,%ebp |
553 { 0x1, {0xFF}, {0x53} },
// push %ebx | 554 { 0x1, {0xFF}, {0x53} },
// push %ebx |
554 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },
// sub 0x??, %esp | 555 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },
// sub 0x??, %esp |
555 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x
00, 0x00} }, // sub 0x??, %esp with 32bit immediate | 556 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x
00, 0x00} }, // sub 0x??, %esp with 32bit immediate |
556 { 0x1, {0xFF}, {0x57} },
// push %edi | 557 { 0x1, {0xFF}, {0x57} },
// push %edi |
557 { 0x1, {0xFF}, {0x56} },
// push %esi | 558 { 0x1, {0xFF}, {0x56} },
// push %esi |
558 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },
// xor %eax, %eax | 559 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },
// xor %eax, %eax |
559 { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %re
g | 560 { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %re
g |
560 { 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx)
, %reg | 561 { 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx)
, %reg |
561 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $im
m(%esp), %ecx | 562 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $im
m(%esp), %ecx |
562 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },
// mov $imm, %eax | |
563 { 0x0 } | 563 { 0x0 } |
564 }; | 564 }; |
565 #elif defined(__x86_64__) | 565 #elif defined(__x86_64__) |
566 static AsmInstructionMatch possibleInstructions[] = { | 566 static AsmInstructionMatch possibleInstructions[] = { |
567 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },
// jmp 0x???????? | |
568 { 0x1, {0xFF}, {0x90} },
// nop | 567 { 0x1, {0xFF}, {0x90} },
// nop |
569 { 0x1, {0xF8}, {0x50} },
// push %rX | 568 { 0x1, {0xF8}, {0x50} },
// push %rX |
570 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },
// mov %rsp,%rbp | 569 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },
// mov %rsp,%rbp |
571 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },
// sub 0x??, %rsp | 570 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },
// sub 0x??, %rsp |
572 { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} },
// move onto rbp | 571 { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} },
// move onto rbp |
573 { 0x4, {0xFF, 0xFF, 0xFF, 0xFF}, {0x40, 0x0f, 0xbe, 0xce} },
// movsbl %sil, %ecx | |
574 { 0x2, {0xFF, 0x00}, {0x41, 0x00} },
// push %rXX | 572 { 0x2, {0xFF, 0x00}, {0x41, 0x00} },
// push %rXX |
575 { 0x2, {0xFF, 0x00}, {0x85, 0x00} },
// test %rX,%rX | 573 { 0x2, {0xFF, 0x00}, {0x85, 0x00} },
// test %rX,%rX |
576 { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },
// mov $imm, %reg | 574 { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },
// mov $imm, %reg |
577 { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi) | 575 { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi) |
578 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },
// xor %eax, %eax | |
579 { 0x2, {0xFF, 0xFF}, {0x89, 0xF8} }, // mov %edi, %ea
x | |
580 { 0x0 } | 576 { 0x0 } |
581 }; | 577 }; |
582 #endif | 578 #endif |
583 | 579 |
584 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch*
instruction) | 580 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch*
instruction) |
585 { | 581 { |
586 Boolean match = true; | 582 Boolean match = true; |
587 | 583 |
588 size_t i; | 584 size_t i; |
589 for (i=0; i<instruction->length; i++) { | 585 for (i=0; i<instruction->length; i++) { |
590 unsigned char mask = instruction->mask[i]; | 586 unsigned char mask = instruction->mask[i]; |
591 unsigned char constraint = instruction->constraint[i]; | 587 unsigned char constraint = instruction->constraint[i]; |
592 unsigned char codeValue = code[i]; | 588 unsigned char codeValue = code[i]; |
593 | 589 |
594 match = ((codeValue & mask) == constraint); | 590 match = ((codeValue & mask) == constraint); |
595 if (!match) break; | 591 if (!match) break; |
596 } | 592 } |
597 | 593 |
598 return match; | 594 return match; |
599 } | 595 } |
600 | 596 |
601 #if defined(__i386__) || defined(__x86_64__) | 597 #if defined(__i386__) || defined(__x86_64__) |
602 static Boolean | 598 static Boolean |
603 eatKnownInstructions( | 599 eatKnownInstructions( |
604 » unsigned char» *code, | 600 » unsigned char *code, |
605 » uint64_t» » *newInstruction, | 601 » uint64_t* newInstruction, |
606 » int» » » » *howManyEaten, | 602 » int* howManyEaten, |
607 » char» » » *originalInstructions, | 603 » char* originalInstructions ) |
608 » int» » » » *originalInstructionCount, | |
609 » uint8_t»» » *originalInstructionSizes ) | |
610 { | 604 { |
611 Boolean allInstructionsKnown = true; | 605 Boolean allInstructionsKnown = true; |
612 int totalEaten = 0; | 606 int totalEaten = 0; |
613 unsigned char* ptr = code; | 607 unsigned char* ptr = code; |
614 int remainsToEat = 5; // a JMP instruction takes 5 bytes | 608 int remainsToEat = 5; // a JMP instruction takes 5 bytes |
615 int instructionIndex = 0; | |
616 | 609 |
617 if (howManyEaten) *howManyEaten = 0; | 610 if (howManyEaten) *howManyEaten = 0; |
618 if (originalInstructionCount) *originalInstructionCount = 0; | |
619 while (remainsToEat > 0) { | 611 while (remainsToEat > 0) { |
620 Boolean curInstructionKnown = false; | 612 Boolean curInstructionKnown = false; |
621 | 613 |
622 // See if instruction matches one we know | 614 // See if instruction matches one we know |
623 AsmInstructionMatch* curInstr = possibleInstructions; | 615 AsmInstructionMatch* curInstr = possibleInstructions; |
624 do { | 616 do { |
625 if ((curInstructionKnown = codeMatchesInstruction(ptr, c
urInstr))) break; | 617 if ((curInstructionKnown = codeMatchesInstruction(ptr, c
urInstr))) break; |
626 curInstr++; | 618 curInstr++; |
627 } while (curInstr->length > 0); | 619 } while (curInstr->length > 0); |
628 | 620 |
629 // if all instruction matches failed, we don't know current inst
ruction then, stop here | 621 // if all instruction matches failed, we don't know current inst
ruction then, stop here |
630 if (!curInstructionKnown) { | 622 if (!curInstructionKnown) { |
631 allInstructionsKnown = false; | 623 allInstructionsKnown = false; |
632 fprintf(stderr, "mach_override: some instructions unknow
n! Need to update mach_override.c\n"); | 624 fprintf(stderr, "mach_override: some instructions unknow
n! Need to update mach_override.c\n"); |
633 break; | 625 break; |
634 } | 626 } |
635 | 627 |
636 // At this point, we've matched curInstr | 628 // At this point, we've matched curInstr |
637 int eaten = curInstr->length; | 629 int eaten = curInstr->length; |
638 ptr += eaten; | 630 ptr += eaten; |
639 remainsToEat -= eaten; | 631 remainsToEat -= eaten; |
640 totalEaten += eaten; | 632 totalEaten += eaten; |
641 | |
642 if (originalInstructionSizes) originalInstructionSizes[instructi
onIndex] = eaten; | |
643 instructionIndex += 1; | |
644 if (originalInstructionCount) *originalInstructionCount = instru
ctionIndex; | |
645 } | 633 } |
646 | 634 |
647 | 635 |
648 if (howManyEaten) *howManyEaten = totalEaten; | 636 if (howManyEaten) *howManyEaten = totalEaten; |
649 | 637 |
650 if (originalInstructions) { | 638 if (originalInstructions) { |
651 Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOrig
inalInstructionsSize); | 639 Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOrig
inalInstructionsSize); |
652 | 640 |
653 if (enoughSpaceForOriginalInstructions) { | 641 if (enoughSpaceForOriginalInstructions) { |
654 memset(originalInstructions, 0x90 /* NOP */, kOriginalIn
structionsSize); // fill instructions with NOP | 642 memset(originalInstructions, 0x90 /* NOP */, kOriginalIn
structionsSize); // fill instructions with NOP |
(...skipping 10 matching lines...) Expand all Loading... |
665 currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode)
; // back to memory representation | 653 currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode)
; // back to memory representation |
666 currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL; | 654 currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL; |
667 | 655 |
668 // keep only last 3 instructions bytes, first 5 will be replaced
by JMP instr | 656 // keep only last 3 instructions bytes, first 5 will be replaced
by JMP instr |
669 *newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes | 657 *newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes |
670 *newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFF
FLL); // set last 3 bytes | 658 *newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFF
FLL); // set last 3 bytes |
671 } | 659 } |
672 | 660 |
673 return allInstructionsKnown; | 661 return allInstructionsKnown; |
674 } | 662 } |
675 | |
676 static void | |
677 fixupInstructions( | |
678 void *originalFunction, | |
679 void *escapeIsland, | |
680 void *instructionsToFix, | |
681 int instructionCount, | |
682 uint8_t *instructionSizes ) | |
683 { | |
684 int index; | |
685 for (index = 0;index < instructionCount;index += 1) | |
686 { | |
687 if (*(uint8_t*)instructionsToFix == 0xE9) // 32-bit jump relativ
e | |
688 { | |
689 uint32_t offset = (uintptr_t)originalFunction - (uintptr
_t)escapeIsland; | |
690 uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instruc
tionsToFix + 1); | |
691 *jumpOffsetPtr += offset; | |
692 } | |
693 | |
694 originalFunction = (void*)((uintptr_t)originalFunction + instruc
tionSizes[index]); | |
695 escapeIsland = (void*)((uintptr_t)escapeIsland + instructionSize
s[index]); | |
696 instructionsToFix = (void*)((uintptr_t)instructionsToFix + instr
uctionSizes[index]); | |
697 } | |
698 } | |
699 #endif | 663 #endif |
700 | 664 |
701 #if defined(__i386__) | 665 #if defined(__i386__) |
702 __asm( | 666 __asm( |
703 ".text;" | 667 ".text;" |
704 ".align 2, 0x90;" | 668 ".align 2, 0x90;" |
705 "_atomic_mov64:;" | 669 "_atomic_mov64:;" |
706 " pushl %ebp;" | 670 " pushl %ebp;" |
707 " movl %esp, %ebp;" | 671 " movl %esp, %ebp;" |
708 " pushl %esi;" | 672 " pushl %esi;" |
(...skipping 26 matching lines...) Expand all Loading... |
735 ); | 699 ); |
736 #elif defined(__x86_64__) | 700 #elif defined(__x86_64__) |
737 void atomic_mov64( | 701 void atomic_mov64( |
738 uint64_t *targetAddress, | 702 uint64_t *targetAddress, |
739 uint64_t value ) | 703 uint64_t value ) |
740 { | 704 { |
741 *targetAddress = value; | 705 *targetAddress = value; |
742 } | 706 } |
743 #endif | 707 #endif |
744 #endif | 708 #endif |
OLD | NEW |