Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/boot2/modules.c

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

Archive Download this file

Revision: 929