ÜberWall

UWfirmforce

/* $Id: elf.c,v 1.1 2009/02/21 21:25:19 khorben Exp $ */
/* Copyright (c) 2007 khorben of Uberwall */
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef __OpenBSD__
# include <elf_abi.h>
#else
# include <elf.h>
#endif
#include "plugin.h"
/* elf */
/* public */
/* types */
typedef union
{
Elf32_Ehdr e32;
Elf64_Ehdr e64;
} elf_ehdr;
/* constants */
/* elf.h might not know these (GNU/Linux) */
#ifndef ELFOSABI_HURD
# define ELFOSABI_HURD 4
#endif
#ifndef ELFOSABI_MONTEREY
# define ELFOSABI_MONTEREY 7
#endif
#ifndef EM_486
# define EM_486 6
#endif
#ifndef EM_MIPS_RS3_LE
# define EM_MIPS_RS3_LE 10
#endif
/* variables */
/* magic */
static unsigned char elf[] = ELFMAG;
PluginMagic elf_magic[] =
{
{ sizeof(Elf32_Ehdr), 0, elf, sizeof(elf)-1 },
{ 0, 0, NULL, 0 }
};
/* functions */
static int elf_callback(PluginHelper * ph, int signature, FILE * fp);
/* plugin */
Plugin plugin =
{
PT_EXECUTABLE,
"ELF",
elf_magic,
elf_callback
};
/* private */
/* functions */
/* plugin_callback */
static int _callback_32(PluginHelper * ph, Elf32_Ehdr * hdr);
static int _callback_64(PluginHelper * ph, Elf64_Ehdr * hdr);
static int elf_callback(PluginHelper * ph, int signature, FILE * fp)
{
fpos_t pos;
elf_ehdr buf;
if(fgetpos(fp, &pos) != 0)
return -1;
if(fread(&buf, sizeof(buf), 1, fp) == 1)
{
if(buf.e32.e_ident[EI_CLASS] == ELFCLASS32)
return _callback_32(ph, &buf.e32);
if(buf.e64.e_ident[EI_CLASS] == ELFCLASS64)
return _callback_64(ph, &buf.e64);
return -1;
}
if(fsetpos(fp, &pos) != 0)
return -1;
if(fread(&buf.e32, sizeof(buf.e32), 1, fp) == 1
&& buf.e32.e_ident[EI_CLASS] == ELFCLASS32)
return _callback_32(ph, &buf.e32);
return -1;
}
static int _callback_encoding(PluginHelper * ph, unsigned char encoding);
static int _callback_version(PluginHelper * ph, unsigned char version);
static int _callback_system(PluginHelper * ph, unsigned char system);
static void _32_endian(Elf32_Ehdr * hdr);
static int _callback_type(PluginHelper * ph, uint16_t type);
static int _callback_machine(PluginHelper * ph, uint16_t machine);
static int _callback_32(PluginHelper * ph, Elf32_Ehdr * hdr)
{
int score = 0;
ph->printf(ph, "%s", "32-bits");
score+=_callback_encoding(ph, hdr->e_ident[EI_DATA]);
score+=_callback_version(ph, hdr->e_ident[EI_VERSION]);
score+=_callback_system(ph, hdr->e_ident[EI_OSABI]);
_32_endian(hdr);
score+=_callback_type(ph, hdr->e_type);
score+=_callback_machine(ph, hdr->e_machine);
ph->printf(ph, "\n");
return score / 5;
}
static void _32_endian(Elf32_Ehdr * hdr)
{
if(hdr->e_ident[EI_DATA] == ELFDATA2LSB)
{
hdr->e_type = htol16(hdr->e_type);
hdr->e_machine = htol16(hdr->e_machine);
hdr->e_version = htol32(hdr->e_version);
}
else if(hdr->e_ident[EI_DATA] == ELFDATA2MSB)
{
hdr->e_type = htob16(hdr->e_type);
hdr->e_machine = htob16(hdr->e_machine);
hdr->e_version = htob32(hdr->e_version);
}
}
static void _64_endian(Elf64_Ehdr * hdr);
static int _callback_64(PluginHelper * ph, Elf64_Ehdr * hdr)
{
int score = 0;
ph->printf(ph, "%s", "64-bits");
score+=_callback_encoding(ph, hdr->e_ident[EI_DATA]);
score+=_callback_version(ph, hdr->e_ident[EI_VERSION]);
score+=_callback_system(ph, hdr->e_ident[EI_OSABI]);
_64_endian(hdr);
score+=_callback_type(ph, hdr->e_type);
score+=_callback_machine(ph, hdr->e_machine);
ph->printf(ph, "\n");
return score / 5;
}
static void _64_endian(Elf64_Ehdr * hdr)
{
if(hdr->e_ident[EI_DATA] == ELFDATA2LSB)
{
hdr->e_type = htol16(hdr->e_type);
hdr->e_machine = htol16(hdr->e_machine);
hdr->e_version = htol32(hdr->e_version);
}
else if(hdr->e_ident[EI_DATA] == ELFDATA2MSB)
{
hdr->e_type = htob16(hdr->e_type);
hdr->e_machine = htob16(hdr->e_machine);
hdr->e_version = htob32(hdr->e_version);
}
}
static int _callback_encoding(PluginHelper * ph, unsigned char encoding)
{
switch(encoding)
{
case ELFDATANONE:
ph->printf(ph, "%s", ", invalid encoding");
return 50;
case ELFDATA2LSB:
ph->printf(ph, "%s", ", little endian");
return 100;
case ELFDATA2MSB:
ph->printf(ph, "%s", ", big endian");
return 100;
default:
ph->printf(ph, "%s", ", unknown encoding");
return 0;
}
}
static int _callback_version(PluginHelper * ph, unsigned char version)
{
if(version == EV_CURRENT)
{
ph->printf(ph, "%s", ", current version");
return 100;
}
ph->printf(ph, "%s", ", invalid version");
return 0;
}
static int _callback_system(PluginHelper * ph, unsigned char system)
{
struct
{
unsigned char system;
char * name;
int score;
} sns[] =
{
{ ELFOSABI_SYSV, "SYSV", 100 },
{ ELFOSABI_HPUX, "HP-UX", 100 },
{ ELFOSABI_NETBSD, "NetBSD", 100 },
{ ELFOSABI_LINUX, "GNU/Linux", 100 },
{ ELFOSABI_HURD, "GNU/Hurd", 100 },
{ ELFOSABI_SOLARIS, "Solaris", 100 },
{ ELFOSABI_MONTEREY, "Monterey", 100 },
{ ELFOSABI_IRIX, "IRIX", 100 },
{ ELFOSABI_FREEBSD, "FreeBSD", 100 },
{ ELFOSABI_TRU64, "TRU64", 100 },
{ ELFOSABI_MODESTO, "Modesto", 100 },
{ ELFOSABI_OPENBSD, "OpenBSD", 100 },
{ ELFOSABI_ARM, "ARM", 100 },
{ 0, NULL, 0 }
};
size_t i;
for(i = 0; sns[i].name != NULL; i++)
if(sns[i].system == system)
break;
if(sns[i].name == NULL)
{
ph->printf(ph, "%s%d%s", ", unknown ABI (", system, ")");
return 0;
}
ph->printf(ph, "%s%s%s", ", ", sns[i].name, " ABI");
return sns[i].score;
}
static int _callback_type(PluginHelper * ph, uint16_t type)
{
struct
{
uint16_t type;
char * name;
int score;
} tns[] =
{
{ ET_NONE, "no type", 50 },
{ ET_REL, "relocatable", 100 },
{ ET_EXEC, "executable", 100 },
{ ET_DYN, "shared object", 100 },
{ ET_CORE, "core file", 100 },
{ 0, NULL, 0 }
};
size_t i;
for(i = 0; tns[i].name != NULL; i++)
if(tns[i].type == type)
break;
if(tns[i].name == NULL)
{
ph->printf(ph, "%s", ", unknown type");
return 0;
}
ph->printf(ph, "%s%s", ", ", tns[i].name);
return tns[i].score;
}
static int _callback_machine(PluginHelper * ph, uint16_t machine)
{
struct
{
uint16_t machine;
char * name;
int score;
} mns[] =
{
{ EM_NONE, "no machine", 50 },
{ EM_SPARC, "SPARC", 100 },
{ EM_386, "i386", 100 },
{ EM_68K, "m68k", 100 },
{ EM_88K, "m88k", 100 },
{ EM_486, "i486", 100 },
{ EM_860, "i860", 100 },
{ EM_MIPS, "MIPS", 100 },
{ EM_MIPS_RS3_LE, "MIPS", 100 },
{ EM_ARM, "ARM", 100 },
{ 0, NULL, 0 }
};
size_t i;
for(i = 0; mns[i].name != NULL; i++)
if(mns[i].machine == machine)
break;
if(mns[i].name == NULL)
{
ph->printf(ph, "%s%d%s", ", unknown target (", machine, ")");
return 0;
}
ph->printf(ph, "%s%s", ", for ", mns[i].name);
return mns[i].score;
}