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

Archive Download this file

Revision: 896