Replaced all instances of the word "module" with "plugin"

This commit is contained in:
Maschell
2018-02-18 16:10:27 +01:00
parent d0908e7eb6
commit 41da4db58c
19 changed files with 194 additions and 194 deletions

View File

@@ -0,0 +1,428 @@
/* based on module.c
* by Alex Chadwick
*
* Copyright (C) 2014, Alex Chadwick
* Modified 2018, Maschell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "ElfTools.h"
#include <string.h>
#include <malloc.h>
#include <libelf.h>
#include <utils/logger.h>
bool ElfTools::elfLoadSection(const Elf *elf, Elf_Scn *scn, const Elf32_Shdr *shdr,void *destination) {
if (destination == NULL) { return false; }
switch (shdr->sh_type) {
case SHT_SYMTAB:
case SHT_PROGBITS: {
Elf_Data *data;
size_t n;
n = 0;
for (data = elf_getdata(scn, NULL); data != NULL; data = elf_getdata(scn, data)) {
memcpy((char *)destination + n, data->d_buf, data->d_size);
n += data->d_size;
}
return true;
} case SHT_NOBITS: {
memset(destination, 0, shdr->sh_size);
return true;
} default:
return false;
}
}
bool ElfTools::loadElfSymtab(Elf *elf, Elf32_Sym **symtab, size_t *symtab_count, size_t *symtab_strndx) {
Elf_Scn *scn;
bool result = false;
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
Elf32_Shdr *shdr;
shdr = elf32_getshdr(scn);
if (shdr == NULL){
continue;
}
if (shdr->sh_type == SHT_SYMTAB) {
size_t sym;
if (*symtab != NULL){
continue;
}
*symtab = (Elf32_Sym *)malloc(shdr->sh_size);
if (*symtab == NULL){
continue;
}
*symtab_count = shdr->sh_size / sizeof(Elf32_Sym);
*symtab_strndx = shdr->sh_link;
if (!elfLoadSection(elf, scn, shdr, *symtab)){
goto exit_error;
}
for (sym = 0; sym < *symtab_count; sym++){
(*symtab)[sym].st_other = 0;
}
break;
}
}
if (*symtab == NULL){
goto exit_error;
}
result = true;
exit_error:
return result;
}
void ElfTools::elfLoadSymbols(size_t shndx, const void *destination, Elf32_Sym *symtab, size_t symtab_count) {
size_t i;
/* use the st_other field (no defined meaning) to indicate whether or not a
* symbol address has been calculated. */
for (i = 0; i < symtab_count; i++) {
if (symtab[i].st_shndx == shndx &&
symtab[i].st_other == 0) {
symtab[i].st_value += (Elf32_Addr)destination;
symtab[i].st_other = 1;
}
}
}
bool ElfTools::elfLink(Elf *elf, size_t shndx, void *destination, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx, bool allow_globals) {
Elf_Scn *scn;
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
Elf32_Shdr *shdr;
shdr = elf32_getshdr(scn);
if (shdr == NULL)
continue;
switch (shdr->sh_type) {
case SHT_REL: {
const Elf32_Rel *rel;
Elf_Data *data;
size_t i;
if (shdr->sh_info != shndx){
continue;
}
data = elf_getdata(scn, NULL);
if (data == NULL){
continue;
}
rel = (const Elf32_Rel *) data->d_buf;
for (i = 0; i < shdr->sh_size / sizeof(Elf32_Rel); i++) {
uint32_t symbol_addr;
size_t symbol;
symbol = ELF32_R_SYM(rel[i].r_info);
if (symbol > symtab_count)
return false;
switch (symtab[symbol].st_shndx) {
case SHN_ABS: {
symbol_addr = symtab[symbol].st_value;
break;
} case SHN_COMMON: {
return false;
} case SHN_UNDEF: {
if (allow_globals) {
DEBUG_FUNCTION_LINE("The elf still have unresolved relocations. This is not supported.");
/*
Not support and not needed.
module_unresolved_relocation_t *reloc;
char *name;
reloc = (module_unresolved_relocation_t *) Module_ListAllocate(
&module_relocations,
sizeof(module_unresolved_relocation_t), 1,
&module_relocations_capacity,
&module_relocations_count,
PLUGIN_RELOCATIONS_CAPCITY_DEFAULT);
if (reloc == NULL)
return false;
name = elf_strptr(
elf, symtab_strndx, symtab[symbol].st_name);
if (name == NULL) {
module_relocations_count--;
return false;
}
reloc->name = strdup(name);
if (reloc->name == NULL) {
module_relocations_count--;
return false;
}
reloc->module = index;
reloc->address = destination;
reloc->offset = rel[i].r_offset;
reloc->type = ELF32_R_TYPE(rel[i].r_info);
reloc->addend = *(int *)((char *)destination + rel[i].r_offset);
continue;
*/
return false;
} else {
return false;
}
} default: {
if (symtab[symbol].st_other != 1) {
return false;
}
symbol_addr = symtab[symbol].st_value;
break;
}
}
if (!ElfTools::elfLinkOne(ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, *(int *)((char *)destination + rel[i].r_offset), destination, symbol_addr)){
return false;
}
}
break;
} case SHT_RELA: {
const Elf32_Rela *rela;
Elf_Data *data;
size_t i;
if (shdr->sh_info != shndx)
continue;
data = elf_getdata(scn, NULL);
if (data == NULL)
continue;
rela = (const Elf32_Rela *) data->d_buf;
for (i = 0; i < shdr->sh_size / sizeof(Elf32_Rela); i++) {
uint32_t symbol_addr;
size_t symbol;
symbol = ELF32_R_SYM(rela[i].r_info);
if (symbol > symtab_count)
return false;
switch (symtab[symbol].st_shndx) {
case SHN_ABS: {
symbol_addr = symtab[symbol].st_value;
break;
} case SHN_COMMON: {
return false;
} case SHN_UNDEF: {
if (allow_globals) {
DEBUG_FUNCTION_LINE("The elf still have unresolved relocations. This is not supported.");
/*
Not support and not needed.
module_unresolved_relocation_t *reloc;
char *name;
reloc = (module_unresolved_relocation_t *) Module_ListAllocate(
&module_relocations,
sizeof(module_unresolved_relocation_t), 1,
&module_relocations_capacity,
&module_relocations_count,
PLUGIN_RELOCATIONS_CAPCITY_DEFAULT);
if (reloc == NULL)
return false;
name = elf_strptr(
elf, symtab_strndx, symtab[symbol].st_name);
if (name == NULL) {
module_relocations_count--;
return false;
}
reloc->name = strdup(name);
if (reloc->name == NULL) {
module_relocations_count--;
return false;
}
DEBUG_FUNCTION_LINE("Adding relocation!\n");
reloc->module = index;
reloc->address = destination;
reloc->offset = rela[i].r_offset;
reloc->type = ELF32_R_TYPE(rela[i].r_info);
reloc->addend = rela[i].r_addend;
continue;*/
return false;
} else
return false;
} default: {
if (symtab[symbol].st_other != 1){
return false;
}
symbol_addr = symtab[symbol].st_value;
break;
}
}
if (!ElfTools::elfLinkOne(ELF32_R_TYPE(rela[i].r_info), rela[i].r_offset,rela[i].r_addend, destination, symbol_addr)){
return false;
}
}
break;
}
}
}
return true;
}
bool ElfTools::elfLinkOne(char type, size_t offset, int addend, void *destination, uint32_t symbol_addr) {
int value;
char *target = (char *)destination + offset;
bool result = false;
switch (type) {
case R_PPC_ADDR32:
case R_PPC_ADDR24:
case R_PPC_ADDR16:
case R_PPC_ADDR16_HI:
case R_PPC_ADDR16_HA:
case R_PPC_ADDR16_LO:
case R_PPC_ADDR14:
case R_PPC_ADDR14_BRTAKEN:
case R_PPC_ADDR14_BRNTAKEN:
case R_PPC_UADDR32:
case R_PPC_UADDR16: {
value = (int)symbol_addr + addend;
break;
} case R_PPC_REL24:
case R_PPC_PLTREL24:
case R_PPC_LOCAL24PC:
case R_PPC_REL14:
case R_PPC_REL14_BRTAKEN:
case R_PPC_REL14_BRNTAKEN:
case R_PPC_REL32:
case R_PPC_ADDR30: {
value = (int)symbol_addr + addend - (int)target;
break;
} case R_PPC_SECTOFF:
case R_PPC_SECTOFF_LO:
case R_PPC_SECTOFF_HI:
case R_PPC_SECTOFF_HA: {
value = offset + addend;
break;
} case R_PPC_EMB_NADDR32:
case R_PPC_EMB_NADDR16:
case R_PPC_EMB_NADDR16_LO:
case R_PPC_EMB_NADDR16_HI:
case R_PPC_EMB_NADDR16_HA: {
value = addend - (int)symbol_addr;
break;
} default:
DEBUG_FUNCTION_LINE("Unknown relocation type: %02X\n",type);
goto exit_error;
}
switch (type) {
case R_PPC_ADDR32:
case R_PPC_UADDR32:
case R_PPC_REL32:
case R_PPC_SECTOFF:
case R_PPC_EMB_NADDR32: {
*(int *)target = value;
break;
} case R_PPC_ADDR24:
case R_PPC_PLTREL24:
case R_PPC_LOCAL24PC:
case R_PPC_REL24: {
*(int *)target =
(*(int *)target & 0xfc000003) | (value & 0x03fffffc);
break;
} case R_PPC_ADDR16:
case R_PPC_UADDR16:
case R_PPC_EMB_NADDR16: {
*(short *)target = value;
break;
} case R_PPC_ADDR16_HI:
case R_PPC_SECTOFF_HI:
case R_PPC_EMB_NADDR16_HI: {
*(short *)target = value >> 16;
break;
} case R_PPC_ADDR16_HA:
case R_PPC_SECTOFF_HA:
case R_PPC_EMB_NADDR16_HA: {
*(short *)target = (value >> 16) + ((value >> 15) & 1);
break;
} case R_PPC_ADDR16_LO:
case R_PPC_SECTOFF_LO:
case R_PPC_EMB_NADDR16_LO: {
*(short *)target = value & 0xffff;
break;
} case R_PPC_ADDR14:
case R_PPC_REL14: {
*(int *)target =
(*(int *)target & 0xffff0003) | (value & 0x0000fffc);
break;
} case R_PPC_ADDR14_BRTAKEN:
case R_PPC_REL14_BRTAKEN: {
*(int *)target =
(*(int *)target & 0xffdf0003) | (value & 0x0000fffc) |
0x00200000;
break;
} case R_PPC_ADDR14_BRNTAKEN:
case R_PPC_REL14_BRNTAKEN: {
*(int *)target =
(*(int *)target & 0xffdf0003) | (value & 0x0000fffc);
break;
} case R_PPC_ADDR30: {
*(int *)target =
(*(int *)target & 0x00000003) | (value & 0xfffffffc);
break;
}default:
goto exit_error;
}
result = true;
exit_error:
if (!result) DEBUG_FUNCTION_LINE("Plugin_ElfLinkOne: exit_error\n");
return result;
}

