minecraft-pi-reborn/libreborn/src/libreborn.c

236 lines
7.9 KiB
C
Raw Normal View History

2020-09-25 16:43:53 +00:00
#include <stdio.h>
#include <stdlib.h>
2020-09-25 16:43:53 +00:00
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdint.h>
#include <elf.h>
2020-11-10 20:06:29 +00:00
#include <errno.h>
2020-09-25 16:43:53 +00:00
2021-01-27 21:26:19 +00:00
#include <libreborn/libreborn.h>
2020-09-25 16:43:53 +00:00
// Find And Iterate Over All .text Sections In Current Binary
typedef void (*text_section_callback)(void *section, Elf32_Word size, void *data);
static void iterate_text_section(text_section_callback callback, void *data) {
// Load Main Binary
char *real_path = realpath("/proc/self/exe", NULL);
FILE *file_obj = fopen(real_path, "rb");
2020-11-22 18:07:10 +00:00
// Verify Binary
if (!file_obj) {
ERR("Unable To Open Binary: %s", real_path);
}
// Get File Size
fseek(file_obj, 0L, SEEK_END);
long int size = ftell(file_obj);
fseek(file_obj, 0L, SEEK_SET);
// Map File To Pointer
unsigned char *file_map = mmap(0, size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0);
// Parse ELF
Elf32_Ehdr *elf_header = (Elf32_Ehdr *) file_map;
Elf32_Shdr *elf_section_headers = (Elf32_Shdr *) (file_map + elf_header->e_shoff);
int elf_section_header_count = elf_header->e_shnum;
// Locate Section Names
Elf32_Shdr elf_strtab = elf_section_headers[elf_header->e_shstrndx];
unsigned char *elf_strtab_p = file_map + elf_strtab.sh_offset;
2020-11-22 18:07:10 +00:00
// Track .text Sections
int text_sections = 0;
// Iterate Sections
for (int i = 0; i < elf_section_header_count; ++i) {
Elf32_Shdr header = elf_section_headers[i];
char *name = (char *) (elf_strtab_p + header.sh_name);
if (strcmp(name, ".text") == 0) {
(*callback)((void *) header.sh_addr, header.sh_size, data);
2020-11-22 18:07:10 +00:00
text_sections++;
}
}
2020-10-01 15:08:46 +00:00
2020-11-22 18:07:10 +00:00
// Ensure At Least .text Section Was Scanned
if (text_sections < 1) {
ERR("Unable To Find .text Sectons On: %s", real_path);
}
// Free Binary Path
free(real_path);
// Unmap And Close File
munmap(file_map, size);
fclose(file_obj);
}
2020-10-01 15:08:46 +00:00
// BL Instruction Magic Number
#define BL_INSTRUCTION 0xeb
2020-09-25 16:43:53 +00:00
// Generate A BL Instruction
static uint32_t generate_bl_instruction(void *from, void *to) {
uint32_t instruction;
unsigned char *instruction_array = (unsigned char *) &instruction;
2020-10-01 15:08:46 +00:00
instruction_array[3] = BL_INSTRUCTION;
2020-10-01 15:08:46 +00:00
unsigned char *pc = ((unsigned char *) from) + 8;
int32_t offset = (int32_t) to - (int32_t) pc;
int32_t target = offset >> 2;
unsigned char *target_array = (unsigned char *) &target;
instruction_array[0] = target_array[0];
instruction_array[1] = target_array[1];
instruction_array[2] = target_array[2];
return instruction;
2020-10-01 15:08:46 +00:00
}
// Run For Every .text Section
struct overwrite_data {
const char *file;
int line;
void *target;
void *replacement;
2020-11-10 20:06:29 +00:00
int found;
};
static void overwrite_calls_callback(void *section, Elf32_Word size, void *data) {
2020-11-10 20:06:29 +00:00
struct overwrite_data *args = (struct overwrite_data *) data;
for (uint32_t i = 0; i < size; i = i + 4) {
unsigned char *addr = ((unsigned char *) section) + i;
if (addr[3] == BL_INSTRUCTION) {
2020-11-10 20:06:29 +00:00
uint32_t check_instruction = generate_bl_instruction(addr, args->target);
unsigned char *check_instruction_array = (unsigned char *) &check_instruction;
if (addr[0] == check_instruction_array[0] && addr[1] == check_instruction_array[1] && addr[2] == check_instruction_array[2]) {
2020-11-10 20:06:29 +00:00
uint32_t new_instruction = generate_bl_instruction(addr, args->replacement);
_patch(args->file, args->line, addr, (unsigned char *) &new_instruction);
args->found++;
}
}
}
}
// Limit To 512 overwrite_calls() Uses
#define CODE_BLOCK_SIZE 4096
static unsigned char *code_block = NULL;
2020-11-10 20:06:29 +00:00
#define CODE_SIZE 8
static int code_block_remaining = CODE_BLOCK_SIZE;
2020-11-20 18:36:03 +00:00
static void update_code_block(void *target) {
// BL Instructions Can Only Access A Limited Portion of Memory, So This Allocates Memory Closer To The Original Instruction, That When Run, Will Jump Into The Actual Target
if (code_block == NULL) {
code_block = mmap((void *) 0x200000, CODE_BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
2020-11-10 20:06:29 +00:00
if (code_block == MAP_FAILED) {
ERR("Unable To Allocate Code Block: %s", strerror(errno));
}
INFO("Code Block Allocated At: 0x%08x", (uint32_t) code_block);
2020-10-03 16:57:58 +00:00
}
2020-11-10 20:06:29 +00:00
if (code_block_remaining < CODE_SIZE) {
ERR("%s", "Maximum Amount Of overwrite_calls() Uses Reached");
}
_overwrite(NULL, -1, code_block, target);
2020-11-20 18:36:03 +00:00
}
2020-11-20 19:29:34 +00:00
static void increment_code_block() {
code_block = code_block + CODE_SIZE;
code_block_remaining = code_block_remaining - CODE_SIZE;
}
2020-11-20 18:36:03 +00:00
// Overwrite Specific BL Instruction
void _overwrite_call(const char *file, int line, void *start, void *target) {
2020-11-20 19:29:34 +00:00
// Add New Target To Code Block
2020-11-20 18:36:03 +00:00
update_code_block(target);
uint32_t new_instruction = generate_bl_instruction(start, code_block);
_patch(file, line, start, (unsigned char *) &new_instruction);
2020-11-20 19:29:34 +00:00
// Increment Code Block Position
increment_code_block();
2020-11-20 18:36:03 +00:00
}
// Overwrite Function Calls
void _overwrite_calls(const char *file, int line, void *start, void *target) {
2020-11-20 19:29:34 +00:00
// Add New Target To Code Block
2020-11-20 18:36:03 +00:00
update_code_block(target);
2020-10-01 15:08:46 +00:00
struct overwrite_data data;
data.file = file;
data.line = line;
data.target = start;
data.replacement = code_block;
2020-11-10 20:06:29 +00:00
data.found = 0;
iterate_text_section(overwrite_calls_callback, &data);
2020-11-20 19:29:34 +00:00
// Increment Code Block Position
increment_code_block();
2020-11-10 20:06:29 +00:00
if (data.found < 1) {
ERR("(%s:%i) Unable To Find Callsites For 0x%08x", file, line, (uint32_t) start);
}
}
2020-10-03 16:57:58 +00:00
// Overwrite Function
void _overwrite(const char *file, int line, void *start, void *target) {
2021-03-05 00:27:24 +00:00
unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"
2020-10-04 20:45:00 +00:00
_patch(file, line, start, patch_data);
_patch_address(file, line, start + 4, target);
2020-09-25 16:43:53 +00:00
}
// Print Patch Debug Data
#define PATCH_PRINTF(file, line, start, str) if (file != NULL) fprintf(stderr, "[PATCH]: (%s:%i) Patching (0x%08x) - "str": 0x%02x 0x%02x 0x%02x 0x%02x\n", file, line, (uint32_t) start, data[0], data[1], data[2], data[3]);
// Patch Instruction
2020-10-04 00:30:15 +00:00
void _patch(const char *file, int line, void *start, unsigned char patch[]) {
2020-10-03 16:57:58 +00:00
size_t page_size = sysconf(_SC_PAGESIZE);
uintptr_t end = ((uintptr_t) start) + 4;
uintptr_t page_start = ((uintptr_t) start) & -page_size;
2021-01-30 05:07:13 +00:00
// Allow Writing To Code Memory
mprotect((void *) page_start, end - page_start, PROT_READ | PROT_WRITE | PROT_EXEC); // PROT_EXEC Is Needed Because Other Code In The Page May Be Being Executed
2020-10-03 16:57:58 +00:00
unsigned char *data = (unsigned char *) start;
PATCH_PRINTF(file, line, start, "original");
2020-09-25 16:43:53 +00:00
memcpy(data, patch, 4);
2020-10-03 16:57:58 +00:00
PATCH_PRINTF(file, line, start, "result");
2021-01-30 05:07:13 +00:00
// Reset Code Memory Permissions
2020-10-03 16:57:58 +00:00
mprotect((void *) page_start, end - page_start, PROT_READ | PROT_EXEC);
2020-10-16 22:23:39 +00:00
2020-10-26 19:58:28 +00:00
// Clear ARM Instruction Cache
2020-10-17 21:18:18 +00:00
__clear_cache(start, (void *) end);
2020-09-25 16:43:53 +00:00
}
2020-10-02 23:28:31 +00:00
// Patch Address
2020-10-04 00:30:15 +00:00
void _patch_address(const char *file, int line, void *start, void *target) {
2020-10-03 00:07:08 +00:00
uint32_t addr = (uint32_t) target;
unsigned char patch_data[4] = {addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, (addr >> 24) & 0xff};
2020-10-03 16:57:58 +00:00
_patch(file, line, start, patch_data);
2020-10-02 23:28:31 +00:00
}
2021-02-22 03:43:57 +00:00
// Sanitize String
#define MINIMUM_SAFE_CHARACTER 32
#define MAXIMUM_SAFE_CHARACTER 126
#define MINIMUM_EXTENDED_SAFE_CHARACTER 128
2021-02-22 03:51:01 +00:00
void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
2021-02-22 03:43:57 +00:00
// Store Message Length
int length = strlen(*str);
// Truncate Message
if (max_length != -1 && length > max_length) {
(*str)[max_length] = '\0';
length = max_length;
}
// Loop Through Message
for (int i = 0; i < length; i++) {
2021-02-22 03:51:01 +00:00
if (allow_newlines && ((*str)[i] == '\n' || (*str)[i] == '\r')) {
continue;
}
if (((*str)[i] < MINIMUM_SAFE_CHARACTER || (*str)[i] > MAXIMUM_SAFE_CHARACTER) && (*str)[i] < MINIMUM_EXTENDED_SAFE_CHARACTER) {
2021-02-22 03:43:57 +00:00
// Replace Illegal Character
(*str)[i] = '?';
}
}
}