Chameleon

Chameleon Svn Source Tree

Root/tags/2.1/i386/boot2/modules.c

Source at commit 2381 created 10 years 21 days ago.
By ifabio, Apply patch: (Credits to Thomas Jansen aka tja) - Reading options from all devices during boot. The options for the boot menu are only read from the devices rd(0,0) or bt(0,0). Consequently, boot menu options (e.g. "Quiet Boot", "Timeout", etc.) in plists on other devices (like most users have) are ignored. This patch extends the list of paths to search for the options plist on all devices that can be found.
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
25// NOTE: Global so that modules can link with this
26static UInt64 textAddress = 0;
27static UInt64 textSection = 0;
28
29/** Internal symbols, however there are accessor methods **/
30moduleHook_t* moduleCallbacks = NULL;
31moduleList_t* loadedModules = NULL;
32symbolList_t* moduleSymbols = NULL;
33unsigned int (*lookup_symbol)(const char*) = NULL;
34
35
36/*
37 * Initialize the module system by loading the Symbols.dylib module.
38 * Once loaded, locate the _lookup_symbol function so that internal
39 * symbols can be resolved.
40 */
41int init_module_system()
42{
43 // Start any modules that were compiled in first.
44 start_built_in_modules();
45
46
47int retVal = 0;
48void (*module_start)(void) = NULL;
49
50extern char symbols_start __asm("section$start$__DATA$__Symbols");
51char* module_data = &symbols_start;
52
53// Intialize module system
54if(module_data)
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(*module_start)();// Start the module. This will point to load_all_modules due to the way the dylib was constructed.
64execute_hook("ModulesLoaded", NULL, NULL, NULL, NULL);
65DBG("Module %s Loaded.\n", SYMBOLS_MODULE);
66retVal = 1;
67
68}
69else
70{
71// The module does not have a valid start function
72printf("Unable to start %s at 0x%x\n", SYMBOLS_MODULE, module_data); pause();
73}
74}
75return retVal;
76}
77
78void start_built_in_module(const char* name,
79 const char* author,
80 const char* description,
81 UInt32 version,
82 UInt32 compat,
83 void(*start_function)(void))
84{
85 start_function();
86 // Notify the module system that this module really exists, specificaly, let other module link with it
87 module_loaded(name, author, description, version, compat);
88}
89
90/*
91 * Load all modules in the /Extra/modules/ directory
92 * Module depencdies will be loaded first
93 * Modules will only be loaded once. When loaded a module must
94 * setup apropriete function calls and hooks as required.
95 * NOTE: To ensure a module loads after another you may
96 * link one module with the other. For dyld to allow this, you must
97 * reference at least one symbol within the module.
98 */
99void load_all_modules()
100{
101char* name;
102long flags;
103long time;
104struct dirstuff* moduleDir = opendir("/Extra/modules/");
105while(readdir(moduleDir, (const char**)&name, &flags, &time) >= 0)
106{
107if(strcmp(&name[strlen(name) - sizeof("dylib")], ".dylib") == 0)
108{
109char* tmp = malloc(strlen(name) + 1);
110strcpy(tmp, name);
111
112if(!load_module(tmp))
113{
114// failed to load
115// free(tmp);
116}
117}
118else
119{
120DBG("Ignoring %s\n", name);
121}
122
123}
124}
125
126
127/*
128 * Load a module file in /Extra/modules/
129 */
130int load_module(char* module)
131{
132int retVal = 1;
133void (*module_start)(void) = NULL;
134char modString[128];
135int fh = -1;
136
137// Check to see if the module has already been loaded
138if(is_module_loaded(module))
139{
140return 1;
141}
142
143sprintf(modString, MODULE_PATH "%s", module);
144fh = open(modString, 0);
145if(fh < 0)
146{
147DBG("WARNING: Unable to locate module %s\n", modString); DBGPAUSE();
148return 0;
149}
150
151unsigned int moduleSize = file_size(fh);
152char* module_base = (char*) malloc(moduleSize);
153if (moduleSize && read(fh, module_base, moduleSize) == moduleSize)
154{
155// Module loaded into memory, parse it
156module_start = parse_mach(module_base, &load_module, &add_symbol, NULL);
157
158if(module_start && module_start != (void*)0xFFFFFFFF)
159{
160// Notify the system that it was laoded
161module_loaded(module, NULL, NULL, 0, 0 /*moduleName, NULL, moduleVersion, moduleCompat*/);
162(*module_start)();// Start the module
163DBG("Module %s Loaded.\n", module); DBGPAUSE();
164}
165#if CONFIG_MODULE_DEBUG
166else // The module does not have a valid start function. This may be a library.
167{
168printf("WARNING: Unable to start %s\n", module);
169getchar();
170}
171#else
172else msglog("WARNING: Unable to start %s\n", module);
173#endif
174}
175else
176{
177DBG("Unable to read in module %s\n.", module); DBGPAUSE();
178retVal = 0;
179}
180
181close(fh);
182return retVal;
183}
184
185/*
186 * add_symbol
187 * This function adds a symbol from a module to the list of known symbols
188 * possibly change to a pointer and add this to the Symbol module so that it can
189 * adjust it's internal symbol list (sort) to optimize locating new symbols
190 * NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF
191 */
192long long add_symbol(char* symbol, long long addr, char is64)
193{
194// This only can handle 32bit symbols
195symbolList_t* entry;
196//DBG("Adding symbol %s at 0x%X\n", symbol, addr);
197
198entry = malloc(sizeof(symbolList_t));
199entry->next = moduleSymbols;
200moduleSymbols = entry;
201
202entry->addr = (UInt32)addr;
203entry->symbol = symbol;
204
205if(!is64 && strcmp(symbol, "start") == 0)
206{
207return addr;
208}
209else
210{
211return 0xFFFFFFFF; // fixme
212}
213}
214
215
216/*
217 * print out the information about the loaded module
218 */
219void module_loaded(const char* name, const char* author, const char* description, UInt32 version, UInt32 compat)
220{
221moduleList_t* new_entry = malloc(sizeof(moduleList_t));
222new_entry->next = loadedModules;
223
224loadedModules = new_entry;
225
226 if(!name) name = "Unknown";
227 if(!author) author = "Unknown";
228 if(!description) description = "";
229
230new_entry->name = name;
231 new_entry->author = author;
232 new_entry->description = description;
233new_entry->version = version;
234 new_entry->compat = compat;
235
236 msglog("Module '%s' by '%s' Loaded.\n", name, author);
237 msglog("\tDescription: %s\n", description);
238 msglog("\tVersion: %d\n", version); // todo: sperate to major.minor.bugfix
239 msglog("\tCompat: %d\n", compat); // todo: ^^^ major.minor.bugfix
240}
241
242int is_module_loaded(const char* name)
243{
244// todo sorted search
245moduleList_t* entry = loadedModules;
246while(entry)
247{
248if(strcmp(entry->name, name) == 0)
249{
250DBG("Located module %s\n", name); DBGPAUSE();
251return 1;
252}
253else
254{
255entry = entry->next;
256}
257
258}
259
260DBG("Module %s not loaded\n", name); DBGPAUSE();
261return 0;
262}
263
264/*
265 *lookup symbols in all loaded modules. Thins inludes boot syms due to Symbols.dylib construction
266 *
267 */
268unsigned int lookup_all_symbols(const char* name)
269{
270symbolList_t* entry = moduleSymbols;
271while(entry)
272{
273if(strcmp(entry->symbol, name) == 0)
274{
275//DBG("External symbol %s located at 0x%X\n", name, entry->addr);
276return entry->addr;
277}
278else
279{
280entry = entry->next;
281}
282}
283
284#if CONFIG_MODULE_DEBUG
285printf("Unable to locate symbol %s\n", name);
286getchar();
287#endif
288
289if(strcmp(name, VOID_SYMBOL) == 0) return 0xFFFFFFFF;
290// In the event that a symbol does not exist
291// Return a pointer to a void function.
292else return lookup_all_symbols(VOID_SYMBOL);
293}
294
295/********************************************************************************/
296/*Macho Parser*/
297/********************************************************************************/
298
299/*
300 * Parse through a macho module. The module will be rebased and binded
301 * as specified in the macho header. If the module is sucessfuly laoded
302 * the module iinit address will be returned.
303 * NOTE; all dependecies will be loaded before this module is started
304 * NOTE: If the module is unable to load ot completeion, the modules
305 * symbols will still be available.
306 */
307void* parse_mach(void* binary,
308 int(*dylib_loader)(char*),
309 long long(*symbol_handler)(char*, long long, char),
310 void (*section_handler)(char* section, char* segment, void* cmd, UInt64 offset, UInt64 address)
311)
312{
313char is64 = false;
314void (*module_start)(void) = NULL;
315
316// Module info
317/*char* moduleName = NULL;
318 UInt32 moduleVersion = 0;
319 UInt32 moduleCompat = 0;
320 */
321// TODO convert all of the structs to a union
322struct load_command *loadCommand = NULL;
323struct dylib_command* dylibCommand = NULL;
324struct dyld_info_command* dyldInfoCommand = NULL;
325
326struct symtab_command* symtabCommand = NULL;
327struct segment_command *segCommand = NULL;
328struct segment_command_64 *segCommand64 = NULL;
329
330//struct dysymtab_command* dysymtabCommand = NULL;
331UInt32 binaryIndex = 0;
332UInt16 cmd = 0;
333
334textSection = 0;
335textAddress = 0;// reinitialize text location in case it doesn't exist;
336
337// Parse through the load commands
338if(((struct mach_header*)binary)->magic == MH_MAGIC)
339{
340is64 = false;
341binaryIndex += sizeof(struct mach_header);
342}
343else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
344{
345// NOTE: modules cannot be 64bit. This is used to parse the kernel and kexts
346is64 = true;
347binaryIndex += sizeof(struct mach_header_64);
348}
349else
350{
351verbose("Invalid mach magic 0x%X\n", ((struct mach_header*)binary)->magic);
352return NULL;
353}
354
355
356
357/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
358 {
359 printf("Module is not a dylib. Unable to load.\n");
360 getchar();
361 return NULL; // Module is in the incorrect format
362 }*/
363
364while(cmd < ((struct mach_header*)binary)->ncmds)
365{
366cmd++;
367
368loadCommand = binary + binaryIndex;
369UInt32 cmdSize = loadCommand->cmdsize;
370
371
372switch ((loadCommand->cmd & 0x7FFFFFFF))
373{
374case LC_SYMTAB:
375symtabCommand = binary + binaryIndex;
376break;
377
378case LC_SEGMENT: // 32bit macho
379 {
380 segCommand = binary + binaryIndex;
381
382 UInt32 sectionIndex;
383
384 sectionIndex = sizeof(struct segment_command);
385
386 struct section *sect;
387
388 while(sectionIndex < segCommand->cmdsize)
389 {
390 sect = binary + binaryIndex + sectionIndex;
391
392 sectionIndex += sizeof(struct section);
393
394 if(section_handler) section_handler(sect->sectname, segCommand->segname, (void*)sect, sect->offset, sect->addr);
395
396if((strcmp("__TEXT", segCommand->segname) == 0) && (strcmp("__text", sect->sectname) == 0))
397 {
398 // __TEXT,__text found, save the offset and address for when looking for the calls.
399 textSection = sect->offset;
400 textAddress = sect->addr;
401 }
402 }
403 }
404break;
405case LC_SEGMENT_64:// 64bit macho's
406 {
407 segCommand64 = binary + binaryIndex;
408 UInt32 sectionIndex;
409
410 sectionIndex = sizeof(struct segment_command_64);
411
412 struct section_64 *sect;
413
414 while(sectionIndex < segCommand64->cmdsize)
415 {
416 sect = binary + binaryIndex + sectionIndex;
417
418 sectionIndex += sizeof(struct section_64);
419
420 if(section_handler) section_handler(sect->sectname, segCommand64->segname, (void*)sect, sect->offset, sect->addr);
421
422 if((strcmp("__TEXT", segCommand64->segname) == 0) && (strcmp("__text", sect->sectname) == 0))
423 {
424 // __TEXT,__text found, save the offset and address for when looking for the calls.
425 textSection = sect->offset;
426 textAddress = sect->addr;
427 }
428 }
429}
430break;
431
432
433case LC_LOAD_DYLIB:
434case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
435 // Required modules
436dylibCommand = binary + binaryIndex;
437char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
438// Possible enhancments: verify version
439// =dylibCommand->dylib.current_version;
440// =dylibCommand->dylib.compatibility_version;
441if(dylib_loader)
442{
443char* name = malloc(strlen(module) + strlen(".dylib") + 1);
444sprintf(name, "%s.dylib", module);
445
446if (!dylib_loader(name))
447{
448// NOTE: any symbols exported by dep will be replace with the void function
449free(name);
450}
451}
452
453break;
454
455case LC_ID_DYLIB:
456//dylibCommand = binary + binaryIndex;
457/*moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
458 moduleVersion =dylibCommand->dylib.current_version;
459 moduleCompat =dylibCommand->dylib.compatibility_version;
460 */
461break;
462
463case LC_DYLD_INFO:
464//case LC_DYLD_INFO_ONLY:// compressed info, 10.6+ macho files, already handeled
465// Bind and rebase info is stored here
466dyldInfoCommand = binary + binaryIndex;
467break;
468
469case LC_DYSYMTAB:
470case LC_UUID:
471case LC_UNIXTHREAD:
472break;
473
474default:
475DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
476break;
477
478}
479
480binaryIndex += cmdSize;
481}
482
483// bind_macho uses the symbols, if the textAdd does not exist (Symbols.dylib, no code), addresses are static and not relative
484module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);
485
486if(dyldInfoCommand)
487{
488// Rebase the module before binding it.
489if(dyldInfoCommand->rebase_off)rebase_macho(binary, (char*)dyldInfoCommand->rebase_off,dyldInfoCommand->rebase_size);
490// Bind all symbols.
491if(dyldInfoCommand->bind_off)bind_macho(binary, (UInt8*)dyldInfoCommand->bind_off,dyldInfoCommand->bind_size);
492if(dyldInfoCommand->weak_bind_off)bind_macho(binary, (UInt8*)dyldInfoCommand->weak_bind_off,dyldInfoCommand->weak_bind_size);
493if(dyldInfoCommand->lazy_bind_off)bind_macho(binary, (UInt8*)dyldInfoCommand->lazy_bind_off,dyldInfoCommand->lazy_bind_size);
494}
495
496return module_start;
497
498}
499
500/*
501 * parse the symbol table
502 * Lookup any undefined symbols
503 */
504
505unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)
506{
507unsigned int module_start= 0xFFFFFFFF;
508UInt32 symbolIndex= 0;
509char* symbolString= base + (char*)symtabCommand->stroff;
510
511if(!is64)
512{
513struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
514while(symbolIndex < symtabCommand->nsyms)
515{
516// If the symbol is exported by this module
517if(symbolEntry->n_value &&
518 symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)
519{
520
521// Module start located. Start is an alias so don't register it
522module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;
523}
524
525symbolEntry++;
526symbolIndex++;// TODO remove
527}
528}
529else
530{
531struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
532// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now, verify later)
533while(symbolIndex < symtabCommand->nsyms)
534{
535
536
537// If the symbol is exported by this module
538if(symbolEntry->n_value &&
539 symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)
540{
541
542// Module start located. Start is an alias so don't register it
543module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;
544}
545
546symbolEntry++;
547symbolIndex++;// TODO remove
548}
549}
550return module_start;
551}
552
553// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
554void rebase_macho(void* base, char* rebase_stream, UInt32 size)
555{
556rebase_stream += (UInt32)base;
557
558UInt8 immediate = 0;
559UInt8 opcode = 0;
560UInt8 type = 0;
561UInt32 segmentAddress = 0;
562
563
564UInt32 tmp = 0;
565UInt32 tmp2 = 0;
566UInt8 bits = 0;
567int index = 0;
568unsigned int i = 0;
569
570while(i < size)
571{
572immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
573opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
574
575
576switch(opcode)
577{
578case REBASE_OPCODE_DONE:
579// Rebase complete, reset vars
580immediate = 0;
581opcode = 0;
582type = 0;
583segmentAddress = 0;
584default:
585break;
586
587
588case REBASE_OPCODE_SET_TYPE_IMM:
589type = immediate;
590break;
591
592
593case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
594// Locate address to begin rebasing
595segmentAddress = 0;
596struct segment_command* segCommand = NULL; // NOTE: 32bit only
597
598unsigned int binIndex = 0;
599index = 0;
600do
601{
602segCommand = base + sizeof(struct mach_header) + binIndex;
603
604
605binIndex += segCommand->cmdsize;
606index++;
607}
608while(index <= immediate);
609
610
611segmentAddress = segCommand->fileoff;
612
613tmp = 0;
614bits = 0;
615do
616{
617tmp |= (rebase_stream[++i] & 0x7f) << bits;
618bits += 7;
619}
620while(rebase_stream[i] & 0x80);
621
622segmentAddress += tmp;
623break;
624
625
626case REBASE_OPCODE_ADD_ADDR_ULEB:
627// Add value to rebase address
628tmp = 0;
629bits = 0;
630do
631{
632tmp <<= bits;
633tmp |= rebase_stream[++i] & 0x7f;
634bits += 7;
635}
636while(rebase_stream[i] & 0x80);
637
638segmentAddress +=tmp;
639break;
640
641case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
642segmentAddress += immediate * sizeof(void*);
643break;
644
645
646case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
647index = 0;
648for (index = 0; index < immediate; ++index) {
649rebase_location(base + segmentAddress, (char*)base, type);
650segmentAddress += sizeof(void*);
651}
652break;
653
654
655case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
656tmp = 0;
657bits = 0;
658do
659{
660tmp |= (rebase_stream[++i] & 0x7f) << bits;
661bits += 7;
662}
663while(rebase_stream[i] & 0x80);
664
665index = 0;
666for (index = 0; index < tmp; ++index) {
667//DBG("\tRebasing 0x%X\n", segmentAddress);
668rebase_location(base + segmentAddress, (char*)base, type);
669segmentAddress += sizeof(void*);
670}
671break;
672
673case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
674tmp = 0;
675bits = 0;
676do
677{
678tmp |= (rebase_stream[++i] & 0x7f) << bits;
679bits += 7;
680}
681while(rebase_stream[i] & 0x80);
682
683rebase_location(base + segmentAddress, (char*)base, type);
684
685segmentAddress += tmp + sizeof(void*);
686break;
687
688case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
689tmp = 0;
690bits = 0;
691do
692{
693tmp |= (rebase_stream[++i] & 0x7f) << bits;
694bits += 7;
695}
696while(rebase_stream[i] & 0x80);
697
698
699tmp2 = 0;
700bits = 0;
701do
702{
703tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
704bits += 7;
705}
706while(rebase_stream[i] & 0x80);
707
708index = 0;
709for (index = 0; index < tmp; ++index) {
710
711rebase_location(base + segmentAddress, (char*)base, type);
712
713segmentAddress += tmp2 + sizeof(void*);
714}
715break;
716}
717i++;
718}
719}
720
721inline void rebase_location(UInt32* location, char* base, int type)
722{
723switch(type)
724{
725case REBASE_TYPE_POINTER:
726case REBASE_TYPE_TEXT_ABSOLUTE32:
727*location += (UInt32)base;
728break;
729
730default:
731break;
732}
733}
734
735
736UInt32 read_uleb(UInt8* bind_stream, unsigned int* i)
737{
738 // Read in offset
739 UInt32 tmp = 0;
740 UInt8 bits = 0;
741 do
742 {
743 if(bits < sizeof(UInt32)*8) // hack
744 {
745 tmp |= (bind_stream[++(*i)] & 0x7f) << bits;
746 bits += 7;
747 }
748 else
749 {
750 ++(*i);
751 }
752 }
753 while(bind_stream[*i] & 0x80);
754 return tmp;
755}
756
757
758// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
759// NOTE: this uses 32bit values, and not 64bit values.
760// There is a possibility that this could cause issues,
761// however the modules are 32 bits, so it shouldn't matter too much
762void bind_macho(void* base, UInt8* bind_stream, UInt32 size)
763{
764bind_stream += (UInt32)base;
765
766UInt8 immediate = 0;
767UInt8 opcode = 0;
768UInt8 type = BIND_TYPE_POINTER;
769
770UInt32 segmentAddress = 0;
771
772UInt32 address = 0;
773
774SInt32 addend = 0;
775SInt32 libraryOrdinal = 0;
776
777const char* symbolName = NULL;
778UInt8 symboFlags = 0;
779UInt32 symbolAddr = 0xFFFFFFFF;
780
781// Temperary variables
782UInt32 tmp = 0;
783UInt32 tmp2 = 0;
784UInt32 index = 0;
785unsigned int i = 0;
786
787while(i < size)
788{
789immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
790opcode = bind_stream[i] & BIND_OPCODE_MASK;
791
792
793switch(opcode)
794{
795case BIND_OPCODE_DONE:
796// reset vars
797type = BIND_TYPE_POINTER;
798segmentAddress = 0;
799address = 0;
800addend = 0;
801libraryOrdinal = 0;
802symbolAddr = 0xFFFFFFFF;
803default:
804break;
805
806case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
807libraryOrdinal = immediate;
808break;
809
810case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
811libraryOrdinal = read_uleb(bind_stream, &i);
812break;
813
814case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
815libraryOrdinal = immediate ? (SInt8)(BIND_OPCODE_MASK | immediate) : immediate;
816break;
817
818case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
819symboFlags = immediate;
820symbolName = (char*)&bind_stream[++i];
821i += strlen((char*)&bind_stream[i]);
822
823symbolAddr = lookup_all_symbols(symbolName);
824break;
825
826case BIND_OPCODE_SET_TYPE_IMM:
827type = immediate;
828break;
829
830case BIND_OPCODE_SET_ADDEND_SLEB:
831addend = read_uleb(bind_stream, &i);
832if(!(bind_stream[i-1] & 0x40)) addend *= -1;
833break;
834
835case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
836segmentAddress = 0;
837
838// Locate address
839struct segment_command* segCommand = NULL;// NOTE: 32bit only
840
841unsigned int binIndex = 0;
842index = 0;
843do
844{
845segCommand = base + sizeof(struct mach_header) + binIndex;
846binIndex += segCommand->cmdsize;
847index++;
848}
849while(index <= immediate);
850
851segmentAddress = segCommand->fileoff;
852
853segmentAddress += read_uleb(bind_stream, &i);
854break;
855
856case BIND_OPCODE_ADD_ADDR_ULEB:
857segmentAddress += read_uleb(bind_stream, &i);
858break;
859
860case BIND_OPCODE_DO_BIND:
861if(symbolAddr != 0xFFFFFFFF)
862{
863address = segmentAddress + (UInt32)base;
864
865bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
866}
867else
868{
869printf("Unable to bind symbol %s\n", symbolName);
870getchar();
871}
872
873segmentAddress += sizeof(void*);
874break;
875
876case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
877// Read in offset
878tmp = read_uleb(bind_stream, &i);
879
880if(symbolAddr != 0xFFFFFFFF)
881{
882address = segmentAddress + (UInt32)base;
883
884bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
885}
886else
887{
888printf("Unable to bind symbol %s\n", symbolName);
889getchar();
890}
891
892segmentAddress += tmp + sizeof(void*);
893
894
895break;
896
897case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
898if(symbolAddr != 0xFFFFFFFF)
899{
900address = segmentAddress + (UInt32)base;
901
902bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
903}
904else
905{
906printf("Unable to bind symbol %s\n", symbolName);
907getchar();
908}
909segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
910
911
912break;
913
914case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
915tmp = read_uleb(bind_stream, &i);
916
917tmp2 = read_uleb(bind_stream, &i);
918
919if(symbolAddr != 0xFFFFFFFF)
920{
921for(index = 0; index < tmp; index++)
922{
923
924address = segmentAddress + (UInt32)base;
925bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
926segmentAddress += tmp2 + sizeof(void*);
927}
928}
929else
930{
931printf("Unable to bind symbol %s\n", symbolName);
932getchar();
933}
934break;
935}
936i++;
937}
938}
939
940
941inline void bind_location(UInt32* location, char* value, UInt32 addend, int type)
942{
943// do actual update
944char* newValue = value + addend;
945
946switch (type) {
947case BIND_TYPE_POINTER:
948case BIND_TYPE_TEXT_ABSOLUTE32:
949break;
950
951case BIND_TYPE_TEXT_PCREL32:
952newValue -= ((UInt32)location + 4);
953
954break;
955default:
956return;
957}
958//DBG("Binding 0x%X to 0x%X (was 0x%X)\n", location, newValue, *location);
959*location = (UInt32)newValue;
960}
961
962/********************************************************************************/
963/*Module Hook Interface*/
964/********************************************************************************/
965
966/*
967* Locate the symbol for an already loaded function and modify the beginning of
968* the function to jump directly to the new one
969* example: replace_function("_HelloWorld_start", &replacement_start);
970*/
971int replace_function(const char* symbol, void* newAddress)
972{
973UInt32* jumpPointer = malloc(sizeof(UInt32*));
974UInt32 addr = lookup_all_symbols(symbol);
975
976char* binary = (char*)addr;
977if(addr != 0xFFFFFFFF)
978{
979//DBG("Replacing %s to point to 0x%x\n", symbol, newAddress);
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

Archive Download this file

Revision: 2381