diff --git a/selfpatch/src/targets.c b/selfpatch/src/targets.c index 8351364..3e784bf 100644 --- a/selfpatch/src/targets.c +++ b/selfpatch/src/targets.c @@ -1,6 +1,15 @@ #include "targets.h" #include +#include + +static void seed_rand_time() { + srand(time(NULL)); +} + +static uint32_t rand_uint32() { + return (uint32_t)rand(); +} struct Field { uint32_t initial_offset; @@ -121,8 +130,163 @@ int spslr_field(uint32_t target, uint32_t offset, uint32_t size, uint32_t flags) return 0; } +struct ShuffleRegion { + uint32_t begin, end; + uint32_t fill_begin, fill_end; +}; + +static uint32_t field_alignment(const struct Field* field) { + return field->size; // Note -> alignments should be gathered by pinpoint plugin +} + +static void target_get_origin_region(const struct Target* target, struct ShuffleRegion* region, uint32_t idx) { + region->fill_begin = target->fields[idx].offset; + region->fill_end = region->fill_begin + target->fields[idx].size; + + if (idx <= 0) + region->begin = 0; + else + region->begin = target->fields[idx - 1].offset + target->fields[idx - 1].size; + + if (idx >= target->field_count - 1) + region->end = target->size; + else + region->end = target->fields[idx + 1].offset; +} + +static uint32_t target_get_shuffle_options(const struct Target* target, uint32_t* options, + const struct ShuffleRegion* origin, uint32_t alignment) { + uint32_t count = 0; + + uint32_t current_field = 0; + for (uint32_t offset = 0; offset < target->size; offset += alignment) { + // Placing the origin region here or further would exceed struct boundaries + uint32_t option_would_end = offset + (origin->fill_end - origin->fill_begin); + if (option_would_end > target->size) + break; + + // Fields that end before offset are irrelevant at this point + while (current_field < target->field_count && target->fields[current_field].offset + + target->fields[current_field].size <= offset) current_field++; + + // If origin->fill_begin was placed at offset, could all fields that overlap with range swap with origin? + int conflict = 0; + uint32_t origin_region_ptr = origin->begin; + for (uint32_t it = current_field; it < target->field_count; it++) { + struct Field* f = &target->fields[it]; + if (f->offset >= option_would_end) + break; + + // Could field be placed in origin? + uint32_t falign = field_alignment(f); + if (origin_region_ptr % falign != 0) + origin_region_ptr += falign - (origin_region_ptr % falign); + + origin_region_ptr += f->size; + + if (origin_region_ptr > origin->end) { + conflict = 1; + break; + } + } + + if (!conflict) + options[count++] = offset; + } + + return count; +} + +static void target_swap(struct Target* target, uint32_t origin_idx, const struct ShuffleRegion* origin_region, + uint32_t new_offset) { + int origin_pulled = 0; + uint32_t origin_region_ptr = origin_region->begin; + uint32_t option_fill_end = new_offset + (origin_region->fill_end - origin_region->fill_begin); + for (uint32_t it = 0; it < target->field_count; it++) { + // Fields that end before new_offset can stay there + if (target->fields[it].offset + target->fields[it].size <= new_offset) + continue; + + // Fields that start after where origin goes are irrelevant + if (target->fields[it].offset >= option_fill_end) + break; + + uint32_t falign = field_alignment(&target->fields[it]); + if (origin_region_ptr % falign != 0) + origin_region_ptr += falign - (origin_region_ptr % falign); + + // First field in swap region is exchanged with origin + if (!origin_pulled) { + origin_pulled = 1; + + struct Field tmp = target->fields[it]; + target->fields[it] = target->fields[origin_idx]; + target->fields[origin_idx] = tmp; + + // Update origin field + target->fields[it].offset = new_offset; + + // Update swapped field + target->fields[origin_idx].offset = origin_region_ptr; + origin_region_ptr += target->fields[origin_idx].size; + + continue; + } + + // For all other fields in swap region, pull all until origin_idx one forward and place at origin_idx + struct Field tmp = target->fields[it]; + + for (uint32_t pull_it = it + 1; pull_it <= origin_idx; pull_it++) + target->fields[it - 1] = target->fields[it]; + + target->fields[origin_idx] = tmp; + } +} + +static void target_shuffle_one(struct Target* target) { + if (!target || !target->field_count) + return; + + uint32_t origin = rand_uint32() % target->field_count; + uint32_t origin_alignment = field_alignment(&target->fields[origin]); + + uint32_t max_options = target->size / origin_alignment; + uint32_t* swap_options = (uint32_t*)malloc(sizeof(uint32_t) * max_options); // match fill_begin + + struct ShuffleRegion origin_region; + target_get_origin_region(target, &origin_region, origin); + + uint32_t option_count = target_get_shuffle_options(target, swap_options, &origin_region, origin_alignment); + + if (!option_count) { + free(swap_options); + return; + } + + uint32_t selected_option_idx = rand_uint32() % option_count; + uint32_t selected_option = swap_options[selected_option_idx]; + + free(swap_options); + + target_swap(target, origin, &origin_region, selected_option); +} + int spslr_randomize(uint32_t target) { - // TODO + struct Target* t = find_target(target); + if (!t) + return -1; + + if (t->field_count != t->present_field_count) + return -1; + + seed_rand_time(); // Note -> this is obviously not sufficient + + uint32_t shuffle_count = t->field_count * 2; + for (uint32_t i = 0; i < shuffle_count; i++) + target_shuffle_one(t); + + // TODO final_fields + return 0; }