Root/
Source at commit 2755 created 8 years 10 months ago. By ifabio, fix allocate space for ascii string zero terminating in device_inject.c (thx Slice and BlackOsx) | |
---|---|
1 | /*␊ |
2 | * Copyright 2010 Evan Lojewski. All rights reserved.␊ |
3 | *␊ |
4 | */␊ |
5 | #include "boot.h"␊ |
6 | #include "bootstruct.h"␊ |
7 | #include "modules.h"␊ |
8 | #include "boot_modules.h"␊ |
9 | #include <vers.h>␊ |
10 | ␊ |
11 | #ifdef CONFIG_MODULES␊ |
12 | #ifndef CONFIG_MODULE_DEBUG␊ |
13 | #define CONFIG_MODULE_DEBUG 0␊ |
14 | #endif␊ |
15 | ␊ |
16 | ␊ |
17 | #if CONFIG_MODULE_DEBUG␊ |
18 | #define DBG(x...)␉printf(x);␊ |
19 | #define DBGPAUSE()␉getchar()␊ |
20 | #else␊ |
21 | #define DBG(x...)␊ |
22 | #define DBGPAUSE()␊ |
23 | #endif␊ |
24 | ␊ |
25 | // NOTE: Global so that modules can link with this␊ |
26 | static UInt64 textAddress = 0;␊ |
27 | static UInt64 textSection = 0;␊ |
28 | ␊ |
29 | /** Internal symbols, however there are accessor methods **/␊ |
30 | moduleHook_t* moduleCallbacks = NULL;␊ |
31 | moduleList_t* loadedModules = NULL;␊ |
32 | symbolList_t* moduleSymbols = NULL;␊ |
33 | unsigned int (*lookup_symbol)(const char*) = NULL;␊ |
34 | ␊ |
35 | ␊ |
36 | /*␊ |
37 | * Initialize the module system by loading the Symbols.dylib module.␊ |
38 | * Once loaded, locate the _lookup_symbol function so that internal␊ |
39 | * symbols can be resolved.␊ |
40 | */␊ |
41 | int init_module_system()␊ |
42 | {␊ |
43 | // Start any modules that were compiled in first.␊ |
44 | start_built_in_modules();␊ |
45 | ␊ |
46 | ␊ |
47 | ␉int retVal = 0;␊ |
48 | ␉void (*module_start)(void) = NULL;␊ |
49 | ␉␊ |
50 | ␉extern char symbols_start __asm("section$start$__DATA$__Symbols");␊ |
51 | ␉char* module_data = &symbols_start;␊ |
52 | ␊ |
53 | ␉// Intialize module system␊ |
54 | ␉if(module_data)␊ |
55 | ␉{␊ |
56 | ␉␉// Module system was compiled in (Symbols.dylib addr known)␊ |
57 | ␉␉module_start = parse_mach(module_data, &load_module, &add_symbol, NULL);␊ |
58 | ␉␉␊ |
59 | ␉␉if(module_start && module_start != (void*)0xFFFFFFFF)␊ |
60 | ␉␉{␊ |
61 | ␉␉␉// Notify the system that it was laoded␊ |
62 | ␉␉␉module_loaded(SYMBOLS_MODULE, SYMBOLS_AUTHOR, SYMBOLS_DESCRIPTION, SYMBOLS_VERSION, SYMBOLS_COMPAT);␊ |
63 | ␉␉␉(*module_start)();␉// Start the module. This will point to load_all_modules due to the way the dylib was constructed.␊ |
64 | ␉␉␉execute_hook("ModulesLoaded", NULL, NULL, NULL, NULL);␊ |
65 | ␉␉␉DBG("Module %s Loaded.\n", SYMBOLS_MODULE);␊ |
66 | ␉␉␉retVal = 1;␊ |
67 | ␊ |
68 | ␉␉}␊ |
69 | ␉␉else␊ |
70 | ␉␉{␊ |
71 | ␉␉␉// The module does not have a valid start function␊ |
72 | ␉␉␉printf("Unable to start %s at 0x%x\n", SYMBOLS_MODULE, module_data); pause();␊ |
73 | ␉␉}␉␉␊ |
74 | ␉}␊ |
75 | ␉return retVal;␊ |
76 | }␊ |
77 | ␊ |
78 | void start_built_in_module(const char* name, ␊ |
79 | const char* author, ␊ |
80 | const char* description,␊ |
81 | UInt32 version,␊ |
82 | UInt32 compat,␊ |
83 | void(*start_function)(void))␊ |
84 | {␊ |
85 | start_function();␊ |
86 | // Notify the module system that this module really exists, specificaly, let other module link with it␊ |
87 | module_loaded(name, author, description, version, compat);␊ |
88 | }␊ |
89 | ␊ |
90 | /*␊ |
91 | * Load all modules in the /Extra/modules/ directory␊ |
92 | * Module depencdies will be loaded first␊ |
93 | * Modules will only be loaded once. When loaded a module must␊ |
94 | * setup apropriete function calls and hooks as required.␊ |
95 | * NOTE: To ensure a module loads after another you may ␊ |
96 | * link one module with the other. For dyld to allow this, you must␊ |
97 | * reference at least one symbol within the module.␊ |
98 | */␊ |
99 | void load_all_modules()␊ |
100 | {␊ |
101 | ␉char* name;␊ |
102 | ␉long flags;␊ |
103 | ␉long time;␊ |
104 | ␉struct dirstuff* moduleDir = opendir("/Extra/modules/");␊ |
105 | ␉while(readdir(moduleDir, (const char**)&name, &flags, &time) >= 0)␊ |
106 | ␉{␊ |
107 | ␉␉if(strcmp(&name[strlen(name) - sizeof("dylib")], ".dylib") == 0)␊ |
108 | ␉␉{␊ |
109 | ␉␉␉char* tmp = malloc(strlen(name) + 1);␊ |
110 | ␉␉␉strcpy(tmp, name);␊ |
111 | ␉␉␉␊ |
112 | ␉␉␉if(!load_module(tmp))␊ |
113 | ␉␉␉{␊ |
114 | ␉␉␉␉// failed to load␊ |
115 | ␉␉␉␉// free(tmp);␊ |
116 | ␉␉␉}␊ |
117 | ␉␉}␊ |
118 | ␉␉else ␊ |
119 | ␉␉{␊ |
120 | ␉␉␉DBG("Ignoring %s\n", name);␊ |
121 | ␉␉}␊ |
122 | ␊ |
123 | ␉}␊ |
124 | }␊ |
125 | ␊ |
126 | ␊ |
127 | /*␊ |
128 | * Load a module file in /Extra/modules/␊ |
129 | */␊ |
130 | int load_module(char* module)␊ |
131 | {␊ |
132 | ␉int retVal = 1;␊ |
133 | ␉void (*module_start)(void) = NULL;␊ |
134 | ␉char modString[128];␊ |
135 | ␉int fh = -1;␊ |
136 | ␊ |
137 | ␉// Check to see if the module has already been loaded␊ |
138 | ␉if(is_module_loaded(module))␊ |
139 | ␉{␊ |
140 | ␉␉return 1;␊ |
141 | ␉}␊ |
142 | ␉␊ |
143 | ␉sprintf(modString, MODULE_PATH "%s", module);␊ |
144 | ␉fh = open(modString, 0);␊ |
145 | ␉if(fh < 0)␊ |
146 | ␉{␊ |
147 | ␉␉DBG("WARNING: Unable to locate module %s\n", modString); DBGPAUSE();␊ |
148 | ␉␉return 0;␊ |
149 | ␉}␊ |
150 | ␉␊ |
151 | ␉unsigned int moduleSize = file_size(fh);␊ |
152 | ␉char* module_base = (char*) malloc(moduleSize);␊ |
153 | ␉if (moduleSize && read(fh, module_base, moduleSize) == moduleSize)␊ |
154 | ␉{␊ |
155 | ␉␉// Module loaded into memory, parse it␊ |
156 | ␉␉module_start = parse_mach(module_base, &load_module, &add_symbol, NULL);␊ |
157 | ␊ |
158 | ␉␉if(module_start && module_start != (void*)0xFFFFFFFF)␊ |
159 | ␉␉{␊ |
160 | ␉␉␉// Notify the system that it was laoded␊ |
161 | ␉␉␉module_loaded(module, NULL, NULL, 0, 0 /*moduleName, NULL, moduleVersion, moduleCompat*/);␊ |
162 | ␉␉␉(*module_start)();␉// Start the module␊ |
163 | ␉␉␉DBG("Module %s Loaded.\n", module); DBGPAUSE();␊ |
164 | ␉␉}␊ |
165 | #if CONFIG_MODULE_DEBUG␊ |
166 | ␉␉else // The module does not have a valid start function. This may be a library.␊ |
167 | ␉␉{␊ |
168 | ␉␉␉printf("WARNING: Unable to start %s\n", module);␊ |
169 | ␉␉␉getchar();␊ |
170 | ␉␉}␊ |
171 | #else␊ |
172 | ␉␉else msglog("WARNING: Unable to start %s\n", module);␊ |
173 | #endif␊ |
174 | ␉}␊ |
175 | ␉else␊ |
176 | ␉{␊ |
177 | ␉␉DBG("Unable to read in module %s\n.", module); DBGPAUSE();␊ |
178 | ␉␉retVal = 0;␊ |
179 | ␉}␊ |
180 | ␊ |
181 | ␉close(fh);␊ |
182 | ␉return retVal;␊ |
183 | }␊ |
184 | ␊ |
185 | /*␊ |
186 | * add_symbol␊ |
187 | * This function adds a symbol from a module to the list of known symbols ␊ |
188 | * possibly change to a pointer and add this to the Symbol module so that it can␊ |
189 | * adjust it's internal symbol list (sort) to optimize locating new symbols␊ |
190 | * NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF␊ |
191 | */␊ |
192 | long long add_symbol(char* symbol, long long addr, char is64)␊ |
193 | {␊ |
194 | ␉// This only can handle 32bit symbols ␊ |
195 | ␉symbolList_t* entry;␊ |
196 | ␉//DBG("Adding symbol %s at 0x%X\n", symbol, addr);␊ |
197 | ␉␊ |
198 | ␉entry = malloc(sizeof(symbolList_t));␊ |
199 | ␉entry->next = moduleSymbols;␊ |
200 | ␉moduleSymbols = entry;␊ |
201 | ␉␊ |
202 | ␉entry->addr = (UInt32)addr;␊ |
203 | ␉entry->symbol = symbol;␊ |
204 | ␉␊ |
205 | ␉if(!is64 && strcmp(symbol, "start") == 0)␊ |
206 | ␉{␊ |
207 | ␉␉return addr;␊ |
208 | ␉}␊ |
209 | ␉else␊ |
210 | ␉{␊ |
211 | ␉␉return 0xFFFFFFFF; // fixme␊ |
212 | ␉}␊ |
213 | }␊ |
214 | ␊ |
215 | ␊ |
216 | /*␊ |
217 | * print out the information about the loaded module␊ |
218 | */␊ |
219 | void module_loaded(const char* name, const char* author, const char* description, UInt32 version, UInt32 compat)␊ |
220 | {␊ |
221 | ␉moduleList_t* new_entry = malloc(sizeof(moduleList_t));␊ |
222 | ␉new_entry->next = loadedModules;␊ |
223 | ␊ |
224 | ␉loadedModules = new_entry;␊ |
225 | ␉␊ |
226 | if(!name) name = "Unknown";␊ |
227 | if(!author) author = "Unknown";␊ |
228 | if(!description) description = "";␊ |
229 | ␊ |
230 | ␉new_entry->name = name;␊ |
231 | new_entry->author = author;␊ |
232 | new_entry->description = description;␊ |
233 | ␉new_entry->version = version;␊ |
234 | new_entry->compat = compat;␊ |
235 | ␊ |
236 | msglog("Module '%s' by '%s' Loaded.\n", name, author);␊ |
237 | msglog("\tDescription: %s\n", description);␊ |
238 | msglog("\tVersion: %d\n", version); // todo: sperate to major.minor.bugfix␊ |
239 | msglog("\tCompat: %d\n", compat); // todo: ^^^ major.minor.bugfix␊ |
240 | }␊ |
241 | ␊ |
242 | int is_module_loaded(const char* name)␊ |
243 | {␊ |
244 | ␉// todo sorted search␊ |
245 | ␉moduleList_t* entry = loadedModules;␊ |
246 | ␉while(entry)␊ |
247 | ␉{␊ |
248 | ␉␉if(strcmp(entry->name, name) == 0)␊ |
249 | ␉␉{␊ |
250 | ␉␉␉DBG("Located module %s\n", name); DBGPAUSE();␊ |
251 | ␉␉␉return 1;␊ |
252 | ␉␉}␊ |
253 | ␉␉else␊ |
254 | ␉␉{␊ |
255 | ␉␉␉entry = entry->next;␊ |
256 | ␉␉}␊ |
257 | ␊ |
258 | ␉}␊ |
259 | ␉␊ |
260 | ␉DBG("Module %s not loaded\n", name); DBGPAUSE();␊ |
261 | ␉return 0;␊ |
262 | }␊ |
263 | ␊ |
264 | /*␊ |
265 | *␉lookup symbols in all loaded modules. Thins inludes boot syms due to Symbols.dylib construction␊ |
266 | *␊ |
267 | */␊ |
268 | unsigned int lookup_all_symbols(const char* name)␊ |
269 | {␊ |
270 | ␉symbolList_t* entry = moduleSymbols;␊ |
271 | ␉while(entry)␊ |
272 | ␉{␊ |
273 | ␉␉if(strcmp(entry->symbol, name) == 0)␊ |
274 | ␉␉{␊ |
275 | ␉␉␉//DBG("External symbol %s located at 0x%X\n", name, entry->addr);␊ |
276 | ␉␉␉return entry->addr;␊ |
277 | ␉␉}␊ |
278 | ␉␉else␊ |
279 | ␉␉{␊ |
280 | ␉␉␉entry = entry->next;␊ |
281 | ␉␉}␊ |
282 | ␉}␊ |
283 | ␉␊ |
284 | #if CONFIG_MODULE_DEBUG␊ |
285 | ␉printf("Unable to locate symbol %s\n", name);␊ |
286 | ␉getchar();␊ |
287 | #endif␊ |
288 | ␉␊ |
289 | ␉if(strcmp(name, VOID_SYMBOL) == 0) return 0xFFFFFFFF;␊ |
290 | ␉// In the event that a symbol does not exist␊ |
291 | ␉// Return a pointer to a void function.␊ |
292 | ␉else return lookup_all_symbols(VOID_SYMBOL);␉␊ |
293 | }␊ |
294 | ␊ |
295 | /********************************************************************************/␊ |
296 | /*␉Macho Parser␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉*/␊ |
297 | /********************************************************************************/␊ |
298 | ␊ |
299 | /*␊ |
300 | * Parse through a macho module. The module will be rebased and binded␊ |
301 | * as specified in the macho header. If the module is sucessfuly laoded␊ |
302 | * the module iinit address will be returned.␊ |
303 | * NOTE; all dependecies will be loaded before this module is started␊ |
304 | * NOTE: If the module is unable to load ot completeion, the modules␊ |
305 | * symbols will still be available.␊ |
306 | */␊ |
307 | void* parse_mach(void* binary, ␊ |
308 | int(*dylib_loader)(char*), ␊ |
309 | long long(*symbol_handler)(char*, long long, char),␊ |
310 | void (*section_handler)(char* section, char* segment, void* cmd, UInt64 offset, UInt64 address)␊ |
311 | )␊ |
312 | {␉␊ |
313 | ␉char is64 = false;␊ |
314 | ␉void (*module_start)(void) = NULL;␊ |
315 | ␉␊ |
316 | ␉// Module info␊ |
317 | ␉/*char* moduleName = NULL;␊ |
318 | ␉ UInt32 moduleVersion = 0;␊ |
319 | ␉ UInt32 moduleCompat = 0;␊ |
320 | ␉ */␊ |
321 | ␉// TODO convert all of the structs to a union␊ |
322 | ␉struct load_command *loadCommand = NULL;␊ |
323 | ␉struct dylib_command* dylibCommand = NULL;␊ |
324 | ␉struct dyld_info_command* dyldInfoCommand = NULL;␊ |
325 | ␉␊ |
326 | ␉struct symtab_command* symtabCommand = NULL;␊ |
327 | ␉struct segment_command *segCommand = NULL;␊ |
328 | ␉struct segment_command_64 *segCommand64 = NULL;␊ |
329 | ␉␊ |
330 | ␉//struct dysymtab_command* dysymtabCommand = NULL;␊ |
331 | ␉UInt32 binaryIndex = 0;␊ |
332 | ␉UInt16 cmd = 0;␊ |
333 | ␉␊ |
334 | ␉textSection = 0;␊ |
335 | ␉textAddress = 0;␉// reinitialize text location in case it doesn't exist;␊ |
336 | ␉␊ |
337 | ␉// Parse through the load commands␊ |
338 | ␉if(((struct mach_header*)binary)->magic == MH_MAGIC)␊ |
339 | ␉{␊ |
340 | ␉␉is64 = false;␊ |
341 | ␉␉binaryIndex += sizeof(struct mach_header);␊ |
342 | ␉}␊ |
343 | ␉else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)␊ |
344 | ␉{␊ |
345 | ␉␉// NOTE: modules cannot be 64bit. This is used to parse the kernel and kexts␊ |
346 | ␉␉is64 = true;␊ |
347 | ␉␉binaryIndex += sizeof(struct mach_header_64);␊ |
348 | ␉}␊ |
349 | ␉else␊ |
350 | ␉{␊ |
351 | ␉␉verbose("Invalid mach magic 0x%X\n", ((struct mach_header*)binary)->magic);␊ |
352 | ␉␉return NULL;␊ |
353 | ␉}␊ |
354 | ␉␊ |
355 | ␉␊ |
356 | ␉␊ |
357 | ␉/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)␊ |
358 | ␉ {␊ |
359 | ␉ printf("Module is not a dylib. Unable to load.\n");␊ |
360 | ␉ getchar();␊ |
361 | ␉ return NULL; // Module is in the incorrect format␊ |
362 | ␉ }*/␊ |
363 | ␉␊ |
364 | ␉while(cmd < ((struct mach_header*)binary)->ncmds)␊ |
365 | ␉{␊ |
366 | ␉␉cmd++;␊ |
367 | ␉␉␊ |
368 | ␉␉loadCommand = binary + binaryIndex;␊ |
369 | ␉␉UInt32 cmdSize = loadCommand->cmdsize;␊ |
370 | ␉␉␊ |
371 | ␉␉␊ |
372 | ␉␉switch ((loadCommand->cmd & 0x7FFFFFFF))␊ |
373 | ␉␉{␊ |
374 | ␉␉␉case LC_SYMTAB:␊ |
375 | ␉␉␉␉symtabCommand = binary + binaryIndex;␊ |
376 | ␉␉␉␉break;␊ |
377 | ␉␉␉␉␊ |
378 | ␉␉␉case LC_SEGMENT: // 32bit macho␊ |
379 | {␊ |
380 | segCommand = binary + binaryIndex;␊ |
381 | ␊ |
382 | UInt32 sectionIndex;␊ |
383 | ␊ |
384 | sectionIndex = sizeof(struct segment_command);␊ |
385 | ␊ |
386 | struct section *sect;␊ |
387 | ␊ |
388 | while(sectionIndex < segCommand->cmdsize)␊ |
389 | {␊ |
390 | sect = binary + binaryIndex + sectionIndex;␊ |
391 | ␊ |
392 | sectionIndex += sizeof(struct section);␊ |
393 | ␊ |
394 | if(section_handler) section_handler(sect->sectname, segCommand->segname, (void*)sect, sect->offset, sect->addr);␊ |
395 | ␊ |
396 | ␉␉␉␉␉␉if((strcmp("__TEXT", segCommand->segname) == 0) && (strcmp("__text", sect->sectname) == 0))␊ |
397 | {␊ |
398 | // __TEXT,__text found, save the offset and address for when looking for the calls.␊ |
399 | textSection = sect->offset;␊ |
400 | textAddress = sect->addr;␊ |
401 | }␉␉␉␉␉␊ |
402 | }␊ |
403 | }␊ |
404 | ␉␉␉␉break;␊ |
405 | ␉␉␉case LC_SEGMENT_64:␉// 64bit macho's␊ |
406 | {␊ |
407 | segCommand64 = binary + binaryIndex;␉␉␉␉␊ |
408 | UInt32 sectionIndex;␊ |
409 | ␊ |
410 | sectionIndex = sizeof(struct segment_command_64);␊ |
411 | ␊ |
412 | struct section_64 *sect;␊ |
413 | ␊ |
414 | while(sectionIndex < segCommand64->cmdsize)␊ |
415 | {␊ |
416 | sect = binary + binaryIndex + sectionIndex;␊ |
417 | ␊ |
418 | sectionIndex += sizeof(struct section_64);␊ |
419 | ␊ |
420 | if(section_handler) section_handler(sect->sectname, segCommand64->segname, (void*)sect, sect->offset, sect->addr);␊ |
421 | ␊ |
422 | if((strcmp("__TEXT", segCommand64->segname) == 0) && (strcmp("__text", sect->sectname) == 0))␊ |
423 | {␊ |
424 | // __TEXT,__text found, save the offset and address for when looking for the calls.␊ |
425 | textSection = sect->offset;␊ |
426 | textAddress = sect->addr;␊ |
427 | }␉␉␉␉␉␊ |
428 | }␉␊ |
429 | ␉␉␉␉}␉␉␉␊ |
430 | ␉␉␉␉break;␊ |
431 | ␉␉␉␉␊ |
432 | ␉␉␉␉␊ |
433 | ␉␉␉case LC_LOAD_DYLIB:␊ |
434 | ␉␉␉case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:␊ |
435 | // Required modules␊ |
436 | ␉␉␉␉dylibCommand = binary + binaryIndex;␊ |
437 | ␉␉␉␉char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));␊ |
438 | ␉␉␉␉// Possible enhancments: verify version␊ |
439 | ␉␉␉␉// =␉dylibCommand->dylib.current_version;␊ |
440 | ␉␉␉␉// =␉dylibCommand->dylib.compatibility_version;␊ |
441 | ␉␉␉␉if(dylib_loader)␊ |
442 | ␉␉␉␉{␊ |
443 | ␉␉␉␉␉char* name = malloc(strlen(module) + strlen(".dylib") + 1);␊ |
444 | ␉␉␉␉␉sprintf(name, "%s.dylib", module);␊ |
445 | ␉␉␉␉␉␊ |
446 | ␉␉␉␉␉if (!dylib_loader(name))␊ |
447 | ␉␉␉␉␉{␊ |
448 | ␉␉␉␉␉␉// NOTE: any symbols exported by dep will be replace with the void function␊ |
449 | ␉␉␉␉␉␉free(name);␊ |
450 | ␉␉␉␉␉}␊ |
451 | ␉␉␉␉}␊ |
452 | ␉␉␉␉␊ |
453 | ␉␉␉␉break;␊ |
454 | ␉␉␉␉␊ |
455 | ␉␉␉case LC_ID_DYLIB:␊ |
456 | ␉␉␉␉//dylibCommand = binary + binaryIndex;␊ |
457 | ␉␉␉␉/*moduleName =␉binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));␊ |
458 | ␉␉␉␉ moduleVersion =␉dylibCommand->dylib.current_version;␊ |
459 | ␉␉␉␉ moduleCompat =␉dylibCommand->dylib.compatibility_version;␊ |
460 | ␉␉␉␉ */␊ |
461 | ␉␉␉␉break;␊ |
462 | ␉␉␉␉␊ |
463 | ␉␉␉case LC_DYLD_INFO:␊ |
464 | ␉␉␉//case LC_DYLD_INFO_ONLY:␉// compressed info, 10.6+ macho files, already handeled␊ |
465 | ␉␉␉␉// Bind and rebase info is stored here␊ |
466 | ␉␉␉␉dyldInfoCommand = binary + binaryIndex;␊ |
467 | ␉␉␉␉break;␊ |
468 | ␉␉␉␉␊ |
469 | ␉␉␉case LC_DYSYMTAB:␊ |
470 | ␉␉␉case LC_UUID:␊ |
471 | ␉␉␉case LC_UNIXTHREAD:␊ |
472 | ␉␉␉␉break;␊ |
473 | ␉␉␉␉␊ |
474 | ␉␉␉default:␊ |
475 | ␉␉␉␉DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);␊ |
476 | ␉␉␉␉break;␊ |
477 | ␉␉␉␉␊ |
478 | ␉␉}␊ |
479 | ␉␉␊ |
480 | ␉␉binaryIndex += cmdSize;␊ |
481 | ␉}␊ |
482 | ␊ |
483 | ␉// bind_macho uses the symbols, if the textAdd does not exist (Symbols.dylib, no code), addresses are static and not relative␊ |
484 | ␉module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);␊ |
485 | ␉␊ |
486 | ␉if(dyldInfoCommand)␊ |
487 | ␉{␊ |
488 | ␉␉// Rebase the module before binding it.␊ |
489 | ␉␉if(dyldInfoCommand->rebase_off)␉␉rebase_macho(binary, (char*)dyldInfoCommand->rebase_off,␉dyldInfoCommand->rebase_size);␊ |
490 | ␉␉// Bind all symbols. ␊ |
491 | ␉␉if(dyldInfoCommand->bind_off)␉␉bind_macho(binary, (UInt8*)dyldInfoCommand->bind_off,␉␉dyldInfoCommand->bind_size);␊ |
492 | ␉␉if(dyldInfoCommand->weak_bind_off)␉bind_macho(binary, (UInt8*)dyldInfoCommand->weak_bind_off,␉dyldInfoCommand->weak_bind_size);␊ |
493 | ␉␉if(dyldInfoCommand->lazy_bind_off)␉bind_macho(binary, (UInt8*)dyldInfoCommand->lazy_bind_off,␉dyldInfoCommand->lazy_bind_size);␊ |
494 | ␉}␊ |
495 | ␉␊ |
496 | ␉return module_start;␊ |
497 | ␉␊ |
498 | }␊ |
499 | ␊ |
500 | /*␊ |
501 | * parse the symbol table␊ |
502 | * Lookup any undefined symbols␊ |
503 | */␊ |
504 | ␊ |
505 | unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)␊ |
506 | {␊ |
507 | ␉unsigned int module_start␉= 0xFFFFFFFF;␉␊ |
508 | ␉UInt32 symbolIndex␉␉␉= 0;␊ |
509 | ␉char* symbolString␉␉␉= base + (char*)symtabCommand->stroff;␊ |
510 | ␊ |
511 | ␉if(!is64)␊ |
512 | ␉{␊ |
513 | ␉␉struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;␊ |
514 | ␉␉while(symbolIndex < symtabCommand->nsyms)␊ |
515 | ␉␉{␊ |
516 | ␉␉␉// If the symbol is exported by this module␊ |
517 | ␉␉␉if(symbolEntry->n_value &&␊ |
518 | ␉␉␉ symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)␊ |
519 | ␉␉␉{␊ |
520 | ␉␉␉␉␊ |
521 | ␉␉␉␉// Module start located. Start is an alias so don't register it␊ |
522 | ␉␉␉␉module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;␊ |
523 | ␉␉␉}␊ |
524 | ␉␉␉␊ |
525 | ␉␉␉symbolEntry++;␊ |
526 | ␉␉␉symbolIndex++;␉// TODO remove␊ |
527 | ␉␉}␊ |
528 | ␉}␊ |
529 | ␉else␊ |
530 | ␉{␊ |
531 | ␉␉struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;␊ |
532 | ␉␉// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now, verify later)␉␊ |
533 | ␉␉while(symbolIndex < symtabCommand->nsyms)␊ |
534 | ␉␉{␊ |
535 | ␉␉␉␊ |
536 | ␉␉␉␊ |
537 | ␉␉␉// If the symbol is exported by this module␊ |
538 | ␉␉␉if(symbolEntry->n_value &&␊ |
539 | ␉␉␉ symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)␊ |
540 | ␉␉␉{␊ |
541 | ␉␉␉␉␊ |
542 | ␉␉␉␉// Module start located. Start is an alias so don't register it␊ |
543 | ␉␉␉␉module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;␊ |
544 | ␉␉␉}␊ |
545 | ␉␉␉␊ |
546 | ␉␉␉symbolEntry++;␊ |
547 | ␉␉␉symbolIndex++;␉// TODO remove␊ |
548 | ␉␉}␊ |
549 | ␉}␊ |
550 | ␉return module_start;␊ |
551 | }␊ |
552 | ␊ |
553 | // Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp␊ |
554 | void rebase_macho(void* base, char* rebase_stream, UInt32 size)␊ |
555 | {␊ |
556 | ␉rebase_stream += (UInt32)base;␊ |
557 | ␉␊ |
558 | ␉UInt8 immediate = 0;␊ |
559 | ␉UInt8 opcode = 0;␊ |
560 | ␉UInt8 type = 0;␊ |
561 | ␉UInt32 segmentAddress = 0;␊ |
562 | ␉␊ |
563 | ␉␊ |
564 | ␉UInt32 tmp = 0;␊ |
565 | ␉UInt32 tmp2 = 0;␊ |
566 | ␉UInt8 bits = 0;␊ |
567 | ␉int index = 0;␊ |
568 | ␉unsigned int i = 0;␊ |
569 | ␉␊ |
570 | ␉while(i < size)␊ |
571 | ␉{␊ |
572 | ␉␉immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;␊ |
573 | ␉␉opcode = rebase_stream[i] & REBASE_OPCODE_MASK;␊ |
574 | ␉␉␊ |
575 | ␉␉␊ |
576 | ␉␉switch(opcode)␊ |
577 | ␉␉{␊ |
578 | ␉␉␉case REBASE_OPCODE_DONE:␊ |
579 | ␉␉␉␉// Rebase complete, reset vars␊ |
580 | ␉␉␉␉immediate = 0;␊ |
581 | ␉␉␉␉opcode = 0;␊ |
582 | ␉␉␉␉type = 0;␊ |
583 | ␉␉␉␉segmentAddress = 0;␊ |
584 | ␉␉␉default:␊ |
585 | ␉␉␉␉break;␊ |
586 | ␉␉␉␉␊ |
587 | ␉␉␉␉␊ |
588 | ␉␉␉case REBASE_OPCODE_SET_TYPE_IMM:␊ |
589 | ␉␉␉␉type = immediate;␊ |
590 | ␉␉␉␉break;␊ |
591 | ␉␉␉␉␊ |
592 | ␉␉␉␉␊ |
593 | ␉␉␉case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:␊ |
594 | ␉␉␉␉// Locate address to begin rebasing␊ |
595 | ␉␉␉␉segmentAddress = 0;␊ |
596 | ␉␉␉␉struct segment_command* segCommand = NULL; // NOTE: 32bit only␊ |
597 | ␉␉␉␉␊ |
598 | ␉␉␉␉unsigned int binIndex = 0;␊ |
599 | ␉␉␉␉index = 0;␊ |
600 | ␉␉␉␉do␊ |
601 | ␉␉␉␉{␊ |
602 | ␉␉␉␉␉segCommand = base + sizeof(struct mach_header) + binIndex;␊ |
603 | ␉␉␉␉␉␊ |
604 | ␉␉␉␉␉␊ |
605 | ␉␉␉␉␉binIndex += segCommand->cmdsize;␊ |
606 | ␉␉␉␉␉index++;␊ |
607 | ␉␉␉␉}␊ |
608 | ␉␉␉␉while(index <= immediate);␊ |
609 | ␉␉␉␉␊ |
610 | ␉␉␉␉␊ |
611 | ␉␉␉␉segmentAddress = segCommand->fileoff;␊ |
612 | ␉␉␉␉␊ |
613 | ␉␉␉␉tmp = 0;␊ |
614 | ␉␉␉␉bits = 0;␊ |
615 | ␉␉␉␉do␊ |
616 | ␉␉␉␉{␊ |
617 | ␉␉␉␉␉tmp |= (rebase_stream[++i] & 0x7f) << bits;␊ |
618 | ␉␉␉␉␉bits += 7;␊ |
619 | ␉␉␉␉}␊ |
620 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
621 | ␉␉␉␉␊ |
622 | ␉␉␉␉segmentAddress += tmp;␊ |
623 | ␉␉␉␉break;␊ |
624 | ␉␉␉␉␊ |
625 | ␉␉␉␉␊ |
626 | ␉␉␉case REBASE_OPCODE_ADD_ADDR_ULEB:␊ |
627 | ␉␉␉␉// Add value to rebase address␊ |
628 | ␉␉␉␉tmp = 0;␊ |
629 | ␉␉␉␉bits = 0;␊ |
630 | ␉␉␉␉do␊ |
631 | ␉␉␉␉{␊ |
632 | ␉␉␉␉␉tmp <<= bits;␊ |
633 | ␉␉␉␉␉tmp |= rebase_stream[++i] & 0x7f;␊ |
634 | ␉␉␉␉␉bits += 7;␊ |
635 | ␉␉␉␉}␊ |
636 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
637 | ␉␉␉␉␊ |
638 | ␉␉␉␉segmentAddress +=␉tmp; ␊ |
639 | ␉␉␉␉break;␊ |
640 | ␉␉␉␉␊ |
641 | ␉␉␉case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:␊ |
642 | ␉␉␉␉segmentAddress += immediate * sizeof(void*);␊ |
643 | ␉␉␉␉break;␊ |
644 | ␉␉␉␉␊ |
645 | ␉␉␉␉␊ |
646 | ␉␉␉case REBASE_OPCODE_DO_REBASE_IMM_TIMES:␊ |
647 | ␉␉␉␉index = 0;␊ |
648 | ␉␉␉␉for (index = 0; index < immediate; ++index) {␊ |
649 | ␉␉␉␉␉rebase_location(base + segmentAddress, (char*)base, type);␊ |
650 | ␉␉␉␉␉segmentAddress += sizeof(void*);␊ |
651 | ␉␉␉␉}␊ |
652 | ␉␉␉␉break;␊ |
653 | ␉␉␉␉␊ |
654 | ␉␉␉␉␊ |
655 | ␉␉␉case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:␊ |
656 | ␉␉␉␉tmp = 0;␊ |
657 | ␉␉␉␉bits = 0;␊ |
658 | ␉␉␉␉do␊ |
659 | ␉␉␉␉{␊ |
660 | ␉␉␉␉␉tmp |= (rebase_stream[++i] & 0x7f) << bits;␊ |
661 | ␉␉␉␉␉bits += 7;␊ |
662 | ␉␉␉␉}␊ |
663 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
664 | ␉␉␉␉␊ |
665 | ␉␉␉␉index = 0;␊ |
666 | ␉␉␉␉for (index = 0; index < tmp; ++index) {␊ |
667 | ␉␉␉␉␉//DBG("\tRebasing 0x%X\n", segmentAddress);␊ |
668 | ␉␉␉␉␉rebase_location(base + segmentAddress, (char*)base, type);␉␉␉␉␉␊ |
669 | ␉␉␉␉␉segmentAddress += sizeof(void*);␊ |
670 | ␉␉␉␉}␊ |
671 | ␉␉␉␉break;␊ |
672 | ␉␉␉␉␊ |
673 | ␉␉␉case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:␊ |
674 | ␉␉␉␉tmp = 0;␊ |
675 | ␉␉␉␉bits = 0;␊ |
676 | ␉␉␉␉do␊ |
677 | ␉␉␉␉{␊ |
678 | ␉␉␉␉␉tmp |= (rebase_stream[++i] & 0x7f) << bits;␊ |
679 | ␉␉␉␉␉bits += 7;␊ |
680 | ␉␉␉␉}␊ |
681 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
682 | ␉␉␉␉␊ |
683 | ␉␉␉␉rebase_location(base + segmentAddress, (char*)base, type);␊ |
684 | ␉␉␉␉␊ |
685 | ␉␉␉␉segmentAddress += tmp + sizeof(void*);␊ |
686 | ␉␉␉␉break;␊ |
687 | ␉␉␉␉␊ |
688 | ␉␉␉case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:␊ |
689 | ␉␉␉␉tmp = 0;␊ |
690 | ␉␉␉␉bits = 0;␊ |
691 | ␉␉␉␉do␊ |
692 | ␉␉␉␉{␊ |
693 | ␉␉␉␉␉tmp |= (rebase_stream[++i] & 0x7f) << bits;␊ |
694 | ␉␉␉␉␉bits += 7;␊ |
695 | ␉␉␉␉}␊ |
696 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
697 | ␉␉␉␉␊ |
698 | ␉␉␉␉␊ |
699 | ␉␉␉␉tmp2 = 0;␊ |
700 | ␉␉␉␉bits = 0;␊ |
701 | ␉␉␉␉do␊ |
702 | ␉␉␉␉{␊ |
703 | ␉␉␉␉␉tmp2 |= (rebase_stream[++i] & 0x7f) << bits;␊ |
704 | ␉␉␉␉␉bits += 7;␊ |
705 | ␉␉␉␉}␊ |
706 | ␉␉␉␉while(rebase_stream[i] & 0x80);␊ |
707 | ␉␉␉␉␊ |
708 | ␉␉␉␉index = 0;␊ |
709 | ␉␉␉␉for (index = 0; index < tmp; ++index) {␊ |
710 | ␉␉␉␉␉␊ |
711 | ␉␉␉␉␉rebase_location(base + segmentAddress, (char*)base, type);␊ |
712 | ␉␉␉␉␉␊ |
713 | ␉␉␉␉␉segmentAddress += tmp2 + sizeof(void*);␊ |
714 | ␉␉␉␉}␊ |
715 | ␉␉␉␉break;␊ |
716 | ␉␉}␊ |
717 | ␉␉i++;␊ |
718 | ␉}␊ |
719 | }␊ |
720 | ␊ |
721 | inline void rebase_location(UInt32* location, char* base, int type)␊ |
722 | {␉␊ |
723 | ␉switch(type)␊ |
724 | ␉{␊ |
725 | ␉␉case REBASE_TYPE_POINTER:␊ |
726 | ␉␉case REBASE_TYPE_TEXT_ABSOLUTE32:␊ |
727 | ␉␉␉*location += (UInt32)base;␊ |
728 | ␉␉␉break;␊ |
729 | ␉␉␉␊ |
730 | ␉␉default:␊ |
731 | ␉␉␉break;␊ |
732 | ␉}␊ |
733 | }␊ |
734 | ␊ |
735 | ␊ |
736 | UInt32 read_uleb(UInt8* bind_stream, unsigned int* i)␊ |
737 | {␊ |
738 | // Read in offset␊ |
739 | UInt32 tmp = 0;␊ |
740 | UInt8 bits = 0;␊ |
741 | do␊ |
742 | {␊ |
743 | if(bits < sizeof(UInt32)*8) // hack␊ |
744 | {␊ |
745 | tmp |= (bind_stream[++(*i)] & 0x7f) << bits;␊ |
746 | bits += 7;␊ |
747 | }␊ |
748 | else␊ |
749 | {␊ |
750 | ++(*i);␊ |
751 | }␊ |
752 | }␊ |
753 | while(bind_stream[*i] & 0x80);␊ |
754 | return tmp;␊ |
755 | }␊ |
756 | ␊ |
757 | ␊ |
758 | // Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp␊ |
759 | // NOTE: this uses 32bit values, and not 64bit values. ␊ |
760 | // There is a possibility that this could cause issues,␊ |
761 | // however the modules are 32 bits, so it shouldn't matter too much␊ |
762 | void bind_macho(void* base, UInt8* bind_stream, UInt32 size)␊ |
763 | {␉␊ |
764 | ␉bind_stream += (UInt32)base;␊ |
765 | ␉␊ |
766 | ␉UInt8 immediate = 0;␊ |
767 | ␉UInt8 opcode = 0;␊ |
768 | ␉UInt8 type = BIND_TYPE_POINTER;␊ |
769 | ␉␊ |
770 | ␉UInt32 segmentAddress = 0;␊ |
771 | ␉␊ |
772 | ␉UInt32 address = 0;␊ |
773 | ␉␊ |
774 | ␉SInt32 addend = 0;␊ |
775 | ␉SInt32 libraryOrdinal = 0;␊ |
776 | ␉␊ |
777 | ␉const char* symbolName = NULL;␊ |
778 | ␉UInt8 symboFlags = 0;␊ |
779 | ␉UInt32 symbolAddr = 0xFFFFFFFF;␊ |
780 | ␉␊ |
781 | ␉// Temperary variables␊ |
782 | ␉UInt32 tmp = 0;␊ |
783 | ␉UInt32 tmp2 = 0;␊ |
784 | ␉UInt32 index = 0;␊ |
785 | ␉unsigned int i = 0;␊ |
786 | ␉␊ |
787 | ␉while(i < size)␊ |
788 | ␉{␊ |
789 | ␉␉immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;␊ |
790 | ␉␉opcode = bind_stream[i] & BIND_OPCODE_MASK;␊ |
791 | ␉␉␊ |
792 | ␉␉␊ |
793 | ␉␉switch(opcode)␊ |
794 | ␉␉{␊ |
795 | ␉␉␉case BIND_OPCODE_DONE:␊ |
796 | ␉␉␉␉// reset vars␊ |
797 | ␉␉␉␉type = BIND_TYPE_POINTER;␊ |
798 | ␉␉␉␉segmentAddress = 0;␊ |
799 | ␉␉␉␉address = 0;␊ |
800 | ␉␉␉␉addend = 0;␊ |
801 | ␉␉␉␉libraryOrdinal = 0;␊ |
802 | ␉␉␉␉symbolAddr = 0xFFFFFFFF;␊ |
803 | ␉␉␉default:␊ |
804 | ␉␉␉␉break;␊ |
805 | ␉␉␉␉␊ |
806 | ␉␉␉case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:␊ |
807 | ␉␉␉␉libraryOrdinal = immediate;␊ |
808 | ␉␉␉␉break;␊ |
809 | ␉␉␉␉␊ |
810 | ␉␉␉case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:␊ |
811 | ␉␉␉␉libraryOrdinal = read_uleb(bind_stream, &i);␊ |
812 | ␉␉␉␉break;␊ |
813 | ␉␉␉␉␊ |
814 | ␉␉␉case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:␊ |
815 | ␉␉␉␉libraryOrdinal = immediate ? (SInt8)(BIND_OPCODE_MASK | immediate) : immediate;␉␉␉␉␊ |
816 | ␉␉␉␉break;␊ |
817 | ␉␉␉␉␊ |
818 | ␉␉␉case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:␊ |
819 | ␉␉␉␉symboFlags = immediate;␊ |
820 | ␉␉␉␉symbolName = (char*)&bind_stream[++i];␊ |
821 | ␉␉␉␉i += strlen((char*)&bind_stream[i]);␊ |
822 | ␊ |
823 | ␉␉␉␉symbolAddr = lookup_all_symbols(symbolName);␊ |
824 | ␉␉␉␉break;␊ |
825 | ␉␉␉␉␊ |
826 | ␉␉␉case BIND_OPCODE_SET_TYPE_IMM:␊ |
827 | ␉␉␉␉type = immediate;␊ |
828 | ␉␉␉␉break;␊ |
829 | ␉␉␉␉␊ |
830 | ␉␉␉case BIND_OPCODE_SET_ADDEND_SLEB:␊ |
831 | ␉␉␉␉addend = read_uleb(bind_stream, &i);␉␉␉␉␊ |
832 | ␉␉␉␉if(!(bind_stream[i-1] & 0x40)) addend *= -1;␊ |
833 | ␉␉␉␉break;␊ |
834 | ␉␉␉␉␊ |
835 | ␉␉␉case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:␊ |
836 | ␉␉␉␉segmentAddress = 0;␊ |
837 | ␉␉␉␉␊ |
838 | ␉␉␉␉// Locate address␊ |
839 | ␉␉␉␉struct segment_command* segCommand = NULL;␉// NOTE: 32bit only␊ |
840 | ␉␉␉␉␊ |
841 | ␉␉␉␉unsigned int binIndex = 0;␊ |
842 | ␉␉␉␉index = 0;␊ |
843 | ␉␉␉␉do␊ |
844 | ␉␉␉␉{␊ |
845 | ␉␉␉␉␉segCommand = base + sizeof(struct mach_header) + binIndex;␊ |
846 | ␉␉␉␉␉binIndex += segCommand->cmdsize;␊ |
847 | ␉␉␉␉␉index++;␊ |
848 | ␉␉␉␉}␊ |
849 | ␉␉␉␉while(index <= immediate);␊ |
850 | ␉␉␉␉␊ |
851 | ␉␉␉␉segmentAddress = segCommand->fileoff;␊ |
852 | ␉␉␉␉␉␉␉␉␊ |
853 | ␉␉␉␉segmentAddress += read_uleb(bind_stream, &i);␊ |
854 | ␉␉␉␉break;␊ |
855 | ␉␉␉␉␊ |
856 | ␉␉␉case BIND_OPCODE_ADD_ADDR_ULEB:␊ |
857 | ␉␉␉␉segmentAddress += read_uleb(bind_stream, &i);␊ |
858 | ␉␉␉␉break;␊ |
859 | ␉␉␉␉␊ |
860 | ␉␉␉case BIND_OPCODE_DO_BIND:␊ |
861 | ␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
862 | ␉␉␉␉{␊ |
863 | ␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
864 | ␉␉␉␉␉␉␊ |
865 | ␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
866 | ␉␉␉␉}␊ |
867 | ␉␉␉␉else␊ |
868 | ␉␉␉␉{␊ |
869 | ␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
870 | ␉␉␉␉␉getchar();␊ |
871 | ␉␉␉␉}␊ |
872 | ␉␉␉␉␊ |
873 | ␉␉␉␉segmentAddress += sizeof(void*);␊ |
874 | ␉␉␉␉break;␊ |
875 | ␉␉␉␉␊ |
876 | ␉␉␉case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:␊ |
877 | ␉␉␉␉// Read in offset␊ |
878 | ␉␉␉␉tmp = read_uleb(bind_stream, &i);␊ |
879 | ␊ |
880 | ␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
881 | ␉␉␉␉{␊ |
882 | ␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
883 | ␉␉␉␉␉␊ |
884 | ␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
885 | ␉␉␉␉}␊ |
886 | ␉␉␉␉else␊ |
887 | ␉␉␉␉{␊ |
888 | ␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
889 | ␉␉␉␉␉getchar();␊ |
890 | ␉␉␉␉}␊ |
891 | ␊ |
892 | ␉␉␉␉segmentAddress += tmp + sizeof(void*);␊ |
893 | ␉␉␉␉␊ |
894 | ␉␉␉␉␊ |
895 | ␉␉␉␉break;␊ |
896 | ␉␉␉␉␊ |
897 | ␉␉␉case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:␊ |
898 | ␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
899 | ␉␉␉␉{␊ |
900 | ␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
901 | ␉␉␉␉␉␊ |
902 | ␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
903 | ␉␉␉␉}␊ |
904 | ␉␉␉␉else␊ |
905 | ␉␉␉␉{␊ |
906 | ␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
907 | ␉␉␉␉␉getchar();␊ |
908 | ␉␉␉␉}␊ |
909 | ␉␉␉␉segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);␊ |
910 | ␉␉␉␉␊ |
911 | ␉␉␉␉␊ |
912 | ␉␉␉␉break;␊ |
913 | ␉␉␉␉␊ |
914 | ␉␉␉case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:␊ |
915 | ␉␉␉␉tmp = read_uleb(bind_stream, &i);␉␉␉␉␊ |
916 | ␉␉␉␉␊ |
917 | ␉␉␉␉tmp2 = read_uleb(bind_stream, &i);␉␉␉␉␊ |
918 | ␉␉␉␉␊ |
919 | ␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
920 | ␉␉␉␉{␊ |
921 | ␉␉␉␉␉for(index = 0; index < tmp; index++)␊ |
922 | ␉␉␉␉␉{␊ |
923 | ␉␉␉␉␉␉␊ |
924 | ␉␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
925 | ␉␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
926 | ␉␉␉␉␉␉segmentAddress += tmp2 + sizeof(void*);␊ |
927 | ␉␉␉␉␉}␊ |
928 | ␉␉␉␉}␊ |
929 | ␉␉␉␉else␊ |
930 | ␉␉␉␉{␊ |
931 | ␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
932 | ␉␉␉␉␉getchar();␊ |
933 | ␉␉␉␉}␊ |
934 | ␉␉␉␉break;␊ |
935 | ␉␉}␊ |
936 | ␉␉i++;␊ |
937 | ␉}␊ |
938 | }␊ |
939 | ␊ |
940 | ␊ |
941 | inline void bind_location(UInt32* location, char* value, UInt32 addend, int type)␊ |
942 | {␉␊ |
943 | ␉// do actual update␊ |
944 | ␉char* newValue = value + addend;␊ |
945 | ␉␊ |
946 | ␉switch (type) {␊ |
947 | ␉␉case BIND_TYPE_POINTER:␊ |
948 | ␉␉case BIND_TYPE_TEXT_ABSOLUTE32:␊ |
949 | ␉␉␉break;␊ |
950 | ␉␉␉␊ |
951 | ␉␉case BIND_TYPE_TEXT_PCREL32:␊ |
952 | ␉␉␉newValue -= ((UInt32)location + 4);␊ |
953 | ␉␉␉␊ |
954 | ␉␉␉break;␊ |
955 | ␉␉default:␊ |
956 | ␉␉␉return;␊ |
957 | ␉}␊ |
958 | ␉//DBG("Binding 0x%X to 0x%X (was 0x%X)\n", location, newValue, *location);␊ |
959 | ␉*location = (UInt32)newValue;␊ |
960 | }␊ |
961 | ␊ |
962 | /********************************************************************************/␊ |
963 | /*␉Module Hook Interface␉␉␉␉␉␉␉␉␉␉␉␉␉␉*/␊ |
964 | /********************************************************************************/␊ |
965 | ␊ |
966 | /*␊ |
967 | * Locate the symbol for an already loaded function and modify the beginning of␊ |
968 | * the function to jump directly to the new one␊ |
969 | * example: replace_function("_HelloWorld_start", &replacement_start);␊ |
970 | */␊ |
971 | int replace_function(const char* symbol, void* newAddress)␊ |
972 | {␊ |
973 | ␉UInt32* jumpPointer = malloc(sizeof(UInt32*));␉ ␊ |
974 | ␉UInt32 addr = lookup_all_symbols(symbol);␊ |
975 | ␉␊ |
976 | ␉char* binary = (char*)addr;␊ |
977 | ␉if(addr != 0xFFFFFFFF)␊ |
978 | ␉{␊ |
979 | ␉␉//DBG("Replacing %s to point to 0x%x\n", symbol, newAddress);␊ |
980 | ␉␉*binary++ = 0xFF;␉// Jump␊ |
981 | ␉␉*binary++ = 0x25;␉// Long Jump␊ |
982 | ␉␉*((UInt32*)binary) = (UInt32)jumpPointer;␊ |
983 | ␉␉␊ |
984 | ␉␉*jumpPointer = (UInt32)newAddress;␊ |
985 | ␉␉return 1;␊ |
986 | ␉}␊ |
987 | ␉return 0;␊ |
988 | }␊ |
989 | ␊ |
990 | ␊ |
991 | /*␊ |
992 | *␉execute_hook( const char* name )␊ |
993 | *␉␉name - Name of the module hook␊ |
994 | *␉␉␉If any callbacks have been registered for this hook␊ |
995 | *␉␉␉they will be executed now in the same order that the␊ |
996 | *␉␉␉hooks were added.␊ |
997 | */␊ |
998 | int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)␊ |
999 | {␊ |
1000 | ␉DBG("Attempting to execute hook '%s'\n", name); DBGPAUSE();␊ |
1001 | ␉moduleHook_t* hook = hook_exists(name);␊ |
1002 | ␉␊ |
1003 | ␉if(hook)␊ |
1004 | ␉{␊ |
1005 | ␉␉// Loop through all callbacks for this module␊ |
1006 | ␉␉callbackList_t* callbacks = hook->callbacks;␊ |
1007 | ␊ |
1008 | ␉␉while(callbacks)␊ |
1009 | ␉␉{␊ |
1010 | ␉␉␉// Execute callback␊ |
1011 | ␉␉␉callbacks->callback(arg1, arg2, arg3, arg4);␊ |
1012 | ␉␉␉callbacks = callbacks->next;␊ |
1013 | ␉␉}␊ |
1014 | ␉␉DBG("Hook '%s' executed.\n", name); DBGPAUSE();␊ |
1015 | ␉␉return 1;␊ |
1016 | ␉}␊ |
1017 | ␉else␊ |
1018 | ␉{␊ |
1019 | ␉␉// Callback for this hook doesn't exist;␊ |
1020 | ␉␉DBG("No callbacks for '%s' hook.\n", name);␊ |
1021 | ␉␉return 0;␊ |
1022 | ␉}␊ |
1023 | }␊ |
1024 | ␊ |
1025 | ␊ |
1026 | ␊ |
1027 | /*␊ |
1028 | *␉register_hook_callback( const char* name, void(*callback)())␊ |
1029 | *␉␉name - Name of the module hook to attach to.␊ |
1030 | *␉␉callbacks - The funciton pointer that will be called when the␊ |
1031 | *␉␉␉hook is executed. When registering a new callback name, the callback is added sorted.␊ |
1032 | *␉␉␉NOTE: the hooks take four void* arguments.␊ |
1033 | */␊ |
1034 | void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))␊ |
1035 | {␉␊ |
1036 | ␉DBG("Adding callback for '%s' hook.\n", name); DBGPAUSE();␊ |
1037 | ␉␊ |
1038 | ␉moduleHook_t* hook = hook_exists(name);␊ |
1039 | ␉␊ |
1040 | ␉if(hook)␊ |
1041 | ␉{␊ |
1042 | ␉␉// append␊ |
1043 | ␉␉callbackList_t* newCallback = malloc(sizeof(callbackList_t));␊ |
1044 | ␉␉newCallback->next = hook->callbacks;␊ |
1045 | ␉␉hook->callbacks = newCallback;␊ |
1046 | ␉␉newCallback->callback = callback;␊ |
1047 | ␉}␊ |
1048 | ␉else␊ |
1049 | ␉{␊ |
1050 | ␉␉// create new hook␊ |
1051 | ␉␉moduleHook_t* newHook = malloc(sizeof(moduleHook_t));␉␉␊ |
1052 | ␉␉newHook->name = name;␊ |
1053 | ␉␉newHook->callbacks = malloc(sizeof(callbackList_t));␊ |
1054 | ␉␉newHook->callbacks->callback = callback;␊ |
1055 | ␉␉newHook->callbacks->next = NULL;␊ |
1056 | ␉␉␊ |
1057 | ␉␉newHook->next = moduleCallbacks;␊ |
1058 | ␉␉moduleCallbacks = newHook;␊ |
1059 | ␉␉␊ |
1060 | ␉}␊ |
1061 | ␉␊ |
1062 | #if CONFIG_MODULE_DEBUG␊ |
1063 | ␉//print_hook_list();␊ |
1064 | ␉//getchar();␊ |
1065 | #endif␊ |
1066 | ␉␊ |
1067 | }␊ |
1068 | ␊ |
1069 | ␊ |
1070 | moduleHook_t* hook_exists(const char* name)␊ |
1071 | {␊ |
1072 | ␉moduleHook_t* hooks = moduleCallbacks;␊ |
1073 | ␉␊ |
1074 | ␉// look for a hook. If it exists, return the moduleHook_t*,␊ |
1075 | ␉// If not, return NULL.␊ |
1076 | ␉while(hooks)␊ |
1077 | ␉{␊ |
1078 | ␉␉if(strcmp(name, hooks->name) == 0)␊ |
1079 | ␉␉{␊ |
1080 | ␉␉␉//DBG("Located hook %s\n", name);␊ |
1081 | ␉␉␉return hooks;␊ |
1082 | ␉␉}␊ |
1083 | ␉␉hooks = hooks->next;␊ |
1084 | ␉}␊ |
1085 | ␉//DBG("Hook %s does not exist\n", name);␊ |
1086 | ␉return NULL;␊ |
1087 | ␉␊ |
1088 | }␊ |
1089 | ␊ |
1090 | #if CONFIG_MODULE_DEBUG␊ |
1091 | void print_hook_list()␊ |
1092 | {␊ |
1093 | ␉printf("---Hook Table---\n");␊ |
1094 | ␉␊ |
1095 | ␉moduleHook_t* hooks = moduleCallbacks;␊ |
1096 | ␉while(hooks)␊ |
1097 | ␉{␊ |
1098 | ␉␉printf("Hook: %s\n", hooks->name);␊ |
1099 | ␉␉hooks = hooks->next;␊ |
1100 | ␉}␊ |
1101 | }␊ |
1102 | ␊ |
1103 | #endif␊ |
1104 | ␊ |
1105 | /********************************************************************************/␊ |
1106 | /*␉dyld / Linker Interface␉␉␉␉␉␉␉␉␉␉␉␉␉␉*/␊ |
1107 | /********************************************************************************/␊ |
1108 | ␊ |
1109 | void dyld_stub_binder()␊ |
1110 | {␊ |
1111 | ␉printf("ERROR: dyld_stub_binder was called, should have been take care of by the linker.\n");␊ |
1112 | ␉getchar();␊ |
1113 | }␊ |
1114 | ␊ |
1115 | #else /* CONFIG_MODULES */␊ |
1116 | ␊ |
1117 | int init_module_system()␊ |
1118 | {␊ |
1119 | return 0;␊ |
1120 | }␊ |
1121 | ␊ |
1122 | void load_all_modules()␊ |
1123 | {␊ |
1124 | ␊ |
1125 | }␊ |
1126 | ␊ |
1127 | int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)␊ |
1128 | {␊ |
1129 | return 0;␊ |
1130 | }␊ |
1131 | ␊ |
1132 | void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))␊ |
1133 | {␊ |
1134 | ␉printf("WARNING: register_hook_callback is not supported when compiled in.\n");␊ |
1135 | ␉pause();␊ |
1136 | }␊ |
1137 | ␊ |
1138 | int replace_function(const char* symbol, void* newAddress)␊ |
1139 | {␊ |
1140 | ␉printf("WARNING: replace_functions is not supported when compiled in.\n");␊ |
1141 | ␉pause();␊ |
1142 | ␉return 0;␊ |
1143 | }␊ |
1144 | ␊ |
1145 | void start_built_in_module(const char* name, ␊ |
1146 | const char* author, ␊ |
1147 | const char* description,␊ |
1148 | UInt32 version,␊ |
1149 | UInt32 compat,␊ |
1150 | void(*start_function)(void))␊ |
1151 | {␊ |
1152 | start_function();␊ |
1153 | }␊ |
1154 | ␊ |
1155 | #endif |