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

Archive Download this file

Revision: 2253