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

Archive Download this file

Revision: 2531