ELF32: RELRO, strip, linking info

This commit is contained in:
2025-09-06 12:18:27 +02:00
parent ae889caae4
commit f3496b103e
5 changed files with 132 additions and 33 deletions

View File

@@ -4,3 +4,6 @@
- display protections - display protections
- colorful - colorful
- maybe display elf sections if command entered (??) - maybe display elf sections if command entered (??)
- security:
enforce malloc secure fail

BIN
a.out

Binary file not shown.

BIN
helpelf

Binary file not shown.

160
main.c
View File

@@ -44,11 +44,16 @@
#define PT_GNU_STACK 0x6474e551 #define PT_GNU_STACK 0x6474e551
#define SHT_DYNSYM 11 #define SHT_DYNSYM 11
#define SHT_SYMTAB 2 #define SHT_SYMTAB 2
#define PT_GNU_RELRO 0x6474e552
#define PT_DYNAMIC 2
#define DT_BIND_NOW 24
#define PT_INTERP 3
#define Elf32_Half uint16_t #define Elf32_Half uint16_t
#define Elf32_Word uint32_t #define Elf32_Word uint32_t
#define Elf32_Addr uint32_t #define Elf32_Sword int32_t
#define Elf32_Off uint32_t #define Elf32_Addr uint32_t
#define Elf32_Off uint32_t
#define Elf64_Half uint32_t #define Elf64_Half uint32_t
#define Elf64_Word uint64_t #define Elf64_Word uint64_t
@@ -59,6 +64,10 @@ bool verbose = false;
bool pie = false; bool pie = false;
bool nx = false; bool nx = false;
bool canary = false; bool canary = false;
bool relro = false;
bool bind_now = false;
bool stripped = true;
bool interp = false;
struct Elf32_Ehdr struct Elf32_Ehdr
{ {
@@ -114,6 +123,16 @@ struct Elf32_Sym
Elf32_Half st_shndx; Elf32_Half st_shndx;
}; };
struct Elf32_Dyn
{
Elf32_Sword d_tag;
union
{
Elf32_Word d_val;
Elf32_Addr d_ptr;
} d_un;
} Elf32_Dyn;
struct Elf64_Ehdr struct Elf64_Ehdr
{ {
unsigned char e_ident[EI_NIDENT]; unsigned char e_ident[EI_NIDENT];
@@ -181,7 +200,41 @@ void display_elf_common(unsigned char e_ident[EI_NIDENT])
} }
} }
void display_elf32(struct Elf32_Ehdr* header) void check_dynamic32(struct Elf32_Ehdr* header, FILE* fp)
{
// Is dynamically linked? (has PT_INTERP program header?)
// read program headers
fseek(fp, header->e_phoff, SEEK_SET);
struct Elf32_Phdr *p_headers = malloc(header->e_phnum * sizeof(struct Elf32_Phdr));
fread(p_headers, sizeof(struct Elf32_Phdr), header->e_phnum, fp);
const char* interpstr = NULL;
for (int i=0; i<header->e_phnum; i++)
{
if (p_headers[i].p_type == PT_INTERP)
{
interp = true;
// Get interpreter path
interpstr = malloc(p_headers[i].p_filesz);
fseek(fp, p_headers[i].p_offset, SEEK_SET);
fread((char*)interpstr, 1, p_headers[i].p_filesz, fp);
break;
}
}
if (interp)
{
printf("dynamically linked (interpreter: %s), ", interpstr);
}
else
{
printf("statically linked, ");
}
}
void display_elf32(struct Elf32_Ehdr* header, FILE* fp)
{ {
printf("32-bit ELF "); printf("32-bit ELF ");
display_elf_common(header->e_ident); display_elf_common(header->e_ident);
@@ -219,57 +272,51 @@ void display_elf32(struct Elf32_Ehdr* header)
switch (header->e_machine) switch (header->e_machine)
{ {
case 0x00: case 0x00:
printf("No architecture,"); printf("No architecture, ");
break; break;
case 0x01: case 0x01:
printf("AT&T WE 32100,"); printf("AT&T WE 32100, ");
break; break;
case 0x02: case 0x02:
printf("SPARC,"); printf("SPARC, ");
break; break;
case 0x03: case 0x03:
printf("i386,"); printf("i386, ");
break; break;
case 0x04: case 0x04:
printf("Motorola 68000,"); printf("Motorola 68000, ");
break; break;
case 0x05: case 0x05:
printf("Motorola 88000,"); printf("Motorola 88000, ");
break; break;
case 0x07: case 0x07:
printf("Intel 80860,"); printf("Intel 80860, ");
break; break;
case 0x08: case 0x08:
printf("MIPS RS3000,"); printf("MIPS RS3000, ");
break; break;
case 0x09: case 0x09:
printf("MIPS RS4000,"); printf("MIPS RS4000, ");
break; break;
default: default:
printf("Unknown architecture"); printf("Unknown architecture, ");
break; break;
} }
if (verbose) if (verbose)
{ {
printf("\ne_version: %d\n", header->e_version); check_dynamic32(header, fp);
printf("e_entry: 0x%08x\n", header->e_entry);
printf("e_phoff: 0x%08x\n", header->e_phoff);
printf("e_shoff: 0x%08x\n", header->e_shoff);
printf("e_flags: 0x%08x\n", header->e_flags);
printf("e_ehsize: 0x%08x\n", header->e_ehsize);
printf("e_phentsize: 0x%08x\n", header->e_phentsize);
printf("e_phnum: 0x%08x\n", header->e_phnum);
printf("e_shentsize: 0x%08x\n", header->e_shentsize);
printf("e_shnum: 0x%08x\n", header->e_shnum);
printf("e_shstrndx: 0x%08x\n", header->e_shstrndx);
} }
} }
void check_nx32(struct Elf32_Ehdr* header, FILE* fp)
{
}
void check_sec32(struct Elf32_Ehdr* header, FILE* fp) void check_sec32(struct Elf32_Ehdr* header, FILE* fp)
{ {
/* NX:
/*
* Browse thru program header table (e_phnum items) from e_phoff (program header offset) * Browse thru program header table (e_phnum items) from e_phoff (program header offset)
* if its stack and has executable bit then we know NX isnt there * if its stack and has executable bit then we know NX isnt there
*/ */
@@ -291,7 +338,7 @@ void check_sec32(struct Elf32_Ehdr* header, FILE* fp)
} }
} }
/* /* Stack canary:
* Same for section header table (e_shnum items) from e_shoff (section header offset) * Same for section header table (e_shnum items) from e_shoff (section header offset)
* find sections .dynsym or .symtab: * find sections .dynsym or .symtab:
* and look for __stack_chk_fail (call for stack smashing) * and look for __stack_chk_fail (call for stack smashing)
@@ -310,6 +357,9 @@ void check_sec32(struct Elf32_Ehdr* header, FILE* fp)
for (size_t i=0; i<header->e_shnum; i++) for (size_t i=0; i<header->e_shnum; i++)
{ {
// additional small check for stripping as we're already browsing section headers
if (s_headers[i].sh_type == SHT_SYMTAB && s_headers[i].sh_size > 0) stripped = false;
if (s_headers[i].sh_type == SHT_DYNSYM || s_headers[i].sh_type == SHT_SYMTAB) if (s_headers[i].sh_type == SHT_DYNSYM || s_headers[i].sh_type == SHT_SYMTAB)
{ {
// load symbol table // load symbol table
@@ -335,6 +385,50 @@ void check_sec32(struct Elf32_Ehdr* header, FILE* fp)
} }
} }
} }
/* RELRO:
* Segment type PT_GNU_RELRO should be present
*/
// Read program headers
fseek(fp, header->e_phoff, SEEK_SET);
struct Elf32_Phdr *p_headers = malloc(header->e_phnum * sizeof(struct Elf32_Phdr));
fread (p_headers, sizeof(struct Elf32_Phdr), header->e_phnum, fp);
Elf32_Off dyn_off = 0;
Elf32_Word dyn_size = 0;
for (int i=0; i<header->e_phnum; i++)
{
if (p_headers[i].p_type == PT_GNU_RELRO)
{
relro = true;
}
if (p_headers[i].p_type == PT_DYNAMIC)
{
dyn_off = p_headers[i].p_offset;
dyn_size = p_headers[i].p_filesz;
}
}
if (dyn_off && dyn_size)
{
int n = dyn_size / sizeof(struct Elf32_Dyn);
struct Elf32_Dyn *dyns = malloc(dyn_size);
fseek(fp, dyn_off, SEEK_SET);
fread(dyns, sizeof(struct Elf32_Dyn), n, fp);
for (int i=0; i<n; i++)
{
// Has full RELRO?
if (dyns[i].d_tag == DT_BIND_NOW)
{
bind_now = true;
break;
}
}
}
} }
void display_elf64(struct Elf64_Ehdr* header) void display_elf64(struct Elf64_Ehdr* header)
@@ -354,9 +448,11 @@ unsigned char read_elf_obj_size(FILE* fp)
void display_sec_common() void display_sec_common()
{ {
printf(" %s, ", nx ? "\x1b[32mNX enabled\x1b[0m" : "\x1b[31mNX disabled\x1b[0m"); printf("%s, ", nx ? "\x1b[32mNX enabled\x1b[0m" : "\x1b[31mNX disabled\x1b[0m");
printf("%s, ", pie ? "\x1b[32mPIE enabled\x1b[0m" : "\x1b[31mPIE disabled\x1b[0m"); printf("%s, ", pie ? "\x1b[32mPIE enabled\x1b[0m" : "\x1b[31mPIE disabled\x1b[0m");
printf("%s\n", canary ? "\x1b[32mStack canary enabled\x1b[0m" : "\x1b[31mStack canary disabled\x1b[0m"); printf("%s, ", canary ? "\x1b[32mStack canary enabled\x1b[0m" : "\x1b[31mStack canary disabled\x1b[0m");
printf("%s, ", relro && bind_now ? "\x1b[32mFull RELRO\x1b[0m" : relro ? "\x1b[33mPartial RELRO\x1b[0m" : "\x1b[31mNo RELRO\x1b[0m");
printf("%s\n", stripped ? "\x1b[32mStripped\x1b[0m" : "\x1b[31mNot stripped\x1b[0m");
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
@@ -408,7 +504,7 @@ int main(int argc, char* argv[])
printf("Failed to parse 32-bit ELF header\n"); printf("Failed to parse 32-bit ELF header\n");
return -EINVAL; return -EINVAL;
} }
display_elf32(&elf32_header); display_elf32(&elf32_header, elf_file);
check_sec32(&elf32_header, elf_file); check_sec32(&elf32_header, elf_file);
break; break;
case 0x02: case 0x02:

View File

@@ -6,7 +6,7 @@ install:
test: test:
make make
gcc -m32 -fstack-protector main.c gcc -m32 -fstack-protector -static -Wl,-z,relro,-z,now main.c
./helpelf a.out ./helpelf a.out
clean: clean: