Bug Fixes & Low-Level Improvements

This commit is contained in:
TheBrokenRail 2024-02-12 00:44:38 -05:00
parent 180ba9dcaf
commit a2b3bb128b
28 changed files with 378 additions and 288 deletions

View File

@ -87,9 +87,7 @@ jobs:
./out/client/host/usr/bin/minecraft-pi-reborn-client --copy-sdk
# Build Example Mods
- name: Build Example Mods
run: |
cd example-mods
./build.sh
run: ./example-mods/build.sh
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:

View File

@ -21,6 +21,7 @@
* Fix Item Dropping When Killing Players From The Server Console
* Fix Furnace Visual Bug When Using Lava Bucket As Fuel
* Add Splash Text To Start Screen
* `overwrite_calls` Now Scans VTables
**2.5.3**
* Add `Replace Block Highlight With Outline` Feature Flag (Enabled By Default)

View File

@ -3,6 +3,7 @@
set -e
# Create Output Directory
cd "$(dirname "$0")"
ROOT="$(pwd)"
OUT="${ROOT}/out"
rm -rf "${OUT}"

View File

@ -3,6 +3,9 @@
#include <LIEF/ELF.hpp>
#include <dlfcn.h>
#include <link.h>
#include <libreborn/libreborn.h>
#include "patchelf.h"

View File

