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

Archive Download this file

Revision: 2411