Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 444