Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2457