commit 3a99de7642ee3e74c43d7da016830f7144329305 Author: TheBrokenRail Date: Tue Mar 22 19:13:25 2022 -0400 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..14125a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vscode +build +CMakeLists.txt.user +*.autosave diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b06624e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.13.0) + +# Project +project(elf-padder) + +# Warnings +add_compile_options(-Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference) +add_link_options(-Wl,--no-undefined) +add_definitions(-D_GNU_SOURCE) +set(CMAKE_C_STANDARD 99) + +# Build +add_executable(elf-padder src/main.c src/elf_32.c src/elf_64.c) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2eee90d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 TheBrokenRail + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/elf.h b/src/elf.h new file mode 100644 index 0000000..6f21932 --- /dev/null +++ b/src/elf.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +void Elf32_pad(unsigned char *out, size_t padding); +void Elf64_pad(unsigned char *out, size_t padding); diff --git a/src/elf_32.c b/src/elf_32.c new file mode 100644 index 0000000..d73aeb1 --- /dev/null +++ b/src/elf_32.c @@ -0,0 +1,2 @@ +#define CustomElfW(x) Elf32_##x +#include "elf_common.c" diff --git a/src/elf_64.c b/src/elf_64.c new file mode 100644 index 0000000..c813730 --- /dev/null +++ b/src/elf_64.c @@ -0,0 +1,2 @@ +#define CustomElfW(x) Elf64_##x +#include "elf_common.c" diff --git a/src/elf_common.c b/src/elf_common.c new file mode 100644 index 0000000..622bbce --- /dev/null +++ b/src/elf_common.c @@ -0,0 +1,39 @@ +#ifndef CustomElfW +#include +#define CustomElfW(x) ElfW(x) +#endif + +#include + +#include "log.h" +#include "elf.h" + +// Fix ELF Pointers +void CustomElfW(pad)(unsigned char *out, size_t padding) { + // Get ELF Header + CustomElfW(Ehdr) *elf_header = (CustomElfW(Ehdr) *) out; + + // Fix ELF Program Header Offset + if (elf_header->e_phoff != 0) { + elf_header->e_phoff += padding; + + // Fix ELF Program Headers + CustomElfW(Phdr) *elf_program_headers = (CustomElfW(Phdr) *) (out + elf_header->e_phoff); + int elf_program_header_count = elf_header->e_phnum; + for (int i = 0; i < elf_program_header_count; i++) { + elf_program_headers[i].p_offset += padding; + } + } + + // Fix ELF Section Header + if (elf_header->e_shoff != 0) { + elf_header->e_shoff += padding; + + // Fix ELF Section Headers + CustomElfW(Shdr) *elf_section_headers = (CustomElfW(Shdr) *) (out + elf_header->e_shoff); + int elf_section_header_count = elf_header->e_shnum; + for (int i = 0; i < elf_section_header_count; i++) { + elf_section_headers[i].sh_offset += padding; + } + } +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..ce237dc --- /dev/null +++ b/src/log.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +// Logging +#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", __VA_ARGS__); } +#define ERR(format, ...) { fprintf(stderr, "[ERR]: (%s:%i): " format "\n", __FILE__, __LINE__, __VA_ARGS__); exit(EXIT_FAILURE); } + +// Check Memory Allocation +#define ALLOC_CHECK(obj) \ + { \ + if (obj == NULL) { \ + ERR("%s", "Memory Allocation Failed"); \ + } \ + } diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..56af8b8 --- /dev/null +++ b/src/main.c @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include + +#include "log.h" +#include "elf.h" + +// Pad ELF File +static void *elf_pad(const char *target, size_t padding, size_t *out_size) { + // File Data + FILE *file_obj = NULL; + unsigned char *file_map = NULL; + long int file_size = 0; + + // Return + unsigned char *out = NULL; + + // Code + { + // Load Main Binary + file_obj = fopen(target, "rb"); + + // Verify Binary + if (!file_obj) { + ERR("Unable To Open: %s", target); + } + + // Get File Size + fseek(file_obj, 0L, SEEK_END); + file_size = ftell(file_obj); + fseek(file_obj, 0L, SEEK_SET); + + // Map File To Pointer + file_map = (unsigned char *) mmap(0, file_size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0); + + // Check ELF Magic + if (file_map[EI_MAG0] != ELFMAG0 || file_map[EI_MAG1] != ELFMAG1 || file_map[EI_MAG2] != ELFMAG2 || file_map[EI_MAG3] != ELFMAG3) { + ERR("Not An ELF File: %s", target); + } + int is_64bit = file_map[EI_CLASS] != ELFCLASS32; + if (file_map[EI_DATA] != ELFDATA2LSB) { + ERR("ELF File Isn't Little-Endian: %s", target); + } + + // Allocate New File + *out_size = file_size + padding; + out = malloc(*out_size); + ALLOC_CHECK(out); + + // Copy Header + size_t header_size = is_64bit ? sizeof (Elf64_Ehdr) : sizeof (Elf32_Ehdr); + memcpy(out, file_map, header_size); + // Copy Everything Else + memcpy(out + header_size + padding, file_map + header_size, file_size - header_size); + // Zero Padding + memset(out + header_size, 0, padding); + + // Fix Pointers + if (is_64bit) { + Elf64_pad(out, padding); + } else { + Elf32_pad(out, padding); + } + } + + // Unmap And Close File + if (file_map != NULL) { + munmap(file_map, file_size); + } + if (file_obj != NULL) { + fclose(file_obj); + } + + // Return + return out; +} + +// Main +int main(int argc, char *argv[]) { + if (argc != 3) { + ERR("%s", "Invalid Arguments"); + } + + // Arguments + size_t padding = 0; + if (sscanf(argv[1], "%zu", &padding) != 1) { + ERR("%s", "Unable To Parse Padding Number"); + } + char *target = argv[2]; + + // Align Padding To Page Boundary + { + long page_size = sysconf(_SC_PAGESIZE); + size_t old_padding = padding; + padding = (padding / page_size) * page_size; + if ((old_padding % page_size) != 0) { + padding += page_size; + } + } + INFO("Aligning Padding To Page Boundary: %zu", padding); + + // Pad + size_t out_size = 0; + void *out = elf_pad(target, padding, &out_size); + + // Print + fwrite(out, 1, out_size, stdout); + + // Free + free(out); +}