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

Archive Download this file

Revision: 499