Chameleon

Chameleon Svn Source Tree

Root/branches/rewrite/i386/modules/ModuleSystem/modules.c

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

Archive Download this file

Revision: 1146