From 10fdb22cf1a483384a08ecf51e2f8adeb4ad6f8d Mon Sep 17 00:00:00 2001 From: Zephyr Lykos Date: Mon, 16 Sep 2024 07:17:34 +0800 Subject: [PATCH 1/3] Add meson build system support --- .gitignore | 5 ++ meson.build | 182 ++++++++++++++++++++++++++++++++++++++ meson_options.txt | 6 ++ src/disasm.h | 2 +- subprojects/capstone.wrap | 7 ++ subprojects/zydis.wrap | 7 ++ 6 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 subprojects/capstone.wrap create mode 100644 subprojects/zydis.wrap diff --git a/.gitignore b/.gitignore index 6fc52c5..7aea196 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,8 @@ *~ /build* +# subproject directories +/subprojects/* +!/subprojects/packagefiles/ +!/subprojects/*.wrap +/subprojects/zycore.wrap diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..df16f2e --- /dev/null +++ b/meson.build @@ -0,0 +1,182 @@ +project( + 'funchook', + 'c', + version: '2.0.0', + # Nearly Classpath-exception-2.0, but not exactly. Additional clause: + # "If you modify this library, you must extend this exception to + # your version of the library." + license: 'GPL-2.0-or-later WITH Classpath-exception-2.0', + default_options: [ + 'c_std=c11', + 'warning_level=2', + ], + meson_version: '>=1.2', +) + +cc = meson.get_compiler('c') + +host_cpu_family = host_machine.cpu_family() + +if host_cpu_family in ['x86', 'x86_64'] + funchook_cpu = 'x86' + default_disasm = 'Zydis' +elif host_cpu_family == 'aarch64' + funchook_cpu = 'arm64' + default_disasm = 'capstone' +endif + +host_system = host_machine.system() + +funchook_deps = [] +cdata = configuration_data() + +if host_system in ['windows', 'cygwin'] + funchook_os = 'windows' + funchook_deps += cc.find_library('psapi') +else + funchook_os = 'unix' + funchook_deps += dependency('dl') +endif + +if host_machine.system() == 'linux' + add_project_arguments( + '-D_GNU_SOURCE', + language: 'c', + ) + # musl libc doesn't provide the GNU-specific version of strerror_r + # even when _GNU_SOURCE is defined. + gnu_strerror_r = cc.compiles( + ''' + #define _GNU_SOURCE + #include + int main() + { + char dummy[128]; + return *strerror_r(0, dummy, sizeof(dummy)); + } + ''', + ) + cdata.set10('GNU_SPECIFIC_STRERROR_R', gnu_strerror_r) +endif + +disasm = get_option('disasm') +if disasm == 'auto' + funchook_disasm = default_disasm +else + funchook_disasm = disasm +endif + +if funchook_disasm == 'Zydis' + funchook_deps += dependency( + 'zydis', + version: '>=4.0.0', + default_options: { + 'minimal': 'enabled', + 'decoder': 'enabled', + }, + ) + cdata.set10('DISASM_ZYDIS', true) +elif disasm == 'capstone' + funchook_deps += dependency( + 'capstone', + version: '>=5.0.0', + default_options: { + 'archs': [funchook_cpu], + 'x86_reduce': true, + 'x86_att_disable': true, + }, + ) + cdata.set10('DISASM_CAPSTONE', true) +endif + +sizeof_void_p = cc.sizeof('void*') +cdata.set('SIZEOF_VOID_P', sizeof_void_p) + +configure_file( + output: 'config.h', + configuration: cdata, +) + +hdrs = files( + 'include/funchook.h', +) + +src = files( + 'src/funchook.c', + f'src/arch_@funchook_cpu@.c', + f'src/os_@funchook_os@.c', + f'src/disasm_@funchook_disasm@.c', +) + +extra_masmflags = [] + +if funchook_cpu == 'x86' and sizeof_void_p == 8 + if cc.get_id() == 'msvc' and add_languages('masm', native: false) + prehook = 'prehook-x86_64-ms' + src += configure_file( + input: 'src' / f'@prehook@.asm', + output: f'@prehook@.masm', + copy: true, + ) + elif funchook_os == 'windows' + src += files('src/prehook-x86_64-ms.S') + else + src += files('src/prehook-x86_64-sysv.S') + endif +endif + +if funchook_cpu == 'x86' and sizeof_void_p == 4 + if cc.get_id() == 'msvc' and add_languages('masm', native: false) + prehook = 'prehook-i686-ms' + src += configure_file( + input: 'src' / f'@prehook@.asm', + output: f'@prehook@.masm', + copy: true, + ) + extra_masmflags += '/safeseh' + else + src += files('src/prehook-i686-gas.S') + endif +endif + +if funchook_cpu == 'arm64' + if cc.get_id() == 'msvc' and add_languages('masm', native: false) + prehook = 'prehook-arm64-ms' + src += configure_file( + input: 'src' / f'@prehook@.asm', + output: f'@prehook@.masm', + copy: true, + ) + else + src += files('src/prehook-arm64-gas.S') + endif +endif + +inc = include_directories('include') + +funchook_lib = library( + 'funchook', + src, + include_directories: inc, + dependencies: funchook_deps, + masm_args: extra_masmflags, + version: meson.project_version(), + install: true, +) + +install_headers(hdrs) + +funchook_dep = declare_dependency( + link_with: funchook_lib, + include_directories: inc, +) + +pkg = import('pkgconfig') +pkg.generate( + funchook_lib, + name: 'funchook', + description: 'Cross platform inline hooking library', + url: 'https://github.com/kubo/funchook', +) + +meson.override_dependency('funchook', funchook_dep) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..9148b86 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,6 @@ +option( + 'disasm', + type: 'combo', + choices: ['auto', 'Zydis', 'capstone'], + value: 'auto', +) diff --git a/src/disasm.h b/src/disasm.h index d19a3f0..2ddb8f7 100644 --- a/src/disasm.h +++ b/src/disasm.h @@ -51,7 +51,7 @@ typedef _DInst funchook_insn_t; #endif #ifdef DISASM_CAPSTONE -#include +#include typedef struct funchook_disasm { funchook_t *funchook; diff --git a/subprojects/capstone.wrap b/subprojects/capstone.wrap new file mode 100644 index 0000000..f75e1e6 --- /dev/null +++ b/subprojects/capstone.wrap @@ -0,0 +1,7 @@ +[wrap-git] +url = https://github.com/frida/capstone.git +revision = e98746112da0a40b2ccd0340db0d20cca5f97950 +depth = 1 + +[provide] +dependency_names = capstone diff --git a/subprojects/zydis.wrap b/subprojects/zydis.wrap new file mode 100644 index 0000000..a204554 --- /dev/null +++ b/subprojects/zydis.wrap @@ -0,0 +1,7 @@ +[wrap-git] +url = https://github.com/zyantific/zydis.git +revision = cb487f1cb477b2c03345aa72baf7eda725b77507 +depth = 1 + +[provide] +dependency_names = zydis From 6d4d96c3d4e0929b4af10d071e606376bc43262c Mon Sep 17 00:00:00 2001 From: Zephyr Lykos Date: Tue, 7 Jan 2025 20:59:54 +0800 Subject: [PATCH 2/3] Support Zydis V5 --- meson.build | 16 +++++++++++++++- src/disasm_Zydis.c | 4 ++++ subprojects/zydis.wrap | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index df16f2e..e30d622 100644 --- a/meson.build +++ b/meson.build @@ -67,7 +67,7 @@ else endif if funchook_disasm == 'Zydis' - funchook_deps += dependency( + zydis_dep = dependency( 'zydis', version: '>=4.0.0', default_options: { @@ -76,6 +76,20 @@ if funchook_disasm == 'Zydis' }, ) cdata.set10('DISASM_ZYDIS', true) + + cdata.set10( + 'DISASM_ZYDIS_V5', + cc.has_member( + 'ZydisDecodedOperandMem', + 'disp.size', + dependencies: zydis_dep.partial_dependency(compile_args: true, includes: true), + prefix: ''' + #include + ''', + ), + ) + + funchook_deps += zydis_dep elif disasm == 'capstone' funchook_deps += dependency( 'capstone', diff --git a/src/disasm_Zydis.c b/src/disasm_Zydis.c index c2b585c..9490e74 100644 --- a/src/disasm_Zydis.c +++ b/src/disasm_Zydis.c @@ -130,7 +130,11 @@ void funchook_disasm_x86_rip_relative(funchook_disasm_t *disasm, const funchook_ int i; for (i = 0; i < insn->insn.operand_count; i++) { const ZydisDecodedOperand *op = &insn->operands[i]; +#if DISASM_ZYDIS_V5 + if (op->mem.disp.size != 0 && op->mem.base == ZYDIS_REGISTER_RIP) { +#else if (op->mem.disp.has_displacement && op->mem.base == ZYDIS_REGISTER_RIP) { +#endif // Fix IP-relative addressing such as: // mov eax, dword ptr [rip + 0x236eda] // jmp qword ptr [rip + 0x239468] diff --git a/subprojects/zydis.wrap b/subprojects/zydis.wrap index a204554..c0cb84c 100644 --- a/subprojects/zydis.wrap +++ b/subprojects/zydis.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://github.com/zyantific/zydis.git -revision = cb487f1cb477b2c03345aa72baf7eda725b77507 +revision = bffbb610cfea643b98e87658b9058382f7522807 depth = 1 [provide] From 332741f56739b4843b52d2bfb344e491cc7ba0a3 Mon Sep 17 00:00:00 2001 From: Dmitriy Goncharov Date: Thu, 12 Dec 2024 12:41:01 +0700 Subject: [PATCH 3/3] Fixed the search for the region closest to the function --- src/os_unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os_unix.c b/src/os_unix.c index 65150d2..02b7099 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -416,7 +416,7 @@ void *funchook_resolve_func(funchook_t *funchook, void *func) if ((void*)lm->l_addr <= func) { if (lmap == NULL) { lmap = lm; - } else if (lmap->l_addr > lm->l_addr) { + } else if (lmap->l_addr < lm->l_addr) { lmap = lm; } }