Chameleon

Chameleon Svn Source Tree

Root/branches/slice/i386/boot2/modules.c

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

Archive Download this file

Revision: 721