From f144539432836911430458159406ddbd4de48b8c Mon Sep 17 00:00:00 2001 From: chaoskagami Date: Wed, 28 Dec 2016 17:56:12 -0500 Subject: [PATCH] Add a early-ish prototype ips2pco tool. This tool takes an IPS or IPS32 patch and creates a .pco (bytecode source) skeleton. This is based on a previously written tool in my libbinmod repository for actually creating/applying IPS patches. The core changes to blib.c/blib.h will make it there soon-ish. This can be used to automate conversion of IPS patches to a format compatible with corbenik's patcher system. Do note the output files are not ready for use as-is -- you will need to manually edit the name, description, and titleID as needed, as well as actually run it through bytecode_asm.py. --- host/Makefile | 6 +- host/ips2pco/Makefile | 22 +++ host/ips2pco/bips.c | 350 +++++++++++++++++++++++++++++++++++++++++ host/ips2pco/blib.c | 197 +++++++++++++++++++++++ host/ips2pco/blib.h | 79 ++++++++++ host/ips2pco/ips_fmt.h | 64 ++++++++ host/ips2pco/util.c | 97 ++++++++++++ host/ips2pco/util.h | 15 ++ 8 files changed, 829 insertions(+), 1 deletion(-) create mode 100644 host/ips2pco/Makefile create mode 100755 host/ips2pco/bips.c create mode 100755 host/ips2pco/blib.c create mode 100755 host/ips2pco/blib.h create mode 100755 host/ips2pco/ips_fmt.h create mode 100755 host/ips2pco/util.c create mode 100755 host/ips2pco/util.h diff --git a/host/Makefile b/host/Makefile index 4c486d2..816f6a1 100644 --- a/host/Makefile +++ b/host/Makefile @@ -3,12 +3,16 @@ all: bdfe font misc misc: gcc -o error_decoder error_decoder.c -g -O0 +ips2pco: + $(MAKE) -C ips2pco + bdfe_dir: - make -C bdfe + $(MAKE) -C bdfe font: bdfe_dir ./bdfe/bdfe -n -A ../external/tewi-font/tewi-medium-11.bdf > termfont.bin clean: + $(MAKE) -C ips2pco clean $(MAKE) -C bdfe clean rm -f termfont.bin key_char error_decoder diff --git a/host/ips2pco/Makefile b/host/ips2pco/Makefile new file mode 100644 index 0000000..940867e --- /dev/null +++ b/host/ips2pco/Makefile @@ -0,0 +1,22 @@ +CXX = gcc +CFLAGS = -Wall -Werror +CFLAGS += -g +#CFLAGS += -O3 +LIBS = + +CORE = ips2pco +OBJS = bips.o blib.o util.o +HFILES = Makefile +CFILES = bips.c blib.c util.c + +all: $(CORE) + +$(CORE): $(OBJS) $(CFILES) $(HFILES) + $(CXX) $(CFLAGS) -o $(CORE) $(OBJS) $(LIBS) + +clean: + rm -f $(CORE) + rm -f *.o + +%.o: %.c $(HFILES) + $(CXX) -c $(CFLAGS) -DOSSD_TARGET=OSSD_IF_LINUX $< -o $@ diff --git a/host/ips2pco/bips.c b/host/ips2pco/bips.c new file mode 100755 index 0000000..4a128f1 --- /dev/null +++ b/host/ips2pco/bips.c @@ -0,0 +1,350 @@ +/* bips - A IPS patcher tool */ + +#include "blib.h" +#include "ips_fmt.h" + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +uint8_t* ips_buffer = NULL; + +int simulate = 0; // Don't actually apply; only show the results. +int plaintext = 0; // Decompile IPS to a human-readable listing. +int splitmini = 0; // Split IPS to one chunk mini-ips patches in a folder. + +// On success, returns the number of IPS records read. On failure, +// returns -1. +int load_ips(__READ char* ips_filename, __WRITE ips_record_t** ips_structs) { + // We load the entire thing to memory. + + FILE* f = fopen(ips_filename, "r"); + fseek(f, 0, SEEK_END); + uint64_t pos = ftell(f); + rewind(f); + + ips_buffer = (uint8_t*)malloc(pos); + + fread(ips_buffer, 1, pos, f); + + fclose(f); + + printf("Loaded file to memory successfully. Size: %lu\n", pos); + + // Loaded. Begin by checking shit. + if( strncmp((const char*)ips_buffer, IPS_MAGIC, IPS_MAGIC_LENGTH) ) { + // Invalid signature. Not an IPS. + free(ips_buffer); + ips_buffer = NULL; + return -1; + } + + // Seems legit. Begin record calculation. + int ips_count = 0; + uint64_t offset_in = 5; + ips_record_t* ips_data = NULL; + while( offset_in < pos && strncmp((char*)&ips_buffer[offset_in], IPS_TAIL, IPS_TAIL_LENGTH) ) { + // Increment. + ips_count++; + + // Reallocate. + ips_data = (ips_record_t*)realloc(ips_data, sizeof(ips_record_t) * ips_count); + + ips_data[ips_count-1].info = (ips_record_com_t*)&ips_buffer[offset_in]; + + offset_in += sizeof(ips_record_com_t); + + ips_data[ips_count-1].data = (void*)&ips_buffer[offset_in]; + + if(ips_data[ips_count-1].info->size[0] == 0x00 && ips_data[ips_count-1].info->size[1] == 0x00) // Zero is zero regardless of byte order, no casting needed + // RLE. Add the size of an RLE struct. + offset_in += sizeof(ips_record_rle_t); + else + offset_in += BYTE2_TO_UINT16(ips_data[ips_count-1].info->size); + + // Aaand onto the next. + } + + printf("Read in IPS data. Record count: %d\n", ips_count); + + ips_structs[0] = ips_data; + + return ips_count; +} + +int conv_ips(__READ char* filename, __READ ips_record_t* records, __READ int record_count) { + FILE* out = stdout; + if (filename != NULL) { + out = fopen(filename, "wb"); + if (!out) { + fprintf(stderr, "Can't open. Writing to stdout.\n"); + out = stdout; + } + } + + srand(time(NULL)); + uint16_t uuid = (0x6600 + (rand() % 0x4400)); + + fprintf(out, "# $name EDITME\n"); + fprintf(out, "# $desc Converted IPS Patch\n"); + fprintf(out, "# $title EDITME\n"); + fprintf(out, "# $ver 01\n"); + fprintf(out, "# $uuid %04hx\n", uuid); + fprintf(out, "# This file was automatically generated by ips2pco\n"); + + for (int i=0; i < record_count; i++) { + uint32_t offset = BYTE3_TO_UINT32(records[i].info->offset); + uint16_t size = BYTE2_TO_UINT16(records[i].info->size); + + fprintf(out, "seek %08x\n", offset); + + if (size == 0) { // RLE + ips_record_rle_t* rle = (ips_record_rle_t*)records[i].data; + + size = BYTE2_TO_UINT16(rle->rle_size); + + for (int i=0; i < size; i += 0x20) { + uint32_t max_l = (size - i > 0x20) ? + 0x20 : + size - i; + fprintf(out, "set "); + + for(uint32_t j=0; j < max_l; j++) + fprintf(out, "%02hhx", rle->byte); + fprintf(out, "\n"); + } + } else { // Normal + uint8_t* bytes = (uint8_t*)records[i].data; + + for (int i=0; i < size; i += 0x20) { + uint32_t max_l = (size - i > 0x20) ? + 0x20 : + size - i; + fprintf(out, "set "); + + for(uint32_t j=0; j < max_l; j++) + fprintf(out, "%02hhx", bytes[i+j]); + fprintf(out, "\n"); + } + } + } + + return 0; +} + + +// On success, returns the number of IPS records read. On failure, +// returns -1. +int load_ips32(__READ char* ips_filename, __WRITE ips32_record_t** ips_structs) { + // We load the entire thing to memory. + + FILE* f = fopen(ips_filename, "r"); + fseek(f, 0, SEEK_END); + uint64_t pos = ftell(f); + rewind(f); + + ips_buffer = (uint8_t*)malloc(pos); + + fread(ips_buffer, 1, pos, f); + + fclose(f); + + printf("Loaded file to memory successfully. Size: %lu\n", pos); + + // Loaded. Begin by checking shit. + if( strncmp((const char*)ips_buffer, IPS32_MAGIC, IPS32_MAGIC_LENGTH) ) { + // Invalid signature. Not an IPS. + free(ips_buffer); + ips_buffer = NULL; + return -1; + } + + // Seems legit. Begin record calculation. + int ips_count = 0; + uint64_t offset_in = 5; + ips32_record_t* ips_data = NULL; + while( offset_in < pos && strncmp((char*)&ips_buffer[offset_in], IPS32_TAIL, IPS32_TAIL_LENGTH) ) { + // Increment. + ips_count++; + + // Reallocate. + ips_data = (ips32_record_t*)realloc(ips_data, sizeof(ips32_record_t) * ips_count); + + ips_data[ips_count-1].info = (ips32_record_com_t*)&ips_buffer[offset_in]; + + offset_in += sizeof(ips32_record_com_t); + + ips_data[ips_count-1].data = (void*)&ips_buffer[offset_in]; + + if(ips_data[ips_count-1].info->size[0] == 0x00 && ips_data[ips_count-1].info->size[1] == 0x00) { // Zero is zero regardless of byte order, no casting needed + // RLE. Add the size of an RLE struct. + offset_in += sizeof(ips32_record_rle_t); + } else { + offset_in += BYTE2_TO_UINT16(ips_data[ips_count-1].info->size); + } + + // Aaand onto the next. + } + + printf("Read in IPS data. Record count: %d\n", ips_count); + + ips_structs[0] = ips_data; + + return ips_count; +} + +int conv_ips32(__READ char* filename, __READ ips32_record_t* records, __READ int record_count) { + FILE* out = stdout; + if (filename != NULL) { + out = fopen(filename, "wb"); + if (!out) { + fprintf(stderr, "Can't open. Writing to stdout.\n"); + out = stdout; + } + } + + srand(time(NULL)); + uint16_t uuid = (0x6600 + (rand() % 0x4400)); + + fprintf(out, "# $name EDITME\n"); + fprintf(out, "# $desc Converted IPS Patch\n"); + fprintf(out, "# $title EDITME\n"); + fprintf(out, "# $ver 01\n"); + fprintf(out, "# $uuid %04hx\n", uuid); + fprintf(out, "# This file was automatically generated by ips2pco\n"); + + for (int i=0; i < record_count; i++) { + uint32_t offset = BYTE4_TO_UINT32(records[i].info->offset); + uint16_t size = BYTE2_TO_UINT16(records[i].info->size); + + fprintf(out, "seek %08x\n", offset); + + if (size == 0) { // RLE + ips32_record_rle_t* rle = (ips32_record_rle_t*)records[i].data; + + size = BYTE2_TO_UINT16(rle->rle_size); + + for (int i=0; i < size; i += 0x20) { + uint32_t max_l = (size - i > 0x20) ? + 0x20 : + size - i; + fprintf(out, "set "); + + for(uint32_t j=0; j < max_l; j++) + fprintf(out, "%02hhx", rle->byte); + fprintf(out, "\n"); + } + } else { // Normal + uint8_t* bytes = (uint8_t*)records[i].data; + + for (int i=0; i < size; i += 0x20) { + uint32_t max_l = (size - i > 0x20) ? + 0x20 : + size - i; + fprintf(out, "set "); + + for(uint32_t j=0; j < max_l; j++) + fprintf(out, "%02hhx", bytes[i+j]); + fprintf(out, "\n"); + } + } + } + + if (out != stdout) + fclose(out); + + return 0; +} + + +int identify_patch(__READ char* filename) { + char test[8]; + FILE* f = fopen(filename, "r"); + fseek(f, 0, SEEK_END); + if (ftell(f) < 8) { + // Wrong. No patch is smaller than this. Die. + return TYPE_INVALID; + } + rewind(f); + fread(test, 1, 8, f); + + fclose(f); + + if ( !strncmp(test, IPS_MAGIC, IPS_MAGIC_LENGTH) ) + return TYPE_IPS; + if ( !strncmp(test, IPS32_MAGIC, IPS32_MAGIC_LENGTH) ) + return TYPE_IPS32; + + return TYPE_INVALID; +} + +void help(char* name) { + printf("corbenik ips2pco v0.1\n"); + printf("(C) 2015 Jon Feldman (@chaoskagami) \n"); + printf("Usage:\n"); + printf(" %s [options] patch.ips [out.pco]\n", name); + printf("Options:\n"); + printf(" -h Print this help text.\n"); + printf("Patch is dumped to stdout if a output file is not specified.\n"); + printf("Report bugs to \n"); + printf("This software is licensed under the MIT license.\n"); + +} + +int main(int argc, char** argv) { + ips_record_t* ips = NULL; + ips32_record_t* ips32 = NULL; + int record_count = 0; + int opt; + int prog_ret = 0; + + while ( (opt = getopt(argc, argv, "hs")) != -1) { + switch(opt) { + case 'h': + help(argv[0]); + return 1; + case 's': + simulate = 1; + break; + case '?': + fprintf(stderr, "error: unknown option. Run with -h for more info\n"); + return 1; + default: + fprintf(stderr, "error: unknown option. Run with -h for more info\n"); + return 1; + } + } + + if (argc - optind < 1) { + fprintf(stderr, "error: requires more arguments. Run with -h for more info\n"); + return 1; + } + + char* patch = argv[optind]; + int type = identify_patch(patch); + char *out_file = NULL; + if (argc - optind >= 2) { + out_file = argv[optind+1]; + } + + switch(type) { + case TYPE_IPS: + fprintf(stderr, "Patch format: IPS (24-bit offsets)\n"); + record_count = load_ips(patch, &ips); + conv_ips(out_file, ips, record_count); + break; + case TYPE_IPS32: + fprintf(stderr, "Patch format: IPS32 (IPS derivative w/ 32-bit offsets)\n"); + record_count = load_ips32(patch, &ips32); + conv_ips32(out_file, ips32, record_count); + break; + default: + fprintf(stderr, "Patch format not understood or invalid.\n"); + prog_ret = -2; + break; + } + + free(ips); + free(ips32); + free(ips_buffer); + + return prog_ret; +} diff --git a/host/ips2pco/blib.c b/host/ips2pco/blib.c new file mode 100755 index 0000000..d14e888 --- /dev/null +++ b/host/ips2pco/blib.c @@ -0,0 +1,197 @@ +#define BLIB_NO_EXTERNS + +#include "blib.h" + +int blib_filefd; +unsigned char* blib_buffer; +struct stat blib_stat; + +int copy_file(__READ char* dest, __READ char* src) { + // Can you believe there's no standard method to copy files? Neither can I. + // We use the generic POSIX way. + + int in_fd = open(src, O_RDONLY); + if(in_fd <= 0) + goto error_copy_file; + + int out_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (out_fd <= 0) + goto error_copy_file; + + char buf[8192]; + + while (1) { + ssize_t result = read(in_fd, buf, sizeof(buf)); + + if (!result) // Done? + break; + + if(result < 0) { + // ERROR! + fprintf(stderr, "Negative bytes read?\n"); + goto error_copy_file; + } + + if (write(out_fd, buf, result) != result) { + // Short write? Out of disk, maybe. Either way, abort. + fprintf(stderr, "Short write?\n"); + goto error_copy_file; + } + } + + close(in_fd); + close(out_fd); + + return 0; + +error_copy_file: + if (in_fd) close(in_fd); + if (out_fd) close(out_fd); + + return 1; +} + +int hexdump_file(__READ uint8_t *buffer, __READ uint64_t len, __READ int format) { + return hexdump_manual(0, buffer, len, format, stdout); +} + +int hexdump_manual(__READ uint64_t offset, __READ uint8_t* buffer, __READ uint64_t len, __READ int format, FILE* output) { + // Okay, hexdump. + + for (int i = 0; i < len;) { + int length = 16; + if (len - i < 16) // Incomplete line. + length = len - i; + + // First, offsets. + if (format & PRINT_OFFSET) { + + fprintf(output, "%08x", i); + + if (format & USE_COLON) + fprintf(output, ":"); + else if (format & PIPE_OFFSET) + fprintf(output, " | "); + else + fprintf(output, " "); + fprintf(output, " "); + } + + // Next, bytes. + if (format & BYTE_A) { // One byte + int copylen = length; + for(int j=0; j < 16; j++) { + if (copylen) { + fprintf(output, "%02x ", buffer[i+j]); + copylen--; + } else { + fprintf(output, " "); + } + if (j == 7 && (format & CENTER_SPLIT) ) + fprintf(output, " "); + } + } else if (format & BYTE_B) { // Two byte + int copylen = length; + for(int j=0; j < 16; j++) { + if (copylen) { + fprintf(output, "%02x", buffer[i+j]); + if (j % 2 == 1) + fprintf(output, " "); + copylen--; + } else { + fprintf(output, " "); + if (j % 2 == 1) + fprintf(output, " "); + } + if (j == 7 && (format & CENTER_SPLIT) ) + fprintf(output, " "); + } + } else if (format & BYTE_C) { // Three byte + int copylen = length; + for(int j=0; j < 16; j++) { + if (copylen) { + fprintf(output, "%02x", buffer[i+j]); + if (j % 4 == 3) + fprintf(output, " "); + copylen--; + } else { + fprintf(output, " "); + if (j % 4 == 3) + fprintf(output, " "); + } + if (j == 7 && (format & CENTER_SPLIT) ) + fprintf(output, " "); + } + } + + if (format & WITH_ASCII) { // Print ascii + fprintf(output, " "); + + if (format & PIPE_SEPARATE) { + fprintf(output, "|"); + } + + for(int j=0; j < length; j++) { + // We only print printables. + int c = buffer[i+j]; + if (c > 0x1f && c < 0x7f) // Printable? + fprintf(output, "%c", c); + else { + if (format & NONPRINT_PERIOD) { + fprintf(output, "."); + } else if (format & NONPRINT_UNDERS) { + fprintf(output, "_"); + } else { + fprintf(output, " "); + } + } + } + + if (format & PIPE_SEPARATE) { + fprintf(output, "|"); + } + } + + i += 16; + fprintf(output, "\n"); + } + + return 0; +} + +uint8_t hexb_to_u8(char a, char b) { + if (a >= 'a' && a <= 'f') { + a -= 'a'; + a += 10; + } else if (a >= 'A' && a <= 'F') { + a -= 'A'; + a += 10; + } else if (a >= '0' && a <= '9') { + a -= '0'; + } else { + return 0; + } + + if (b >= 'a' && b <= 'f') { + b -= 'a'; + b += 10; + } else if (b >= 'A' && b <= 'F') { + b -= 'A'; + b += 10; + } else if (b >= '0' && b <= '9') { + b -= '0'; + } else { + return 0; + } + + return ((a<<4)|b); +} + +// Unhexdump +int unhexdump_buffer(__READ uint8_t* buffer, __READ uint64_t len, __WRITE uint8_t* output) { + for(uint64_t i=0; i < (len/2); i++) { + output[i] = hexb_to_u8(buffer[i*2], buffer[i*2+1]); + } + + return 0; +} diff --git a/host/ips2pco/blib.h b/host/ips2pco/blib.h new file mode 100755 index 0000000..b7f47b3 --- /dev/null +++ b/host/ips2pco/blib.h @@ -0,0 +1,79 @@ +/* Common functions for binary modifying programs. */ + +#ifndef __BINLIB_H +#define __BINLIB_H + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include "util.h" + +#ifdef MAX +#undef MAX +#endif +#define MAX(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) + +// map_file flags +#define READ_FILE 0 +#define WRITE_FILE 1 // Implies read + +// Hexdump feature bits +#define USE_SPACES 1 +#define PRINT_OFFSET 2 +#define USE_COLON 4 +#define LINE_BREAKS 8 +#define PIPE_SEPARATE 16 +#define PIPE_OFFSET 32 +#define WITH_ASCII 64 +#define BYTE_A 128 // 1byte +#define BYTE_B 256 // 2byte +#define BYTE_C 512 // 4byte +#define CENTER_SPLIT 1024 +#define NONPRINT_PERIOD 2048 +#define NONPRINT_UNDERS 4096 +#define COLORIZED 8192 + +// Hexdump presets. +#define SPACED_BYTES USE_SPACES | BYTE_A +#define PRESET_XXD USE_SPACES | BYTE_B | PRINT_OFFSET | USE_COLON | WITH_ASCII | LINE_BREAKS | NONPRINT_PERIOD +#define PRESET_HEXDUMP_C USE_SPACES | BYTE_A | PRINT_OFFSET | PIPE_SEPARATE | WITH_ASCII | LINE_BREAKS | CENTER_SPLIT | NONPRINT_PERIOD +#define PRESET_FANCY USE_SPACES | BYTE_A | PRINT_OFFSET | PIPE_SEPARATE | WITH_ASCII | LINE_BREAKS | CENTER_SPLIT | PIPE_OFFSET + +// None of these have any meaning, but serve as documentation. +#ifdef NO_STRICT_SPECS + #define __READ +#else + #define __READ const +#endif + +#define __WRITE +#define __WRITEREAD + +// Buffer size. +#define BUFFER_SIZE 1024 + +// Copy file. +int copy_file(__READ char* dest, __READ char* src); + +// Hexdump +int hexdump_file(__READ uint8_t *buffer, __READ uint64_t len, __READ int format); +int hexdump_manual(__READ uint64_t offset, __READ uint8_t* buffer, __READ uint64_t len, __READ int format, FILE* output); + +// Unhexdump +int unhexdump_buffer(__READ uint8_t* buffer, __READ uint64_t len, __WRITE uint8_t* output); + +#endif diff --git a/host/ips2pco/ips_fmt.h b/host/ips2pco/ips_fmt.h new file mode 100755 index 0000000..cfd736a --- /dev/null +++ b/host/ips2pco/ips_fmt.h @@ -0,0 +1,64 @@ +/* IPS. Pretty standard stuff. */ + +#define IPS_MAGIC "PATCH" // Original Spec +#define IPS_MAGIC_LENGTH 5 + +#define IPS_TAIL "EOF" +#define IPS_TAIL_LENGTH 3 + +typedef struct ips_record_com_s { + uint8_t offset[3]; + uint8_t size[2]; +} ips_record_com_t; + +typedef struct ips_record_rle_s { + uint8_t rle_size[2]; + uint8_t byte; +} ips_record_rle_t; + +typedef struct ips_record_s { + ips_record_com_t* info; + void* data; // Can be ips_record_rle_t or uint8_t. +} ips_record_t; + +/* IPS32 is IPS with 32-bit offsets. */ + +#define IPS32_MAGIC "IPS32" // 32-bit extension +#define IPS32_MAGIC_LENGTH 5 + +#define IPS32_TAIL "EEOF" +#define IPS32_TAIL_LENGTH 4 + +typedef struct ips32_record_com_s { + uint8_t offset[4]; + uint8_t size[2]; +} ips32_record_com_t; + +typedef struct ips32_record_rle_s { + uint8_t rle_size[2]; + uint8_t byte; +} ips32_record_rle_t; + +typedef struct ips32_record_s { + ips32_record_com_t* info; + void* data; // Can be ips_record_rle_t or uint8_t. +} ips32_record_t; + +#define TYPE_INVALID 0 +#define TYPE_IPS 1 +#define TYPE_IPS32 2 + +#define BYTE4_TO_UINT32(bp) \ + (((uint32_t)(bp [0]) << 24) & 0xFF000000) | \ + (((uint32_t)(bp [1]) << 16) & 0x00FF0000) | \ + (((uint32_t)(bp [2]) << 8 ) & 0x0000FF00) | \ + ( (uint32_t)(bp [3]) & 0x000000FF) + +#define BYTE3_TO_UINT32(bp) \ + (((uint32_t)(bp [0]) << 16) & 0x00FF0000) | \ + (((uint32_t)(bp [1]) << 8 ) & 0x0000FF00) | \ + ( (uint32_t)(bp [2]) & 0x000000FF) + +#define BYTE2_TO_UINT16(bp) \ + (((uint16_t)(bp [0]) << 8 ) & 0xFF00) | \ + ( (uint16_t)(bp [1]) & 0x00FF) diff --git a/host/ips2pco/util.c b/host/ips2pco/util.c new file mode 100755 index 0000000..f0760b7 --- /dev/null +++ b/host/ips2pco/util.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include + +#include "blib.h" + +size_t fsize(FILE* file) { + size_t at = ftell(file); + + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + fseek(file, at, SEEK_SET); + + return size; +} + +int read_alloc_file(const char* filename, void** ptr, size_t* size) { + FILE* handle = fopen(filename, "rb"); + if (!handle) + return -READALLOC_NOFILE; + + size_t alloc_size = *size; + + *size = fsize(handle); + if (size <= 0) { + fclose(handle); + *size = 0; + return -READALLOC_BADSIZE; + } + + if (alloc_size) { + *ptr = malloc(alloc_size); + if (alloc_size < *size) { + *size = alloc_size; + } + } else { + *ptr = malloc(*size); + } + + if (*ptr == NULL) { + fclose(handle); + *ptr = NULL; + *size = 0; + return -READALLOC_OOM; + } + + if (fread(*ptr, 1, *size, handle) != *size) { + free(*ptr); + fclose(handle); + *ptr = NULL; + *size = 0; + return -READALLOC_READERR; + } + + if (alloc_size && alloc_size > *size) { + *size = alloc_size; + } + + fclose(handle); + + return 0; +} + +#define ALPHABET_LEN 256 +#define NOT_FOUND patlen +#define max(a, b) ((a < b) ? b : a) + +// Quick Search algorithm, adapted from +// http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190 +const void * +memfind(const void *input, uint32_t size, const void *pattern, uint32_t patternSize) +{ + const uint8_t *startPos = (const uint8_t *)input; + const uint8_t *patternc = (const uint8_t *)pattern; + + // Preprocessing + uint32_t table[ALPHABET_LEN]; + + for (uint32_t i = 0; i < ALPHABET_LEN; ++i) + table[i] = patternSize + 1; + for (uint32_t i = 0; i < patternSize; ++i) + table[patternc[i]] = patternSize - i; + + // Searching + size_t j = 0; + + while (j <= size - patternSize) { + if (memcmp(patternc, startPos + j, patternSize) == 0) + return startPos + j; + j += table[startPos[j + patternSize]]; + } + + return NULL; +} + diff --git a/host/ips2pco/util.h b/host/ips2pco/util.h new file mode 100755 index 0000000..2c0a443 --- /dev/null +++ b/host/ips2pco/util.h @@ -0,0 +1,15 @@ +#ifndef __LIBC2PATCHER_OLDVM_UTIL__ +#define __LIBC2PATCHER_OLDVM_UTIL__ + +size_t fsize(FILE* file); + +const void* memfind(const void *input, uint32_t size, const void *pattern, uint32_t patternSize); + +#define READALLOC_NOFILE 1 +#define READALLOC_BADSIZE 2 +#define READALLOC_OOM 3 +#define READALLOC_READERR 4 + +int read_alloc_file(const char* filename, void** ptr, size_t* size); + +#endif -- 2.39.5