166 lines
5.3 KiB
C++
Raw Normal View History

2024-02-12 00:44:38 -05:00
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/mman.h>
#include <cstdint>
#include <cerrno>
#include <libreborn/libreborn.h>
#include "patch-internal.h"
// Overwrite Specific B(L) Instruction
2024-07-14 05:06:27 -04:00
static void _overwrite_call_internal(void *start, void *target, const bool use_b_instruction) {
2024-02-12 00:44:38 -05:00
// Add New Target To Code Block
void *code_block = update_code_block(target);
// Patch
uint32_t new_instruction = generate_bl_instruction(start, code_block, use_b_instruction);
2024-07-14 05:06:27 -04:00
patch(start, (unsigned char *) &new_instruction);
2024-02-12 00:44:38 -05:00
// Increment Code Block Position
increment_code_block();
}
2024-07-14 05:06:27 -04:00
void overwrite_call(void *start, void *target) {
const bool use_b_instruction = ((unsigned char *) start)[3] == B_INSTRUCTION;
_overwrite_call_internal(start, target, use_b_instruction);
2024-02-12 00:44:38 -05:00
}
// .rodata Information
#define RODATA_START 0x1020c8
#define RODATA_END 0x11665c
2024-02-12 00:55:50 -05:00
// .data.rel.ro Information
#define DATA_REL_RO_START 0x1352b8
#define DATA_REL_RO_END 0x135638
2024-02-12 00:44:38 -05:00
// Search And Patch VTables Containing Function
2024-02-12 00:55:50 -05:00
#define scan_vtables(section) \
for (uintptr_t i = section##_START; i < section##_END; i = i + 4) { \
uint32_t *addr = (uint32_t *) i; \
if (*addr == (uintptr_t) target) { \
/* Found VTable Entry */ \
2024-07-14 05:06:27 -04:00
patch_address(addr, replacement); \
2024-02-12 00:55:50 -05:00
found++; \
} \
}
2024-07-14 05:06:27 -04:00
static int _patch_vtables(void *target, void *replacement) {
2024-02-12 00:44:38 -05:00
int found = 0;
2024-02-12 00:55:50 -05:00
scan_vtables(RODATA);
scan_vtables(DATA_REL_RO);
2024-02-12 00:44:38 -05:00
return found;
}
2024-02-12 00:55:50 -05:00
#undef scan_vtables
2024-02-12 00:44:38 -05:00
// Patch Calls Within Range
2024-07-14 05:06:27 -04:00
static int _overwrite_calls_within_internal(void *from, void *to, void *target, void *replacement) {
2024-02-12 00:44:38 -05:00
int found = 0;
for (uintptr_t i = (uintptr_t) from; i < (uintptr_t) to; i = i + 4) {
unsigned char *addr = (unsigned char *) i;
2024-07-14 05:06:27 -04:00
const int use_b_instruction = addr[3] == B_INSTRUCTION;
2024-02-12 00:44:38 -05:00
// Check If Instruction is B Or BL
if (addr[3] == BL_INSTRUCTION || use_b_instruction) {
uint32_t check_instruction = generate_bl_instruction(addr, target, use_b_instruction);
unsigned char *check_instruction_array = (unsigned char *) &check_instruction;
// Check If Instruction Calls Target
if (addr[0] == check_instruction_array[0] && addr[1] == check_instruction_array[1] && addr[2] == check_instruction_array[2]) {
// Patch Instruction
uint32_t new_instruction = generate_bl_instruction(addr, replacement, use_b_instruction);
2024-07-14 05:06:27 -04:00
patch(addr, (unsigned char *) &new_instruction);
2024-02-12 00:44:38 -05:00
found++;
}
}
}
return found;
}
// .text Information
#define TEXT_START 0xde60
#define TEXT_END 0x1020c0
// Overwrite All B(L) Intrusctions That Target The Specified Address
2024-07-14 05:06:27 -04:00
#define NO_CALLSITE_ERROR() ERR("Unable To Find Callsites")
void *overwrite_calls_manual(void *start, void *target, const bool allow_no_callsites) {
2024-02-12 00:44:38 -05:00
// Add New Target To Code Block
void *code_block = update_code_block(target);
// Patch Code
2024-07-14 05:06:27 -04:00
int found = _overwrite_calls_within_internal((void *) TEXT_START, (void *) TEXT_END, start, code_block);
2024-02-12 00:44:38 -05:00
// Patch VTables
2024-07-14 05:06:27 -04:00
found += _patch_vtables(start, code_block);
2024-02-12 00:44:38 -05:00
// Increment Code Block Position
increment_code_block();
// Check
2024-07-14 05:06:27 -04:00
if (found < 1 && !allow_no_callsites) {
NO_CALLSITE_ERROR();
2024-02-12 00:44:38 -05:00
}
2024-05-09 17:50:02 -04:00
// Return
return code_block;
2024-02-12 00:44:38 -05:00
}
2024-07-14 05:06:27 -04:00
void overwrite_calls_within_manual(void *from /* inclusive */, void *to /* exclusive */, void *target, void *replacement) {
2024-02-12 00:44:38 -05:00
// Add New Target To Code Block
void *code_block = update_code_block(replacement);
// Patch
2024-07-14 05:06:27 -04:00
const int found = _overwrite_calls_within_internal(from, to, target, code_block);
2024-02-12 00:44:38 -05:00
// Check
if (found < 1) {
2024-07-14 05:06:27 -04:00
NO_CALLSITE_ERROR();
2024-02-12 00:44:38 -05:00
}
// Increment Code Block Position
increment_code_block();
}
// Patch Instruction
static void safe_mprotect(void *addr, size_t len, int prot) {
2024-07-14 05:06:27 -04:00
const long page_size = sysconf(_SC_PAGESIZE);
const long diff = uintptr_t(addr) % page_size;
2024-02-12 00:44:38 -05:00
void *aligned_addr = (void *) (((uintptr_t) addr) - diff);
size_t aligned_len = len + diff;
2024-07-14 05:06:27 -04:00
const int ret = mprotect(aligned_addr, aligned_len, prot);
2024-02-12 00:44:38 -05:00
if (ret == -1) {
ERR("Unable To Set Permissions: %p: %s", addr, strerror(errno));
}
}
2024-07-14 05:06:27 -04:00
void patch(void *start, unsigned char patch[4]) {
2024-02-12 00:44:38 -05:00
if (((uint32_t) start) % 4 != 0) {
ERR("Invalid Address: %p", start);
2024-02-12 00:44:38 -05:00
}
// Get Current Permissions
segment_data &segment_data = get_data_for_addr(start);
int prot = PROT_READ;
if (segment_data.is_executable) {
prot |= PROT_EXEC;
}
if (segment_data.is_writable) {
prot |= PROT_WRITE;
}
// Allow Writing To Code Memory
2024-07-14 05:06:27 -04:00
const uint32_t size = 4;
2024-02-12 00:44:38 -05:00
safe_mprotect(start, size, prot | PROT_WRITE);
// Patch
unsigned char *data = (unsigned char *) start;
memcpy(data, patch, 4);
// Reset Code Memory Permissions
safe_mprotect(start, size, prot);
// Clear ARM Instruction Cache
__clear_cache(start, (void *) (((uintptr_t) start) + size));
}
// Patch Address
2024-07-14 05:06:27 -04:00
void patch_address(void *start, void *target) {
2024-02-12 00:44:38 -05:00
uint32_t addr = (uint32_t) target;
unsigned char *patch_data = (unsigned char *) &addr;
2024-07-14 05:06:27 -04:00
patch(start, patch_data);
2024-02-12 00:44:38 -05:00
}
2024-07-14 05:06:27 -04:00
// Thunks
void *reborn_thunk_enabler(void *target, void *thunk) {
return overwrite_calls_manual(target, thunk, true);
}