Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2469