@ -5,7 +5,7 @@ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn")
configure_file(include/libreborn/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn/config.h" ESCAPE_QUOTES @ONLY)
# Util
add_library(reborn-util SHARED src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c src/util/log.c src/util/cp437.cpp)
add_library(reborn-util SHARED src/util/exec.c src/util/string.c src/util/util.c src/util/log.c src/util/cp437.cpp)
target_include_directories(
reborn-util
PUBLIC
@ -25,7 +25,7 @@ endif()
# Patch
if(BUILD_ARM_COMPONENTS)
add_library(reborn-patch SHARED src/patch/patch.c)
add_library(reborn-patch SHARED src/patch/patch.cpp src/patch/segments.cpp src/patch/code-block.cpp src/patch/instruction.cpp)
target_link_libraries(reborn-patch dl pthread reborn-util)
target_compile_definitions(reborn-patch PUBLIC -DREBORN_HAS_PATCH_CODE)
# Install

View File

@ -1,22 +0,0 @@
#pragma once
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <elf.h>
#include <link.h>
#include "log.h"
#include "exec.h"
#ifdef __cplusplus
extern "C" {
#endif
// Find And Iterate Over All Segments In Current Binary
typedef void (*segment_callback_t)(ElfW(Addr) section, ElfW(Word) size, void *data);
void iterate_segments(segment_callback_t callback, void *data);
#ifdef __cplusplus
}
#endif

View File

@ -5,6 +5,5 @@
#include "util.h"
#include "string.h"
#include "exec.h"
#include "elf.h"
#include "home.h"
#include "patch.h"

View File

@ -8,6 +8,8 @@ extern "C" {
#ifdef REBORN_HAS_PATCH_CODE
void reborn_init_patch();
void _overwrite_call(const char *file, int line, void *start, void *target);
#define overwrite_call(start, target) _overwrite_call(__FILE__, __LINE__, start, target);

View File

@ -0,0 +1,46 @@
#include <sys/mman.h>
#include <libreborn/libreborn.h>
#include "patch-internal.h"
// Limit To 512 overwrite_calls() Uses
#define CODE_BLOCK_SIZE 4096
static unsigned char *code_block = NULL;
#define CODE_SIZE 8
static int code_block_remaining = CODE_BLOCK_SIZE;
// Create Long Overwrite At Current Position
static void long_overwrite(void *start, void *target) {
unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"
_patch(NULL, -1, start, patch_data);
_patch_address(NULL, -1, (void *) (((unsigned char *) start) + 4), target);
}
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 = (unsigned char *) mmap((void *) 0x200000, CODE_BLOCK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (code_block == MAP_FAILED) {
ERR("Unable To Allocate Code Block: %s", strerror(errno));
}
DEBUG("Code Block Allocated At: 0x%08x", (uint32_t) code_block);
// Store Segment
segment_data data;
data.start = code_block;
data.end = (void *) (((uintptr_t) code_block) + CODE_BLOCK_SIZE);
data.is_executable = true;
data.is_writable = true;
add_segment(data);
}
if (code_block_remaining < CODE_SIZE) {
ERR("Maximum Amount Of overwrite_calls() Uses Reached");
}
long_overwrite(code_block, target);
// Return
return code_block;
}
void increment_code_block() {
code_block = code_block + CODE_SIZE;
code_block_remaining = code_block_remaining - CODE_SIZE;
}

View File

@ -0,0 +1,50 @@
#include <libreborn/libreborn.h>
#include "patch-internal.h"
// Generate A BL Instruction
#define INSTRUCTION_RANGE 32000000
static uint64_t nice_diff_64(uint64_t a, uint64_t b) {
if (a > b) {
return a - b;
} else {
return b - a;
}
}
uint32_t generate_bl_instruction(void *from, void *to, int use_b_instruction) {
// Check Instruction Range
if (nice_diff_64((uint64_t) to, (uint64_t) from) > INSTRUCTION_RANGE) {
IMPOSSIBLE();
}
// Create New Instruction
uint32_t instruction;
unsigned char *instruction_array = (unsigned char *) &instruction;
instruction_array[3] = use_b_instruction ? B_INSTRUCTION : BL_INSTRUCTION;
// Determine PC
unsigned char *pc = ((unsigned char *) from) + 8;
int32_t offset = (int32_t) to - (int32_t) pc;
int32_t target = offset >> 2;
// Set Instruction Offset
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
return instruction;
}
// Extract Target Address From B(L) Instruction
void *extract_from_bl_instruction(unsigned char *from) {
// Calculate PC
unsigned char *pc = ((unsigned char *) from) + 8;
// Extract Offset From Instruction
int32_t target = *(int32_t *) from;
target = (target << 8) >> 8;
int32_t offset = target << 2;
// Add PC To Offset
return (void *) (pc + offset);
}

View File

@ -0,0 +1,26 @@
#pragma once
#ifndef __arm__
#error "Patching Code Is ARM Only"
#endif
#include <cstdint>
// Segments
struct segment_data {
void *start;
void *end;
bool is_executable;
bool is_writable;
};
__attribute__((visibility("internal"))) segment_data &get_data_for_addr(void *addr);
__attribute__((visibility("internal"))) void add_segment(segment_data data);
// Code Block
__attribute__((visibility("internal"))) void *update_code_block(void *target);
__attribute__((visibility("internal"))) void increment_code_block();
// BL Instruction Magic Number
#define BL_INSTRUCTION 0xeb
#define B_INSTRUCTION 0xea
__attribute__((visibility("internal"))) uint32_t generate_bl_instruction(void *from, void *to, int use_b_instruction);

View File

@ -1,214 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdint.h>
#include <errno.h>
#include <libreborn/libreborn.h>
#ifndef __arm__
#error "Patching Code Is ARM Only"
#endif
// BL Instruction Magic Number
#define BL_INSTRUCTION 0xeb
#define B_INSTRUCTION 0xea
// Generate A BL Instruction
static uint32_t generate_bl_instruction(void *from, void *to, int use_b_instruction) {
if (abs(((int32_t) to) - ((int32_t) from)) > 32000000) {
IMPOSSIBLE();
}
uint32_t instruction;
unsigned char *instruction_array = (unsigned char *) &instruction;
instruction_array[3] = use_b_instruction ? B_INSTRUCTION : BL_INSTRUCTION;
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;
}
// Run For Every .text Section
static int _overwrite_calls_within_internal(const char *file, int line, void *from, void *to, void *target, void *replacement) {
int found = 0;
for (uint32_t i = (uint32_t) from; i < (uint32_t) to; i = i + 4) {
unsigned char *addr = (unsigned char *) i;
int use_b_instruction = addr[3] == B_INSTRUCTION;
// 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);
_patch(file, line, addr, (unsigned char *) &new_instruction);
found++;
}
}
}
return found;
}
struct overwrite_data {
const char *file;
int line;
void *target;
void *replacement;
int found;
};
static void overwrite_calls_callback(ElfW(Addr) section_addr, ElfW(Word) size, void *data) {
struct overwrite_data *args = (struct overwrite_data *) data;
void *section = (void *) section_addr;
args->found += _overwrite_calls_within_internal(args->file, args->line, section, (void *) (section_addr + size), args->target, args->replacement);
}
// Limit To 512 overwrite_calls() Uses
#define CODE_BLOCK_SIZE 4096
static unsigned char *code_block = NULL;
#define CODE_SIZE 8
static int code_block_remaining = CODE_BLOCK_SIZE;
static void _long_overwrite(void *start, void *target) {
unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"
_patch(NULL, -1, start, patch_data);
_patch_address(NULL, -1, (void *) (((unsigned char *) start) + 4), target);
}
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);
if (code_block == MAP_FAILED) {
ERR("Unable To Allocate Code Block: %s", strerror(errno));
}
DEBUG("Code Block Allocated At: 0x%08x", (uint32_t) code_block);
}
if (code_block_remaining < CODE_SIZE) {
ERR("Maximum Amount Of overwrite_calls() Uses Reached");
}
_long_overwrite(code_block, target);
}
static void increment_code_block() {
code_block = code_block + CODE_SIZE;
code_block_remaining = code_block_remaining - CODE_SIZE;
}
// Overwrite Specific B(L) Instruction
static void _overwrite_call_internal(const char *file, int line, void *start, void *target, int use_b_instruction) {
// Add New Target To Code Block
update_code_block(target);
// Patch
uint32_t new_instruction = generate_bl_instruction(start, code_block, use_b_instruction);
_patch(file, line, start, (unsigned char *) &new_instruction);
// Increment Code Block Position
increment_code_block();
}
void _overwrite_call(const char *file, int line, void *start, void *target) {
int use_b_instruction = ((unsigned char *) start)[3] == B_INSTRUCTION;
_overwrite_call_internal(file, line, start, target, use_b_instruction);
}
// Overwrite All B(L) Intrusctions That Target The Specified Address
#define NO_CALLSITE_ERROR "(%s:%i) Unable To Find Callsites For 0x%08x"
void _overwrite_calls(const char *file, int line, void *start, void *target) {
// Add New Target To Code Block
update_code_block(target);
struct overwrite_data data;
data.file = file;
data.line = line;
data.target = start;
data.replacement = code_block;
data.found = 0;
iterate_segments(overwrite_calls_callback, &data);
// Increment Code Block Position
increment_code_block();
// Check
if (data.found < 1) {
ERR(NO_CALLSITE_ERROR, file, line, (uint32_t) start);
}
}
void _overwrite_calls_within(const char *file, int line, void *from /* inclusive */, void *to /* exclusive */, void *target, void *replacement) {
// Add New Target To Code Block
update_code_block(replacement);
// Patch
int found = _overwrite_calls_within_internal(file, line, from, to, target, code_block);
// Check
if (found < 1) {
ERR(NO_CALLSITE_ERROR, file, line, (uint32_t) target);
}
// Increment Code Block Position
increment_code_block();
}
// Extract Target Address From B(L) Instruction
void *extract_from_bl_instruction(unsigned char *from) {
unsigned char *pc = ((unsigned char *) from) + 8;
int32_t target = *(int32_t *) from;
target = (target << 8) >> 8;
int32_t offset = target << 2;
return (void *) (pc + offset);
}
// Overwrite Function
void _overwrite(const char *file, int line, void *start, void *target) {
_overwrite_call_internal(file, line, start, target, 1);
}
// Print Patch Debug Data
#define PATCH_PRINTF(file, line, start, str) if (file != NULL) DEBUG("(%s:%i): Patching (0x%08x) - " str ": 0x%02x 0x%02x 0x%02x 0x%02x", file, line, (uint32_t) start, data[0], data[1], data[2], data[3]);
// Patch Instruction
void _patch(const char *file, int line, void *start, unsigned char patch[4]) {
if (((uint32_t) start) % 4 != 0) {
ERR("Invalid Address");
}
size_t page_size = sysconf(_SC_PAGESIZE);
uintptr_t end = ((uintptr_t) start) + 4;
uintptr_t page_start = ((uintptr_t) start) & -page_size;
// 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
unsigned char *data = (unsigned char *) start;
PATCH_PRINTF(file, line, start, "original");
memcpy(data, patch, 4);
PATCH_PRINTF(file, line, start, "result");
// Reset Code Memory Permissions
mprotect((void *) page_start, end - page_start, PROT_READ | PROT_EXEC);
// Clear ARM Instruction Cache
__clear_cache(start, (void *) end);
}
// Patch Address
void _patch_address(const char *file, int line, void *start, void *target) {
uint32_t addr = (uint32_t) target;
unsigned char *patch_data = (unsigned char *) &addr;
_patch(file, line, start, patch_data);
}

