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

Archive Download this file

Revision: 2266