ELF32: stack canary
This commit is contained in:
129
main.c
129
main.c
@@ -33,11 +33,17 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// Data structures as per ELF specification:
|
||||||
|
// https://refspecs.linuxfoundation.org/elf/elf.pdf
|
||||||
|
// Only what we need (no elf.h)
|
||||||
|
|
||||||
#define MAX_FILENAME 256
|
#define MAX_FILENAME 256
|
||||||
#define EI_NIDENT 16
|
#define EI_NIDENT 16
|
||||||
#define MAX_HEADER_LEN 2048
|
#define MAX_HEADER_LEN 2048
|
||||||
#define PF_X 1
|
#define PF_X 1
|
||||||
#define PT_GNU_STACK 0x6474e551
|
#define PT_GNU_STACK 0x6474e551
|
||||||
|
#define SHT_DYNSYM 11
|
||||||
|
#define SHT_SYMTAB 2
|
||||||
|
|
||||||
#define Elf32_Half uint16_t
|
#define Elf32_Half uint16_t
|
||||||
#define Elf32_Word uint32_t
|
#define Elf32_Word uint32_t
|
||||||
@@ -52,6 +58,7 @@
|
|||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
bool pie = false;
|
bool pie = false;
|
||||||
bool nx = false;
|
bool nx = false;
|
||||||
|
bool canary = false;
|
||||||
|
|
||||||
struct Elf32_Ehdr
|
struct Elf32_Ehdr
|
||||||
{
|
{
|
||||||
@@ -83,6 +90,30 @@ struct Elf32_Phdr
|
|||||||
Elf32_Word p_align;
|
Elf32_Word p_align;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Elf32_Shdr
|
||||||
|
{
|
||||||
|
Elf32_Word sh_name;
|
||||||
|
Elf32_Word sh_type;
|
||||||
|
Elf32_Word sh_flags;
|
||||||
|
Elf32_Addr sh_addr;
|
||||||
|
Elf32_Off sh_offset;
|
||||||
|
Elf32_Word sh_size;
|
||||||
|
Elf32_Word sh_link;
|
||||||
|
Elf32_Word sh_info;
|
||||||
|
Elf32_Word sh_addralign;
|
||||||
|
Elf32_Word sh_entsize;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf32_Sym
|
||||||
|
{
|
||||||
|
Elf32_Word st_name;
|
||||||
|
Elf32_Addr st_value;
|
||||||
|
Elf32_Word st_size;
|
||||||
|
unsigned char st_info;
|
||||||
|
unsigned char st_other;
|
||||||
|
Elf32_Half st_shndx;
|
||||||
|
};
|
||||||
|
|
||||||
struct Elf64_Ehdr
|
struct Elf64_Ehdr
|
||||||
{
|
{
|
||||||
unsigned char e_ident[EI_NIDENT];
|
unsigned char e_ident[EI_NIDENT];
|
||||||
@@ -155,29 +186,35 @@ void display_elf32(struct Elf32_Ehdr* header)
|
|||||||
printf("32-bit ELF ");
|
printf("32-bit ELF ");
|
||||||
display_elf_common(header->e_ident);
|
display_elf_common(header->e_ident);
|
||||||
|
|
||||||
switch (header->e_type)
|
if (verbose)
|
||||||
{
|
{
|
||||||
case 0x00:
|
switch (header->e_type)
|
||||||
printf("(no file type),");
|
{
|
||||||
break;
|
case 0x00:
|
||||||
case 0x01:
|
printf("(no file type),");
|
||||||
printf("(relocatable file),");
|
break;
|
||||||
break;
|
case 0x01:
|
||||||
case 0x02:
|
printf("(relocatable file),");
|
||||||
printf("(executable file),");
|
break;
|
||||||
break;
|
case 0x02:
|
||||||
case 0x03: // (ET_DYN, prob means PIE)
|
printf("(executable file),");
|
||||||
printf("(shared object file),");
|
break;
|
||||||
pie = true;
|
case 0x03: // (ET_DYN, prob means PIE)
|
||||||
break;
|
printf("(shared object file),");
|
||||||
case 0x04:
|
pie = true;
|
||||||
printf("(core file),");
|
break;
|
||||||
break;
|
case 0x04:
|
||||||
default:
|
printf("(core file),");
|
||||||
printf("(unknown),");
|
break;
|
||||||
break;
|
default:
|
||||||
|
printf("(unknown),");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf(" ");
|
||||||
|
} else if (header->e_type == 0x03)
|
||||||
|
{
|
||||||
|
pie = true;
|
||||||
}
|
}
|
||||||
printf(" ");
|
|
||||||
|
|
||||||
switch (header->e_machine)
|
switch (header->e_machine)
|
||||||
{
|
{
|
||||||
@@ -231,13 +268,13 @@ void display_elf32(struct Elf32_Ehdr* header)
|
|||||||
|
|
||||||
void check_sec32(struct Elf32_Ehdr* header, FILE* fp)
|
void check_sec32(struct Elf32_Ehdr* header, FILE* fp)
|
||||||
{
|
{
|
||||||
fseek(fp, header->e_phoff, SEEK_SET);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
*/
|
*/
|
||||||
for (size_t i=0; i < header->e_phnum; i++)
|
fseek(fp, header->e_phoff, SEEK_SET);
|
||||||
|
for (size_t i=0; i<header->e_phnum; i++)
|
||||||
{
|
{
|
||||||
struct Elf32_Phdr p_header;
|
struct Elf32_Phdr p_header;
|
||||||
fread (&p_header, 1, sizeof(struct Elf32_Phdr), fp);
|
fread (&p_header, 1, sizeof(struct Elf32_Phdr), fp);
|
||||||
@@ -253,6 +290,51 @@ void check_sec32(struct Elf32_Ehdr* header, FILE* fp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Same for section header table (e_shnum items) from e_shoff (section header offset)
|
||||||
|
* find sections .dynsym or .symtab:
|
||||||
|
* and look for __stack_chk_fail (call for stack smashing)
|
||||||
|
*/
|
||||||
|
fseek(fp, header->e_shoff, SEEK_SET);
|
||||||
|
|
||||||
|
// Read section headers
|
||||||
|
struct Elf32_Shdr *s_headers = malloc(header->e_shnum * sizeof(struct Elf32_Shdr));
|
||||||
|
fread(s_headers, sizeof(struct Elf32_Shdr), header->e_shnum, fp);
|
||||||
|
|
||||||
|
// Find section name string table (at e_shstrndx) and read it
|
||||||
|
struct Elf32_Shdr s_header_str = s_headers[header->e_shstrndx];
|
||||||
|
char* s_header_strtab = malloc(s_header_str.sh_size);
|
||||||
|
fseek(fp, s_header_str.sh_offset, SEEK_SET);
|
||||||
|
fread(s_header_strtab, 1, s_header_str.sh_size, fp);
|
||||||
|
|
||||||
|
for (size_t i=0; i<header->e_shnum; i++)
|
||||||
|
{
|
||||||
|
if (s_headers[i].sh_type == SHT_DYNSYM || s_headers[i].sh_type == SHT_SYMTAB)
|
||||||
|
{
|
||||||
|
// load symbol table
|
||||||
|
unsigned int nsyms = s_headers[i].sh_size / s_headers[i].sh_entsize;
|
||||||
|
struct Elf32_Sym *syms = malloc(s_headers[i].sh_size);
|
||||||
|
fseek(fp, s_headers[i].sh_offset, SEEK_SET);
|
||||||
|
fread(syms, s_headers[i].sh_size, 1, fp);
|
||||||
|
|
||||||
|
// load string table
|
||||||
|
struct Elf32_Shdr str_header = s_headers[s_headers[i].sh_link];
|
||||||
|
char* strtab = malloc(str_header.sh_size);
|
||||||
|
fseek(fp, str_header.sh_offset, SEEK_SET);
|
||||||
|
fread(strtab, 1, str_header.sh_size, fp);
|
||||||
|
|
||||||
|
// iterate through symbols, check for __stack_chk_fail
|
||||||
|
for (size_t j=0; j<nsyms; j++)
|
||||||
|
{
|
||||||
|
const char* name = strtab + syms[j].st_name;
|
||||||
|
if (strcmp(name, "__stack_chk_fail") == 0)
|
||||||
|
{
|
||||||
|
canary = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_elf64(struct Elf64_Ehdr* header)
|
void display_elf64(struct Elf64_Ehdr* header)
|
||||||
@@ -274,6 +356,7 @@ 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
|
|||||||
Reference in New Issue
Block a user