View File

@ -0,0 +1,163 @@
#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
static void _overwrite_call_internal(const char *file, int line, void *start, void *target, int use_b_instruction) {
// 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);
_patch(file, line, start, (unsigned char *) &new_instruction);
// Increment Code Block Position
increment_code_block();
}
void _overwrite_call(const char *file, int line, void *start, void *target) {
int use_b_instruction = ((unsigned char *) start)[3] == B_INSTRUCTION;
_overwrite_call_internal(file, line, start, target, use_b_instruction);
}
// .rodata Information
#define RODATA_START 0x1020c8
#define RODATA_END 0x11665c
// Search And Patch VTables Containing Function
static int _patch_vtables(const char *file, int line, void *target, void *replacement) {
int found = 0;
for (uintptr_t i = RODATA_START; i < RODATA_END; i = i + 4) {
uint32_t *addr = (uint32_t *) i;
if (*addr == (uintptr_t) target) {
// Found VTable Entry
_patch_address(file, line, addr, replacement);
found++;
}
}
return found;
}
// Patch Calls Within Range
static int _overwrite_calls_within_internal(const char *file, int line, void *from, void *to, void *target, void *replacement) {
int found = 0;
for (uintptr_t i = (uintptr_t) from; i < (uintptr_t) to; i = i + 4) {
unsigned char *addr = (unsigned char *) i;
int use_b_instruction = addr[3] == B_INSTRUCTION;
// 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);
_patch(file, line, addr, (unsigned char *) &new_instruction);
found++;
}
}
}
return found;
}
// .text Information
#define TEXT_START 0xde60
#define TEXT_END 0x1020c0
// Overwrite All B(L) Intrusctions That Target The Specified Address
#define NO_CALLSITE_ERROR "(%s:%i) Unable To Find Callsites For %p"
void _overwrite_calls(const char *file, int line, void *start, void *target) {
// Add New Target To Code Block
void *code_block = update_code_block(target);
// Patch Code
int found = _overwrite_calls_within_internal(file, line, (void *) TEXT_START, (void *) TEXT_END, start, code_block);
// Patch VTables
found += _patch_vtables(file, line, start, code_block);
// Increment Code Block Position
increment_code_block();
// Check
if (found < 1) {
ERR(NO_CALLSITE_ERROR, file, line, start);
}
}
void _overwrite_calls_within(const char *file, int line, void *from /* inclusive */, void *to /* exclusive */, void *target, void *replacement) {
// Add New Target To Code Block
void *code_block = update_code_block(replacement);
// Patch
int found = _overwrite_calls_within_internal(file, line, from, to, target, code_block);
// Check
if (found < 1) {
ERR(NO_CALLSITE_ERROR, file, line, target);
}
// Increment Code Block Position
increment_code_block();
}
// Overwrite Function
void _overwrite(const char *file, int line, void *start, void *target) {
// Replace the function's start with a call
// to the replacement function.
_overwrite_call_internal(file, line, start, target, 1);
}
// Print Patch Debug Data
#define PATCH_PRINTF(file, line, start, str) if (file != NULL) DEBUG("(%s:%i): Patching (%p) - " str ": %02x %02x %02x %02x", file, line, start, data[0], data[1], data[2], data[3]);
// Patch Instruction
static void safe_mprotect(void *addr, size_t len, int prot) {
long page_size = sysconf(_SC_PAGESIZE);
long diff = ((uintptr_t) addr) % page_size;
void *aligned_addr = (void *) (((uintptr_t) addr) - diff);
size_t aligned_len = len + diff;
int ret = mprotect(aligned_addr, aligned_len, prot);
if (ret == -1) {
ERR("Unable To Set Permissions: %p: %s", addr, strerror(errno));
}
}
void _patch(const char *file, int line, void *start, unsigned char patch[4]) {
if (((uint32_t) start) % 4 != 0) {
ERR("Invalid Address");
}
// 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
uint32_t size = 4;
safe_mprotect(start, size, prot | PROT_WRITE);
// Patch
unsigned char *data = (unsigned char *) start;
PATCH_PRINTF(file, line, start, "original");
memcpy(data, patch, 4);
PATCH_PRINTF(file, line, start, "result");
// Reset Code Memory Permissions
safe_mprotect(start, size, prot);
// Clear ARM Instruction Cache
__clear_cache(start, (void *) (((uintptr_t) start) + size));
}
// Patch Address
void _patch_address(const char *file, int line, void *start, void *target) {
uint32_t addr = (uint32_t) target;
unsigned char *patch_data = (unsigned char *) &addr;
_patch(file, line, start, patch_data);
}

