Chameleon

Chameleon Svn Source Tree

Root/tags/2.0/i386/boot2/modules.c

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

Archive Download this file

Revision: 1808