View File

@@ -0,0 +1,49 @@
/* based on module.c
* by Alex Chadwick
*
* Copyright (C) 2014, Alex Chadwick
* Modified 2018, Maschell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _ELF_TOOLS_H_
#define _ELF_TOOLS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <libelf.h>
#ifdef __cplusplus
}
#endif
class ElfTools{
public:
static bool elfLoadSection(const Elf *elf, Elf_Scn *scn, const Elf32_Shdr *shdr,void *destination);
static bool loadElfSymtab(Elf *elf, Elf32_Sym **symtab, size_t *symtab_count, size_t *symtab_strndx);
static void elfLoadSymbols(size_t shndx, const void *destination, Elf32_Sym *symtab, size_t symtab_count);
static bool elfLink(Elf *elf, size_t shndx, void *destination, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx, bool allow_globals);
static bool elfLinkOne(char type, size_t offset, int addend, void *destination, uint32_t symbol_addr);
};
#endif

View File

@@ -0,0 +1,62 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _ENTRY_DATA_H_
#define _ENTRY_DATA_H_
#include <wups.h>
#include <string>
class EntryData{
public:
EntryData(const char * name, wups_loader_library_type_t library, void * target, void * call_addr){
this->name = name;
this->library = library;
this->replaceAddr = target;
this->replaceCall = call_addr;
}
~EntryData(){
}
std::string getName(){
return this->name;
}
wups_loader_library_type_t getLibrary(){
return this->library;
}
void * getReplaceAddress(){
return replaceAddr;
}
void * getReplaceCall(){
return replaceCall;
}
private:
std::string name;
wups_loader_library_type_t library;
void * replaceAddr = NULL;
void * replaceCall = NULL;
};
#endif

View File

@@ -0,0 +1,49 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _HOOK_DATA_H_
#define _HOOK_DATA_H_
#include <wups.h>
#include <string>
class HookData{
public:
HookData(void * function_pointer, wups_loader_hook_type_t type){
this->function_pointer = function_pointer;
this->type = type;
}
~HookData(){
}
void * getFunctionPointer(){
return function_pointer;
}
wups_loader_hook_type_t getType(){
return this->type;
}
private:
void * function_pointer;
wups_loader_hook_type_t type;
};
#endif

View File

@@ -0,0 +1,87 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _PLUGIN_DATA_H_
#define _PLUGIN_DATA_H_
#include <string>
#include <vector>
#include "EntryData.h"
#include "HookData.h"
#include "PluginInformation.h"
#include <utils/logger.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <libelf.h>
#ifdef __cplusplus
}
#endif
class PluginData{
public:
PluginData(PluginInformation * pluginInformation){
this->pluginInformation = pluginInformation;
}
~PluginData(){
for(size_t i = 0;i< entry_data_list.size();i++){
if(entry_data_list[i] != NULL){
delete entry_data_list[i];
}
}
for(size_t i = 0;i< hook_data_list.size();i++){
if(hook_data_list[i] != NULL){
delete hook_data_list[i];
}
}
}
void addEntryData(EntryData * entry_data){
entry_data_list.push_back(entry_data);
}
std::vector<EntryData *> getEntryDataList(){
return entry_data_list;
}
void addHookData(HookData * hook_data){
hook_data_list.push_back(hook_data);
}
std::vector<HookData *> getHookDataList(){
return hook_data_list;
}
PluginInformation * getPluginInformation(){
return pluginInformation;
}
private:
PluginInformation * pluginInformation;
std::vector<EntryData *> entry_data_list;
std::vector<HookData *> hook_data_list;
};
#endif

View File

@@ -0,0 +1,404 @@
/* based on plugin.c
* by Alex Chadwick
*
* Copyright (C) 2014, Alex Chadwick
* Modified 2018, Maschell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "PluginInformation.h"
#include <utils/logger.h>
#include <dynamic_libs/os_types.h>
#include <libelf.h>
#include <string.h>
#include <sys/types.h>
#include <wups.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <utils/utils.h>
#include "ElfTools.h"
bool PluginInformation::checkFileExtenstion(const char * path) {
if(path == NULL){
return false;
}
const char *extension;
/* find the file extension */
extension = strrchr(path, '.');
if (extension == NULL){
extension = strchr(path, '\0');
}else{
extension++;
}
if(extension == NULL){
return false;
}
if (strcmp(extension, "mod") == 0 ||
strcmp(extension, "o") == 0 ||
strcmp(extension, "a") == 0 ||
strcmp(extension, "elf") == 0) {
return true;
}
return false;
}
bool PluginInformation::openAndParseElf() {
bool result = false;
int fd = -1;
Elf *elf = NULL;
/* check for compile errors */
if (elf_version(EV_CURRENT) == EV_NONE){
goto exit_error;
}
fd = open(getPath().c_str(), O_RDONLY, 0);
if (fd == -1){
DEBUG_FUNCTION_LINE("failed to open '%s' \n", getPath().c_str());
goto exit_error;
}
elf = elf_begin(fd, ELF_C_READ, NULL);
if (elf == NULL){
DEBUG_FUNCTION_LINE("elf was NULL\n");
goto exit_error;
}
switch (elf_kind(elf)) {
case ELF_K_AR:
/* TODO */
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Archives not yet supported.\n", getPath().c_str());
goto exit_error;
case ELF_K_ELF:
result = this->parseElf(elf);
break;
default:
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF file.\n", getPath().c_str());
goto exit_error;
}
exit_error:
if (elf != NULL){
elf_end(elf);
}
if (fd != -1){
close(fd);
}
return result;
}
bool PluginInformation::parseElf( Elf *elf) {
bool res = false;
Elf_Scn *scn;
Elf32_Ehdr *ehdr;
char *ident;
size_t shstrndx, sz, symtab_count, symtab_strndx;
Elf32_Sym *symtab = NULL;
size_t cur_size = 0;
const char * path_c = getPath().c_str();
if(elf == NULL){ goto exit_error; }
if(elf_kind(elf) != ELF_K_ELF){ goto exit_error; }
ident = elf_getident(elf, &sz);
if (ident == NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF header.\n", path_c);
goto exit_error;
}
if (sz < 7) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF header.\n", path_c);
goto exit_error;
}
if (ident[4] != ELFCLASS32) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not 32 bit ELF.\n", path_c);
goto exit_error;
}
if (ident[5] != ELFDATA2MSB) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not Big Endian.\n", path_c);
goto exit_error;
}
if (ident[6] != EV_CURRENT) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unknown ELF version.\n", path_c);
goto exit_error;
}
ehdr = elf32_getehdr(elf);
if (ehdr == NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF header\n", path_c);
goto exit_error;
}
if (ehdr->e_type != ET_REL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not relocatable ELF.\n", path_c);
goto exit_error;
}
if (ehdr->e_machine != EM_PPC) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Architecture not EM_PPC.\n", path_c);
goto exit_error;
}
if (ehdr->e_version != EV_CURRENT) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unknown ELF version.\n", path_c);
goto exit_error;
}
if (!ElfTools::loadElfSymtab(elf, &symtab, &symtab_count, &symtab_strndx)) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't parse symtab.\n", path_c);
goto exit_error;
}
if(symtab == NULL){ goto exit_error; }
if(!metadataRead(elf, symtab, symtab_count, symtab_strndx)){
goto exit_error;
}
if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't find shdrstndx.\n", path_c);
goto exit_error;
}
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
Elf32_Shdr *shdr;
shdr = elf32_getshdr(scn);
if (shdr == NULL){
continue;
}
if ((shdr->sh_type == SHT_PROGBITS || shdr->sh_type == SHT_NOBITS) &&
(shdr->sh_flags & SHF_ALLOC)) {
const char *name;
name = elf_strptr(elf, shstrndx, shdr->sh_name);
if (name == NULL){
continue;
}
if (strcmp(name, ".wups.meta") == 0) {
continue;
} else if (strcmp(name, ".wups.load") == 0) {
cur_size +=
shdr->sh_size / sizeof(wups_loader_entry_t) * 6*4;
} else if (strcmp(name, ".wups.hooks") == 0) {
cur_size +=
shdr->sh_size / sizeof(wups_loader_hook_t) * 2*4;
} else {
cur_size += shdr->sh_size;
/* add alignment padding to size */
if (shdr->sh_addralign > 3){
/* roundup to multiple of sh_addralign */
cur_size += (-cur_size & (shdr->sh_addralign - 1));
}else{
/* roundup to multiple of 4 */
cur_size += (-cur_size & 3);
}
}
}
}
/* roundup to multiple of 4 */
cur_size += (-cur_size & 3);
this->setSize(cur_size);
res = true;
exit_error:
if (symtab != NULL){
free(symtab);
}
return res;
}
bool PluginInformation::metadataRead(Elf *elf, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx) {
char *metadata = NULL, *metadata_cur, *metadata_end;
const char *game, *name, *author, *version, *license, *wups;
Elf_Scn *scn;
size_t shstrndx;
if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't find shstrndx\n", path);
goto exit_error;
}
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
Elf32_Shdr *shdr;
const char *name;
shdr = elf32_getshdr(scn);
if (shdr == NULL){
continue;
}
name = elf_strptr(elf, shstrndx, shdr->sh_name);
if (name == NULL){
continue;
}
if (strcmp(name, ".wups.meta") == 0) {
if (shdr->sh_size == 0){
continue;
}
if (metadata != NULL){
continue;
}
metadata = (char*) malloc(shdr->sh_size);
if (metadata == NULL){
continue;
}
if (!ElfTools::elfLoadSection(elf, scn, shdr, metadata)) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't load .wups.meta.\n", path);
goto exit_error;
}
ElfTools::elfLoadSymbols(elf_ndxscn(scn), metadata, symtab, symtab_count);
if (!ElfTools::elfLink(elf, elf_ndxscn(scn), metadata, symtab, symtab_count, symtab_strndx, false)) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - .wups.meta contains invalid relocations.\n", path);
goto exit_error;
}
metadata_end = metadata + shdr->sh_size;
metadata_end[-1] = '\0';
}
}
if (metadata == NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not a WUPS plugin file.\n", path);
goto exit_error;
}
game = NULL;
name = NULL;
author = NULL;
version = NULL;
license = NULL;
wups = NULL;
for (metadata_cur = metadata; metadata_cur < metadata_end; metadata_cur = strchr(metadata_cur, '\0') + 1) {
char *eq;
if(metadata_cur < metadata || metadata_cur >= metadata_end){
goto exit_error;
}
if (*metadata_cur == '\0'){
continue;
}
eq = strchr(metadata_cur, '=');
if (eq == NULL){
continue;
}
if (strncmp(metadata_cur, "game", eq - metadata_cur) == 0) {
if (game != NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_GAME declarations.\n", path);
goto exit_error;
}
game = eq + 1;
} else if (strncmp(metadata_cur, "name", eq - metadata_cur) == 0) {
if (name != NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_NAME declarations.\n", path);
goto exit_error;
}
name = eq + 1;
} else if (strncmp(metadata_cur, "author", eq - metadata_cur) == 0) {
if (author != NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_AUTHOR declarations.\n", path);
goto exit_error;
}
author = eq + 1;
} else if (strncmp(metadata_cur, "version", eq - metadata_cur) == 0) {
if (version != NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_VERSION declarations.\n", path);
goto exit_error;
}
version = eq + 1;
} else if (strncmp(metadata_cur, "license", eq - metadata_cur) == 0) {
if (license != NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_LICENSE declarations.\n", path);
goto exit_error;
}
license = eq + 1;
} else if (strncmp(metadata_cur, "wups", eq - metadata_cur) == 0) {
if (wups != NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_NAME declarations.\n", path);
goto exit_error;
}
wups = eq + 1;
}
}
if (game == NULL){
game = "";
}
// TODO:
/*if (wups == NULL || strcmp(wups, "0.1") != 0) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unrecognised WUPS version.\n", path);
goto exit_error;
}*/
if (name == NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Missing WUPS_PLUGIN_NAME declaration.\n",path);
goto exit_error;
}
if (author == NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Missing WUPS_PLUGIN_AUTHOR declaration.\n", path);
goto exit_error;
}
if (version == NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Missing WUPS_PLUGIN_VERSION declaration.\n", path);
goto exit_error;
}
if (license == NULL) {
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Missing WUPS_PLUGIN_LICENSE declaration.\n", path);
goto exit_error;
}
this->setName(name);
this->setAuthor(author);
this->setVersion(version);
this->setLicense(license);
return true;
exit_error:
if (metadata != NULL){
free(metadata);
}
return false;
}

