Chameleon

Chameleon Svn Source Tree

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

Source at commit 741 created 13 years 2 months ago.
By meklort, Module system cleanup. KextPatcher compiled with -O3
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;// TGlobal, 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{
130printf("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
263return 0xFFFFFFFF;
264}
265
266/********************************************************************************/
267/*Macho Parser*/
268/********************************************************************************/
269
270/*
271 * Parse through a macho module. The module will be rebased and binded
272 * as specified in the macho header. If the module is sucessfuly laoded
273 * the module iinit address will be returned.
274 * NOTE; all dependecies will be loaded before this module is started
275 * NOTE: If the module is unable to load ot completeion, the modules
276 * symbols will still be available (TODO: fix this). This should not
277 * happen as all dependencies are verified before the sybols are read in.
278 */
279void* parse_mach(void* binary, int(*dylib_loader)(char*), long long(*symbol_handler)(char*, long long, char))// TODO: add param to specify valid archs
280{
281char is64 = false;
282void (*module_start)(void) = NULL;
283
284// Module info
285/*char* moduleName = NULL;
286 UInt32 moduleVersion = 0;
287 UInt32 moduleCompat = 0;
288 */
289// TODO convert all of the structs to a union
290struct load_command *loadCommand = NULL;
291struct dylib_command* dylibCommand = NULL;
292struct dyld_info_command* dyldInfoCommand = NULL;
293
294struct symtab_command* symtabCommand = NULL;
295struct segment_command *segCommand = NULL;
296struct segment_command_64 *segCommand64 = NULL;
297
298//struct dysymtab_command* dysymtabCommand = NULL;
299UInt32 binaryIndex = 0;
300UInt16 cmd = 0;
301
302textSection = 0;
303textAddress = 0;// reinitialize text location in case it doesn't exist;
304
305// Parse through the load commands
306if(((struct mach_header*)binary)->magic == MH_MAGIC)
307{
308is64 = false;
309binaryIndex += sizeof(struct mach_header);
310}
311else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
312{
313// NOTE: modules cannot be 64bit...
314is64 = true;
315binaryIndex += sizeof(struct mach_header_64);
316}
317else
318{
319printf("Invalid mach magic 0x%X\n", ((struct mach_header*)binary)->magic);
320getc();
321return NULL;
322}
323
324
325
326/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
327 {
328 printf("Module is not a dylib. Unable to load.\n");
329 getc();
330 return NULL; // Module is in the incorrect format
331 }*/
332
333while(cmd < ((struct mach_header*)binary)->ncmds)
334{
335cmd++;
336
337loadCommand = binary + binaryIndex;
338UInt32 cmdSize = loadCommand->cmdsize;
339
340
341switch ((loadCommand->cmd & 0x7FFFFFFF))
342{
343// TODO: sepeare function to handel appropriate sections
344case LC_SYMTAB:
345symtabCommand = binary + binaryIndex;
346break;
347
348case LC_SEGMENT: // 32bit macho
349segCommand = binary + binaryIndex;
350
351//printf("Segment name is %s\n", segCommand->segname);
352
353if(strcmp("__TEXT", segCommand->segname) == 0)
354{
355UInt32 sectionIndex;
356
357sectionIndex = sizeof(struct segment_command);
358
359struct section *sect;
360
361while(sectionIndex < segCommand->cmdsize)
362{
363sect = binary + binaryIndex + sectionIndex;
364
365sectionIndex += sizeof(struct section);
366
367
368if(strcmp("__text", sect->sectname) == 0)
369{
370// __TEXT,__text found, save the offset and address for when looking for the calls.
371textSection = sect->offset;
372textAddress = sect->addr;
373break;
374}
375}
376}
377
378break;
379case LC_SEGMENT_64:// 64bit macho's
380segCommand64 = binary + binaryIndex;
381
382//printf("Segment name is %s\n", segCommand->segname);
383
384if(strcmp("__TEXT", segCommand64->segname) == 0)
385{
386UInt32 sectionIndex;
387
388sectionIndex = sizeof(struct segment_command_64);
389
390struct section_64 *sect;
391
392while(sectionIndex < segCommand64->cmdsize)
393{
394sect = binary + binaryIndex + sectionIndex;
395
396sectionIndex += sizeof(struct section_64);
397
398
399if(strcmp("__text", sect->sectname) == 0)
400{
401// __TEXT,__text found, save the offset and address for when looking for the calls.
402textSection = sect->offset;
403textAddress = sect->addr;
404
405break;
406}
407}
408}
409
410break;
411
412case LC_DYSYMTAB:
413break;
414
415case LC_LOAD_DYLIB:
416case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
417dylibCommand = binary + binaryIndex;
418char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
419// TODO: verify version
420// =dylibCommand->dylib.current_version;
421// =dylibCommand->dylib.compatibility_version;
422if(dylib_loader)
423{
424char* name = malloc(strlen(module) + strlen(".dylib") + 1);
425sprintf(name, "%s.dylib", module);
426
427if (!dylib_loader(name))
428{
429free(name);
430// Unable to load dependancy
431//return NULL;
432}
433}
434
435break;
436
437case LC_ID_DYLIB:
438dylibCommand = binary + binaryIndex;
439/*moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
440 moduleVersion =dylibCommand->dylib.current_version;
441 moduleCompat =dylibCommand->dylib.compatibility_version;
442 */
443break;
444
445case LC_DYLD_INFO:
446//case LC_DYLD_INFO_ONLY:// compressed info, 10.6+ macho files, already handeled
447// Bind and rebase info is stored here
448dyldInfoCommand = binary + binaryIndex;
449break;
450
451case LC_UUID:
452break;
453
454case LC_UNIXTHREAD:
455break;
456
457default:
458DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
459break;
460
461}
462
463binaryIndex += cmdSize;
464}
465//if(!moduleName) return NULL;
466
467
468// bind_macho uses the symbols, if the textAdd does not exist (Symbols.dylib, no code), addresses are static and not relative
469module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);
470
471// Rebase the module before binding it.
472if(dyldInfoCommand && dyldInfoCommand->rebase_off)
473{
474rebase_macho(binary, (char*)dyldInfoCommand->rebase_off, dyldInfoCommand->rebase_size);
475}
476
477if(dyldInfoCommand && dyldInfoCommand->bind_off)
478{
479bind_macho(binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size);
480}
481
482if(dyldInfoCommand && dyldInfoCommand->weak_bind_off)
483{
484// NOTE: this currently should never happen.
485bind_macho(binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size);
486}
487
488if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off)
489{
490// NOTE: we are binding the lazy pointers as a module is laoded,
491// This should be changed to bind when a symbol is referened at runtime instead.
492bind_macho(binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);
493}
494
495return module_start;
496
497}
498
499/*
500 * parse the symbol table
501 * Lookup any undefined symbols
502 */
503
504unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)
505{
506// TODO: verify that the _TEXT,_text segment starts at the same locaiton in the file. If not
507//subtract the vmaddress and add the actual file address back on. (NOTE: if compiled properly, not needed)
508
509unsigned int module_start = 0xFFFFFFFF;
510
511UInt32 symbolIndex = 0;
512char* symbolString = base + (char*)symtabCommand->stroff;
513//char* symbolTable = base + symtabCommand->symoff;
514if(!is64)
515{
516struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
517while(symbolIndex < symtabCommand->nsyms)
518{
519// If the symbol is exported by this module
520if(symbolEntry->n_value &&
521 symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)
522{
523
524// Module start located. Start is an alias so don't register it
525module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;
526}
527
528symbolEntry++;
529symbolIndex++;// TODO remove
530}
531}
532else
533{
534struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
535// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)
536while(symbolIndex < symtabCommand->nsyms)
537{
538
539
540// If the symbol is exported by this module
541if(symbolEntry->n_value &&
542 symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)
543{
544
545// Module start located. Start is an alias so don't register it
546module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;
547}
548
549symbolEntry++;
550symbolIndex++;// TODO remove
551}
552}
553
554return module_start;
555
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;
566
567UInt32 segmentAddress = 0;
568
569
570
571UInt32 tmp = 0;
572UInt32 tmp2 = 0;
573UInt8 bits = 0;
574int index = 0;
575
576//int done = 0;
577unsigned int i = 0;
578
579while(/*!done &&*/ i < size)
580{
581immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
582opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
583
584
585switch(opcode)
586{
587case REBASE_OPCODE_DONE:
588// Rebase complete.
589//done = 1;
590default:
591break;
592
593
594case REBASE_OPCODE_SET_TYPE_IMM:
595// Set rebase type (pointer, absolute32, pcrel32)
596//DBG("Rebase type = 0x%X\n", immediate);
597type = immediate;
598break;
599
600
601case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
602// Locate address to begin rebasing
603segmentAddress = 0;
604
605struct segment_command* segCommand = NULL; // NOTE: 32bit only
606
607unsigned int binIndex = 0;
608index = 0;
609do
610{
611segCommand = base + sizeof(struct mach_header) + binIndex;
612
613
614binIndex += segCommand->cmdsize;
615index++;
616}
617while(index <= immediate);
618
619
620segmentAddress = segCommand->fileoff;
621
622tmp = 0;
623bits = 0;
624do
625{
626tmp |= (rebase_stream[++i] & 0x7f) << bits;
627bits += 7;
628}
629while(rebase_stream[i] & 0x80);
630
631segmentAddress += tmp;
632break;
633
634
635case REBASE_OPCODE_ADD_ADDR_ULEB:
636// Add value to rebase address
637tmp = 0;
638bits = 0;
639do
640{
641tmp <<= bits;
642tmp |= rebase_stream[++i] & 0x7f;
643bits += 7;
644}
645while(rebase_stream[i] & 0x80);
646
647segmentAddress +=tmp;
648break;
649
650case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
651segmentAddress += immediate * sizeof(void*);
652break;
653
654
655case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
656index = 0;
657for (index = 0; index < immediate; ++index) {
658rebase_location(base + segmentAddress, (char*)base, type);
659segmentAddress += sizeof(void*);
660}
661break;
662
663
664case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
665tmp = 0;
666bits = 0;
667do
668{
669tmp |= (rebase_stream[++i] & 0x7f) << bits;
670bits += 7;
671}
672while(rebase_stream[i] & 0x80);
673
674index = 0;
675for (index = 0; index < tmp; ++index) {
676//DBG("\tRebasing 0x%X\n", segmentAddress);
677rebase_location(base + segmentAddress, (char*)base, type);
678segmentAddress += sizeof(void*);
679}
680break;
681
682case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
683tmp = 0;
684bits = 0;
685do
686{
687tmp |= (rebase_stream[++i] & 0x7f) << bits;
688bits += 7;
689}
690while(rebase_stream[i] & 0x80);
691
692rebase_location(base + segmentAddress, (char*)base, type);
693
694segmentAddress += tmp + sizeof(void*);
695break;
696
697case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
698tmp = 0;
699bits = 0;
700do
701{
702tmp |= (rebase_stream[++i] & 0x7f) << bits;
703bits += 7;
704}
705while(rebase_stream[i] & 0x80);
706
707
708tmp2 = 0;
709bits = 0;
710do
711{
712tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
713bits += 7;
714}
715while(rebase_stream[i] & 0x80);
716
717index = 0;
718for (index = 0; index < tmp; ++index) {
719
720rebase_location(base + segmentAddress, (char*)base, type);
721
722segmentAddress += tmp2 + sizeof(void*);
723}
724break;
725}
726i++;
727}
728}
729
730inline void rebase_location(UInt32* location, char* base, int type)
731{
732switch(type)
733{
734case REBASE_TYPE_POINTER:
735case REBASE_TYPE_TEXT_ABSOLUTE32:
736*location += (UInt32)base;
737break;
738
739default:
740break;
741}
742}
743
744
745// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
746// NOTE: this uses 32bit values, and not 64bit values.
747// There is apossibility that this could cause issues,
748// however the macho file is 32 bit, so it shouldn't matter too much
749void bind_macho(void* base, char* bind_stream, UInt32 size)
750{
751bind_stream += (UInt32)base;
752
753UInt8 immediate = 0;
754UInt8 opcode = 0;
755UInt8 type = BIND_TYPE_POINTER;
756
757UInt32 segmentAddress = 0;
758
759UInt32 address = 0;
760
761SInt32 addend = 0;
762SInt32 libraryOrdinal = 0;
763
764const char* symbolName = NULL;
765UInt8 symboFlags = 0;
766UInt32 symbolAddr = 0xFFFFFFFF;
767
768// Temperary variables
769UInt8 bits = 0;
770UInt32 tmp = 0;
771UInt32 tmp2 = 0;
772
773UInt32 index = 0;
774//int done = 0;
775unsigned int i = 0;
776
777while(/*!done &&*/ i < size)
778{
779immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
780opcode = bind_stream[i] & BIND_OPCODE_MASK;
781
782
783switch(opcode)
784{
785case BIND_OPCODE_DONE:
786// reset vars
787type = BIND_TYPE_POINTER;
788segmentAddress = 0;
789address = 0;
790addend = 0;
791libraryOrdinal = 0;
792symbolAddr = 0xFFFFFFFF;
793//done = 1;
794default:
795break;
796
797case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
798libraryOrdinal = immediate;
799//printf("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);
800break;
801
802case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
803libraryOrdinal = 0;
804bits = 0;
805do
806{
807libraryOrdinal |= (bind_stream[++i] & 0x7f) << bits;
808bits += 7;
809}
810while(bind_stream[i] & 0x80);
811
812//printf("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);
813
814break;
815
816case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
817// NOTE: this is wrong, fortunately we don't use it
818libraryOrdinal = immediate ? (SInt8)(BIND_OPCODE_MASK | immediate) : immediate;
819//printf("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);
820
821break;
822
823case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
824symboFlags = immediate;
825symbolName = (char*)&bind_stream[++i];
826i += strlen((char*)&bind_stream[i]);
827//DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X", symbolName, symboFlags);
828
829symbolAddr = lookup_all_symbols(symbolName);
830//DBG(", addr = 0x%X\n", symbolAddr);
831break;
832
833case BIND_OPCODE_SET_TYPE_IMM:
834// Set bind type (pointer, absolute32, pcrel32)
835type = immediate;
836//DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);
837
838break;
839
840case BIND_OPCODE_SET_ADDEND_SLEB:
841addend = 0;
842bits = 0;
843do
844{
845addend |= (bind_stream[++i] & 0x7f) << bits;
846bits += 7;
847}
848while(bind_stream[i] & 0x80);
849
850if(!(bind_stream[i-1] & 0x40)) addend *= -1;
851
852//DBG("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);
853break;
854
855case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
856segmentAddress = 0;
857
858// Locate address
859struct segment_command* segCommand = NULL;// NOTE: 32bit only
860
861unsigned int binIndex = 0;
862index = 0;
863do
864{
865segCommand = base + sizeof(struct mach_header) + binIndex;
866binIndex += segCommand->cmdsize;
867index++;
868}
869while(index <= immediate);
870
871segmentAddress = segCommand->fileoff;
872
873// Read in offset
874tmp = 0;
875bits = 0;
876do
877{
878tmp |= (bind_stream[++i] & 0x7f) << bits;
879bits += 7;
880}
881while(bind_stream[i] & 0x80);
882
883segmentAddress += tmp;
884break;
885
886case BIND_OPCODE_ADD_ADDR_ULEB:
887// Read in offset
888tmp = 0;
889bits = 0;
890do
891{
892tmp |= (bind_stream[++i] & 0x7f) << bits;
893bits += 7;
894}
895while(bind_stream[i] & 0x80);
896
897segmentAddress += tmp;
898break;
899
900case BIND_OPCODE_DO_BIND:
901if(symbolAddr != 0xFFFFFFFF)
902{
903address = segmentAddress + (UInt32)base;
904
905bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
906}
907else
908{
909printf("Unable to bind symbol %s, libraryOrdinal = %d, symboFlags = %d, type = %d\n", symbolName, libraryOrdinal, symboFlags, type);
910getc();
911}
912
913
914segmentAddress += sizeof(void*);
915break;
916
917case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
918// Read in offset
919tmp = 0;
920bits = 0;
921do
922{
923tmp |= (bind_stream[++i] & 0x7f) << bits;
924bits += 7;
925}
926while(bind_stream[i] & 0x80);
927
928if(symbolAddr != 0xFFFFFFFF)
929{
930address = segmentAddress + (UInt32)base;
931
932bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
933}
934else
935{
936printf("Unable to bind symbol %s\n", symbolName);
937getc();
938}
939
940segmentAddress += tmp + sizeof(void*);
941
942
943break;
944
945case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
946if(symbolAddr != 0xFFFFFFFF)
947{
948address = segmentAddress + (UInt32)base;
949
950bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
951}
952else
953{
954printf("Unable to bind symbol %s\n", symbolName);
955getc();
956}
957segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
958
959
960break;
961
962case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
963
964tmp = 0;
965bits = 0;
966do
967{
968tmp |= (bind_stream[++i] & 0x7f) << bits;
969bits += 7;
970}
971while(bind_stream[i] & 0x80);
972
973
974tmp2 = 0;
975bits = 0;
976do
977{
978tmp2 |= (bind_stream[++i] & 0x7f) << bits;
979bits += 7;
980}
981while(bind_stream[i] & 0x80);
982
983
984if(symbolAddr != 0xFFFFFFFF)
985{
986for(index = 0; index < tmp; index++)
987{
988
989address = segmentAddress + (UInt32)base;
990bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
991segmentAddress += tmp2 + sizeof(void*);
992}
993}
994else
995{
996printf("Unable to bind symbol %s\n", symbolName);
997getc();
998}
999
1000
1001break;
1002
1003}
1004i++;
1005}
1006}
1007
1008inline void bind_location(UInt32* location, char* value, UInt32 addend, int type)
1009{
1010// do actual update
1011char* newValue = value + addend;
1012
1013switch (type) {
1014case BIND_TYPE_POINTER:
1015case BIND_TYPE_TEXT_ABSOLUTE32:
1016break;
1017
1018case BIND_TYPE_TEXT_PCREL32:
1019newValue -= ((UInt32)location + 4);
1020
1021break;
1022default:
1023return;
1024}
1025//DBG("Binding 0x%X to 0x%X (was 0x%X)\n", location, newValue, *location);
1026*location = (UInt32)newValue;
1027}
1028
1029/********************************************************************************/
1030/*Module Hook Interface*/
1031/********************************************************************************/
1032
1033/*
1034* Locate the symbol for an already loaded function and modify the beginning of
1035* the function to jump directly to the new one
1036* example: replace_function("_HelloWorld_start", &replacement_start);
1037*/
1038int replace_function(const char* symbol, void* newAddress)
1039{
1040UInt32* jumpPointer = malloc(sizeof(UInt32*));
1041// TODO: look into using the next four bytes of the function instead
1042// Most functions should support this, as they probably will be at
1043// least 10 bytes long, but you never know, this is sligtly safer as
1044// function can be as small as 6 bytes.
1045UInt32 addr = lookup_all_symbols(symbol);
1046
1047char* binary = (char*)addr;
1048if(addr != 0xFFFFFFFF)
1049{
1050//DBG("Replacing %s to point to 0x%x\n", symbol, newAddress);
1051*binary++ = 0xFF;// Jump
1052*binary++ = 0x25;// Long Jump
1053*((UInt32*)binary) = (UInt32)jumpPointer;
1054
1055*jumpPointer = (UInt32)newAddress;
1056
1057return 1;
1058}
1059else
1060{
1061return 0;
1062}
1063
1064}
1065
1066
1067/*
1068 *execute_hook( const char* name )
1069 *name - Name of the module hook
1070 *If any callbacks have been registered for this hook
1071 *they will be executed now in the same order that the
1072 *hooks were added.
1073*/
1074int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)
1075{
1076DBG("Attempting to execute hook '%s'\n", name); DBGPAUSE();
1077moduleHook_t* hook = hook_exists(name);
1078
1079if(hook)
1080{
1081// Loop through all callbacks for this module
1082callbackList_t* callbacks = hook->callbacks;
1083
1084while(callbacks)
1085{
1086//DBG("Executing '%s' callback at 0x%X.\n", name, callbacks->callback);
1087// Execute callback
1088callbacks->callback(arg1, arg2, arg3, arg4);
1089callbacks = callbacks->next;
1090//DBG("Hook '%s' callback executed, next is 0x%X.\n", name, callbacks);
1091
1092}
1093DBG("Hook '%s' executed.\n", name); DBGPAUSE();
1094return 1;
1095}
1096else
1097{
1098// Callback for this hook doesn't exist;
1099DBG("No callbacks for '%s' hook.\n", name);
1100return 0;
1101}
1102}
1103
1104
1105
1106/*
1107 *register_hook_callback( const char* name, void(*callback)())
1108 *name - Name of the module hook to attach to.
1109 *callbacks - The funciton pointer that will be called when the
1110 *hook is executed. When registering a new callback name, the callback is added sorted.
1111 *NOTE: the hooks take four void* arguments.
1112 */
1113void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))
1114{
1115DBG("Adding callback for '%s' hook.\n", name); DBGPAUSE();
1116
1117moduleHook_t* hook = hook_exists(name);
1118
1119if(hook)
1120{
1121// append
1122callbackList_t* newCallback = malloc(sizeof(callbackList_t));
1123newCallback->next = hook->callbacks;
1124hook->callbacks = newCallback;
1125newCallback->callback = callback;
1126}
1127else
1128{
1129// create new hook
1130moduleHook_t* newHook = malloc(sizeof(moduleHook_t));
1131newHook->name = name;
1132newHook->callbacks = malloc(sizeof(callbackList_t));
1133newHook->callbacks->callback = callback;
1134newHook->callbacks->next = NULL;
1135
1136newHook->next = moduleCallbacks;
1137moduleCallbacks = newHook;
1138
1139}
1140
1141#if DEBUG_MODULES
1142//print_hook_list();
1143//getc();
1144#endif
1145
1146}
1147
1148
1149moduleHook_t* hook_exists(const char* name)
1150{
1151moduleHook_t* hooks = moduleCallbacks;
1152
1153// look for a hook. If it exists, return the moduleHook_t*,
1154// If not, return NULL.
1155while(hooks)
1156{
1157if(strcmp(name, hooks->name) == 0)
1158{
1159//DBG("Located hook %s\n", name);
1160return hooks;
1161}
1162hooks = hooks->next;
1163}
1164//DBG("Hook %s does not exist\n", name);
1165return NULL;
1166
1167}
1168
1169#if DEBUG_MODULES
1170void print_hook_list()
1171{
1172printf("---Hook Table---\n");
1173
1174moduleHook_t* hooks = moduleCallbacks;
1175while(hooks)
1176{
1177printf("Hook: %s\n", hooks->name);
1178hooks = hooks->next;
1179}
1180}
1181#endif
1182
1183/********************************************************************************/
1184/*dyld / Linker Interface*/
1185/********************************************************************************/
1186
1187void dyld_stub_binder()
1188{
1189// TODO: actualy impliment this function (asm)
1190printf("ERROR: dyld_stub_binder was called, should have been take care of by the linker.\n");
1191getc();
1192}
1193

Archive Download this file

Revision: 741