Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1147