Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/boot2/modules.c

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

Archive Download this file

Revision: 2858