Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 482