Replace PatcheLF With LIEF

This commit is contained in:
TheBrokenRail 2022-09-25 15:47:36 -04:00
parent eb3c5d2e6f
commit bedd5ea53a
17 changed files with 157 additions and 294 deletions

6
.gitmodules vendored
View File

@ -11,6 +11,6 @@
[submodule "dependencies/zenity/src"] [submodule "dependencies/zenity/src"]
path = dependencies/zenity/src path = dependencies/zenity/src
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/zenity.git url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/zenity.git
[submodule "launcher/dependencies/patchelf/src"] [submodule "dependencies/LIEF/src"]
path = launcher/dependencies/patchelf/src path = dependencies/LIEF/src
url = https://github.com/NixOS/patchelf.git url = https://github.com/lief-project/LIEF.git

View File

@ -117,6 +117,7 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(DEFAULT_PREFIX "/") set(DEFAULT_PREFIX "/")
endif() endif()
set(CMAKE_INSTALL_PREFIX "${DEFAULT_PREFIX}" CACHE PATH "" FORCE) set(CMAKE_INSTALL_PREFIX "${DEFAULT_PREFIX}" CACHE PATH "" FORCE)
set(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT FALSE)
endif() endif()
# Required Compile Flags # Required Compile Flags

View File

@ -12,3 +12,7 @@ endif()
if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_SERVER_MODE) if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_SERVER_MODE)
add_subdirectory(zenity) add_subdirectory(zenity)
endif() endif()
# LIEF
if(BUILD_NATIVE_COMPONENTS OR (BUILD_ARM_COMPONENTS AND NOT MCPI_SERVER_MODE AND NOT MCPI_USE_MEDIA_LAYER_PROXY))
add_subdirectory(LIEF)
endif()

39
dependencies/LIEF/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,39 @@
project(LIEF)
# Silence Warnings
add_compile_options(-w -Wno-psabi)
## LIEF
# Options
set(BUILD_SHARED_LIBS TRUE CACHE BOOL "" FORCE)
set(LIEF_C_API FALSE CACHE BOOL "" FORCE)
set(LIEF_EXAMPLES FALSE CACHE BOOL "" FORCE)
set(LIEF_PYTHON_API FALSE CACHE BOOL "" FORCE)
set(LIEF_TESTS FALSE CACHE BOOL "" FORCE)
set(LIEF_USE_CCACHE FALSE CACHE BOOL "" FORCE)
set(LIEF_LOGGING FALSE CACHE BOOL "" FORCE)
set(LIEF_LOGGING_DEBUG FALSE CACHE BOOL "" FORCE)
set(LIEF_ENABLE_JSON FALSE CACHE BOOL "" FORCE)
set(LIEF_ELF TRUE CACHE BOOL "" FORCE)
set(LIEF_PE FALSE CACHE BOOL "" FORCE)
set(LIEF_MACHO FALSE CACHE BOOL "" FORCE)
set(LIEF_DEX FALSE CACHE BOOL "" FORCE)
set(LIEF_ART FALSE CACHE BOOL "" FORCE)
set(LIEF_OAT FALSE CACHE BOOL "" FORCE)
set(LIEF_VDEX FALSE CACHE BOOL "" FORCE)
# Download
add_subdirectory(src EXCLUDE_FROM_ALL)
# Ensure Build
add_custom_target(LIEF-build ALL DEPENDS LIB_LIEF)
# Install
install(TARGETS LIB_LIEF DESTINATION "${MCPI_LIB_DIR}")
if(BUILD_ARM_COMPONENTS)
install(TARGETS LIB_LIEF EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()
# License
install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/LIEF")

1
dependencies/LIEF/src vendored Submodule

@ -0,0 +1 @@
Subproject commit c7b3ce3b2ce6917855a72709f73ef6d00b50e1f7

View File

@ -1,17 +1,14 @@
project(launcher) project(launcher)
# Dependencies
add_subdirectory(dependencies)
# Launcher # Launcher
add_executable(launcher src/bootstrap.c src/patchelf.c src/crash-report.c) add_executable(launcher src/bootstrap.c src/patchelf.cpp src/crash-report.c)
if(MCPI_SERVER_MODE) if(MCPI_SERVER_MODE)
target_sources(launcher PRIVATE src/server/launcher.c) target_sources(launcher PRIVATE src/server/launcher.c)
else() else()
embed_resource(launcher src/client/available-feature-flags) embed_resource(launcher src/client/available-feature-flags)
target_sources(launcher PRIVATE src/client/launcher.cpp src/client/cache.cpp) target_sources(launcher PRIVATE src/client/launcher.cpp src/client/cache.cpp)
endif() endif()
target_link_libraries(launcher reborn-util) target_link_libraries(launcher reborn-util LIB_LIEF)
# RPath # RPath
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native") set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native")

