Root/
Source at commit 1406 created 12 years 10 months ago. By meklort, Revert drivers.c so that kexts are only loaded when OSBundleRequired is set and that value is not safe mode. Added some comments about it too. | |
---|---|
1 | /*␊ |
2 | * Copyright 2010 Evan Lojewski. All rights reserved.␊ |
3 | *␊ |
4 | */␊ |
5 | #ifndef CONFIG_MACHO_DEBUG␊ |
6 | #define CONFIG_MACHO_DEBUG 0␊ |
7 | #endif␊ |
8 | ␊ |
9 | ␊ |
10 | #include <stdlib.h>␊ |
11 | #include "modules.h"␊ |
12 | ␊ |
13 | extern void start_built_in_modules();␊ |
14 | ␊ |
15 | #if CONFIG_MACHO_DEBUG␊ |
16 | #define DBG(x...)␉printf(x);␊ |
17 | #define DBGPAUSE()␉getchar()␊ |
18 | #else␊ |
19 | #define DBG(x...)␊ |
20 | #define DBGPAUSE()␊ |
21 | #endif␊ |
22 | ␊ |
23 | // NOTE: Global so that modules can link with this␊ |
24 | UInt64 textAddress = 0;␊ |
25 | UInt64 textSection = 0;␊ |
26 | ␊ |
27 | /********************************************************************************/␊ |
28 | /*␉Macho Parser␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉*/␊ |
29 | /********************************************************************************/␊ |
30 | ␊ |
31 | /*␊ |
32 | * Parse through a macho module. The module will be rebased and binded␊ |
33 | * as specified in the macho header. If the module is sucessfuly laoded␊ |
34 | * the module iinit address will be returned.␊ |
35 | * NOTE; all dependecies will be loaded before this module is started␊ |
36 | * NOTE: If the module is unable to load ot completeion, the modules␊ |
37 | * symbols will still be available.␊ |
38 | */␊ |
39 | void* parse_mach(void* binary, ␊ |
40 | int(*dylib_loader)(char*), ␊ |
41 | long long(*symbol_handler)(char*, long long, char),␊ |
42 | void (*section_handler)(char* section, char* segment, long long offset, long long address)␊ |
43 | )␊ |
44 | {␉␊ |
45 | ␉char is64 = false;␊ |
46 | ␉void (*module_start)(void) = NULL;␊ |
47 | ␉␊ |
48 | ␉// Module info␊ |
49 | ␉/*char* moduleName = NULL;␊ |
50 | ␉ UInt32 moduleVersion = 0;␊ |
51 | ␉ UInt32 moduleCompat = 0;␊ |
52 | ␉ */␊ |
53 | ␉// TODO convert all of the structs to a union␊ |
54 | ␉struct load_command *loadCommand = NULL;␊ |
55 | ␉struct dylib_command* dylibCommand = NULL;␊ |
56 | ␉struct dyld_info_command* dyldInfoCommand = NULL;␊ |
57 | ␉␊ |
58 | ␉struct symtab_command* symtabCommand = NULL;␊ |
59 | ␉struct segment_command *segCommand = NULL;␊ |
60 | ␉struct segment_command_64 *segCommand64 = NULL;␊ |
61 | ␉␊ |
62 | ␉//struct dysymtab_command* dysymtabCommand = NULL;␊ |
63 | ␉UInt32 binaryIndex = 0;␊ |
64 | ␉UInt16 cmd = 0;␊ |
65 | ␉␊ |
66 | ␉textSection = 0;␊ |
67 | ␉textAddress = 0;␉// reinitialize text location in case it doesn't exist;␊ |
68 | ␉␊ |
69 | ␉// Parse through the load commands␊ |
70 | ␉if(((struct mach_header*)binary)->magic == MH_MAGIC)␊ |
71 | ␉{␊ |
72 | ␉␉is64 = false;␊ |
73 | ␉␉binaryIndex += sizeof(struct mach_header);␊ |
74 | ␉}␊ |
75 | ␉else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)␊ |
76 | ␉{␊ |
77 | ␉␉// NOTE: modules cannot be 64bit...␊ |
78 | ␉␉is64 = true;␊ |
79 | ␉␉binaryIndex += sizeof(struct mach_header_64);␊ |
80 | ␉}␊ |
81 | ␉else␊ |
82 | ␉{␊ |
83 | ␉␉verbose("Invalid mach magic 0x%X\n", ((struct mach_header*)binary)->magic);␊ |
84 | ␉␉//getchar();␊ |
85 | ␉␉return NULL;␊ |
86 | ␉}␊ |
87 | ␉␊ |
88 | ␉␊ |
89 | ␉␊ |
90 | ␉/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)␊ |
91 | ␉ {␊ |
92 | ␉ printf("Module is not a dylib. Unable to load.\n");␊ |
93 | ␉ getchar();␊ |
94 | ␉ return NULL; // Module is in the incorrect format␊ |
95 | ␉ }*/␊ |
96 | ␉␊ |
97 | ␉while(cmd < ((struct mach_header*)binary)->ncmds)␊ |
98 | ␉{␊ |
99 | ␉␉cmd++;␊ |
100 | ␉␉␊ |
101 | ␉␉loadCommand = binary + binaryIndex;␊ |
102 | ␉␉UInt32 cmdSize = loadCommand->cmdsize;␊ |
103 | ␉␉␊ |
104 | ␉␉␊ |
105 | ␉␉switch ((loadCommand->cmd & 0x7FFFFFFF))␊ |
106 | ␉␉{␊ |
107 | ␉␉␉case LC_SYMTAB:␊ |
108 | ␉␉␉␉symtabCommand = binary + binaryIndex;␊ |
109 | ␉␉␉␉break;␊ |
110 | ␉␉␉␉␊ |
111 | ␉␉␉case LC_SEGMENT: // 32bit macho␊ |
112 | {␊ |
113 | segCommand = binary + binaryIndex;␊ |
114 | ␊ |
115 | UInt32 sectionIndex;␊ |
116 | ␊ |
117 | sectionIndex = sizeof(struct segment_command);␊ |
118 | ␊ |
119 | struct section *sect;␊ |
120 | ␊ |
121 | while(sectionIndex < segCommand->cmdsize)␊ |
122 | {␊ |
123 | sect = binary + binaryIndex + sectionIndex;␊ |
124 | ␊ |
125 | sectionIndex += sizeof(struct section);␊ |
126 | ␊ |
127 | if(section_handler) section_handler(sect->sectname, segCommand->segname, sect->offset, sect->addr);␊ |
128 | ␊ |
129 | ␊ |
130 | ␊ |
131 | if((strcmp("__TEXT", segCommand->segname) == 0) && (strcmp("__text", sect->sectname) == 0))␊ |
132 | {␊ |
133 | // __TEXT,__text found, save the offset and address for when looking for the calls.␊ |
134 | textSection = sect->offset;␊ |
135 | textAddress = sect->addr;␊ |
136 | }␉␉␉␉␉␊ |
137 | }␊ |
138 | }␊ |
139 | ␉␉␉␉break;␊ |
140 | ␉␉␉case LC_SEGMENT_64:␉// 64bit macho's␊ |
141 | {␊ |
142 | segCommand64 = binary + binaryIndex;␉␉␉␉␊ |
143 | UInt32 sectionIndex;␊ |
144 | ␊ |
145 | sectionIndex = sizeof(struct segment_command_64);␊ |
146 | ␊ |
147 | struct section_64 *sect;␊ |
148 | ␊ |
149 | while(sectionIndex < segCommand64->cmdsize)␊ |
150 | {␊ |
151 | sect = binary + binaryIndex + sectionIndex;␊ |
152 | ␊ |
153 | sectionIndex += sizeof(struct section_64);␊ |
154 | ␊ |
155 | if(section_handler) section_handler(sect->sectname, segCommand->segname, sect->offset, sect->addr);␊ |
156 | ␊ |
157 | ␊ |
158 | if((strcmp("__TEXT", segCommand->segname) == 0) && (strcmp("__text", sect->sectname) == 0))␊ |
159 | {␊ |
160 | // __TEXT,__text found, save the offset and address for when looking for the calls.␊ |
161 | textSection = sect->offset;␊ |
162 | textAddress = sect->addr;␊ |
163 | }␉␉␉␉␉␊ |
164 | }␉␊ |
165 | ␉␉␉␉}␉␉␉␊ |
166 | ␉␉␉␉break;␊ |
167 | ␉␉␉␉␊ |
168 | ␉␉␉␉␊ |
169 | ␉␉␉case LC_LOAD_DYLIB:␊ |
170 | ␉␉␉case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:␊ |
171 | ␉␉␉␉dylibCommand = binary + binaryIndex;␊ |
172 | ␉␉␉␉char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));␊ |
173 | ␉␉␉␉// Possible enhancments: verify version␊ |
174 | ␉␉␉␉// =␉dylibCommand->dylib.current_version;␊ |
175 | ␉␉␉␉// =␉dylibCommand->dylib.compatibility_version;␊ |
176 | ␉␉␉␉if(dylib_loader)␊ |
177 | ␉␉␉␉{␊ |
178 | ␉␉␉␉␉char* name = malloc(strlen(module) + strlen(".dylib") + 1);␊ |
179 | ␉␉␉␉␉sprintf(name, "%s.dylib", module);␊ |
180 | ␉␉␉␉␉␊ |
181 | ␉␉␉␉␉if (!dylib_loader(name))␊ |
182 | ␉␉␉␉␉{␊ |
183 | ␉␉␉␉␉␉// NOTE: any symbols exported by dep will be replace with the void function␊ |
184 | ␉␉␉␉␉␉free(name);␊ |
185 | ␉␉␉␉␉}␊ |
186 | ␉␉␉␉}␊ |
187 | ␉␉␉␉␊ |
188 | ␉␉␉␉break;␊ |
189 | ␉␉␉␉␊ |
190 | ␉␉␉case LC_ID_DYLIB:␊ |
191 | ␉␉␉␉dylibCommand = binary + binaryIndex;␊ |
192 | ␉␉␉␉/*moduleName =␉binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));␊ |
193 | ␉␉␉␉ moduleVersion =␉dylibCommand->dylib.current_version;␊ |
194 | ␉␉␉␉ moduleCompat =␉dylibCommand->dylib.compatibility_version;␊ |
195 | ␉␉␉␉ */␊ |
196 | ␉␉␉␉break;␊ |
197 | ␉␉␉␉␊ |
198 | ␉␉␉case LC_DYLD_INFO:␊ |
199 | ␉␉␉//case LC_DYLD_INFO_ONLY:␉// compressed info, 10.6+ macho files, already handeled␊ |
200 | ␉␉␉␉// Bind and rebase info is stored here␊ |
201 | ␉␉␉␉dyldInfoCommand = binary + binaryIndex;␊ |
202 | ␉␉␉␉break;␊ |
203 | ␉␉␉␉␊ |
204 | ␉␉␉case LC_DYSYMTAB:␊ |
205 | ␉␉␉case LC_UUID:␊ |
206 | ␉␉␉case LC_UNIXTHREAD:␊ |
207 | ␉␉␉␉break;␊ |
208 | ␉␉␉␉␊ |
209 | ␉␉␉default:␊ |
210 | ␉␉␉␉DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);␊ |
211 | ␉␉␉␉break;␊ |
212 | ␉␉␉␉␊ |
213 | ␉␉}␊ |
214 | ␉␉␊ |
215 | ␉␉binaryIndex += cmdSize;␊ |
216 | ␉}␊ |
217 | ␊ |
218 | ␉// bind_macho uses the symbols, if the textAdd does not exist (Symbols.dylib, no code), addresses are static and not relative␊ |
219 | ␉module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);␊ |
220 | ␉␊ |
221 | ␉if(dyldInfoCommand)␊ |
222 | ␉{␊ |
223 | ␉␉// Rebase the module before binding it.␊ |
224 | ␉␉if(dyldInfoCommand->rebase_off)␉␉rebase_macho(binary, (char*)dyldInfoCommand->rebase_off,␉dyldInfoCommand->rebase_size);␊ |
225 | ␉␉// Bind all symbols. ␊ |
226 | ␉␉if(dyldInfoCommand->bind_off)␉␉bind_macho(binary, (UInt8*)dyldInfoCommand->bind_off,␉␉dyldInfoCommand->bind_size);␊ |
227 | ␉␉if(dyldInfoCommand->weak_bind_off)␉bind_macho(binary, (UInt8*)dyldInfoCommand->weak_bind_off,␉dyldInfoCommand->weak_bind_size);␊ |
228 | ␉␉if(dyldInfoCommand->lazy_bind_off)␉bind_macho(binary, (UInt8*)dyldInfoCommand->lazy_bind_off,␉dyldInfoCommand->lazy_bind_size);␊ |
229 | ␉}␊ |
230 | ␉␊ |
231 | ␉return module_start;␊ |
232 | ␉␊ |
233 | }␊ |
234 | ␊ |
235 | /*␊ |
236 | * parse the symbol table␊ |
237 | * Lookup any undefined symbols␊ |
238 | */␊ |
239 | ␊ |
240 | void* handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)␊ |
241 | {␊ |
242 | ␉␊ |
243 | ␉void* module_start␉= (void*) -1;␉␊ |
244 | ␉UInt32 symbolIndex␉␉␉= 0;␊ |
245 | ␉char* symbolString␉␉␉= base + (char*)symtabCommand->stroff;␊ |
246 | ␊ |
247 | ␉if(!is64)␊ |
248 | ␉{␊ |
249 | ␉␉struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;␊ |
250 | ␉␉while(symbolIndex < symtabCommand->nsyms)␊ |
251 | ␉␉{␊ |
252 | ␉␉␉// If the symbol is exported by this module␊ |
253 | ␉␉␉if(symbolEntry->n_value &&␊ |
254 | ␉␉␉ symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)␊ |
255 | ␉␉␉{␊ |
256 | ␉␉␉␉␊ |
257 | ␉␉␉␉// Module start located. Start is an alias so don't register it␊ |
258 | ␉␉␉␉module_start = (void*)(textAddress ? base + symbolEntry->n_value : symbolEntry->n_value);␊ |
259 | ␉␉␉}␊ |
260 | ␉␉␉␊ |
261 | ␉␉␉symbolEntry++;␊ |
262 | ␉␉␉symbolIndex++;␉// TODO remove␊ |
263 | ␉␉}␊ |
264 | ␉}␊ |
265 | ␉else␊ |
266 | ␉{␊ |
267 | ␉␉/*␊ |
268 | ␉␉struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;␊ |
269 | ␉␉// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now, verify later)␉␊ |
270 | ␉␉while(symbolIndex < symtabCommand->nsyms)␊ |
271 | ␉␉{␊ |
272 | ␉␉␉␊ |
273 | ␉␉␉␊ |
274 | ␉␉␉// If the symbol is exported by this module␊ |
275 | ␉␉␉if(symbolEntry->n_value &&␊ |
276 | ␉␉␉ symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)␊ |
277 | ␉␉␉{␊ |
278 | ␉␉␉␉␊ |
279 | ␉␉␉␉// Module start located. Start is an alias so don't register it␊ |
280 | ␉␉␉␉module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;␊ |
281 | ␉␉␉}␊ |
282 | ␉␉␉␊ |
283 | ␉␉␉symbolEntry++;␊ |
284 | ␉␉␉symbolIndex++;␉// TODO remove␊ |
285 | ␉␉}␊ |
286 | ␉␉ */␊ |
287 | ␉}␊ |
288 | ␉return module_start;␊ |
289 | }␊ |
290 | ␊ |
291 | // Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp␊ |
292 | void rebase_macho(void* base, char* rebase_stream, UInt32 size)␊ |
293 | {␊ |
294 | ␉rebase_stream += (UInt32)base;␊ |
295 | ␉␊ |
296 | ␉UInt8 immediate = 0;␊ |
297 | ␉UInt8 opcode = 0;␊ |
298 | ␉UInt8 type = 0;␊ |
299 | ␉UInt32 segmentAddress = 0;␊ |
300 | ␉␊ |
301 | ␉␊ |
302 | ␉UInt32 tmp = 0;␊ |
303 | ␉UInt32 tmp2 = 0;␊ |
304 | ␉UInt8 bits = 0;␊ |
305 | ␉int index = 0;␊ |
306 | ␉unsigned int i = 0;␊ |
307 | ␉␊ |
308 | ␉while(i < size)␊ |
309 | ␉{␊ |
310 | ␉␉immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;␊ |
311 | ␉␉opcode = rebase_stream[i] & REBASE_OPCODE_MASK;␊ |
312 | ␉␉␊ |
313 | ␉␉␊ |
314 | ␉␉switch(opcode)␊ |
315 | ␉␉{␊ |
316 | ␉␉␉case REBASE_OPCODE_DONE:␊ |
317 | ␉␉␉␉// Rebase complete, reset vars␊ |
318 | ␉␉␉␉immediate = 0;␊ |
319 | ␉␉␉␉opcode = 0;␊ |
320 | ␉␉␉␉type = 0;␊ |
321 | ␉␉␉␉segmentAddress = 0;␊ |
322 | ␉␉␉default:␊ |
323 | ␉␉␉␉break;␊ |
324 | ␉␉␉␉␊ |
325 | ␉␉␉␉␊ |
326 | ␉␉␉case REBASE_OPCODE_SET_TYPE_IMM:␊ |
327 | ␉␉␉␉type = immediate;␊ |
328 | ␉␉␉␉break;␊ |
329 | ␉␉␉␉␊ |
330 | ␉␉␉␉␊ |
331 | ␉␉␉case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:␊ |
332 | ␉␉␉␉// Locate address to begin rebasing␊ |
333 | ␉␉␉␉segmentAddress = 0;␊ |
334 | ␉␉␉␉struct segment_command* segCommand = NULL; // NOTE: 32bit only␊ |
335 | ␉␉␉␉␊ |
336 | ␉␉␉␉unsigned int binIndex = 0;␊ |
337 | ␉␉␉␉index = 0;␊ |
338 | ␉␉␉␉do␊ |
339 | ␉␉␉␉{␊ |
340 | ␉␉␉␉␉segCommand = base + sizeof(struct mach_header) + binIndex;␊ |
341 | ␉␉␉␉␉␊ |
342 | ␉␉␉␉␉␊ |
343 | ␉␉␉␉␉binIndex += segCommand->cmdsize;␊ |
344 | ␉␉␉␉␉index++;␊ |
345 | ␉␉␉␉}␊ |
346 | ␉␉␉␉while(index <= immediate);␊ |
347 | ␉␉␉␉␊ |
348 | ␉␉␉␉␊ |
349 | ␉␉␉␉segmentAddress = segCommand->fileoff;␊ |
350 | ␉␉␉␉␊ |
351 | ␉␉␉␉tmp = 0;␊ |
352 | ␉␉␉␉bits = 0;␊ |
353 | ␉␉␉␉do␊ |
354 | ␉␉␉␉{␊ |
355 | ␉␉␉␉␉tmp |= (rebase_stream[++i] & 0x7f) << bits;␊ |
356 | ␉␉␉␉␉bits += 7;␊ |
357 | ␉␉␉␉}␊ |
358 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
359 | ␉␉␉␉␊ |
360 | ␉␉␉␉segmentAddress += tmp;␊ |
361 | ␉␉␉␉break;␊ |
362 | ␉␉␉␉␊ |
363 | ␉␉␉␉␊ |
364 | ␉␉␉case REBASE_OPCODE_ADD_ADDR_ULEB:␊ |
365 | ␉␉␉␉// Add value to rebase address␊ |
366 | ␉␉␉␉tmp = 0;␊ |
367 | ␉␉␉␉bits = 0;␊ |
368 | ␉␉␉␉do␊ |
369 | ␉␉␉␉{␊ |
370 | ␉␉␉␉␉tmp <<= bits;␊ |
371 | ␉␉␉␉␉tmp |= rebase_stream[++i] & 0x7f;␊ |
372 | ␉␉␉␉␉bits += 7;␊ |
373 | ␉␉␉␉}␊ |
374 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
375 | ␉␉␉␉␊ |
376 | ␉␉␉␉segmentAddress +=␉tmp; ␊ |
377 | ␉␉␉␉break;␊ |
378 | ␉␉␉␉␊ |
379 | ␉␉␉case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:␊ |
380 | ␉␉␉␉segmentAddress += immediate * sizeof(void*);␊ |
381 | ␉␉␉␉break;␊ |
382 | ␉␉␉␉␊ |
383 | ␉␉␉␉␊ |
384 | ␉␉␉case REBASE_OPCODE_DO_REBASE_IMM_TIMES:␊ |
385 | ␉␉␉␉index = 0;␊ |
386 | ␉␉␉␉for (index = 0; index < immediate; ++index) {␊ |
387 | ␉␉␉␉␉rebase_location(base + segmentAddress, (char*)base, type);␊ |
388 | ␉␉␉␉␉segmentAddress += sizeof(void*);␊ |
389 | ␉␉␉␉}␊ |
390 | ␉␉␉␉break;␊ |
391 | ␉␉␉␉␊ |
392 | ␉␉␉␉␊ |
393 | ␉␉␉case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:␊ |
394 | ␉␉␉␉tmp = 0;␊ |
395 | ␉␉␉␉bits = 0;␊ |
396 | ␉␉␉␉do␊ |
397 | ␉␉␉␉{␊ |
398 | ␉␉␉␉␉tmp |= (rebase_stream[++i] & 0x7f) << bits;␊ |
399 | ␉␉␉␉␉bits += 7;␊ |
400 | ␉␉␉␉}␊ |
401 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
402 | ␉␉␉␉␊ |
403 | ␉␉␉␉index = 0;␊ |
404 | ␉␉␉␉for (index = 0; index < tmp; ++index) {␊ |
405 | ␉␉␉␉␉//DBG("\tRebasing 0x%X\n", segmentAddress);␊ |
406 | ␉␉␉␉␉rebase_location(base + segmentAddress, (char*)base, type);␉␉␉␉␉␊ |
407 | ␉␉␉␉␉segmentAddress += sizeof(void*);␊ |
408 | ␉␉␉␉}␊ |
409 | ␉␉␉␉break;␊ |
410 | ␉␉␉␉␊ |
411 | ␉␉␉case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:␊ |
412 | ␉␉␉␉tmp = 0;␊ |
413 | ␉␉␉␉bits = 0;␊ |
414 | ␉␉␉␉do␊ |
415 | ␉␉␉␉{␊ |
416 | ␉␉␉␉␉tmp |= (rebase_stream[++i] & 0x7f) << bits;␊ |
417 | ␉␉␉␉␉bits += 7;␊ |
418 | ␉␉␉␉}␊ |
419 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
420 | ␉␉␉␉␊ |
421 | ␉␉␉␉rebase_location(base + segmentAddress, (char*)base, type);␊ |
422 | ␉␉␉␉␊ |
423 | ␉␉␉␉segmentAddress += tmp + sizeof(void*);␊ |
424 | ␉␉␉␉break;␊ |
425 | ␉␉␉␉␊ |
426 | ␉␉␉case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:␊ |
427 | ␉␉␉␉tmp = 0;␊ |
428 | ␉␉␉␉bits = 0;␊ |
429 | ␉␉␉␉do␊ |
430 | ␉␉␉␉{␊ |
431 | ␉␉␉␉␉tmp |= (rebase_stream[++i] & 0x7f) << bits;␊ |
432 | ␉␉␉␉␉bits += 7;␊ |
433 | ␉␉␉␉}␊ |
434 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
435 | ␉␉␉␉␊ |
436 | ␉␉␉␉␊ |
437 | ␉␉␉␉tmp2 = 0;␊ |
438 | ␉␉␉␉bits = 0;␊ |
439 | ␉␉␉␉do␊ |
440 | ␉␉␉␉{␊ |
441 | ␉␉␉␉␉tmp2 |= (rebase_stream[++i] & 0x7f) << bits;␊ |
442 | ␉␉␉␉␉bits += 7;␊ |
443 | ␉␉␉␉}␊ |
444 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
445 | ␉␉␉␉␊ |
446 | ␉␉␉␉index = 0;␊ |
447 | ␉␉␉␉for (index = 0; index < tmp; ++index) {␊ |
448 | ␉␉␉␉␉␊ |
449 | ␉␉␉␉␉rebase_location(base + segmentAddress, (char*)base, type);␊ |
450 | ␉␉␉␉␉␊ |
451 | ␉␉␉␉␉segmentAddress += tmp2 + sizeof(void*);␊ |
452 | ␉␉␉␉}␊ |
453 | ␉␉␉␉break;␊ |
454 | ␉␉}␊ |
455 | ␉␉i++;␊ |
456 | ␉}␊ |
457 | }␊ |
458 | ␊ |
459 | inline void rebase_location(UInt32* location, char* base, int type)␊ |
460 | {␉␊ |
461 | ␉switch(type)␊ |
462 | ␉{␊ |
463 | ␉␉case REBASE_TYPE_POINTER:␊ |
464 | ␉␉case REBASE_TYPE_TEXT_ABSOLUTE32:␊ |
465 | ␉␉␉*location += (UInt32)base;␊ |
466 | ␉␉␉break;␊ |
467 | ␉␉␉␊ |
468 | ␉␉default:␊ |
469 | ␉␉␉break;␊ |
470 | ␉}␊ |
471 | }␊ |
472 | ␊ |
473 | ␊ |
474 | UInt32 read_uleb(UInt8* bind_stream, unsigned int* i)␊ |
475 | {␊ |
476 | // Read in offset␊ |
477 | UInt32 tmp = 0;␊ |
478 | UInt8 bits = 0;␊ |
479 | do␊ |
480 | {␊ |
481 | if(bits < sizeof(UInt32)*8) // hack␊ |
482 | {␊ |
483 | tmp |= (bind_stream[++(*i)] & 0x7f) << bits;␊ |
484 | bits += 7;␊ |
485 | }␊ |
486 | else␊ |
487 | {␊ |
488 | ++(*i);␊ |
489 | }␊ |
490 | }␊ |
491 | while(bind_stream[*i] & 0x80);␊ |
492 | return tmp;␊ |
493 | }␊ |
494 | ␊ |
495 | ␊ |
496 | // Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp␊ |
497 | // NOTE: this uses 32bit values, and not 64bit values. ␊ |
498 | // There is a possibility that this could cause issues,␊ |
499 | // however the modules are 32 bits, so it shouldn't matter too much␊ |
500 | void bind_macho(void* base, UInt8* bind_stream, UInt32 size)␊ |
501 | {␉␊ |
502 | ␉bind_stream += (UInt32)base;␊ |
503 | ␉␊ |
504 | ␉UInt8 immediate = 0;␊ |
505 | ␉UInt8 opcode = 0;␊ |
506 | ␉UInt8 type = BIND_TYPE_POINTER;␊ |
507 | ␉␊ |
508 | ␉UInt32 segmentAddress = 0;␊ |
509 | ␉␊ |
510 | ␉UInt32 address = 0;␊ |
511 | ␉␊ |
512 | ␉SInt32 addend = 0;␊ |
513 | ␉SInt32 libraryOrdinal = 0;␊ |
514 | ␉␊ |
515 | ␉const char* symbolName = NULL;␊ |
516 | ␉UInt8 symboFlags = 0;␊ |
517 | ␉UInt32 symbolAddr = 0xFFFFFFFF;␊ |
518 | ␉␊ |
519 | ␉// Temperary variables␊ |
520 | ␉UInt32 tmp = 0;␊ |
521 | ␉UInt32 tmp2 = 0;␊ |
522 | ␉UInt32 index = 0;␊ |
523 | ␉unsigned int i = 0;␊ |
524 | ␉␊ |
525 | ␉while(i < size)␊ |
526 | ␉{␊ |
527 | ␉␉immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;␊ |
528 | ␉␉opcode = bind_stream[i] & BIND_OPCODE_MASK;␊ |
529 | ␉␉␊ |
530 | ␉␉␊ |
531 | ␉␉switch(opcode)␊ |
532 | ␉␉{␊ |
533 | ␉␉␉case BIND_OPCODE_DONE:␊ |
534 | ␉␉␉␉// reset vars␊ |
535 | ␉␉␉␉type = BIND_TYPE_POINTER;␊ |
536 | ␉␉␉␉segmentAddress = 0;␊ |
537 | ␉␉␉␉address = 0;␊ |
538 | ␉␉␉␉addend = 0;␊ |
539 | ␉␉␉␉libraryOrdinal = 0;␊ |
540 | ␉␉␉␉symbolAddr = 0xFFFFFFFF;␊ |
541 | ␉␉␉default:␊ |
542 | ␉␉␉␉break;␊ |
543 | ␉␉␉␉␊ |
544 | ␉␉␉case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:␊ |
545 | ␉␉␉␉libraryOrdinal = immediate;␊ |
546 | ␉␉␉␉break;␊ |
547 | ␉␉␉␉␊ |
548 | ␉␉␉case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:␊ |
549 | ␉␉␉␉libraryOrdinal = read_uleb(bind_stream, &i);␊ |
550 | ␉␉␉␉break;␊ |
551 | ␉␉␉␉␊ |
552 | ␉␉␉case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:␊ |
553 | ␉␉␉␉libraryOrdinal = immediate ? (SInt8)(BIND_OPCODE_MASK | immediate) : immediate;␉␉␉␉␊ |
554 | ␉␉␉␉break;␊ |
555 | ␉␉␉␉␊ |
556 | ␉␉␉case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:␊ |
557 | ␉␉␉␉symboFlags = immediate;␊ |
558 | ␉␉␉␉symbolName = (char*)&bind_stream[++i];␊ |
559 | ␉␉␉␉i += strlen((char*)&bind_stream[i]);␊ |
560 | ␊ |
561 | ␉␉␉␉symbolAddr = lookup_all_symbols(symbolName);␊ |
562 | ␉␉␉␉break;␊ |
563 | ␉␉␉␉␊ |
564 | ␉␉␉case BIND_OPCODE_SET_TYPE_IMM:␊ |
565 | ␉␉␉␉type = immediate;␊ |
566 | ␉␉␉␉break;␊ |
567 | ␉␉␉␉␊ |
568 | ␉␉␉case BIND_OPCODE_SET_ADDEND_SLEB:␊ |
569 | ␉␉␉␉addend = read_uleb(bind_stream, &i);␉␉␉␉␊ |
570 | ␉␉␉␉if(!(bind_stream[i-1] & 0x40)) addend *= -1;␊ |
571 | ␉␉␉␉break;␊ |
572 | ␉␉␉␉␊ |
573 | ␉␉␉case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:␊ |
574 | ␉␉␉␉segmentAddress = 0;␊ |
575 | ␉␉␉␉␊ |
576 | ␉␉␉␉// Locate address␊ |
577 | ␉␉␉␉struct segment_command* segCommand = NULL;␉// NOTE: 32bit only␊ |
578 | ␉␉␉␉␊ |
579 | ␉␉␉␉unsigned int binIndex = 0;␊ |
580 | ␉␉␉␉index = 0;␊ |
581 | ␉␉␉␉do␊ |
582 | ␉␉␉␉{␊ |
583 | ␉␉␉␉␉segCommand = base + sizeof(struct mach_header) + binIndex;␊ |
584 | ␉␉␉␉␉binIndex += segCommand->cmdsize;␊ |
585 | ␉␉␉␉␉index++;␊ |
586 | ␉␉␉␉}␊ |
587 | ␉␉␉␉while(index <= immediate);␊ |
588 | ␉␉␉␉␊ |
589 | ␉␉␉␉segmentAddress = segCommand->fileoff;␊ |
590 | ␉␉␉␉␉␉␉␉␊ |
591 | ␉␉␉␉segmentAddress += read_uleb(bind_stream, &i);␊ |
592 | ␉␉␉␉break;␊ |
593 | ␉␉␉␉␊ |
594 | ␉␉␉case BIND_OPCODE_ADD_ADDR_ULEB:␊ |
595 | ␉␉␉␉segmentAddress += read_uleb(bind_stream, &i);␊ |
596 | ␉␉␉␉break;␊ |
597 | ␉␉␉␉␊ |
598 | ␉␉␉case BIND_OPCODE_DO_BIND:␊ |
599 | ␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
600 | ␉␉␉␉{␊ |
601 | ␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
602 | ␉␉␉␉␉␉␊ |
603 | ␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
604 | ␉␉␉␉}␊ |
605 | ␉␉␉␉else␊ |
606 | ␉␉␉␉{␊ |
607 | ␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
608 | ␉␉␉␉␉getchar();␊ |
609 | ␉␉␉␉}␊ |
610 | ␉␉␉␉␊ |
611 | ␉␉␉␉segmentAddress += sizeof(void*);␊ |
612 | ␉␉␉␉break;␊ |
613 | ␉␉␉␉␊ |
614 | ␉␉␉case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:␊ |
615 | ␉␉␉␉// Read in offset␊ |
616 | ␉␉␉␉tmp = read_uleb(bind_stream, &i);␊ |
617 | ␊ |
618 | ␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
619 | ␉␉␉␉{␊ |
620 | ␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
621 | ␉␉␉␉␉␊ |
622 | ␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
623 | ␉␉␉␉}␊ |
624 | ␉␉␉␉else␊ |
625 | ␉␉␉␉{␊ |
626 | ␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
627 | ␉␉␉␉␉getchar();␊ |
628 | ␉␉␉␉}␊ |
629 | ␊ |
630 | ␉␉␉␉segmentAddress += tmp + sizeof(void*);␊ |
631 | ␉␉␉␉␊ |
632 | ␉␉␉␉␊ |
633 | ␉␉␉␉break;␊ |
634 | ␉␉␉␉␊ |
635 | ␉␉␉case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:␊ |
636 | ␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
637 | ␉␉␉␉{␊ |
638 | ␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
639 | ␉␉␉␉␉␊ |
640 | ␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
641 | ␉␉␉␉}␊ |
642 | ␉␉␉␉else␊ |
643 | ␉␉␉␉{␊ |
644 | ␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
645 | ␉␉␉␉␉getchar();␊ |
646 | ␉␉␉␉}␊ |
647 | ␉␉␉␉segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);␊ |
648 | ␉␉␉␉␊ |
649 | ␉␉␉␉␊ |
650 | ␉␉␉␉break;␊ |
651 | ␉␉␉␉␊ |
652 | ␉␉␉case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:␊ |
653 | ␉␉␉␉tmp = read_uleb(bind_stream, &i);␉␉␉␉␊ |
654 | ␉␉␉␉␊ |
655 | ␉␉␉␉tmp2 = read_uleb(bind_stream, &i);␉␉␉␉␊ |
656 | ␉␉␉␉␊ |
657 | ␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
658 | ␉␉␉␉{␊ |
659 | ␉␉␉␉␉for(index = 0; index < tmp; index++)␊ |
660 | ␉␉␉␉␉{␊ |
661 | ␉␉␉␉␉␉␊ |
662 | ␉␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
663 | ␉␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
664 | ␉␉␉␉␉␉segmentAddress += tmp2 + sizeof(void*);␊ |
665 | ␉␉␉␉␉}␊ |
666 | ␉␉␉␉}␊ |
667 | ␉␉␉␉else␊ |
668 | ␉␉␉␉{␊ |
669 | ␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
670 | ␉␉␉␉␉getchar();␊ |
671 | ␉␉␉␉}␊ |
672 | ␉␉␉␉break;␊ |
673 | ␉␉}␊ |
674 | ␉␉i++;␊ |
675 | ␉}␊ |
676 | }␊ |
677 | ␊ |
678 | ␊ |
679 | inline void bind_location(UInt32* location, char* value, UInt32 addend, int type)␊ |
680 | {␉␊ |
681 | ␉// do actual update␊ |
682 | ␉char* newValue = value + addend;␊ |
683 | ␉␊ |
684 | ␉switch (type) {␊ |
685 | ␉␉case BIND_TYPE_POINTER:␊ |
686 | ␉␉case BIND_TYPE_TEXT_ABSOLUTE32:␊ |
687 | ␉␉␉break;␊ |
688 | ␉␉␉␊ |
689 | ␉␉case BIND_TYPE_TEXT_PCREL32:␊ |
690 | ␉␉␉newValue -= ((UInt32)location + 4);␊ |
691 | ␉␉␉␊ |
692 | ␉␉␉break;␊ |
693 | ␉␉default:␊ |
694 | ␉␉␉return;␊ |
695 | ␉}␊ |
696 | ␉//DBG("Binding 0x%X to 0x%X (was 0x%X)\n", location, newValue, *location);␊ |
697 | ␉*location = (UInt32)newValue;␊ |
698 | }␊ |
699 | ␊ |
700 | /*␊ |
701 | * Locate the symbol for an already loaded function and modify the beginning of␊ |
702 | * the function to jump directly to the new one␊ |
703 | * example: replace_function("_HelloWorld_start", &replacement_start);␊ |
704 | */␊ |
705 | int replace_function(const char* symbol, void* newAddress)␊ |
706 | {␊ |
707 | ␉UInt32* jumpPointer = malloc(sizeof(UInt32*));␉ ␊ |
708 | ␉UInt32 addr = lookup_all_symbols(symbol);␊ |
709 | ␉␊ |
710 | ␉char* binary = (char*)addr;␊ |
711 | ␉if(addr != 0xFFFFFFFF)␊ |
712 | ␉{␊ |
713 | ␉␉//DBG("Replacing %s to point to 0x%x\n", symbol, newAddress);␊ |
714 | ␉␉*binary++ = 0xFF;␉// Jump␊ |
715 | ␉␉*binary++ = 0x25;␉// Long Jump␊ |
716 | ␉␉*((UInt32*)binary) = (UInt32)jumpPointer;␊ |
717 | ␉␉␊ |
718 | ␉␉*jumpPointer = (UInt32)newAddress;␊ |
719 | ␉␉return 1;␊ |
720 | ␉}␊ |
721 | ␉return 0;␊ |
722 | }␊ |
723 | ␊ |
724 | /********************************************************************************/␊ |
725 | /*␉dyld / Linker Interface␉␉␉␉␉␉␉␉␉␉␉␉␉␉*/␊ |
726 | /********************************************************************************/␊ |
727 | ␊ |
728 | void dyld_stub_binder()␊ |
729 | {␊ |
730 | ␉printf("ERROR: dyld_stub_binder was called, should have been take care of by the linker.\n");␊ |
731 | ␉getchar();␊ |
732 | } |