*␊ |
* TODO: Zero out bss if needed␊ |
*/␊ |
#ifndef DEBUG_MODULES␊ |
#define DEBUG_MODULES 0␊ |
#endif␊ |
␊ |
#include "boot.h"␊ |
#include "bootstruct.h"␊ |
#include "modules.h"␊ |
␊ |
#ifndef DEBUG_MODULES␊ |
#define DEBUG_MODULES 0␊ |
#endif␊ |
␊ |
#if DEBUG_MODULES␊ |
#define DBG(x...)␉printf(x); getc()␊ |
#define DBG(x...)␉printf(x);␊ |
#define DBGPAUSE()␉getc()␊ |
#else␊ |
#define DBG(x...)␊ |
#define DBGPAUSE()␊ |
#endif␊ |
␊ |
// NOTE: Global so that modules can link with this␊ |
|
unsigned int (*lookup_symbol)(const char*) = NULL;␊ |
␊ |
␊ |
␊ |
␊ |
␊ |
#if DEBUG_MODULES␊ |
void print_hook_list()␊ |
{␊ |
␉printf("---Hook Table---\n");␊ |
␊ |
␉moduleHook_t* hooks = moduleCallbacks;␊ |
␉while(hooks)␊ |
␉{␊ |
␉␉printf("Hook: %s\n", hooks->name);␊ |
␉␉hooks = hooks->next;␊ |
␉}␊ |
}␊ |
#endif␊ |
␊ |
/*␊ |
* Initialize the module system by loading the Symbols.dylib module.␊ |
* Once loaded, locate the _lookup_symbol function so that internal␊ |
|
␉// Intialize module system␊ |
␉if(symbols_module_start == (void*)0xFFFFFFFF)␊ |
␉{␊ |
␉␉DBG("Module system not compiled in\n");␊ |
␉␉DBG("Module system not compiled in.\n"); DBGPAUSE();␊ |
␉␉load_module(SYMBOLS_MODULE);␊ |
␉␉␊ |
␉␉lookup_symbol = (void*)lookup_all_symbols(SYMBOL_LOOKUP_SYMBOL);␊ |
|
␉}␊ |
␉else {␊ |
␉␉// The module does not have a valid start function␊ |
␉␉printf("Unable to start %s\n", SYMBOLS_MODULE);␊ |
␉␉printf("Unable to start %s\n", SYMBOLS_MODULE); DBGPAUSE();␊ |
␉␉getc();␊ |
␉}␉␉␊ |
␉return 0;␊ |
|
␉␉␉char* tmp = malloc(strlen(name) + 1);␊ |
␉␉␉strcpy(tmp, name);␊ |
␉␉␉␊ |
␉␉␉DBG("Attempting to load %s\n", tmp);␉␉␉␊ |
␉␉␉if(!load_module(tmp))␊ |
␉␉␉{␊ |
␉␉␉␉// failed to load␊ |
|
␉// Check to see if the module has already been loaded␊ |
␉if(is_module_loaded(module))␊ |
␉{␊ |
␉␉// NOTE: Symbols.dylib tries to load twice, this catches it as well␊ |
␉␉// as when a module links with an already loaded module␊ |
␉␉DBG("Module %s already loaded\n", module);␊ |
␉␉return 1;␊ |
␉}␊ |
␉␊ |
|
␉fh = open(modString, 0);␊ |
␉if(fh < 0)␊ |
␉{␊ |
␉␉printf("Unable to locate module %s\n", modString);␊ |
␉␉printf("Unable to locate module %s\n", modString); DBGPAUSE();␊ |
␉␉getc();␊ |
␉␉return 0;␊ |
␉}␊ |
|
␉if (moduleSize && read(fh, module_base, moduleSize) == moduleSize)␊ |
␉{␊ |
␊ |
␉␉DBG("Module %s read in.\n", modString);␊ |
␉␉//DBG("Module %s read in.\n", modString);␊ |
␊ |
␉␉// Module loaded into memory, parse it␊ |
␉␉module_start = parse_mach(module_base, &load_module, &add_symbol);␊ |
|
␉␉{␊ |
␉␉␉// Notify the system that it was laoded␊ |
␉␉␉module_loaded(module/*moduleName, moduleVersion, moduleCompat*/);␊ |
␊ |
␉␉␉(*module_start)();␉// Start the module␊ |
␉␉␉DBG("Module %s Loaded.\n", module);␊ |
␉␉␉DBG("Module %s Loaded.\n", module); DBGPAUSE();␊ |
␉␉}␊ |
␉␉else {␊ |
␉␉␉// The module does not have a valid start function␊ |
|
␉␉getc();␊ |
␉}␊ |
␉close(fh);␊ |
␊ |
␉return 1;␊ |
}␊ |
␊ |
/*␊ |
*␉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.␊ |
* add_symbol␊ |
* This function adds a symbol from a module to the list of known symbols ␊ |
* possibly change to a pointer and add this to the Symbol module so that it can␊ |
* adjust it's internal symbol list (sort) to optimize locating new symbols␊ |
* NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF␊ |
*/␊ |
int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)␊ |
long long add_symbol(char* symbol, long long addr, char is64)␊ |
{␊ |
␉DBG("Attempting to execute hook '%s'\n", name);␊ |
␉moduleHook_t* hooks = moduleCallbacks;␊ |
␉if(is64) return 0xFFFFFFFF; // Fixme␊ |
␊ |
␉while(hooks && strcmp(name, hooks->name) < 0)␊ |
␉// This only can handle 32bit symbols ␊ |
␉symbolList_t* entry;␊ |
␉//DBG("Adding symbol %s at 0x%X\n", symbol, addr);␊ |
␉␊ |
␉if(!moduleSymbols)␊ |
␉{␊ |
␉␉//DBG("%s cmp %s = %d\n", name, hooks->name, strcmp(name, hooks->name));␊ |
␉␉hooks = hooks->next;␊ |
␉}␊ |
␉␉moduleSymbols = entry = malloc(sizeof(symbolList_t));␊ |
␊ |
␉if(hooks && strcmp(name, hooks->name) == 0)␊ |
␉}␊ |
␉else␊ |
␉{␊ |
␉␉// Loop through all callbacks for this module␊ |
␉␉callbackList_t* callbacks = hooks->callbacks;␊ |
␉␉␊ |
␉␉while(callbacks)␊ |
␉␉entry = moduleSymbols;␊ |
␉␉while(entry->next)␊ |
␉␉{␊ |
␉␉␉DBG("Executing '%s' with callback 0x%X.\n", name, callbacks->callback);␊ |
␉␉␉// Execute callback␊ |
␉␉␉callbacks->callback(arg1, arg2, arg3, arg4);␊ |
␉␉␉callbacks = callbacks->next;␊ |
␉␉␉DBG("Hook '%s' callback executed, next is 0x%X.\n", name, callbacks);␊ |
␉␉␉␊ |
␉␉␉entry = entry->next;␊ |
␉␉}␊ |
␉␉DBG("Hook '%s' executed.\n", name);␊ |
␉␉␊ |
␉␉return 1;␊ |
␉␉entry->next = malloc(sizeof(symbolList_t));␊ |
␉␉entry = entry->next;␊ |
␉}␊ |
␊ |
␉entry->next = NULL;␊ |
␉entry->addr = (UInt32)addr;␊ |
␉entry->symbol = symbol;␊ |
␉␊ |
␉if(strcmp(symbol, "start") == 0)␊ |
␉{␊ |
␉␉return addr;␊ |
␉}␊ |
␉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;␊ |
␉␉return 0xFFFFFFFF; // fixme␊ |
␉}␊ |
}␊ |
␊ |
␊ |
␊ |
/*␊ |
*␉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. When registering a new callback name, the callback is added sorted.␊ |
*␉␉␉NOTE: the hooks take four void* arguments.␊ |
*␉␉␉TODO: refactor␊ |
* print out the information about the loaded module␊ |
*/␊ |
void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))␊ |
{␉␊ |
␉DBG("Adding callback for '%s' hook.\n", name);␊ |
void module_loaded(const char* name/*, UInt32 version, UInt32 compat*/)␊ |
{␊ |
␉// TODO: insert sorted␊ |
␉moduleList_t* new_entry = malloc(sizeof(moduleList_t));␊ |
␊ |
␉moduleHook_t* newHook = malloc(sizeof(moduleHook_t));␊ |
␉if(!moduleCallbacks)␊ |
␉new_entry->next = loadedModules;␊ |
␉loadedModules = new_entry;␊ |
␉␊ |
␉new_entry->module = (char*)name;␊ |
␉new_entry->version = 0; //version;␊ |
␉new_entry->compat = 0; //compat;␊ |
}␊ |
␊ |
int is_module_loaded(const char* name)␊ |
{␊ |
␉// todo sorted search␊ |
␉moduleList_t* entry = loadedModules;␊ |
␉while(entry)␊ |
␉{␊ |
␉␉newHook->next = moduleCallbacks;␊ |
␉␉moduleCallbacks = newHook;␊ |
␉␉␊ |
␉␉newHook->name = name;␊ |
␉␉newHook->callbacks = (callbackList_t*)malloc(sizeof(callbackList_t));␊ |
␉␉newHook->callbacks->callback = callback;␊ |
␉␉newHook->callbacks->next = NULL;␊ |
␉}␊ |
␉else␊ |
␉{␊ |
␉␉moduleHook_t* hooks = moduleCallbacks;␊ |
␉␉␊ |
␉␉while(hooks->next && strcmp(name, hooks->next->name) < 0)␊ |
␉␉if(strcmp(entry->module, name) == 0)␊ |
␉␉{␊ |
␉␉␉hooks = hooks->next;␊ |
␉␉␉DBG("Located module %s\n", name); DBGPAUSE();␊ |
␉␉␉return 1;␊ |
␉␉}␊ |
␉␉␊ |
␉␉if(!hooks->next)␊ |
␉␉else␊ |
␉␉{␊ |
␉␉␉// Appent to the end␊ |
␉␉␉newHook->next = NULL;␊ |
␉␉␉hooks->next = newHook;␊ |
␉␉␉newHook->name = name;␊ |
␉␉␉newHook->callbacks = (callbackList_t*)malloc(sizeof(callbackList_t));␊ |
␉␉␉newHook->callbacks->callback = callback;␊ |
␉␉␉newHook->callbacks->next = NULL;␊ |
␉␉␉␊ |
␉␉␉␊ |
␉␉␉entry = entry->next;␊ |
␉␉}␊ |
␉␉else if(strcmp(name, hooks->next->name) == 0)␊ |
␊ |
␉}␊ |
␉DBG("Module %s not found\n", name); DBGPAUSE();␊ |
␊ |
␉return 0;␊ |
}␊ |
␊ |
// Look for symbols using the Smbols moduel function.␊ |
// If non are found, look through the list of module symbols␊ |
unsigned int lookup_all_symbols(const char* name)␊ |
{␊ |
␉unsigned int addr = 0xFFFFFFFF;␊ |
␉symbolList_t* entry = moduleSymbols;␊ |
␉while(entry)␊ |
␉{␊ |
␉␉if(strcmp(entry->symbol, name) == 0)␊ |
␉␉{␊ |
␉␉␉// We found the hook␊ |
␉␉␉// Hook alreday exists, add a callback to this hook␊ |
␉␉␉callbackList_t* callbacks = hooks->next->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;␊ |
␉␉␉//DBG("External symbol %s located at 0x%X\n", name, entry->addr);␊ |
␉␉␉return entry->addr;␊ |
␉␉}␊ |
␉␉else␊ |
␉␉{␊ |
␉␉␉// We are too far beyond the hook␊ |
␉␉␉newHook->next = hooks->next;␊ |
␉␉␉hooks->next = newHook;␊ |
␉␉␉newHook->name = name;␊ |
␉␉␉newHook->callbacks = (callbackList_t*)malloc(sizeof(callbackList_t));␊ |
␉␉␉newHook->callbacks->callback = callback;␊ |
␉␉␉newHook->callbacks->next = NULL;␊ |
␉␉␉␊ |
␉␉␉entry = entry->next;␊ |
␉␉}␊ |
␊ |
␉}␊ |
␉␊ |
␉if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)␊ |
␉{␊ |
␉␉addr = lookup_symbol(name);␊ |
␉␉if(addr != 0xFFFFFFFF)␊ |
␉␉{␊ |
␉␉␉//DBG("Internal symbol %s located at 0x%X\n", name, addr);␊ |
␉␉␉return addr;␊ |
␉␉}␊ |
␉}␊ |
␉␊ |
␊ |
#if DEBUG_MODULES␊ |
␉print_hook_list();␊ |
␉verbose("Unable to locate symbol %s\n", name);␊ |
␉getc();␊ |
#endif␊ |
␉␊ |
␊ |
␉return 0xFFFFFFFF;␊ |
}␊ |
␊ |
/********************************************************************************/␊ |
/*␉Macho Parser␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉*/␊ |
/********************************************************************************/␊ |
␊ |
/*␊ |
* Parse through a macho module. The module will be rebased and binded␊ |
|
␉␊ |
␉// Module info␊ |
␉/*char* moduleName = NULL;␊ |
␉UInt32 moduleVersion = 0;␊ |
␉UInt32 moduleCompat = 0;␊ |
␉*/␊ |
␉ UInt32 moduleVersion = 0;␊ |
␉ UInt32 moduleCompat = 0;␊ |
␉ */␊ |
␉// TODO convert all of the structs to a union␊ |
␉struct load_command *loadCommand = NULL;␊ |
␉struct dylib_command* dylibCommand = NULL;␊ |
|
␉struct symtab_command* symtabCommand = NULL;␊ |
␉struct segment_command *segCommand = NULL;␊ |
␉struct segment_command_64 *segCommand64 = NULL;␊ |
␊ |
␉␊ |
␉//struct dysymtab_command* dysymtabCommand = NULL;␊ |
␉UInt32 binaryIndex = 0;␊ |
␉UInt16 cmd = 0;␊ |
␊ |
␉␊ |
␉// Parse through the load commands␊ |
␉if(((struct mach_header*)binary)->magic == MH_MAGIC)␊ |
␉{␊ |
|
␉␉getc();␊ |
␉␉return NULL;␊ |
␉}␊ |
␊ |
␊ |
␉␊ |
␉␊ |
␉␊ |
␉/*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␊ |
␉}*/␊ |
␉ {␊ |
␉ printf("Module is not a dylib. Unable to load.\n");␊ |
␉ getc();␊ |
␉ return NULL; // Module is in the incorrect format␊ |
␉ }*/␊ |
␉␊ |
␉while(cmd < ((struct mach_header*)binary)->ncmds)␊ |
␉{␊ |
|
␉␉␊ |
␉␉loadCommand = binary + binaryIndex;␊ |
␉␉UInt32 cmdSize = loadCommand->cmdsize;␊ |
␊ |
␉␉␊ |
␉␉␊ |
␉␉switch ((loadCommand->cmd & 0x7FFFFFFF))␊ |
␉␉{␊ |
␉␉␉␉// TODO: sepeare function to handel appropriate sections␊ |
␉␉␉// TODO: sepeare function to handel appropriate sections␊ |
␉␉␉case LC_SYMTAB:␊ |
␉␉␉␉symtabCommand = binary + binaryIndex;␊ |
␉␉␉␉break;␊ |
|
␉␉␉␉␉␉}␉␉␉␉␉␊ |
␉␉␉␉␉}␊ |
␉␉␉␉}␊ |
␉␉␉␉else if(strcmp("__DATA", segCommand->segname) == 0)␊ |
␉␉␉␉{␊ |
␉␉␉␉␉UInt32 sectionIndex;␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉sectionIndex = sizeof(struct segment_command);␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉struct section *sect;␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉while(sectionIndex < segCommand->cmdsize)␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉sect = binary + binaryIndex + sectionIndex;␊ |
␉␉␉␉␉␉␊ |
␉␉␉␉␉␉sectionIndex += sizeof(struct section);␊ |
␉␉␉␉␉␉␊ |
␉␉␉␉␉␉␊ |
␉␉␉␉␉␉if(strcmp("__bss", sect->sectname) == 0)␊ |
␉␉␉␉␉␉{␊ |
␉␉␉␉␉␉␉// __TEXT,__text found, save the offset and address for when looking for the calls.␊ |
␉␉␉␉␉␉␉//printf("__DATA,__bss found.\n"); getc();␊ |
␉␉␉␉␉␉␉break;␊ |
␉␉␉␉␉␉}␉␉␉␉␉␊ |
␉␉␉␉␉}␊ |
␉␉␉␉␉␊ |
␉␉␉␉}␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉break;␊ |
␉␉␉case LC_SEGMENT_64:␉// 64bit macho's␊ |
␉␉␉␉segCommand64 = binary + binaryIndex;␊ |
|
␉␉␉␉␉␉␉break;␊ |
␉␉␉␉␉␉}␉␉␉␉␉␊ |
␉␉␉␉␉}␊ |
␉␉␉␉}␊ |
␉␉␉␉else if(strcmp("__DATA", segCommand->segname) == 0)␊ |
␉␉␉␉{␊ |
␉␉␉␉␉UInt32 sectionIndex;␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉sectionIndex = sizeof(struct segment_command_64);␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉struct section_64 *sect;␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉while(sectionIndex < segCommand->cmdsize)␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉sect = binary + binaryIndex + sectionIndex;␊ |
␉␉␉␉␉␉␊ |
␉␉␉␉␉␉sectionIndex += sizeof(struct section);␊ |
␉␉␉␉␉␉␊ |
␉␉␉␉␉␉␊ |
␉␉␉␉␉␉if(strcmp("__bss", sect->sectname) == 0)␊ |
␉␉␉␉␉␉{␊ |
␉␉␉␉␉␉␉// __TEXT,__text found, save the offset and address for when looking for the calls.␊ |
␉␉␉␉␉␉␉//printf("__DATA,__bss found.\n"); getc();␊ |
␉␉␉␉␉␉␉break;␊ |
␉␉␉␉␉␉}␉␉␉␉␉␊ |
␉␉␉␉␉}␊ |
␉␉␉␉␉␊ |
␉␉␉␉}␊ |
␉␉␉␉}␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case LC_DYSYMTAB:␊ |
|
␉␉␉␉{␊ |
␉␉␉␉␉char* name = malloc(strlen(module) + strlen(".dylib") + 1);␊ |
␉␉␉␉␉sprintf(name, "%s.dylib", module);␊ |
␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉if (!dylib_loader(name))␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉free(name);␊ |
|
␉␉␉␉␉␉//return NULL;␊ |
␉␉␉␉␉}␊ |
␉␉␉␉}␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case LC_ID_DYLIB:␊ |
␉␉␉␉dylibCommand = binary + binaryIndex;␊ |
␉␉␉␉/*moduleName =␉binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));␊ |
␉␉␉␉moduleVersion =␉dylibCommand->dylib.current_version;␊ |
␉␉␉␉moduleCompat =␉dylibCommand->dylib.compatibility_version;␊ |
␉␉␉␉ moduleVersion =␉dylibCommand->dylib.current_version;␊ |
␉␉␉␉ moduleCompat =␉dylibCommand->dylib.compatibility_version;␊ |
␉␉␉␉ */␊ |
␉␉␉␉break;␊ |
␊ |
␉␉␉␉␊ |
␉␉␉case LC_DYLD_INFO:␊ |
␉␉␉//case LC_DYLD_INFO_ONLY:␉// compressed info, 10.6+ macho files, already handeled␊ |
␉␉␉␉// Bind and rebase info is stored here␊ |
␉␉␉␉dyldInfoCommand = binary + binaryIndex;␊ |
␉␉␉␉break;␊ |
|
␉␉␉default:␊ |
␉␉␉␉DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);␊ |
␉␉␉␉break;␊ |
␉␉␊ |
␉␉␉␉␊ |
␉␉}␊ |
␊ |
␉␉␊ |
␉␉binaryIndex += cmdSize;␊ |
␉}␊ |
␉//if(!moduleName) return NULL;␊ |
␉␉␊ |
␊ |
␉␊ |
␉␊ |
␉// bind_macho uses the symbols.␊ |
␉module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);␊ |
␊ |
␉␊ |
␉// Rebase the module before binding it.␊ |
␉if(dyldInfoCommand && dyldInfoCommand->rebase_off)␊ |
␉{␊ |
|
␉␉// This should be changed to bind when a symbol is referened at runtime instead.␊ |
␉␉bind_macho(binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);␊ |
␉}␊ |
␊ |
␉␊ |
␉return module_start;␊ |
␉␊ |
}␊ |
␊ |
/*␊ |
* parse the symbol table␊ |
* Lookup any undefined symbols␊ |
*/␊ |
␊ |
unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)␊ |
{␊ |
␉// TODO: verify that the _TEXT,_text segment starts at the same locaiton in the file. If not␊ |
␉//␉␉␉subtract the vmaddress and add the actual file address back on. (NOTE: if compiled properly, not needed)␊ |
␉␊ |
␉unsigned int module_start = 0xFFFFFFFF;␊ |
␉␊ |
␉UInt32 symbolIndex = 0;␊ |
␉char* symbolString = base + (char*)symtabCommand->stroff;␊ |
␉//char* symbolTable = base + symtabCommand->symoff;␊ |
␉if(!is64)␊ |
␉{␊ |
␉␉struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;␊ |
␉␉while(symbolIndex < symtabCommand->nsyms)␊ |
␉␉{␊ |
␉␉␉// If the symbol is exported by this module␊ |
␉␉␉if(symbolEntry->n_value &&␊ |
␉␉␉ symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)␊ |
␉␉␉{␊ |
␉␉␉␉␊ |
␉␉␉␉// Module start located. Start is an alias so don't register it␊ |
␉␉␉␉module_start = base + symbolEntry->n_value;␊ |
␉␉␉}␊ |
␉␉␉␊ |
␉␉␉symbolEntry++;␊ |
␉␉␉symbolIndex++;␉// TODO remove␊ |
␉␉}␊ |
␉}␊ |
␉else␊ |
␉{␊ |
␉␉struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;␊ |
␉␉// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)␉␊ |
␉␉while(symbolIndex < symtabCommand->nsyms)␊ |
␉␉{␊ |
␉␉␉␊ |
␉␉␉␊ |
␉␉␉// If the symbol is exported by this module␊ |
␉␉␉if(symbolEntry->n_value &&␊ |
␉␉␉ symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)␊ |
␉␉␉{␊ |
␉␉␉␉␊ |
␉␉␉␉// Module start located. Start is an alias so don't register it␊ |
␉␉␉␉module_start = base + symbolEntry->n_value;␊ |
␉␉␉}␊ |
␉␉␉␊ |
␉␉␉symbolEntry++;␊ |
␉␉␉symbolIndex++;␉// TODO remove␊ |
␉␉}␊ |
␉}␊ |
␉␊ |
␉return module_start;␊ |
␉␊ |
}␊ |
␊ |
// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp␊ |
void rebase_macho(void* base, char* rebase_stream, UInt32 size)␊ |
{␊ |
|
␉{␊ |
␉␉immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;␊ |
␉␉opcode = rebase_stream[i] & REBASE_OPCODE_MASK;␊ |
␊ |
␉␉␊ |
␉␉␊ |
␉␉switch(opcode)␊ |
␉␉{␊ |
␉␉␉case REBASE_OPCODE_DONE:␊ |
|
␉␉␉case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:␊ |
␉␉␉␉// Locate address to begin rebasing␊ |
␉␉␉␉segmentAddress = 0;␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉struct segment_command* segCommand = NULL; // NOTE: 32bit only␊ |
␉␉␉␉␊ |
␉␉␉␉unsigned int binIndex = 0;␊ |
|
␉␉␉␉␉index++;␊ |
␉␉␉␉}␊ |
␉␉␉␉while(index <= immediate);␊ |
␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉segmentAddress = segCommand->fileoff;␊ |
␉␉␉␉␊ |
␉␉␉␉tmp = 0;␊ |
|
␉␉␉␉␉segmentAddress += sizeof(void*);␊ |
␉␉␉␉}␊ |
␉␉␉␉break;␊ |
␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:␊ |
␉␉␉␉tmp = 0;␊ |
␉␉␉␉bits = 0;␊ |
|
␉␉␉␉␊ |
␉␉␉␉index = 0;␊ |
␉␉␉␉for (index = 0; index < tmp; ++index) {␊ |
␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉rebase_location(base + segmentAddress, (char*)base, type);␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉segmentAddress += tmp2 + sizeof(void*);␊ |
|
␉}␊ |
}␊ |
␊ |
inline void rebase_location(UInt32* location, char* base, int type)␊ |
{␉␊ |
␉switch(type)␊ |
␉{␊ |
␉␉case REBASE_TYPE_POINTER:␊ |
␉␉case REBASE_TYPE_TEXT_ABSOLUTE32:␊ |
␉␉␉*location += (UInt32)base;␊ |
␉␉␉break;␊ |
␉␉␉␊ |
␉␉default:␊ |
␉␉␉break;␊ |
␉}␊ |
}␊ |
␊ |
␊ |
// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp␊ |
// NOTE: this uses 32bit values, and not 64bit values. ␊ |
// There is apossibility that this could cause issues,␊ |
|
␉␊ |
␉UInt8 immediate = 0;␊ |
␉UInt8 opcode = 0;␊ |
␉UInt8 type = 0;␊ |
␉UInt8 type = BIND_TYPE_POINTER;␊ |
␉␊ |
␉UInt32 segmentAddress = 0;␊ |
␉␊ |
␉UInt32 address = 0;␊ |
␉␊ |
␉SInt32 addend = 0;␉␉␉// TODO: handle this␊ |
␉SInt32 addend = 0;␊ |
␉SInt32 libraryOrdinal = 0;␊ |
␊ |
␉␊ |
␉const char* symbolName = NULL;␊ |
␉UInt8 symboFlags = 0;␊ |
␉UInt32 symbolAddr = 0xFFFFFFFF;␊ |
|
␉␉switch(opcode)␊ |
␉␉{␊ |
␉␉␉case BIND_OPCODE_DONE:␊ |
␉␉␉␉// reset vars␊ |
␉␉␉␉type = BIND_TYPE_POINTER;␊ |
␉␉␉␉segmentAddress = 0;␊ |
␉␉␉␉address = 0;␊ |
␉␉␉␉addend = 0;␊ |
␉␉␉␉libraryOrdinal = 0;␊ |
␉␉␉␉symbolAddr = 0xFFFFFFFF;␊ |
␉␉␉␉//done = 1; ␊ |
␉␉␉default:␊ |
␉␉␉␉break;␊ |
|
␉␉␉␉while(bind_stream[i] & 0x80);␊ |
␉␉␉␉␊ |
␉␉␉␉//printf("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 ? (SInt8)(BIND_OPCODE_MASK | immediate) : immediate;␉␉␉␉␊ |
␉␉␉␉//printf("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:␊ |
␉␉␉␉symboFlags = immediate;␊ |
␉␉␉␉symbolName = (char*)&bind_stream[++i];␊ |
␉␉␉␉i += strlen((char*)&bind_stream[i]);␊ |
␉␉␉␉//DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symboFlags);␊ |
␊ |
␉␉␉␉//DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X", symbolName, symboFlags);␊ |
␉␉␉␉␊ |
␉␉␉␉symbolAddr = lookup_all_symbols(symbolName);␊ |
␊ |
␉␉␉␉//DBG(", addr = 0x%X\n", symbolAddr);␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_SET_TYPE_IMM:␊ |
␉␉␉␉// Set bind type (pointer, absolute32, pcrel32)␊ |
␉␉␉␉type = immediate;␊ |
␉␉␉␉//DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_SET_ADDEND_SLEB:␊ |
|
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:␊ |
␉␉␉␉segmentAddress = 0;␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉// Locate address␊ |
␉␉␉␉struct segment_command* segCommand = NULL;␉// NOTE: 32bit only␊ |
␉␉␉␉␊ |
|
␉␉␉␉while(bind_stream[i] & 0x80);␊ |
␉␉␉␉␊ |
␉␉␉␉segmentAddress += tmp;␊ |
␉␉␉␉␊ |
␉␉␉␉//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;␊ |
␉␉␉␉//DBG("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_DO_BIND:␊ |
␉␉␉␉//DBG("BIND_OPCODE_DO_BIND\n");␊ |
␉␉␉␉if(libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP && type == BIND_TYPE_POINTER)␊ |
␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
␉␉␉␉{␊ |
␉␉␉␉␉// HACK(ish)␊ |
␉␉␉␉␉// Internal symbol, don't bind␊ |
␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
␉␉␉␉␉␉␊ |
␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
␉␉␉␉}␊ |
␉␉␉␉else␊ |
␉␉␉␉{␊ |
␉␉␉␉␉//printf("Binding symbol %s, libraryOrdinal = %d, symboFlags = %d, type = %d\n", symbolName, libraryOrdinal, symboFlags, type);␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
␉␉␉␉␉␉␊ |
␉␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);␊ |
␉␉␉␉␉}␊ |
␉␉␉␉␉else␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉printf("Unable to bind symbol %s, libraryOrdinal = %d, symboFlags = %d, type = %d\n", symbolName, libraryOrdinal, symboFlags, type);␊ |
␉␉␉␉␉␉getc();␊ |
␉␉␉␉␉}␊ |
␉␉␉␉␉printf("Unable to bind symbol %s, libraryOrdinal = %d, symboFlags = %d, type = %d\n", symbolName, libraryOrdinal, symboFlags, type);␊ |
␉␉␉␉␉getc();␊ |
␉␉␉␉}␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉segmentAddress += sizeof(void*);␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:␊ |
␉␉␉␉//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉// Read in offset␊ |
␉␉␉␉tmp = 0;␊ |
␉␉␉␉bits = 0;␊ |
|
␉␉␉␉␉bits += 7;␊ |
␉␉␉␉}␊ |
␉␉␉␉while(bind_stream[i] & 0x80);␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉if(libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP && type == BIND_TYPE_POINTER)␊ |
␊ |
␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
␉␉␉␉{␊ |
␉␉␉␉␉// Internal symbol, don't bind␊ |
␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
␉␉␉␉}␊ |
␉␉␉␉else␊ |
␉␉␉␉{␊ |
␉␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
␉␉␉␉␉␉␊ |
␉␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);␊ |
␉␉␉␉␉}␊ |
␉␉␉␉␉else␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
␉␉␉␉␉␉getc();␊ |
␉␉␉␉␉}␊ |
␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
␉␉␉␉␉getc();␊ |
␉␉␉␉}␊ |
␉␉␉␉segmentAddress += tmp + sizeof(void*);␊ |
␊ |
␉␉␉␉segmentAddress += tmp + sizeof(void*);␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:␊ |
␉␉␉␉//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");␊ |
␉␉␉␉if(libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP && type == BIND_TYPE_POINTER)␊ |
␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
␉␉␉␉{␊ |
␉␉␉␉␉// Internal symbol, don't bind␊ |
␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
␉␉␉␉␉␊ |
␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
␉␉␉␉}␊ |
␉␉␉␉else␊ |
␉␉␉␉{␊ |
␉␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
␉␉␉␉␉␉␊ |
␉␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);␊ |
␉␉␉␉␉}␊ |
␉␉␉␉␉else␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
␉␉␉␉␉␉getc();␊ |
␉␉␉␉␉}␊ |
␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
␉␉␉␉␉getc();␊ |
␉␉␉␉}␊ |
␉␉␉␉segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉break;␊ |
␉␉␉␉␊ |
␉␉␉case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉tmp = 0;␊ |
␉␉␉␉bits = 0;␊ |
␉␉␉␉do␊ |
|
␉␉␉␉␉bits += 7;␊ |
␉␉␉␉}␊ |
␉␉␉␉while(bind_stream[i] & 0x80);␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉tmp2 = 0;␊ |
␉␉␉␉bits = 0;␊ |
␉␉␉␉do␊ |
|
␉␉␉␉while(bind_stream[i] & 0x80);␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
␉␉␉␉//DBG("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);␊ |
␊ |
␉␉␉␉␊ |
␉␉␉␉if(symbolAddr != 0xFFFFFFFF)␊ |
␉␉␉␉{␊ |
␉␉␉␉␉for(index = 0; index < tmp; index++)␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉␊ |
␉␉␉␉␉␉address = segmentAddress + (UInt32)base;␊ |
␉␉␉␉␉␉if(libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP && type == BIND_TYPE_POINTER)␊ |
␉␉␉␉␉␉{␊ |
␉␉␉␉␉␉␉// Internal symbol, don't bind␊ |
␉␉␉␉␉␉}␊ |
␉␉␉␉␉␉else␊ |
␉␉␉␉␉␉{␊ |
␉␉␉␉␉␉␉␊ |
␉␉␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);␊ |
␉␉␉␉␉␉}␉␉␉␉␉␉␊ |
␉␉␉␉␉␉bind_location((UInt32*)address, (char*)symbolAddr, addend, type);␊ |
␉␉␉␉␉␉segmentAddress += tmp2 + sizeof(void*);␊ |
␉␉␉␉␉}␊ |
␉␉␉␉}␊ |
␉␉␉␉else␊ |
␉␉␉␉{␊ |
␉␉␉␉␉if(libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP && type == BIND_TYPE_POINTER)␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉// Internal symbol, don't bind␊ |
␉␉␉␉␉}␊ |
␉␉␉␉␉else␊ |
␉␉␉␉␉{␉␉␉␉␉␉␊ |
␉␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
␉␉␉␉␉␉getc();␊ |
␉␉␉␉␉}␊ |
␉␉␉␉␉printf("Unable to bind symbol %s\n", symbolName);␊ |
␉␉␉␉␉getc();␊ |
␉␉␉␉}␊ |
␉␉␉␉␊ |
␉␉␉␉␊ |
|
␉}␊ |
}␊ |
␊ |
inline void rebase_location(UInt32* location, char* base, int type)␊ |
{␉␊ |
␉switch(type)␊ |
␉{␊ |
␉␉case REBASE_TYPE_POINTER:␊ |
␉␉case REBASE_TYPE_TEXT_ABSOLUTE32:␊ |
␉␉␉*location += (UInt32)base;␊ |
␉␉␉break;␊ |
␉␉␉␊ |
␉␉default:␊ |
␉␉␉break;␊ |
␉}␊ |
}␊ |
␊ |
inline void bind_location(UInt32* location, char* value, UInt32 addend, int type)␊ |
{␉␊ |
␉// do actual update␊ |
␉char* newValue = value + addend;␊ |
␊ |
␉␊ |
␉switch (type) {␊ |
␉␉case BIND_TYPE_POINTER:␊ |
␉␉case BIND_TYPE_TEXT_ABSOLUTE32:␊ |
␉␉␉break;␊ |
␊ |
␉␉␉␊ |
␉␉case BIND_TYPE_TEXT_PCREL32:␊ |
␉␉␉newValue -= ((UInt32)location + 4);␊ |
␊ |
␉␉␉␊ |
␉␉␉break;␊ |
␉␉default:␊ |
␉␉␉return;␊ |
␉}␊ |
␉␊ |
␉//DBG("Binding 0x%X to 0x%X (was 0x%X)\n", location, newValue, *location);␊ |
␉*location = (UInt32)newValue;␊ |
}␊ |
␊ |
/********************************************************************************/␊ |
/*␉Module Hook Interface␉␉␉␉␉␉␉␉␉␉␉␉␉␉*/␊ |
/********************************************************************************/␊ |
␊ |
/*␊ |
* add_symbol␊ |
* This function adds a symbol from a module to the list of known symbols ␊ |
* possibly change to a pointer and add this to the Symbol module so that it can␊ |
* adjust it's internal symbol list (sort) to optimize locating new symbols␊ |
* NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF␊ |
*/␊ |
long long add_symbol(char* symbol, long long addr, char is64)␊ |
* Locate the symbol for an already loaded function and modify the beginning of␊ |
* the function to jump directly to the new one␊ |
* example: replace_function("_HelloWorld_start", &replacement_start);␊ |
*/␊ |
int replace_function(const char* symbol, void* newAddress)␊ |
{␊ |
␉if(is64) return 0xFFFFFFFF; // Fixme␊ |
␊ |
␉// This only can handle 32bit symbols ␊ |
␉symbolList_t* entry;␊ |
␉//DBG("Adding symbol %s at 0x%X\n", symbol, addr);␊ |
␉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 safer as␊ |
␉// function can be as small as 6 bytes.␊ |
␉UInt32 addr = lookup_all_symbols(symbol);␊ |
␉␊ |
␉if(!moduleSymbols)␊ |
␉char* binary = (char*)addr;␊ |
␉if(addr != 0xFFFFFFFF)␊ |
␉{␊ |
␉␉moduleSymbols = entry = malloc(sizeof(symbolList_t));␊ |
␊ |
␉␉//DBG("Replacing %s to point to 0x%x\n", symbol, newAddress);␊ |
␉␉*binary++ = 0xFF;␉// Jump␊ |
␉␉*binary++ = 0x25;␉// Long Jump␊ |
␉␉*((UInt32*)binary) = (UInt32)jumpPointer;␊ |
␉␉␊ |
␉␉*jumpPointer = (UInt32)newAddress;␊ |
␉␉␊ |
␉␉return 1;␊ |
␉}␊ |
␉else␊ |
␉else ␊ |
␉{␊ |
␉␉entry = moduleSymbols;␊ |
␉␉while(entry->next)␊ |
␉␉{␊ |
␉␉␉entry = entry->next;␊ |
␉␉}␊ |
␉␉␊ |
␉␉entry->next = malloc(sizeof(symbolList_t));␊ |
␉␉entry = entry->next;␊ |
␉␉return 0;␊ |
␉}␊ |
␉␊ |
}␊ |
␊ |
␉entry->next = NULL;␊ |
␉entry->addr = (UInt32)addr;␊ |
␉entry->symbol = symbol;␊ |
␊ |
/*␊ |
*␉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); DBGPAUSE();␊ |
␉moduleHook_t* hook = hook_exists(name);␊ |
␉␊ |
␉if(strcmp(symbol, "start") == 0)␊ |
␉if(hook)␊ |
␉{␊ |
␉␉return addr;␊ |
␉␉// Loop through all callbacks for this module␊ |
␉␉callbackList_t* callbacks = hook->callbacks;␊ |
␉␉␊ |
␉␉while(callbacks)␊ |
␉␉{␊ |
␉␉␉//DBG("Executing '%s' callback at 0x%X.\n", name, callbacks->callback);␊ |
␉␉␉// Execute callback␊ |
␉␉␉callbacks->callback(arg1, arg2, arg3, arg4);␊ |
␉␉␉callbacks = callbacks->next;␊ |
␉␉␉//DBG("Hook '%s' callback executed, next is 0x%X.\n", name, callbacks);␊ |
␉␉␉␊ |
␉␉}␊ |
␉␉DBG("Hook '%s' executed.\n", name); DBGPAUSE();␊ |
␉␉return 1;␊ |
␉}␊ |
␉else␊ |
␉{␊ |
␉␉return 0xFFFFFFFF; // fixme␊ |
␉␉// Callback for this hook doesn't exist;␊ |
␉␉DBG("No callbacks for '%s' hook.\n", name);␊ |
␉␉return 0;␊ |
␉}␊ |
}␊ |
␊ |
␊ |
␊ |
/*␊ |
* print out the information about the loaded module␊ |
␊ |
*␉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. When registering a new callback name, the callback is added sorted.␊ |
*␉␉␉NOTE: the hooks take four void* arguments.␊ |
*/␊ |
void module_loaded(const char* name/*, UInt32 version, UInt32 compat*/)␊ |
{␊ |
␉// TODO: insert sorted␊ |
␉moduleList_t* new_entry = malloc(sizeof(moduleList_t));␊ |
␊ |
␉new_entry->next = loadedModules;␊ |
␉loadedModules = new_entry;␊ |
void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))␊ |
{␉␊ |
␉DBG("Adding callback for '%s' hook.\n", name); DBGPAUSE();␊ |
␉␊ |
␉new_entry->module = (char*)name;␊ |
␉new_entry->version = 0; //version;␊ |
␉new_entry->compat = 0; //compat;␊ |
}␊ |
␊ |
int is_module_loaded(const char* name)␊ |
{␊ |
␉// todo sorted search␊ |
␉moduleList_t* entry = loadedModules;␊ |
␉while(entry)␊ |
␉moduleHook_t* hook = hook_exists(name);␊ |
␉␊ |
␉if(hook)␊ |
␉{␊ |
␉␉DBG("Comparing %s with %s\n", name, entry->module);␊ |
␉␉if(strcmp(entry->module, name) == 0)␊ |
␉␉{␊ |
␉␉␉DBG("Located module %s\n", name);␊ |
␉␉␉return 1;␊ |
␉␉}␊ |
␉␉else␊ |
␉␉{␊ |
␉␉␉entry = entry->next;␊ |
␉␉}␊ |
␊ |
␉␉// append␊ |
␉␉callbackList_t* newCallback = malloc(sizeof(callbackList_t));␊ |
␉␉newCallback->next = hook->callbacks;␊ |
␉␉hook->callbacks = newCallback;␊ |
␉␉newCallback->callback = callback;␊ |
␉}␊ |
␉DBG("Module %s not found\n", name);␊ |
␊ |
␉return 0;␊ |
}␊ |
␊ |
// Look for symbols using the Smbols moduel function.␊ |
// If non are found, look through the list of module symbols␊ |
unsigned int lookup_all_symbols(const char* name)␊ |
{␊ |
␉unsigned int addr = 0xFFFFFFFF;␊ |
␉symbolList_t* entry = moduleSymbols;␊ |
␉while(entry)␊ |
␉else␊ |
␉{␊ |
␉␉if(strcmp(entry->symbol, name) == 0)␊ |
␉␉{␊ |
␉␉␉//DBG("External symbol %s located at 0x%X\n", name, entry->addr);␊ |
␉␉␉return entry->addr;␊ |
␉␉}␊ |
␉␉else␊ |
␉␉{␊ |
␉␉␉entry = entry->next;␊ |
␉␉}␊ |
␊ |
␉␉// create new hook␊ |
␉␉moduleHook_t* newHook = malloc(sizeof(moduleHook_t));␉␉␊ |
␉␉newHook->name = name;␊ |
␉␉newHook->callbacks = malloc(sizeof(callbackList_t));␊ |
␉␉newHook->callbacks->callback = callback;␊ |
␉␉newHook->callbacks->next = NULL;␊ |
␉␉␊ |
␉␉newHook->next = moduleCallbacks;␊ |
␉␉moduleCallbacks = newHook;␊ |
␉␉␊ |
␉}␊ |
␉␊ |
␉if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)␊ |
␉{␊ |
␉␉addr = lookup_symbol(name);␊ |
␉␉if(addr != 0xFFFFFFFF)␊ |
␉␉{␊ |
␉␉␉//DBG("Internal symbol %s located at 0x%X\n", name, addr);␊ |
␉␉␉return addr;␊ |
␉␉}␊ |
␉}␊ |
␉␊ |
␊ |
#if DEBUG_MODULES␊ |
␉verbose("Unable to locate symbol %s\n", name);␊ |
␉getc();␊ |
␉//print_hook_list();␊ |
␉//getc();␊ |
#endif␊ |
␊ |
␉return 0xFFFFFFFF;␊ |
␉␊ |
}␊ |
␊ |
␊ |
/*␊ |
* parse the symbol table␊ |
* Lookup any undefined symbols␊ |
*/␊ |
␊ |
unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)␊ |
moduleHook_t* hook_exists(const char* name)␊ |
{␊ |
␉// TODO: verify that the _TEXT,_text segment starts at the same locaiton in the file. If not␊ |
␉//␉␉␉subtract the vmaddress and add the actual file address back on. (NOTE: if compiled properly, not needed)␊ |
␉moduleHook_t* hooks = moduleCallbacks;␊ |
␉␊ |
␉unsigned int module_start = 0xFFFFFFFF;␊ |
␉␊ |
␉UInt32 symbolIndex = 0;␊ |
␉char* symbolString = base + (char*)symtabCommand->stroff;␊ |
␉//char* symbolTable = base + symtabCommand->symoff;␊ |
␉if(!is64)␊ |
␉// look for a hook. If it exists, return the moduleHook_t*,␊ |
␉// If not, return NULL.␊ |
␉while(hooks)␊ |
␉{␊ |
␉␉struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;␊ |
␉␉while(symbolIndex < symtabCommand->nsyms)␊ |
␉␉if(strcmp(name, hooks->name) == 0)␊ |
␉␉{␊ |
␉␉␉// If the symbol is exported by this module␊ |
␉␉␉if(symbolEntry->n_value &&␊ |
␉␉␉ symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)␊ |
␉␉␉{␊ |
␉␉␉␉␊ |
␉␉␉␉// Module start located. Start is an alias so don't register it␊ |
␉␉␉␉module_start = base + symbolEntry->n_value;␊ |
␉␉␉}␊ |
␉␉␉␊ |
␉␉␉symbolEntry++;␊ |
␉␉␉symbolIndex++;␉// TODO remove␊ |
␉␉␉//DBG("Located hook %s\n", name);␊ |
␉␉␉return hooks;␊ |
␉␉}␊ |
␉␉hooks = hooks->next;␊ |
␉}␊ |
␉else␊ |
␉{␊ |
␉␉struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;␊ |
␉␉// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)␉␊ |
␉␉while(symbolIndex < symtabCommand->nsyms)␊ |
␉␉{␊ |
␉␉␉␊ |
␉␉␉␊ |
␉␉␉// If the symbol is exported by this module␊ |
␉␉␉if(symbolEntry->n_value &&␊ |
␉␉␉ symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64) != 0xFFFFFFFF)␊ |
␉␉␉{␊ |
␉␉␉␉␊ |
␉␉␉␉// Module start located. Start is an alias so don't register it␊ |
␉␉␉␉module_start = base + symbolEntry->n_value;␊ |
␉␉␉}␊ |
␉␉␉␊ |
␉␉␉symbolEntry++;␊ |
␉␉␉symbolIndex++;␉// TODO remove␊ |
␉␉}␊ |
␉}␊ |
␉␉␊ |
␉return module_start;␊ |
␉//DBG("Hook %s does not exist\n", name);␊ |
␉return NULL;␊ |
␉␊ |
}␊ |
␊ |
␊ |
/*␊ |
* Locate the symbol for an already loaded function and modify the beginning of␊ |
* the function to jump directly to the new one␊ |
* example: replace_function("_HelloWorld_start", &replacement_start);␊ |
*/␊ |
int replace_function(const char* symbol, void* newAddress)␊ |
#if DEBUG_MODULES␊ |
void print_hook_list()␊ |
{␊ |
␉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 safer as␊ |
␉// function can be as small as 6 bytes.␊ |
␉UInt32 addr = lookup_all_symbols(symbol);␊ |
␉printf("---Hook Table---\n");␊ |
␉␊ |
␉char* binary = (char*)addr;␊ |
␉if(addr != 0xFFFFFFFF)␊ |
␉moduleHook_t* hooks = moduleCallbacks;␊ |
␉while(hooks)␊ |
␉{␊ |
␉␉DBG("Replacing %s to point to 0x%x\n", symbol, newAddress);␊ |
␉␉*binary++ = 0xFF;␉// Jump␊ |
␉␉*binary++ = 0x25;␉// Long Jump␊ |
␉␉*((UInt32*)binary) = (UInt32)jumpPointer;␊ |
␉␉␊ |
␉␉*jumpPointer = (UInt32)newAddress;␊ |
␉␉␊ |
␉␉return 1;␊ |
␉␉printf("Hook: %s\n", hooks->name);␊ |
␉␉hooks = hooks->next;␊ |
␉}␊ |
␉else ␊ |
␉{␊ |
␉␉return 0;␊ |
␉}␊ |
␊ |
}␊ |
#endif␊ |
␊ |
/********************************************************************************/␊ |
/*␉dyld / Linker Interface␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉␉*/␊ |
/********************************************************************************/␊ |
␊ |
void dyld_stub_binder()␊ |
{␊ |
␉// TODO: actualy impliment this function (asm)␊ |
␉stop("ERROR: dyld_stub_binder was called, should have been take care of by the linker.\n");␊ |
} |
␉printf("ERROR: dyld_stub_binder was called, should have been take care of by the linker.\n");␊ |
␉getc();␊ |
}␊ |