View File

@ -1,4 +0,0 @@
project(launcher-dependencies)
# PatchELF
add_subdirectory(patchelf)

View File

@ -1,17 +0,0 @@
project(patchelf)
# Silence Warnings
add_compile_options(-w)
## PatchELF
# Build
add_executable(patchelf src/src/patchelf.cc)
target_compile_definitions(patchelf PRIVATE -D_FILE_OFFSET_BITS=64)
set_target_properties(patchelf PROPERTIES CXX_STANDARD 17)
# Install
install(TARGETS patchelf DESTINATION "${MCPI_BIN_DIR}")
# License
install(FILES src/COPYING DESTINATION "${MCPI_LEGAL_DIR}/patchelf")

@ -1 +0,0 @@
Subproject commit c2b419dc2a0d6095eaa69b65ad5854ce847bdd01

View File

@ -272,10 +272,7 @@ void bootstrap(int argc, char *argv[]) {
safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory); safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory);
#else #else
// Use Current Linker // Use Current Linker
char *exe = realpath("/proc/self/exe", NULL); linker = patch_get_interpreter();
ALLOC_CHECK(exe);
linker = patch_get_interpreter(exe);
free(exe);
#endif #endif
// Patch // Patch

View File

@ -1,136 +0,0 @@
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <libreborn/libreborn.h>
#include "bootstrap.h"
#include "patchelf.h"
// Duplicate MCPI Executable Into /tmp
static void duplicate_mcpi_executable(const char *original_path, char *new_path) {
// Ensure Temporary Directory
{
// Check If It Exists
struct stat tmp_stat;
int exists = stat(MCPI_PATCHED_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode);
if (!exists) {
// Doesn't Exist
if (mkdir(MCPI_PATCHED_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
ERR("Unable To Create Temporary Folder: %s", strerror(errno));
}
}
}
// Generate New File
int new_file_fd = mkstemp(new_path);
if (new_file_fd == -1) {
ERR("Unable To Create Temporary File: %s", strerror(errno));
}
FILE *new_file = fdopen(new_file_fd, "wb");
if (new_file == NULL) {
ERR("Unable To Open Temporary File: %s", strerror(errno));
}
// Copy Original File
{
// Open Original File
FILE *original_file = fopen(original_path, "rb");
if (original_file == NULL) {
ERR("Unable To Open File: %s", original_path);
}
// Copy
#define BUFFER_SIZE 1024
char buf[BUFFER_SIZE];
size_t bytes_read = 0;
while ((bytes_read = fread((void *) buf, 1, BUFFER_SIZE, original_file)) > 0) {
fwrite((void *) buf, 1, bytes_read, new_file);
if (ferror(new_file) != 0) {
ERR("Unable To Write File: %s", new_path);
}
}
if (ferror(original_file) != 0) {
ERR("Unable To Read File: %s", original_path);
}
// Close Original File
fclose(original_file);
}
// Close New File
fclose(new_file);
close(new_file_fd);
}
// Fix MCPI Dependencies
#define patch_mcpi_elf_dependencies_with_extra_patchelf_args(...) \
({ \
const char *const _macro_command[] = { \
"patchelf", \
##__VA_ARGS__, \
"--remove-needed", "libbcm_host.so", \
"--remove-needed", "libX11.so.6", \
"--remove-needed", "libEGL.so", \
"--remove-needed", "libGLESv2.so", \
"--remove-needed", "libSDL-1.2.so.0", \
"--add-needed", "libmedia-layer-core.so", \
new_path, \
NULL \
}; \
int _macro_return_code = 0; \
char *_macro_output = run_command(_macro_command, &_macro_return_code); \
if (_macro_output != NULL) { \
free(_macro_output); \
} \
_macro_return_code; \
})
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker) {
// Duplicate MCPI executable into /tmp so it can be modified.
duplicate_mcpi_executable(original_path, new_path);
// Run patchelf
int return_code;
if (linker == NULL) {
return_code = patch_mcpi_elf_dependencies_with_extra_patchelf_args();
} else {
return_code = patch_mcpi_elf_dependencies_with_extra_patchelf_args("--set-interpreter", linker);
}
if (!is_exit_status_success(return_code)) {
char *exit_status_line = NULL;
get_exit_status_string(return_code, &exit_status_line);
ERR("patchelf Failed%s", exit_status_line);
}
// Fix Permissions
if (chmod(new_path, S_IRUSR | S_IXUSR) != 0) {
ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno));
}
}
// Get Interpreter
char *patch_get_interpreter(const char *file) {
// Run
const char *const command[] = {
"patchelf",
"--print-interpreter",
file,
NULL
};
int return_code;
char *output = run_command(command, &return_code);
if (!is_exit_status_success(return_code)) {
char *exit_status_line = NULL;
get_exit_status_string(return_code, &exit_status_line);
ERR("patchelf Failed%s", exit_status_line);
}
if (output != NULL) {
// Trim
int length = strlen(output);
if (output[length - 1] == '\n') {
output[length - 1] = '\0';
}
}
// Return
return output;
}

