#include "multiboot.h"␊ |
#include "modules.h"␊ |
␊ |
#ifndef DEBUG_MODULES␊ |
#define DEBUG_MODULES 0␊ |
#endif␊ |
␊ |
#if DEBUG_MODULES␊ |
#define DBG(x...)␉printf(x); getc()␊ |
#else␊ |
#define DBG(x...)␊ |
#endif␊ |
␊ |
␊ |
moduleHook_t* moduleCallbacks = NULL;␊ |
moduleList_t* loadedModules = NULL;␊ |
symbolList_t* moduleSymbols = NULL;␊ |
unsigned int (*lookup_symbol)(const char*) = NULL;␊ |
|
␉if(load_module(SYMBOLS_MODULE))␊ |
␉{␊ |
␉␉lookup_symbol = (void*)lookup_all_symbols("_lookup_symbol");␊ |
␉␉␊ |
␉␉if((UInt32)lookup_symbol != 0xFFFFFFFF)␊ |
␉␉{␊ |
␉␉␉return 1;␊ |
␉␉}␊ |
␉␉␊ |
␉}␊ |
␉␊ |
␉if((UInt32)lookup_symbol == 0xFFFFFFFF)␊ |
␉{␊ |
␉␉return 0;␊ |
␉}␊ |
␉else␊ |
␉{␊ |
␉␉return 1;␊ |
␉}␊ |
␉return 0;␊ |
}␊ |
␊ |
␊ |
/*␊ |
* Load all modules in the /Extra/modules/ directory␊ |
* Module depencdies will be loaded first␊ |
|
␉struct dirstuff* moduleDir = opendir("/Extra/modules/");␊ |
␉while(readdir(moduleDir, (const char**)&name, &flags, &time) >= 0)␊ |
␉{␊ |
␉␉// TODO: verify ends in .dylib␊ |
␉␉if(strlen(name) > sizeof(".dylib"))␊ |
␉␉if(strcmp(&name[strlen(name) - sizeof("dylib")], ".dylib") == 0)␊ |
␉␉{␊ |
␉␉␉name[strlen(name) - sizeof(".dylib")] = 0;␊ |
␉␉␉name[strlen(name) - sizeof("dylib")] = 0;␊ |
␉␉␉load_module(name);␊ |
␉␉}␊ |
␉}␊ |
|
␉{␊ |
␉␉void (*module_start)(void) = NULL;␊ |
␊ |
␉␉printf("Module %s read in.\n", modString);␊ |
␉␉//printf("Module %s read in.\n", modString);␊ |
␊ |
␉␉// Module loaded into memory, parse it␊ |
␉␉module_start = parse_mach(module_base);␊ |
|
␉␉if(module_start)␊ |
␉␉{␊ |
␉␉␉(*module_start)();␉// Start the module␊ |
␉␉␉printf("Module started\n");␊ |
␉␉␉DBG("Module %s.dylib Loaded.\n", module);␊ |
␉␉}␊ |
␉␉else {␊ |
␉␉␉printf("Unabel to locate module start\n");␊ |
␉␉␉printf("Unabel to start %s.dylib\n", module);␊ |
␉␉␉getc();␊ |
␉␉}␊ |
␊ |
␉␉␊ |
␉␉getc();␊ |
␉␉␊ |
␉␉// TODO: Add module to loaded list if loaded successfuly␊ |
␉␉␊ |
␉}␊ |
|
␉return 1;␊ |
}␊ |
␊ |
␊ |
/*␊ |
* register_hook( const char* name )␊ |
*␉␉name - Name of the module Hook.␊ |
*␉␉␉ NOTE: If the name already exists in the list, it'll␊ |
*␉␉␉ still be added, however the entry will not be used, the first one␊ |
*␉␉␉ will instead. That also means the the hook will most likely be␊ |
*␉␉␉ called twice.␊ |
*␊ |
* Registers a hook with the module system, This allows modules to␊ |
* register a callback when the hook is executed.␊ |
*/␊ |
␊ |
inline void register_hook(const char* name)␊ |
{␊ |
␉moduleHook_t* hooks;␊ |
␉if(moduleCallbacks == NULL)␊ |
␉{␊ |
␉␉moduleCallbacks = malloc(sizeof(moduleHook_t));␊ |
␉␉moduleCallbacks->next = NULL;␊ |
␉}␊ |
␉␊ |
␉hooks = moduleCallbacks;␊ |
␉while(hooks->next != NULL)␊ |
␉{␊ |
␉␉hooks = hooks->next;␊ |
␉}␊ |
␉␊ |
␉␊ |
␉hooks->name = name;␊ |
␉hooks->callbacks = NULL;␊ |
}␊ |
␊ |
␊ |
/*␊ |
*␉execute_hook( const char* name )␊ |
*␉␉name - Name of the module hook␊ |
*␉␉␉If any callbacks have been registered for this hook␊ |
*␉␉␉they will be executed now in the same order that the␊ |
*␉␉␉hooks were added.␊ |
*/␊ |
int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)␊ |
{␊ |
␉DBG("Attempting to execute hook '%s'\n", name);␊ |
␊ |
␉if(moduleCallbacks != NULL)␊ |
␉{␊ |
␉␉moduleHook_t* hooks = moduleCallbacks;␊ |
␉␉␊ |
␉␉while(hooks != NULL && strcmp(name, hooks->name) != 0)␊ |
␉␉{␊ |
␉␉␉hooks = hooks->next;␊ |
␉␉}␊ |
␉␉␊ |
␉␉if(hooks != NULL)␊ |
␉␉{␊ |
␉␉␉// Loop through all callbacks for this module␊ |
␉␉␉callbackList_t* callbacks = hooks->callbacks;␊ |
␉␉␉␊ |
␉␉␉while(callbacks)␊ |
␉␉␉{␊ |
␉␉␉␉// Execute callback␊ |
␉␉␉␉callbacks->callback(arg1, arg2, arg3, arg4);␊ |
␉␉␉␉callbacks = callbacks->next;␊ |
␉␉␉}␊ |
␉␉␉DBG("Hook '%s' executed.\n", name);␊ |
␊ |
␉␉␉return 1;␊ |
␉␉}␊ |
␉␉else␊ |
␉␉{␊ |
␉␉␉DBG("No callbacks for '%s' hook.\n", name);␊ |
␊ |
␉␉␉// Callbaack for this module doesn't exist;␊ |
␉␉␉//verbose("Unable execute hook '%s', no callbacks registered.\n", name);␊ |
␉␉␉//pause();␊ |
␉␉␉return 0;␊ |
␉␉}␊ |
␊ |
␊ |
␉}␉␊ |
␉DBG("No hooks have been registered.\n", name);␊ |
␉return 0;␊ |
}␊ |
␊ |
␊ |
␊ |
/*␊ |
*␉register_hook_callback( const char* name, void(*callback)())␊ |
*␉␉name - Name of the module hook to attach to.␊ |
*␉␉callbacks - The funciton pointer that will be called when the␊ |
*␉␉␉hook is executed.␊ |
*␉␉␉NOTE: the hooks take four void* arguments.␊ |
*/␊ |
/*␊ |
void register_hook_callback(const char* name,␊ |
␉␉␉␉␉␉␉void(*callback)(void*, void*, void*, void*),␊ |
␉␉␉␉␉␉␉)*/␊ |
void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))␊ |
{␊ |
␉// Locate Module hook␊ |
␉if(moduleCallbacks == NULL)␊ |
␉{␊ |
␉␉register_hook(name);␊ |
␉}␊ |
␉volatile moduleHook_t* hooks = moduleCallbacks;␊ |
␉␊ |
␉while(hooks != NULL && strcmp(name, hooks->name) != 0)␊ |
␉{␊ |
␉␉hooks = hooks->next;␊ |
␉}␊ |
␉␊ |
␉if(hooks == NULL)␊ |
␉{␊ |
␉␉// Hook doesn't exist, add it.␊ |
␉␉register_hook(name);␊ |
␉␉␊ |
␉␉// This is just a pointer, the data was modified in the register_hook function.␊ |
␉␉hooks = hooks->next;␊ |
␉}␊ |
␉␊ |
␉// Module Hooks located␊ |
␉if(hooks->callbacks == NULL)␊ |
␉{␊ |
␉␉// Initialize hook list␊ |
␉␉hooks->callbacks = (callbackList_t*)malloc(sizeof(callbackList_t));␊ |
␉␉hooks->callbacks->callback = callback;␊ |
␉␉hooks->callbacks->next = NULL;␊ |
␉}␊ |
␉else␊ |
␉{␊ |
␉␉callbackList_t* callbacks = hooks->callbacks;␊ |
␉␉while(callbacks->next != NULL)␊ |
␉␉{␊ |
␉␉␉callbacks = callbacks->next;␊ |
␉␉}␊ |
␉␉// Add new entry to end of hook list.␊ |
␉␉callbacks->next = (callbackList_t*)malloc(sizeof(callbackList_t));␊ |
␉␉callbacks = callbacks->next;␊ |
␉␉callbacks->next = NULL;␊ |
␉␉callbacks->callback = callback;␊ |
␉}␊ |
}␊ |
␊ |
␊ |
␊ |
/*␊ |
* Parse through a macho module. The module will be rebased and binded␊ |
* as specified in the macho header. If the module is sucessfuly laoded␊ |
* the module iinit address will be returned.␊ |
|
␉if(((struct mach_header*)binary)->magic != MH_MAGIC)␊ |
␉{␊ |
␉␉printf("Module is not 32bit\n");␊ |
␉␉getc();␊ |
␉␉return NULL;␉// 32bit only␊ |
␉}␊ |
␉␊ |
␉if(((struct mach_header*)binary)->filetype != MH_DYLIB)␊ |
␉{␊ |
␉␉printf("Module is not a dylib. Unable to load.\n");␊ |
␉␉getc();␊ |
␉␉return NULL; // Module is in the incorrect format␊ |
␉}␊ |
␉␊ |
|
␉␉␉␉␉␉␉␉break;␊ |
␉␉␉␉␉␉␉␉␊ |
␉␉␉␉␉␉␉case S_LAZY_SYMBOL_POINTERS:␊ |
␉␉␉␉␉␉␉␉// NOTE: Theses currently are not handled.␊ |
␉␉␉␉␉␉␉␉//nonlazy = binary + section->offset;␊ |
␉␉␉␉␉␉␉␉//printf("%s S_LAZY_SYMBOL_POINTERS section, 0x%X\n", SECT_NON_LAZY_SYMBOL_PTR, nonlazy);␊ |
␉␉␉␉␉␉␉␉// Fucntions␊ |
|
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉default:␊ |
␉␉␉␉printf("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);␊ |
␉␉␉␉DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);␊ |
␉␉␉␉break;␊ |
␉␉␊ |
␉␉}␊ |
|
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:␊ |
␉␉␉␉libraryOrdinal = immediate;␊ |
␉␉␉␉//printf("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);␊ |
␉␉␉␉//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:␊ |
|
␉␉␉␉}␊ |
␉␉␉␉while(bind_stream[i] & 0x80);␊ |
␉␉␉␉␊ |
␉␉␉␉//printf("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);␊ |
␉␉␉␉//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);␊ |
␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:␊ |
␉␉␉␉// NOTE: this is wrong, fortunately we don't use it␊ |
␉␉␉␉libraryOrdinal = -immediate;␊ |
␉␉␉␉//printf("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);␊ |
␉␉␉␉//DBG("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);␊ |
␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
|
␉␉␉␉symboFlags = immediate;␊ |
␉␉␉␉symbolName = (char*)&bind_stream[++i];␊ |
␉␉␉␉i += strlen((char*)&bind_stream[i]);␊ |
␉␉␉␉//printf("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symboFlags);␊ |
␉␉␉␉//DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symboFlags);␊ |
␊ |
␉␉␉␉symbolAddr = lookup_all_symbols(symbolName);␊ |
␊ |
|
␉␉␉case BIND_OPCODE_SET_TYPE_IMM:␊ |
␉␉␉␉// Set bind type (pointer, absolute32, pcrel32)␊ |
␉␉␉␉type = immediate;␊ |
␉␉␉␉//printf("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);␊ |
␉␉␉␉//DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);␊ |
␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
|
␉␉␉␉␊ |
␉␉␉␉if(!(bind_stream[i-1] & 0x40)) addend *= -1;␊ |
␉␉␉␉␊ |
␉␉␉␉//printf("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);␊ |
␉␉␉␉//DBG("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:␊ |
|
␉␉␉␉␊ |
␉␉␉␉segmentAddress += tmp;␊ |
␉␉␉␉␊ |
␉␉␉␉//printf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 0x%X\n", segmentAddress);␊ |
␉␉␉␉//DBG("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 0x%X\n", segmentAddress);␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_ADD_ADDR_ULEB:␊ |
|
␉␉␉␉while(bind_stream[i] & 0x80);␊ |
␉␉␉␉␊ |
␉␉␉␉segmentAddress += tmp;␊ |
␉␉␉␉//printf("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);␊ |
␉␉␉␉//DBG("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_DO_BIND:␊ |
␉␉␉␉//printf("BIND_OPCODE_DO_BIND\n");␊ |
␉␉␉␉//DBG("BIND_OPCODE_DO_BIND\n");␊ |
␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
␉␉␉␉{␊ |
␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
|
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:␊ |
␉␉␉␉//printf("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");␊ |
␉␉␉␉//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉// Read in offset␊ |
|
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:␊ |
␉␉␉␉//printf("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");␊ |
␉␉␉␉//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");␊ |
␉␉␉␉␊ |
␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
␉␉␉␉{␊ |
|
␉␉␉␉while(bind_stream[i] & 0x80);␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉//printf("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);␊ |
␉␉␉␉//DBG("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
|
void add_symbol(char* symbol, void* addr)␊ |
{␊ |
␉symbolList_t* entry;␊ |
␉//printf("Adding symbol %s at 0x%X\n", symbol, addr);␊ |
␉//DBG("Adding symbol %s at 0x%X\n", symbol, addr);␊ |
␉␊ |
␉if(!moduleSymbols)␊ |
␉{␊ |
|
{␊ |
␉moduleList_t* entry;␊ |
␉/*␊ |
␉printf("\%s.dylib Version %d.%d.%d loaded\n"␊ |
␉DBG("\%s.dylib Version %d.%d.%d loaded\n"␊ |
␉␉ "\tCompatibility Version: %d.%d.%d\n",␊ |
␉␉ name,␊ |
␉␉ (version >> 16) & 0xFFFF,␊ |
|
␉␉addr = lookup_symbol(name);␊ |
␉␉if(addr != 0xFFFFFFFF)␊ |
␉␉{␊ |
␉␉␉//printf("Internal symbol %s located at 0x%X\n", name, addr);␊ |
␉␉␉//DBG("Internal symbol %s located at 0x%X\n", name, addr);␊ |
␉␉␉return addr;␊ |
␉␉}␊ |
␉}␊ |
|
␉{␊ |
␉␉if(strcmp(entry->symbol, name) == 0)␊ |
␉␉{␊ |
␉␉␉//printf("External symbol %s located at 0x%X\n", name, entry->addr);␊ |
␉␉␉//DBG("External symbol %s located at 0x%X\n", name, entry->addr);␊ |
␉␉␉return entry->addr;␊ |
␉␉}␊ |
␉␉else␊ |
|
␉UInt32* jumpPointer = malloc(sizeof(UInt32*));␉ ␊ |
␉// TODO: look into using the next four bytes of the function instead␊ |
␉// Most functions should support this, as they probably will be at ␊ |
␉// least 10 bytes long, but you never know, this is sligtly saver as␊ |
␉// least 10 bytes long, but you never know, this is sligtly safer as␊ |
␉// function can be as small as 6 bytes.␊ |
␉UInt32 addr = lookup_all_symbols(symbol);␊ |
␉␊ |