about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2021-03-02 17:55:55 +0100
committerptitSeb <sebastien.chev@gmail.com>2021-03-02 17:55:55 +0100
commitb4851d8dd52dba587e55818b2e20b15f8624e955 (patch)
tree799db5bcbe4d71e8ee91d1e6f2445b7ccae78fe4 /src
parent8b56536bb1e38cfa83346544ec62e2e2003dd071 (diff)
downloadbox64-b4851d8dd52dba587e55818b2e20b15f8624e955.tar.gz
box64-b4851d8dd52dba587e55818b2e20b15f8624e955.zip
Added bridge handling
Diffstat (limited to 'src')
-rwxr-xr-xsrc/box64context.c13
-rwxr-xr-xsrc/include/box64context.h7
-rwxr-xr-xsrc/include/bridge.h25
-rwxr-xr-xsrc/tools/bridge.c220
-rwxr-xr-xsrc/tools/bridge_private.h22
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