Chameleon

Chameleon Svn Source Tree

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

Source at commit 532 created 13 years 7 months ago.
By meklort, More module changes, temperary hack to disable static variables in modules until I get it fixed.
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//getc();
549// NOTE: This is currently NOT used
550type = immediate;
551break;
552
553
554case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
555// Locate address to begin rebasing
556segmentAddress = 0;
557
558
559struct segment_command* segCommand = NULL; // NOTE: 32bit only
560
561unsigned int binIndex = 0;
562index = 0;
563do
564{
565segCommand = base + sizeof(struct mach_header) + binIndex;
566
567
568binIndex += segCommand->cmdsize;
569index++;
570}
571while(index <= immediate);
572
573
574segmentAddress = segCommand->fileoff;
575
576tmp = 0;
577bits = 0;
578do
579{
580tmp |= (rebase_stream[++i] & 0x7f) << bits;
581bits += 7;
582}
583while(rebase_stream[i] & 0x80);
584
585segmentAddress += tmp;
586break;
587
588
589case REBASE_OPCODE_ADD_ADDR_ULEB:
590// Add value to rebase address
591tmp = 0;
592bits = 0;
593do
594{
595tmp <<= bits;
596tmp |= rebase_stream[++i] & 0x7f;
597bits += 7;
598}
599while(rebase_stream[i] & 0x80);
600
601segmentAddress +=tmp;
602break;
603
604case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
605segmentAddress += immediate * sizeof(void*);
606break;
607
608
609case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
610index = 0;
611for (index = 0; index < immediate; ++index) {
612rebase_location(base + segmentAddress, (char*)base, type);
613segmentAddress += sizeof(void*);
614}
615break;
616
617
618case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
619tmp = 0;
620bits = 0;
621do
622{
623tmp |= (rebase_stream[++i] & 0x7f) << bits;
624bits += 7;
625}
626while(rebase_stream[i] & 0x80);
627
628index = 0;
629for (index = 0; index < tmp; ++index) {
630//DBG("\tRebasing 0x%X\n", segmentAddress);
631rebase_location(base + segmentAddress, (char*)base, type);
632segmentAddress += sizeof(void*);
633}
634break;
635
636case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
637tmp = 0;
638bits = 0;
639do
640{
641tmp |= (rebase_stream[++i] & 0x7f) << bits;
642bits += 7;
643}
644while(rebase_stream[i] & 0x80);
645
646rebase_location(base + segmentAddress, (char*)base, type);
647
648segmentAddress += tmp + sizeof(void*);
649break;
650
651case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
652tmp = 0;
653bits = 0;
654do
655{
656tmp |= (rebase_stream[++i] & 0x7f) << bits;
657bits += 7;
658}
659while(rebase_stream[i] & 0x80);
660
661
662tmp2 = 0;
663bits = 0;
664do
665{
666tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
667bits += 7;
668}
669while(rebase_stream[i] & 0x80);
670
671index = 0;
672for (index = 0; index < tmp; ++index) {
673
674rebase_location(base + segmentAddress, (char*)base, type);
675
676segmentAddress += tmp2 + sizeof(void*);
677}
678break;
679}
680i++;
681}
682}
683
684// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
685// NOTE: this uses 32bit values, and not 64bit values.
686// There is apossibility that this could cause issues,
687// however the macho file is 32 bit, so it shouldn't matter too much
688void bind_macho(void* base, char* bind_stream, UInt32 size)
689{
690bind_stream += (UInt32)base;
691
692UInt8 immediate = 0;
693UInt8 opcode = 0;
694UInt8 type = 0;
695
696UInt32 segmentAddress = 0;
697
698UInt32 address = 0;
699
700SInt32 addend = 0;// TODO: handle this
701SInt32 libraryOrdinal = 0;
702
703const char* symbolName = NULL;
704UInt8 symboFlags = 0;
705UInt32 symbolAddr = 0xFFFFFFFF;
706
707// Temperary variables
708UInt8 bits = 0;
709UInt32 tmp = 0;
710UInt32 tmp2 = 0;
711
712UInt32 index = 0;
713int done = 0;
714unsigned int i = 0;
715
716while(/*!done &&*/ i < size)
717{
718immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
719opcode = bind_stream[i] & BIND_OPCODE_MASK;
720
721
722switch(opcode)
723{
724case BIND_OPCODE_DONE:
725done = 1;
726break;
727
728case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
729libraryOrdinal = immediate;
730//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);
731break;
732
733case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
734libraryOrdinal = 0;
735bits = 0;
736do
737{
738libraryOrdinal |= (bind_stream[++i] & 0x7f) << bits;
739bits += 7;
740}
741while(bind_stream[i] & 0x80);
742
743//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);
744
745break;
746
747case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
748// NOTE: this is wrong, fortunately we don't use it
749libraryOrdinal = -immediate;
750//DBG("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);
751
752break;
753
754case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
755symboFlags = immediate;
756symbolName = (char*)&bind_stream[++i];
757i += strlen((char*)&bind_stream[i]);
758//DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symboFlags);
759
760symbolAddr = lookup_all_symbols(symbolName);
761
762break;
763
764case BIND_OPCODE_SET_TYPE_IMM:
765// Set bind type (pointer, absolute32, pcrel32)
766type = immediate;
767//DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);
768
769break;
770
771case BIND_OPCODE_SET_ADDEND_SLEB:
772addend = 0;
773bits = 0;
774do
775{
776addend |= (bind_stream[++i] & 0x7f) << bits;
777bits += 7;
778}
779while(bind_stream[i] & 0x80);
780
781if(!(bind_stream[i-1] & 0x40)) addend *= -1;
782
783//DBG("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);
784break;
785
786case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
787segmentAddress = 0;
788
789// Locate address
790struct segment_command* segCommand = NULL;// NOTE: 32bit only
791
792unsigned int binIndex = 0;
793index = 0;
794do
795{
796segCommand = base + sizeof(struct mach_header) + binIndex;
797binIndex += segCommand->cmdsize;
798index++;
799}
800while(index <= immediate);
801
802segmentAddress = segCommand->fileoff;
803
804// Read in offset
805tmp = 0;
806bits = 0;
807do
808{
809tmp |= (bind_stream[++i] & 0x7f) << bits;
810bits += 7;
811}
812while(bind_stream[i] & 0x80);
813
814segmentAddress += tmp;
815
816//DBG("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 0x%X\n", segmentAddress);
817break;
818
819case BIND_OPCODE_ADD_ADDR_ULEB:
820// Read in offset
821tmp = 0;
822bits = 0;
823do
824{
825tmp |= (bind_stream[++i] & 0x7f) << bits;
826bits += 7;
827}
828while(bind_stream[i] & 0x80);
829
830segmentAddress += tmp;
831//DBG("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);
832break;
833
834case BIND_OPCODE_DO_BIND:
835//DBG("BIND_OPCODE_DO_BIND\n");
836if(symbolAddr != 0xFFFFFFFF)
837{
838address = segmentAddress + (UInt32)base;
839
840bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
841}
842else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
843{
844printf("Unable to bind symbol %s\n", symbolName);
845}
846
847segmentAddress += sizeof(void*);
848break;
849
850case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
851//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");
852
853
854// Read in offset
855tmp = 0;
856bits = 0;
857do
858{
859tmp |= (bind_stream[++i] & 0x7f) << bits;
860bits += 7;
861}
862while(bind_stream[i] & 0x80);
863
864
865
866if(symbolAddr != 0xFFFFFFFF)
867{
868address = segmentAddress + (UInt32)base;
869
870bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
871}
872else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
873{
874printf("Unable to bind symbol %s\n", symbolName);
875}
876segmentAddress += tmp + sizeof(void*);
877
878
879break;
880
881case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
882//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
883
884if(symbolAddr != 0xFFFFFFFF)
885{
886address = segmentAddress + (UInt32)base;
887
888bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
889}
890else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
891{
892printf("Unable to bind symbol %s\n", symbolName);
893}
894segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
895
896
897break;
898
899case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
900
901tmp = 0;
902bits = 0;
903do
904{
905tmp |= (bind_stream[++i] & 0x7f) << bits;
906bits += 7;
907}
908while(bind_stream[i] & 0x80);
909
910
911tmp2 = 0;
912bits = 0;
913do
914{
915tmp2 |= (bind_stream[++i] & 0x7f) << bits;
916bits += 7;
917}
918while(bind_stream[i] & 0x80);
919
920
921//DBG("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);
922
923
924if(symbolAddr != 0xFFFFFFFF)
925{
926for(index = 0; index < tmp; index++)
927{
928
929address = segmentAddress + (UInt32)base;
930
931bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
932
933segmentAddress += tmp2 + sizeof(void*);
934}
935}
936else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
937{
938printf("Unable to bind symbol %s\n", symbolName);
939}
940
941
942break;
943
944}
945i++;
946}
947}
948
949inline void rebase_location(UInt32* location, char* base, int type)
950{
951switch(type)
952{
953case REBASE_TYPE_POINTER:
954case REBASE_TYPE_TEXT_ABSOLUTE32:
955*location += (UInt32)base;
956break;
957
958default:
959break;
960}
961}
962
963inline void bind_location(UInt32* location, char* value, UInt32 addend, int type)
964{
965// do actual update
966char* newValue = value + addend;
967
968switch (type) {
969case BIND_TYPE_POINTER:
970case BIND_TYPE_TEXT_ABSOLUTE32:
971break;
972
973case BIND_TYPE_TEXT_PCREL32:
974newValue -= ((UInt32)location + 4);
975
976break;
977default:
978return;
979}
980*location = (UInt32)newValue;
981
982
983}
984
985
986/*
987 * add_symbol
988 * This function adds a symbol from a module to the list of known symbols
989 * possibly change to a pointer and add this to the Symbol module so that it can
990 * adjust it's internal symbol list (sort) to optimize locating new symbols
991 * NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF
992 */
993long long add_symbol(char* symbol, long long addr, char is64)
994{
995if(is64) return 0xFFFFFFFF; // Fixme
996
997// This only can handle 32bit symbols
998symbolList_t* entry;
999//DBG("Adding symbol %s at 0x%X\n", symbol, addr);
1000
1001if(!moduleSymbols)
1002{
1003moduleSymbols = entry = malloc(sizeof(symbolList_t));
1004
1005}
1006else
1007{
1008entry = moduleSymbols;
1009while(entry->next)
1010{
1011entry = entry->next;
1012}
1013
1014entry->next = malloc(sizeof(symbolList_t));
1015entry = entry->next;
1016}
1017
1018entry->next = NULL;
1019entry->addr = (UInt32)addr;
1020entry->symbol = symbol;
1021
1022if(strcmp(symbol, "start") == 0)
1023{
1024return addr;
1025}
1026else
1027{
1028return 0xFFFFFFFF; // fixme
1029}
1030}
1031
1032
1033/*
1034 * print out the information about the loaded module
1035
1036 */
1037void module_loaded(const char* name/*, UInt32 version, UInt32 compat*/)
1038{
1039moduleList_t* entry;
1040/*
1041DBG("\%s.dylib Version %d.%d.%d loaded\n"
1042 "\tCompatibility Version: %d.%d.%d\n",
1043 name,
1044 (version >> 16) & 0xFFFF,
1045 (version >> 8) & 0x00FF,
1046 (version >> 0) & 0x00FF,
1047 (compat >> 16) & 0xFFFF,
1048 (compat >> 8) & 0x00FF,
1049 (compat >> 0) & 0x00FF);
1050*/
1051if(loadedModules == NULL)
1052{
1053loadedModules = entry = malloc(sizeof(moduleList_t));
1054}
1055else
1056{
1057entry = loadedModules;
1058while(entry->next)
1059{
1060entry = entry->next;
1061}
1062entry->next = malloc(sizeof(moduleList_t));
1063entry = entry->next;
1064}
1065
1066entry->next = NULL;
1067entry->module = (char*)name;
1068entry->version = 0; //version;
1069entry->compat = 0; //compat;
1070
1071
1072}
1073
1074int is_module_loaded(const char* name)
1075{
1076moduleList_t* entry = loadedModules;
1077while(entry)
1078{
1079DBG("Comparing %s with %s\n", name, entry->module);
1080if(strcmp(entry->module, name) == 0)
1081{
1082DBG("Located module %s\n", name);
1083return 1;
1084}
1085else
1086{
1087entry = entry->next;
1088}
1089
1090}
1091DBG("Module %s not found\n", name);
1092
1093return 0;
1094}
1095
1096// Look for symbols using the Smbols moduel function.
1097// If non are found, look through the list of module symbols
1098unsigned int lookup_all_symbols(const char* name)
1099{
1100unsigned int addr = 0xFFFFFFFF;
1101if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)
1102{
1103addr = lookup_symbol(name);
1104if(addr != 0xFFFFFFFF)
1105{
1106//DBG("Internal symbol %s located at 0x%X\n", name, addr);
1107return addr;
1108}
1109}
1110
1111
1112symbolList_t* entry = moduleSymbols;
1113while(entry)
1114{
1115if(strcmp(entry->symbol, name) == 0)
1116{
1117//DBG("External symbol %s located at 0x%X\n", name, entry->addr);
1118return entry->addr;
1119}
1120else
1121{
1122entry = entry->next;
1123}
1124
1125}
1126if(strcmp(name, SYMBOL_DYLD_STUB_BINDER) != 0)
1127{
1128printf("Unable to locate symbol %s\n", name);
1129getc();
1130}
1131return 0xFFFFFFFF;
1132}
1133
1134
1135/*
1136 * parse the symbol table
1137 * Lookup any undefined symbols
1138 */
1139
1140unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)
1141{
1142// TODO: verify that the _TEXT,_text segment starts at the same locaiton in the file. If not
1143//subtract the vmaddress and add the actual file address back on. (NOTE: if compiled properly, not needed)
1144
1145unsigned int module_start = 0xFFFFFFFF;
1146
1147UInt32 symbolIndex = 0;
1148char* symbolString = base + (char*)symtabCommand->stroff;
1149//char* symbolTable = base + symtabCommand->symoff;
1150if(!is64)
1151{
1152struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
1153while(symbolIndex < symtabCommand->nsyms)
1154{
1155// If the symbol is exported by this module
1156if(symbolEntry->n_value &&
1157 symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)
1158{
1159
1160// Module start located. Start is an alias so don't register it
1161module_start = base + symbolEntry->n_value;
1162}
1163
1164symbolEntry++;
1165symbolIndex++;// TODO remove
1166}
1167}
1168else
1169{
1170struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
1171// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)
1172while(symbolIndex < symtabCommand->nsyms)
1173{
1174
1175
1176// If the symbol is exported by this module
1177if(symbolEntry->n_value &&
1178 symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)
1179{
1180
1181// Module start located. Start is an alias so don't register it
1182module_start = base + symbolEntry->n_value;
1183}
1184
1185symbolEntry++;
1186symbolIndex++;// TODO remove
1187}
1188}
1189
1190return module_start;
1191
1192}
1193
1194
1195/*
1196 * Locate the symbol for an already loaded function and modify the beginning of
1197 * the function to jump directly to the new one
1198 * example: replace_function("_HelloWorld_start", &replacement_start);
1199 */
1200int replace_function(const char* symbol, void* newAddress)
1201{
1202UInt32* jumpPointer = malloc(sizeof(UInt32*));
1203// TODO: look into using the next four bytes of the function instead
1204// Most functions should support this, as they probably will be at
1205// least 10 bytes long, but you never know, this is sligtly safer as
1206// function can be as small as 6 bytes.
1207UInt32 addr = lookup_all_symbols(symbol);
1208
1209char* binary = (char*)addr;
1210if(addr != 0xFFFFFFFF)
1211{
1212*binary++ = 0xFF;// Jump
1213*binary++ = 0x25;// Long Jump
1214*((UInt32*)binary) = (UInt32)jumpPointer;
1215
1216*jumpPointer = (UInt32)newAddress;
1217
1218return 1;
1219}
1220else
1221{
1222return 0;
1223}
1224
1225}

Archive Download this file

Revision: 532