Chameleon

Chameleon Svn Source Tree

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

Source at commit 728 created 13 years 2 months ago.
By meklort, Updated Symbols.dylib generation. Module linked list rework beginning. USB Legacy off patch still needs fixing. Added a new tool to generate the symbols.dylib. It's a fairly correct dylib file, however nm complains about it (it still works fine though). Updated Symbols.dylib file is smaller (~13%) that the old method and is a bit cleaner. dylib generation needs a bit of cleaning up though)
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); getc();
81}
82return 0;
83}
84
85
86/*
87 * Load all modules in the /Extra/modules/ directory
88 * Module depencdies will be loaded first
89 * MOdules will only be loaded once. When loaded a module must
90 * setup apropriete function calls and hooks as required.
91 * NOTE: To ensure a module loads after another you may
92 * link one module with the other. For dyld to allow this, you must
93 * reference at least one symbol within the module.
94 */
95void load_all_modules()
96{
97char* name;
98long flags;
99long time;
100struct dirstuff* moduleDir = opendir("/Extra/modules/");
101while(readdir(moduleDir, (const char**)&name, &flags, &time) >= 0)
102{
103if(strcmp(&name[strlen(name) - sizeof("dylib")], ".dylib") == 0)
104{
105char* tmp = malloc(strlen(name) + 1);
106strcpy(tmp, name);
107
108if(!load_module(tmp))
109{
110// failed to load
111// free(tmp);
112}
113}
114else
115{
116DBG("Ignoring %s\n", name);
117}
118
119}
120}
121
122
123/*
124 * Load a module file in /Extra/modules
125 * TODO: verify version number of module
126 */
127int load_module(char* module)
128{
129void (*module_start)(void) = NULL;
130
131
132// Check to see if the module has already been loaded
133if(is_module_loaded(module))
134{
135return 1;
136}
137
138char modString[128];
139int fh = -1;
140sprintf(modString, "/Extra/modules/%s", module);
141fh = open(modString, 0);
142if(fh < 0)
143{
144printf("Unable to locate module %s\n", modString); DBGPAUSE();
145getc();
146return 0;
147}
148
149unsigned int moduleSize = file_size(fh);
150char* module_base = (char*) malloc(moduleSize);
151if (moduleSize && read(fh, module_base, moduleSize) == moduleSize)
152{
153
154//DBG("Module %s read in.\n", modString);
155
156// Module loaded into memory, parse it
157module_start = parse_mach(module_base, &load_module, &add_symbol);
158
159if(module_start && module_start != (void*)0xFFFFFFFF)
160{
161// Notify the system that it was laoded
162module_loaded(module/*moduleName, moduleVersion, moduleCompat*/);
163
164(*module_start)();// Start the module
165DBG("Module %s Loaded.\n", module); DBGPAUSE();
166
167//module_entry = malloc(sizeof(moduleList_t); TODO: mode to module_loaded
168
169}
170else {
171// The module does not have a valid start function
172printf("Unable to start %s\n", module);
173getc();
174}
175}
176else
177{
178DBG("Unable to read in module %s\n.", module);
179getc();
180}
181close(fh);
182
183return 1;
184}
185
186/*
187 * add_symbol
188 * This function adds a symbol from a module to the list of known symbols
189 * possibly change to a pointer and add this to the Symbol module so that it can
190 * adjust it's internal symbol list (sort) to optimize locating new symbols
191 * NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF
192 */
193long long add_symbol(char* symbol, long long addr, char is64)
194{
195if(is64) return 0xFFFFFFFF; // Fixme
196
197// This only can handle 32bit symbols
198symbolList_t* entry;
199//DBG("Adding symbol %s at 0x%X\n", symbol, addr);
200
201if(!moduleSymbols)
202{
203moduleSymbols = entry = malloc(sizeof(symbolList_t));
204
205}
206else
207{
208entry = moduleSymbols;
209while(entry->next)
210{
211entry = entry->next;
212}
213
214entry->next = malloc(sizeof(symbolList_t));
215entry = entry->next;
216}
217
218entry->next = NULL;
219entry->addr = (UInt32)addr;
220entry->symbol = symbol;
221if(strcmp(symbol, "start") == 0)
222{
223return addr;
224}
225else
226{
227return 0xFFFFFFFF; // fixme
228}
229}
230
231
232/*
233 * print out the information about the loaded module
234 */
235void module_loaded(const char* name/*, UInt32 version, UInt32 compat*/)
236{
237// TODO: insert sorted
238moduleList_t* new_entry = malloc(sizeof(moduleList_t));
239
240new_entry->next = loadedModules;
241loadedModules = new_entry;
242
243new_entry->name = (char*)name;
244new_entry->base_addr = NULL;// TODO
245// todo; symbols
246new_entry->version = 0; //version;
247new_entry->compat = 0; //compat;
248}
249
250int is_module_loaded(const char* name)
251{
252// todo sorted search
253moduleList_t* entry = loadedModules;
254while(entry)
255{
256if(strcmp(entry->name, name) == 0)
257{
258DBG("Located module %s\n", name); DBGPAUSE();
259return 1;
260}
261else
262{
263entry = entry->next;
264}
265
266}
267DBG("Module %s not found\n", name); DBGPAUSE();
268
269return 0;
270}
271
272// Look for symbols using the Smbols moduel function.
273// If non are found, look through the list of module symbols
274unsigned int lookup_all_symbols(const char* name)
275{
276unsigned int addr = 0xFFFFFFFF;
277symbolList_t* entry = moduleSymbols;
278while(entry)
279{
280if(strcmp(entry->symbol, name) == 0)
281{
282//DBG("External symbol %s located at 0x%X\n", name, entry->addr);
283return entry->addr;
284}
285else
286{
287entry = entry->next;
288}
289
290}
291
292if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)
293{
294addr = lookup_symbol(name);
295if(addr != 0xFFFFFFFF)
296{
297//DBG("Internal symbol %s located at 0x%X\n", name, addr);
298return addr;
299}
300}
301
302
303#if DEBUG_MODULES
304verbose("Unable to locate symbol %s\n", name);
305getc();
306#endif
307
308return 0xFFFFFFFF;
309}
310
311/********************************************************************************/
312/*Macho Parser*/
313/********************************************************************************/
314
315/*
316 * Parse through a macho module. The module will be rebased and binded
317 * as specified in the macho header. If the module is sucessfuly laoded
318 * the module iinit address will be returned.
319 * NOTE; all dependecies will be loaded before this module is started
320 * NOTE: If the module is unable to load ot completeion, the modules
321 * symbols will still be available (TODO: fix this). This should not
322 * happen as all dependencies are verified before the sybols are read in.
323 */
324void* parse_mach(void* binary, int(*dylib_loader)(char*), long long(*symbol_handler)(char*, long long, char))// TODO: add param to specify valid archs
325{
326char is64 = false;
327void (*module_start)(void) = NULL;
328
329// Module info
330/*char* moduleName = NULL;
331 UInt32 moduleVersion = 0;
332 UInt32 moduleCompat = 0;
333 */
334// TODO convert all of the structs to a union
335struct load_command *loadCommand = NULL;
336struct dylib_command* dylibCommand = NULL;
337struct dyld_info_command* dyldInfoCommand = NULL;
338
339struct symtab_command* symtabCommand = NULL;
340struct segment_command *segCommand = NULL;
341struct segment_command_64 *segCommand64 = NULL;
342
343//struct dysymtab_command* dysymtabCommand = NULL;
344UInt32 binaryIndex = 0;
345UInt16 cmd = 0;
346
347textSection = 0;
348textAddress = 0;// reinitialize text location in case it doesn't exist;
349
350// Parse through the load commands
351if(((struct mach_header*)binary)->magic == MH_MAGIC)
352{
353is64 = false;
354binaryIndex += sizeof(struct mach_header);
355}
356else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
357{
358// NOTE: modules cannot be 64bit...
359is64 = true;
360binaryIndex += sizeof(struct mach_header_64);
361}
362else
363{
364printf("Invalid mach magic 0x%X\n", ((struct mach_header*)binary)->magic);
365getc();
366return NULL;
367}
368
369
370
371/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
372 {
373 printf("Module is not a dylib. Unable to load.\n");
374 getc();
375 return NULL; // Module is in the incorrect format
376 }*/
377
378while(cmd < ((struct mach_header*)binary)->ncmds)
379{
380cmd++;
381
382loadCommand = binary + binaryIndex;
383UInt32 cmdSize = loadCommand->cmdsize;
384
385
386switch ((loadCommand->cmd & 0x7FFFFFFF))
387{
388// TODO: sepeare function to handel appropriate sections
389case LC_SYMTAB:
390symtabCommand = binary + binaryIndex;
391break;
392
393case LC_SEGMENT: // 32bit macho
394segCommand = binary + binaryIndex;
395
396//printf("Segment name is %s\n", segCommand->segname);
397
398if(strcmp("__TEXT", segCommand->segname) == 0)
399{
400UInt32 sectionIndex;
401
402sectionIndex = sizeof(struct segment_command);
403
404struct section *sect;
405
406while(sectionIndex < segCommand->cmdsize)
407{
408sect = binary + binaryIndex + sectionIndex;
409
410sectionIndex += sizeof(struct section);
411
412
413if(strcmp("__text", sect->sectname) == 0)
414{
415// __TEXT,__text found, save the offset and address for when looking for the calls.
416textSection = sect->offset;
417textAddress = sect->addr;
418break;
419}
420}
421}
422
423break;
424case LC_SEGMENT_64:// 64bit macho's
425segCommand64 = binary + binaryIndex;
426
427//printf("Segment name is %s\n", segCommand->segname);
428
429if(strcmp("__TEXT", segCommand64->segname) == 0)
430{
431UInt32 sectionIndex;
432
433sectionIndex = sizeof(struct segment_command_64);
434
435struct section_64 *sect;
436
437while(sectionIndex < segCommand64->cmdsize)
438{
439sect = binary + binaryIndex + sectionIndex;
440
441sectionIndex += sizeof(struct section_64);
442
443
444if(strcmp("__text", sect->sectname) == 0)
445{
446// __TEXT,__text found, save the offset and address for when looking for the calls.
447textSection = sect->offset;
448textAddress = sect->addr;
449
450break;
451}
452}
453}
454
455break;
456
457case LC_DYSYMTAB:
458break;
459
460case LC_LOAD_DYLIB:
461case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
462dylibCommand = binary + binaryIndex;
463char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
464// TODO: verify version
465// =dylibCommand->dylib.current_version;
466// =dylibCommand->dylib.compatibility_version;
467if(dylib_loader)
468{
469char* name = malloc(strlen(module) + strlen(".dylib") + 1);
470sprintf(name, "%s.dylib", module);
471
472if (!dylib_loader(name))
473{
474free(name);
475// Unable to load dependancy
476//return NULL;
477}
478}
479
480break;
481
482case LC_ID_DYLIB:
483dylibCommand = binary + binaryIndex;
484/*moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
485 moduleVersion =dylibCommand->dylib.current_version;
486 moduleCompat =dylibCommand->dylib.compatibility_version;
487 */
488break;
489
490case LC_DYLD_INFO:
491//case LC_DYLD_INFO_ONLY:// compressed info, 10.6+ macho files, already handeled
492// Bind and rebase info is stored here
493dyldInfoCommand = binary + binaryIndex;
494break;
495
496case LC_UUID:
497break;
498
499case LC_UNIXTHREAD:
500break;
501
502default:
503DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
504break;
505
506}
507
508binaryIndex += cmdSize;
509}
510//if(!moduleName) return NULL;
511
512
513// bind_macho uses the symbols, if the textAdd does not exist (Symbols.dylib, no code), addresses are static and not relative
514module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);
515
516// Rebase the module before binding it.
517if(dyldInfoCommand && dyldInfoCommand->rebase_off)
518{
519rebase_macho(binary, (char*)dyldInfoCommand->rebase_off, dyldInfoCommand->rebase_size);
520}
521
522if(dyldInfoCommand && dyldInfoCommand->bind_off)
523{
524bind_macho(binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size);
525}
526
527if(dyldInfoCommand && dyldInfoCommand->weak_bind_off)
528{
529// NOTE: this currently should never happen.
530bind_macho(binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size);
531}
532
533if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off)
534{
535// NOTE: we are binding the lazy pointers as a module is laoded,
536// This should be changed to bind when a symbol is referened at runtime instead.
537bind_macho(binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);
538}
539
540return module_start;
541
542}
543
544/*
545 * parse the symbol table
546 * Lookup any undefined symbols
547 */
548
549unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)
550{
551// TODO: verify that the _TEXT,_text segment starts at the same locaiton in the file. If not
552//subtract the vmaddress and add the actual file address back on. (NOTE: if compiled properly, not needed)
553
554unsigned int module_start = 0xFFFFFFFF;
555
556UInt32 symbolIndex = 0;
557char* symbolString = base + (char*)symtabCommand->stroff;
558//char* symbolTable = base + symtabCommand->symoff;
559if(!is64)
560{
561struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
562while(symbolIndex < symtabCommand->nsyms)
563{
564// If the symbol is exported by this module
565if(symbolEntry->n_value &&
566 symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)
567{
568
569// Module start located. Start is an alias so don't register it
570module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;
571}
572
573symbolEntry++;
574symbolIndex++;// TODO remove
575}
576}
577else
578{
579struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
580// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)
581while(symbolIndex < symtabCommand->nsyms)
582{
583
584
585// If the symbol is exported by this module
586if(symbolEntry->n_value &&
587 symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)
588{
589
590// Module start located. Start is an alias so don't register it
591module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;
592}
593
594symbolEntry++;
595symbolIndex++;// TODO remove
596}
597}
598
599return module_start;
600
601}
602
603// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
604void rebase_macho(void* base, char* rebase_stream, UInt32 size)
605{
606rebase_stream += (UInt32)base;
607
608UInt8 immediate = 0;
609UInt8 opcode = 0;
610UInt8 type = 0;
611
612UInt32 segmentAddress = 0;
613
614
615
616UInt32 tmp = 0;
617UInt32 tmp2 = 0;
618UInt8 bits = 0;
619int index = 0;
620
621//int done = 0;
622unsigned int i = 0;
623
624while(/*!done &&*/ i < size)
625{
626immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
627opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
628
629
630switch(opcode)
631{
632case REBASE_OPCODE_DONE:
633// Rebase complete.
634//done = 1;
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}
1104else
1105{
1106return 0;
1107}
1108
1109}
1110
1111
1112/*
1113 *execute_hook( const char* name )
1114 *name - Name of the module hook
1115 *If any callbacks have been registered for this hook
1116 *they will be executed now in the same order that the
1117 *hooks were added.
1118*/
1119int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)
1120{
1121DBG("Attempting to execute hook '%s'\n", name); DBGPAUSE();
1122moduleHook_t* hook = hook_exists(name);
1123
1124if(hook)
1125{
1126// Loop through all callbacks for this module
1127callbackList_t* callbacks = hook->callbacks;
1128
1129while(callbacks)
1130{
1131//DBG("Executing '%s' callback at 0x%X.\n", name, callbacks->callback);
1132// Execute callback
1133callbacks->callback(arg1, arg2, arg3, arg4);
1134callbacks = callbacks->next;
1135//DBG("Hook '%s' callback executed, next is 0x%X.\n", name, callbacks);
1136
1137}
1138DBG("Hook '%s' executed.\n", name); DBGPAUSE();
1139return 1;
1140}
1141else
1142{
1143// Callback for this hook doesn't exist;
1144DBG("No callbacks for '%s' hook.\n", name);
1145return 0;
1146}
1147}
1148
1149
1150
1151/*
1152 *register_hook_callback( const char* name, void(*callback)())
1153 *name - Name of the module hook to attach to.
1154 *callbacks - The funciton pointer that will be called when the
1155 *hook is executed. When registering a new callback name, the callback is added sorted.
1156 *NOTE: the hooks take four void* arguments.
1157 */
1158void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))
1159{
1160DBG("Adding callback for '%s' hook.\n", name); DBGPAUSE();
1161
1162moduleHook_t* hook = hook_exists(name);
1163
1164if(hook)
1165{
1166// append
1167callbackList_t* newCallback = malloc(sizeof(callbackList_t));
1168newCallback->next = hook->callbacks;
1169hook->callbacks = newCallback;
1170newCallback->callback = callback;
1171}
1172else
1173{
1174// create new hook
1175moduleHook_t* newHook = malloc(sizeof(moduleHook_t));
1176newHook->name = name;
1177newHook->callbacks = malloc(sizeof(callbackList_t));
1178newHook->callbacks->callback = callback;
1179newHook->callbacks->next = NULL;
1180
1181newHook->next = moduleCallbacks;
1182moduleCallbacks = newHook;
1183
1184}
1185
1186#if DEBUG_MODULES
1187//print_hook_list();
1188//getc();
1189#endif
1190
1191}
1192
1193
1194moduleHook_t* hook_exists(const char* name)
1195{
1196moduleHook_t* hooks = moduleCallbacks;
1197
1198// look for a hook. If it exists, return the moduleHook_t*,
1199// If not, return NULL.
1200while(hooks)
1201{
1202if(strcmp(name, hooks->name) == 0)
1203{
1204//DBG("Located hook %s\n", name);
1205return hooks;
1206}
1207hooks = hooks->next;
1208}
1209//DBG("Hook %s does not exist\n", name);
1210return NULL;
1211
1212}
1213
1214#if DEBUG_MODULES
1215void print_hook_list()
1216{
1217printf("---Hook Table---\n");
1218
1219moduleHook_t* hooks = moduleCallbacks;
1220while(hooks)
1221{
1222printf("Hook: %s\n", hooks->name);
1223hooks = hooks->next;
1224}
1225}
1226#endif
1227
1228/********************************************************************************/
1229/*dyld / Linker Interface*/
1230/********************************************************************************/
1231
1232void dyld_stub_binder()
1233{
1234// TODO: actualy impliment this function (asm)
1235printf("ERROR: dyld_stub_binder was called, should have been take care of by the linker.\n");
1236getc();
1237}
1238

Archive Download this file

Revision: 728