Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/Chazi/i386/boot2/modules.c

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

Archive Download this file

Revision: 1047