Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2839