Last active
August 29, 2015 14:03
-
-
Save kubo/9a47f22fe685fb4b7073 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'mkmf' | |
create_makefile('hide_loaded_oralib') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -*- indent-tabs-mode: nil -*- */ | |
#include <ruby.h> | |
#include <plthook.h> | |
#include "link.h" | |
#define DT_THISPROCNUM 0 | |
/* Copied from link.h in eglibc-2.11.1 source tree. | |
* | |
* This is an internal structre in the libc6 package. | |
* The strcutre may be changed in other versions. | |
*/ | |
struct r_scope_elem | |
{ | |
/* Array of maps for the scope. */ | |
struct link_map **r_list; | |
/* Number of entries in the scope. */ | |
unsigned int r_nlist; | |
}; | |
/* Copied 'struct link_map' from link.h in eglibc-2.11.1 source tree, | |
* renamed 'struct link_map' to 'struct libc_link_map' | |
* and cut all structure members after l_nbuckets. | |
* | |
* This is an internal structre in the libc6 package. | |
* The strcutre may be changed in other versions. | |
*/ | |
struct libc_link_map | |
{ | |
/* These first few members are part of the protocol with the debugger. | |
This is the same format used in SVR4. */ | |
ElfW(Addr) l_addr; /* Base address shared object is loaded at. */ | |
char *l_name; /* Absolute file name object was found in. */ | |
ElfW(Dyn) *l_ld; /* Dynamic section of the shared object. */ | |
struct link_map *l_next, *l_prev; /* Chain of loaded objects. */ | |
/* All following members are internal to the dynamic linker. | |
They may change without notice. */ | |
/* This is an element which is only ever different from a pointer to | |
the very same copy of this type for ld.so when it is used in more | |
than one namespace. */ | |
struct link_map *l_real; | |
/* Number of the namespace this link map belongs to. */ | |
Lmid_t l_ns; | |
struct libname_list *l_libname; | |
/* Indexed pointers to dynamic section. | |
[0,DT_NUM) are indexed by the processor-independent tags. | |
[DT_NUM,DT_NUM+DT_THISPROCNUM) are indexed by the tag minus DT_LOPROC. | |
[DT_NUM+DT_THISPROCNUM,DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM) are | |
indexed by DT_VERSIONTAGIDX(tagvalue). | |
[DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM, | |
DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM) are indexed by | |
DT_EXTRATAGIDX(tagvalue). | |
[DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM, | |
DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM) are | |
indexed by DT_VALTAGIDX(tagvalue) and | |
[DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM, | |
DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM+DT_ADDRNUM) | |
are indexed by DT_ADDRTAGIDX(tagvalue), see <elf.h>. */ | |
ElfW(Dyn) *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM | |
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM]; | |
const ElfW(Phdr) *l_phdr; /* Pointer to program header table in core. */ | |
ElfW(Addr) l_entry; /* Entry point location. */ | |
ElfW(Half) l_phnum; /* Number of program header entries. */ | |
ElfW(Half) l_ldnum; /* Number of dynamic segment entries. */ | |
/* Array of DT_NEEDED dependencies and their dependencies, in | |
dependency order for symbol lookup (with and without | |
duplicates). There is no entry before the dependencies have | |
been loaded. */ | |
struct r_scope_elem l_searchlist; | |
/* We need a special searchlist to process objects marked with | |
DT_SYMBOLIC. */ | |
struct r_scope_elem l_symbolic_searchlist; | |
/* Dependent object that first caused this object to be loaded. */ | |
struct link_map *l_loader; | |
/* Array with version names. */ | |
struct r_found_version *l_versions; | |
unsigned int l_nversions; | |
/* Symbol hash table. */ | |
Elf_Symndx l_nbuckets; | |
}; | |
#define MAX_ORACLE_LIBS 10 | |
static void *my_dlopen(const char *filename, int flag) | |
{ | |
struct link_map *map; | |
struct link_map *oralib_maps[MAX_ORACLE_LIBS]; | |
Elf_Symndx nbuckets[MAX_ORACLE_LIBS]; | |
int nused = 0; | |
int i; | |
void *hndl; | |
const char *dirname = "/data/OLT/lib/"; | |
size_t dirname_len = strlen(dirname); | |
if (strstr(filename, "oci8lib_") == NULL) { | |
/* It isn't the oci8 library. */ | |
return dlopen(filename, flag); | |
} | |
/* try to find libraries under /data/OLT/lib */ | |
for (map = _r_debug.r_map; map != NULL; map = map->l_next) { | |
if (strncmp(map->l_name, dirname, dirname_len) == 0) { | |
oralib_maps[nused++] = map; | |
if (nused == MAX_ORACLE_LIBS) { | |
break; | |
} | |
} | |
} | |
/* temporarily change the number of symbols exported by Oracle libraries to zero. */ | |
for (i = 0; i < nused; i++) { | |
struct libc_link_map *map = (struct libc_link_map*)oralib_maps[i]; | |
nbuckets[i] = map->l_nbuckets; | |
map->l_nbuckets = 0; | |
} | |
/* load oci8lib.so */ | |
flag &= ~RTLD_BINDING_MASK; /* unset binding time value */ | |
flag |= RTLD_NOW; /* set RTLD_NOW to bind all symbols while l_nbuckets is zero. */ | |
hndl = dlopen(filename, flag); | |
/* restore the number of exported symbols. */ | |
for (i = 0; i < nused; i++) { | |
struct libc_link_map *map = (struct libc_link_map*)oralib_maps[i]; | |
map->l_nbuckets = nbuckets[i]; | |
} | |
return hndl; | |
} | |
void | |
Init_hide_loaded_oralib() | |
{ | |
plthook_t *plthook; | |
/* try to open a library exporting rb_raise, which will be libruby.so. */ | |
if (plthook_open_by_address(&plthook, dlsym(RTLD_DEFAULT, "rb_raise")) != 0) { | |
rb_raise(rb_eRuntimeError, "Cannot open libruby.so by plthook"); | |
} | |
plthook_replace(plthook, "dlopen", my_dlopen, NULL); | |
plthook_close(plthook); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Gem::Specification.new do |s| | |
s.name = 'hide_loaded_oralib' | |
s.version = '0.0.1' | |
s.summary = 'Hide loaded Oracle libraries while loading ruby-oci8' | |
s.description = <<EOS | |
Hide loaded Oracle libraries while loading ruby-oci8. | |
Put "require 'hide_loaded_oralib'" before "require 'oci8'" | |
EOS | |
s.email = 'kubo@jiubao.org' | |
s.homepage = 'https://github.com/kubo/ruby-oci8/issues/58' | |
s.authors = ['Kubo Takehiro'] | |
s.license = '2-clause BSD-style license' | |
s.files = ['hide_loaded_oralib.c', 'plthook.c', 'plthook.h'] | |
s.extensions << 'extconf.rb' | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -*- indent-tabs-mode: nil -*- | |
* | |
* plthook.c -- implemention of plthook for ELF format | |
* | |
* URL: https://github.com/kubo/plthook | |
* | |
* ------------------------------------------------------ | |
* | |
* Copyright 2013-2014 Kubo Takehiro <kubo@jiubao.org> | |
* | |
* Redistribution and use in source and binary forms, with or without modification, are | |
* permitted provided that the following conditions are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright notice, this list of | |
* conditions and the following disclaimer. | |
* | |
* 2. Redistributions in binary form must reproduce the above copyright notice, this list | |
* of conditions and the following disclaimer in the documentation and/or other materials | |
* provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED | |
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR | |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
* | |
* The views and conclusions contained in the software and documentation are those of the | |
* authors and should not be interpreted as representing official policies, either expressed | |
* or implied, of the authors. | |
* | |
*/ | |
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <stdarg.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <limits.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <errno.h> | |
#include <dlfcn.h> | |
#ifdef __sun | |
#include <procfs.h> | |
#define ELF_TARGET_ALL | |
#endif /* __sun */ | |
#include <elf.h> | |
#include <link.h> | |
#include "plthook.h" | |
#ifndef __GNUC__ | |
#define __attribute__(arg) | |
#endif | |
#if defined __linux__ | |
#define ELF_OSABI ELFOSABI_SYSV | |
#elif defined __sun | |
#define ELF_OSABI ELFOSABI_SOLARIS | |
#elif defined __FreeBSD__ | |
#define ELF_OSABI ELFOSABI_FREEBSD | |
#if defined __i386__ && __ELF_WORD_SIZE == 64 | |
#error 32-bit application on 64-bit OS is not supported. | |
#endif | |
#else | |
#error unsupported OS | |
#endif | |
#if defined __x86_64__ || defined __x86_64 | |
#define ELF_DATA ELFDATA2LSB | |
#define E_MACHINE EM_X86_64 | |
#ifdef R_X86_64_JUMP_SLOT | |
#define R_JUMP_SLOT R_X86_64_JUMP_SLOT | |
#else | |
#define R_JUMP_SLOT R_X86_64_JMP_SLOT | |
#endif | |
#define SHT_PLT_REL SHT_RELA | |
#define Elf_Plt_Rel Elf_Rela | |
#define PLT_SECTION_NAME ".rela.plt" | |
#elif defined __i386__ || defined __i386 | |
#define ELF_DATA ELFDATA2LSB | |
#define E_MACHINE EM_386 | |
#define R_JUMP_SLOT R_386_JMP_SLOT | |
#define SHT_PLT_REL SHT_REL | |
#define Elf_Plt_Rel Elf_Rel | |
#define PLT_SECTION_NAME ".rel.plt" | |
#else | |
#error E_MACHINE is not defined. | |
#endif | |
#if defined __LP64__ | |
#ifndef ELF_CLASS | |
#define ELF_CLASS ELFCLASS64 | |
#endif | |
#define SIZE_T_FMT "lu" | |
#define Elf_Half Elf64_Half | |
#define Elf_Addr Elf64_Addr | |
#define Elf_Ehdr Elf64_Ehdr | |
#define Elf_Phdr Elf64_Phdr | |
#define Elf_Shdr Elf64_Shdr | |
#define Elf_Sym Elf64_Sym | |
#define Elf_Rel Elf64_Rel | |
#define Elf_Rela Elf64_Rela | |
#ifndef ELF_R_SYM | |
#define ELF_R_SYM ELF64_R_SYM | |
#endif | |
#ifndef ELF_R_TYPE | |
#define ELF_R_TYPE ELF64_R_TYPE | |
#endif | |
#else /* __LP64__ */ | |
#ifndef ELF_CLASS | |
#define ELF_CLASS ELFCLASS32 | |
#endif | |
#define SIZE_T_FMT "u" | |
#define Elf_Half Elf32_Half | |
#define Elf_Addr Elf32_Addr | |
#define Elf_Ehdr Elf32_Ehdr | |
#define Elf_Phdr Elf32_Phdr | |
#define Elf_Shdr Elf32_Shdr | |
#define Elf_Sym Elf32_Sym | |
#define Elf_Rel Elf32_Rel | |
#define Elf_Rela Elf32_Rela | |
#ifndef ELF_R_SYM | |
#define ELF_R_SYM ELF32_R_SYM | |
#endif | |
#ifndef ELF_R_TYPE | |
#define ELF_R_TYPE ELF32_R_TYPE | |
#endif | |
#endif /* __LP64__ */ | |
struct plthook { | |
const char *base; | |
const Elf_Phdr *phdr; | |
size_t phnum; | |
Elf_Shdr *shdr; | |
size_t shnum; | |
char *shstrtab; | |
size_t shstrtab_size; | |
const Elf_Sym *dynsym; | |
size_t dynsym_cnt; | |
const char *dynstr; | |
size_t dynstr_size; | |
const Elf_Plt_Rel *plt; | |
size_t plt_cnt; | |
}; | |
static char errmsg[512]; | |
static int plthook_open_executable(plthook_t **plthook_out); | |
static int plthook_open_shared_library(plthook_t **plthook_out, const char *filename); | |
static int plthook_open_real(plthook_t **plthook_out, const char *base, const char *filename); | |
static int check_elf_header(const Elf_Ehdr *ehdr); | |
static int find_section(plthook_t *image, const char *name, const Elf_Shdr **out); | |
static void set_errmsg(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2))); | |
int plthook_open(plthook_t **plthook_out, const char *filename) | |
{ | |
*plthook_out = NULL; | |
if (filename == NULL) { | |
return plthook_open_executable(plthook_out); | |
} else { | |
return plthook_open_shared_library(plthook_out, filename); | |
} | |
} | |
int plthook_open_by_address(plthook_t **plthook_out, void *address) | |
{ | |
Dl_info info; | |
*plthook_out = NULL; | |
if (dladdr(address, &info) == 0) { | |
set_errmsg("dladdr error"); | |
return PLTHOOK_FILE_NOT_FOUND; | |
} | |
return plthook_open_real(plthook_out, info.dli_fbase, info.dli_fname); | |
} | |
static int plthook_open_executable(plthook_t **plthook_out) | |
{ | |
#if defined __linux__ | |
/* Open the main program. */ | |
char buf[128]; | |
FILE *fp = fopen("/proc/self/maps", "r"); | |
unsigned long base; | |
if (fp == NULL) { | |
set_errmsg("Could not open /proc/self/maps: %s", | |
strerror(errno)); | |
return PLTHOOK_INTERNAL_ERROR; | |
} | |
if (fgets(buf, sizeof(buf), fp) == NULL) { | |
set_errmsg("Could not read /proc/self/maps: %s", | |
strerror(errno)); | |
fclose(fp); | |
return PLTHOOK_INTERNAL_ERROR; | |
} | |
fclose(fp); | |
if (sscanf(buf, "%lx-%*x r-xp %*x %*x:%*x %*u ", &base) != 1) { | |
set_errmsg("invalid /proc/self/maps format: %s", buf); | |
return PLTHOOK_INTERNAL_ERROR; | |
} | |
return plthook_open_real(plthook_out, (const char*)base, "/proc/self/exe"); | |
#elif defined __sun | |
prmap_t prmap; | |
pid_t pid = getpid(); | |
char fname[128]; | |
int fd; | |
sprintf(fname, "/proc/%d/map", pid); | |
fd = open(fname, O_RDONLY); | |
if (fd == -1) { | |
set_errmsg("Could not open %s: %s", fname, | |
strerror(errno)); | |
return PLTHOOK_INTERNAL_ERROR; | |
} | |
if (read(fd, &prmap, sizeof(prmap)) != sizeof(prmap)) { | |
set_errmsg("Could not read %s: %s", fname, | |
strerror(errno)); | |
close(fd); | |
return PLTHOOK_INTERNAL_ERROR; | |
} | |
close(fd); | |
sprintf(fname, "/proc/%d/object/a.out", pid); | |
return plthook_open_real(plthook_out, (const char*)prmap.pr_vaddr, fname); | |
#elif defined __FreeBSD__ | |
return plthook_open_shared_library(plthook_out, NULL); | |
#else | |
#error unsupported OS | |
#endif | |
} | |
static int plthook_open_shared_library(plthook_t **plthook_out, const char *filename) | |
{ | |
void *hndl = dlopen(filename, RTLD_LAZY | RTLD_NOLOAD); | |
struct link_map *lmap = NULL; | |
if (hndl == NULL) { | |
set_errmsg("dlopen error: %s", dlerror()); | |
return PLTHOOK_FILE_NOT_FOUND; | |
} | |
if (dlinfo(hndl, RTLD_DI_LINKMAP, &lmap) != 0) { | |
set_errmsg("dlinfo error"); | |
dlclose(hndl); | |
return PLTHOOK_FILE_NOT_FOUND; | |
} | |
dlclose(hndl); | |
return plthook_open_real(plthook_out, (const char*)lmap->l_addr, lmap->l_name); | |
} | |
static int plthook_open_real(plthook_t **plthook_out, const char *base, const char *filename) | |
{ | |
const Elf_Ehdr *ehdr = (Elf_Ehdr *)base; | |
const Elf_Shdr *shdr; | |
size_t shdr_size; | |
int fd = -1; | |
off_t offset; | |
plthook_t *plthook; | |
int rv; | |
if (base == NULL) { | |
set_errmsg("The base address is zero."); | |
return PLTHOOK_FILE_NOT_FOUND; | |
} | |
if (filename == NULL) { | |
set_errmsg("failed to get the file name on the disk."); | |
return PLTHOOK_FILE_NOT_FOUND; | |
} | |
plthook = calloc(1, sizeof(plthook_t)); | |
if (plthook == NULL) { | |
set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", sizeof(plthook_t)); | |
return PLTHOOK_OUT_OF_MEMORY; | |
} | |
/* sanity check */ | |
rv = check_elf_header(ehdr); | |
if (rv != 0) { | |
goto error_exit; | |
} | |
if (ehdr->e_type == ET_DYN) { | |
plthook->base = base; | |
} | |
plthook->phdr = (const Elf_Phdr *)(plthook->base + ehdr->e_phoff); | |
plthook->phnum = ehdr->e_phnum; | |
fd = open(filename, O_RDONLY, 0); | |
if (fd == -1) { | |
set_errmsg("Could not open %s: %s", filename, strerror(errno)); | |
rv = PLTHOOK_FILE_NOT_FOUND; | |
goto error_exit; | |
} | |
shdr_size = ehdr->e_shnum * ehdr->e_shentsize; | |
plthook->shdr = calloc(1, shdr_size); | |
if (plthook->shdr == NULL) { | |
set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", shdr_size); | |
rv = PLTHOOK_OUT_OF_MEMORY; | |
goto error_exit; | |
} | |
offset = ehdr->e_shoff; | |
if ((rv = lseek(fd, offset, SEEK_SET)) != offset) { | |
set_errmsg("failed to seek to the section header table."); | |
rv = PLTHOOK_INVALID_FILE_FORMAT; | |
goto error_exit; | |
} | |
if (read(fd, plthook->shdr, shdr_size) != shdr_size) { | |
set_errmsg("failed to read the section header table."); | |
rv = PLTHOOK_INVALID_FILE_FORMAT; | |
goto error_exit; | |
} | |
plthook->shnum = ehdr->e_shnum; | |
plthook->shstrtab_size = plthook->shdr[ehdr->e_shstrndx].sh_size; | |
plthook->shstrtab = malloc(plthook->shstrtab_size); | |
if (plthook->shstrtab == NULL) { | |
set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", plthook->shstrtab_size); | |
rv = PLTHOOK_OUT_OF_MEMORY; | |
goto error_exit; | |
} | |
offset = plthook->shdr[ehdr->e_shstrndx].sh_offset; | |
if (lseek(fd, offset, SEEK_SET) != offset) { | |
set_errmsg("failed to seek to the section header string table."); | |
rv = PLTHOOK_INVALID_FILE_FORMAT; | |
goto error_exit; | |
} | |
if (read(fd, plthook->shstrtab, plthook->shstrtab_size) != plthook->shstrtab_size) { | |
set_errmsg("failed to read the section header string table."); | |
rv = PLTHOOK_INVALID_FILE_FORMAT; | |
goto error_exit; | |
} | |
close(fd); | |
fd = -1; | |
rv = find_section(plthook, ".dynsym", &shdr); | |
if (rv != 0) { | |
goto error_exit; | |
} | |
if (shdr->sh_type != SHT_DYNSYM) { | |
set_errmsg("The type of .dynsym section should be SHT_DYNSYM but %d.", shdr->sh_type); | |
rv = PLTHOOK_INVALID_FILE_FORMAT; | |
goto error_exit; | |
} | |
if (shdr->sh_entsize != sizeof(Elf_Sym)) { | |
set_errmsg("The size of a section header entry should be sizeof(Elf_Sym)(%" SIZE_T_FMT ") but %" SIZE_T_FMT ".", | |
sizeof(Elf_Sym), shdr->sh_entsize); | |
rv = PLTHOOK_INVALID_FILE_FORMAT; | |
goto error_exit; | |
} | |
plthook->dynsym = (const Elf_Sym*)(plthook->base + shdr->sh_addr); | |
plthook->dynsym_cnt = shdr->sh_size / shdr->sh_entsize; | |
rv = find_section(plthook, ".dynstr", &shdr); | |
if (rv != 0) { | |
goto error_exit; | |
} | |
if (shdr->sh_type != SHT_STRTAB) { | |
set_errmsg("The type of .dynstrx section should be SHT_STRTAB but %d.", shdr->sh_type); | |
rv = PLTHOOK_INVALID_FILE_FORMAT; | |
goto error_exit; | |
} | |
plthook->dynstr = (const char*)(plthook->base + shdr->sh_addr); | |
plthook->dynstr_size = shdr->sh_size; | |
rv = find_section(plthook, PLT_SECTION_NAME, &shdr); | |
if (rv != 0) { | |
goto error_exit; | |
} | |
if (shdr->sh_entsize != sizeof(Elf_Plt_Rel)) { | |
set_errmsg("invalid " PLT_SECTION_NAME " table entry size: %" SIZE_T_FMT, shdr->sh_entsize); | |
rv = PLTHOOK_INVALID_FILE_FORMAT; | |
goto error_exit; | |
} | |
plthook->plt = (Elf_Plt_Rel *)(plthook->base + shdr->sh_addr); | |
plthook->plt_cnt = shdr->sh_size / sizeof(Elf_Plt_Rel); | |
*plthook_out = plthook; | |
return 0; | |
error_exit: | |
if (fd != -1) { | |
close(fd); | |
} | |
plthook_close(plthook); | |
return rv; | |
} | |
int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out) | |
{ | |
while (*pos < plthook->plt_cnt) { | |
const Elf_Plt_Rel *plt = plthook->plt + *pos; | |
if (ELF_R_TYPE(plt->r_info) == R_JUMP_SLOT) { | |
size_t idx = ELF_R_SYM(plt->r_info); | |
if (idx >= plthook->dynsym_cnt) { | |
set_errmsg(".dynsym index %" SIZE_T_FMT " should be less than %" SIZE_T_FMT ".", idx, plthook->dynsym_cnt); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
idx = plthook->dynsym[idx].st_name; | |
if (idx + 1 > plthook->dynstr_size) { | |
set_errmsg("too big section header string table index: %" SIZE_T_FMT, idx); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
*name_out = plthook->dynstr + idx; | |
*addr_out = (void**)(plthook->base + plt->r_offset); | |
(*pos)++; | |
return 0; | |
} | |
(*pos)++; | |
} | |
*name_out = NULL; | |
*addr_out = NULL; | |
return EOF; | |
} | |
int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, void **oldfunc) | |
{ | |
size_t funcnamelen = strlen(funcname); | |
unsigned int pos = 0; | |
const char *name; | |
void **addr; | |
int rv; | |
if (plthook == NULL) { | |
set_errmsg("invalid argument: The first argument is null."); | |
return PLTHOOK_INVALID_ARGUMENT; | |
} | |
while ((rv = plthook_enum(plthook, &pos, &name, &addr)) == 0) { | |
if (strncmp(name, funcname, funcnamelen) == 0) { | |
if (name[funcnamelen] == '\0' || name[funcnamelen] == '@') { | |
if (oldfunc) { | |
*oldfunc = *addr; | |
} | |
*addr = funcaddr; | |
return 0; | |
} | |
} | |
} | |
if (rv == EOF) { | |
set_errmsg("no such function: %s", funcname); | |
rv = PLTHOOK_FUNCTION_NOT_FOUND; | |
} | |
return rv; | |
} | |
void plthook_close(plthook_t *plthook) | |
{ | |
if (plthook != NULL) { | |
free(plthook->shdr); | |
free(plthook->shstrtab); | |
free(plthook); | |
} | |
} | |
const char *plthook_error(void) | |
{ | |
return errmsg; | |
} | |
static int check_elf_header(const Elf_Ehdr *ehdr) | |
{ | |
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) { | |
set_errmsg("invalid file signature: 0x%02x,0x%02x,0x%02x,0x%02x", | |
ehdr->e_ident[0], ehdr->e_ident[1], ehdr->e_ident[2], ehdr->e_ident[3]); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) { | |
set_errmsg("invalid elf class: 0x%02x", ehdr->e_ident[EI_CLASS]); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
if (ehdr->e_ident[EI_DATA] != ELF_DATA) { | |
set_errmsg("invalid elf data: 0x%02x", ehdr->e_ident[EI_DATA]); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) { | |
set_errmsg("invalid elf version: 0x%02x", ehdr->e_ident[EI_VERSION]); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
if (ehdr->e_ident[EI_OSABI] != ELF_OSABI) { | |
set_errmsg("invalid OS ABI: 0x%02x", ehdr->e_ident[EI_OSABI]); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) { | |
set_errmsg("invalid file type: 0x%04x", ehdr->e_type); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
if (ehdr->e_machine != E_MACHINE) { | |
set_errmsg("invalid machine type: %u", ehdr->e_machine); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
if (ehdr->e_version != EV_CURRENT) { | |
set_errmsg("invalid object file version: %u", ehdr->e_version); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
if (ehdr->e_ehsize != sizeof(Elf_Ehdr)) { | |
set_errmsg("invalid elf header size: %u", ehdr->e_ehsize); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
if (ehdr->e_phentsize != sizeof(Elf_Phdr)) { | |
set_errmsg("invalid program header table entry size: %u", ehdr->e_phentsize); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
if (ehdr->e_shentsize != sizeof(Elf_Shdr)) { | |
set_errmsg("invalid section header table entry size: %u", ehdr->e_shentsize); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
return 0; | |
} | |
static int find_section(plthook_t *image, const char *name, const Elf_Shdr **out) | |
{ | |
const Elf_Shdr *shdr = image->shdr; | |
const Elf_Shdr *shdr_end = shdr + image->shnum; | |
size_t namelen = strlen(name); | |
while (shdr < shdr_end) { | |
if (shdr->sh_name + namelen >= image->shstrtab_size) { | |
set_errmsg("too big section header string table index: %u", shdr->sh_name); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
if (strcmp(image->shstrtab + shdr->sh_name, name) == 0) { | |
*out = shdr; | |
return 0; | |
} | |
shdr++; | |
} | |
set_errmsg("failed to find the section header: %s", name); | |
return PLTHOOK_INVALID_FILE_FORMAT; | |
} | |
static void set_errmsg(const char *fmt, ...) | |
{ | |
va_list ap; | |
va_start(ap, fmt); | |
vsnprintf(errmsg, sizeof(errmsg) - 1, fmt, ap); | |
va_end(ap); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -*- indent-tabs-mode: nil -*- | |
* | |
* plthook.h -- the header file of plthook | |
* | |
* URL: https://github.com/kubo/plthook | |
* | |
* ------------------------------------------------------ | |
* | |
* Copyright 2013-2014 Kubo Takehiro <kubo@jiubao.org> | |
* | |
* Redistribution and use in source and binary forms, with or without modification, are | |
* permitted provided that the following conditions are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright notice, this list of | |
* conditions and the following disclaimer. | |
* | |
* 2. Redistributions in binary form must reproduce the above copyright notice, this list | |
* of conditions and the following disclaimer in the documentation and/or other materials | |
* provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED | |
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR | |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
* | |
* The views and conclusions contained in the software and documentation are those of the | |
* authors and should not be interpreted as representing official policies, either expressed | |
* or implied, of the authors. | |
* | |
*/ | |
#ifndef PLTHOOK_H | |
#define PLTHOOK_H 1 | |
#define PLTHOOK_SUCCESS 0 | |
#define PLTHOOK_FILE_NOT_FOUND 1 | |
#define PLTHOOK_INVALID_FILE_FORMAT 2 | |
#define PLTHOOK_FUNCTION_NOT_FOUND 3 | |
#define PLTHOOK_INVALID_ARGUMENT 4 | |
#define PLTHOOK_OUT_OF_MEMORY 5 | |
#define PLTHOOK_INTERNAL_ERROR 6 | |
typedef struct plthook plthook_t; | |
int plthook_open(plthook_t **plthook_out, const char *filename); | |
int plthook_open_by_address(plthook_t **plthook_out, void *address); | |
int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out); | |
int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, void **oldfunc); | |
void plthook_close(plthook_t *plthook); | |
const char *plthook_error(void); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment