diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2021-03-02 17:55:55 +0100 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2021-03-02 17:55:55 +0100 |
| commit | b4851d8dd52dba587e55818b2e20b15f8624e955 (patch) | |
| tree | 799db5bcbe4d71e8ee91d1e6f2445b7ccae78fe4 /src | |
| parent | 8b56536bb1e38cfa83346544ec62e2e2003dd071 (diff) | |
| download | box64-b4851d8dd52dba587e55818b2e20b15f8624e955.tar.gz box64-b4851d8dd52dba587e55818b2e20b15f8624e955.zip | |
Added bridge handling
Diffstat (limited to 'src')
| -rwxr-xr-x | src/box64context.c | 13 | ||||
| -rwxr-xr-x | src/include/box64context.h | 7 | ||||
| -rwxr-xr-x | src/include/bridge.h | 25 | ||||
| -rwxr-xr-x | src/tools/bridge.c | 220 | ||||
| -rwxr-xr-x | src/tools/bridge_private.h | 22 |
5 files changed, 282 insertions, 5 deletions
diff --git a/src/box64context.c b/src/box64context.c index c9aac3b1..fa4b74b7 100755 --- a/src/box64context.c +++ b/src/box64context.c @@ -12,6 +12,7 @@ #include "custommem.h" #include "threads.h" #include "x64trace.h" +#include "bridge.h" EXPORTDYN @@ -60,6 +61,8 @@ void free_tlsdatasize(void* p) free(p); } +void x64Syscall(x64emu_t *emu); + EXPORTDYN box64context_t *NewBox64Context(int argc) { @@ -77,6 +80,9 @@ box64context_t *NewBox64Context(int argc) init_custommem_helper(context); + context->system = NewBridge(); + // create vsyscall +// context->vsyscall = AddBridge(context->system, vFv, x64Syscall, 0); context->box64lib = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL); //context->dlprivate = NewDLPrivate(); @@ -127,11 +133,6 @@ void FreeBox64Context(box64context_t** context) CleanStackSize(ctx); -#ifndef BUILD_LIB - if(ctx->box64lib) - dlclose(ctx->box64lib); -#endif - //FreeDLPrivate(&ctx->dlprivate); free(ctx->stack); @@ -139,6 +140,8 @@ void FreeBox64Context(box64context_t** context) free(ctx->fullpath); free(ctx->box64path); + FreeBridge(&ctx->system); + void* ptr; if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) { free_tlsdatasize(ptr); diff --git a/src/include/box64context.h b/src/include/box64context.h index 0ffd0651..9eca567e 100755 --- a/src/include/box64context.h +++ b/src/include/box64context.h @@ -9,6 +9,8 @@ typedef struct cleanup_s cleanup_t; typedef struct x64emu_s x64emu_t; typedef struct zydis_s zydis_t; typedef struct zydis_dec_s zydis_dec_t; +typedef struct lib_s lib_t; +typedef struct bridge_s bridge_t; typedef struct kh_threadstack_s kh_threadstack_t; typedef void* (*procaddess_t)(const char* name); @@ -58,7 +60,12 @@ typedef struct box64context_s { uintptr_t ep; // entry point + lib_t *maplib; // lib and symbols handling + lib_t *local_maplib; // libs and symbols openned has local (only collection of libs, no symbols) + kh_threadstack_t *stacksizes; // stack sizes attributes for thread (temporary) + bridge_t *system; // other bridges + uintptr_t vsyscall; // vsyscall bridge value pthread_mutex_t mutex_thread; diff --git a/src/include/bridge.h b/src/include/bridge.h new file mode 100755 index 00000000..dfe402f9 --- /dev/null +++ b/src/include/bridge.h @@ -0,0 +1,25 @@ +#ifndef __BRIDGE_H_ +#define __BRIDGE_H_ +#include <stdint.h> + +typedef struct x64emu_s x64emu_t; +typedef struct bridge_s bridge_t; +typedef struct box64context_s box64context_t; +typedef void (*wrapper_t)(x64emu_t* emu, uintptr_t fnc); + +bridge_t *NewBridge(); +void FreeBridge(bridge_t** bridge); + +uintptr_t AddBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N); +uintptr_t CheckBridged(bridge_t* bridge, void* fnc); +uintptr_t AddCheckBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N); +uintptr_t AddAutomaticBridge(x64emu_t* emu, bridge_t* bridge, wrapper_t w, void* fnc, int N); +void* GetNativeFnc(uintptr_t fnc); +void* GetNativeFncOrFnc(uintptr_t fnc); + +int hasAlternate(void* addr); +void* getAlternate(void* addr); +void addAlternate(void* addr, void* alt); +void cleanAlternate(); + +#endif //__BRIDGE_H_ \ No newline at end of file diff --git a/src/tools/bridge.c b/src/tools/bridge.c new file mode 100755 index 00000000..76eb20b2 --- /dev/null +++ b/src/tools/bridge.c @@ -0,0 +1,220 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> +#include <pthread.h> + +//#include "custommem.h" +#include "bridge.h" +#include "bridge_private.h" +#include "khash.h" +#include "debug.h" +#include "x64emu.h" +#ifdef DYNAREC +#include "dynablock.h" +#include "box64context.h" +#endif + +KHASH_MAP_INIT_INT64(bridgemap, uintptr_t) + +//onebridge is 32 bytes +#define NBRICK 4096/32 +typedef struct brick_s brick_t; +typedef struct brick_s { + onebridge_t *b; + int sz; + brick_t *next; +} brick_t; + +typedef struct bridge_s { + brick_t *head; + brick_t *last; // to speed up + pthread_mutex_t mutex; + kh_bridgemap_t *bridgemap; +} bridge_t; + +brick_t* NewBrick() +{ + brick_t* ret = (brick_t*)calloc(1, sizeof(brick_t)); + posix_memalign((void**)&ret->b, box64_pagesize, NBRICK*sizeof(onebridge_t)); + return ret; +} + +bridge_t *NewBridge() +{ + bridge_t *b = (bridge_t*)calloc(1, sizeof(bridge_t)); + b->head = NewBrick(); + b->last = b->head; + pthread_mutex_init(&b->mutex, NULL); + b->bridgemap = kh_init(bridgemap); + + return b; +} +void FreeBridge(bridge_t** bridge) +{ + brick_t *b = (*bridge)->head; + while(b) { + brick_t *n = b->next; + #ifdef DYNAREC + if(getProtection((uintptr_t)b->b)&PROT_DYNAREC) + unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t)); + #endif + free(b->b); + free(b); + b = n; + } + kh_destroy(bridgemap, (*bridge)->bridgemap); + pthread_mutex_destroy(&(*bridge)->mutex); + free(*bridge); + *bridge = NULL; +} + +uintptr_t AddBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N) +{ + pthread_mutex_lock(&bridge->mutex); + brick_t *b = bridge->last; + if(b->sz == NBRICK) { + b->next = NewBrick(); + b = b->next; + bridge->last = b; + } + #ifdef DYNAREC + int prot = 0; + if(box64_dynarec) { + prot=(getProtection((uintptr_t)b->b)&PROT_DYNAREC)?1:0; + if(prot) + unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t)); + addDBFromAddressRange((uintptr_t)&b->b[b->sz].CC, sizeof(onebridge_t)); + } + #endif + b->b[b->sz].CC = 0xCC; + b->b[b->sz].S = 'S'; b->b[b->sz].C='C'; + b->b[b->sz].w = w; + b->b[b->sz].f = (uintptr_t)fnc; + b->b[b->sz].C3 = N?0xC2:0xC3; + b->b[b->sz].N = N; + #ifdef DYNAREC + if(box64_dynarec && prot) + protectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t)); + #endif + // add bridge to map, for fast recovery + int ret; + khint_t k = kh_put(bridgemap, bridge->bridgemap, (uintptr_t)fnc, &ret); + kh_value(bridge->bridgemap, k) = (uintptr_t)&b->b[b->sz].CC; + pthread_mutex_unlock(&bridge->mutex); + + return (uintptr_t)&b->b[b->sz++].CC; +} + +uintptr_t CheckBridged(bridge_t* bridge, void* fnc) +{ + // check if function alread have a bridge (the function wrapper will not be tested) + khint_t k = kh_get(bridgemap, bridge->bridgemap, (uintptr_t)fnc); + if(k==kh_end(bridge->bridgemap)) + return 0; + return kh_value(bridge->bridgemap, k); +} + +uintptr_t AddCheckBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N) +{ + if(!fnc && w) + return 0; + uintptr_t ret = CheckBridged(bridge, fnc); + if(!ret) + ret = AddBridge(bridge, w, fnc, N); + return ret; +} + +uintptr_t AddAutomaticBridge(x64emu_t* emu, bridge_t* bridge, wrapper_t w, void* fnc, int N) +{ + if(!fnc) + return 0; + uintptr_t ret = CheckBridged(bridge, fnc); + if(!ret) + ret = AddBridge(bridge, w, fnc, N); + if(!hasAlternate(fnc)) { + printf_log(LOG_DEBUG, "Adding AutomaticBridge for %p to %p\n", fnc, (void*)ret); + addAlternate(fnc, (void*)ret); + #ifdef DYNAREC + // now, check if dynablock at native address exist + DBAlternateBlock(emu, (uintptr_t)fnc, ret); + #endif + } + return ret; +} + +void* GetNativeFnc(uintptr_t fnc) +{ + if(!fnc) return NULL; + // check if function exist in some loaded lib + Dl_info info; + if(dladdr((void*)fnc, &info)) + return (void*)fnc; + // check if it's an indirect jump + #define PK(a) *(uint8_t*)(fnc+a) + #define PK32(a) *(uint32_t*)(fnc+a) + if(PK(0)==0xff && PK(1)==0x25) { // absolute jump, maybe the GOT + uintptr_t a1 = (PK32(2)); // need to add a check to see if the address is from the GOT ! + a1 = *(uintptr_t*)a1; + if(a1 && a1>0x10000) { + a1 = (uintptr_t)GetNativeFnc(a1); + if(a1) + return (void*)a1; + } + } + #undef PK + #undef PK32 + // check if bridge exist + onebridge_t *b = (onebridge_t*)fnc; + if(b->CC != 0xCC || b->S!='S' || b->C!='C' || (b->C3!=0xC3 && b->C3!=0xC2)) + return NULL; // not a bridge?! + return (void*)b->f; +} + +void* GetNativeFncOrFnc(uintptr_t fnc) +{ + onebridge_t *b = (onebridge_t*)fnc; + if(b->CC != 0xCC || b->S!='S' || b->C!='C' || (b->C3!=0xC3 && b->C3!=0xC2)) + return (void*)fnc; // not a bridge?! + return (void*)b->f; +} + +// Alternate address handling +KHASH_MAP_INIT_INT64(alternate, void*) +static kh_alternate_t *my_alternates = NULL; + +int hasAlternate(void* addr) { + if(!my_alternates) + return 0; + khint_t k = kh_get(alternate, my_alternates, (uintptr_t)addr); + if(k==kh_end(my_alternates)) + return 0; + return 1; +} + +void* getAlternate(void* addr) { + if(!my_alternates) + return addr; + khint_t k = kh_get(alternate, my_alternates, (uintptr_t)addr); + if(k!=kh_end(my_alternates)) + return kh_value(my_alternates, k); + return addr; +} +void addAlternate(void* addr, void* alt) { + if(!my_alternates) { + my_alternates = kh_init(alternate); + } + int ret; + khint_t k = kh_put(alternate, my_alternates, (uintptr_t)addr, &ret); + if(!ret) // already there + return; + kh_value(my_alternates, k) = alt; +} + +void cleanAlternate() { + if(my_alternates) { + kh_destroy(alternate, my_alternates); + my_alternates = NULL; + } +} diff --git a/src/tools/bridge_private.h b/src/tools/bridge_private.h new file mode 100755 index 00000000..928e1e02 --- /dev/null +++ b/src/tools/bridge_private.h @@ -0,0 +1,22 @@ +#ifndef __BRIDGE_PRIVATE_H_ +#define __BRIDGE_PRIVATE_H_ +#include <stdint.h> + +// the generic wrapper pointer functions +typedef void (*wrapper_t)(x64emu_t* emu, uintptr_t fnc); + +#pragma pack(push, 1) +typedef union onebridge_s { + struct { + uint8_t CC; // CC int 0x3 + uint8_t S, C; // 'S' 'C', just a signature + wrapper_t w; // wrapper + uintptr_t f; // the function for the wrapper + uint8_t C3; // C2 or C3 ret + uint16_t N; // N in case of C2 ret + }; + uint64_t dummy[4]; +} onebridge_t; +#pragma pack(pop) + +#endif //__BRIDGE_PRIVATE_H_ \ No newline at end of file |