bool application::application_private::setup_modules() { // dll // if module path is defined ... // TODO: add install path in // must provide default buildtin modules, ascii/utf8/basic_marks char * mod_env = ew::core::program::getenv("EEDIT_MODULES_LIST"); // TODO: add documentation comma separated list if (!mod_env) { app_log << "env[EEDIT_MODULES_LIST] is not defined...\n"; return true; } app_log << "env[EEDIT_MODULES_LIST] is set to : '" << mod_env << "'\n"; std::vector<std::string> mod_vec = split(mod_env, ','); // module_type(codec, filter, ???) // extern "C" dll::module_name() -> char * // extern "C" dll::module_type() -> int // based on type the module provides other interface see codec.h , filter.h for (auto & libname : mod_vec) { auto lib = std::make_unique<ew::core::dll>(libname.c_str()); app_log << "try to load file '" << libname << "'\n"; if (lib->load() == false) { app_log << "cannot load file '" << libname << "'\n"; continue; } bool error = false; // TODO lambda over mandatory symbols array // extract const char * mandatory_symbols[] = { "module_name", "module_version", "module_type", "module_init", "module_quit", "module_depends" }; for (auto sym : mandatory_symbols) { auto ptr = lib->symbol_by_name(sym); if (ptr == nullptr) { error = true; break; } app_log << "found symbol '" << sym << "'\n"; } if (error == true) { continue; } app_log << libname << " : all mandatory symbols found\n"; const char * (*modname_fn_ptr)() = reinterpret_cast<const char * (*)()>(lib->symbol_by_name("module_name")); const char * (*modversion_fn_ptr)() = reinterpret_cast<const char * (*)()>(lib->symbol_by_name("module_version")); eedit_module_type_e (*modtype_fn_ptr)() = reinterpret_cast<eedit_module_type_e (*)()>(lib->symbol_by_name("module_type")); // add to application module map std::string modname = modname_fn_ptr(); std::string modversion = modversion_fn_ptr(); eedit_module_type_e modtype = modtype_fn_ptr(); app_log << libname << " : modname : '" << modname << "'\n"; app_log << libname << " : modversion : '" << modversion << "'\n"; app_log << libname << " : modtype : '" << modtype << "'\n"; if (modtype == MODULE_TYPE_INVALID) { error = true; app_log << libname << " : invliad modtype\n"; } if (error == false) { if (module_map.find(modname) != module_map.end()) { error = true; } } if (error == false) { eedit_module_init_status_e (*modinit_fn_ptr)() = reinterpret_cast<eedit_module_init_status_e (*)()>(lib->symbol_by_name("module_init")); eedit_module_init_status_e modinit_ret = modinit_fn_ptr(); if (modinit_ret != MODULE_INIT_OK) { error = true; app_log << libname << " : modinit error\n"; } else { app_log << libname << " : modinit ok\n"; } } if (error == false) { // allow multiple version at same time ? // "modname:version" std::string prefix; auto modinfo = std::make_unique<module_info_s>(); modinfo->lib = std::move(lib); switch (modtype) { case MODULE_TYPE_CODEC: prefix = "codec"; break; case MODULE_TYPE_FILTER: prefix = "filter"; break; case MODULE_TYPE_EDITOR_MODE: prefix = "mode"; break; default: error = true; } if (error == false) { module_map[prefix + ":" + modname] = std::move(modinfo); } } } for ( const auto & e : module_map) { app_log << e.first << "\n"; } // TODO: config: // TODO: add config function function // load-codec [name] // load-codec text/ascii return true; }
void *elf_hook(char const *module_filename, void const *module_address, char const *name, void const *substitution) { static size_t pagesize; int descriptor; //file descriptor of shared module Elf_Shdr *dynsym = NULL, // ".dynsym" section header *rel_plt = NULL, // ".rel.plt" section header *rel_dyn = NULL; // ".rel.dyn" section header Elf_Sym *symbol = NULL; //symbol table entry for symbol named "name" Elf_Rel *rel_plt_table = NULL, //array with ".rel.plt" entries *rel_dyn_table = NULL; //array with ".rel.dyn" entries size_t i, name_index, //index of symbol named "name" in ".dyn.sym" rel_plt_amount, // amount of ".rel.plt" entries rel_dyn_amount, // amount of ".rel.dyn" entries *name_address = NULL; //address of relocation for symbol named "name" void *original = NULL; //address of the symbol being substituted if (NULL == module_address || NULL == name || NULL == substitution) return original; if (!pagesize) pagesize = sysconf(_SC_PAGESIZE); descriptor = open(module_filename, O_RDONLY); if (descriptor < 0) return original; if ( section_by_type(descriptor, SHT_DYNSYM, &dynsym) || //get ".dynsym" section symbol_by_name(descriptor, dynsym, name, &symbol, &name_index) || //actually, we need only the index of symbol named "name" in the ".dynsym" table section_by_name(descriptor, REL_PLT, &rel_plt) || //get ".rel.plt" (for 32-bit) or ".rela.plt" (for 64-bit) section section_by_name(descriptor, REL_DYN, &rel_dyn) //get ".rel.dyn" (for 32-bit) or ".rela.dyn" (for 64-bit) section ) { //if something went wrong free(dynsym); free(rel_plt); free(rel_dyn); free(symbol); close(descriptor); return original; } //release the data used free(dynsym); free(symbol); rel_plt_table = (Elf_Rel *)(((size_t)module_address) + rel_plt->sh_addr); //init the ".rel.plt" array rel_plt_amount = rel_plt->sh_size / sizeof(Elf_Rel); //and get its size rel_dyn_table = (Elf_Rel *)(((size_t)module_address) + rel_dyn->sh_addr); //init the ".rel.dyn" array rel_dyn_amount = rel_dyn->sh_size / sizeof(Elf_Rel); //and get its size //release the data used free(rel_plt); free(rel_dyn); //and descriptor close(descriptor); //now we've got ".rel.plt" (needed for PIC) table and ".rel.dyn" (for non-PIC) table and the symbol's index for (i = 0; i < rel_plt_amount; ++i) //lookup the ".rel.plt" table if (ELF_R_SYM(rel_plt_table[i].r_info) == name_index) //if we found the symbol to substitute in ".rel.plt" { original = (void *)*(size_t *)(((size_t)module_address) + rel_plt_table[i].r_offset); //save the original function address *(size_t *)(((size_t)module_address) + rel_plt_table[i].r_offset) = (size_t)substitution; //and replace it with the substitutional break; //the target symbol appears in ".rel.plt" only once } if (original) return original; //we will get here only with 32-bit non-PIC module for (i = 0; i < rel_dyn_amount; ++i) //lookup the ".rel.dyn" table if (ELF_R_SYM(rel_dyn_table[i].r_info) == name_index) //if we found the symbol to substitute in ".rel.dyn" { name_address = (size_t *)(((size_t)module_address) + rel_dyn_table[i].r_offset); //get the relocation address (address of a relative CALL (0xE8) instruction's argument) if (!original) original = (void *)(*name_address + (size_t)name_address + sizeof(size_t)); //calculate an address of the original function by a relative CALL (0xE8) instruction's argument mprotect((void *)(((size_t)name_address) & (((size_t)-1) ^ (pagesize - 1))), pagesize, PROT_READ | PROT_WRITE); //mark a memory page that contains the relocation as writable if (errno) return NULL; *name_address = (size_t)substitution - (size_t)name_address - sizeof(size_t); //calculate a new relative CALL (0xE8) instruction's argument for the substitutional function and write it down mprotect((void *)(((size_t)name_address) & (((size_t)-1) ^ (pagesize - 1))), pagesize, PROT_READ | PROT_EXEC); //mark a memory page that contains the relocation back as executable if (errno) //if something went wrong { *name_address = (size_t)original - (size_t)name_address - sizeof(size_t); //then restore the original function address return NULL; } } return original; }
void ExecFileParser::find_NOPs() { try { NOP_symbols.push_back(symbol_by_name("_TRaP_Linux_PaddingBytes_text").start); } catch (std::out_of_range e) {} sort(NOP_symbols.begin(), NOP_symbols.end()); }