Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/boot2/modules.c

1/*
2 * Copyright 2010 Evan Lojewski. All rights reserved.
3 *
4 */
5#include "boot.h"
6#include "bootstruct.h"
7#include "modules.h"
8#include "boot_modules.h"
9#include <vers.h>
10
11#ifdef CONFIG_MODULES
12#ifndef CONFIG_MODULE_DEBUG
13#define CONFIG_MODULE_DEBUG 0
14#endif
15
16
17#if CONFIG_MODULE_DEBUG
18#define DBG(x...)printf(x);
19#define DBGPAUSE()getchar()
20#else
21#define DBG(x...)
22#define DBGPAUSE()
23#endif
24
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: 2101