64-bit checksec + README

This commit is contained in:
2025-09-07 13:20:19 +02:00
parent 489d35a65b
commit cc1883b1e5
3 changed files with 231 additions and 7 deletions

184
main.c
View File

@@ -468,6 +468,189 @@ void check_sec32(Elf32_Ehdr* header, FILE* fp)
free(p_headers);
}
// Duplicate code. Should find a workaround
void check_sec64(Elf64_Ehdr* header, FILE* fp)
{
/* NX:
* 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
*/
fseek(fp, header->e_phoff, SEEK_SET);
for (size_t i=0; i<header->e_phnum; i++)
{
Elf64_Phdr p_header;
if (!fread(&p_header, 1, sizeof(Elf64_Phdr), fp))
{
puts("Read error.");
exit(-EIO);
}
if (p_header.p_type == PT_GNU_STACK)
{
if (p_header.p_flags & PF_X)
{
nx = false;
}
else
{
nx = true;
}
}
}
/* Stack canary:
* 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
Elf64_Shdr *s_headers = malloc(header->e_shnum * sizeof(Elf64_Shdr));
if (!s_headers)
{
puts("Memory allocation error.");
exit(-ENOMEM);
}
if (!fread(s_headers, sizeof(Elf64_Shdr), header->e_shnum, fp))
{
puts("Read error.");
exit(-EIO);
}
// Find section name string table (at e_shstrndx) and read it
Elf64_Shdr s_header_str = s_headers[header->e_shstrndx];
char* s_header_strtab = malloc(s_header_str.sh_size);
if (!s_header_strtab)
{
puts("Memory allocation error.");
exit(-ENOMEM);
}
fseek(fp, s_header_str.sh_offset, SEEK_SET);
if (!fread(s_header_strtab, 1, s_header_str.sh_size, fp))
{
puts("Read error.");
exit(-EIO);
}
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)
{
// load symbol table
unsigned int nsyms = s_headers[i].sh_size / s_headers[i].sh_entsize;
Elf64_Sym *syms = malloc(s_headers[i].sh_size);
if (!syms)
{
puts("Memory allocation error.");
exit(-EIO);
}
fseek(fp, s_headers[i].sh_offset, SEEK_SET);
if (!fread(syms, s_headers[i].sh_size, 1, fp))
{
puts("Read error.");
exit(-EIO);
}
// load string table
Elf64_Shdr str_header = s_headers[s_headers[i].sh_link];
char* strtab = malloc(str_header.sh_size);
if (!strtab)
{
puts("Memory allocation error.");
exit(-ENOMEM);
}
fseek(fp, str_header.sh_offset, SEEK_SET);
if (!fread(strtab, 1, str_header.sh_size, fp))
{
puts("Read error.");
exit(-EIO);
}
// 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;
}
}
free(syms);
free(strtab);
}
}
/* RELRO:
* Segment type PT_GNU_RELRO should be present
*/
// Read program headers
fseek(fp, header->e_phoff, SEEK_SET);
Elf64_Phdr *p_headers = malloc(header->e_phnum * sizeof(Elf64_Phdr));
if (!p_headers)
{
puts("Memory allocation error.");
exit(-ENOMEM);
}
if (!fread (p_headers, sizeof(Elf64_Phdr), header->e_phnum, fp))
{
puts("Read error.");
exit(-EIO);
}
Elf64_Off dyn_off = 0;
Elf64_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(Elf64_Dyn);
Elf64_Dyn *dyns = malloc(dyn_size);
if (!dyns)
{
puts("Memory allocation error.");
exit(-ENOMEM);
}
fseek(fp, dyn_off, SEEK_SET);
if (!fread(dyns, sizeof(Elf64_Dyn), n, fp))
{
puts("Read error.");
exit(-EIO);
}
for (int i=0; i<n; i++)
{
// Has full RELRO?
if (dyns[i].d_tag == DT_BIND_NOW)
{
bind_now = true;
break;
}
}
free(dyns);
}
free(s_headers);
free(s_header_strtab);
free(p_headers);
}
unsigned char read_elf_obj_size(FILE* fp)
{
unsigned char local_elf_obj_size = 0;
@@ -550,6 +733,7 @@ int main(int argc, char* argv[])
return -EINVAL;
}
display_elf64(&elf64_header, elf_file);
check_sec64(&elf64_header, elf_file);
break;
default:
puts("Invalid ELF object size");