Files
JonathanSalwan-ROPgadget/src/parse_elf.c
T
2013-01-29 13:32:09 -05:00

226 lines
7.1 KiB
C

/*
** RopGadget - Release v4.0.0
** Allan Wirth - http://allanwirth.com/
** Jonathan Salwan - http://twitter.com/JonathanSalwan
** 2013-1-20
**
** 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; either version 2 of the License, or
** (at your option) any later version.
**
** 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
*/
#include "ropgadget.h"
#define MAGIC_ELF "\x7F\x45\x4C\x46"
/* does something to the phdr/header struct with a given type, based on 32 or 64 bits */
/* Joshua 7:20 - Achan replied, "It is true! I have sinned against the LORD, the God of Israel." */
#define EHDR(b, X, t) (b->container == CONTAINER_ELF32?((t)((Elf32_Ehdr*)b->data) X):((t)((Elf64_Ehdr*)b->data) X))
#define PHDR(b, X, t) (b->container == CONTAINER_ELF32?((t)((Elf32_Phdr*)b->phdr) X):((t)((Elf64_Phdr*)b->phdr) X))
#define SHDR(a, b, X, t) (b->container == CONTAINER_ELF32?((t)((Elf32_Shdr*)a) X) :((t)((Elf64_Shdr*)a) X))
#define DYN(a, b, X, t) (b->container == CONTAINER_ELF32?(t)(a.dyn32 X) :(t)(a.dyn64 X))
#define ARTH_PHDR(b,n,op)(b->container == CONTAINER_ELF32?(b->phdr op sizeof(Elf32_Phdr)*(n)):(b->phdr op sizeof(Elf64_Phdr)*(n)))
#define ARTH_SHDR(a,b,n,op)(b->container == CONTAINER_ELF32?(a op sizeof(Elf32_Shdr)*(n)):(a op sizeof(Elf64_Shdr)*(n)))
#define INC_PHDR(b, n) ARTH_PHDR(b, n, +=)
#define INC_SHDR(a, b, n) ARTH_SHDR(a, b, n, +=)
#define DEC_PHDR(b, n) ARTH_PHDR(b, n, -=)
#define DEC_SHDR(a, b, n) ARTH_SHDR(a, b, n, -=)
#define SYSV(d) (d[EI_OSABI] == ELFOSABI_SYSV)
#define LINUX(d) (d[EI_OSABI] == ELFOSABI_LINUX)
#define FREEBSD(d) (d[EI_OSABI] == ELFOSABI_FREEBSD)
#define ELF_F(d) (d[EI_CLASS] == ELFCLASS32)
#define ELF_F64(d) (d[EI_CLASS] == ELFCLASS64)
#define PROC8632(b) (EHDR(b,->e_machine, int) == (int)EM_386)
#define PROC8664(b) (EHDR(b,->e_machine, int) == (int)EM_X86_64)
static void save_depends(t_binary *bin, void *dyns)
{
union {
Elf32_Dyn *dyn32;
Elf64_Dyn *dyn64;
} a;
char *strtab;
size_t i;
DYN(a, bin, = dyns, void *);
for (i = 0; DYN(a, bin, [i].d_tag, Elf64_Sxword) != DT_NULL; i++)
{
if (DYN(a, bin, [i].d_tag, Elf64_Sxword) == DT_STRTAB)
{
strtab = (char*)(DYN(a, bin, [i].d_un.d_val, Address) - bin->load_diff + bin->data);
break;
}
}
for (i = 0; DYN(a, bin, [i].d_tag, Elf64_Sxword) != DT_NULL; i++)
{
Elf64_Sxword type = DYN(a, bin, [i].d_tag, Elf64_Sxword);
if (type == DT_NEEDED)
bin->depends = add_dep(bin->depends, strtab + DYN(a, bin, [i].d_un.d_ptr, Address));
}
}
static void save_sections(t_binary *bin)
{
Size x = 0;
char *ptrNameSection = NULL;
Size shnum;
unsigned char *shdr;
shdr = bin->data+ EHDR(bin, ->e_shoff, size_t);
shnum = EHDR(bin, ->e_shnum, Size);
INC_SHDR(shdr, bin, EHDR(bin, ->e_shstrndx, size_t));
ptrNameSection = (char *)(bin->data + SHDR(shdr, bin, ->sh_offset, size_t));
DEC_SHDR(shdr, bin, EHDR(bin, ->e_shstrndx, size_t));
for ( x = 0; x != shnum; x++, INC_SHDR(shdr, bin, 1))
{
char *name = ptrNameSection + SHDR(shdr, bin, ->sh_name, size_t);
int flags = SHDR(shdr, bin, ->sh_flags, int);
Address addr = SHDR(shdr, bin, ->sh_addr, Address);
Size size = SHDR(shdr, bin, ->sh_size, Size);
Size offset = SHDR(shdr, bin, ->sh_offset, Size);
if (flags & SHF_ALLOC && flags & SHF_WRITE) /* .data, etc. */
{
if (addr == bin->writable_offset + bin->writable_size)
bin->writable_size += size;
else if (size > bin->writable_size)
{
bin->writable_offset = addr;
bin->writable_size = size;
}
}
if (flags & SHF_ALLOC && flags & SHF_WRITE && flags & SHF_EXECINSTR) /* .got, etc. */
{
if (addr == bin->writable_exec_offset + bin->writable_exec_size)
bin->writable_exec_size += size;
else if (size > bin->writable_exec_size)
{
bin->writable_exec_offset = addr;
bin->writable_exec_size = size;
}
}
if (!strcmp(name, ".text"))
{
bin->exec_offset = offset;
bin->exec_size = size;
}
else if (!strcmp(name, ".dynamic"))
{
save_depends(bin, bin->data + offset);
}
}
if (bin->writable_offset % 0x100 == 0x00 && bin->writable_size > 0)
{
bin->writable_offset++;
bin->writable_size--;
}
if (bin->writable_exec_offset % 0x100 == 0x00 && bin->writable_exec_size > 0)
{
bin->writable_exec_offset++;
bin->writable_exec_size--;
}
}
/* check if flag have a READ BIT */
static int check_read_flag(Elf64_Word flag)
{
return (flag > 3);
}
/* check if flag have a EXEC BIT */
static int check_exec_flag(Elf64_Word flag)
{
return (flag%2 == 1);
}
/* return linked list with maps read/exec segment */
static void make_maps(t_binary *bin, int read)
{
Elf64_Half x;
t_map *map;
Elf64_Half phnum;
map = NULL;
phnum = EHDR(bin, ->e_phnum, Elf64_Half);
for (x = 0; x != phnum; x++, INC_PHDR(bin, 1))
{
if (read?check_read_flag(PHDR(bin, ->p_flags, Elf64_Word)):check_exec_flag(PHDR(bin, ->p_flags, Elf64_Word)))
map = add_map(map, PHDR(bin, ->p_vaddr, Address), PHDR(bin, ->p_offset, Address), PHDR(bin, ->p_filesz, Size));
if (!read && PHDR(bin, ->p_type == PT_LOAD, int) && !bin->load_diff_set)
{
bin->load_diff = PHDR(bin, ->p_vaddr, Address) - PHDR(bin, ->p_offset, Offset);
bin->load_diff_set = TRUE;
}
}
DEC_PHDR(bin, phnum);
if (read)
bin->maps_read = map;
else
bin->maps_exec = map;
}
static int is_elf(unsigned char *data)
{
return !strncmp((char *)data, MAGIC_ELF, 4);
}
int process_elf(t_binary *output)
{
unsigned char *data = output->data;
if (!is_elf(output->data))
return FALSE;
/* supported: - Linux/x86-32bits */
/* supported: - FreeBSD/x86-32bits */
if (ELF_F(data) && (SYSV(data) || LINUX(data) || FREEBSD(data)))
{
output->container = CONTAINER_ELF32;
output->processor = PROCESSOR_X8632;
if (!PROC8632(output))
return FALSE;
}
else if (ELF_F64(data) && (SYSV(data) || LINUX(data) || FREEBSD(data)))
{
output->container = CONTAINER_ELF64;
output->processor = PROCESSOR_X8664;
if (!PROC8664(output))
return FALSE;
}
else
return FALSE;
if (EHDR(output, ->e_type, uint16_t) == ET_DYN)
output->object = OBJECT_SHARED;
else
output->object = OBJECT_EXECUTABLE;
output->abi = ABI_LINUX;
output->phdr = output->data + EHDR(output, ->e_phoff, Size);
make_maps(output, 0);
make_maps(output, 1);
save_sections(output);
return TRUE;
}