mirror of
https://github.com/JonathanSalwan/ROPgadget
synced 2026-06-08 11:25:23 +00:00
226 lines
7.1 KiB
C
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;
|
|
}
|