Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/boot2/modules.c

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

Archive Download this file

Revision: 2482