Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/Chazi/i386/boot2/modules.c

1/*
2 * Copyright 2010 Evan Lojewski. All rights reserved.
3 *
4 */
5
6//#include "boot.h"
7#include "libsa.h"
8#include "saio_internal.h"
9//---
10#include "bootstruct.h"
11#include "multiboot.h"
12#include "modules.h"
13
14#ifndef DEBUG_MODULES
15#define DEBUG_MODULES 0
16#endif
17
18#if DEBUG_MODULES
19#define DBG(x...)printf(x); getc()
20#else
21#define DBG(x...)
22#endif
23
24// NOTE: Global so that modules can link with this
25unsigned long long textAddress = 0;
26unsigned long long textSection = 0;
27
28moduleHook_t* moduleCallbacks = NULL;
29moduleList_t* loadedModules = NULL;
30symbolList_t* moduleSymbols = NULL;
31unsigned int (*lookup_symbol)(const char*) = NULL;
32
33
34
35
36
37#if DEBUG_MODULES
38void print_hook_list()
39{
40moduleHook_t* hooks = moduleCallbacks;
41while(hooks)
42{
43printf("Hook: %s\n", hooks->name);
44hooks = hooks->next;
45}
46}
47#endif
48
49/*
50 * Initialize the module system by loading the Symbols.dylib module.
51 * Once laoded, locate the _lookup_symbol function so that internal
52 * symbols can be resolved.
53 */
54int init_module_system()
55{
56// Intialize module system
57if(load_module(SYMBOLS_MODULE))
58{
59lookup_symbol = (void*)lookup_all_symbols(SYMBOL_LOOKUP_SYMBOL);
60
61if((UInt32)lookup_symbol != 0xFFFFFFFF)
62{
63return 1;
64}
65
66}
67
68return 0;
69}
70
71
72/*
73 * Load all modules in the /Extra/modules/ directory
74 * Module depencdies will be loaded first
75 * MOdules will only be loaded once. When loaded a module must
76 * setup apropriete function calls and hooks as required.
77 * NOTE: To ensure a module loads after another you may
78 * link one module with the other. For dyld to allow this, you must
79 * reference at least one symbol within the module.
80 */
81void load_all_modules()
82{
83char* name;
84long flags;
85long time;
86struct dirstuff* moduleDir = opendir("/Extra/modules/");
87while(readdir(moduleDir, (const char**)&name, &flags, &time) >= 0)
88{
89if(strcmp(&name[strlen(name) - sizeof("dylib")], ".dylib") == 0)
90{
91char* tmp = malloc(strlen(name) + 1); // TODO: look into this
92strcpy(tmp, name);
93DBG("Attempting to load %s\n", tmp);
94load_module(tmp);
95}
96else
97{
98DBG("Ignoring %s\n", name);
99}
100
101}
102}
103
104
105/*
106 * Load a module file in /Extra/modules
107 * TODO: verify version number of module
108 */
109int load_module(char* module)
110{
111// Check to see if the module has already been loaded
112if(is_module_laoded(module))
113{
114// NOTE: Symbols.dylib tries to load twice, this catches it as well
115// as when a module links with an already loaded module
116DBG("Module %s already loaded\n", module);
117return 1;
118}
119
120char modString[128];
121int fh = -1;
122sprintf(modString, "/Extra/modules/%s", module);
123fh = open(modString, 0);
124if(fh < 0)
125{
126printf("Unable to locate module %s\n", modString);
127getc();
128return 0;
129}
130
131unsigned int moduleSize = file_size(fh);
132char* module_base = (char*) malloc(moduleSize);
133if (read(fh, module_base, moduleSize) == moduleSize)
134{
135void (*module_start)(void) = NULL;
136
137//printf("Module %s read in.\n", modString);
138
139// Module loaded into memory, parse it
140module_start = parse_mach(module_base, &load_module, &add_symbol);
141
142if(module_start && module_start != (void*)0xFFFFFFFF)
143{
144// Notify the system that it was laoded
145module_loaded(module/*moduleName, moduleVersion, moduleCompat*/);
146(*module_start)();// Start the module
147DBG("Module %s Loaded.\n", module);
148}
149else {
150printf("Unable to start %s\n", module);
151getc();
152}
153}
154else
155{
156printf("Unable to read in module %s\n.", module);
157getc();
158}
159return 1;
160}
161
162/*
163 *execute_hook( const char* name )
164 *name - Name of the module hook
165 *If any callbacks have been registered for this hook
166 *they will be executed now in the same order that the
167 *hooks were added.
168 */
169int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)
170{
171DBG("Attempting to execute hook '%s'\n", name);
172
173if(moduleCallbacks != NULL)
174{
175moduleHook_t* hooks = moduleCallbacks;
176
177while(hooks != NULL && strcmp(name, hooks->name) < 0)
178{
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;
439
440if(dylib_loader && !dylib_loader(module))
441{
442// Unable to load dependancy
443return NULL;
444}
445break;
446
447case LC_ID_DYLIB:
448dylibCommand = binary + binaryIndex;
449/*moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
450moduleVersion =dylibCommand->dylib.current_version;
451moduleCompat =dylibCommand->dylib.compatibility_version;
452 */
453break;
454
455case LC_DYLD_INFO:
456// Bind and rebase info is stored here
457dyldInfoCommand = binary + binaryIndex;
458break;
459
460case LC_UUID:
461break;
462
463case LC_UNIXTHREAD:
464break;
465
466default:
467DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
468break;
469
470}
471
472binaryIndex += cmdSize;
473}
474//if(!moduleName) return NULL;
475
476
477// bind_macho uses the symbols.
478module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);
479
480// Rebase the module before binding it.
481if(dyldInfoCommand && dyldInfoCommand->rebase_off)
482{
483rebase_macho(binary, (char*)dyldInfoCommand->rebase_off, dyldInfoCommand->rebase_size);
484}
485
486if(dyldInfoCommand && dyldInfoCommand->bind_off)
487{
488bind_macho(binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size);
489}
490
491if(dyldInfoCommand && dyldInfoCommand->weak_bind_off)
492{
493// NOTE: this currently should never happen.
494bind_macho(binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size);
495}
496
497if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off)
498{
499// NOTE: we are binding the lazy pointers as a module is laoded,
500// This should be changed to bind when a symbol is referened at runtime instead.
501bind_macho(binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);
502}
503
504return module_start;
505
506}
507
508
509// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
510void rebase_macho(void* base, char* rebase_stream, UInt32 size)
511{
512rebase_stream += (UInt32)base;
513
514UInt8 immediate = 0;
515UInt8 opcode = 0;
516UInt8 type = 0;
517
518UInt32 segmentAddress = 0;
519
520
521
522UInt32 tmp = 0;
523UInt32 tmp2 = 0;
524UInt8 bits = 0;
525int index = 0;
526
527int done = 0;
528unsigned int i = 0;
529
530while(/*!done &&*/ i < size)
531{
532immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
533opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
534
535
536switch(opcode)
537{
538case REBASE_OPCODE_DONE:
539// Rebase complete.
540done = 1;
541break;
542
543
544case REBASE_OPCODE_SET_TYPE_IMM:
545// Set rebase type (pointer, absolute32, pcrel32)
546//printf("Rebase type = 0x%X\n", immediate);
547// NOTE: This is currently NOT used
548type = immediate;
549break;
550
551
552case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
553// Locate address to begin rebasing
554segmentAddress = 0;
555
556
557struct segment_command* segCommand = NULL; // NOTE: 32bit only
558
559unsigned int binIndex = 0;
560index = 0;
561do
562{
563segCommand = base + sizeof(struct mach_header) + binIndex;
564
565
566binIndex += segCommand->cmdsize;
567index++;
568}
569while(index <= immediate);
570
571
572segmentAddress = segCommand->fileoff;
573
574tmp = 0;
575bits = 0;
576do
577{
578tmp |= (rebase_stream[++i] & 0x7f) << bits;
579bits += 7;
580}
581while(rebase_stream[i] & 0x80);
582
583segmentAddress += tmp;
584break;
585
586
587case REBASE_OPCODE_ADD_ADDR_ULEB:
588// Add value to rebase address
589tmp = 0;
590bits = 0;
591do
592{
593tmp <<= bits;
594tmp |= rebase_stream[++i] & 0x7f;
595bits += 7;
596}
597while(rebase_stream[i] & 0x80);
598
599segmentAddress +=tmp;
600break;
601
602case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
603segmentAddress += immediate * sizeof(void*);
604break;
605
606
607case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
608index = 0;
609for (index = 0; index < immediate; ++index) {
610rebase_location(base + segmentAddress, (char*)base);
611segmentAddress += sizeof(void*);
612}
613break;
614
615
616case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
617tmp = 0;
618bits = 0;
619do
620{
621tmp |= (rebase_stream[++i] & 0x7f) << bits;
622bits += 7;
623}
624while(rebase_stream[i] & 0x80);
625
626index = 0;
627for (index = 0; index < tmp; ++index) {
628//DBG("\tRebasing 0x%X\n", segmentAddress);
629rebase_location(base + segmentAddress, (char*)base);
630segmentAddress += sizeof(void*);
631}
632break;
633
634case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
635tmp = 0;
636bits = 0;
637do
638{
639tmp |= (rebase_stream[++i] & 0x7f) << bits;
640bits += 7;
641}
642while(rebase_stream[i] & 0x80);
643
644rebase_location(base + segmentAddress, (char*)base);
645
646segmentAddress += tmp + sizeof(void*);
647break;
648
649case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
650tmp = 0;
651bits = 0;
652do
653{
654tmp |= (rebase_stream[++i] & 0x7f) << bits;
655bits += 7;
656}
657while(rebase_stream[i] & 0x80);
658
659
660tmp2 = 0;
661bits = 0;
662do
663{
664tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
665bits += 7;
666}
667while(rebase_stream[i] & 0x80);
668
669index = 0;
670for (index = 0; index < tmp; ++index) {
671rebase_location(base + segmentAddress, (char*)base);
672
673segmentAddress += tmp2 + sizeof(void*);
674}
675break;
676}
677i++;
678}
679}
680
681// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
682// NOTE: this uses 32bit values, and not 64bit values.
683// There is apossibility that this could cause issues,
684// however the macho file is 32 bit, so it shouldn't matter too much
685void bind_macho(void* base, char* bind_stream, UInt32 size)
686{
687bind_stream += (UInt32)base;
688
689UInt8 immediate = 0;
690UInt8 opcode = 0;
691UInt8 type = 0;
692
693UInt32 segmentAddress = 0;
694
695UInt32 address = 0;
696
697SInt32 addend = 0;// TODO: handle this
698SInt32 libraryOrdinal = 0;
699
700const char* symbolName = NULL;
701UInt8 symboFlags = 0;
702UInt32 symbolAddr = 0xFFFFFFFF;
703
704// Temperary variables
705UInt8 bits = 0;
706UInt32 tmp = 0;
707UInt32 tmp2 = 0;
708
709UInt32 index = 0;
710int done = 0;
711unsigned int i = 0;
712
713while(/*!done &&*/ i < size)
714{
715immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
716opcode = bind_stream[i] & BIND_OPCODE_MASK;
717
718
719switch(opcode)
720{
721case BIND_OPCODE_DONE:
722done = 1;
723break;
724
725case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
726libraryOrdinal = immediate;
727//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);
728break;
729
730case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
731libraryOrdinal = 0;
732bits = 0;
733do
734{
735libraryOrdinal |= (bind_stream[++i] & 0x7f) << bits;
736bits += 7;
737}
738while(bind_stream[i] & 0x80);
739
740//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);
741
742break;
743
744case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
745// NOTE: this is wrong, fortunately we don't use it
746libraryOrdinal = -immediate;
747//DBG("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);
748
749break;
750
751case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
752symboFlags = immediate;
753symbolName = (char*)&bind_stream[++i];
754i += strlen((char*)&bind_stream[i]);
755//DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symboFlags);
756
757symbolAddr = lookup_all_symbols(symbolName);
758
759break;
760
761case BIND_OPCODE_SET_TYPE_IMM:
762// Set bind type (pointer, absolute32, pcrel32)
763type = immediate;
764//DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);
765
766break;
767
768case BIND_OPCODE_SET_ADDEND_SLEB:
769addend = 0;
770bits = 0;
771do
772{
773addend |= (bind_stream[++i] & 0x7f) << bits;
774bits += 7;
775}
776while(bind_stream[i] & 0x80);
777
778if(!(bind_stream[i-1] & 0x40)) addend *= -1;
779
780//DBG("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);
781break;
782
783case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
784segmentAddress = 0;
785
786// Locate address
787struct segment_command* segCommand = NULL;// NOTE: 32bit only
788
789unsigned int binIndex = 0;
790index = 0;
791do
792{
793segCommand = base + sizeof(struct mach_header) + binIndex;
794binIndex += segCommand->cmdsize;
795index++;
796}
797while(index <= immediate);
798
799segmentAddress = segCommand->fileoff;
800
801// Read in offset
802tmp = 0;
803bits = 0;
804do
805{
806tmp |= (bind_stream[++i] & 0x7f) << bits;
807bits += 7;
808}
809while(bind_stream[i] & 0x80);
810
811segmentAddress += tmp;
812
813//DBG("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 0x%X\n", segmentAddress);
814break;
815
816case BIND_OPCODE_ADD_ADDR_ULEB:
817// Read in offset
818tmp = 0;
819bits = 0;
820do
821{
822tmp |= (bind_stream[++i] & 0x7f) << bits;
823bits += 7;
824}
825while(bind_stream[i] & 0x80);
826
827segmentAddress += tmp;
828//DBG("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);
829break;
830
831case BIND_OPCODE_DO_BIND:
832//DBG("BIND_OPCODE_DO_BIND\n");
833if(symbolAddr != 0xFFFFFFFF)
834{
835address = segmentAddress + (UInt32)base;
836
837((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
838((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
839((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
840((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
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
870((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
871((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
872((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
873((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
874}
875else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
876{
877printf("Unable to bind symbol %s\n", symbolName);
878}
879segmentAddress += tmp + sizeof(void*);
880
881
882break;
883
884case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
885//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
886
887if(symbolAddr != 0xFFFFFFFF)
888{
889address = segmentAddress + (UInt32)base;
890
891((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
892((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
893((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
894((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
895}
896else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
897{
898printf("Unable to bind symbol %s\n", symbolName);
899}
900segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
901
902
903break;
904
905case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
906
907tmp = 0;
908bits = 0;
909do
910{
911tmp |= (bind_stream[++i] & 0x7f) << bits;
912bits += 7;
913}
914while(bind_stream[i] & 0x80);
915
916
917tmp2 = 0;
918bits = 0;
919do
920{
921tmp2 |= (bind_stream[++i] & 0x7f) << bits;
922bits += 7;
923}
924while(bind_stream[i] & 0x80);
925
926
927//DBG("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);
928
929
930if(symbolAddr != 0xFFFFFFFF)
931{
932for(index = 0; index < tmp; index++)
933{
934
935address = segmentAddress + (UInt32)base;
936
937((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
938((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
939((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
940((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
941
942segmentAddress += tmp2 + sizeof(void*);
943}
944}
945else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
946{
947printf("Unable to bind symbol %s\n", symbolName);
948}
949
950
951break;
952
953}
954i++;
955}
956}
957
958inline void rebase_location(UInt32* location, char* base)
959{
960*location += (UInt32)base;
961}
962
963/*
964 * add_symbol
965 * This function adds a symbol from a module to the list of known symbols
966 * possibly change to a pointer and add this to the Symbol module so that it can
967 * adjust it's internal symbol list (sort) to optimize locating new symbols
968 * NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF
969 */
970long long add_symbol(char* symbol, long long addr, char is64)
971{
972if(is64) return 0xFFFFFFFF; // Fixme
973
974// This only can handle 32bit symbols
975symbolList_t* entry;
976//DBG("Adding symbol %s at 0x%X\n", symbol, addr);
977
978if(!moduleSymbols)
979{
980moduleSymbols = entry = malloc(sizeof(symbolList_t));
981
982}
983else
984{
985entry = moduleSymbols;
986while(entry->next)
987{
988entry = entry->next;
989}
990
991entry->next = malloc(sizeof(symbolList_t));
992entry = entry->next;
993}
994
995entry->next = NULL;
996entry->addr = (UInt32)addr;
997entry->symbol = symbol;
998
999if(strcmp(symbol, "start") == 0)
1000{
1001return addr;
1002}
1003else
1004{
1005return 0xFFFFFFFF; // fixme
1006}
1007}
1008
1009
1010/*
1011 * print out the information about the loaded module
1012
1013 */
1014void module_loaded(const char* name/*, UInt32 version, UInt32 compat*/)
1015{
1016moduleList_t* entry;
1017/*
1018DBG("\%s.dylib Version %d.%d.%d loaded\n"
1019 "\tCompatibility Version: %d.%d.%d\n",
1020 name,
1021 (version >> 16) & 0xFFFF,
1022 (version >> 8) & 0x00FF,
1023 (version >> 0) & 0x00FF,
1024 (compat >> 16) & 0xFFFF,
1025 (compat >> 8) & 0x00FF,
1026 (compat >> 0) & 0x00FF);
1027*/
1028if(loadedModules == NULL)
1029{
1030loadedModules = entry = malloc(sizeof(moduleList_t));
1031}
1032else
1033{
1034entry = loadedModules;
1035while(entry->next)
1036{
1037entry = entry->next;
1038}
1039entry->next = malloc(sizeof(moduleList_t));
1040entry = entry->next;
1041}
1042
1043entry->next = NULL;
1044entry->module = (char*)name;
1045entry->version = 0; //version;
1046entry->compat = 0; //compat;
1047
1048
1049}
1050
1051int is_module_laoded(const char* name)
1052{
1053moduleList_t* entry = loadedModules;
1054while(entry)
1055{
1056DBG("Comparing %s with %s\n", name, entry->module);
1057if(strcmp(entry->module, name) == 0)
1058{
1059DBG("Located module %s\n", name);
1060return 1;
1061}
1062else
1063{
1064entry = entry->next;
1065}
1066
1067}
1068DBG("Module %s not found\n", name);
1069
1070return 0;
1071}
1072
1073// Look for symbols using the Smbols moduel function.
1074// If non are found, look through the list of module symbols
1075unsigned int lookup_all_symbols(const char* name)
1076{
1077unsigned int addr = 0xFFFFFFFF;
1078if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)
1079{
1080addr = lookup_symbol(name);
1081if(addr != 0xFFFFFFFF)
1082{
1083//DBG("Internal symbol %s located at 0x%X\n", name, addr);
1084return addr;
1085}
1086}
1087
1088
1089symbolList_t* entry = moduleSymbols;
1090while(entry)
1091{
1092if(strcmp(entry->symbol, name) == 0)
1093{
1094//DBG("External symbol %s located at 0x%X\n", name, entry->addr);
1095return entry->addr;
1096}
1097else
1098{
1099entry = entry->next;
1100}
1101
1102}
1103if(strcmp(name, SYMBOL_DYLD_STUB_BINDER) != 0)
1104{
1105printf("Unable to locate symbol %s\n", name);
1106getc();
1107}
1108return 0xFFFFFFFF;
1109}
1110
1111
1112/*
1113 * parse the symbol table
1114 * Lookup any undefined symbols
1115 */
1116
1117unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)
1118{
1119// TODO: verify that the _TEXT,_text segment starts at the same locaiton in the file. If not
1120//subtract the vmaddress and add the actual file address back on. (NOTE: if compiled properly, not needed)
1121
1122unsigned int module_start = 0xFFFFFFFF;
1123
1124UInt32 symbolIndex = 0;
1125char* symbolString = base + (char*)symtabCommand->stroff;
1126//char* symbolTable = base + symtabCommand->symoff;
1127if(!is64)
1128{
1129struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
1130while(symbolIndex < symtabCommand->nsyms)
1131{
1132// If the symbol is exported by this module
1133if(symbolEntry->n_value &&
1134 symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)
1135{
1136
1137// Module start located. Start is an alias so don't register it
1138module_start = base + symbolEntry->n_value;
1139}
1140
1141symbolEntry++;
1142symbolIndex++;// TODO remove
1143}
1144}
1145else
1146{
1147struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
1148// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)
1149while(symbolIndex < symtabCommand->nsyms)
1150{
1151
1152
1153// If the symbol is exported by this module
1154if(symbolEntry->n_value &&
1155 symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)
1156{
1157
1158// Module start located. Start is an alias so don't register it
1159module_start = base + symbolEntry->n_value;
1160}
1161
1162symbolEntry++;
1163symbolIndex++;// TODO remove
1164}
1165}
1166
1167return module_start;
1168
1169}
1170
1171
1172/*
1173 * Locate the symbol for an already loaded function and modify the beginning of
1174 * the function to jump directly to the new one
1175 * example: replace_function("_HelloWorld_start", &replacement_start);
1176 */
1177int replace_function(const char* symbol, void* newAddress)
1178{
1179UInt32* jumpPointer = malloc(sizeof(UInt32*));
1180// TODO: look into using the next four bytes of the function instead
1181// Most functions should support this, as they probably will be at
1182// least 10 bytes long, but you never know, this is sligtly safer as
1183// function can be as small as 6 bytes.
1184UInt32 addr = lookup_all_symbols(symbol);
1185
1186char* binary = (char*)addr;
1187if(addr != 0xFFFFFFFF)
1188{
1189*binary++ = 0xFF;// Jump
1190*binary++ = 0x25;// Long Jump
1191*((UInt32*)binary) = (UInt32)jumpPointer;
1192
1193*jumpPointer = (UInt32)newAddress;
1194
1195return 1;
1196}
1197else
1198{
1199return 0;
1200}
1201
1202}

Archive Download this file

Revision: 497