Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 522