91
launcher/src/patchelf.cpp Normal file
View File

@ -0,0 +1,91 @@
#include <cstdlib>
#include <sys/stat.h>
#include <LIEF/ELF.hpp>
#include <libreborn/libreborn.h>
#include "patchelf.h"
// Duplicate MCPI Executable Into /tmp
static void duplicate_mcpi_executable(char *new_path) {
// Ensure Temporary Directory
{
// Check If It Exists
struct stat tmp_stat;
int exists = stat(MCPI_PATCHED_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode);
if (!exists) {
// Doesn't Exist
if (mkdir(MCPI_PATCHED_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
ERR("Unable To Create Temporary Folder: %s", strerror(errno));
}
}
}
// Generate New File
int new_file_fd = mkstemp(new_path);
if (new_file_fd == -1) {
ERR("Unable To Create Temporary File: %s", strerror(errno));
}
close(new_file_fd);
}
// Fix MCPI Dependencies
static const char *libraries_to_remove[] = {
"libbcm_host.so",
"libX11.so.6",
"libEGL.so",
"libGLESv2.so",
"libSDL-1.2.so.0"
};
static const char *libraries_to_add[] = {
"libmedia-layer-core.so"
};
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker) {
// Duplicate MCPI executable into /tmp so it can be modified.
duplicate_mcpi_executable(new_path);
// Patch File
{
std::unique_ptr<LIEF::ELF::Binary> binary = LIEF::ELF::Parser::parse(original_path);
if (linker != NULL) {
binary->interpreter(linker);
}
for (size_t i = 0; i < (sizeof (libraries_to_remove) / sizeof (const char *)); i++) {
binary->remove_library(libraries_to_remove[i]);
}
for (size_t i = 0; i < (sizeof (libraries_to_add) / sizeof (const char *)); i++) {
binary->add_library(libraries_to_add[i]);
}
LIEF::ELF::Builder builder{*binary};
builder.build();
builder.write(new_path);
}
// Fix Permissions
if (chmod(new_path, S_IRUSR | S_IXUSR) != 0) {
ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno));
}
}
// Get Interpreter
static int dl_iterate_callback(struct dl_phdr_info *info, __attribute__((unused)) size_t size, void *data) {
// Only Search Current Program
if (strcmp(info->dlpi_name, "") == 0) {
for (int i = 0; i < info->dlpi_phnum; i++) {
if (info->dlpi_phdr[i].p_type == PT_INTERP) {
// Callback
*(char **) data = (char *) info->dlpi_phdr[i].p_vaddr;
}
}
}
return 0;
}
char *patch_get_interpreter() {
char *interpreter = NULL;
dl_iterate_phdr(dl_iterate_callback, &interpreter);
if (interpreter != NULL) {
interpreter = strdup(interpreter);
}
return interpreter;
}

View File

@ -7,7 +7,7 @@ extern "C" {
#define MCPI_PATCHED_DIR "/tmp/.minecraft-pi-patched" #define MCPI_PATCHED_DIR "/tmp/.minecraft-pi-patched"
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker); void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker);
char *patch_get_interpreter(const char *file); char *patch_get_interpreter();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -5,7 +5,6 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
#include <elf.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>

View File

@ -28,5 +28,5 @@ if(NOT MCPI_HEADLESS_MODE)
# OpenAL # OpenAL
find_library(OPENAL_LIBRARY NAMES openal REQUIRED) find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
# Link # Link
target_link_libraries(media-layer-core PRIVATE "${OPENAL_LIBRARY}" PRIVATE m PRIVATE glfw) target_link_libraries(media-layer-core PRIVATE "${OPENAL_LIBRARY}" PRIVATE m PRIVATE glfw PRIVATE LIB_LIEF)
endif() endif()

View File

