Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 737