199 lines
5.4 KiB
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;
|
|
}
|
|
|