static void* get_unused_xblock(CTX ctx) { if (unlikely(xfreelist == NULL)) { unsigned char *xmem = (unsigned char*)knh_xmalloc(ctx, 1); assert(xmem != NULL); knh_xblock_t *p = (knh_xblock_t*)knh_malloc(ctx, XBLOCK_NUMBER * sizeof(knh_xblock_t)); size_t idx = 0; for (idx = 0; idx < XBLOCK_NUMBER - 1; idx++) { p[idx].block = &(xmem[idx * XBLOCK_SIZE]); p[idx].next = &(p[idx + 1]); // fprintf(stderr, "idx:%d, p:%p, block:%p, next:%p\n", idx, &(p[idx]), p[idx].block, p[idx].next); } p[idx].block = &(xmem[idx * XBLOCK_SIZE]); p[idx].next = NULL; xfreelist = p; } if (xfreelist->next == NULL) { unsigned char *xmem = (unsigned char*)knh_xmalloc(ctx, 1); knh_xblock_t *p = (knh_xblock_t*)knh_malloc(ctx, XBLOCK_NUMBER * sizeof(knh_xblock_t)); size_t idx = 0; for (idx = 0; idx < XBLOCK_NUMBER - 1; idx++) { p[idx].block = &(xmem[idx * XBLOCK_SIZE]); p[idx].next = &(p[idx + 1]); } p[idx].block = &(xmem[idx * XBLOCK_SIZE]); p[idx].next = NULL; xfreelist->next = p; } assert(xfreelist->next != NULL); knh_xblock_t *ret = xfreelist; xfreelist = ret->next; return ret; }
void* knh_copyCallbackFunc(CTX ctx, void *func, knh_Func_t *fo) { void *f = NULL; #if !defined(K_USING_WINDOWS) && !defined(K_USING_BTRON) f = (void*)(knh_uchar_t*)knh_xmalloc(ctx, FUNC_SIZE); int i, marker = -1; for (i = 0; i < FUNC_SIZE; i++) { if (*(int*)&f[i] == -1) { marker = i; i += 3; } } #endif return f; }
static void *knh_generateCallbackFunc64(CTX ctx, void *tmpl, void *dest, kFunc *fo) { kchar_t *function = NULL; #if !defined(K_USING_WINDOWS) && !defined(K_USING_BTRON) function = (kchar_t*)tmpl; // search -1 (0xfffffff0fffffff0) int i, marker = -1, jmp_pos = -1; enum last_inst lastInst = call_leave_ret; for (i = 0; i < FUNC_SIZE; i++) { if (*(intptr_t*)&function[i] == 0xfffffff0fffffff0 && marker == -1) { marker = i; i += 8; } // XXX ??? function[i] == 0xe8 && 0x66 /* jmp instruction * e8 00 00 00 */ if (function[i] == 0xe8 /*&& function[i] == 0x66*/) { jmp_pos = i; } // jmppos for x86_64 // c9 : leave // e9 xxxxxxxx : jmp xxxxxxxx if(function[i] == 0xc9 && function[i + 1] == 0xe9) { lastInst = leave_jmp; jmp_pos = i + 1; i += 4; // rel address is 4 bytes break; } //linux amd64 if (function[i] == 0xe9 && *(int*)&function[i+1] < 0) { lastInst = jmp_only; jmp_pos = i; i += 5 + 4; break; } // typical epilogue. if (function[i] == 0xc9 && function[i+1] == 0xc3) { i += 2; break; } } // copy function size_t funcsize = i; function = (kchar_t*)knh_xmalloc(ctx, funcsize); memcpy(function, tmpl, i); if (marker > 0) { memcpy(&function[marker], &fo, sizeof(void*)); } // now, patch if (jmp_pos > 0) { //linux // happend to use rax // movq 0x(dest) %rax function[jmp_pos+0] = 0x48; function[jmp_pos+1] = 0xb8; union { unsigned char code[sizeof(intptr_t)]; intptr_t v; } code; code.v = (intptr_t) dest; memcpy(function+(jmp_pos+2), code.code, sizeof(code)); size_t seekidx = jmp_pos + 2 + sizeof(intptr_t); // call switch (lastInst) { case leave_jmp: /* leave */ //function[seekidx++] = 0xc9; /* fall through */ case jmp_only: /*case leave_jmp:*/ /* jmp *%rax */ function[seekidx+0] = 0xff; function[seekidx+1] = 0xe0; break; case call_leave_ret: /* callq *%rax */ function[seekidx+0] = 0xff; function[seekidx+1] = 0xd0; /* leave */ function[seekidx+2] = 0xc9; /* ret */ function[seekidx+3] = 0xc3; break; } } #endif /* tron, lkm */ return function; }
static void *knh_generateCallbackFunc32(CTX ctx, void *tmpl, void *dest, kFunc *fo) { kchar_t *function = NULL; #if !defined(K_USING_WINDOWS) && !defined(K_USING_BTRON) function = (kchar_t*)tmpl; //search -1 int i, marker = -1, jmp_pos = -1, shrink_pos = -1; for (i = 0; i < FUNC_SIZE; i++) { // fprintf(stderr, "dump:%02x\n", *(int*)&function[i]); if (*(int*)&function[i] == -1 && marker == -1) { marker = i; i += 3; } // for thunk.bx, they call thunk, and add. if (function[i] == 0xe8 && function[i+5] == 0x81 && function[i+6] == 0xc3){ shrink_pos = i; continue; } else if (function[i] == 0xe8 && *(int*)&function[i+1] < 0 && jmp_pos < 0) { jmp_pos = i; } // loop condition if (function[i] == 0x5d && function[i + 1] == 0xc3) { i += 14; break; } if (i != 0 && function[i] == 0x55 && function[i + 1] == 0x89 && function[i+2] == 0xe5) { // next prologue i -= 1; break; } } // fprintf(stderr, "i=%d\n", i); function = (kchar_t*)knh_xmalloc(ctx, i); memcpy(function, tmpl, i); // fprintf(stderr, "marker:%d, jmp:%d, shrink:%d\n", marker, jmp_pos, shrink_pos); kchar_t buf[FUNC_SIZE]={0}; // dumpBinary(function, 48); size_t funcsize = i; if (shrink_pos > 0) { // shrinking call xxx, add xxx // they always moving ebx; memcpy(buf, &function[shrink_pos + 11], funcsize - (shrink_pos + 11)); function[shrink_pos] = 0x90; memcpy(&function[shrink_pos + 1], buf, funcsize - (shrink_pos + 11)); marker -= 10; jmp_pos -= 10; funcsize -= 10; // fprintf(stderr, "marker:%d, jmp:%d, shrink:%d\n", marker, jmp_pos, shrink_pos); } if (marker > 0){ *(intptr_t*)&function[marker] = (intptr_t)fo; } // fprintf(stderr, "jpos:%x\n", *(int*)&function[jmp_pos]); if (jmp_pos > 0) { // int disp = (intptr_t)dest - (intptr_t)&function[jmp_pos + 5]; // it is too far.. make far calling function[jmp_pos] = 0xb8; *(intptr_t*)&function[jmp_pos+1] = (intptr_t)dest; memcpy(buf, &function[jmp_pos + 5], funcsize - (jmp_pos + 5)); // insert 2 values; //before jmp! size_t seekidx = jmp_pos + 5; function[seekidx] = 0x90; function[seekidx+1] = 0xff; function[seekidx+2] = 0xd0; // shift the rest; memcpy(&function[seekidx+3], buf, funcsize - (seekidx+3)); // dumpBinary(function, 48); } #endif return function; }