selfpatch-slr/selfpatch/src/selfpatch.c

199 lines
5.4 KiB
C

#include <spslr.h>
#include "randomizer.h"
#include "env.h"
#include "spslr_list_link.h"
#define SPSLR_SANITY_CHECK
static void spslr_selfpatch_load_targets(void);
static void spslr_selfpatch_randomize_targets(void);
static void spslr_selfpatch_patch_dpins(void);
static void spslr_selfpatch_patch_dpin(void* addr, spslr_u32 target);
static void spslr_selfpatch_patch_ipins(void);
static void reorder_object(void* dst, const void* src, spslr_u32 target);
static spslr_s64 spslr_calculate_ipin_value(spslr_u32 start);
static void* reorder_buffer = SPSLR_NULL;
static void allocate_reorder_buffer();
static void release_reorder_buffer();
void spslr_selfpatch(void) {
if (spslr_randomizer_init() < 0)
spslr_env_panic("failed to initialize randomizer");
if (spslr_randomize() < 0)
spslr_env_panic("failed to randomize targets");
allocate_reorder_buffer();
spslr_selfpatch_patch_dpins();
release_reorder_buffer();
spslr_selfpatch_patch_ipins();
spslr_randomizer_clear();
}
static void allocate_reorder_buffer() {
if (reorder_buffer)
return;
spslr_u32 max_target_size = 0;
for (spslr_u32 i = 0; i < spslr_target_cnt; i++) {
if (spslr_targets[i].size > max_target_size)
max_target_size = spslr_targets[i].size;
}
reorder_buffer = spslr_env_malloc(max_target_size);
if (!reorder_buffer)
spslr_env_panic("failed to allocate reorder buffer");
}
static void release_reorder_buffer() {
if (!reorder_buffer)
return;
spslr_env_free(reorder_buffer);
reorder_buffer = SPSLR_NULL;
}
static void spslr_selfpatch_patch_dpins(void) {
for (spslr_u32 dpidx = 0; dpidx < spslr_dpin_cnt; dpidx++) {
const struct spslr_dpin* dp = &spslr_dpins[dpidx];
spslr_selfpatch_patch_dpin((void*)dp->addr, dp->target);
}
}
static void reorder_object(void* dst, const void* src, spslr_u32 target) {
spslr_u32 field_count;
if (spslr_randomizer_get_target(target, SPSLR_NULL, &field_count))
spslr_env_panic("failed to get target field count");
const spslr_u8* src_countable = (const spslr_u8*)src;
spslr_u8* dst_countable = (spslr_u8*)dst;
for (spslr_u32 i = 0; i < field_count; i++) {
struct spslr_randomizer_field_info finfo;
if (spslr_randomizer_get_field(target, i, SPSLR_RANDOMIZER_FIELD_IDX_MODE_FINAL, &finfo))
spslr_env_panic("failed to get ordered field descriptor");
spslr_env_memcpy(dst_countable + finfo.offset, src_countable + finfo.initial_offset, finfo.size);
}
}
static void spslr_selfpatch_patch_dpin(void* addr, spslr_u32 target) {
#ifdef SPSLR_SANITY_CHECK
if (target >= spslr_target_cnt)
spslr_env_panic("dpin refers to invalid target");
#endif
const struct spslr_target* t = &spslr_targets[target];
spslr_env_memset(reorder_buffer, 0, t->size);
reorder_object(reorder_buffer, addr, target);
spslr_env_poke_data(addr, reorder_buffer, t->size);
}
static void spslr_selfpatch_patch_ipins(void) {
for (spslr_u32 ipidx = 0; ipidx < spslr_ipin_cnt; ipidx++) {
const struct spslr_ipin* ip = &spslr_ipins[ipidx];
spslr_s64 value = spslr_calculate_ipin_value(ip->program);
switch (ip->size) {
case 1:
spslr_env_poke_text_8((void*)ip->addr, (spslr_u8)value);
break;
case 2:
spslr_env_poke_text_16((void*)ip->addr, (spslr_u16)value);
break;
case 4:
spslr_env_poke_text_32((void*)ip->addr, (spslr_u32)value);
break;
case 8:
spslr_env_poke_text_64((void*)ip->addr, (spslr_u64)value);
break;
#ifdef SPSLR_SANITY_CHECK
default:
spslr_env_panic("invalid ipin size");
#endif
}
}
}
static spslr_s64 spslr_calculate_ipin_value(spslr_u32 start) {
spslr_s64 res = 0;
spslr_u32 pc = start;
while (true) {
#ifdef SPSLR_SANITY_CHECK
if (pc >= spslr_ipin_op_cnt)
spslr_env_panic("ipin op out of bounds");
#endif
int end_flag = 0;
const struct spslr_ipin_op* op = &spslr_ipin_ops[pc++];
switch (op->code) {
case SPSLR_IPIN_OP_PATCH:
end_flag = 1;
break;
case SPSLR_IPIN_OP_ADD_INITIAL_OFFSET:
{
struct spslr_randomizer_field_info finfo;
if (spslr_randomizer_get_field(op->op0.add_initial_offset_target,
op->op1.add_initial_offset_field, SPSLR_RANDOMIZER_FIELD_IDX_MODE_ORIGINAL, &finfo))
spslr_env_panic("failed to get initial field offset");
res += finfo.initial_offset;
}
break;
case SPSLR_IPIN_OP_ADD_OFFSET:
{
struct spslr_randomizer_field_info finfo;
if (spslr_randomizer_get_field(op->op0.add_initial_offset_target,
op->op1.add_offset_field, SPSLR_RANDOMIZER_FIELD_IDX_MODE_ORIGINAL, &finfo))
spslr_env_panic("failed to get initial field offset");
res += finfo.offset;
}
break;
case SPSLR_IPIN_OP_SUB_INITIAL_OFFSET:
{
struct spslr_randomizer_field_info finfo;
if (spslr_randomizer_get_field(op->op0.add_initial_offset_target,
op->op1.sub_initial_offset_field, SPSLR_RANDOMIZER_FIELD_IDX_MODE_ORIGINAL, &finfo))
spslr_env_panic("failed to get initial field offset");
res -= finfo.initial_offset;
}
break;
case SPSLR_IPIN_OP_SUB_OFFSET:
{
struct spslr_randomizer_field_info finfo;
if (spslr_randomizer_get_field(op->op0.add_initial_offset_target,
op->op1.sub_offset_field, SPSLR_RANDOMIZER_FIELD_IDX_MODE_ORIGINAL, &finfo))
spslr_env_panic("failed to get initial field offset");
res -= finfo.offset;
}
break;
case SPSLR_IPIN_OP_ADD_CONST:
res += op->op0.add_const_value;
break;
#ifdef SPSLR_SANITY_CHECK
default:
spslr_env_panic("invalid ipin op");
#endif
}
if (end_flag)
break;
}
return res;
}