Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2094