diff options
-rw-r--r-- | .gitignore | 11 | ||||
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | LICENSE | 25 | ||||
-rw-r--r-- | README.md | 84 | ||||
-rw-r--r-- | main.c | 154 | ||||
-rw-r--r-- | reloc.h | 47 |
6 files changed, 328 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5a63b1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +reloc + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1c8055f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.11) +project(reloc C) + +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra") + +add_executable(reloc main.c reloc.h) @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2019, Joseph Hunkeler +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..551118b --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# Reloc + +Replace strings in binary executables and data files. + +## System Requirements + +* `gcc` +* `>=cmake-2.18.11` + +## Installing + +```bash +$ git clone https://github.com/jhunkeler/reloc +$ mkdir build +$ cd build +$ cmake -DCMAKE_INSTALL_PREFIX=/some/place .. +$ make install +``` + +## Usage +``` +$ reloc <str1> <str2> <input_file> <output_file> + +Arguments: +str1 - Pattern to search for +str2 - Replace str1 with contents of str2 +input_file - Path to input file +output_file - Path to output file + +Example: +reloc /original/path /new/path input.bin output.bin +``` + +## Showcase + +### Before + +``` +$ xxd -u -g1 test.dat +00000000: DE AD BE EF 2F 5F 30 31 32 33 34 35 36 37 38 39 ..../_0123456789 +00000010: 5F 30 31 32 33 34 35 36 37 38 39 5F 30 31 32 33 _0123456789_0123 +00000020: 34 35 36 37 38 39 5F 30 31 32 33 34 35 36 37 38 456789_012345678 +00000030: 39 5F 30 31 32 33 34 35 36 37 38 39 5F 30 31 32 9_0123456789_012 +00000040: 33 34 35 36 37 38 39 5F 30 31 32 33 34 35 36 37 3456789_01234567 +00000050: 38 39 5F 2F 74 65 73 74 00 52 41 4E 44 4F 4D 20 89_/test.RANDOM +00000060: 44 41 54 41 20 54 48 41 54 20 43 41 4E 4E 4F 54 DATA THAT CANNOT +00000070: 20 42 45 20 4D 4F 56 45 44 00 FE CE FA CE 2F 5F BE MOVED...../_ +00000080: 30 31 32 33 34 35 36 37 38 39 5F 30 31 32 33 34 0123456789_01234 +00000090: 35 36 37 38 39 5F 30 31 32 33 34 35 36 37 38 39 56789_0123456789 +000000a0: 5F 30 31 32 33 34 35 36 37 38 39 5F 30 31 32 33 _0123456789_0123 +000000b0: 34 35 36 37 38 39 5F 30 31 32 33 34 35 36 37 38 456789_012345678 +000000c0: 39 5F 30 31 32 33 34 35 36 37 38 39 5F 2F 73 75 9_0123456789_/su +000000d0: 66 66 69 78 00 FF FF FF FF FF FF FF FF FF ffix.......... +``` + +### During + +```bash +$ reloc \ + /_0123456789_0123456789_0123456789_0123456789_0123456789_0123456789_0123456789_ \ + /tmp/_installed \ + test.dat \ + output.dat +``` + +### After + +``` +xxd -u -g1 output.dat +00000000: DE AD BE EF 2F 74 6D 70 2F 5F 69 6E 73 74 61 6C ..../tmp/_instal +00000010: 6C 65 64 2F 74 65 73 74 00 00 00 00 00 00 00 00 led/test........ +00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00000050: 00 00 00 00 00 00 00 00 00 52 41 4E 44 4F 4D 20 .........RANDOM +00000060: 44 41 54 41 20 54 48 41 54 20 43 41 4E 4E 4F 54 DATA THAT CANNOT +00000070: 20 42 45 20 4D 4F 56 45 44 00 FE CE FA CE 2F 74 BE MOVED...../t +00000080: 6D 70 2F 5F 69 6E 73 74 61 6C 6C 65 64 2F 73 75 mp/_installed/su +00000090: 66 66 69 78 00 00 00 00 00 00 00 00 00 00 00 00 ffix............ +000000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +000000d0: 00 00 00 00 00 FF FF FF FF FF FF FF FF FF .............. +``` @@ -0,0 +1,154 @@ +#include "reloc.h" + + +RelocMatch *reloc_match(char *haystack, const char *needle) { + char *data = haystack; + size_t needle_size = strlen(needle); + RelocMatch *match = NULL; + + // Search the needle in the data + if (!(memcmp(data, needle, needle_size))) { + if (!(match = calloc(1, sizeof(RelocMatch)))) { + fprintf(stderr,"Failed to allocate FindStat structure: %s\n", strerror(errno)); + exit(1); + } + size_t data_end = strlen(data); + match->begin = data; + match->end = match->begin + needle_size; + match->length = match->end - match->begin; + match->post = match->end; + match->post_length = strlen(match->post); + match->total_length = data_end; + } + return match; +} + + +RelocData *reloc_read(const char *filename) { + char *data = NULL; + FILE *fp = NULL; + size_t size = 0; + + // Open file for reading in binary mode + if (!(fp = fopen(filename, "rb"))) { + fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno)); + exit(1); + } + + // Determine file size + fseek(fp, 0, SEEK_END); + size = ftell(fp); + rewind(fp); + + if (!(data = calloc(sizeof(char), size + 1))) { + fprintf(stderr, "Cannot allocate data array: %s\n", strerror(errno)); + exit(1); + } + + // Read data into array + fread(data, sizeof(char), size, fp); + RelocData *result = (RelocData *) malloc(sizeof(RelocData)); + result->size = size; + result->data = data; + result->path = strdup(filename); + return result; +} + + +size_t reloc_write(RelocData *finfo, const char *filename) { + FILE *fp; + + // Open file for writing in binary mode + if (!(fp = fopen(filename, "w+b"))) { + fprintf(stderr,"Cannot open %s for writing: %s\n", filename, strerror(errno)); + exit(1); + } + + // Write data + return fwrite(finfo->data, sizeof(char), finfo->size, fp); +} + + +void reloc_deinit_data(RelocData *finfo) { + if (finfo) { + if (finfo->path) { + free(finfo->path); + } + free(finfo); + } +} + + +void reloc_replace(RelocMatch *match, const char *rstr) { + size_t rstr_length = strlen(rstr); + if (rstr_length > match->length) { + fprintf(stderr, "Replacement value is too long (%lu > %lu)\n", match->length, rstr_length); + return; + } + char *data = match->begin; + size_t i = 0; + + // Overwrite data with replacement string + while (i < rstr_length) { + *data = *rstr; + data++; + rstr++; + i++; + } + + i = 0; + // Append remaining bytes not part of the original match to the replaced string + char *post = match->post; + while (i < match->post_length) { + *data = *post; + data++; + post++; + i++; + } + + // Destroy bytes between the end of the original data and the end of the replaced string + memset(data, '\0', post - data); +} + + +int main(int argc, char *argv[]) { + const char *program = strrchr(argv[0], DIRSEP) + 1; + if (argc < 5) { + printf("%s <str1> <str2> <input_file> <output_file>\n" + "\n" + "Arguments:\n" + "str1 - Pattern to search for\n" + "str2 - Replace str1 with contents of str2\n" + "input_file - Path to input file\n" + "output_file - Path to output file\n" + "\n" + "Example:\n" + "%s /original/path /new/path input.bin output.bin\n" + "\n", program, program); + exit(1); + } + char *needle = argv[1]; + char *replacement = argv[2]; + char *input_file = strdup(argv[3]); + char *output_file = strdup(argv[4]); + RelocData *info = reloc_read(input_file); + size_t records = 0; + + for (size_t i = 0; i < info->size; i++) { + RelocMatch *match = NULL; + if (!(match = reloc_match(&info->data[i], needle))) { + // No match found + continue; + } + // Replace string + reloc_replace(match, replacement); + free(match); + records++; + } + + reloc_write(info, output_file); + printf("%lu\n", records); + + reloc_deinit_data(info); + return 0; +} @@ -0,0 +1,47 @@ +// +// Created by jhunk on 11/7/2019. +// + +#ifndef RELOC_RELOC_H +#define RELOC_RELOC_H + +#define _GNU_SOURCE 1 + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(_WIN32) || defined(_WIN64) +#define DIRSEP '\\' +#elif defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__MACH__) +#define DIRSEP '/' +#endif + + +typedef struct { + size_t size; + char *path; + char *data; +} RelocData; + + +typedef struct { + char *begin; + char *end; + char *post; + size_t length; + size_t post_length; + size_t total_length; +} RelocMatch; + + +RelocMatch *reloc_match(char *haystack, const char *needle); +char *reloc_find_null(char *s); +RelocData *reloc_read(const char *filename); +size_t reloc_write(RelocData *finfo, const char *filename); +void reloc_deinit_data(RelocData *finfo); +void reloc_replace(RelocMatch *match, const char *rstr); + + +#endif //RELOC_RELOC_H |