Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 502