Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/boot2/modules.c

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

Archive Download this file

Revision: 774