Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1174