Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch/i386/boot2/modules.c

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

Archive Download this file

Revision: 2587