View File

@ -0,0 +1,50 @@
#include <vector>
#include <elf.h>
#include <dlfcn.h>
#include <link.h>
#include <libreborn/libreborn.h>
#include "patch-internal.h"
// Track Segments
static std::vector<segment_data> &get_segments() {
static std::vector<segment_data> data;
return data;
}
// Functions
segment_data &get_data_for_addr(void *addr) {
for (segment_data &data : get_segments()) {
if (addr >= data.start && addr < data.end) {
return data;
}
}
ERR("Address Not Part Of Main Program: %p", addr);
}
void add_segment(segment_data data) {
get_segments().push_back(data);
}
// Init
void reborn_init_patch() {
dl_iterate_phdr([](struct dl_phdr_info *info, __attribute__((unused)) size_t size, __attribute__((unused)) void *user_data) {
// Only Search Current Program
if (strcmp(info->dlpi_name, "") == 0) {
for (int i = 0; i < info->dlpi_phnum; i++) {
// Only Loaded Segemnts
if (info->dlpi_phdr[i].p_type == PT_LOAD) {
// Store
segment_data data;
data.start = (void *) (info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
data.end = (void *) (((uintptr_t) data.start) + info->dlpi_phdr[i].p_memsz);
data.is_executable = info->dlpi_phdr[i].p_flags & PF_X;
data.is_writable = info->dlpi_phdr[i].p_flags & PF_W;
add_segment(data);
}
}
}
// Return
return 0;
}, nullptr);
}

View File

@ -1,28 +0,0 @@
#include <libreborn/elf.h>
// Find And Iterate Over All Segments In Current Binary
typedef struct {
segment_callback_t callback;
void *data;
} dl_iterate_callback_data;
static int dl_iterate_callback(struct dl_phdr_info *info, __attribute__((unused)) size_t size, void *data) {
dl_iterate_callback_data *callback_data = (dl_iterate_callback_data *) data;
// Only Search Current Program
if (strcmp(info->dlpi_name, "") == 0) {
for (int i = 0; i < info->dlpi_phnum; i++) {
// Only Executable Segemnts
if (info->dlpi_phdr[i].p_type == PT_LOAD && (info->dlpi_phdr[i].p_flags & PF_X) != 0) {
// Callback
(*callback_data->callback)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_memsz, callback_data->data);
}
}
}
return 0;
}
void iterate_segments(segment_callback_t callback, void *data) {
dl_iterate_callback_data callback_data = {
.callback = callback,
.data = data
};
dl_iterate_phdr(dl_iterate_callback, (void *) &callback_data);
}

