diff --git a/mixr/mixr.c b/mixr/mixr.c index 74eb7ea4aaf79c0c36bfce1ddf54ec91d382f79c..1d618f9ec530f9b191c276fd68e3d49b3f503f0c 100644 --- a/mixr/mixr.c +++ b/mixr/mixr.c @@ -13,14 +13,18 @@ #include <itox.h> #endif +#include <mixr_rw.h> + #define PROT_NONE 0x0 #define PROT_READ 0x1 #define PROT_WRITE 0x2 #define PROT_EXEC 0x4 +#ifndef TEST #define SYS_mprotect 10 +#endif -#define DT_ENTRY_SIZE 8 +#define DT_ENTRY_SIZE (8+2) #define DT_LENGTH_SIZE 8 #define DT_FIXED_SIZE_SIZE 8 #define DT_FIRST_ENTRY_OFFSET (DT_LENGTH_SIZE+DT_FIXED_SIZE_SIZE) @@ -37,6 +41,7 @@ #ifdef DEBUG #define print_str_debug mixr_print_str #define print_int_debug mixr_print_int + #define print_addr_debug mixr_print_addr #define print_unsigned_long_long_debug mixr_print_unsigned_long_long #else #define print_str_debug(a) @@ -45,7 +50,8 @@ #endif -uint8_t swap_space[40]; +uint8_t swap_space[MIXR_FIXED_SIZE]; + #ifdef DEBUG #define write_fd 2 void mixr_print_str(char *s) @@ -64,6 +70,10 @@ void mixr_print_unsigned_long_long(unsigned long long x) itox(x,buf); write(write_fd,buf,strlen(buf)); } +void mixr_print_addr(void *x) +{ + mixr_print_unsigned_long_long((unsigned long long)x); +} #endif uint64_t read_random64(void) { @@ -87,11 +97,19 @@ void _memcpy(void *dst, const void *src, unsigned long int len) return; } +void make_writable(void *addr, size_t len) +{ +} + +void make_unwritable(void *addr, size_t len) +{ +} + int _mprotect(void *addr, size_t len, int flags); int _mprotect(void *addr, size_t len, int flags) { #ifdef TEST - printf("_mprotect: addr: %llx\n", addr); + printf("_mprotect: addr: %p\n", addr); //return mprotect(addr, len, flags); return 0; #else @@ -99,6 +117,53 @@ int _mprotect(void *addr, size_t len, int flags) #endif } +uint16_t rw_table_entry_count(void *rw_table_addr) +{ + uint16_t entry_count = 0; + + _memcpy(&entry_count, (const void*)rw_table_addr, sizeof(uint16_t)); + + return entry_count; +} + +struct rw_table_entry rw_table_read_entry(void *rw_table_addr, unsigned int entry) +{ + struct rw_table_entry rw_entry = {}; + void *entry_address = NULL; + uint16_t entry_count = rw_table_entry_count(rw_table_addr); + + if (entry_count < entry) + return rw_entry; + + entry_address = (void*)(rw_table_addr + + entry*RW_TABLE_ENTRY_SIZE + + RW_TABLE_HEADER_SIZE); + _memcpy(&rw_entry, entry_address, sizeof(struct rw_table_entry)); + + return rw_entry; +} + +void rw_table_write_entry(void *rw_table_addr, unsigned int entry, struct rw_table_entry rw_entry) +{ + void *entry_address = NULL; + uint16_t entry_count = rw_table_entry_count(rw_table_addr); + + if (entry_count < entry) + return; + + entry_address = (void*)(rw_table_addr + + entry*RW_TABLE_ENTRY_SIZE + + RW_TABLE_HEADER_SIZE); + _memcpy(entry_address, &rw_entry, sizeof(struct rw_table_entry)); +} + +#ifdef TEST +void rw_table_print_entry(struct rw_table_entry rw_entry) +{ + printf("RW Entry: {%hd, 0x%hhx, 0x%hhx, 0x%lx}\n", rw_entry.instruction_offset,rw_entry.rewrite_offset, rw_entry.rewrite_length,rw_entry.absolute_value); +} +#endif + uint64_t dt_table_length(void *dt_table_addr) { uint64_t table_length = 0; @@ -121,7 +186,7 @@ uint64_t dt_fixed_size(void *dt_table_addr) uint64_t dt_table_entry_address(void *dt_table_addr, unsigned int entry) { uint64_t entry_offset = entry * DT_ENTRY_SIZE + DT_FIRST_ENTRY_OFFSET; - return (((uint64_t)dt_table_addr)+entry_offset); + return (uint64_t)(dt_table_addr+entry_offset); } uint64_t dt_table_read_entry_address(void *dt_table_addr, unsigned int entry) @@ -135,6 +200,15 @@ uint64_t dt_table_read_entry_address(void *dt_table_addr, unsigned int entry) return entry_address; } +uint16_t dt_table_read_entry_offset(void *dt_table_addr, unsigned int entry) +{ + uint16_t entry_offset; + _memcpy(&entry_offset, + (const void*)(dt_table_entry_address(dt_table_addr, entry)+8), + sizeof(uint16_t)); + return entry_offset; +} + void dt_table_write_entry_address(void *dt_table_addr, unsigned int entry, uint64_t entry_address) { _memcpy((void*)dt_table_entry_address(dt_table_addr, entry), @@ -142,6 +216,13 @@ void dt_table_write_entry_address(void *dt_table_addr, unsigned int entry, uint6 sizeof(uint64_t)); } +void dt_table_write_entry_offset(void *dt_table_addr, unsigned int entry, uint16_t entry_offset) +{ + _memcpy((void*)(dt_table_entry_address(dt_table_addr, entry)+8), + (const void*)&entry_offset, + sizeof(uint16_t)); +} + void dt_table_swap_entry_addresses(void *dt_table_addr, unsigned int a, unsigned int b) { uint64_t address_entry_a = dt_table_read_entry_address(dt_table_addr, a); @@ -153,7 +234,7 @@ void dt_table_swap_entry_addresses(void *dt_table_addr, unsigned int a, unsigned void dt_table_swap_entry_contents(void *dt_table_addr, unsigned int a, unsigned int b) { - uint64_t fixed_size = 40; //dt_fixed_size(dt_table_addr); + uint64_t fixed_size = MIXR_FIXED_SIZE; //void *swap_space = (void*)malloc(fixed_size); void *a_contents_addr = (void*)dt_table_read_entry_address(dt_table_addr,a); void *b_contents_addr = (void*)dt_table_read_entry_address(dt_table_addr,b); @@ -168,21 +249,21 @@ void dt_table_swap_entry_contents(void *dt_table_addr, unsigned int a, unsigned * The assumption is that we are '-w' in these * pages when we start. */ - _mprotect((void*)(((uint64_t)dt_table_addr)&PAGE_MASK), + _mprotect((void*)(((uintptr_t)dt_table_addr)&PAGE_MASK), table_length + PAGE_SIZE, PROT_READ|PROT_EXEC|PROT_WRITE); - _mprotect((void*)(((uint64_t)a_contents_addr)&PAGE_MASK), + _mprotect((void*)(((uintptr_t)a_contents_addr)&PAGE_MASK), PAGE_SIZE + PAGE_SIZE, PROT_READ|PROT_EXEC|PROT_WRITE); - _mprotect((void*)(((uint64_t)b_contents_addr)&PAGE_MASK), + _mprotect((void*)(((uintptr_t)b_contents_addr)&PAGE_MASK), PAGE_SIZE + PAGE_SIZE, PROT_READ|PROT_EXEC|PROT_WRITE); #ifdef DEBUG print_str_debug("swap_space: "); - print_int_debug((void*)(&swap_space)); + print_addr_debug((void*)(&swap_space)); print_str_debug("\n"); print_str_debug("b_contents_addr: "); - print_int_debug(a_contents_addr); + print_addr_debug(a_contents_addr); print_str_debug("\n"); print_str_debug("fixed_size: "); print_int_debug(fixed_size); @@ -196,10 +277,10 @@ void dt_table_swap_entry_contents(void *dt_table_addr, unsigned int a, unsigned #ifdef DEBUG print_str_debug("a: "); print_int_debug(dt_table_read_entry_address(dt_table_addr, a)); - print_str_debug("\n "); + print_str_debug("\n"); print_str_debug("b: "); print_int_debug(dt_table_read_entry_address(dt_table_addr, b)); - print_str_debug("\n "); + print_str_debug("\n"); #endif dt_table_swap_entry_addresses(dt_table_addr, a, b); @@ -207,19 +288,91 @@ void dt_table_swap_entry_contents(void *dt_table_addr, unsigned int a, unsigned #ifdef DEBUG print_str_debug("a: "); print_int_debug(dt_table_read_entry_address(dt_table_addr, a)); - print_str_debug("\n "); + print_str_debug("\n"); print_str_debug("b: "); print_int_debug(dt_table_read_entry_address(dt_table_addr, b)); - print_str_debug("\n "); + print_str_debug("\n"); #endif - _mprotect((void*)(((uint64_t)dt_table_addr)&PAGE_MASK), + _mprotect((void*)((uintptr_t)(dt_table_addr)&PAGE_MASK), table_length + PAGE_SIZE, PROT_READ|PROT_EXEC); - _mprotect((void*)(((uint64_t)a_contents_addr)&PAGE_MASK), + _mprotect((void*)((uintptr_t)(a_contents_addr)&PAGE_MASK), PAGE_SIZE + PAGE_SIZE, PROT_READ|PROT_EXEC); - _mprotect((void*)(((uint64_t)b_contents_addr)&PAGE_MASK), + _mprotect((void*)((uintptr_t)(b_contents_addr)&PAGE_MASK), + PAGE_SIZE + PAGE_SIZE, + PROT_READ|PROT_EXEC); +} + +void mixr_do_rw(uint64_t dollop_start, struct rw_table_entry rw_entry) +{ + uint64_t next_pc_address = dollop_start + rw_entry.instruction_offset; + uint64_t relative = next_pc_address - rw_entry.rewrite_offset; + void *rw_val = NULL; + uint8_t rw8_val; + uint16_t rw16_val; + uint32_t rw32_val; + uint64_t rw48_val; + uint64_t rw64_val; + +#if DEBUG + print_str_debug("Abs "); + print_unsigned_long_long_debug(rw_entry.absolute_value); + print_str_debug(" to (0x"); + print_addr_debug((void*)next_pc_address); + print_str_debug(") "); + print_int_debug(rw_entry.absolute_value-next_pc_address); + print_str_debug(" at "); + print_addr_debug((void*)relative); + print_str_debug("\n"); +#endif + + switch (rw_entry.rewrite_length) + { + case 0x0: + { + rw8_val = rw_entry.absolute_value-next_pc_address; + rw_val = (void*)&rw8_val; + break; + } + case 0x1: + { + rw16_val = rw_entry.absolute_value-next_pc_address; + rw_val = (void*)&rw16_val; + break; + } + case 0x3: + { + rw32_val = rw_entry.absolute_value-next_pc_address; + rw_val = (void*)&rw32_val; + break; + } + case 0x5: + { + rw48_val = rw_entry.absolute_value-next_pc_address; + rw_val = (void*)&rw48_val; + break; + } + case 0x7: + { + rw64_val = rw_entry.absolute_value-next_pc_address; + rw_val = (void*)&rw64_val; + break; + } + } +#ifdef DEBUG + if (rw_val == NULL) + rw_val = 0xdead; +#else + assert(rw_val); +#endif + + _mprotect((void*)(((uintptr_t)relative)&PAGE_MASK), + PAGE_SIZE + PAGE_SIZE, + PROT_READ|PROT_EXEC|PROT_WRITE); + _memcpy((void*)relative, rw_val, rw_entry.rewrite_length); + _mprotect((void*)(((uintptr_t)relative)&PAGE_MASK), PAGE_SIZE + PAGE_SIZE, PROT_READ|PROT_EXEC); } @@ -233,16 +386,16 @@ void dt_table_swap_entry_contents(void *dt_table_addr, unsigned int a, unsigned output = _rbp_value; \ } \ -void zipr_hook_start(unsigned int id, +void zipr_hook_start(unsigned long long id, unsigned long long rax, unsigned long long rsp) { - uint64_t table_addr = 0; + void *table_addr = 0; uint64_t table_length = 0; uint64_t table_iterator = 2; uint64_t ra = 0, rbp_value = 0; - table_addr = (uint64_t)id; + table_addr = (void*)id; table_length = dt_table_length(table_addr); //a = read_random64() % table_length; //b = read_random64() % table_length; @@ -257,31 +410,46 @@ void zipr_hook_start(unsigned int id, #ifdef DEBUG print_str_debug("rbp_value:"); - print_int_debug(rbp_value); + print_unsigned_long_long_debug(rbp_value); print_str_debug("\n"); print_str_debug("ra:"); - print_int_debug(ra); + print_unsigned_long_long_debug(ra); print_str_debug("\n"); #endif - +#if 1 for (table_iterator = 2; table_iterator<table_length; table_iterator+=2) { uint64_t a = table_iterator, b = a-1; + uint64_t dt_address_a = dt_table_read_entry_address(table_addr, a); + uint16_t dt_offset_a = dt_table_read_entry_offset(table_addr, a); + uint64_t rw_address_a = dt_address_a + dt_offset_a; + uint16_t rw_entry_count_a = rw_table_entry_count((void*)rw_address_a); + uint64_t dt_address_b = dt_table_read_entry_address(table_addr, b); + uint16_t dt_offset_b = dt_table_read_entry_offset(table_addr, b); + uint64_t rw_address_b = dt_address_b + dt_offset_b; + uint16_t rw_entry_count_b = rw_table_entry_count((void*)rw_address_b); + uint16_t rw_entry_count_iterator = 0; #ifdef DEBUG print_str_debug("Swapping:"); - print_int_debug(a); - print_str_debug(":"); - print_int_debug(dt_table_read_entry_address(table_addr, a)); - print_str_debug("<->"); + print_unsigned_long_long_debug(a); + print_str_debug(": ("); + print_addr_debug((void*)dt_address_a); + print_str_debug(","); + print_int_debug(dt_offset_a); + print_str_debug(" #"); + print_int_debug(rw_entry_count_a); + print_str_debug(") <-> "); print_int_debug(b); - print_str_debug(":"); - print_int_debug(dt_table_read_entry_address(table_addr, b)); - print_str_debug("\n"); + print_str_debug(": ("); + print_addr_debug((void*)dt_address_b); + print_str_debug(","); + print_int_debug(dt_offset_b); + print_str_debug(" #"); + print_int_debug(rw_entry_count_b); + print_str_debug(")\n"); #endif - if ((dt_table_read_entry_address(table_addr, a) <= ra && - (dt_table_read_entry_address(table_addr, a)+MIXR_FIXED_SIZE) >= ra) || - (dt_table_read_entry_address(table_addr, b) <= ra && - (dt_table_read_entry_address(table_addr, b)+MIXR_FIXED_SIZE) >= ra)) + if ((dt_address_a <= ra && (dt_address_a+MIXR_FIXED_SIZE) >= ra) || + (dt_address_b <= ra && (dt_address_b+MIXR_FIXED_SIZE) >= ra)) { #ifdef DEBUG print_str_debug("Skipping swap "); @@ -293,21 +461,59 @@ void zipr_hook_start(unsigned int id, continue; } dt_table_swap_entry_contents(table_addr, a, b); + + /* + * Rewrite a. + */ + for (rw_entry_count_iterator = 0; + rw_entry_count_iterator<rw_entry_count_a; + rw_entry_count_iterator++) + { + /* + * Since we already swapped, the old a is now + * at b. To reuse variable assignments from above, + * this looks more confusing. + */ + mixr_do_rw(dt_address_b, + rw_table_read_entry((void*)(dt_address_b+dt_offset_a), + rw_entry_count_iterator)); + } + /* + * Rewrite b. + */ + for (rw_entry_count_iterator = 0; + rw_entry_count_iterator<rw_entry_count_b; + rw_entry_count_iterator++) + { + /* + * Since we already swapped, the old b is now + * at a. To reuse variable assignments from above, + * this looks more confusing. + */ + mixr_do_rw(dt_address_a, + rw_table_read_entry((void*)(dt_address_a+dt_offset_b), + rw_entry_count_iterator)); + } } +#endif } #ifdef TEST -int main() +void test_dollop_table(void) { uint64_t table_entries = 11; uint64_t table_fixed_size = MIXR_FIXED_SIZE; uint64_t table_entry_address = 0xff00ff00; + uint16_t table_entry_offset = 0; void *table = (void*)malloc((table_entries*DT_ENTRY_SIZE)+DT_FIRST_ENTRY_OFFSET); unsigned i = 0; int nine = 9; int ten = 10; + uint16_t nine_offset = 0x9; + uint16_t ten_offset = 0xa; + _memcpy(table, (const void*)&table_entries, sizeof(uint64_t)); _memcpy(table, (const void*)&table_entries, sizeof(uint64_t)); _memcpy((void*)(((uint64_t)table)+(DT_LENGTH_SIZE)), @@ -317,34 +523,88 @@ int main() for (i = 0; i<table_entries-2; i++) { table_entry_address += 1; - printf("table_entry_address: (%d): %llx\n", i, table_entry_address); + table_entry_offset += 1; + printf("table_entry_address: (%d): %lx\n", i, table_entry_address); + printf("table_entry_offset: (%d): %hx\n", i, table_entry_offset); dt_table_write_entry_address(table, i, table_entry_address); + dt_table_write_entry_offset(table, i, table_entry_offset); } - dt_table_write_entry_address(table, 9, &nine); - dt_table_write_entry_address(table, 10, &ten); + dt_table_write_entry_address(table, 9, (uint64_t)&nine); + dt_table_write_entry_offset(table, 9, nine_offset); + dt_table_write_entry_address(table, 10, (uint64_t)&ten); + dt_table_write_entry_offset(table, 10, ten_offset); - printf("dt_table_length: %llu\n", dt_table_length(table)); - printf("dt_fixed_size: %llu\n", dt_fixed_size(table)); - printf("dt_table_read_entry_address(0): %llx\n", dt_table_read_entry_address(table, 0)); - printf("dt_table_read_entry_address(5): %llx\n", dt_table_read_entry_address(table, 5)); - printf("dt_table_read_entry_address(8): %llx\n", dt_table_read_entry_address(table, 8)); + printf("dt_table_length: %lu\n", dt_table_length(table)); + printf("dt_fixed_size: %lu\n", dt_fixed_size(table)); + printf("dt_table_read_entry_address(0): %lx\n", dt_table_read_entry_address(table, 0)); + printf("dt_table_read_entry_address(5): %lx\n", dt_table_read_entry_address(table, 5)); + printf("dt_table_read_entry_address(8): %lx\n", dt_table_read_entry_address(table, 8)); + printf("dt_table_read_entry_offset(0): %hx\n", dt_table_read_entry_offset(table, 0)); + printf("dt_table_read_entry_offset(5): %hx\n", dt_table_read_entry_offset(table, 5)); + printf("dt_table_read_entry_offset(8): %hx\n", dt_table_read_entry_offset(table, 8)); printf("swap 5 <-> 8\n"); dt_table_swap_entry_addresses(table, 5, 8); - printf("dt_table_read_entry_address(5): %llx\n", dt_table_read_entry_address(table, 5)); - printf("dt_table_read_entry_address(8): %llx\n", dt_table_read_entry_address(table, 8)); + printf("dt_table_read_entry_address(5): %lx\n", dt_table_read_entry_address(table, 5)); + printf("dt_table_read_entry_offset(5): %hx\n", dt_table_read_entry_offset(table, 5)); + printf("dt_table_read_entry_address(8): %lx\n", dt_table_read_entry_address(table, 8)); + printf("dt_table_read_entry_offset(8): %hx\n", dt_table_read_entry_offset(table, 8)); + printf("swap 8 <-> 0\n"); dt_table_swap_entry_addresses(table, 0, 8); - printf("dt_table_read_entry_address(0): %llx\n", dt_table_read_entry_address(table, 0)); - printf("dt_table_read_entry_address(8): %llx\n", dt_table_read_entry_address(table, 8)); + printf("dt_table_read_entry_address(0): %lx\n", dt_table_read_entry_address(table, 0)); + printf("dt_table_read_entry_offset(0): %hx\n", dt_table_read_entry_offset(table, 0)); + printf("dt_table_read_entry_address(8): %lx\n", dt_table_read_entry_address(table, 8)); + printf("dt_table_read_entry_offset(8): %hx\n", dt_table_read_entry_offset(table, 8)); - printf("dt_table_read_entry_address(9): %llx, %llx\n", dt_table_read_entry_address(table, 9), *((int*)dt_table_read_entry_address(table, 9))); - printf("dt_table_read_entry_address(10): %llx, %llx\n", dt_table_read_entry_address(table, 10), *((int*)dt_table_read_entry_address(table, 10))); + printf("dt_table_read_entry_address(9): %lx, %x\n", dt_table_read_entry_address(table, 9), *((int*)dt_table_read_entry_address(table, 9))); + printf("dt_table_read_entry_offset(9): %hx\n", dt_table_read_entry_offset(table, 9)); + printf("dt_table_read_entry_address(10): %lx, %x\n", dt_table_read_entry_address(table, 10), *((int*)dt_table_read_entry_address(table, 10))); + printf("dt_table_read_entry_offset(10): %hx\n", dt_table_read_entry_offset(table, 10)); + dt_table_swap_entry_contents(table, 10, 9); - printf("dt_table_read_entry_address(9): %llx, %llx\n", dt_table_read_entry_address(table, 9), *((int*)dt_table_read_entry_address(table, 9))); - printf("dt_table_read_entry_address(10): %llx, %llx\n", dt_table_read_entry_address(table, 10), *((int*)dt_table_read_entry_address(table, 10))); + + printf("dt_table_read_entry_address(9): %lx, %x\n", dt_table_read_entry_address(table, 9), *((int*)dt_table_read_entry_address(table, 9))); + printf("dt_table_read_entry_offset(9): %hx\n", dt_table_read_entry_offset(table, 9)); + printf("dt_table_read_entry_address(10): %lx, %x\n", dt_table_read_entry_address(table, 10), *((int*)dt_table_read_entry_address(table, 10))); + printf("dt_table_read_entry_offset(10): %hx\n", dt_table_read_entry_offset(table, 10)); +} + +void test_rw_table(void) +{ + struct rw_table_header *rw_table = NULL; + int entry_count = 11; + struct rw_table_entry entry_ten = {1, 2, 3, 4}; + struct rw_table_entry entry_eleven = {11, 22, 33, 44}; + struct rw_table_entry entry_fiftyk = {111, 222, 333, 444}; + + rw_table = (struct rw_table_header*)malloc(sizeof(struct rw_table_header) + (entry_count*sizeof(struct rw_table_entry))); + + rw_table->entry_count = 11; + + rw_table_write_entry((void*)rw_table, 10, entry_ten); + rw_table_write_entry((void*)rw_table, 11, entry_eleven); + + /* + * Will fail out -- entry too high. + */ + rw_table_write_entry((void*)rw_table, 50000, entry_fiftyk); + + rw_table_print_entry(rw_table_read_entry((void*)rw_table, 10)); + rw_table_print_entry(rw_table_read_entry((void*)rw_table, 11)); + + /* + * Will return 0'd rw_table_entry -- entry too high. + */ + rw_table_print_entry(rw_table_read_entry((void*)rw_table, 50000)); +} + +int main() +{ + test_rw_table(); + test_dollop_table(); return 0; } #endif