Modernized selfpatch interface - awaiting patchcompile update
This commit is contained in:
parent
c57b3f03a3
commit
b40222f0ae
@ -1,8 +1,8 @@
|
||||
add_library(spslr_selfpatch STATIC src/selfpatch.c src/targets.c src/patcher.c)
|
||||
add_library(spslr_selfpatch STATIC src/selfpatch.c src/targets.c src/env.c)
|
||||
|
||||
target_include_directories(spslr_selfpatch PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
target_include_directories(spslr_patchcompile PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) # For spslr_program.h
|
||||
target_include_directories(spslr_patchcompile PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) # For spslr_list.h
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#ifndef SPSLR_SELFPATCH_H
|
||||
#define SPSLR_SELFPATCH_H
|
||||
|
||||
void spslr_selfpatch();
|
||||
void spslr_selfpatch(void);
|
||||
|
||||
#endif
|
||||
|
||||
109
selfpatch/src/env.c
Normal file
109
selfpatch/src/env.c
Normal file
@ -0,0 +1,109 @@
|
||||
#include "env.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
|
||||
#define PAGE_MASK ~(0x1000ull - 1)
|
||||
|
||||
static int spslr_env_get_prot(void* addr, int* prot) {
|
||||
FILE* f = fopen("/proc/self/maps", "r");
|
||||
if (!f)
|
||||
return -1;
|
||||
|
||||
uintptr_t query = (uintptr_t)addr;
|
||||
char line[512];
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
uintptr_t start, end;
|
||||
char perms[5];
|
||||
|
||||
if (sscanf(line, "%lx-%lx %4s", &start, &end, perms) != 3)
|
||||
continue;
|
||||
|
||||
if (query < start || query >= end)
|
||||
continue;
|
||||
|
||||
*prot = 0;
|
||||
|
||||
if (perms[0] == 'r')
|
||||
*prot |= PROT_READ;
|
||||
if (perms[1] == 'w')
|
||||
*prot |= PROT_WRITE;
|
||||
if (perms[2] == 'x')
|
||||
*prot |= PROT_EXEC;
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void spslr_env_poke_safe(void* dst, const void* src, uint32_t n) {
|
||||
int original_prot;
|
||||
if (spslr_env_get_prot(dst, &original_prot))
|
||||
spslr_env_panic("failed to get prot of text poke destination");
|
||||
|
||||
uint64_t ptr_uint = (uint64_t)dst;
|
||||
uint64_t ptr_page = ptr_uint & PAGE_MASK;
|
||||
uint64_t prot_size = n + (ptr_uint - ptr_page);
|
||||
|
||||
int tmp_prot = original_prot | PROT_WRITE;
|
||||
|
||||
if (tmp_prot != original_prot)
|
||||
mprotect((void*)ptr_page, prot_size, tmp_prot);
|
||||
|
||||
spslr_env_memcpy(dst, src, n);
|
||||
|
||||
if (tmp_prot != original_prot)
|
||||
mprotect((void*)ptr_page, prot_size, original_prot);
|
||||
}
|
||||
|
||||
void spslr_env_panic(const char* reason) {
|
||||
fprintf(stderr, "[spslr_panic] %s\n", reason);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void spslr_env_poke_text_8(void* dst, uint8_t value) {
|
||||
spslr_env_poke_safe(dst, &value, sizeof(value));
|
||||
}
|
||||
|
||||
void spslr_env_poke_text_16(void* dst, uint16_t value) {
|
||||
spslr_env_poke_safe(dst, &value, sizeof(value));
|
||||
}
|
||||
|
||||
void spslr_env_poke_text_32(void* dst, uint32_t value) {
|
||||
spslr_env_poke_safe(dst, &value, sizeof(value));
|
||||
}
|
||||
|
||||
void spslr_env_poke_text_64(void* dst, uint64_t value) {
|
||||
spslr_env_poke_safe(dst, &value, sizeof(value));
|
||||
}
|
||||
|
||||
void* spslr_env_malloc(uint32_t n) {
|
||||
void* res = malloc(n);
|
||||
if (!res)
|
||||
spslr_env_panic("malloc failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void spslr_env_free(void* ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void spslr_env_poke_data(void* dst, const void* src, uint32_t n) {
|
||||
spslr_env_poke_safe(dst, src, n);
|
||||
}
|
||||
|
||||
void spslr_env_memset(void* dst, int v, uint32_t n) {
|
||||
memset(dst, v, n);
|
||||
}
|
||||
|
||||
void spslr_env_memcpy(void* dst, const void* src, uint32_t n) {
|
||||
memcpy(dst, src, n);
|
||||
}
|
||||
|
||||
17
selfpatch/src/env.h
Normal file
17
selfpatch/src/env.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef SPSLR_ENV_H
|
||||
#define SPSLR_ENV_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void spslr_env_panic(const char* reason);
|
||||
void spslr_env_poke_text_8(void* dst, uint8_t value);
|
||||
void spslr_env_poke_text_16(void* dst, uint16_t value);
|
||||
void spslr_env_poke_text_32(void* dst, uint32_t value);
|
||||
void spslr_env_poke_text_64(void* dst, uint64_t value);
|
||||
void* spslr_env_malloc(uint32_t n); // Either return valid buffer or panic internally
|
||||
void spslr_env_free(void* ptr);
|
||||
void spslr_env_poke_data(void* dst, const void* src, uint32_t n);
|
||||
void spslr_env_memset(void* dst, int v, uint32_t n);
|
||||
void spslr_env_memcpy(void* dst, const void* src, uint32_t n);
|
||||
|
||||
#endif
|
||||
@ -1,138 +0,0 @@
|
||||
#include "patcher.h"
|
||||
#include "targets.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PAGE_MASK ~(0x1000ull - 1)
|
||||
|
||||
static int get_prot(void* addr, int* prot) {
|
||||
FILE* f = fopen("/proc/self/maps", "r");
|
||||
if (!f)
|
||||
return -1;
|
||||
|
||||
uintptr_t query = (uintptr_t)addr;
|
||||
char line[512];
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
uintptr_t start, end;
|
||||
char perms[5];
|
||||
|
||||
if (sscanf(line, "%lx-%lx %4s", &start, &end, perms) != 3)
|
||||
continue;
|
||||
|
||||
if (query < start || query >= end)
|
||||
continue;
|
||||
|
||||
*prot = 0;
|
||||
|
||||
if (perms[0] == 'r')
|
||||
*prot |= PROT_READ;
|
||||
if (perms[1] == 'w')
|
||||
*prot |= PROT_WRITE;
|
||||
if (perms[2] == 'x')
|
||||
*prot |= PROT_EXEC;
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int patch_immediate(void* ptr, uint32_t size, uint32_t v) {
|
||||
if (size != 4)
|
||||
return -1;
|
||||
|
||||
memcpy(ptr, &v, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spslr_ipatch(void* ptr, uint32_t size, uint32_t target, uint32_t field) {
|
||||
uint32_t field_offset;
|
||||
if (spslr_get_randomized_field_offset(target, field, &field_offset))
|
||||
return -1;
|
||||
|
||||
int original_prot;
|
||||
if (get_prot(ptr, &original_prot))
|
||||
return -1;
|
||||
|
||||
uint64_t ptr_uint = (uint64_t)ptr;
|
||||
uint64_t ptr_page = ptr_uint & PAGE_MASK;
|
||||
uint64_t corrected_size = size + (ptr_uint - ptr_page);
|
||||
|
||||
int tmp_prot = original_prot | PROT_WRITE;
|
||||
|
||||
if (tmp_prot != original_prot)
|
||||
mprotect((void*)ptr_page, corrected_size, tmp_prot);
|
||||
|
||||
if (patch_immediate(ptr, size, field_offset))
|
||||
return -1;
|
||||
|
||||
if (tmp_prot != original_prot)
|
||||
mprotect((void*)ptr_page, corrected_size, original_prot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reorder_object(const void* src, void* dst, uint32_t target) {
|
||||
if (!src || !dst)
|
||||
return -1;
|
||||
|
||||
uint32_t field_count;
|
||||
if (spslr_get_target_fieldcnt(target, &field_count))
|
||||
return -1;
|
||||
|
||||
const uint8_t* src_countable = (const uint8_t*)src;
|
||||
uint8_t* dst_countable = (uint8_t*)dst;
|
||||
|
||||
for (uint32_t i = 0; i < field_count; i++) {
|
||||
uint32_t field_offset, field_size, field_initial_offset;
|
||||
if (spslr_get_target_field_ordered(target, i, &field_offset, &field_size, &field_initial_offset))
|
||||
return -1;
|
||||
|
||||
memcpy(dst_countable + field_offset, src_countable + field_initial_offset, field_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spslr_dpatch(void* ptr, uint32_t target) {
|
||||
uint32_t target_size;
|
||||
if (spslr_get_target_size(target, &target_size))
|
||||
return -1;
|
||||
|
||||
int original_prot;
|
||||
if (get_prot(ptr, &original_prot))
|
||||
return -1;
|
||||
|
||||
uint64_t ptr_uint = (uint64_t)ptr;
|
||||
uint64_t ptr_page = ptr_uint & PAGE_MASK;
|
||||
uint64_t corrected_size = target_size + (ptr_uint - ptr_page);
|
||||
|
||||
int tmp_prot = original_prot | PROT_WRITE | PROT_READ;
|
||||
|
||||
if (tmp_prot != original_prot)
|
||||
mprotect((void*)ptr_page, corrected_size, tmp_prot);
|
||||
|
||||
void* tmp_obj = malloc(target_size);
|
||||
if (!tmp_obj)
|
||||
return -1;
|
||||
|
||||
memset(tmp_obj, 0, target_size);
|
||||
|
||||
if (reorder_object(ptr, tmp_obj, target))
|
||||
return -1;
|
||||
|
||||
memcpy(ptr, tmp_obj, target_size);
|
||||
free(tmp_obj);
|
||||
|
||||
if (tmp_prot != original_prot)
|
||||
mprotect((void*)ptr_page, corrected_size, original_prot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
#ifndef SPSLR_PATCHER_H
|
||||
#define SPSLR_PATCHER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int spslr_ipatch(void* ptr, uint32_t size, uint32_t target, uint32_t field);
|
||||
int spslr_dpatch(void* ptr, uint32_t target);
|
||||
|
||||
#endif
|
||||
@ -1,71 +1,198 @@
|
||||
#include <spslr.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "spslr_program.h"
|
||||
#include "targets.h"
|
||||
#include "patcher.h"
|
||||
#include "env.h"
|
||||
|
||||
extern const uint8_t __spslr_program[];
|
||||
#include "spslr_list_link.h"
|
||||
|
||||
static int spslr_do(const struct SPSLR_INST* inst) {
|
||||
if (!inst)
|
||||
return -1;
|
||||
#define SPSLR_SANITY_CHECK
|
||||
|
||||
static uint32_t pending_fields = 0;
|
||||
static uint32_t pending_fields_target = 0;
|
||||
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, uint32_t target);
|
||||
static void spslr_selfpatch_patch_ipins(void);
|
||||
|
||||
if (pending_fields) {
|
||||
if (inst->op != SPSLR_FIELD) {
|
||||
fprintf(stderr, "spslr_do encountered non field instruction where a field instruction was expected\n");
|
||||
return -1;
|
||||
static void reorder_object(void* dst, const void* src, uint32_t target);
|
||||
static int64_t spslr_calculate_ipin_value(uint32_t start);
|
||||
|
||||
void spslr_selfpatch(void) {
|
||||
spslr_selfpatch_load_targets();
|
||||
spslr_selfpatch_randomize_targets();
|
||||
spslr_selfpatch_patch_dpins();
|
||||
spslr_selfpatch_patch_ipins();
|
||||
spslr_clear_targets();
|
||||
}
|
||||
|
||||
void spslr_selfpatch_load_targets(void) {
|
||||
for (uint32_t tidx = 0; tidx < spslr_target_cnt; tidx++) {
|
||||
const struct spslr_target* t = &spslr_targets[tidx];
|
||||
|
||||
#ifdef SPSLR_SANITY_CHECK
|
||||
if (t->fieldoff + t->fieldcnt > spslr_target_field_cnt)
|
||||
spslr_env_panic("target field offset and count reference invalid fields");
|
||||
#endif
|
||||
|
||||
if (spslr_register_target(tidx, t->size, t->fieldcnt) < 0)
|
||||
spslr_env_panic("failed to register target");
|
||||
|
||||
for (uint32_t fidx = 0; fidx < t->fieldcnt; fidx++) {
|
||||
const struct spslr_target_field* f = &spslr_target_fields[t->fieldoff + fidx];
|
||||
|
||||
#ifdef SPSLR_SANITY_CHECK
|
||||
if (f->offset + f->size > t->size)
|
||||
spslr_env_panic("target field resides beyond target size");
|
||||
|
||||
if (f->offset % f->alignment != 0)
|
||||
spslr_env_panic("target field is misaligned");
|
||||
#endif
|
||||
|
||||
if (spslr_register_target_field(tidx, f->offset, f->size, f->alignment, f->flags) < 0)
|
||||
spslr_env_panic("failed to register target field");
|
||||
}
|
||||
|
||||
pending_fields--;
|
||||
} else if (inst->op == SPSLR_FIELD) {
|
||||
fprintf(stderr, "spslr_do encountered field instruction where none was expected\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (inst->op) {
|
||||
case SPSLR_TARGET:
|
||||
pending_fields = inst->op2.target_fieldcnt;
|
||||
pending_fields_target = inst->op0.target_uid;
|
||||
return spslr_target(inst->op0.target_uid, inst->op1.target_size, inst->op2.target_fieldcnt);
|
||||
case SPSLR_FIELD:
|
||||
return spslr_field(pending_fields_target, inst->op0.field_offset, inst->op1.field_size,
|
||||
inst->op2.field_alignment, inst->op3.field_flags);
|
||||
case SPSLR_RANDOMIZE:
|
||||
return spslr_randomize(inst->op0.randomize_target);
|
||||
case SPSLR_IPATCH:
|
||||
return spslr_ipatch((void*)(uintptr_t)inst->op0.ipatch_ptr, inst->op1.ipatch_size,
|
||||
inst->op2.ipatch_target, inst->op3.ipatch_field);
|
||||
case SPSLR_DPATCH:
|
||||
return spslr_dpatch((void*)(uintptr_t)inst->op0.dpatch_ptr, inst->op1.dpatch_target);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void spslr_selfpatch() {
|
||||
const uint8_t* pc = __spslr_program;
|
||||
void spslr_selfpatch_randomize_targets(void) {
|
||||
for (uint32_t tidx = 0; tidx < spslr_target_cnt; tidx++) {
|
||||
if (spslr_randomize(tidx) < 0)
|
||||
spslr_env_panic("failed to randomize target");
|
||||
}
|
||||
}
|
||||
|
||||
int sz;
|
||||
struct SPSLR_INST inst;
|
||||
while ((sz = spslr_inst_load(&inst, pc)) > 0) {
|
||||
if (inst.op == SPSLR_EXIT) {
|
||||
spslr_targets_clear();
|
||||
return;
|
||||
void spslr_selfpatch_patch_dpins(void) {
|
||||
for (uint32_t dpidx = 0; dpidx < spslr_dpin_cnt; dpidx++) {
|
||||
const struct spslr_dpin* dp = &spslr_dpins[dpidx];
|
||||
spslr_selfpatch_patch_dpin((void*)dp->addr, dp->target);
|
||||
}
|
||||
}
|
||||
|
||||
void reorder_object(void* dst, const void* src, uint32_t target) {
|
||||
uint32_t field_count;
|
||||
if (spslr_get_target_fieldcnt(target, &field_count))
|
||||
spslr_env_panic("failed to get target field count");
|
||||
|
||||
const uint8_t* src_countable = (const uint8_t*)src;
|
||||
uint8_t* dst_countable = (uint8_t*)dst;
|
||||
|
||||
for (uint32_t i = 0; i < field_count; i++) {
|
||||
uint32_t field_offset, field_size, field_initial_offset;
|
||||
if (spslr_get_target_field_ordered(target, i, &field_offset, &field_size, &field_initial_offset))
|
||||
spslr_env_panic("failed to get ordered field descriptor");
|
||||
|
||||
spslr_env_memcpy(dst_countable + field_offset, src_countable + field_initial_offset, field_size);
|
||||
}
|
||||
}
|
||||
|
||||
void spslr_selfpatch_patch_dpin(void* addr, uint32_t 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];
|
||||
|
||||
void* reorder_buffer = spslr_env_malloc(t->size);
|
||||
spslr_env_memset(reorder_buffer, 0, t->size);
|
||||
reorder_object(reorder_buffer, addr, target);
|
||||
|
||||
spslr_env_poke_data(addr, reorder_buffer, t->size);
|
||||
|
||||
spslr_env_free(reorder_buffer);
|
||||
}
|
||||
|
||||
void spslr_selfpatch_patch_ipins(void) {
|
||||
for (uint32_t ipidx = 0; ipidx < spslr_ipin_cnt; ipidx++) {
|
||||
const struct spslr_ipin* ip = &spslr_ipins[ipidx];
|
||||
|
||||
int64_t value = spslr_calculate_ipin_value(ip->program);
|
||||
|
||||
switch (ip->size) {
|
||||
case 1:
|
||||
spslr_env_poke_text_8((void*)ip->addr, (uint8_t)value);
|
||||
break;
|
||||
case 2:
|
||||
spslr_env_poke_text_64((void*)ip->addr, (uint16_t)value);
|
||||
break;
|
||||
case 4:
|
||||
spslr_env_poke_text_32((void*)ip->addr, (uint32_t)value);
|
||||
break;
|
||||
case 8:
|
||||
spslr_env_poke_text_64((void*)ip->addr, (uint64_t)value);
|
||||
break;
|
||||
#ifdef SPSLR_SANITY_CHECK
|
||||
default:
|
||||
spslr_env_panic("invalid ipin size");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (spslr_do(&inst) < 0) {
|
||||
fprintf(stderr, "spslr_selfpatch failed to execute an instruction\n");
|
||||
exit(1);
|
||||
int64_t spslr_calculate_ipin_value(uint32_t start) {
|
||||
int64_t res = 0;
|
||||
|
||||
uint32_t pc = start;
|
||||
while (true) {
|
||||
#ifdef SPSLR_SANITY_CHECK
|
||||
if (pc >= spslr_ipin_op_cnt)
|
||||
spslr_env_panic("ipin op out of bounds");
|
||||
#endif
|
||||
|
||||
const struct spslr_ipin_op* op = &spslr_ipin_ops[pc++];
|
||||
switch (op->code) {
|
||||
case SPSLR_IPIN_OP_PATCH:
|
||||
break;
|
||||
case SPSLR_IPIN_OP_ADD_INITIAL_OFFSET:
|
||||
{
|
||||
uint32_t initial_offset;
|
||||
if (spslr_get_target_field_ordered(op->op0.add_initial_offset_target,
|
||||
op->op1.add_initial_offset_field, NULL, NULL, &initial_offset))
|
||||
spslr_env_panic("failed to get initial field offset");
|
||||
|
||||
res += initial_offset;
|
||||
}
|
||||
continue;
|
||||
case SPSLR_IPIN_OP_ADD_OFFSET:
|
||||
{
|
||||
uint32_t offset;
|
||||
if (spslr_get_target_field_ordered(op->op0.add_initial_offset_target,
|
||||
op->op1.add_initial_offset_field, &offset, NULL, NULL))
|
||||
spslr_env_panic("failed to get initial field offset");
|
||||
|
||||
res += offset;
|
||||
}
|
||||
continue;
|
||||
case SPSLR_IPIN_OP_SUB_INITIAL_OFFSET:
|
||||
{
|
||||
uint32_t initial_offset;
|
||||
if (spslr_get_target_field_ordered(op->op0.add_initial_offset_target,
|
||||
op->op1.add_initial_offset_field, NULL, NULL, &initial_offset))
|
||||
spslr_env_panic("failed to get initial field offset");
|
||||
|
||||
res -= initial_offset;
|
||||
}
|
||||
continue;
|
||||
case SPSLR_IPIN_OP_SUB_OFFSET:
|
||||
{
|
||||
uint32_t offset;
|
||||
if (spslr_get_target_field_ordered(op->op0.add_initial_offset_target,
|
||||
op->op1.add_initial_offset_field, &offset, NULL, NULL))
|
||||
spslr_env_panic("failed to get initial field offset");
|
||||
|
||||
res -= offset;
|
||||
}
|
||||
continue;
|
||||
case SPSLR_IPIN_OP_ADD_CONST:
|
||||
res += op->op0.add_const_value;
|
||||
continue;
|
||||
#ifdef SPSLR_SANITY_CHECK
|
||||
default:
|
||||
spslr_env_panic("invalid ipin op");
|
||||
#endif
|
||||
}
|
||||
|
||||
pc += sz;
|
||||
}
|
||||
|
||||
fprintf(stderr, "spslr_selfpatch encountered invalid instruction\n");
|
||||
exit(1);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
65
selfpatch/src/spslr_list.h
Normal file
65
selfpatch/src/spslr_list.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef SPSLR_LIST_H
|
||||
#define SPSLR_LIST_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define __packed __attribute__((packed))
|
||||
|
||||
#define SPSLR_IPIN_OP_PATCH 1
|
||||
#define SPSLR_IPIN_OP_ADD_INITIAL_OFFSET 2
|
||||
#define SPSLR_IPIN_OP_SUB_INITIAL_OFFSET 3
|
||||
#define SPSLR_IPIN_OP_ADD_OFFSET 4
|
||||
#define SPSLR_IPIN_OP_SUB_OFFSET 5
|
||||
#define SPSLR_IPIN_OP_ADD_CONST 6
|
||||
|
||||
#define SPSLR_FLAG_FIELD_FIXED 1
|
||||
|
||||
struct spslr_target {
|
||||
uint32_t size;
|
||||
uint32_t fieldcnt;
|
||||
uint32_t fieldoff; // Offset into spslr_target_field array
|
||||
} __packed;
|
||||
|
||||
struct spslr_target_field {
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
uint32_t alignment;
|
||||
uint32_t flags;
|
||||
} __packed;
|
||||
|
||||
struct spslr_ipin {
|
||||
uint64_t addr;
|
||||
uint32_t size;
|
||||
uint32_t program; // Index in spslr_ipin_op array
|
||||
} __packed;
|
||||
|
||||
struct spslr_ipin_op {
|
||||
uint32_t code;
|
||||
|
||||
union {
|
||||
uint32_t patch_unused;
|
||||
uint32_t add_initial_offset_target;
|
||||
uint32_t sub_initial_offset_target;
|
||||
uint32_t add_offset_target;
|
||||
uint32_t sub_offset_target;
|
||||
int32_t add_const_value;
|
||||
} op0;
|
||||
|
||||
union {
|
||||
uint32_t patch_unused;
|
||||
uint32_t add_initial_offset_field;
|
||||
uint32_t sub_initial_offset_field;
|
||||
uint32_t add_offset_field;
|
||||
uint32_t sub_offset_field;
|
||||
uint32_t add_const_unused;
|
||||
} op1;
|
||||
} __packed;
|
||||
|
||||
struct spslr_dpin {
|
||||
uint64_t addr;
|
||||
uint32_t target; // Index in spslr_target array
|
||||
} __packed;
|
||||
|
||||
#undef __packed
|
||||
|
||||
#endif
|
||||
21
selfpatch/src/spslr_list_link.h
Normal file
21
selfpatch/src/spslr_list_link.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef SPSLR_LIST_LINK_H
|
||||
#define SPSLR_LIST_LINK_H
|
||||
|
||||
#include "spslr_list.h"
|
||||
|
||||
extern uint32_t spslr_target_cnt;
|
||||
extern struct spslr_target spslr_targets[];
|
||||
|
||||
extern uint32_t spslr_target_field_cnt;
|
||||
extern struct spslr_target_field spslr_target_fields[];
|
||||
|
||||
extern uint32_t spslr_ipin_cnt;
|
||||
extern struct spslr_ipin spslr_ipins[];
|
||||
|
||||
extern uint32_t spslr_ipin_op_cnt;
|
||||
extern struct spslr_ipin_op spslr_ipin_ops[];
|
||||
|
||||
extern uint32_t spslr_dpin_cnt;
|
||||
extern struct spslr_dpin spslr_dpins[];
|
||||
|
||||
#endif
|
||||
@ -1,324 +0,0 @@
|
||||
#ifndef SPSLR_PROGRAM_H
|
||||
#define SPSLR_PROGRAM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SPSLR_FLAG_FIELD_FIXED 1
|
||||
|
||||
#define OPCODE_SPSLR_TARGET 1
|
||||
#define OPCODE_SPSLR_FIELD 2
|
||||
#define OPCODE_SPSLR_RANDOMIZE 3
|
||||
#define OPCODE_SPSLR_IPATCH 4
|
||||
#define OPCODE_SPSLR_DPATCH 5
|
||||
#define OPCODE_SPSLR_EXIT 6
|
||||
|
||||
enum SPSLR_OP {
|
||||
SPSLR_TARGET, // uid, size, field count
|
||||
SPSLR_FIELD, // offset, size, alignment, flags
|
||||
SPSLR_RANDOMIZE, // target uid
|
||||
SPSLR_IPATCH, // ptr, size, target uid, field idx (not offset!)
|
||||
SPSLR_DPATCH, // ptr, target uid
|
||||
SPSLR_EXIT
|
||||
};
|
||||
|
||||
struct SPSLR_INST {
|
||||
enum SPSLR_OP op;
|
||||
|
||||
union {
|
||||
uint32_t target_uid;
|
||||
uint32_t field_offset;
|
||||
uint32_t randomize_target;
|
||||
uint64_t ipatch_ptr;
|
||||
uint64_t dpatch_ptr;
|
||||
} op0;
|
||||
|
||||
union {
|
||||
uint32_t target_size;
|
||||
uint32_t field_size;
|
||||
uint32_t ipatch_size;
|
||||
uint32_t dpatch_target;
|
||||
} op1;
|
||||
|
||||
union {
|
||||
uint32_t target_fieldcnt;
|
||||
uint32_t field_alignment;
|
||||
uint32_t ipatch_target;
|
||||
} op2;
|
||||
|
||||
union {
|
||||
uint32_t field_flags;
|
||||
uint32_t ipatch_field;
|
||||
} op3;
|
||||
};
|
||||
|
||||
static inline int spslr_inst_dump_opcode(const struct SPSLR_INST* inst, uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
switch (inst->op) {
|
||||
case SPSLR_TARGET:
|
||||
*buf = OPCODE_SPSLR_TARGET; return 1;
|
||||
case SPSLR_FIELD:
|
||||
*buf = OPCODE_SPSLR_FIELD; return 1;
|
||||
case SPSLR_RANDOMIZE:
|
||||
*buf = OPCODE_SPSLR_RANDOMIZE; return 1;
|
||||
case SPSLR_IPATCH:
|
||||
*buf = OPCODE_SPSLR_IPATCH; return 1;
|
||||
case SPSLR_DPATCH:
|
||||
*buf = OPCODE_SPSLR_DPATCH; return 1;
|
||||
case SPSLR_EXIT:
|
||||
*buf = OPCODE_SPSLR_EXIT; return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int spslr_inst_load_opcode(struct SPSLR_INST* inst, const uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
switch (*buf) {
|
||||
case OPCODE_SPSLR_TARGET:
|
||||
inst->op = SPSLR_TARGET; return 1;
|
||||
case OPCODE_SPSLR_FIELD:
|
||||
inst->op = SPSLR_FIELD; return 1;
|
||||
case OPCODE_SPSLR_RANDOMIZE:
|
||||
inst->op = SPSLR_RANDOMIZE; return 1;
|
||||
case OPCODE_SPSLR_IPATCH:
|
||||
inst->op = SPSLR_IPATCH; return 1;
|
||||
case OPCODE_SPSLR_DPATCH:
|
||||
inst->op = SPSLR_DPATCH; return 1;
|
||||
case OPCODE_SPSLR_EXIT:
|
||||
inst->op = SPSLR_EXIT; return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#define DUMP_OP_RET(field) { memcpy(buf, &field, sizeof(field)); return sizeof(field); }
|
||||
#define LOAD_OP_RET(field) { memcpy(&field, buf, sizeof(field)); return sizeof(field); }
|
||||
|
||||
static inline int spslr_inst_dump_op0(const struct SPSLR_INST* inst, uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
switch (inst->op) {
|
||||
case SPSLR_TARGET:
|
||||
DUMP_OP_RET(inst->op0.target_uid);
|
||||
case SPSLR_FIELD:
|
||||
DUMP_OP_RET(inst->op0.field_offset);
|
||||
case SPSLR_RANDOMIZE:
|
||||
DUMP_OP_RET(inst->op0.randomize_target);
|
||||
case SPSLR_IPATCH:
|
||||
DUMP_OP_RET(inst->op0.ipatch_ptr);
|
||||
case SPSLR_DPATCH:
|
||||
DUMP_OP_RET(inst->op0.dpatch_ptr);
|
||||
case SPSLR_EXIT:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int spslr_inst_load_op0(struct SPSLR_INST* inst, const uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
switch (inst->op) {
|
||||
case SPSLR_TARGET:
|
||||
LOAD_OP_RET(inst->op0.target_uid);
|
||||
case SPSLR_FIELD:
|
||||
LOAD_OP_RET(inst->op0.field_offset);
|
||||
case SPSLR_RANDOMIZE:
|
||||
LOAD_OP_RET(inst->op0.randomize_target);
|
||||
case SPSLR_IPATCH:
|
||||
LOAD_OP_RET(inst->op0.ipatch_ptr);
|
||||
case SPSLR_DPATCH:
|
||||
LOAD_OP_RET(inst->op0.dpatch_ptr);
|
||||
case SPSLR_EXIT:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int spslr_inst_dump_op1(const struct SPSLR_INST* inst, uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
switch (inst->op) {
|
||||
case SPSLR_TARGET:
|
||||
DUMP_OP_RET(inst->op1.target_size);
|
||||
case SPSLR_FIELD:
|
||||
DUMP_OP_RET(inst->op1.field_size);
|
||||
case SPSLR_IPATCH:
|
||||
DUMP_OP_RET(inst->op1.ipatch_size);
|
||||
case SPSLR_DPATCH:
|
||||
DUMP_OP_RET(inst->op1.dpatch_target);
|
||||
case SPSLR_RANDOMIZE:
|
||||
case SPSLR_EXIT:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int spslr_inst_load_op1(struct SPSLR_INST* inst, const uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
switch (inst->op) {
|
||||
case SPSLR_TARGET:
|
||||
LOAD_OP_RET(inst->op1.target_size);
|
||||
case SPSLR_FIELD:
|
||||
LOAD_OP_RET(inst->op1.field_size);
|
||||
case SPSLR_IPATCH:
|
||||
LOAD_OP_RET(inst->op1.ipatch_size);
|
||||
case SPSLR_DPATCH:
|
||||
LOAD_OP_RET(inst->op1.dpatch_target);
|
||||
case SPSLR_RANDOMIZE:
|
||||
case SPSLR_EXIT:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int spslr_inst_dump_op2(const struct SPSLR_INST* inst, uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
switch (inst->op) {
|
||||
case SPSLR_TARGET:
|
||||
DUMP_OP_RET(inst->op2.target_fieldcnt);
|
||||
case SPSLR_FIELD:
|
||||
DUMP_OP_RET(inst->op2.field_alignment);
|
||||
case SPSLR_IPATCH:
|
||||
DUMP_OP_RET(inst->op2.ipatch_target);
|
||||
case SPSLR_DPATCH:
|
||||
case SPSLR_RANDOMIZE:
|
||||
case SPSLR_EXIT:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int spslr_inst_load_op2(struct SPSLR_INST* inst, const uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
switch (inst->op) {
|
||||
case SPSLR_TARGET:
|
||||
LOAD_OP_RET(inst->op2.target_fieldcnt);
|
||||
case SPSLR_FIELD:
|
||||
LOAD_OP_RET(inst->op2.field_alignment);
|
||||
case SPSLR_IPATCH:
|
||||
LOAD_OP_RET(inst->op2.ipatch_target);
|
||||
case SPSLR_DPATCH:
|
||||
case SPSLR_RANDOMIZE:
|
||||
case SPSLR_EXIT:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int spslr_inst_dump_op3(const struct SPSLR_INST* inst, uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
switch (inst->op) {
|
||||
case SPSLR_FIELD:
|
||||
DUMP_OP_RET(inst->op3.field_flags);
|
||||
case SPSLR_IPATCH:
|
||||
DUMP_OP_RET(inst->op3.ipatch_field);
|
||||
case SPSLR_TARGET:
|
||||
case SPSLR_DPATCH:
|
||||
case SPSLR_RANDOMIZE:
|
||||
case SPSLR_EXIT:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int spslr_inst_load_op3(struct SPSLR_INST* inst, const uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
switch (inst->op) {
|
||||
case SPSLR_FIELD:
|
||||
LOAD_OP_RET(inst->op3.field_flags);
|
||||
case SPSLR_IPATCH:
|
||||
LOAD_OP_RET(inst->op3.ipatch_field);
|
||||
case SPSLR_TARGET:
|
||||
case SPSLR_DPATCH:
|
||||
case SPSLR_RANDOMIZE:
|
||||
case SPSLR_EXIT:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int spslr_inst_dump(const struct SPSLR_INST* inst, uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
int opcode_sz, op0_sz, op1_sz, op2_sz, op3_sz;
|
||||
|
||||
if ((opcode_sz = spslr_inst_dump_opcode(inst, buf)) < 0)
|
||||
return -1;
|
||||
buf += opcode_sz;
|
||||
|
||||
if ((op0_sz = spslr_inst_dump_op0(inst, buf)) < 0)
|
||||
return -1;
|
||||
buf += op0_sz;
|
||||
|
||||
if ((op1_sz = spslr_inst_dump_op1(inst, buf)) < 0)
|
||||
return -1;
|
||||
buf += op1_sz;
|
||||
|
||||
if ((op2_sz = spslr_inst_dump_op2(inst, buf)) < 0)
|
||||
return -1;
|
||||
buf += op2_sz;
|
||||
|
||||
if ((op3_sz = spslr_inst_dump_op3(inst, buf)) < 0)
|
||||
return -1;
|
||||
buf += op3_sz;
|
||||
|
||||
return opcode_sz + op0_sz + op1_sz + op2_sz + op3_sz;
|
||||
}
|
||||
|
||||
static inline int spslr_inst_load(struct SPSLR_INST* inst, const uint8_t* buf) {
|
||||
if (!inst || !buf)
|
||||
return -1;
|
||||
|
||||
int opcode_sz, op0_sz, op1_sz, op2_sz, op3_sz;
|
||||
|
||||
if ((opcode_sz = spslr_inst_load_opcode(inst, buf)) < 0)
|
||||
return -1;
|
||||
buf += opcode_sz;
|
||||
|
||||
if ((op0_sz = spslr_inst_load_op0(inst, buf)) < 0)
|
||||
return -1;
|
||||
buf += op0_sz;
|
||||
|
||||
if ((op1_sz = spslr_inst_load_op1(inst, buf)) < 0)
|
||||
return -1;
|
||||
buf += op1_sz;
|
||||
|
||||
if ((op2_sz = spslr_inst_load_op2(inst, buf)) < 0)
|
||||
return -1;
|
||||
buf += op2_sz;
|
||||
|
||||
if ((op3_sz = spslr_inst_load_op3(inst, buf)) < 0)
|
||||
return -1;
|
||||
buf += op3_sz;
|
||||
|
||||
return opcode_sz + op0_sz + op1_sz + op2_sz + op3_sz;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,5 +1,6 @@
|
||||
#include "targets.h"
|
||||
#include "spslr_program.h"
|
||||
|
||||
#include "spslr_list.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
@ -96,14 +97,14 @@ static void clear_targets() {
|
||||
targets = NULL;
|
||||
}
|
||||
|
||||
int spslr_target(uint32_t uid, uint32_t size, uint32_t fieldcnt) {
|
||||
int spslr_register_target(uint32_t uid, uint32_t size, uint32_t fieldcnt) {
|
||||
if (find_target(uid))
|
||||
return -1;
|
||||
|
||||
return add_target(uid, size, fieldcnt);
|
||||
}
|
||||
|
||||
int spslr_field(uint32_t target, uint32_t offset, uint32_t size, uint32_t alignment, uint32_t flags) {
|
||||
int spslr_register_target_field(uint32_t target, uint32_t offset, uint32_t size, uint32_t alignment, uint32_t flags) {
|
||||
struct Target* t = find_target(target);
|
||||
if (!t)
|
||||
return -1;
|
||||
@ -380,30 +381,39 @@ int spslr_get_target_size(uint32_t target, uint32_t* size) {
|
||||
|
||||
int spslr_get_target_fieldcnt(uint32_t target, uint32_t* cnt) {
|
||||
const struct Target* t = find_target(target);
|
||||
if (!t || !cnt)
|
||||
if (!t)
|
||||
return -1;
|
||||
|
||||
*cnt = t->field_count;
|
||||
if (cnt)
|
||||
*cnt = t->field_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spslr_get_target_field_ordered(uint32_t target, uint32_t field, uint32_t* offset,
|
||||
uint32_t* size, uint32_t* initial_offset) {
|
||||
const struct Target* t = find_target(target);
|
||||
if (!t || !offset || !size || !initial_offset)
|
||||
if (!t)
|
||||
return -1;
|
||||
|
||||
if (field >= t->field_count)
|
||||
return -1;
|
||||
|
||||
const struct Field* f = &t->fields[field];
|
||||
*offset = f->offset;
|
||||
*size = f->size;
|
||||
*initial_offset = f->initial_offset;
|
||||
|
||||
if (offset)
|
||||
*offset = f->offset;
|
||||
|
||||
if (size)
|
||||
*size = f->size;
|
||||
|
||||
if (initial_offset)
|
||||
*initial_offset = f->initial_offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spslr_targets_clear() {
|
||||
void spslr_clear_targets() {
|
||||
clear_targets();
|
||||
}
|
||||
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int spslr_target(uint32_t uid, uint32_t size, uint32_t fieldcnt);
|
||||
int spslr_field(uint32_t target, uint32_t offset, uint32_t size, uint32_t alignment, uint32_t flags);
|
||||
int spslr_register_target(uint32_t uid, uint32_t size, uint32_t fieldcnt);
|
||||
int spslr_register_target_field(uint32_t target, uint32_t offset, uint32_t size, uint32_t alignment, uint32_t flags);
|
||||
int spslr_randomize(uint32_t target);
|
||||
|
||||
int spslr_get_randomized_field_offset(uint32_t target, uint32_t field, uint32_t* offset);
|
||||
@ -13,6 +13,6 @@ int spslr_get_target_fieldcnt(uint32_t target, uint32_t* cnt);
|
||||
int spslr_get_target_field_ordered(uint32_t target, uint32_t field, uint32_t* offset,
|
||||
uint32_t* size, uint32_t* initial_offset);
|
||||
|
||||
void spslr_targets_clear();
|
||||
void spslr_clear_targets();
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue
Block a user