View File

@ -1,4 +1,5 @@
#include <libreborn/libreborn.h>
#include "compat-internal.h"
// Do Nothing Function
static void do_nothing() {
@ -6,7 +7,7 @@ static void do_nothing() {
}
// Patch bcm_host Calls
__attribute__((constructor)) static void patch_bcm_host_calls() {
void _patch_bcm_host_calls() {
// Disable bcm_host Calls
overwrite_call((void *) 0xdfec, (void *) do_nothing); // bcm_host_init
overwrite_call((void *) 0x12418, (void *) do_nothing); // bcm_host_deinit

View File

@ -0,0 +1,5 @@
#pragma once
__attribute__((visibility("internal"))) void _patch_egl_calls();
__attribute__((visibility("internal"))) void _patch_x11_calls();
__attribute__((visibility("internal"))) void _patch_bcm_host_calls();

View File

@ -5,6 +5,7 @@
#include <mods/compat/compat.h>
#include <mods/screenshot/screenshot.h>
#include <mods/init/init.h>
#include "compat-internal.h"
#include <libreborn/libreborn.h>
@ -120,6 +121,10 @@ void init_compat() {
act_sigterm.sa_flags = SA_RESTART;
act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL);
// Patches
_patch_egl_calls();
_patch_x11_calls();
_patch_bcm_host_calls();
}
// Store Exit Requests

View File

@ -2,6 +2,7 @@
#include <libreborn/libreborn.h>
#include <media-layer/core.h>
#include "compat-internal.h"
// Functions That Have Their Return Values Used
static EGLSurface eglCreateWindowSurface_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) NativeWindowType native_window, __attribute__((unused)) EGLint const *attrib_list) {
@ -20,7 +21,7 @@ static EGLBoolean eglSwapBuffers_injection(__attribute__((unused)) EGLDisplay di
}
// Patch EGL Calls
__attribute__((constructor)) static void patch_egl_calls() {
void _patch_egl_calls() {
// Disable EGL Calls
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x1250c, nop_patch); // eglTerminate

View File

@ -2,6 +2,7 @@
#include <libreborn/libreborn.h>
#include <media-layer/core.h>
#include "compat-internal.h"
// Functions That Have Their Return Values Used
static int XTranslateCoordinates_injection(__attribute__((unused)) void *display, __attribute__((unused)) XID src_w, __attribute__((unused)) XID dest_w, int src_x, int src_y, int *dest_x_return, int *dest_y_return, __attribute__((unused)) XID *child_return) {
@ -21,7 +22,7 @@ static int XGetWindowAttributes_injection(__attribute__((unused)) void *display,
}
// Patch X11 Calls
__attribute__((constructor)) static void patch_x11_calls() {
void _patch_x11_calls() {
// Disable X11 Calls
overwrite_call((void *) 0x132a4, (void *) XGetWindowAttributes_injection); // XGetWindowAttributes
overwrite_call((void *) 0x132d4, (void *) XTranslateCoordinates_injection); // XTranslateCoordinates

View File

@ -130,13 +130,13 @@ void init_death() {
patch_address(LocalPlayer_die_vtable_addr, (void *) LocalPlayer_die_injection);
patch_address(ServerPlayer_actuallyHurt_vtable_addr, (void *) ServerPlayer_actuallyHurt_injection);
patch_address(LocalPlayer_actuallyHurt_vtable_addr, (void *) LocalPlayer_actuallyHurt_injection);
patch_address(Mob_hurt_vtable_addr, (void *) Mob_hurt_injection);
overwrite_calls((void *) Mob_hurt_non_virtual, (void *) Mob_hurt_injection);
}
// Fix TNT
// This changes PrimedTnt_explode from Level_explode(NULL, x, y, z, 3.1f) to Level_explode(this, x, y, z, 3.1f)
unsigned char cpy_r1_r0_patch[4] = {0x00, 0x10, 0xa0, 0xe1}; // "cpy r1,r0"
// This changes PrimedTnt_explode from Level::explode(NULL, x, y, z, 3.1f) to Level::explode(this, x, y, z, 3.1f)
unsigned char cpy_r1_r0_patch[4] = {0x00, 0x10, 0xa0, 0xe1}; // "cpy r1, r0"
patch((void *) 0x87998, cpy_r1_r0_patch);
unsigned char ldr_r0_24_patch[4] = {0x24, 0x00, 0x90, 0xe5}; // "ldr r0,[r0,#0x24]"
unsigned char ldr_r0_24_patch[4] = {0x24, 0x00, 0x90, 0xe5}; // "ldr r0, [r0, #0x24]"
patch((void *) 0x8799c, ldr_r0_24_patch);
}

View File

@ -5,6 +5,7 @@
__attribute__((constructor)) static void init(int argc, char *argv[]) {
media_ensure_loaded();
reborn_init_patch();
run_tests();
init_symbols();
init_version();

View File

@ -799,7 +799,6 @@ void init_misc() {
// Animation
overwrite_calls((void *) ContainerMenu_constructor, (void *) ContainerMenu_injection);
overwrite_calls((void *) ContainerMenu_destructor_complete_non_virtual, (void *) ContainerMenu_destructor_injection);
patch_address(ContainerMenu_destructor_complete_vtable_addr, (void *) ContainerMenu_destructor_injection);
}
patch_address((void *) 0x115b48, (void *) ChestTileEntity_shouldSave_injection);

View File

@ -215,9 +215,7 @@ void _init_options_cpp() {
// Replace "feedback_vibration" Loading/Saving With "gfx_ao"
{
// Replace String
static const char *new_feedback_vibration_options_txt_name = "gfx_ao";
patch_address((void *) Strings_feedback_vibration_options_txt_name_1_pointer, (void *) &new_feedback_vibration_options_txt_name);
patch_address((void *) Strings_feedback_vibration_options_txt_name_2_pointer, (void *) &new_feedback_vibration_options_txt_name);
patch_address((void *) Strings_feedback_vibration_options_txt_name_pointer, (void *) "gfx_ao");
// Loading
unsigned char offset = (unsigned char) offsetof(Options, ambient_occlusion);
unsigned char gfx_ao_loading_patch[4] = {offset, 0x10, 0x84, 0xe2}; // "add r1, r4, #OFFSET"
@ -230,8 +228,7 @@ void _init_options_cpp() {
// Replace "gfx_lowquality" Loading With "gfx_anaglyph"
{
// Replace String
static const char *new_gfx_lowquality_options_txt_name = "gfx_anaglyph";
patch_address((void *) Strings_gfx_lowquality_options_txt_name_pointer, (void *) &new_gfx_lowquality_options_txt_name);
patch_address((void *) Strings_gfx_lowquality_options_txt_name_pointer, (void *) "gfx_anaglyph");
// Loading
unsigned char offset = (unsigned char) offsetof(Options, anaglyph_3d);
unsigned char gfx_anaglyph_loading_patch[4] = {offset, 0x10, 0x84, 0xe2}; // "add r1, r4, #OFFSET"

View File

@ -433,7 +433,7 @@ static bool is_ip_in_blacklist(const char *ip) {
}
// Ban Players
static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) unsigned char *rakpeer, const char *ip) {
static bool RakNet_RakPeer_IsBanned_injection(__attribute__((unused)) RakNet_RakPeer *rakpeer, const char *ip) {
// Check List
bool ret = is_ip_in_blacklist(ip);
if (is_whitelist()) {
@ -576,7 +576,7 @@ static void server_init() {
unsigned char max_players_patch[4] = {get_max_players(), 0x30, 0xa0, 0xe3}; // "mov r3, #MAX_PLAYERS"
patch((void *) 0x166d0, max_players_patch);
// Custom Banned IP List
overwrite((void *) RakNet_RakPeer_IsBanned_non_virtual, (void *) RakNet_RakPeer_IsBanned_injection);
patch_address(RakNet_RakPeer_IsBanned_vtable_addr, (void *) RakNet_RakPeer_IsBanned_injection);
// Show The MineCon Icon Next To MOTD In Server List
if (get_server_properties().get_bool("show-minecon-badge", DEFAULT_SHOW_MINECON_BADGE)) {

View File

@ -2,5 +2,8 @@
set -e
# Change Directory
cd "$(dirname "$0")/../"
# Run
act push -W '.gitea/workflows/build.yml'

View File

@ -2,6 +2,9 @@
set -e
# Change Directory
cd "$(dirname "$0")/../"
# Variables
MODE="$(echo "$1" | tr '[:upper:]' '[:lower:]')"
ARCH='host'

View File

@ -4,9 +4,8 @@ static-property char *default_username = 0x18fd4; // StevePi
static-property char *minecraft_pi_version = 0x39d94; // v0.1.1 alpha
static-property char *options_txt_path = 0x19bc8; // options.txt
static-property char *options_txt_fopen_mode_when_loading = 0x19d24; // w
static-property char **feedback_vibration_options_txt_name_1 = 0x198a0; // feedback_vibration
static-property char **feedback_vibration_options_txt_name_2 = 0x194bc; // feedback_vibration
static-property char **gfx_lowquality_options_txt_name = 0x194c4; // gfx_lowquality
static-property char *feedback_vibration_options_txt_name = 0x135d70; // feedback_vibration
static-property char *gfx_lowquality_options_txt_name = 0x135d88; // gfx_lowquality
static-property char *classic_create_button_text = 0x39bec; // Create
static-property-array char creative_mode_description = 0x104492; // Unlimited resources and flying
static-property-array char survival_mode_description = 0x104470; // Mobs, health and gather resources