Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 735