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
26UInt64 textAddress = 0;
27UInt64 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, long long offset, long long 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...
346is64 = true;
347binaryIndex += sizeof(struct mach_header_64);
348}
349else
350{
351verbose("Invalid mach magic 0x%X\n", ((struct mach_header*)binary)->magic);
352//getchar();
353return NULL;
354}
355
356
357
358/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
359 {
360 printf("Module is not a dylib. Unable to load.\n");
361 getchar();
362 return NULL; // Module is in the incorrect format
363 }*/
364
365while(cmd < ((struct mach_header*)binary)->ncmds)
366{
367cmd++;
368
369loadCommand = binary + binaryIndex;
370UInt32 cmdSize = loadCommand->cmdsize;
371
372
373switch ((loadCommand->cmd & 0x7FFFFFFF))
374{
375case LC_SYMTAB:
376symtabCommand = binary + binaryIndex;
377break;
378
379case LC_SEGMENT: // 32bit macho
380 {
381 segCommand = binary + binaryIndex;
382
383 UInt32 sectionIndex;
384
385 sectionIndex = sizeof(struct segment_command);
386
387 struct section *sect;
388
389 while(sectionIndex < segCommand->cmdsize)
390 {
391 sect = binary + binaryIndex + sectionIndex;
392
393 sectionIndex += sizeof(struct section);
394
395 if(section_handler) section_handler(sect->sectname, segCommand->segname, sect->offset, sect->addr);
396
397
398
399 if((strcmp("__TEXT", segCommand->segname) == 0) && (strcmp("__text", sect->sectname) == 0))
400 {
401 // __TEXT,__text found, save the offset and address for when looking for the calls.
402 textSection = sect->offset;
403 textAddress = sect->addr;
404 }
405 }
406 }
407break;
408case LC_SEGMENT_64:// 64bit macho's
409 {
410 segCommand64 = binary + binaryIndex;
411 UInt32 sectionIndex;
412
413 sectionIndex = sizeof(struct segment_command_64);
414
415 struct section_64 *sect;
416
417 while(sectionIndex < segCommand64->cmdsize)
418 {
419 sect = binary + binaryIndex + sectionIndex;
420
421 sectionIndex += sizeof(struct section_64);
422
423 if(section_handler) section_handler(sect->sectname, segCommand->segname, sect->offset, sect->addr);
424
425
426 if((strcmp("__TEXT", segCommand->segname) == 0) && (strcmp("__text", sect->sectname) == 0))
427 {
428 // __TEXT,__text found, save the offset and address for when looking for the calls.
429 textSection = sect->offset;
430 textAddress = sect->addr;
431 }
432 }
433}
434break;
435
436
437case LC_LOAD_DYLIB:
438case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
439 // Required modules
440dylibCommand = binary + binaryIndex;
441char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
442// Possible enhancments: verify version
443// =dylibCommand->dylib.current_version;
444// =dylibCommand->dylib.compatibility_version;
445if(dylib_loader)
446{
447char* name = malloc(strlen(module) + strlen(".dylib") + 1);
448sprintf(name, "%s.dylib", module);
449
450if (!dylib_loader(name))
451{
452// NOTE: any symbols exported by dep will be replace with the void function
453free(name);
454}
455}
456
457break;
458
459case LC_ID_DYLIB:
460//dylibCommand = binary + binaryIndex;
461/*moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
462 moduleVersion =dylibCommand->dylib.current_version;
463 moduleCompat =dylibCommand->dylib.compatibility_version;
464 */
465break;
466
467case LC_DYLD_INFO:
468//case LC_DYLD_INFO_ONLY:// compressed info, 10.6+ macho files, already handeled
469// Bind and rebase info is stored here
470dyldInfoCommand = binary + binaryIndex;
471break;
472
473case LC_DYSYMTAB:
474case LC_UUID:
475case LC_UNIXTHREAD:
476break;
477
478default:
479DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
480break;
481
482}
483
484binaryIndex += cmdSize;
485}
486
487// bind_macho uses the symbols, if the textAdd does not exist (Symbols.dylib, no code), addresses are static and not relative
488module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);
489
490if(dyldInfoCommand)
491{
492// Rebase the module before binding it.
493if(dyldInfoCommand->rebase_off)rebase_macho(binary, (char*)dyldInfoCommand->rebase_off,dyldInfoCommand->rebase_size);
494// Bind all symbols.
495if(dyldInfoCommand->bind_off)bind_macho(binary, (UInt8*)dyldInfoCommand->bind_off,dyldInfoCommand->bind_size);
496if(dyldInfoCommand->weak_bind_off)bind_macho(binary, (UInt8*)dyldInfoCommand->weak_bind_off,dyldInfoCommand->weak_bind_size);
497if(dyldInfoCommand->lazy_bind_off)bind_macho(binary, (UInt8*)dyldInfoCommand->lazy_bind_off,dyldInfoCommand->lazy_bind_size);
498}
499
500return module_start;
501
502}
503
504/*
505 * parse the symbol table
506 * Lookup any undefined symbols
507 */
508
509unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)
510{
511unsigned int module_start= 0xFFFFFFFF;
512UInt32 symbolIndex= 0;
513char* symbolString= base + (char*)symtabCommand->stroff;
514
515if(!is64)
516{
517struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
518while(symbolIndex < symtabCommand->nsyms)
519{
520// If the symbol is exported by this module
521if(symbolEntry->n_value &&
522 symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)
523{
524
525// Module start located. Start is an alias so don't register it
526module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;
527}
528
529symbolEntry++;
530symbolIndex++;// TODO remove
531}
532}
533else
534{
535struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
536// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now, verify later)
537while(symbolIndex < symtabCommand->nsyms)
538{
539
540
541// If the symbol is exported by this module
542if(symbolEntry->n_value &&
543 symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)
544{
545
546// Module start located. Start is an alias so don't register it
547module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;
548}
549
550symbolEntry++;
551symbolIndex++;// TODO remove
552}
553}
554return module_start;
555}
556
557// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
558void rebase_macho(void* base, char* rebase_stream, UInt32 size)
559{
560rebase_stream += (UInt32)base;
561
562UInt8 immediate = 0;
563UInt8 opcode = 0;
564UInt8 type = 0;
565UInt32 segmentAddress = 0;
566
567
568UInt32 tmp = 0;
569UInt32 tmp2 = 0;
570UInt8 bits = 0;
571int index = 0;
572unsigned int i = 0;
573
574while(i < size)
575{
576immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
577opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
578
579
580switch(opcode)
581{
582case REBASE_OPCODE_DONE:
583// Rebase complete, reset vars
584immediate = 0;
585opcode = 0;
586type = 0;
587segmentAddress = 0;
588default:
589break;
590
591
592case REBASE_OPCODE_SET_TYPE_IMM:
593type = immediate;
594break;
595
596
597case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
598// Locate address to begin rebasing
599segmentAddress = 0;
600struct segment_command* segCommand = NULL; // NOTE: 32bit only
601
602unsigned int binIndex = 0;
603index = 0;
604do
605{
606segCommand = base + sizeof(struct mach_header) + binIndex;
607
608
609binIndex += segCommand->cmdsize;
610index++;
611}
612while(index <= immediate);
613
614
615segmentAddress = segCommand->fileoff;
616
617tmp = 0;
618bits = 0;
619do
620{
621tmp |= (rebase_stream[++i] & 0x7f) << bits;
622bits += 7;
623}
624while(rebase_stream[i] & 0x80);
625
626segmentAddress += tmp;
627break;
628
629
630case REBASE_OPCODE_ADD_ADDR_ULEB:
631// Add value to rebase address
632tmp = 0;
633bits = 0;
634do
635{
636tmp <<= bits;
637tmp |= rebase_stream[++i] & 0x7f;
638bits += 7;
639}
640while(rebase_stream[i] & 0x80);
641
642segmentAddress +=tmp;
643break;
644
645case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
646segmentAddress += immediate * sizeof(void*);
647break;
648
649
650case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
651index = 0;
652for (index = 0; index < immediate; ++index) {
653rebase_location(base + segmentAddress, (char*)base, type);
654segmentAddress += sizeof(void*);
655}
656break;
657
658
659case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
660tmp = 0;
661bits = 0;
662do
663{
664tmp |= (rebase_stream[++i] & 0x7f) << bits;
665bits += 7;
666}
667while(rebase_stream[i] & 0x80);
668
669index = 0;
670for (index = 0; index < tmp; ++index) {
671//DBG("\tRebasing 0x%X\n", segmentAddress);
672rebase_location(base + segmentAddress, (char*)base, type);
673segmentAddress += sizeof(void*);
674}
675break;
676
677case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
678tmp = 0;
679bits = 0;
680do
681{
682tmp |= (rebase_stream[++i] & 0x7f) << bits;
683bits += 7;
684}
685while(rebase_stream[i] & 0x80);
686
687rebase_location(base + segmentAddress, (char*)base, type);
688
689segmentAddress += tmp + sizeof(void*);
690break;
691
692case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
693tmp = 0;
694bits = 0;
695do
696{
697tmp |= (rebase_stream[++i] & 0x7f) << bits;
698bits += 7;
699}
700while(rebase_stream[i] & 0x80);
701
702
703tmp2 = 0;
704bits = 0;
705do
706{
707tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
708bits += 7;
709}
710while(rebase_stream[i] & 0x80);
711
712index = 0;
713for (index = 0; index < tmp; ++index) {
714
715rebase_location(base + segmentAddress, (char*)base, type);
716
717segmentAddress += tmp2 + sizeof(void*);
718}
719break;
720}
721i++;
722}
723}
724
725inline void rebase_location(UInt32* location, char* base, int type)
726{
727switch(type)
728{
729case REBASE_TYPE_POINTER:
730case REBASE_TYPE_TEXT_ABSOLUTE32:
731*location += (UInt32)base;
732break;
733
734default:
735break;
736}
737}
738
739
740UInt32 read_uleb(UInt8* bind_stream, unsigned int* i)
741{
742 // Read in offset
743 UInt32 tmp = 0;
744 UInt8 bits = 0;
745 do
746 {
747 if(bits < sizeof(UInt32)*8) // hack
748 {
749 tmp |= (bind_stream[++(*i)] & 0x7f) << bits;
750 bits += 7;
751 }
752 else
753 {
754 ++(*i);
755 }
756 }
757 while(bind_stream[*i] & 0x80);
758 return tmp;
759}
760
761
762// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
763// NOTE: this uses 32bit values, and not 64bit values.
764// There is a possibility that this could cause issues,
765// however the modules are 32 bits, so it shouldn't matter too much
766void bind_macho(void* base, UInt8* bind_stream, UInt32 size)
767{
768bind_stream += (UInt32)base;
769
770UInt8 immediate = 0;
771UInt8 opcode = 0;
772UInt8 type = BIND_TYPE_POINTER;
773
774UInt32 segmentAddress = 0;
775
776UInt32 address = 0;
777
778SInt32 addend = 0;
779SInt32 libraryOrdinal = 0;
780
781const char* symbolName = NULL;
782UInt8 symboFlags = 0;
783UInt32 symbolAddr = 0xFFFFFFFF;
784
785// Temperary variables
786UInt32 tmp = 0;
787UInt32 tmp2 = 0;
788UInt32 index = 0;
789unsigned int i = 0;
790
791while(i < size)
792{
793immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
794opcode = bind_stream[i] & BIND_OPCODE_MASK;
795
796
797switch(opcode)
798{
799case BIND_OPCODE_DONE:
800// reset vars
801type = BIND_TYPE_POINTER;
802segmentAddress = 0;
803address = 0;
804addend = 0;
805libraryOrdinal = 0;
806symbolAddr = 0xFFFFFFFF;
807default:
808break;
809
810case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
811libraryOrdinal = immediate;
812break;
813
814case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
815libraryOrdinal = read_uleb(bind_stream, &i);
816break;
817
818case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
819libraryOrdinal = immediate ? (SInt8)(BIND_OPCODE_MASK | immediate) : immediate;
820break;
821
822case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
823symboFlags = immediate;
824symbolName = (char*)&bind_stream[++i];
825i += strlen((char*)&bind_stream[i]);
826
827symbolAddr = lookup_all_symbols(symbolName);
828break;
829
830case BIND_OPCODE_SET_TYPE_IMM:
831type = immediate;
832break;
833
834case BIND_OPCODE_SET_ADDEND_SLEB:
835addend = read_uleb(bind_stream, &i);
836if(!(bind_stream[i-1] & 0x40)) addend *= -1;
837break;
838
839case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
840segmentAddress = 0;
841
842// Locate address
843struct segment_command* segCommand = NULL;// NOTE: 32bit only
844
845unsigned int binIndex = 0;
846index = 0;
847do
848{
849segCommand = base + sizeof(struct mach_header) + binIndex;
850binIndex += segCommand->cmdsize;
851index++;
852}
853while(index <= immediate);
854
855segmentAddress = segCommand->fileoff;
856
857segmentAddress += read_uleb(bind_stream, &i);
858break;
859
860case BIND_OPCODE_ADD_ADDR_ULEB:
861segmentAddress += read_uleb(bind_stream, &i);
862break;
863
864case BIND_OPCODE_DO_BIND:
865if(symbolAddr != 0xFFFFFFFF)
866{
867address = segmentAddress + (UInt32)base;
868
869bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
870}
871else
872{
873printf("Unable to bind symbol %s\n", symbolName);
874getchar();
875}
876
877segmentAddress += sizeof(void*);
878break;
879
880case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
881// Read in offset
882tmp = read_uleb(bind_stream, &i);
883
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 += tmp + sizeof(void*);
897
898
899break;
900
901case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
902if(symbolAddr != 0xFFFFFFFF)
903{
904address = segmentAddress + (UInt32)base;
905
906bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
907}
908else
909{
910printf("Unable to bind symbol %s\n", symbolName);
911getchar();
912}
913segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
914
915
916break;
917
918case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
919tmp = read_uleb(bind_stream, &i);
920
921tmp2 = read_uleb(bind_stream, &i);
922
923if(symbolAddr != 0xFFFFFFFF)
924{
925for(index = 0; index < tmp; index++)
926{
927
928address = segmentAddress + (UInt32)base;
929bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
930segmentAddress += tmp2 + sizeof(void*);
931}
932}
933else
934{
935printf("Unable to bind symbol %s\n", symbolName);
936getchar();
937}
938break;
939}
940i++;
941}
942}
943
944
945inline void bind_location(UInt32* location, char* value, UInt32 addend, int type)
946{
947// do actual update
948char* newValue = value + addend;
949
950switch (type) {
951case BIND_TYPE_POINTER:
952case BIND_TYPE_TEXT_ABSOLUTE32:
953break;
954
955case BIND_TYPE_TEXT_PCREL32:
956newValue -= ((UInt32)location + 4);
957
958break;
959default:
960return;
961}
962//DBG("Binding 0x%X to 0x%X (was 0x%X)\n", location, newValue, *location);
963*location = (UInt32)newValue;
964}
965
966/********************************************************************************/
967/*Module Hook Interface*/
968/********************************************************************************/
969
970/*
971* Locate the symbol for an already loaded function and modify the beginning of
972* the function to jump directly to the new one
973* example: replace_function("_HelloWorld_start", &replacement_start);
974*/
975int replace_function(const char* symbol, void* newAddress)
976{
977UInt32* jumpPointer = malloc(sizeof(UInt32*));
978UInt32 addr = lookup_all_symbols(symbol);
979
980char* binary = (char*)addr;
981if(addr != 0xFFFFFFFF)
982{
983//DBG("Replacing %s to point to 0x%x\n", symbol, newAddress);
984*binary++ = 0xFF;// Jump
985*binary++ = 0x25;// Long Jump
986*((UInt32*)binary) = (UInt32)jumpPointer;
987
988*jumpPointer = (UInt32)newAddress;
989return 1;
990}
991return 0;
992}
993
994
995/*
996 *execute_hook( const char* name )
997 *name - Name of the module hook
998 *If any callbacks have been registered for this hook
999 *they will be executed now in the same order that the
1000 *hooks were added.
1001*/
1002int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)
1003{
1004DBG("Attempting to execute hook '%s'\n", name); DBGPAUSE();
1005moduleHook_t* hook = hook_exists(name);
1006
1007if(hook)
1008{
1009// Loop through all callbacks for this module
1010callbackList_t* callbacks = hook->callbacks;
1011
1012while(callbacks)
1013{
1014// Execute callback
1015callbacks->callback(arg1, arg2, arg3, arg4);
1016callbacks = callbacks->next;
1017}
1018DBG("Hook '%s' executed.\n", name); DBGPAUSE();
1019return 1;
1020}
1021else
1022{
1023// Callback for this hook doesn't exist;
1024DBG("No callbacks for '%s' hook.\n", name);
1025return 0;
1026}
1027}
1028
1029
1030
1031/*
1032 *register_hook_callback( const char* name, void(*callback)())
1033 *name - Name of the module hook to attach to.
1034 *callbacks - The funciton pointer that will be called when the
1035 *hook is executed. When registering a new callback name, the callback is added sorted.
1036 *NOTE: the hooks take four void* arguments.
1037 */
1038void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))
1039{
1040DBG("Adding callback for '%s' hook.\n", name); DBGPAUSE();
1041
1042moduleHook_t* hook = hook_exists(name);
1043
1044if(hook)
1045{
1046// append
1047callbackList_t* newCallback = malloc(sizeof(callbackList_t));
1048newCallback->next = hook->callbacks;
1049hook->callbacks = newCallback;
1050newCallback->callback = callback;
1051}
1052else
1053{
1054// create new hook
1055moduleHook_t* newHook = malloc(sizeof(moduleHook_t));
1056newHook->name = name;
1057newHook->callbacks = malloc(sizeof(callbackList_t));
1058newHook->callbacks->callback = callback;
1059newHook->callbacks->next = NULL;
1060
1061newHook->next = moduleCallbacks;
1062moduleCallbacks = newHook;
1063
1064}
1065
1066#if CONFIG_MODULE_DEBUG
1067//print_hook_list();
1068//getchar();
1069#endif
1070
1071}
1072
1073
1074moduleHook_t* hook_exists(const char* name)
1075{
1076moduleHook_t* hooks = moduleCallbacks;
1077
1078// look for a hook. If it exists, return the moduleHook_t*,
1079// If not, return NULL.
1080while(hooks)
1081{
1082if(strcmp(name, hooks->name) == 0)
1083{
1084//DBG("Located hook %s\n", name);
1085return hooks;
1086}
1087hooks = hooks->next;
1088}
1089//DBG("Hook %s does not exist\n", name);
1090return NULL;
1091
1092}
1093
1094#if CONFIG_MODULE_DEBUG
1095void print_hook_list()
1096{
1097printf("---Hook Table---\n");
1098
1099moduleHook_t* hooks = moduleCallbacks;
1100while(hooks)
1101{
1102printf("Hook: %s\n", hooks->name);
1103hooks = hooks->next;
1104}
1105}
1106
1107#endif
1108
1109/********************************************************************************/
1110/*dyld / Linker Interface*/
1111/********************************************************************************/
1112
1113void dyld_stub_binder()
1114{
1115printf("ERROR: dyld_stub_binder was called, should have been take care of by the linker.\n");
1116getchar();
1117}
1118
1119#else /* CONFIG_MODULES */
1120
1121int init_module_system()
1122{
1123 return 0;
1124}
1125
1126void load_all_modules()
1127{
1128
1129}
1130
1131int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)
1132{
1133 return 0;
1134}
1135
1136void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))
1137{
1138printf("WARNING: register_hook_callback is not supported when compiled in.\n");
1139pause();
1140}
1141
1142int replace_function(const char* symbol, void* newAddress)
1143{
1144printf("WARNING: replace_functions is not supported when compiled in.\n");
1145pause();
1146return 0;
1147}
1148
1149void start_built_in_module(const char* name,
1150 const char* author,
1151 const char* description,
1152 UInt32 version,
1153 UInt32 compat,
1154 void(*start_function)(void))
1155{
1156 start_function();
1157}
1158
1159#endif

Archive Download this file

Revision: 2095