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

Archive Download this file

Revision: 490