View File

@@ -0,0 +1,133 @@
/* based on module.c
* by Alex Chadwick
*
* Copyright (C) 2014, Alex Chadwick
* Modified 2018, Maschell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _PLUGIN_INFORMATION_H_
#define _PLUGIN_INFORMATION_H_
#include <string>
#include <vector>
#include "EntryData.h"
#include "HookData.h"
#include <utils/logger.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <libelf.h>
#ifdef __cplusplus
}
#endif
class PluginInformation{
public:
/**
returns PluginInformation* if a valid plugin was found at the given path. Otherwise returns NULL
**/
static PluginInformation * loadPluginInformation(std::string path){
if(PluginInformation::checkFileExtenstion(path.c_str())){
DEBUG_FUNCTION_LINE("Checkfile successfully, loading now Plugin Information\n");
PluginInformation * pluginInformation = new PluginInformation(path);
if(pluginInformation->openAndParseElf()){
return pluginInformation;
}else{
delete pluginInformation;
return NULL;
}
} else {
return NULL;
}
}
std::string getName(){
return this->name;
}
std::string getAuthor(){
return this->author;
}
std::string getVersion(){
return this->version;
}
std::string getLicense(){
return this->license;
}
std::string getPath(){
return path;
}
size_t getSize(){
return this->size;
}
private:
PluginInformation(std::string path){
this->path = path;
}
void setName(const char * name){
this->name = name;
}
void setAuthor(const char * author){
this->author = author;
}
void setVersion(const char * version){
this->version = version;
}
void setLicense(const char * license){
this->license = license;
}
void setSize(size_t size){
this->size = size;
}
static bool checkFileExtenstion(const char * path);
bool openAndParseElf();
bool parseElf(Elf *elf);
bool metadataRead(Elf *elf, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx);
bool loadedSuccessfully = false;
std::string path;
std::string name;
std::string author;
std::string version;
std::string license;
size_t size;
};
#endif

