Chameleon

Chameleon Svn Source Tree

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

Source at commit 491 created 13 years 7 months ago.
By meklort, Initial 64bit support. lapic_configure patch is currently 32bit only, however the rest of the patches should work fine on a 64bit kernel. I haven't teted this extensivly, so it may or may not work for everyone.
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 = 0;
305UInt16 cmd = 0;
306
307// Parse through the load commands
308if(((struct mach_header*)binary)->magic == MH_MAGIC)
309{
310is64 = 0;
311binaryIndex += sizeof(struct mach_header);
312}
313else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
314{
315// NOTE: modules cannot be 64bit...
316is64 = 1;
317binaryIndex += sizeof(struct mach_header_64);
318}
319else
320{
321printf("Invalid mach magic\n");
322getc();
323return NULL;
324}
325
326
327
328if(((struct mach_header*)binary)->filetype != MH_DYLIB)
329{
330printf("Module is not a dylib. Unable to load.\n");
331getc();
332return NULL; // Module is in the incorrect format
333}
334
335while(cmd < ((struct mach_header*)binary)->ncmds)// TODO: for loop instead
336{
337cmd++;
338
339loadCommand = binary + binaryIndex;
340UInt32 cmdSize = loadCommand->cmdsize;
341
342
343switch ((loadCommand->cmd & 0x7FFFFFFF))
344{
345case LC_SYMTAB:
346symtabCommand = binary + binaryIndex;
347break;
348
349case LC_SEGMENT:
350case LC_SEGMENT_64:
351break;
352
353case LC_DYSYMTAB:
354break;
355
356case LC_LOAD_DYLIB:
357case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
358dylibCommand = binary + binaryIndex;
359char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
360// TODO: verify version
361// =dylibCommand->dylib.current_version;
362// =dylibCommand->dylib.compatibility_version;
363
364if(!load_module(module))
365{
366// Unable to load dependancy
367return NULL;
368}
369break;
370
371case LC_ID_DYLIB:
372dylibCommand = binary + binaryIndex;
373moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
374moduleVersion =dylibCommand->dylib.current_version;
375moduleCompat =dylibCommand->dylib.compatibility_version;
376break;
377
378case LC_DYLD_INFO:
379// Bind and rebase info is stored here
380dyldInfoCommand = binary + binaryIndex;
381break;
382
383case LC_UUID:
384break;
385
386default:
387DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
388break;
389
390}
391
392binaryIndex += cmdSize;
393}
394if(!moduleName) return NULL;
395
396
397// bind_macho uses the symbols.
398module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, &add_symbol, is64);
399
400// Rebase the module before binding it.
401if(dyldInfoCommand && dyldInfoCommand->rebase_off)
402{
403rebase_macho(binary, (char*)dyldInfoCommand->rebase_off, dyldInfoCommand->rebase_size);
404}
405
406if(dyldInfoCommand && dyldInfoCommand->bind_off)
407{
408bind_macho(binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size);
409}
410
411if(dyldInfoCommand && dyldInfoCommand->weak_bind_off)
412{
413// NOTE: this currently should never happen.
414bind_macho(binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size);
415}
416
417if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off)
418{
419// NOTE: we are binding the lazy pointers as a module is laoded,
420// This should be changed to bind when a symbol is referened at runtime instead.
421bind_macho(binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);
422}
423
424
425
426
427// Notify the system that it was laoded
428module_loaded(moduleName, moduleVersion, moduleCompat);
429
430return module_start;
431
432}
433
434
435// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
436void rebase_macho(void* base, char* rebase_stream, UInt32 size)
437{
438rebase_stream += (UInt32)base;
439
440UInt8 immediate = 0;
441UInt8 opcode = 0;
442UInt8 type = 0;
443
444UInt32 segmentAddress = 0;
445
446
447
448UInt32 tmp = 0;
449UInt32 tmp2 = 0;
450UInt8 bits = 0;
451int index = 0;
452
453int done = 0;
454unsigned int i = 0;
455
456while(/*!done &&*/ i < size)
457{
458immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
459opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
460
461
462switch(opcode)
463{
464case REBASE_OPCODE_DONE:
465// Rebase complete.
466done = 1;
467break;
468
469
470case REBASE_OPCODE_SET_TYPE_IMM:
471// Set rebase type (pointer, absolute32, pcrel32)
472//printf("Rebase type = 0x%X\n", immediate);
473// NOTE: This is currently NOT used
474type = immediate;
475break;
476
477
478case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
479// Locate address to begin rebasing
480segmentAddress = 0;
481
482
483struct segment_command* segCommand = NULL; // NOTE: 32bit only
484
485unsigned int binIndex = 0;
486index = 0;
487do
488{
489segCommand = base + sizeof(struct mach_header) + binIndex;
490
491
492binIndex += segCommand->cmdsize;
493index++;
494}
495while(index <= immediate);
496
497
498segmentAddress = segCommand->fileoff;
499
500tmp = 0;
501bits = 0;
502do
503{
504tmp |= (rebase_stream[++i] & 0x7f) << bits;
505bits += 7;
506}
507while(rebase_stream[i] & 0x80);
508
509segmentAddress += tmp;
510break;
511
512
513case REBASE_OPCODE_ADD_ADDR_ULEB:
514// Add value to rebase address
515tmp = 0;
516bits = 0;
517do
518{
519tmp <<= bits;
520tmp |= rebase_stream[++i] & 0x7f;
521bits += 7;
522}
523while(rebase_stream[i] & 0x80);
524
525segmentAddress +=tmp;
526break;
527
528case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
529segmentAddress += immediate * sizeof(void*);
530break;
531
532
533case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
534index = 0;
535for (index = 0; index < immediate; ++index) {
536rebase_location(base + segmentAddress, (char*)base);
537segmentAddress += sizeof(void*);
538}
539break;
540
541
542case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
543tmp = 0;
544bits = 0;
545do
546{
547tmp |= (rebase_stream[++i] & 0x7f) << bits;
548bits += 7;
549}
550while(rebase_stream[i] & 0x80);
551
552index = 0;
553for (index = 0; index < tmp; ++index) {
554//DBG("\tRebasing 0x%X\n", segmentAddress);
555rebase_location(base + segmentAddress, (char*)base);
556segmentAddress += sizeof(void*);
557}
558break;
559
560case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
561tmp = 0;
562bits = 0;
563do
564{
565tmp |= (rebase_stream[++i] & 0x7f) << bits;
566bits += 7;
567}
568while(rebase_stream[i] & 0x80);
569
570rebase_location(base + segmentAddress, (char*)base);
571
572segmentAddress += tmp + sizeof(void*);
573break;
574
575case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
576tmp = 0;
577bits = 0;
578do
579{
580tmp |= (rebase_stream[++i] & 0x7f) << bits;
581bits += 7;
582}
583while(rebase_stream[i] & 0x80);
584
585
586tmp2 = 0;
587bits = 0;
588do
589{
590tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
591bits += 7;
592}
593while(rebase_stream[i] & 0x80);
594
595index = 0;
596for (index = 0; index < tmp; ++index) {
597rebase_location(base + segmentAddress, (char*)base);
598
599segmentAddress += tmp2 + sizeof(void*);
600}
601break;
602}
603i++;
604}
605}
606
607// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
608// NOTE: this uses 32bit values, and not 64bit values.
609// There is apossibility that this could cause issues,
610// however the macho file is 32 bit, so it shouldn't matter too much
611void bind_macho(void* base, char* bind_stream, UInt32 size)
612{
613bind_stream += (UInt32)base;
614
615UInt8 immediate = 0;
616UInt8 opcode = 0;
617UInt8 type = 0;
618
619UInt32 segmentAddress = 0;
620
621UInt32 address = 0;
622
623SInt32 addend = 0;// TODO: handle this
624SInt32 libraryOrdinal = 0;
625
626const char* symbolName = NULL;
627UInt8 symboFlags = 0;
628UInt32 symbolAddr = 0xFFFFFFFF;
629
630// Temperary variables
631UInt8 bits = 0;
632UInt32 tmp = 0;
633UInt32 tmp2 = 0;
634
635UInt32 index = 0;
636int done = 0;
637unsigned int i = 0;
638
639while(/*!done &&*/ i < size)
640{
641immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
642opcode = bind_stream[i] & BIND_OPCODE_MASK;
643
644
645switch(opcode)
646{
647case BIND_OPCODE_DONE:
648done = 1;
649break;
650
651case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
652libraryOrdinal = immediate;
653//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);
654break;
655
656case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
657libraryOrdinal = 0;
658bits = 0;
659do
660{
661libraryOrdinal |= (bind_stream[++i] & 0x7f) << bits;
662bits += 7;
663}
664while(bind_stream[i] & 0x80);
665
666//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);
667
668break;
669
670case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
671// NOTE: this is wrong, fortunately we don't use it
672libraryOrdinal = -immediate;
673//DBG("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);
674
675break;
676
677case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
678symboFlags = immediate;
679symbolName = (char*)&bind_stream[++i];
680i += strlen((char*)&bind_stream[i]);
681//DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symboFlags);
682
683symbolAddr = lookup_all_symbols(symbolName);
684
685break;
686
687case BIND_OPCODE_SET_TYPE_IMM:
688// Set bind type (pointer, absolute32, pcrel32)
689type = immediate;
690//DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);
691
692break;
693
694case BIND_OPCODE_SET_ADDEND_SLEB:
695addend = 0;
696bits = 0;
697do
698{
699addend |= (bind_stream[++i] & 0x7f) << bits;
700bits += 7;
701}
702while(bind_stream[i] & 0x80);
703
704if(!(bind_stream[i-1] & 0x40)) addend *= -1;
705
706//DBG("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);
707break;
708
709case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
710segmentAddress = 0;
711
712// Locate address
713struct segment_command* segCommand = NULL;// NOTE: 32bit only
714
715unsigned int binIndex = 0;
716index = 0;
717do
718{
719segCommand = base + sizeof(struct mach_header) + binIndex;
720binIndex += segCommand->cmdsize;
721index++;
722}
723while(index <= immediate);
724
725segmentAddress = segCommand->fileoff;
726
727// Read in offset
728tmp = 0;
729bits = 0;
730do
731{
732tmp |= (bind_stream[++i] & 0x7f) << bits;
733bits += 7;
734}
735while(bind_stream[i] & 0x80);
736
737segmentAddress += tmp;
738
739//DBG("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 0x%X\n", segmentAddress);
740break;
741
742case BIND_OPCODE_ADD_ADDR_ULEB:
743// Read in offset
744tmp = 0;
745bits = 0;
746do
747{
748tmp |= (bind_stream[++i] & 0x7f) << bits;
749bits += 7;
750}
751while(bind_stream[i] & 0x80);
752
753segmentAddress += tmp;
754//DBG("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);
755break;
756
757case BIND_OPCODE_DO_BIND:
758//DBG("BIND_OPCODE_DO_BIND\n");
759if(symbolAddr != 0xFFFFFFFF)
760{
761address = segmentAddress + (UInt32)base;
762
763((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
764((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
765((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
766((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
767}
768else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
769{
770printf("Unable to bind symbol %s\n", symbolName);
771}
772
773segmentAddress += sizeof(void*);
774break;
775
776case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
777//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");
778
779
780// Read in offset
781tmp = 0;
782bits = 0;
783do
784{
785tmp |= (bind_stream[++i] & 0x7f) << bits;
786bits += 7;
787}
788while(bind_stream[i] & 0x80);
789
790
791
792if(symbolAddr != 0xFFFFFFFF)
793{
794address = segmentAddress + (UInt32)base;
795
796((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
797((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
798((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
799((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
800}
801else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
802{
803printf("Unable to bind symbol %s\n", symbolName);
804}
805segmentAddress += tmp + sizeof(void*);
806
807
808break;
809
810case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
811//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
812
813if(symbolAddr != 0xFFFFFFFF)
814{
815address = segmentAddress + (UInt32)base;
816
817((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
818((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
819((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
820((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
821}
822else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
823{
824printf("Unable to bind symbol %s\n", symbolName);
825}
826segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
827
828
829break;
830
831case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
832
833tmp = 0;
834bits = 0;
835do
836{
837tmp |= (bind_stream[++i] & 0x7f) << bits;
838bits += 7;
839}
840while(bind_stream[i] & 0x80);
841
842
843tmp2 = 0;
844bits = 0;
845do
846{
847tmp2 |= (bind_stream[++i] & 0x7f) << bits;
848bits += 7;
849}
850while(bind_stream[i] & 0x80);
851
852
853//DBG("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);
854
855
856if(symbolAddr != 0xFFFFFFFF)
857{
858for(index = 0; index < tmp; index++)
859{
860
861address = segmentAddress + (UInt32)base;
862
863((char*)address)[0] = (symbolAddr & 0x000000FF) >> 0;
864((char*)address)[1] = (symbolAddr & 0x0000FF00) >> 8;
865((char*)address)[2] = (symbolAddr & 0x00FF0000) >> 16;
866((char*)address)[3] = (symbolAddr & 0xFF000000) >> 24;
867
868segmentAddress += tmp2 + sizeof(void*);
869}
870}
871else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
872{
873printf("Unable to bind symbol %s\n", symbolName);
874}
875
876
877break;
878
879}
880i++;
881}
882}
883
884inline void rebase_location(UInt32* location, char* base)
885{
886*location += (UInt32)base;
887}
888
889/*
890 * add_symbol
891 * This function adds a symbol from a module to the list of known symbols
892 * possibly change to a pointer and add this to the Symbol module so that it can
893 * adjust it's internal symbol list (sort) to optimize locating new symbols
894 * NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF
895 */
896long long add_symbol(char* symbol, long long addr, char is64)
897{
898if(is64) return 0xFFFFFFFF; // Fixme
899
900// This only can handle 32bit symbols
901symbolList_t* entry;
902//DBG("Adding symbol %s at 0x%X\n", symbol, addr);
903
904if(!moduleSymbols)
905{
906moduleSymbols = entry = malloc(sizeof(symbolList_t));
907
908}
909else
910{
911entry = moduleSymbols;
912while(entry->next)
913{
914entry = entry->next;
915}
916
917entry->next = malloc(sizeof(symbolList_t));
918entry = entry->next;
919}
920
921entry->next = NULL;
922entry->addr = (UInt32)addr;
923entry->symbol = symbol;
924
925if(strcmp(symbol, "start") == 0)
926{
927return addr;
928}
929else
930{
931return 0xFFFFFFFF; // fixme
932}
933}
934
935
936/*
937 * print out the information about the loaded module
938
939 */
940void module_loaded(char* name, UInt32 version, UInt32 compat)
941{
942moduleList_t* entry;
943/*
944DBG("\%s.dylib Version %d.%d.%d loaded\n"
945 "\tCompatibility Version: %d.%d.%d\n",
946 name,
947 (version >> 16) & 0xFFFF,
948 (version >> 8) & 0x00FF,
949 (version >> 0) & 0x00FF,
950 (compat >> 16) & 0xFFFF,
951 (compat >> 8) & 0x00FF,
952 (compat >> 0) & 0x00FF);
953*/
954if(loadedModules == NULL)
955{
956loadedModules = entry = malloc(sizeof(moduleList_t));
957}
958else
959{
960entry = loadedModules;
961while(entry->next)
962{
963entry = entry->next;
964}
965entry->next = malloc(sizeof(moduleList_t));
966entry = entry->next;
967}
968
969entry->next = NULL;
970entry->module = name;
971entry->version = version;
972entry->compat = compat;
973
974
975}
976
977int is_module_laoded(const char* name)
978{
979moduleList_t* entry = loadedModules;
980while(entry)
981{
982if(strcmp(entry->module, name) == 0)
983{
984return 1;
985}
986else
987{
988entry = entry->next;
989}
990
991}
992return 0;
993}
994
995// Look for symbols using the Smbols moduel function.
996// If non are found, look through the list of module symbols
997unsigned int lookup_all_symbols(const char* name)
998{
999unsigned int addr = 0xFFFFFFFF;
1000if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)
1001{
1002addr = lookup_symbol(name);
1003if(addr != 0xFFFFFFFF)
1004{
1005//DBG("Internal symbol %s located at 0x%X\n", name, addr);
1006return addr;
1007}
1008}
1009
1010
1011symbolList_t* entry = moduleSymbols;
1012while(entry)
1013{
1014if(strcmp(entry->symbol, name) == 0)
1015{
1016//DBG("External symbol %s located at 0x%X\n", name, entry->addr);
1017return entry->addr;
1018}
1019else
1020{
1021entry = entry->next;
1022}
1023
1024}
1025if(strcmp(name, SYMBOL_DYLD_STUB_BINDER) != 0)
1026{
1027printf("Unable to locate symbol %s\n", name);
1028getc();
1029}
1030return 0xFFFFFFFF;
1031}
1032
1033
1034/*
1035 * parse the symbol table
1036 * Lookup any undefined symbols
1037 */
1038
1039unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)
1040{
1041// TODO: verify that the _TEXT,_text segment starts at the same locaiton in the file. If not
1042//subtract the vmaddress and add the actual file address back on. (NOTE: if compiled properly, not needed)
1043
1044unsigned int module_start = 0xFFFFFFFF;
1045
1046UInt32 symbolIndex = 0;
1047char* symbolString = base + (char*)symtabCommand->stroff;
1048//char* symbolTable = base + symtabCommand->symoff;
1049if(!is64)
1050{
1051struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
1052while(symbolIndex < symtabCommand->nsyms)
1053{
1054// If the symbol is exported by this module
1055if(symbolEntry->n_value &&
1056 symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)
1057{
1058
1059// Module start located. Start is an alias so don't register it
1060module_start = base + symbolEntry->n_value;
1061}
1062
1063symbolEntry++;
1064symbolIndex++;// TODO remove
1065}
1066}
1067else
1068{
1069struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
1070// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)
1071while(symbolIndex < symtabCommand->nsyms)
1072{
1073
1074
1075// If the symbol is exported by this module
1076if(symbolEntry->n_value &&
1077 symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)
1078{
1079
1080// Module start located. Start is an alias so don't register it
1081module_start = base + symbolEntry->n_value;
1082}
1083
1084symbolEntry++;
1085symbolIndex++;// TODO remove
1086}
1087}
1088
1089return module_start;
1090
1091}
1092
1093
1094/*
1095 * Locate the symbol for an already loaded function and modify the beginning of
1096 * the function to jump directly to the new one
1097 * example: replace_function("_HelloWorld_start", &replacement_start);
1098 */
1099int replace_function(const char* symbol, void* newAddress)
1100{
1101UInt32* jumpPointer = malloc(sizeof(UInt32*));
1102// TODO: look into using the next four bytes of the function instead
1103// Most functions should support this, as they probably will be at
1104// least 10 bytes long, but you never know, this is sligtly safer as
1105// function can be as small as 6 bytes.
1106UInt32 addr = lookup_all_symbols(symbol);
1107
1108char* binary = (char*)addr;
1109if(addr != 0xFFFFFFFF)
1110{
1111*binary++ = 0xFF;// Jump
1112*binary++ = 0x25;// Long Jump
1113*((UInt32*)binary) = (UInt32)jumpPointer;
1114
1115*jumpPointer = (UInt32)newAddress;
1116
1117return 1;
1118}
1119else
1120{
1121return 0;
1122}
1123
1124}

Archive Download this file

Revision: 491