Chameleon

Chameleon Svn Source Tree

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

Source at commit 429 created 13 years 7 months ago.
By meklort, Updated module system. Hooks can now be used within modules when cetaion functions are called in chameleon. Note that onle two hooks currently exist, more need to be added. I also updated the HelloWorld module to use a hook instead of print out right away.
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
299char* symbolStub = NULL;
300char* nonlazy = NULL;
301//char* nonlazy_variables = NULL;
302
303// TODO convert all of the structs to a union
304struct load_command *loadCommand = NULL;
305struct dylib_command* dylibCommand = NULL;
306struct dyld_info_command* dyldInfoCommand = NULL;
307struct symtab_command* symtabCommand = NULL;
308struct segment_command* segmentCommand = NULL;
309//struct dysymtab_command* dysymtabCommand = NULL;
310struct section* section = NULL;
311UInt32 binaryIndex = sizeof(struct mach_header);
312UInt16 cmd = 0;
313
314// Parse through the load commands
315if(((struct mach_header*)binary)->magic != MH_MAGIC)
316{
317printf("Module is not 32bit\n");
318getc();
319return NULL;// 32bit only
320}
321
322if(((struct mach_header*)binary)->filetype != MH_DYLIB)
323{
324printf("Module is not a dylib. Unable to load.\n");
325getc();
326return NULL; // Module is in the incorrect format
327}
328
329while(cmd < ((struct mach_header*)binary)->ncmds)// TODO: for loop instead
330{
331cmd++;
332
333loadCommand = binary + binaryIndex;
334UInt32 cmdSize = loadCommand->cmdsize;
335
336
337switch ((loadCommand->cmd & 0x7FFFFFFF))
338{
339case LC_SYMTAB:
340symtabCommand = binary + binaryIndex;
341break;
342case LC_SEGMENT:
343segmentCommand = binary + binaryIndex;
344
345UInt32 sections = segmentCommand->nsects;
346section = binary + binaryIndex + sizeof(struct segment_command);
347
348// Loop untill needed variables are found
349while(!(nonlazy && symbolStub) && sections)
350{
351// Look for some sections and save the addresses
352if(strcmp(section->sectname, SECT_NON_LAZY_SYMBOL_PTR) == 0)
353{
354/*printf("\tSection non lazy pointers at 0x%X, %d symbols\n",
355 section->offset,
356 section->size / 4);
357*/
358switch(section->flags)
359{
360case S_NON_LAZY_SYMBOL_POINTERS:
361//printf("%s S_NON_LAZY_SYMBOL_POINTERS section\n", SECT_NON_LAZY_SYMBOL_PTR);
362
363//nonlazy_variables = binary + section->offset;
364nonlazy = binary + section->offset;
365break;
366
367case S_LAZY_SYMBOL_POINTERS:
368// NOTE: Theses currently are not handled.
369//nonlazy = binary + section->offset;
370//printf("%s S_LAZY_SYMBOL_POINTERS section, 0x%X\n", SECT_NON_LAZY_SYMBOL_PTR, nonlazy);
371// Fucntions
372break;
373
374default:
375//printf("Unhandled %s section\n", SECT_NON_LAZY_SYMBOL_PTR);
376//getc();
377break;
378}
379//getc();
380}
381else if(strcmp(section->sectname, SECT_SYMBOL_STUBS) == 0)
382{
383symbolStub = binary + section->offset;
384}
385/*
386else
387{
388printf("Unhandled section %s\n", section->sectname);
389}
390*/
391sections--;
392section++;
393}
394
395
396break;
397
398case LC_DYSYMTAB:
399//dysymtabCommand = binary + binaryIndex;
400//printf("Unhandled loadcommand LC_DYSYMTAB\n");
401break;
402
403case LC_LOAD_DYLIB:
404case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
405dylibCommand = binary + binaryIndex;
406char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
407// TODO: verify version
408// =dylibCommand->dylib.current_version;
409// =dylibCommand->dylib.compatibility_version;
410
411if(!load_module(module))
412{
413// Unable to load dependancy
414return NULL;
415}
416break;
417
418case LC_ID_DYLIB:
419dylibCommand = binary + binaryIndex;
420moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
421moduleVersion =dylibCommand->dylib.current_version;
422moduleCompat =dylibCommand->dylib.compatibility_version;
423break;
424
425case LC_DYLD_INFO:
426// Bind and rebase info is stored here
427dyldInfoCommand = binary + binaryIndex;
428break;
429
430case LC_UUID:
431break;
432
433default:
434DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
435break;
436
437}
438
439binaryIndex += cmdSize;
440}
441if(!moduleName) return NULL;
442
443
444// bind_macho uses the symbols added in for some reason...
445module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbolStub, (UInt32)nonlazy);
446
447// REbase the module before binding it.
448if(dyldInfoCommand && dyldInfoCommand->rebase_off)
449{
450rebase_macho(binary, (char*)dyldInfoCommand->rebase_off, dyldInfoCommand->rebase_size);
451}
452
453if(dyldInfoCommand && dyldInfoCommand->bind_off)
454{
455bind_macho(binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size);
456}
457
458if(dyldInfoCommand && dyldInfoCommand->weak_bind_off)
459{
460// NOTE: this currently should never happen.
461bind_macho(binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size);
462}
463
464if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off)
465{
466// NOTE: we are binding the lazy pointers as a module is laoded,
467// This should be cahnged to bund when a symbol is referened at runtime.
468bind_macho(binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);
469}
470
471
472
473
474// Notify the system that it was laoded
475module_loaded(moduleName, moduleVersion, moduleCompat);
476
477return module_start;
478
479}
480
481
482// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
483void rebase_macho(void* base, char* rebase_stream, UInt32 size)
484{
485rebase_stream += (UInt32)base;
486
487UInt8 immediate = 0;
488UInt8 opcode = 0;
489UInt8 type = 0;
490
491UInt32 segmentAddress = 0;
492
493
494
495UInt32 tmp = 0;
496UInt32 tmp2 = 0;
497UInt8 bits = 0;
498int index = 0;
499
500int done = 0;
501unsigned int i = 0;
502
503while(/*!done &&*/ i < size)
504{
505immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
506opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
507
508
509switch(opcode)
510{
511case REBASE_OPCODE_DONE:
512// Rebase complete.
513done = 1;
514break;
515
516
517case REBASE_OPCODE_SET_TYPE_IMM:
518// Set rebase type (pointer, absolute32, pcrel32)
519//printf("Rebase type = 0x%X\n", immediate);
520// NOTE: This is currently NOT used
521type = immediate;
522break;
523
524
525case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
526// Locate address to begin rebasing
527segmentAddress = 0;
528
529struct segment_command* segCommand = NULL;
530
531unsigned int binIndex = 0;
532index = 0;
533do
534{
535segCommand = base + sizeof(struct mach_header) + binIndex;
536
537
538binIndex += segCommand->cmdsize;
539index++;
540}
541while(index <= immediate);
542
543
544segmentAddress = segCommand->fileoff;
545
546tmp = 0;
547bits = 0;
548do
549{
550tmp |= (rebase_stream[++i] & 0x7f) << bits;
551bits += 7;
552}
553while(rebase_stream[i] & 0x80);
554
555segmentAddress += tmp;
556break;
557
558
559case REBASE_OPCODE_ADD_ADDR_ULEB:
560// Add value to rebase address
561tmp = 0;
562bits = 0;
563do
564{
565tmp <<= bits;
566tmp |= rebase_stream[++i] & 0x7f;
567bits += 7;
568}
569while(rebase_stream[i] & 0x80);
570
571segmentAddress +=tmp;
572break;
573
574case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
575segmentAddress += immediate * sizeof(void*);
576break;
577
578
579case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
580index = 0;
581for (index = 0; index < immediate; ++index) {
582rebase_location(base + segmentAddress, (char*)base);
583segmentAddress += sizeof(void*);
584}
585break;
586
587
588case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
589tmp = 0;
590bits = 0;
591do
592{
593tmp |= (rebase_stream[++i] & 0x7f) << bits;
594bits += 7;
595}
596while(rebase_stream[i] & 0x80);
597
598index = 0;
599for (index = 0; index < tmp; ++index) {
600//printf("\tRebasing 0x%X\n", segmentAddress);
601rebase_location(base + segmentAddress, (char*)base);
602segmentAddress += sizeof(void*);
603}
604break;
605
606case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
607tmp = 0;
608bits = 0;
609do
610{
611tmp |= (rebase_stream[++i] & 0x7f) << bits;
612bits += 7;
613}
614while(rebase_stream[i] & 0x80);
615
616rebase_location(base + segmentAddress, (char*)base);
617
618segmentAddress += tmp + sizeof(void*);
619break;
620
621case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
622tmp = 0;
623bits = 0;
624do
625{
626tmp |= (rebase_stream[++i] & 0x7f) << bits;
627bits += 7;
628}
629while(rebase_stream[i] & 0x80);
630
631
632tmp2 = 0;
633bits = 0;
634do
635{
636tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
637bits += 7;
638}
639while(rebase_stream[i] & 0x80);
640
641index = 0;
642for (index = 0; index < tmp; ++index) {
643rebase_location(base + segmentAddress, (char*)base);
644
645segmentAddress += tmp2 + sizeof(void*);
646}
647break;
648}
649i++;
650}
651}
652
653// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
654// NOTE: this uses 32bit values, and not 64bit values.
655// There is apossibility that this could cause issues,
656// however the macho file is 32 bit, so it shouldn't matter too much
657void bind_macho(void* base, char* bind_stream, UInt32 size)
658{
659bind_stream += (UInt32)base;
660
661UInt8 immediate = 0;
662UInt8 opcode = 0;
663UInt8 type = 0;
664
665UInt32 segmentAddress = 0;
666
667UInt32 address = 0;
668
669SInt32 addend = 0;// TODO: handle this
670SInt32 libraryOrdinal = 0;
671
672const char* symbolName = NULL;
673UInt8 symboFlags = 0;
674UInt32 symbolAddr = 0xFFFFFFFF;
675
676// Temperary variables
677UInt8 bits = 0;
678UInt32 tmp = 0;
679UInt32 tmp2 = 0;
680
681UInt32 index = 0;
682int done = 0;
683unsigned int i = 0;
684
685while(/*!done &&*/ i < size)
686{
687immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
688opcode = bind_stream[i] & BIND_OPCODE_MASK;
689
690
691switch(opcode)
692{
693case BIND_OPCODE_DONE:
694done = 1;
695break;
696
697case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
698libraryOrdinal = immediate;
699//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);
700break;
701
702case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
703libraryOrdinal = 0;
704bits = 0;
705do
706{
707libraryOrdinal |= (bind_stream[++i] & 0x7f) << bits;
708bits += 7;
709}
710while(bind_stream[i] & 0x80);
711
712//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);
713
714break;
715
716case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
717// NOTE: this is wrong, fortunately we don't use it
718libraryOrdinal = -immediate;
719//DBG("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);
720
721break;
722
723case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
724symboFlags = immediate;
725symbolName = (char*)&bind_stream[++i];
726i += strlen((char*)&bind_stream[i]);
727//DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symboFlags);
728
729symbolAddr = lookup_all_symbols(symbolName);
730
731break;
732
733case BIND_OPCODE_SET_TYPE_IMM:
734// Set bind type (pointer, absolute32, pcrel32)
735type = immediate;
736//DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);
737
738break;
739
740case BIND_OPCODE_SET_ADDEND_SLEB:
741addend = 0;
742bits = 0;
743do
744{
745addend |= (bind_stream[++i] & 0x7f) << bits;
746bits += 7;
747}
748while(bind_stream[i] & 0x80);
749
750if(!(bind_stream[i-1] & 0x40)) addend *= -1;
751
752//DBG("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);
753break;
754
755case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
756segmentAddress = 0;
757
758// Locate address
759struct segment_command* segCommand = NULL;
760
761unsigned int binIndex = 0;
762index = 0;
763do
764{
765segCommand = base + sizeof(struct mach_header) + binIndex;
766binIndex += segCommand->cmdsize;
767index++;
768}
769while(index <= immediate);
770
771segmentAddress = segCommand->fileoff;
772
773// Read in offset
774tmp = 0;
775bits = 0;
776do
777{
778tmp |= (bind_stream[++i] & 0x7f) << bits;
779bits += 7;
780}
781while(bind_stream[i] & 0x80);
782
783segmentAddress += tmp;
784
785//DBG("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 0x%X\n", segmentAddress);
786break;
787
788case BIND_OPCODE_ADD_ADDR_ULEB:
789// Read in offset
790tmp = 0;
791bits = 0;
792do
793{
794tmp |= (bind_stream[++i] & 0x7f) << bits;
795bits += 7;
796}
797while(bind_stream[i] & 0x80);
798
799segmentAddress += tmp;
800//DBG("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);
801break;
802
803case BIND_OPCODE_DO_BIND:
804//DBG("BIND_OPCODE_DO_BIND\n");
805if(symbolAddr != 0xFFFFFFFF)
806{
807address = segmentAddress + (UInt32)base;
808
809((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
810((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
811((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
812((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
813}
814else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
815{
816printf("Unable to bind symbol %s\n", symbolName);
817}
818
819segmentAddress += sizeof(void*);
820break;
821
822case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
823//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");
824
825
826// Read in offset
827tmp = 0;
828bits = 0;
829do
830{
831tmp |= (bind_stream[++i] & 0x7f) << bits;
832bits += 7;
833}
834while(bind_stream[i] & 0x80);
835
836
837
838if(symbolAddr != 0xFFFFFFFF)
839{
840address = segmentAddress + (UInt32)base;
841
842((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
843((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
844((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
845((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
846}
847else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
848{
849printf("Unable to bind symbol %s\n", symbolName);
850}
851segmentAddress += tmp + sizeof(void*);
852
853
854break;
855
856case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
857//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
858
859if(symbolAddr != 0xFFFFFFFF)
860{
861address = segmentAddress + (UInt32)base;
862
863((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
864((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
865((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
866((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
867}
868else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
869{
870printf("Unable to bind symbol %s\n", symbolName);
871}
872segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
873
874
875break;
876
877case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
878
879tmp = 0;
880bits = 0;
881do
882{
883tmp |= (bind_stream[++i] & 0x7f) << bits;
884bits += 7;
885}
886while(bind_stream[i] & 0x80);
887
888
889tmp2 = 0;
890bits = 0;
891do
892{
893tmp2 |= (bind_stream[++i] & 0x7f) << bits;
894bits += 7;
895}
896while(bind_stream[i] & 0x80);
897
898
899//DBG("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);
900
901
902if(symbolAddr != 0xFFFFFFFF)
903{
904for(index = 0; index < tmp; index++)
905{
906
907address = segmentAddress + (UInt32)base;
908
909((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
910((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
911((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
912((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
913
914segmentAddress += tmp2 + sizeof(void*);
915}
916}
917else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
918{
919printf("Unable to bind symbol %s\n", symbolName);
920}
921
922
923break;
924
925}
926i++;
927}
928}
929
930inline void rebase_location(UInt32* location, char* base)
931{
932*location += (UInt32)base;
933}
934
935/*
936 * add_symbol
937 * This function adds a symbol from a module to the list of known symbols
938 * possibly change to a pointer and add this to the Symbol module so that it can
939 * adjust it's internal symbol list (sort) to optimize locating new symbols
940 */
941void add_symbol(char* symbol, void* addr)
942{
943symbolList_t* entry;
944//DBG("Adding symbol %s at 0x%X\n", symbol, addr);
945
946if(!moduleSymbols)
947{
948moduleSymbols = entry = malloc(sizeof(symbolList_t));
949
950}
951else
952{
953entry = moduleSymbols;
954while(entry->next)
955{
956entry = entry->next;
957}
958
959entry->next = malloc(sizeof(symbolList_t));
960entry = entry->next;
961}
962
963entry->next = NULL;
964entry->addr = (unsigned int)addr;
965entry->symbol = symbol;
966}
967
968
969/*
970 * print out the information about the loaded module
971
972 */
973void module_loaded(char* name, UInt32 version, UInt32 compat)
974{
975moduleList_t* entry;
976/*
977DBG("\%s.dylib Version %d.%d.%d loaded\n"
978 "\tCompatibility Version: %d.%d.%d\n",
979 name,
980 (version >> 16) & 0xFFFF,
981 (version >> 8) & 0x00FF,
982 (version >> 0) & 0x00FF,
983 (compat >> 16) & 0xFFFF,
984 (compat >> 8) & 0x00FF,
985 (compat >> 0) & 0x00FF);
986*/
987if(loadedModules == NULL)
988{
989loadedModules = entry = malloc(sizeof(moduleList_t));
990}
991else
992{
993entry = loadedModules;
994while(entry->next)
995{
996entry = entry->next;
997}
998entry->next = malloc(sizeof(moduleList_t));
999entry = entry->next;
1000}
1001
1002entry->next = NULL;
1003entry->module = name;
1004entry->version = version;
1005entry->compat = compat;
1006
1007
1008}
1009
1010int is_module_laoded(const char* name)
1011{
1012moduleList_t* entry = loadedModules;
1013while(entry)
1014{
1015if(strcmp(entry->module, name) == 0)
1016{
1017return 1;
1018}
1019else
1020{
1021entry = entry->next;
1022}
1023
1024}
1025return 0;
1026}
1027
1028// Look for symbols using the Smbols moduel function.
1029// If non are found, look through the list of module symbols
1030unsigned int lookup_all_symbols(const char* name)
1031{
1032unsigned int addr = 0xFFFFFFFF;
1033if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)
1034{
1035addr = lookup_symbol(name);
1036if(addr != 0xFFFFFFFF)
1037{
1038//DBG("Internal symbol %s located at 0x%X\n", name, addr);
1039return addr;
1040}
1041}
1042
1043
1044symbolList_t* entry = moduleSymbols;
1045while(entry)
1046{
1047if(strcmp(entry->symbol, name) == 0)
1048{
1049//DBG("External symbol %s located at 0x%X\n", name, entry->addr);
1050return entry->addr;
1051}
1052else
1053{
1054entry = entry->next;
1055}
1056
1057}
1058if(strcmp(name, SYMBOL_DYLD_STUB_BINDER) != 0)
1059{
1060printf("Unable to locate symbol %s\n", name);
1061}
1062return 0xFFFFFFFF;
1063}
1064
1065
1066/*
1067 * parse the symbol table
1068 * Lookup any undefined symbols
1069 */
1070
1071unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, char* symbolStub, UInt32 nonlazy)
1072{
1073unsigned int module_start = 0xFFFFFFFF;
1074
1075UInt32 symbolIndex = 0;
1076char* symbolString = base + (char*)symtabCommand->stroff;
1077//char* symbolTable = base + symtabCommand->symoff;
1078
1079while(symbolIndex < symtabCommand->nsyms)
1080{
1081
1082struct nlist* symbolEntry = (void*)base + symtabCommand->symoff + (symbolIndex * sizeof(struct nlist));
1083
1084// If the symbol is exported by this module
1085if(symbolEntry->n_value)
1086{
1087if(strcmp(symbolString + symbolEntry->n_un.n_strx, "start") == 0)
1088{
1089// Module start located. Start is an alias so don't register it
1090module_start = base + symbolEntry->n_value;
1091}
1092else
1093{
1094add_symbol(symbolString + symbolEntry->n_un.n_strx, (void*)base + symbolEntry->n_value);
1095}
1096}
1097
1098symbolEntry+= sizeof(struct nlist);
1099symbolIndex++;// TODO remove
1100}
1101
1102return module_start;
1103
1104}
1105
1106
1107/*
1108 * Locate the symbol for an already loaded function and modify the beginning of
1109 * the function to jump directly to the new one
1110 * example: replace_function("_HelloWorld_start", &replacement_start);
1111 */
1112int replace_function(const char* symbol, void* newAddress)
1113{
1114UInt32* jumpPointer = malloc(sizeof(UInt32*));
1115// TODO: look into using the next four bytes of the function instead
1116// Most functions should support this, as they probably will be at
1117// least 10 bytes long, but you never know, this is sligtly safer as
1118// function can be as small as 6 bytes.
1119UInt32 addr = lookup_all_symbols(symbol);
1120
1121char* binary = (char*)addr;
1122if(addr != 0xFFFFFFFF)
1123{
1124*binary++ = 0xFF;// Jump
1125*binary++ = 0x25;// Long Jump
1126*((UInt32*)binary) = (UInt32)jumpPointer;
1127
1128*jumpPointer = (UInt32)newAddress;
1129
1130return 1;
1131}
1132else
1133{
1134return 0;
1135}
1136
1137}

Archive Download this file

Revision: 429