View File

@@ -0,0 +1,414 @@
/* based on module.c
* by Alex Chadwick
*
* Copyright (C) 2014, Alex Chadwick
* Modified 2018, Maschell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "ElfTools.h"
#include "PluginData.h"
#include "PluginLoader.h"
#include "utils/StringTools.h"
#include "common/retain_vars.h"
PluginLoader * PluginLoader::instance = NULL;
std::vector<PluginInformation *> PluginLoader::getPluginInformation(const char * path){
std::vector<PluginInformation *> result;
struct dirent *dp;
DIR *dfd = NULL;
if(path == NULL){
DEBUG_FUNCTION_LINE("Path was NULL");
return result;
}
if ((dfd = opendir(path)) == NULL){
DEBUG_FUNCTION_LINE("Couldn't open dir %s",path);
return result;
}
while ((dp = readdir(dfd)) != NULL){
struct stat stbuf ;
std::string full_file_path = StringTools::strfmt("%s/%s",path,dp->d_name);
StringTools::RemoveDoubleSlashs(full_file_path);
if( stat(full_file_path.c_str(),&stbuf ) == -1 ){
DEBUG_FUNCTION_LINE("Unable to stat file: %s\n",full_file_path.c_str()) ;
continue;
}
if ( ( stbuf.st_mode & S_IFMT ) == S_IFDIR ){ // Skip directories
continue;
}else{
DEBUG_FUNCTION_LINE("Found file: %s\n",full_file_path.c_str()) ;
PluginInformation * plugin = PluginInformation::loadPluginInformation(full_file_path);
if(plugin != NULL){
DEBUG_FUNCTION_LINE("Found plugin %s by %s. Size: %d kb \n",plugin->getName().c_str(),plugin->getAuthor().c_str(),plugin->getSize()/1024) ;
result.push_back(plugin);
} else {
DEBUG_FUNCTION_LINE("%s is not a valid plugin\n",full_file_path.c_str()) ;
}
}
}
return result;
}
void PluginLoader::loadAndLinkPlugins(std::vector<PluginInformation *> pluginInformation){
std::vector<PluginData *> loadedPlugins;
for(size_t i = 0;i < pluginInformation.size(); i++){
DEBUG_FUNCTION_LINE("loadAndLinkPlugins for %d\n",i) ;
PluginInformation * cur_info = pluginInformation[i];
PluginData * pluginData = loadAndLinkPlugin(cur_info);
if(pluginData == NULL){
DEBUG_FUNCTION_LINE("loadAndLinkPlugins failed for %d\n",i) ;
continue;
} else {
loadedPlugins.push_back(pluginData);
}
}
copyPluginDataIntoGlobalStruct(loadedPlugins);
clearPluginData(loadedPlugins);
}
void PluginLoader::clearPluginData(std::vector<PluginData *> pluginData){
for(size_t i = 0;i < pluginData.size(); i++){
PluginData * curPluginData = pluginData[i];
if(curPluginData != NULL){
delete curPluginData;
}
}
}
PluginData * PluginLoader::loadAndLinkPlugin(PluginInformation * pluginInformation){
DEBUG_FUNCTION_LINE("\n");
PluginData * result = NULL;
int fd = -1;
Elf *elf = NULL;
if(pluginInformation == NULL){
DEBUG_FUNCTION_LINE("pluginInformation was NULL\n");
goto exit_error;
}
if(pluginInformation->getSize() > ((u32) this->getCurrentStoreAddress() - (u32) this->startAddress)){
DEBUG_FUNCTION_LINE("Not enough space left to loader the plugin into memory\n");
goto exit_error;
}
/* check for compile errors */
if (elf_version(EV_CURRENT) == EV_NONE){
goto exit_error;
}
fd = open(pluginInformation->getPath().c_str(), O_RDONLY, 0);
if (fd == -1){
DEBUG_FUNCTION_LINE("failed to open '%s' \n", pluginInformation->getPath().c_str());
goto exit_error;
}
elf = elf_begin(fd, ELF_C_READ, NULL);
if (elf == NULL){
DEBUG_FUNCTION_LINE("elf was NULL\n");
goto exit_error;
}
DEBUG_FUNCTION_LINE("\n");
result = new PluginData(pluginInformation);
if(result == NULL){
DEBUG_FUNCTION_LINE("Failed to create object\n");
goto exit_error;
}
if(!this->loadAndLinkElf(result, elf, this->getCurrentStoreAddress())){
delete result;
result = NULL;
}
exit_error:
if (elf != NULL){
elf_end(elf);
}
if (fd != -1){
close(fd);
}
return result;
}
bool PluginLoader::loadAndLinkElf(PluginData * pluginData, Elf *elf, void * endAddress) {
if(pluginData == NULL || elf == NULL || endAddress == NULL){
return false;
}
DEBUG_FUNCTION_LINE("\n");
u32 curAddress = (u32) endAddress;
Elf_Scn *scn;
size_t symtab_count, section_count, shstrndx, symtab_strndx, entries_count, hooks_count;
Elf32_Sym *symtab = NULL;
uint8_t **destinations = NULL;
wups_loader_entry_t *entries = NULL;
wups_loader_hook_t *hooks = NULL;
bool result = false;
std::vector<wups_loader_entry_t *> entry_t_list;
std::vector<wups_loader_hook_t *> hook_t_list;
std::vector<EntryData *> entry_data_list;
std::vector<HookData *> hook_data_list;
if (!ElfTools::loadElfSymtab(elf, &symtab, &symtab_count, &symtab_strndx)){
goto exit_error;
}
if(symtab == NULL){
goto exit_error;
}
if (elf_getshdrnum(elf, &section_count) != 0){
goto exit_error;
}
if (elf_getshdrstrndx(elf, &shstrndx) != 0){
goto exit_error;
}
destinations = (uint8_t **) malloc(sizeof(uint8_t *) * section_count);
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
Elf32_Shdr *shdr;
shdr = elf32_getshdr(scn);
if (shdr == NULL){
continue;
}
if ((shdr->sh_type == SHT_PROGBITS || shdr->sh_type == SHT_NOBITS) &&
(shdr->sh_flags & SHF_ALLOC)) {
const char *name;
destinations[elf_ndxscn(scn)] = NULL;
name = elf_strptr(elf, shstrndx, shdr->sh_name);
if (name == NULL){
continue;
}
if (strcmp(name, ".wups.meta") == 0) {
continue;
} else if (strcmp(name, ".wups.load") == 0) {
if (entries != NULL){
goto exit_error;
}
entries_count = shdr->sh_size / sizeof(wups_loader_entry_t);
entries = (wups_loader_entry_t *) malloc(sizeof(wups_loader_entry_t) * entries_count);
if (entries == NULL){
goto exit_error;
}
destinations[elf_ndxscn(scn)] = (uint8_t *)entries;
if (!ElfTools::elfLoadSection(elf, scn, shdr, entries)){
goto exit_error;
}
ElfTools::elfLoadSymbols(elf_ndxscn(scn), entries, symtab, symtab_count);
for(size_t i = 0;i< entries_count;i++){
entry_t_list.push_back(&entries[i]);
}
}else if (strcmp(name, ".wups.hooks") == 0) {
if (hooks != NULL){
goto exit_error;
}
hooks_count = shdr->sh_size / sizeof(wups_loader_hook_t);
hooks = (wups_loader_hook_t *) malloc(sizeof(wups_loader_hook_t) * hooks_count);
if (hooks == NULL){
goto exit_error;
}
destinations[elf_ndxscn(scn)] = (uint8_t *)hooks;
if (!ElfTools::elfLoadSection(elf, scn, shdr, hooks)){
goto exit_error;
}
ElfTools::elfLoadSymbols(elf_ndxscn(scn), hooks, symtab, symtab_count);
for(size_t i = 0;i< hooks_count;i++){
hook_t_list.push_back(&hooks[i]);
}
} else {
curAddress -= shdr->sh_size;
if (shdr->sh_addralign > 3){
curAddress = (u32)((int)curAddress & ~(shdr->sh_addralign - 1));
} else {
curAddress = (u32)((int)curAddress & ~3);
}
destinations[elf_ndxscn(scn)] = (uint8_t *) curAddress;
if((u32) curAddress < (u32) this->startAddress){
DEBUG_FUNCTION_LINE("Not enough space to load function %s into memory at %08X.\n",name,curAddress);
goto exit_error;
}
DEBUG_FUNCTION_LINE("Copy section %s to %08X\n",name,curAddress);
if (!ElfTools::elfLoadSection(elf, scn, shdr, (void*) curAddress)){
goto exit_error;
}
ElfTools::elfLoadSymbols(elf_ndxscn(scn), (void*) curAddress, symtab, symtab_count);
}
}
}
if (entries == NULL){
goto exit_error;
}
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
Elf32_Shdr *shdr;
shdr = elf32_getshdr(scn);
if (shdr == NULL){
continue;
}
if ((shdr->sh_type == SHT_PROGBITS || shdr->sh_type == SHT_NOBITS) &&
(shdr->sh_flags & SHF_ALLOC) &&
destinations[elf_ndxscn(scn)] != NULL) {
if (!ElfTools::elfLink(elf, elf_ndxscn(scn), destinations[elf_ndxscn(scn)], symtab, symtab_count, symtab_strndx, true)){
goto exit_error;
}
}
}
for(size_t j=0;j<hook_t_list.size();j++){
wups_loader_hook_t * hook = hook_t_list[j];
DEBUG_FUNCTION_LINE("Saving hook of plugin \"%s\". Type: %08X, target: %08X\n",pluginData->getPluginInformation()->getName().c_str(),hook->type,(void*) hook->target);
HookData * hook_data = new HookData((void *) hook->target,hook->type);
pluginData->addHookData(hook_data);
}
for(size_t j=0;j<entry_t_list.size();j++){
wups_loader_entry_t * entry = entry_t_list[j];
DEBUG_FUNCTION_LINE("Saving entry \"%s\" of plugin \"%s\". Library: %08X, target: %08X, call_addr: %08X\n",entry->_function.name,pluginData->getPluginInformation()->getName().c_str(),entry->_function.library,entry->_function.target, (void *) entry->_function.call_addr);
EntryData * entry_data = new EntryData(entry->_function.name,entry->_function.library, (void *) entry->_function.target, (void *) entry->_function.call_addr);
pluginData->addEntryData(entry_data);
}
this->setCurrentStoreAddress((void *) curAddress);
result = true;
exit_error:
if (!result) DEBUG_FUNCTION_LINE("exit_error\n");
if (destinations != NULL){
free(destinations);
}
if (symtab != NULL){
free(symtab);
}
if (hooks != NULL){
free(hooks);
}
if (entries != NULL){
free(entries);
}
return result;
}
void PluginLoader::copyPluginDataIntoGlobalStruct(std::vector<PluginData *> plugins){
// Reset data
memset((void*)&gbl_replacement_data,0,sizeof(gbl_replacement_data));
int plugin_index = 0;
// Copy data to global struct.
for(size_t i = 0; i< plugins.size();i++){
PluginData * cur_plugin = plugins.at(i);
PluginInformation * cur_pluginInformation = cur_plugin->getPluginInformation();
std::vector<EntryData *> entry_data_list = cur_plugin->getEntryDataList();
std::vector<HookData *> hook_data_list = cur_plugin->getHookDataList();
if(plugin_index >= MAXIMUM_PLUGINS ){
DEBUG_FUNCTION_LINE("Maximum of %d plugins reached. %s won't be loaded!\n",MAXIMUM_PLUGINS,cur_pluginInformation->getName().c_str());
continue;
}
if(entry_data_list.size() > MAXIMUM_FUNCTION_PER_PLUGIN){
DEBUG_FUNCTION_LINE("Plugin %s would replace to many function (%d, maximum is %d). It won't be loaded.\n",cur_pluginInformation->getName().c_str(),entry_data_list.size(),MAXIMUM_FUNCTION_PER_PLUGIN);
continue;
}
if(hook_data_list.size() > MAXIMUM_HOOKS_PER_PLUGIN){
DEBUG_FUNCTION_LINE("Plugin %s would set too many hooks (%d, maximum is %d). It won't be loaded.\n",cur_pluginInformation->getName().c_str(),hook_data_list.size(),MAXIMUM_HOOKS_PER_PLUGIN);
continue;
}
replacement_data_plugin_t * plugin_data = &gbl_replacement_data.plugin_data[plugin_index];
strncpy(plugin_data->plugin_name,cur_pluginInformation->getName().c_str(),MAXIMUM_PLUGIN_NAME_LENGTH-1);
for(size_t j = 0; j < entry_data_list.size();j++){
replacement_data_function_t * function_data = &plugin_data->functions[j];
EntryData * cur_entry = entry_data_list[j];
DEBUG_FUNCTION_LINE("Adding entry \"%s\" for plugin \"%s\"\n",cur_entry->getName().c_str(),plugin_data->plugin_name);
//TODO: Warning/Error if string is too long.
strncpy(function_data->function_name,cur_entry->getName().c_str(),MAXIMUM_FUNCTION_NAME_LENGTH-1);
function_data->library = cur_entry->getLibrary();
function_data->replaceAddr = (u32) cur_entry->getReplaceAddress();
function_data->replaceCall = (u32) cur_entry->getReplaceCall();
plugin_data->number_used_functions++;
}
DEBUG_FUNCTION_LINE("Entries for plugin \"%s\": %d\n",plugin_data->plugin_name,plugin_data->number_used_functions);
for(size_t j = 0; j < hook_data_list.size();j++){
replacement_data_hook_t * hook_data = &plugin_data->hooks[j];
HookData * hook_entry = hook_data_list[j];
DEBUG_FUNCTION_LINE("Set hook for plugin \"%s\" of type %08X to target %08X\n",plugin_data->plugin_name,hook_entry->getType(),(void*) hook_entry->getFunctionPointer());
hook_data->func_pointer = (void*) hook_entry->getFunctionPointer();
hook_data->type = hook_entry->getType();
plugin_data->number_used_hooks++;
}
DEBUG_FUNCTION_LINE("Hooks for plugin \"%s\": %d\n",plugin_data->plugin_name,plugin_data->number_used_hooks);
plugin_index++;
gbl_replacement_data.number_used_plugins++;
}
}

