Chameleon

Chameleon Svn Source Tree

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

Source at commit 430 created 13 years 7 months ago.
By meklort, Removed unused code left over from before rebinding. Modified then handel_symtab function so that it can be used within the kernel patcher module. This is untested, other than to make sure it boots.
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);
1010}
1011return 0xFFFFFFFF;
1012}
1013
1014
1015/*
1016 * parse the symbol table
1017 * Lookup any undefined symbols
1018 */
1019
1020unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, void*(*symbol_handler)(char*, void*))
1021{
1022unsigned int module_start = 0xFFFFFFFF;
1023
1024UInt32 symbolIndex = 0;
1025char* symbolString = base + (char*)symtabCommand->stroff;
1026//char* symbolTable = base + symtabCommand->symoff;
1027
1028while(symbolIndex < symtabCommand->nsyms)
1029{
1030
1031struct nlist* symbolEntry = (void*)base + symtabCommand->symoff + (symbolIndex * sizeof(struct nlist));
1032
1033// If the symbol is exported by this module
1034if(symbolEntry->n_value &&
1035 symbol_handler(symbolString + symbolEntry->n_un.n_strx, (void*)base + symbolEntry->n_value) != (void*)0xFFFFFFFF)
1036{
1037
1038// Module start located. Start is an alias so don't register it
1039module_start = base + symbolEntry->n_value;
1040}
1041
1042symbolEntry+= sizeof(struct nlist);
1043symbolIndex++;// TODO remove
1044}
1045
1046return module_start;
1047
1048}
1049
1050
1051/*
1052 * Locate the symbol for an already loaded function and modify the beginning of
1053 * the function to jump directly to the new one
1054 * example: replace_function("_HelloWorld_start", &replacement_start);
1055 */
1056int replace_function(const char* symbol, void* newAddress)
1057{
1058UInt32* jumpPointer = malloc(sizeof(UInt32*));
1059// TODO: look into using the next four bytes of the function instead
1060// Most functions should support this, as they probably will be at
1061// least 10 bytes long, but you never know, this is sligtly safer as
1062// function can be as small as 6 bytes.
1063UInt32 addr = lookup_all_symbols(symbol);
1064
1065char* binary = (char*)addr;
1066if(addr != 0xFFFFFFFF)
1067{
1068*binary++ = 0xFF;// Jump
1069*binary++ = 0x25;// Long Jump
1070*((UInt32*)binary) = (UInt32)jumpPointer;
1071
1072*jumpPointer = (UInt32)newAddress;
1073
1074return 1;
1075}
1076else
1077{
1078return 0;
1079}
1080
1081}

Archive Download this file

Revision: 430