aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZeex <zeex@rocketmail.com>2018-09-06 23:52:15 +0600
committerZeex <zeex@rocketmail.com>2018-09-06 23:59:35 +0600
commit6cc020b2fd950264cba0decd7d5d986c8a3fe768 (patch)
treeea8afee9b6a1ce764941cbc5b47468d72a2a490c
parent744057d48693974f8da61efe68260b6120cc4ed2 (diff)
downloadsubhook-6cc020b2fd950264cba0decd7d5d986c8a3fe768.zip
subhook-6cc020b2fd950264cba0decd7d5d986c8a3fe768.tar.gz
subhook-6cc020b2fd950264cba0decd7d5d986c8a3fe768.tar.bz2
Rename "options" to "flags"
-rw-r--r--README.md18
-rw-r--r--subhook.h46
-rw-r--r--subhook_private.h2
-rw-r--r--subhook_x86.c26
-rw-r--r--tests/CMakeLists.txt64
-rw-r--r--tests/test.c4
-rw-r--r--tests/test.cpp75
7 files changed, 159 insertions, 76 deletions
diff --git a/README.md b/README.md
index 2430569..d7d1eb9 100644
--- a/README.md
+++ b/README.md
@@ -7,8 +7,8 @@ Linux and macOS. It supports x86 only (32-bit and 64-bit).
Installation
------------
-Simply copy the files to your project and include subhook.c in your build.
-The other source files wil be `#included` by the main C file automatically
+Simply copy the files to your project and include subhook.c in your build.
+The other source files wil be `#included` by the main C file automatically
depending on the OS and achitecture.
Use of CMake is not mandatory, the library can be built wihtout it (no extra
@@ -116,19 +116,19 @@ int main() {
Known issues
------------
-* If a target function (the function you are hooking) is less than N bytes
- in length, for example if it's a short 2-byte jump to a nearby location
+* If a target function (the function you are hooking) is less than N bytes
+ in length, for example if it's a short 2-byte jump to a nearby location
(sometimes compilers generate code like this), then you will not be able
to hook it.
- N is 5 by default (1-byte jmp opcode + 32-bit offset), but it you enable
- the use of 64-bit offsets in 64-bit mode N becomes 14 (see the definition
+ N is 5 by default (1-byte jmp opcode + 32-bit offset), but it you enable
+ the use of 64-bit offsets in 64-bit mode N becomes 14 (see the definition
of `subhook_jmp64`).
-* Some systems protect executable code form being modified at runtime, which
- will not allow you to install hooks, or don't allow to mark heap-allocated
+* Some systems protect executable code form being modified at runtime, which
+ will not allow you to install hooks, or don't allow to mark heap-allocated
memory as executable, which prevents the use of trampolines.
-
+
For example, on Fedora you can have such problems because of SELinux (though
you can disable it or exclude your files).
diff --git a/subhook.h b/subhook.h
index addc7eb..20402de 100644
--- a/subhook.h
+++ b/subhook.h
@@ -89,17 +89,17 @@
#endif
#endif
-typedef enum subhook_options {
- /* Use 64-bit jump method on x86-64 (requires more space). */
- SUBHOOK_OPTION_64BIT_OFFSET = 1u << 1
-} subhook_options_t;
+typedef enum subhook_flags {
+ /* Use the 64-bit jump method on x86-64 (requires more space). */
+ SUBHOOK_64BIT_OFFSET = 1
+} subhook_flags_t;
struct subhook_struct;
typedef struct subhook_struct *subhook_t;
SUBHOOK_EXPORT subhook_t SUBHOOK_API subhook_new(void *src,
void *dst,
- subhook_options_t options);
+ subhook_flags_t flags);
SUBHOOK_EXPORT void SUBHOOK_API subhook_free(subhook_t hook);
SUBHOOK_EXPORT void *SUBHOOK_API subhook_get_src(subhook_t hook);
@@ -121,37 +121,37 @@ SUBHOOK_EXPORT void *SUBHOOK_API subhook_read_dst(void *src);
namespace subhook {
-enum HookOptions {
- HookOptionsNone = 0,
- HookOption64BitOffset = SUBHOOK_OPTION_64BIT_OFFSET
+enum HookFlags {
+ HookNoFlags = 0,
+ HookFlag64BitOffset = SUBHOOK_64BIT_OFFSET
};
-inline HookOptions operator|(HookOptions o1, HookOptions o2) {
- return static_cast<HookOptions>(
+inline HookFlags operator|(HookFlags o1, HookFlags o2) {
+ return static_cast<HookFlags>(
static_cast<unsigned int>(o1) | static_cast<unsigned int>(o2));
}
-inline HookOptions operator&(HookOptions o1, HookOptions o2) {
- return static_cast<HookOptions>(
+inline HookFlags operator&(HookFlags o1, HookFlags o2) {
+ return static_cast<HookFlags>(
static_cast<unsigned int>(o1) & static_cast<unsigned int>(o2));
}
class Hook {
public:
Hook() : hook_(0) {}
- Hook(void *src,
- void *dst,
- HookOptions options = HookOptionsNone)
- : hook_(subhook_new(src, dst, (subhook_options_t)options)) {}
+ Hook(void *src, void *dst, HookFlags flags = HookNoFlags)
+ : hook_(subhook_new(src, dst, (subhook_flags_t)flags))
+ {
+ }
~Hook() {
subhook_remove(hook_);
subhook_free(hook_);
}
- void *GetSrc() { return subhook_get_src(hook_); }
- void *GetDst() { return subhook_get_dst(hook_); }
- void *GetTrampoline() { return subhook_get_trampoline(hook_); }
+ void *GetSrc() const { return subhook_get_src(hook_); }
+ void *GetDst() const { return subhook_get_dst(hook_); }
+ void *GetTrampoline() const { return subhook_get_trampoline(hook_); }
bool Install() {
return subhook_install(hook_) >= 0;
@@ -159,9 +159,9 @@ class Hook {
bool Install(void *src,
void *dst,
- HookOptions options = HookOptionsNone) {
+ HookFlags flags = HookNoFlags) {
if (hook_ == 0) {
- hook_ = subhook_new(src, dst, (subhook_options_t)options);
+ hook_ = subhook_new(src, dst, (subhook_flags_t)flags);
}
return Install();
}
@@ -220,9 +220,9 @@ class ScopedHookInstall {
ScopedHookInstall(Hook *hook,
void *src,
void *dst,
- HookOptions options = HookOptionsNone)
+ HookFlags flags = HookNoFlags)
: hook_(hook)
- , installed_(hook_->Install(src, dst, options))
+ , installed_(hook_->Install(src, dst, flags))
{
}
diff --git a/subhook_private.h b/subhook_private.h
index 37ef7b5..ec0dcc0 100644
--- a/subhook_private.h
+++ b/subhook_private.h
@@ -39,7 +39,7 @@ struct subhook_struct {
int installed;
void *src;
void *dst;
- subhook_options_t options;
+ subhook_flags_t flags;
void *code;
void *trampoline;
size_t jmp_size;
diff --git a/subhook_x86.c b/subhook_x86.c
index 613ec94..a9342ee 100644
--- a/subhook_x86.c
+++ b/subhook_x86.c
@@ -266,13 +266,13 @@ static size_t subhook_disasm(void *src, int32_t *reloc_op_offset) {
return len;
}
-static size_t subhook_get_jmp_size(subhook_options_t options) {
+static size_t subhook_get_jmp_size(subhook_flags_t flags) {
#ifdef SUBHOOK_X86_64
- if ((options & SUBHOOK_OPTION_64BIT_OFFSET) != 0) {
+ if ((flags & SUBHOOK_64BIT_OFFSET) != 0) {
return sizeof(struct subhook_jmp64);
}
#else
- (void)options;
+ (void)flags;
#endif
return sizeof(struct subhook_jmp32);
}
@@ -318,13 +318,13 @@ static int subhook_make_jmp64(void *src, void *dst) {
static int subhook_make_jmp(void *src,
void *dst,
- subhook_options_t options) {
+ subhook_flags_t flags) {
#ifdef SUBHOOK_X86_64
- if ((options & SUBHOOK_OPTION_64BIT_OFFSET) != 0) {
+ if ((flags & SUBHOOK_64BIT_OFFSET) != 0) {
return subhook_make_jmp64(src, dst);
}
#else
- (void)options;
+ (void)flags;
#endif
return subhook_make_jmp32(src, dst);
}
@@ -333,7 +333,7 @@ static int subhook_make_trampoline(void *trampoline,
void *src,
size_t jmp_size,
size_t *trampoline_len,
- subhook_options_t options) {
+ subhook_flags_t flags) {
size_t orig_size = 0;
size_t insn_len;
intptr_t trampoline_addr = (intptr_t)trampoline;
@@ -383,12 +383,12 @@ static int subhook_make_trampoline(void *trampoline,
*/
return subhook_make_jmp((void *)(trampoline_addr + orig_size),
(void *)(src_addr + orig_size),
- options);
+ flags);
}
SUBHOOK_EXPORT subhook_t SUBHOOK_API subhook_new(void *src,
void *dst,
- subhook_options_t options) {
+ subhook_flags_t flags) {
subhook_t hook;
if ((hook = malloc(sizeof(*hook))) == NULL) {
@@ -398,8 +398,8 @@ SUBHOOK_EXPORT subhook_t SUBHOOK_API subhook_new(void *src,
hook->installed = 0;
hook->src = src;
hook->dst = dst;
- hook->options = options;
- hook->jmp_size = subhook_get_jmp_size(hook->options);
+ hook->flags = flags;
+ hook->jmp_size = subhook_get_jmp_size(hook->flags);
hook->trampoline_size = hook->jmp_size * 2 + MAX_INSN_LEN;
hook->trampoline_len = 0;
@@ -430,7 +430,7 @@ SUBHOOK_EXPORT subhook_t SUBHOOK_API subhook_new(void *src,
hook->src,
hook->jmp_size,
&hook->trampoline_len,
- hook->options);
+ hook->flags);
if (hook->trampoline_len == 0) {
free(hook->trampoline);
@@ -459,7 +459,7 @@ SUBHOOK_EXPORT int SUBHOOK_API subhook_install(subhook_t hook) {
return -EINVAL;
}
- error = subhook_make_jmp(hook->src, hook->dst, hook->options);
+ error = subhook_make_jmp(hook->src, hook->dst, hook->flags);
if (error >= 0) {
hook->installed = true;
return 0;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 1b2514e..92c8461 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -40,39 +40,46 @@ add_custom_command(
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/${asm_file}"
)
-add_executable(subhook_test
+add_executable(subhook_test_exe
test.c
"${CMAKE_CURRENT_BINARY_DIR}/${asm_file}.obj"
)
+set_target_properties(subhook_test_exe PROPERTIES OUTPUT_NAME test)
-set_target_properties(subhook_test PROPERTIES OUTPUT_NAME test)
+enable_language(CXX)
+add_executable(subhook_cxx_test_exe
+ test.cpp
+ "${CMAKE_CURRENT_BINARY_DIR}/${asm_file}.obj"
+)
+set_target_properties(subhook_cxx_test_exe PROPERTIES OUTPUT_NAME test++)
-if(SUBHOOK_FORCE_32BIT)
- if(APPLE)
- set_target_properties(subhook_test PROPERTIES OSX_ARCHITECTURES i386)
- endif()
- if(UNIX)
- set_property(TARGET subhook_test APPEND_STRING PROPERTY
- COMPILE_FLAGS " -m32")
- set_property(TARGET subhook_test APPEND_STRING PROPERTY LINK_FLAGS " -m32")
+foreach(target subhook_test_exe subhook_cxx_test_exe)
+ if(SUBHOOK_FORCE_32BIT)
+ if(APPLE)
+ set_target_properties(${target} PROPERTIES OSX_ARCHITECTURES i386)
+ endif()
+ if(UNIX)
+ set_property(TARGET ${target} APPEND_STRING PROPERTY
+ COMPILE_FLAGS " -m32")
+ set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " -m32")
+ endif()
endif()
-endif()
-target_link_libraries(subhook_test subhook)
+ target_link_libraries(${target} subhook)
-if(MSVC)
- set_property(TARGET subhook_test
- APPEND_STRING PROPERTY LINK_FLAGS " /INCREMENTAL:NO")
-endif()
+ if(MSVC)
+ set_property(TARGET ${target}
+ APPEND_STRING PROPERTY LINK_FLAGS " /INCREMENTAL:NO")
+ endif()
-if(APPLE AND CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT SUBHOOK_FORCE_32BIT)
- set_property(TARGET subhook_test APPEND_STRING PROPERTY
- LINK_FLAGS " -Wl,-no_pie")
-endif()
+ if(APPLE AND CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT SUBHOOK_FORCE_32BIT)
+ set_property(TARGET ${target} APPEND_STRING PROPERTY
+ LINK_FLAGS " -Wl,-no_pie")
+ endif()
-add_test(NAME test COMMAND $<TARGET_FILE:subhook_test>)
+ add_test(NAME ${target}_test COMMAND $<TARGET_FILE:${target}>)
-set(expected_output "\
+ set(expected_output "\
Testing initial install[\r\n]+\
foo_hooked\\(\\) called[\r\n]+\
foo\\(\\) called[\r\n]+\
@@ -83,10 +90,11 @@ Testing trampoline[\r\n]+\
foo_hooked_tr\\(\\) called[\r\n]+\
foo\\(\\) called[\r\n]+\
")
-set_tests_properties(test PROPERTIES
- PASS_REGULAR_EXPRESSION "${expected_output}")
+ set_tests_properties(${target}_test PROPERTIES
+ PASS_REGULAR_EXPRESSION "${expected_output}")
-if(WIN32 AND NOT SUBHOOK_STATIC)
- set_tests_properties(test PROPERTIES
- ENVIRONMENT PATH=$<TARGET_FILE_DIR:subhook>)
-endif()
+ if(WIN32 AND NOT SUBHOOK_STATIC)
+ set_tests_properties(${target}_test PROPERTIES
+ ENVIRONMENT PATH=$<TARGET_FILE_DIR:subhook>)
+ endif()
+endforeach()
diff --git a/tests/test.c b/tests/test.c
index 278a4fd..513c060 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -32,7 +32,7 @@ int main() {
subhook_t foo_hook = subhook_new((void *)foo,
(void *)foo_hooked,
- SUBHOOK_OPTION_64BIT_OFFSET);
+ SUBHOOK_64BIT_OFFSET);
if (foo_hook == NULL || subhook_install(foo_hook) < 0) {
puts("Install failed");
return EXIT_FAILURE;
@@ -61,7 +61,7 @@ int main() {
subhook_t foo_hook_tr = subhook_new((void *)foo,
(void *)foo_hooked_tr,
- SUBHOOK_OPTION_64BIT_OFFSET);
+ SUBHOOK_64BIT_OFFSET);
if (subhook_install(foo_hook_tr) < 0) {
puts("Install failed");
return EXIT_FAILURE;
diff --git a/tests/test.cpp b/tests/test.cpp
new file mode 100644
index 0000000..0eee1fa
--- /dev/null
+++ b/tests/test.cpp
@@ -0,0 +1,75 @@
+#include <iostream>
+#include <subhook.h>
+
+typedef void (*foo_func_t)();
+
+#ifdef SUBHOOK_X86
+ #if defined SUBHOOK_WINDOWS
+ #define FOO_CALL __cdecl
+ #elif defined SUBHOOK_UNIX
+ #define FOO_CALL __attribute__((cdecl))
+ #endif
+#else
+ #define FOO_CALL
+#endif
+
+extern "C" void FOO_CALL foo();
+foo_func_t foo_tr = nullptr;
+
+void foo_hooked() {
+ std::cout << "foo_hooked() called" << std::endl;;
+}
+
+void foo_hooked_tr() {
+ std::cout << "foo_hooked_tr() called" << std::endl;
+ foo_tr();
+}
+
+int main() {
+ std::cout << "Testing initial install" << std::endl;
+
+ subhook::Hook foo_hook((void *)foo,
+ (void *)foo_hooked,
+ subhook::HookFlag64BitOffset);
+ if (!foo_hook.Install()) {
+ std::cout << "Install failed" << std::endl;
+ return EXIT_FAILURE;
+ }
+ foo();
+ if (!foo_hook.Remove()) {
+ std::cout << "Remove failed" << std::endl;
+ return EXIT_FAILURE;
+ }
+ foo();
+
+ std::cout << "Testing re-install" << std::endl;
+
+ if (!foo_hook.Install()) {
+ std::cout << "Install failed" << std::endl;
+ return EXIT_FAILURE;
+ }
+ foo();
+ if (!foo_hook.Remove()) {
+ std::cout << "Remove failed" << std::endl;
+ return EXIT_FAILURE;
+ }
+ foo();
+
+ std::cout << "Testing trampoline" << std::endl;
+
+ subhook::Hook foo_hook_tr((void *)foo,
+ (void *)foo_hooked_tr,
+ subhook::HookFlag64BitOffset);
+ if (!foo_hook_tr.Install()) {
+ std::cout << "Install failed" << std::endl;
+ return EXIT_FAILURE;
+ }
+ foo_tr = (foo_func_t)foo_hook_tr.GetTrampoline();
+ if (foo_tr == nullptr) {
+ std::cout << "Failed to build trampoline" << std::endl;
+ return EXIT_FAILURE;
+ }
+ foo();
+
+ return EXIT_SUCCESS;
+}