View File

@@ -0,0 +1,151 @@
/* based on module.c
* by Alex Chadwick
*
* Copyright (C) 2014, Alex Chadwick
* Modified 2018, Maschell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _PLUGIN_LOADER_H_
#define _PLUGIN_LOADER_H_
#include <vector>
#include "PluginInformation.h"
#include "PluginData.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <utils/utils.h>
#ifdef __cplusplus
}
#endif
#define PLUGIN_LOCATION_END_ADDRESS 0x01000000
class PluginLoader{
public:
static PluginLoader *getInstance() {
if(!instance){
instance = new PluginLoader((void*)getApplicationEndAddr(),(void *)PLUGIN_LOCATION_END_ADDRESS);
}
return instance;
}
static void destroyInstance() {
if(instance){
delete instance;
instance = NULL;
}
}
/**
\brief Parses the meta data of all plugins in the given directory.
\param path the path of the directory which should be scanned.
\return a list of PluginInformation objects, one for each valid plugin.
**/
std::vector<PluginInformation *> getPluginInformation(const char * path);
/**
\brief Gets plugin information from the global struct.
\return a list of MetaInformation objects for all plugins currently loaded and linked (relocated). Will only contain
plugin which are still on the sd card.
**/
//std::vector<PluginInformation *> getPluginsLoadedInMemory();
/**
\brief Takes a list of plugins that should be linked (relocated) loaded into the memory.
The function that should be replaced will be replaced in the order of the given plugin list.
So two plugin will override the same function, the plugin first in this list will override the function first.
Also the hooks of the plugins will be called in the order their plugin where passed to this method.
\param A list of plugin that should be linked (relocated) an loaded into memory
**/
void loadAndLinkPlugins(std::vector<PluginInformation *> pluginInformation);
private:
PluginLoader(void * startAddress, void * endAddress){
// TODO: Check if endAddress > startAddress.
this->startAddress = startAddress;
this->endAddress = endAddress;
this->currentStoreAddress = endAddress;
}
~PluginLoader(){
}
static PluginLoader *instance;
/**
\brief Iterates through the vector and delete all it's elements
\param A list of PluginData* that should be deleted.
**/
void clearPluginData(std::vector<PluginData *> pluginData);
/**
\brief Load
\param pluginInformation a PluginInformation object of the plugin that should be linked (relocated) and loaded.
\return NULL on error. On success it will return a PluginData object.
**/
PluginData * loadAndLinkPlugin(PluginInformation * pluginInformation);
/**
\brief Loads a plugin into memory (in the startAddress/endAddress range defined in this loader) and relocates it.
Modifies the pluginData param. Adds loaded functions and hooks.
\param pluginData object where the result should be stored
\param elf source elf from where the sections will be loaded
\param storeAddressEnd the address where the plugin data will be stored in memory. Saving BACKWARD.
**/
bool loadAndLinkElf(PluginData * pluginData, Elf *elf, void * storeAddressEnd);
/**
\brief Copies the needed information into a global, persistent struct. This struct holds information on which
function should be override in which order and which hook should be called.
\param plugins list of plugins that should be used.
**/
void copyPluginDataIntoGlobalStruct(std::vector<PluginData *> plugins);
void * getCurrentStoreAddress(){
return this->currentStoreAddress;
}
void setCurrentStoreAddress(void * addr){
this->currentStoreAddress = addr;
}
void * startAddress = NULL;
void * endAddress = NULL;
void * currentStoreAddress = NULL;
};
#endif