Skip to content

Instantly share code, notes, and snippets.

@kubo
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kubo/9a47f22fe685fb4b7073 to your computer and use it in GitHub Desktop.
Save kubo/9a47f22fe685fb4b7073 to your computer and use it in GitHub Desktop.
require 'mkmf'
create_makefile('hide_loaded_oralib')
/* -*- 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);
}
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
/* -*- 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);
}
/* -*- 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