Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2329