Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 531