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

Archive Download this file

Revision: 483