aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt24
-rw-r--r--README.md4
-rw-r--r--subhook.c72
-rw-r--r--subhook.h226
-rw-r--r--subhook_linux.c44
-rw-r--r--subhook_private.h36
-rw-r--r--subhook_windows.c40
-rw-r--r--subhook_x86.c85
8 files changed, 531 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..1826ce2
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 2.8)
+project(subhook)
+
+set(SUBHOOK_HEADERS "subhook.h")
+set(SUBHOOK_SOURCES "subhook.c" "subhook_private.h")
+
+add_definitions(-DSUBHOOK_IMPLEMENTATION)
+
+if(SUBHOOK_STATIC)
+ add_library(subhook STATIC ${SUBHOOK_HEADERS} ${SUBHOOK_SOURCES})
+else()
+ add_library(subhook SHARED ${SUBHOOK_HEADERS} ${SUBHOOK_SOURCES})
+endif()
+
+set_property(DIRECTORY ${CMAKE_SOURCE_DIR} APPEND PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
+
+if(SUBHOOK_STATIC)
+ set_property(DIRECTORY ${CMAKE_SOURCE_DIR} APPEND PROPERTY COMPILE_DEFINITIONS "SUBHOOK_STATIC")
+endif()
+
+if(SUBHOOK_INSTALL)
+ install(TARGETS subhook LIBRARY DESTINATION "lib")
+ install(FILES ${SUBHOOK_HEADERS} DESTINATION "include")
+endif()
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..cb8c08d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+[subhook][link] is a super-simple mini-library for setting function hooks at
+runtime on x86 CPUs and works on both Linux and Windows.
+
+[link]: https://github.com/Zeex/subhook
diff --git a/subhook.c b/subhook.c
new file mode 100644
index 0000000..6c23b17
--- /dev/null
+++ b/subhook.c
@@ -0,0 +1,72 @@
+/* Copyright (c) 2012 Zeex
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+
+#include "subhook.h"
+#include "subhook_private.h"
+
+SUBHOOK_EXPORT struct subhook *SUBHOOK_API subhook_new() {
+ return (struct subhook *)calloc(1, sizeof(struct subhook));
+}
+
+SUBHOOK_EXPORT void SUBHOOK_API subhook_free(struct subhook *hook) {
+ free(hook->arch);
+ free(hook);
+}
+
+SUBHOOK_EXPORT void *SUBHOOK_API subhook_get_source(struct subhook *hook) {
+ return hook->src;
+}
+
+SUBHOOK_EXPORT void *SUBHOOK_API subhook_get_destination(struct subhook *hook) {
+ return hook->dst;
+}
+
+SUBHOOK_EXPORT void SUBHOOK_API subhook_set_source(struct subhook *hook, void *src) {
+ hook->src = src;
+}
+
+SUBHOOK_EXPORT void SUBHOOK_API subhook_set_destination(struct subhook *hook, void *dst) {
+ hook->dst = dst;
+}
+
+SUBHOOK_EXPORT int SUBHOOK_API subhook_get_flags(struct subhook *hook) {
+ return hook->flags;
+}
+
+SUBHOOK_EXPORT void SUBHOOK_API subhook_set_flags(struct subhook *hook, int flags) {
+ hook->flags = flags;
+}
+
+#if defined SUBHOOK_WINDOWS
+ #include "subhook_windows.c"
+#elif defined SUBHOOK_LINUX
+ #include "subhook_linux.c"
+#endif
+
+#if defined SUBHOOK_X86
+ #include "subhook_x86.c"
+#endif
diff --git a/subhook.h b/subhook.h
new file mode 100644
index 0000000..16d3d4c
--- /dev/null
+++ b/subhook.h
@@ -0,0 +1,226 @@
+/* Copyright (c) 2012 Zeex
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SUBHOOK_H
+#define SUBHOOK_H
+
+#include <stddef.h>
+
+#if defined _M_IX86 || defined __i386__
+ #define SUBHOOK_X86
+#else
+ #error Unsupported architecture
+#endif
+
+#if defined __linux__
+ #define SUBHOOK_LINUX
+#elif defined _WIN32
+ #define SUBHOOK_WINDOWS
+#else
+ #error Unsupported operating system
+#endif
+
+#if !defined SUHOOK_EXTERN
+ #if defined __cplusplus
+ #define SUBHOOK_EXTERN extern "C"
+ #else
+ #define SUBHOOK_EXTERN extern
+ #endif
+#endif
+
+#if defined SUBHOOK_STATIC
+ #define SUBHOOK_API
+ #define SUBHOOK_EXPORT SUBHOOK_EXTERN
+#endif
+
+#if !defined SUBHOOK_API
+ #if defined SUBHOOK_WINDOWS
+ #define SUBHOOK_API __cdecl
+ #elif defined SUBHOOK_LINUX
+ #define SUBHOOK_API __attribute__((cdecl))
+ #endif
+#endif
+
+#if !defined SUBHOOK_EXPORT
+ #if defined SUBHOOK_WINDOWS
+ #if defined SUBHOOK_IMPLEMENTATION
+ #define SUBHOOK_EXPORT SUBHOOK_EXTERN __declspec(dllexport)
+ #else
+ #define SUBHOOK_EXPORT SUBHOOK_EXTERN __declspec(dllimport)
+ #endif
+ #elif defined SUBHOOK_LINUX
+ #if defined SUBHOOK_IMPLEMENTATION
+ #define SUBHOOK_EXPORT SUBHOOK_EXTERN __attribute__((visibility("default")))
+ #else
+ #define SUBHOOK_EXPORT SUBHOOK_EXTERN
+ #endif
+ #endif
+#endif
+
+#define SUBHOOK_FLAG_INSTALLED 0x01
+
+SUBHOOK_EXPORT struct subhook *SUBHOOK_API subhook_new();
+SUBHOOK_EXPORT void SUBHOOK_API subhook_free(struct subhook *hook);
+
+SUBHOOK_EXPORT void SUBHOOK_API subhook_set_source(struct subhook *hook, void *src);
+SUBHOOK_EXPORT void *SUBHOOK_API subhook_get_source(struct subhook *hook);
+
+SUBHOOK_EXPORT void SUBHOOK_API subhook_set_destination(struct subhook *hook, void *dst);
+SUBHOOK_EXPORT void *SUBHOOK_API subhook_get_destination(struct subhook *hook);
+
+/* These return 0 on failure and 1 on success. */
+SUBHOOK_EXPORT int SUBHOOK_API subhook_install(struct subhook *hook);
+SUBHOOK_EXPORT int SUBHOOK_API subhook_remove(struct subhook *hook);
+
+SUBHOOK_EXPORT int SUBHOOK_API subhook_get_flags(struct subhook *hook);
+SUBHOOK_EXPORT void SUBHOOK_API subhook_set_flags(struct subhook *hook, int flags);
+
+/* Sets read+write+execute permissions for memory region. */
+SUBHOOK_EXPORT void *SUBHOOK_API subhook_unprotect(void *address, size_t size);
+
+static int subhook_is_installed(struct subhook *hook) {
+ return (subhook_get_flags(hook) & SUBHOOK_FLAG_INSTALLED) != 0;
+}
+
+/* Reads hook destination address from code.
+ *
+ * This is useful when you don't know the address or want to check
+ * whether src has been hooked with subhook.
+ */
+SUBHOOK_EXPORT void *SUBHOOK_API subhook_read_destination(void *src);
+
+#define SUBHOOK_INSTALL_HOOK(hook, src, dest) \
+ do {\
+ subhook_set_source(hook, src);\
+ subhook_set_destination(hook, dest);\
+ subhook_install(hook);\
+ } while (0);
+
+#ifdef __cplusplus
+
+class SubHook {
+public:
+ SubHook() {
+ hook_ = subhook_new();
+ subhook_set_source(hook_, 0);
+ subhook_set_destination(hook_, 0);
+ }
+
+ SubHook(void *src, void *dst) {
+ hook_ = subhook_new();
+ subhook_set_source(hook_, src);
+ subhook_set_destination(hook_, dst);
+ }
+
+ ~SubHook() {
+ if (installed_) {
+ subhook_remove(hook_);
+ subhook_free(hook_);
+ }
+ }
+
+ bool Install() {
+ if (!installed_) {
+ subhook_install(hook_);
+ installed_ = true;
+ return true;
+ }
+ return false;
+ }
+
+ bool Install(void *src, void *dst) {
+ if (!installed_) {
+ subhook_set_source(hook_, src);
+ subhook_set_destination(hook_, dst);
+ subhook_install(hook_);
+ installed_ = true;
+ return true;
+ }
+ return false;
+ }
+
+ bool Remove() {
+ if (installed_) {
+ subhook_remove(hook_);
+ installed_ = false;
+ return true;
+ }
+ return false;
+ }
+
+ bool IsInstalled() const {
+ return installed_;
+ }
+
+ class ScopedRemove {
+ public:
+ ScopedRemove(SubHook *hook)
+ : hook_(hook)
+ , removed_(hook_->Remove())
+ {
+ }
+
+ ~ScopedRemove() {
+ if (removed_) {
+ hook_->Install();
+ }
+ }
+
+ private:
+ SubHook *hook_;
+ bool removed_;
+ };
+
+ class ScopedInstall {
+ public:
+ ScopedInstall(SubHook *hook)
+ : hook_(hook)
+ , installed_(hook_->Install())
+ {
+ }
+
+ ~ScopedInstall() {
+ if (installed_) {
+ hook_->Remove();
+ }
+ }
+
+ private:
+ SubHook *hook_;
+ bool installed_;
+ };
+
+private:
+ SubHook(const SubHook &);
+ void operator=(const SubHook &);
+
+private:
+ subhook *hook_;
+ bool installed_;
+};
+
+#endif
+
+#endif /* SUBHOOK_H */
diff --git a/subhook_linux.c b/subhook_linux.c
new file mode 100644
index 0000000..15d85b3
--- /dev/null
+++ b/subhook_linux.c
@@ -0,0 +1,44 @@
+/* Copyright (c) 2012 Zeex
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "subhook.h"
+
+SUBHOOK_EXPORT void *SUBHOOK_API subhook_unprotect(void *address, size_t size) {
+ size_t pagesize;
+
+ pagesize = sysconf(_SC_PAGESIZE);
+ address = (void*)((size_t)address & ~(pagesize - 1));
+
+ if (mprotect(address, size, PROT_READ | PROT_WRITE | PROT_EXEC) == 0) {
+ return address;
+ }
+
+ return NULL;
+}
diff --git a/subhook_private.h b/subhook_private.h
new file mode 100644
index 0000000..1de11cf
--- /dev/null
+++ b/subhook_private.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2012 Zeex
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SUBHOOK_PRIVATE_H
+#define SUBHOOK_PRIVATE_H
+
+struct subhook {
+ int flags;
+ void *src;
+ void *dst;
+ void *arch; /* architecture-specific information */
+};
+
+#endif /* SUBHOOK_PRIVATE_H */
diff --git a/subhook_windows.c b/subhook_windows.c
new file mode 100644
index 0000000..3176ffb
--- /dev/null
+++ b/subhook_windows.c
@@ -0,0 +1,40 @@
+/* Copyright (c) 2012 Zeex
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <windows.h>
+
+#include "subhook.h"
+
+SUBHOOK_EXPORT void *SUBHOOK_API subhook_unprotect(void *address, size_t size) {
+ DWORD oldProtect;
+
+ if (VirtualProtect(address, size, PAGE_EXECUTE_READWRITE, &oldProtect) != 0) {
+ return address;
+ }
+
+ return NULL;
+}
diff --git a/subhook_x86.c b/subhook_x86.c
new file mode 100644
index 0000000..0b2c7a2
--- /dev/null
+++ b/subhook_x86.c
@@ -0,0 +1,85 @@
+/* Copyright (c) 2012 Zeex
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "subhook.h"
+#include "subhook_private.h"
+
+/* 1 byte for opcode + 4 for address */
+#define SUBHOOK_JUMP_SIZE 5
+
+struct subhook_x86 {
+ unsigned char code[SUBHOOK_JUMP_SIZE];
+};
+
+SUBHOOK_EXPORT int SUBHOOK_API subhook_install(struct subhook *hook) {
+ static const unsigned char jmp = 0xE9;
+ void *src, *dst;
+ int offset;
+
+ if (subhook_is_installed(hook))
+ return -EINVAL;
+
+ src = subhook_get_source(hook);
+ dst = subhook_get_destination(hook);
+
+ if ((hook->arch = malloc(sizeof(struct subhook_x86))) == NULL)
+ return -ENOMEM;
+
+ subhook_unprotect(src, SUBHOOK_JUMP_SIZE);
+ memcpy(((struct subhook_x86 *)hook->arch)->code, src, SUBHOOK_JUMP_SIZE);
+
+ /* E9 - jump near, relative */
+ memcpy(src, &jmp, sizeof(jmp));
+
+ /* jump address is relative to next instruction */
+ offset = (int)dst - ((int)src + SUBHOOK_JUMP_SIZE);
+ memcpy((void*)((int)src + 1), &offset, SUBHOOK_JUMP_SIZE - sizeof(jmp));
+
+ subhook_set_flags(hook, subhook_get_flags(hook) | SUBHOOK_FLAG_INSTALLED);
+
+ return 0;
+}
+
+SUBHOOK_EXPORT int SUBHOOK_API subhook_remove(struct subhook *hook) {
+ if (!subhook_is_installed(hook))
+ return -EINVAL;
+
+ memcpy(subhook_get_source(hook), ((struct subhook_x86 *)hook->arch)->code, SUBHOOK_JUMP_SIZE);
+ subhook_set_flags(hook, subhook_get_flags(hook) & ~(SUBHOOK_FLAG_INSTALLED));
+
+ return 0;
+}
+
+SUBHOOK_EXPORT void *SUBHOOK_API subhook_read_destination(void *src) {
+ if (*(unsigned char*)src == 0xE9)
+ return (void *)(*(int *)((int)src + 1) + (int)src + SUBHOOK_JUMP_SIZE);
+
+ return NULL;
+}