patch.c
/* * detour for malloc on mips * (c) Jan Stancek, May 2010 * * At runtime, malloc beginning is overwritten to jump to my_malloc, * libc_malloc will jump to trampoline and then back to malloc+XX * to provide standard malloc functionality * * * +---------------------------------------------+ * | | * 0x2ab68964 - malloc | 0x30000000 - trampoline (libc_malloc) | 0x400010 - my_malloc * +-------------------------+ | +-----------------------------+ | +---------------------------+ * | jump to my_malloc | --+ | repair $t9 code |<----+ +->| some code | * | | | first X malloc instructions | +--------| jump to libc_malloc | * | the rest of malloc code |<------| jump to malloc+X | | some code | * | (unchanged) | | | +---------------------------+ * | ... | +-----------------------------+ * | | * +-------------------------+ */ /* original malloc code: Dump of assembler code for function malloc: 0x2acd6964 <+0>: lui gp,0x6 0x2acd6968 <+4>: addiu gp,gp,-25780 0x2acd696c <+8>: addu gp,gp,t9 0x2acd6970 <+12>: addiu sp,sp,-88 0x2acd6974 <+16>: sw ra,84(sp) 0x2acd6978 <+20>: sw s8,80(sp) 0x2acd697c <+24>: sw s7,76(sp) 0x2acd6980 <+28>: sw s6,72(sp) 0x2acd6984 <+32>: sw s5,68(sp) 0x2acd6988 <+36>: sw s4,64(sp) 0x2acd698c <+40>: sw s3,60(sp) 0x2acd6990 <+44>: sw s2,56(sp) 0x2acd6994 <+48>: sw s1,52(sp) 0x2acd6998 <+52>: sw s0,48(sp) 0x2acd699c <+56>: sw gp,24(sp) Dump of assembler code from 0x2ab68964 to 0x2ab68984: 0x2ab68964: lui t9,0x40 0x2ab68968: li at,0xa10 0x2ab6896c: addu t9,t9,at 0x2ab68970: jr t9 0x2ab68974: nop 0x2ab68978: sw s8,80(sp) 0x2ab6897c: sw s7,76(sp) 0x2ab68980: sw s6,72(sp) End of assembler dump. (gdb) info symbol 0x400a10 my_malloc in section .text of /tmp/JSt1/a.out Dump of assembler code from 0x30000000 to 0x30000038: 0x30000000: lui t9,0x2ab6 0x30000004: li at,0x8964 0x30000008: addu t9,t9,at 0x3000000c: lui gp,0x6 0x30000010: addiu gp,gp,-25780 0x30000014: addu gp,gp,t9 0x30000018: addiu sp,sp,-88 0x3000001c: sw ra,84(sp) 0x30000020: lui t9,0x2ab6 0x30000024: li at,0x8978 0x30000028: addu t9,t9,at 0x3000002c: jr t9 0x30000030: nop 0x30000034: nop */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <asm/cachectl.h> #include <asm/unistd.h> #define PAGESIZE 4096 #define TRAMPSIZE 20 int tramp_base = 0x30000000; void *(*libc_malloc)(size_t) = NULL; /* 40096c: 3c19ffff lui t9,0xffff 400970: 3401eeee li at,0xeeee 400974: 0321c821 addu t9,t9,at 400978: 03200008 jr t9 40097c: 00000000 nop */ unsigned char tramp_code[TRAMPSIZE]={ 0x3c, 0x19, 0xff, 0xff, 0x34, 0x01, 0xee, 0xee, 0x03, 0x21, 0xc8, 0x21, 0x03, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00 }; void trampoline_tests() { asm ( "lui $t9, 0xffff\n" "addu $t9, $t9, 0xeeee\n" "jr $t9\n" :: ); } void prepare_tramp_code(void *jump_addr) { int addr = (int) jump_addr; tramp_code[2] = (addr >> 24) & 0xff; tramp_code[3] = (addr >> 16) & 0xff; tramp_code[6] = (addr >> 8) & 0xff; tramp_code[7] = addr & 0xff; } void *my_malloc(size_t size) { void *ret = NULL; printf("my maloooooooooc\n"); ret = libc_malloc(size); printf("my maloooooooooc ret %p\n", ret); return ret; } void dump_mem(void *addr, int len) { int i; unsigned char *c; printf("dump from %p\n", addr); for (i=0;i<len;i++) { c = ((unsigned char *)addr)+i; printf("%x ", *c); if (i % TRAMPSIZE == TRAMPSIZE -1) { printf("\n"); } } printf("\n"); } void test() { void *v; int i; for (i=0;i<1024;i++) { v = malloc(200); if (v==(int *)0x12345678) { break; } } printf("after %d\n", i); } int main() { void *malloc_ptr = (void *) &malloc; void *malloc_trampoline = NULL; void *malloc_page_ptr = NULL; void *malloc_tramp_to_orig = NULL; int i = 0; printf("malloc: %p\n", malloc_ptr); printf("my_malloc: %p\n", (void *) &my_malloc); malloc_trampoline = mmap((void *)(tramp_base & ~(PAGESIZE-1)), PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0); malloc_page_ptr = (void *)(((size_t)malloc_ptr) & ~(PAGESIZE-1)); if (mprotect(malloc_page_ptr, PAGESIZE*(2), PROT_READ | PROT_WRITE | PROT_EXEC) == -1) { printf("mprotect failed\n"); return 2; } if (malloc_trampoline == MAP_FAILED) { printf("mmap failed\n"); return 3; } malloc_tramp_to_orig = malloc_trampoline; // 0x00 - 0x0c malloc repair code for $t9 prepare_tramp_code(malloc_ptr); memcpy(malloc_tramp_to_orig, tramp_code, 0x0c); // store instruction at malloc beginning to trampoline 0xc - 0x20 for (i=0;i<TRAMPSIZE;i++) { unsigned char *dst = ((unsigned char *)malloc_tramp_to_orig)+i+0x0c; unsigned char *src = ((unsigned char *)malloc_ptr)+i; *dst = *src; } // jump from trampoline to original malloc+TRAMPSIZE, 0x20 - 0x34 prepare_tramp_code((unsigned char *) malloc_ptr+TRAMPSIZE); memcpy((unsigned char *) malloc_tramp_to_orig+0x0c+TRAMPSIZE, tramp_code, TRAMPSIZE); libc_malloc = (void *(*)(size_t)) malloc_tramp_to_orig; // jump from original malloc to my_malloc prepare_tramp_code((unsigned char *) &my_malloc); memcpy((unsigned char *) malloc_ptr, tramp_code, TRAMPSIZE); dump_mem(malloc_ptr, TRAMPSIZE); dump_mem(malloc_tramp_to_orig, TRAMPSIZE*3); // flush the icache asm( "lw $a0, %0\n" "nop\n" "li $a1, %1\n" "li $a2, %2\n" "li $v0, %3\n" "syscall\n" :: "m" (malloc_ptr), "i" (TRAMPSIZE), "i" (ICACHE), "i" (__NR_cacheflush) ); // and we are ready to test it test(); printf("this is the end....\n"); return 0; }
makefile:
all: /opt/uclibc-toolchain/ifx-lxdb-1-2/gcc-3.4.4/toolchain-mips-sf/bin-ccache/mips-linux-gcc -g3 -O0 -Wall patch.c