@ -2,8 +2,8 @@
// Matrix Common // Matrix Common
#define MATRIX_SIZE 4 #define MATRIX_SIZE 4
#define MATRIX_DATA_SIZE (sizeof (float) * MATRIX_SIZE * MATRIX_SIZE) #define MATRIX_DATA_SIZE (sizeof (GLfloat) * MATRIX_SIZE * MATRIX_SIZE)
// OpenGL Matricies Are Column-Major // OpenGL Matrices Are Column-Major
typedef struct { typedef struct {
GLfloat data[MATRIX_SIZE][MATRIX_SIZE]; GLfloat data[MATRIX_SIZE][MATRIX_SIZE];
} matrix_t; } matrix_t;

View File

@ -1,14 +1,11 @@
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#include <functional> #include <functional>
#include <cstdint>
#include <cstring>
#include <unistd.h>
#include <sys/mman.h>
#include <elf.h>
#include <AL/al.h> #include <AL/al.h>
#include <LIEF/ELF.hpp>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include "file.h" #include "file.h"
@ -16,121 +13,16 @@
// Load Symbol From ELF File // Load Symbol From ELF File
static void load_symbol(const char *source, const char *name, std::function<void(unsigned char *, uint32_t)> callback) { static void load_symbol(const char *source, const char *name, std::function<void(unsigned char *, uint32_t)> callback) {
// File Data static std::unique_ptr<LIEF::ELF::Binary> binary = NULL;
FILE *file_obj = NULL; if (binary == NULL) {
unsigned char *file_map = NULL; binary = LIEF::ELF::Parser::parse(source);
long int file_size = 0;
// Code
{
// Load Main Binary
file_obj = fopen(source, "rb");
// Verify Binary
if (!file_obj) {
WARN("Unable To Open: %s", source);
goto end;
}
// 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) {
WARN("Not An ELF File: %s", source);
goto end;
}
if (file_map[EI_CLASS] != ELFCLASS32) {
WARN("ELF File Isn't 32-Bit: %s", source);
goto end;
}
if (file_map[EI_DATA] != ELFDATA2LSB) {
WARN("ELF File Isn't Little-Endian: %s", source);
goto end;
}
// 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_shstrtab = elf_section_headers[elf_header->e_shstrndx];
unsigned char *elf_shstrtab_p = file_map + elf_shstrtab.sh_offset;
// Locate String Table
unsigned char *elf_strtab_p = NULL;
for (int i = 0; i < elf_section_header_count; ++i) {
Elf32_Shdr header = elf_section_headers[i];
// Check Section Type
if (header.sh_type == SHT_STRTAB) {
// Check Section Name
char *section_name = (char *) (elf_shstrtab_p + header.sh_name);
if (strcmp(section_name, ".dynstr") == 0) {
// Found
elf_strtab_p = file_map + header.sh_offset;
break;
}
}
}
if (elf_strtab_p == NULL) {
WARN("Unable To Find String Table In: %s", source);
goto end;
}
// Locate Symbol Tables
Elf32_Sym *symbol = NULL;
for (int i = 0; i < elf_section_header_count; ++i) {
// Exit Loop If Finished
if (symbol != NULL) {
break;
}
// Get Section Header
Elf32_Shdr header = elf_section_headers[i];
// Check Section Type
if (header.sh_type == SHT_DYNSYM) {
// Symbol Table
Elf32_Sym *table = (Elf32_Sym *) (file_map + header.sh_offset);
for (int j = 0; (j * sizeof (Elf32_Sym)) < header.sh_size; j++) {
// Check Symbol Name
char *symbol_name = (char *) (elf_strtab_p + table[j].st_name);
if (strcmp(symbol_name, name) == 0) {
// Found
symbol = &table[j];
break;
}
}
}
}
// Check Symbol
if (symbol != NULL) {
// Convert Virtual Address To File Offset
Elf32_Shdr symbol_section_header = elf_section_headers[symbol->st_shndx];
int vaddr_to_offset = -symbol_section_header.sh_addr + symbol_section_header.sh_offset;
Elf32_Off symbol_offset = symbol->st_value + vaddr_to_offset;
// Access Symbol
unsigned char *value = file_map + symbol_offset;
uint32_t size = symbol->st_size;
callback(value, size);
} else {
// Unable To Find Symbol
WARN("Unable To Find Symbol: %s", name);
}
} }
const LIEF::ELF::Symbol *symbol = binary->get_dynamic_symbol(name);
end: if (symbol != NULL) {
// Unmap And Close File std::vector<uint8_t> data = binary->get_content_from_virtual_address(symbol->value(), symbol->size(), LIEF::Binary::VA_TYPES::VA);
if (file_map != NULL) { callback(data.data(), data.size());
munmap(file_map, file_size); } else {
} WARN("Unable To Find Symbol: %s", name);
if (file_obj != NULL) {
fclose(file_obj);
} }
} }