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#include "bootstruct.h"
10#include "multiboot.h"
11#include "modules.h"
12
13#ifndef DEBUG_MODULES
14#define DEBUG_MODULES 0
15#endif
16
17#if DEBUG_MODULES
18#define DBG(x...)printf(x); getc()
19#else
20#define DBG(x...)
21#endif
22
23// NOTE: Global so that modules can link with this
24unsigned long long textAddress = 0;
25unsigned long long textSection = 0;
26
27moduleHook_t* moduleCallbacks = NULL;
28moduleList_t* loadedModules = NULL;
29symbolList_t* moduleSymbols = NULL;
30unsigned int (*lookup_symbol)(const char*) = NULL;
31
32
33
34
35
36#if DEBUG_MODULES
37void print_hook_list()
38{
39moduleHook_t* hooks = moduleCallbacks;
40while(hooks)
41{
42printf("Hook: %s\n", hooks->name);
43hooks = hooks->next;
44}
45}
46#endif
47
48/*
49 * Initialize the module system by loading the Symbols.dylib module.
50 * Once laoded, locate the _lookup_symbol function so that internal
51 * symbols can be resolved.
52 */
53int init_module_system()
54{
55// Intialize module system
56if (load_module(SYMBOLS_MODULE))
57{
58lookup_symbol = (void*)lookup_all_symbols(SYMBOL_LOOKUP_SYMBOL);
59
60if ((UInt32)lookup_symbol != 0xFFFFFFFF)
61{
62return 1;
63}
64
65}
66
67return 0;
68}
69
70
71/*
72 * Load all modules in the /Extra/modules/ directory
73 * Module depencdies will be loaded first
74 * MOdules will only be loaded once. When loaded a module must
75 * setup apropriete function calls and hooks as required.
76 * NOTE: To ensure a module loads after another you may
77 * link one module with the other. For dyld to allow this, you must
78 * reference at least one symbol within the module.
79 */
80void load_all_modules() // called on boot.c
81{
82char* name;
83long flags;
84long time;
85//Azi: Modules.txt-->Issues
86struct dirstuff* moduleDir = opendir("bt(0,0)/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_loaded(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;
122//Azi: Modules.txt-->Issues
123sprintf(modString, "bt(0,0)/Extra/modules/%s", module);
124fh = open(modString, 0);
125if(fh < 0)
126{
127printf("Unable to locate module %s\n", modString);
128getc();
129return 0;
130}
131
132unsigned int moduleSize = file_size(fh);
133char* module_base = (char*) malloc(moduleSize);
134if (read(fh, module_base, moduleSize) == moduleSize)
135{
136void (*module_start)(void) = NULL;
137
138//printf("Module %s read in.\n", modString);
139
140// Module loaded into memory, parse it
141module_start = parse_mach(module_base, &load_module, &add_symbol);
142
143if(module_start && module_start != (void*)0xFFFFFFFF)
144{
145// Notify the system that it was laoded
146module_loaded(module/*moduleName, moduleVersion, moduleCompat*/);
147(*module_start)();// Start the module
148DBG("Module %s Loaded.\n", module);
149}
150else {
151printf("Unable to start %s\n", module);
152getc();
153}
154}
155else
156{
157printf("Unable to read in module %s\n.", module);
158getc();
159}
160return 1;
161}
162
163/*
164 *execute_hook( const char* name )
165 *name - Name of the module hook
166 *If any callbacks have been registered for this hook
167 *they will be executed now in the same order that the
168 *hooks were added.
169 */
170int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)
171{
172DBG("Attempting to execute hook '%s'\n", name);
173
174if(moduleCallbacks != NULL)
175{
176moduleHook_t* hooks = moduleCallbacks;
177
178while(hooks != NULL && strcmp(name, hooks->name) < 0)
179{
180hooks = hooks->next;
181}
182
183if(strcmp(name, hooks->name) == 0)
184{
185// Loop through all callbacks for this module
186callbackList_t* callbacks = hooks->callbacks;
187
188while(callbacks)
189{
190// Execute callback
191callbacks->callback(arg1, arg2, arg3, arg4);
192callbacks = callbacks->next;
193}
194DBG("Hook '%s' executed.\n", name);
195
196return 1;
197}
198else
199{
200DBG("No callbacks for '%s' hook.\n", name);
201
202// Callbaack for this module doesn't exist;
203//verbose("Unable execute hook '%s', no callbacks registered.\n", name);
204//pause();
205return 0;
206}
207
208
209}
210DBG("No hooks have been registered.\n", name);
211return 0;
212}
213
214
215
216/*
217 *register_hook_callback( const char* name, void(*callback)())
218 *name - Name of the module hook to attach to.
219 *callbacks - The funciton pointer that will be called when the
220 *hook is executed. When registering a new callback name, the callback is added sorted.
221 *NOTE: the hooks take four void* arguments.
222 *TODO: refactor
223 */
224void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))
225{
226DBG("Registering %s\n", name);
227// Locate Module hook
228if(moduleCallbacks == NULL)
229{
230moduleCallbacks = malloc(sizeof(moduleHook_t));
231moduleCallbacks->next = NULL;
232moduleCallbacks->name = name;
233// Initialize hook list
234moduleCallbacks->callbacks = (callbackList_t*)malloc(sizeof(callbackList_t));
235moduleCallbacks->callbacks->callback = callback;
236moduleCallbacks->callbacks->next = NULL;
237}
238else
239{
240moduleHook_t* hooks = moduleCallbacks;
241moduleHook_t* newHook = malloc(sizeof(moduleHook_t));;
242
243while(hooks->next != NULL && strcmp(name, hooks->name) < 0)
244{
245hooks = hooks->next;
246}
247
248DBG("%s cmp %s = %d\n", name, hooks->name, strcmp(name, hooks->name));
249
250if(hooks == NULL)
251{
252newHook->next = moduleCallbacks;
253moduleCallbacks = newHook;
254newHook->name = name;
255newHook->callbacks = (callbackList_t*)malloc(sizeof(callbackList_t));
256newHook->callbacks->callback = callback;
257newHook->callbacks->next = NULL;
258
259}
260else if(strcmp(name, hooks->name) != 0)
261{
262newHook->next = hooks->next;
263hooks->next = newHook;
264
265newHook->name = name;
266newHook->callbacks = (callbackList_t*)malloc(sizeof(callbackList_t));
267newHook->callbacks->callback = callback;
268newHook->callbacks->next = NULL;
269}
270else
271{
272callbackList_t* callbacks = hooks->callbacks;
273while(callbacks->next != NULL)
274{
275callbacks = callbacks->next;
276}
277// Add new entry to end of hook list.
278callbacks->next = (callbackList_t*)malloc(sizeof(callbackList_t));
279callbacks = callbacks->next;
280callbacks->next = NULL;
281callbacks->callback = callback;
282
283}
284}
285#if DEBUG_MODULES
286print_hook_list();
287getc();
288#endif
289
290}
291
292
293/*
294 * Parse through a macho module. The module will be rebased and binded
295 * as specified in the macho header. If the module is sucessfuly laoded
296 * the module iinit address will be returned.
297 * NOTE; all dependecies will be loaded before this module is started
298 * NOTE: If the module is unable to load ot completeion, the modules
299 * symbols will still be available (TODO: fix this). This should not
300 * happen as all dependencies are verified before the sybols are read in.
301 */
302void* parse_mach(void* binary, int(*dylib_loader)(char*), long long(*symbol_handler)(char*, long long, char))// TODO: add param to specify valid archs
303{
304char is64 = false;
305void (*module_start)(void) = NULL;
306
307// Module info
308/*char* moduleName = NULL;
309UInt32 moduleVersion = 0;
310UInt32 moduleCompat = 0;
311*/
312// TODO convert all of the structs to a union
313struct load_command *loadCommand = NULL;
314struct dylib_command* dylibCommand = NULL;
315struct dyld_info_command* dyldInfoCommand = NULL;
316
317struct symtab_command* symtabCommand = NULL;
318struct segment_command *segCommand = NULL;
319struct segment_command_64 *segCommand64 = NULL;
320
321//struct dysymtab_command* dysymtabCommand = NULL;
322UInt32 binaryIndex = 0;
323UInt16 cmd = 0;
324
325// Parse through the load commands
326if(((struct mach_header*)binary)->magic == MH_MAGIC)
327{
328is64 = 0;
329binaryIndex += sizeof(struct mach_header);
330}
331else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
332{
333// NOTE: modules cannot be 64bit...
334is64 = 1;
335binaryIndex += sizeof(struct mach_header_64);
336}
337else
338{
339printf("Invalid mach magic\n");
340getc();
341return NULL;
342}
343
344
345
346/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
347{
348printf("Module is not a dylib. Unable to load.\n");
349getc();
350return NULL; // Module is in the incorrect format
351}*/
352
353while(cmd < ((struct mach_header*)binary)->ncmds)// TODO: for loop instead
354{
355cmd++;
356
357loadCommand = binary + binaryIndex;
358UInt32 cmdSize = loadCommand->cmdsize;
359
360
361switch ((loadCommand->cmd & 0x7FFFFFFF))
362{
363case LC_SYMTAB:
364symtabCommand = binary + binaryIndex;
365break;
366
367case LC_SEGMENT: // 32bit macho
368segCommand = binary + binaryIndex;
369
370//printf("Segment name is %s\n", segCommand->segname);
371
372if(strcmp("__TEXT", segCommand->segname) == 0)
373{
374UInt32 sectionIndex;
375
376sectionIndex = sizeof(struct segment_command);
377
378struct section *sect;
379
380while(sectionIndex < segCommand->cmdsize)
381{
382sect = binary + binaryIndex + sectionIndex;
383
384sectionIndex += sizeof(struct section);
385
386
387if(strcmp("__text", sect->sectname) == 0)
388{
389// __TEXT,__text found, save the offset and address for when looking for the calls.
390textSection = sect->offset;
391textAddress = sect->addr;
392break;
393}
394}
395}
396break;
397case LC_SEGMENT_64:// 64bit macho's
398segCommand64 = binary + binaryIndex;
399
400//printf("Segment name is %s\n", segCommand->segname);
401
402if(strcmp("__TEXT", segCommand64->segname) == 0)
403{
404UInt32 sectionIndex;
405
406sectionIndex = sizeof(struct segment_command_64);
407
408struct section_64 *sect;
409
410while(sectionIndex < segCommand64->cmdsize)
411{
412sect = binary + binaryIndex + sectionIndex;
413
414sectionIndex += sizeof(struct section_64);
415
416
417if(strcmp("__text", sect->sectname) == 0)
418{
419// __TEXT,__text found, save the offset and address for when looking for the calls.
420textSection = sect->offset;
421textAddress = sect->addr;
422
423break;
424}
425}
426}
427
428break;
429
430case LC_DYSYMTAB:
431break;
432
433case LC_LOAD_DYLIB:
434case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
435dylibCommand = binary + binaryIndex;
436char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
437// TODO: verify version
438// =dylibCommand->dylib.current_version;
439// =dylibCommand->dylib.compatibility_version;
440
441if(dylib_loader && !dylib_loader(module))
442{
443// Unable to load dependancy
444return 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: 515