Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2525