Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 2249