3
0
mirror of https://github.com/CrazyRedMachine/popnhax.git synced 2024-11-27 15:30:50 +01:00

Omnimix v2

This commit is contained in:
CrazyRedMachine 2023-02-10 20:29:11 +01:00 committed by CrazyRedMachine
parent 86d7046bbc
commit 698e9c5476
53 changed files with 7679 additions and 1 deletions

275
Makefile Normal file
View File

@ -0,0 +1,275 @@
# vim: noexpandtab sts=8 sw=8 ts=8
#
# Overridable variables
#
export SHELL := /bin/bash
BUILDDIR ?= build
#
# Internal variables
#
export TZ := /usr/share/zoneinfo/Japan
ifeq ($(USE_CCACHE),yes)
ccache := ccache
else
ccache :=
endif
depdir := $(BUILDDIR)/dep
objdir := $(BUILDDIR)/obj
bindir := $(BUILDDIR)/bin
toolchain_32 := i686-w64-mingw32-
toolchain_64 := x86_64-w64-mingw32-
cppflags := -I. \
-DNDEBUG \
-D_NEED_FULLVERSION_INFO=1 -D_SECURE_SCL=1 \
-D_CRT_SECURE_NO_WARNINGS=1 -D_NO_CRT_STDIO_INLINE=1 \
-D_WINSOCK_DEPRECATED_NO_WARNINGS=1 \
-DFKG_FORCED_USAGE=1 -DOFFICIAL_BUILD=1 -DBETA=1 -DDEVL=1
com_wflags := -Wall -Werror -Wpointer-arith -Wreturn-type \
-Wwrite-strings -Wswitch -Wcast-align -Wchar-subscripts \
-Wredundant-decls -Wunreachable-code -Wno-pedantic \
-Wshadow -Winline -Wno-cast-qual -Wno-multichar \
-fstrict-aliasing -Wno-unused-function \
-Warray-bounds=2 -Wno-redundant-decls
wflags := $(com_wflags) -Wno-strict-prototypes -Wnested-externs \
-Wno-discarded-qualifiers
wxxflags := $(com_wflags) -Wno-old-style-cast
cflags := -O3 -pipe -ffunction-sections -fdata-sections \
-std=gnu11 $(wflags)
cxxflags := -O3 -pipe -ffunction-sections -fdata-sections \
-std=c++11 $(wxxflags)
ldflags := -Wl,--gc-sections -static -static-libgcc -lstdc++ \
-fdiagnostics-color -Werror \
-Wl,--gc-keep-exported \
-Wl,--enable-auto-image-base \
-Wl,--exclude-all-symbols \
-Wl,--dynamicbase \
-Wl,--nxcompat \
-Wl,-s
#
# The first target that GNU Make encounters becomes the default target.
# Define our ultimate target (`all') here, and also some helpers
#
all:
.PHONY: clean
clean:
rm -rf $(BUILDDIR)
#
# Pull in module definitions
#
deps :=
dlls :=
exes :=
imps :=
libs :=
avsdlls :=
avsexes :=
include Module.mk
modules := $(dlls) $(exes) $(libs) $(avsdlls) $(avsexes)
#
# $1: Bitness
# $2: AVS2 minor version
# $3: Module
#
optflags_64 += -mfpmath=sse -march=x86-64 \
-mtune=generic -mabi=ms -malign-data=cacheline \
-minline-stringops-dynamically -funswitch-loops \
-funroll-loops -fschedule-insns2 -fsched-pressure \
-fprefetch-loop-arrays --param prefetch-latency=300 \
-fsel-sched-pipelining -fselective-scheduling \
-ftree-vectorize -fbranch-target-load-optimize \
-flive-range-shrinkage -falign-functions=16 \
-flto -fno-use-linker-plugin -masm=intel
optflags_32 += -mfpmath=sse -march=pentium-m -mtune=generic \
-mabi=ms -malign-data=cacheline \
-minline-stringops-dynamically -funswitch-loops \
-funroll-loops -fschedule-insns2 -fsched-pressure \
-fprefetch-loop-arrays --param prefetch-latency=300 \
-fsel-sched-pipelining -fselective-scheduling \
-ftree-vectorize -fbranch-target-load-optimize \
-flive-range-shrinkage -falign-functions=16 \
-flto -fno-use-linker-plugin -masm=intel
cflags_32 := $(optflags_32)
cxxflags_32 := $(optflags_32)
cflags_64 := $(optflags_64)
cxxflags_64 := $(optflags_64)
define t_moddefs
cppflags_$3 += $(cppflags) -DBUILD_MODULE=$3
cflags_$3 += $(cflags)
cxxflags_$3 += $(cxxflags)
ldflags_$3 += $(ldflags)
srcdir_$3 := $3
endef
$(eval $(foreach module,$(modules),$(call t_moddefs,_,_,$(module))))
##############################################################################
define t_bitness
subdir_$1_indep := indep-$1
bindir_$1_indep := $(bindir)/$$(subdir_$1_indep)
$$(bindir_$1_indep):
mkdir -p $$@
$$(eval $$(foreach imp,$(imps),$$(call t_import,$1,indep,$$(imp))))
$$(eval $$(foreach dll,$(dlls),$$(call t_linkdll,$1,indep,$$(dll))))
$$(eval $$(foreach exe,$(exes),$$(call t_linkexe,$1,indep,$$(exe))))
$$(eval $$(foreach lib,$(libs),$$(call t_archive,$1,indep,$$(lib))))
$$(eval $$(foreach avsver,$$(avsvers_$1),$$(call t_avsver,$1,$$(avsver))))
endef
##############################################################################
define t_avsver
subdir_$1_$2 := avs2_$2-$1
bindir_$1_$2 := $(bindir)/$$(subdir_$1_$2)
$$(bindir_$1_$2):
mkdir -p $$@
$$(eval $$(foreach imp,$(imps),$$(call t_import,$1,$2,$$(imp))))
$$(eval $$(foreach dll,$(avsdlls),$$(call t_linkdll,$1,$2,$$(dll))))
$$(eval $$(foreach exe,$(avsexes),$$(call t_linkexe,$1,$2,$$(exe))))
endef
##############################################################################
define t_compile
depdir_$1_$2_$3 := $(depdir)/$$(subdir_$1_$2)/$3
abslib_$1_$2_$3 := $$(libs_$3:%=$$(bindir_$1_indep)/lib%.a)
absdpl_$1_$2_$3 := $$(deplibs_$3:%=$$(bindir_$1_$2)/lib%.a)
objdir_$1_$2_$3 := $(objdir)/$$(subdir_$1_$2)/$3
obj_$1_$2_$3 := $$(src_$3:%.c=$$(objdir_$1_$2_$3)/%.o) \
$$(rc_$3:%.rc=$$(objdir_$1_$2_$3)/%_rc.o) \
$$(srcpp_$3:%.cc=$$(objdir_$1_$2_$3)/%.o)
deps += $$(src_$3:%.c=$$(depdir_$1_$2_$3)/%.d) \
$$(srcpp_$3:%.cc=$$(depdir_$1_$2_$3)/%.d)
$$(depdir_$1_$2_$3):
mkdir -p $$@
$$(objdir_$1_$2_$3):
mkdir -p $$@
$$(objdir_$1_$2_$3)/%.o: $$(srcdir_$3)/%.c \
| $$(depdir_$1_$2_$3) $$(objdir_$1_$2_$3)
$(ccache) $$(toolchain_$1)gcc $$(cflags_$3) $$(cflags_$1) $$(cppflags_$3) \
-MMD -MF $$(depdir_$1_$2_$3)/$$*.d -MT $$@ -MP \
-DAVS_VERSION=$2 -c -o $$@ $$<
$$(objdir_$1_$2_$3)/%.o: $$(srcdir_$3)/%.cc \
| $$(depdir_$1_$2_$3) $$(objdir_$1_$2_$3)
$(ccache) $$(toolchain_$1)g++ $$(cxxflags_$3) $$(cxxflags_$1) $$(cppflags_$3) \
-MMD -MF $$(depdir_$1_$2_$3)/$$*.d -MT $$@ -MP \
-DAVS_VERSION=$2 -c -o $$@ $$<
$$(objdir_$1_$2_$3)/%_rc.o: $$(srcdir_$3)/%.rc \
| $$(depdir_$1_$2_$3) $$(objdir_$1_$2_$3)
$$(toolchain_$1)windres $$(cppflags_$3) $$< $$@
endef
##############################################################################
define t_archive
$(t_compile)
$$(bindir_$1_$2)/lib$3.a: $$(obj_$1_$2_$3) | $$(bindir_$1_$2)
$$(toolchain_$1)gcc-ar r $$@ $$^ 2> /dev/null
$$(toolchain_$1)gcc-ranlib $$@
endef
##############################################################################
define t_linkdll
$(t_compile)
dll_$1_$2_$3 := $$(bindir_$1_$2)/$3.dll
implib_$1_$2_$3 := $$(bindir_$1_$2)/lib$3.a
$$(dll_$1_$2_$3) $$(implib_$1_$2_$3): $$(obj_$1_$2_$3) $$(abslib_$1_$2_$3) \
$$(absdpl_$1_$2_$3) \
$$(srcdir_$3)/$3.def | $$(bindir_$1_$2)
$(ccache) $$(toolchain_$1)gcc -shared $$(srcdir_$3)/$3.def \
-o $$(dll_$1_$2_$3) -Wl,--out-implib,$$(implib_$1_$2_$3) \
$$^ $$(ldflags_$3) $(optflags_$1)
$$(toolchain_$1)strip -s $$(dll_$1_$2_$3)
$$(toolchain_$1)ranlib $$(implib_$1_$2_$3)
endef
##############################################################################
define t_linkexe
$(t_compile)
exe_$1_$2_$3 := $$(bindir_$1_$2)/$3.exe
$$(exe_$1_$2_$3): $$(obj_$1_$2_$3) $$(abslib_$1_$2_$3) $$(absdpl_$1_$2_$3) \
| $$(bindir_$1_$2)
$(ccache) $$(toolchain_$1)gcc -o $$@ $$^ $$(ldflags_$3) $(optflags_$1)
$$(toolchain_$1)strip -s $$@
endef
##############################################################################
define t_import
impdef_$1_$2_$3 ?= imports/import_$1_$2_$3.def
$$(bindir_$1_$2)/lib$3.a: $$(impdef_$1_$2_$3) | $$(bindir_$1_$2)
$$(toolchain_$1)dlltool -l $$@ -d $$<
endef
##############################################################################
$(eval $(foreach bitness,32 64,$(call t_bitness,$(bitness))))
#
# Pull in GCC-generated dependency files
#
-include $(deps)

34
Module.mk Normal file
View File

@ -0,0 +1,34 @@
cflags += -DWIN32_LEAN_AND_MEAN -DCOBJMACROS -Ipkcs11 -Wno-attributes
avsvers_32 := 1700 1508
avsvers_64 := 1700 1509
imps += avs avs-ea3
include util/Module.mk
include minhook/Module.mk
include popnhax/Module.mk
#
# Distribution build rules
#
zipdir := $(BUILDDIR)/zip
$(zipdir)/:
mkdir -p $@
$(BUILDDIR)/popnhax.zip: \
build/bin/avs2_1508-32/popnhax.dll \
dist/popnhax/popnhax.xml \
| $(zipdir)/
echo ... $@
zip -j $@ $^
$(BUILDDIR)/bemanihax.zip: \
$(BUILDDIR)/popnhax.zip \
| $(zipdir)/
echo ... $@
zip -9 -q -j $@ $^
all: $(BUILDDIR)/bemanihax.zip

View File

@ -1,2 +1,11 @@
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/donate?hosted_button_id=WT735CX4UMZ9U)
# popnhax # popnhax
popnhax
Arcade game patcher.
Based on [bemanihax](https://github.com/windyfairy/bemanihax) whose an updated version was included with omnimix v1
### Build Instructions
Should be working out of the box with MSYS2/MinGW32. Just run `make`.

30
clang-format.py Normal file
View File

@ -0,0 +1,30 @@
import os
import subprocess
ignore_folders = [".git", "build", "dist", "minhook"]
cpp_extensions = (".cpp", ".cxx", ".c++", ".h++", ".hpp", ".hxx")
for root, dirs, files in os.walk(".", topdown=True):
dirs[:] = [d for d in dirs if d not in ignore_folders]
for filename in files:
if filename.endswith(cpp_extensions):
print(filename)
subprocess.check_call(["clang-format", "-i", "-style=file", root + "/" + filename])
# print(" ".join(["clang-tidy", root + "/" + filename, "--", "-I."]))
subprocess.check_call(["./clang-tidy.sh", root + "/" + filename, "c++11"])
print()
cpp_extensions = (".cc", ".cp", ".c", ".i", ".ii", ".h")
for root, dirs, files in os.walk(".", topdown=True):
dirs[:] = [d for d in dirs if d not in ignore_folders]
for filename in files:
if filename.endswith(cpp_extensions):
print(filename)
subprocess.check_call(["clang-format", "-i", "-style=file", root + "/" + filename])
# print(" ".join(["clang-tidy", root + "/" + filename, "--", "-I."]))
subprocess.check_call(["./clang-tidy.sh", root + "/" + filename, "c11"])
print()

36
clang-tidy.sh Normal file
View File

@ -0,0 +1,36 @@
#!/bin/bash
# Run clang-tidy on a source file
TOOLCHAIN_PREFIX=i686-w64-mingw32
CLANG_TIDY=clang-tidy
SYSROOT=$($TOOLCHAIN_PREFIX-gcc -print-sysroot)/mingw
if [ ! -f $SYSROOT/include/windows.h ]; then
SYSROOT=/usr/i686-w64-mingw32
if [ ! -f $SYSROOT/include/windows.h ]; then
SYSROOT=/usr/local/i686-w64-mingw32
fi
fi
CPP_HEADERS="/usr/share/mingw-w64/include/"
# echo "System root: $SYSROOT"
# echo "C++ headers: $CPP_HEADERS"
$CLANG_TIDY $1 \
-- \
-target i686-w64-mingw32 \
-std=$2 \
--sysroot $SYSROOT \
-isysroot $SYSROOT \
-I $CPP_HEADERS \
-I. \
-Iinclude \
-Dssize_t=int \
-DAVS_VERSION=1700 \
-D_CRT_SECURE_NO_WARNINGS=1 \
-Di386=1 \
-D__i386=1 \
-D__i386__=1 \
-D_WIN32=1 \
-DCOBJMACROS

26
dist/popnhax/popnhax.xml vendored Normal file
View File

@ -0,0 +1,26 @@
<?xml version='1.0' encoding='shift-jis'?>
<popnhax>
<!-- Force unlock music, charts, characters, and deco parts -->
<force_unlocks __type="bool">1</force_unlocks>
<!-- Prevent Windows volume from being reset on boot -->
<unset_volume __type="bool">0</unset_volume>
<!-- Force booting directly into event mode -->
<event_mode __type="bool">1</event_mode>
<!-- Remove the timer completely without event mode -->
<remove_timer __type="bool">0</remove_timer>
<!-- or Freeze the timer at 10 seconds after counting down -->
<freeze_timer __type="bool">0</freeze_timer>
<!-- Force skip menu and long note tutorials without a card -->
<skip_tutorials __type="bool">1</skip_tutorials>
<!-- Settings for database hooking patches follow: -->
<!-- Enable database modifications -->
<patch_db __type="bool">1</patch_db>
<!-- Force the newly created buffers to be the same size as the original buffers -->
<disable_expansions __type="bool">0</disable_expansions>
<!-- Copy the new table information over top the old tables (automatically enables disable_expansions) -->
<disable_redirection __type="bool">0</disable_redirection>
<!-- Autoload latest patch file (highest datecode) from data_mods folder -->
<patch_xml_auto __type="bool">1</patch_xml_auto>
<!-- Manually set XML file containing patches (requires patch_xml_auto to be disabled) -->
<patch_xml_filename __type="str"></patch_xml_filename>
</popnhax>

92
imports/avs-ea3.h Normal file
View File

@ -0,0 +1,92 @@
#ifndef IMPORTS_AVS_EA3_H
#define IMPORTS_AVS_EA3_H
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(AVS_VERSION)
#error "Can't build AVS-dependent project using AVS-independent make rules"
#elif AVS_VERSION == 1509
#define ea3_xrpc_apply XE592acd000057
#define ea3_xrpc_module_register XE592acd000060
#define ea3_xrpc_new XE592acd000052
#define ea3_xrpc_destroy XE592acd000007
#define ea3_boot XE592acd00008c
#define ea3_shutdown XE592acd00005a
#else
#error AVS obfuscated import macros have not been declared for this version
#endif
#define XRPC_STATUS_SERVER_FAULT_ERROR (-17)
#define XRPC_STATUS_SERVER_RESPONSE_ERROR (-18)
void ea3_boot(struct property_node *conf);
void ea3_shutdown(void);
struct xrpc_handle;
struct xrpc_server_handle;
struct xrpc_status {
int16_t status;
int16_t subcode;
int16_t status_code;
int16_t fault_code;
} __attribute__((gcc_struct, packed));
struct xrpc_arg_list {
const char *name;
const char *property_path;
bool omittable;
} __attribute__((gcc_struct, packed));
/*
* The following defines the codes used inside the 'status@' attribute
* used in a xrpc response.
*/
enum ea3_general_status_codes {
XRPC_OK = 0, /* No error */
};
enum xrpc_method_types {
HTTPAC_HTTP10 = 0x1,
};
struct xrpc_method {
const char *xrpc_meth_name;
bool(__cdecl *xrpc_cb_init)(void *shmem, char *buffer);
bool(__cdecl *xrpc_cb_sender)(void *shmem, struct property_node *node);
bool(__cdecl *xrpc_cb_receiver)(void *shmem, struct property_node *node);
char crypt_level;
char padding_00;
bool use_xrpc11;
bool use_esign;
bool use_ssl;
char compress_type;
char method_type;
char padding_01;
struct xrpc_arg_list *arg_list;
} __attribute__((gcc_struct, packed));
typedef int (*xrpc_apply_exit_callback_t)(void *buffer, struct xrpc_status status, void *param);
int ea3_xrpc_apply(struct xrpc_handle *handle, const char *name, void *shmem,
xrpc_apply_exit_callback_t cbexit, void *cbexit_data, ...);
struct xrpc_handle *ea3_xrpc_new(size_t sz_xrpc_buf, const char *xrpc_encoding, uint32_t flags);
void ea3_xrpc_destroy(struct xrpc_handle *handle);
int ea3_xrpc_module_register(const char *xrpc_endpoint, const char *services_url, uint32_t flags,
struct xrpc_method *method_array);
#ifdef __cplusplus
}
#endif
#endif

188
imports/avs.h Normal file
View File

@ -0,0 +1,188 @@
#ifndef IMPORTS_AVS_H
#define IMPORTS_AVS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <windows.h>
#if !defined(AVS_VERSION)
#error "Can't build AVS-dependent project using AVS-independent make rules"
#elif AVS_VERSION == 1508 || AVS_VERSION == 1509
#define avs_thread_delay XCd229cc00012b
#define property_search XCd229cc00012e
#define boot XCd229cc0000aa
#define shutdown XCd229cc00001d
#define property_desc_to_buffer XCd229cc0000fd
#define property_destroy XCd229cc00013c
#define property_read_query_memsize XCd229cc0000ff
#define property_create XCd229cc000126
#define property_insert_read XCd229cc00009a
#define property_node_create XCd229cc00002c
#define property_node_remove XCd229cc000028
#define property_node_refer XCd229cc000009
#define std_setenv XCd229cc000094
#define avs_fs_open XCd229cc000090
#define avs_fs_copy XCd229cc0000eb
#define avs_fs_close XCd229cc00011f
#define avs_fs_dump_mountpoint XCd229cc0000e9
#define avs_fs_mount XCd229cc0000ce
#define avs_fs_fstat XCd229cc0000c3
#define avs_fs_lstat XCd229cc0000c0
#define avs_fs_lseek XCd229cc00004d
#define avs_fs_read XCd229cc00010d
#define avs_fs_opendir XCd229cc0000f0
#define avs_fs_readdir XCd229cc0000bb
#define avs_fs_closedir XCd229cc0000b8
#define cstream_create XCd229cc000141
#define cstream_operate XCd229cc00008c
#define cstream_finish XCd229cc000025
#define cstream_destroy XCd229cc0000e3
#define property_node_read XCd229cc0000f3
#define property_node_write XCd229cc00002d
#define property_file_write XCd229cc000052
#define property_node_traversal XCd229cc000046
#define property_psmap_export XCd229cc000006
#define property_psmap_import XCd229cc000005
#define property_node_name XCd229cc000049
#define property_node_get_desc XCd229cc000165
#define property_get_error XCd229cc0000b5
#define property_node_clone XCd229cc00010a
#define property_query_size XCd229cc000032
#define property_node_query_stat XCd229cc0000b1
#define property_node_datasize XCd229cc000083
#define property_mem_write XCd229cc000033
#define property_part_write XCd229cc000024
#define property_node_absolute_path XCd229cc00007c
#define property_node_has XCd229cc00008a
#define property_node_is_array XCd229cc000142
#define property_node_type XCd229cc000071
#define property_get_attribute_bool XCd229cc000043
#define property_node_get_attribute_bool XCd229cc000110
#define property_node_get_attribute_u32 XCd229cc0000db
#define property_node_get_attribute_s32 XCd229cc00011a
#define property_node_rename XCd229cc0000af
#define property_query_freesize XCd229cc000144
#define property_clear_error XCd229cc00014b
#define property_lookup_encode XCd229cc0000fc
#define property_unlock_flag XCd229cc000145
#define property_lock_flag XCd229cc000121
#define property_set_flag XCd229cc000035
#define property_part_write_meta XCd229cc00004f
#define property_part_write_meta2 XCd229cc000107
#define property_read_data XCd229cc0000de
#define property_read_meta XCd229cc00010e
#define property_get_attribute_u32 XCd229cc000148
#define property_get_attribute_s32 XCd229cc00005f
#define property_get_fingerprint XCd229cc000057
#define property_node_refdata XCd229cc00009f
#define property_insert_read_with_filename XCd229cc0000cd
#define property_mem_read XCd229cc000039
#define property_read_query_memsize_long XCd229cc00002b
#define property_clear XCd229cc0000c2
#define avs_net_add_protocol XCd229cc000156
#define avs_net_del_protocol XCd229cc00000f
#define avs_net_addrinfobyaddr XCd229cc000040
#define avs_net_socket XCd229cc000026
#define avs_net_setsockopt XCd229cc000092
#define avs_net_getsockopt XCd229cc000084
#define avs_net_connect XCd229cc000038
#define avs_net_send XCd229cc00011d
#define avs_net_recv XCd229cc000131
#define avs_net_pollfds_add XCd229cc00004b
#define avs_net_pollfds_get XCd229cc000105
#define avs_net_bind XCd229cc00007e
#define avs_net_close XCd229cc00009c
#define avs_net_shutdown XCd229cc0000ac
#define avs_net_get_peername XCd229cc000085
#define avs_net_get_sockname XCd229cc0000b0
#elif AVS_VERSION == 1700
#define property_create XCgsqzn0000090
#define property_insert_read XCgsqzn0000094
#define property_read_query_memsize XCgsqzn00000b0
#define property_psmap_import XCgsqzn00000b2
#else
#error AVS obfuscated import macros have not been declared for this version
#endif
enum property_type {
PROPERTY_TYPE_VOID = 1,
PROPERTY_TYPE_S8 = 2,
PROPERTY_TYPE_U8 = 3,
PROPERTY_TYPE_S16 = 4,
PROPERTY_TYPE_U16 = 5,
PROPERTY_TYPE_S32 = 6,
PROPERTY_TYPE_U32 = 7,
PROPERTY_TYPE_S64 = 8,
PROPERTY_TYPE_U64 = 9,
PROPERTY_TYPE_BIN = 10,
PROPERTY_TYPE_STR = 11,
PROPERTY_TYPE_FLOAT = 14,
PROPERTY_TYPE_ATTR = 46,
PROPERTY_TYPE_BOOL = 52,
};
enum property_node_traversal {
TRAVERSE_PARENT = 0,
TRAVERSE_FIRST_CHILD = 1,
TRAVERSE_FIRST_ATTR = 2,
TRAVERSE_FIRST_SIBLING = 3,
TRAVERSE_NEXT_SIBLING = 4,
TRAVERSE_PREVIOUS_SIBLING = 5,
TRAVERSE_LAST_SIBLING = 6,
TRAVERSE_NEXT_SEARCH_RESULT = 7,
TRAVERSE_PREV_SEARCH_RESULT = 8,
};
struct property;
struct property_node;
struct property_psmap;
typedef int (*avs_reader_t)(uint32_t context, void *bytes, size_t nbytes);
uint32_t property_read_query_memsize(avs_reader_t reader, uint32_t context, int *nodes, int *total);
struct property *property_create(int flags, void *buffer, uint32_t buffer_size);
int property_insert_read(struct property *prop, struct property_node *node, avs_reader_t reader,
uint32_t context);
int property_psmap_import(struct property *prop, struct property_node *root, void *dest,
const struct property_psmap *psmap);
struct property_node *property_node_create(struct property *prop, struct property_node *parent,
int type, const char *key, ...);
struct property_node *property_search(
struct property *prop, struct property_node *root, const char *path);
int property_mem_write(struct property *prop, void *bytes, int nbytes);
void *property_desc_to_buffer(struct property *prop);
void property_file_write(struct property *prop, const char *path);
int property_set_flag(struct property *prop, int flags, int mask);
void property_destroy(struct property *prop);
int property_node_refer(
struct property *prop,
struct property_node *node,
const char *name,
enum property_type type,
void *bytes,
uint32_t nbytes);
struct property_node *property_node_traversal(
struct property_node *node, enum property_node_traversal direction);
void avs_thread_delay(size_t ms, int zero);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,36 @@
LIBRARY libavs-win32
EXPORTS
avs_boot
avs_net_ctrl
avs_shutdown
avs_thread_create
avs_thread_destroy
avs_thread_exit
avs_thread_join
log_body_fatal
log_body_info
log_body_misc
log_body_warning
log_boot
log_change_level
property_create
property_desc_to_buffer
property_destroy
property_file_write
property_insert_read
property_mem_write
property_read_query_memsize
property_search
property_set_flag
property_node_clone
property_node_create
property_node_name
property_node_refer
property_node_remove
property_node_type
property_node_traversal
property_node_refdata
std_getenv
std_setenv

View File

@ -0,0 +1,28 @@
LIBRARY libavs-win32
EXPORTS
avs_boot @22 NONAME
avs_net_ctrl @107 NONAME
avs_shutdown @140 NONAME
avs_thread_create @156 NONAME
avs_thread_destroy @158 NONAME
avs_thread_exit @159 NONAME
avs_thread_join @161 NONAME
log_assert_body @196 NONAME
log_body_misc @199 NONAME
log_body_info @198 NONAME
log_body_warning @200 NONAME
log_body_fatal @197 NONAME
property_create @245 NONAME
property_desc_to_buffer @246 NONAME
property_destroy @247 NONAME
property_insert_read @255 NONAME
property_node_create @266 NONAME
property_node_refer @278 NONAME
property_node_remove @279 NONAME
property_psmap_import @288 NONAME
property_psmap_export @287 NONAME
property_read_query_memsize @291 NONAME
property_search @294 NONAME
std_getenv @308 NONAME
std_setenv @322 NONAME

View File

@ -0,0 +1,27 @@
LIBRARY libavs-win32
EXPORTS
avs_boot @237 NONAME
avs_net_ctrl @15 NONAME
avs_shutdown @333 NONAME
avs_thread_create @183 NONAME
avs_thread_destroy @76 NONAME
avs_thread_exit @147 NONAME
avs_thread_join @92 NONAME
log_body_misc @44 NONAME
log_body_info @339 NONAME
log_body_warning @219 NONAME
log_body_fatal @128 NONAME
property_create @256 NONAME
property_desc_to_buffer @201 NONAME
property_destroy @264 NONAME
property_insert_read @23 NONAME
property_node_create @316 NONAME
property_node_refer @268 NONAME
property_node_remove @129 NONAME
property_psmap_import @102 NONAME
property_psmap_export @110 NONAME
property_read_query_memsize @100 NONAME
property_search @244 NONAME
std_getenv @226 NONAME
std_setenv @114 NONAME

View File

@ -0,0 +1,24 @@
LIBRARY libavs-win32
EXPORTS
avs_boot @298 NONAME
avs_net_ctrl @100 NONAME
avs_shutdown @299 NONAME
avs_thread_create @6 NONAME
avs_thread_destroy @8 NONAME
avs_thread_join @13 NONAME
log_body_info @363 NONAME
log_body_misc @364 NONAME
log_body_warning @362 NONAME
log_body_fatal @365 NONAME
property_create @129 NONAME
property_desc_to_buffer @131 NONAME
property_destroy @130 NONAME
property_insert_read @133 NONAME
property_node_remove @148 NONAME
property_psmap_import @163 NONAME
property_psmap_export @164 NONAME
property_read_query_memsize @161 NONAME
property_search @146 NONAME
std_getenv @208 NONAME
std_setenv @209 NONAME

View File

@ -0,0 +1,91 @@
LIBRARY libavs-win32
EXPORTS
XCd229cc00012e
XCd229cc0000aa
XCd229cc00001d
XCd229cc0000fd
XCd229cc00013c
XCd229cc0000ff
XCd229cc000126
XCd229cc00009a
XCd229cc00002c
XCd229cc000028
XCd229cc000009
XCd229cc000094
XCd229cc000090
XCd229cc0000eb
XCd229cc00011f
XCd229cc0000e9
XCd229cc0000ce
XCd229cc0000c3
XCd229cc0000c0
XCd229cc00004d
XCd229cc00010d
XCd229cc0000f0
XCd229cc0000bb
XCd229cc0000b8
XCd229cc000141
XCd229cc00008c
XCd229cc000025
XCd229cc0000e3
XCd229cc0000f3
XCd229cc00002d
XCd229cc000052
XCd229cc000046
XCd229cc000006
XCd229cc000005
XCd229cc000049
XCd229cc000165
XCd229cc0000b5
XCd229cc00010a
XCd229cc000032
XCd229cc0000b1
XCd229cc000083
XCd229cc000033
XCd229cc000024
XCd229cc00007c
XCd229cc00008a
XCd229cc000142
XCd229cc000071
XCd229cc000043
XCd229cc000110
XCd229cc0000db
XCd229cc00011a
XCd229cc0000af
XCd229cc000144
XCd229cc00014b
XCd229cc0000fc
XCd229cc000145
XCd229cc000121
XCd229cc000035
XCd229cc00004f
XCd229cc000107
XCd229cc0000de
XCd229cc00010e
XCd229cc000148
XCd229cc00005f
XCd229cc000057
XCd229cc00009f
XCd229cc0000cd
XCd229cc000039
XCd229cc00002b
XCd229cc0000c2
XCd229cc000156
XCd229cc00000f
XCd229cc000040
XCd229cc000026
XCd229cc000092
XCd229cc000084
XCd229cc000038
XCd229cc00011d
XCd229cc000131
XCd229cc00004b
XCd229cc000105
XCd229cc00007e
XCd229cc00009c
XCd229cc0000ac
XCd229cc000085
XCd229cc0000b0

View File

@ -0,0 +1,28 @@
LIBRARY libavs-win32
EXPORTS
avs_thread_create @5 NONAME
avs_thread_destroy @7 NONAME
avs_thread_exit @11 NONAME
avs_thread_join @12 NONAME
avs_net_ctrl @98 NONAME
property_create @124 NONAME
property_destroy @125 NONAME
property_desc_to_buffer @126 NONAME
property_insert_read @128 NONAME
property_search @141 NONAME
property_node_create @142 NONAME
property_node_remove @143 NONAME
property_node_refer @155 NONAME
property_read_query_memsize @156 NONAME
property_psmap_export @159 NONAME
property_psmap_import @158 NONAME
std_getenv @204 NONAME
std_setenv @205 NONAME
avs_boot @283 NONAME
avs_shutdown @284 NONAME
log_body_fatal @361 NONAME
log_body_warning @362 NONAME
log_body_info @363 NONAME
log_body_misc @364 NONAME

View File

@ -0,0 +1,27 @@
LIBRARY libavs-win32
EXPORTS
avs_thread_create @5 NONAME
avs_thread_destroy @7 NONAME
avs_thread_exit @11 NONAME
avs_thread_join @12 NONAME
avs_net_ctrl @119 NONAME
property_create @145 NONAME
property_destroy @146 NONAME
property_desc_to_buffer @147 NONAME
property_insert_read @149 NONAME
property_search @162 NONAME
property_node_create @163 NONAME
property_node_remove @164 NONAME
property_node_refer @176 NONAME
property_read_query_memsize @177 NONAME
property_psmap_import @179 NONAME
property_psmap_export @180 NONAME
std_getenv @212 NONAME
std_setenv @213 NONAME
avs_boot @298 NONAME
avs_shutdown @299 NONAME
log_body_fatal @379 NONAME
log_body_warning @380 NONAME
log_body_info @381 NONAME
log_body_misc @382 NONAME

View File

@ -0,0 +1,53 @@
LIBRARY avs2-core
EXPORTS
XCgsqzn0000007
XCgsqzn0000004
XCgsqzn0000006
XCgsqzn000000a
XCgsqzn000000b
XCgsqzn0000076
XCgsqzn0000090
XCgsqzn0000091
XCgsqzn0000092
XCgsqzn0000094
XCgsqzn00000a1
XCgsqzn00000a2
XCgsqzn00000a3
XCgsqzn00000af
XCgsqzn00000b0
XCgsqzn00000b2
XCgsqzn00000b3
XCgsqzn00000d3
XCgsqzn00000d4
XCgsqzn0000129
XCgsqzn000012a
XCgsqzn000017a
XCgsqzn000017b
XCgsqzn000017c
XCgsqzn000017d
XCgsqzn000004e
XCgsqzn0000055
XCgsqzn0000065
XCgsqzn0000068
XCgsqzn00000d5
XCgsqzn0000051
XCgsqzn00000a6
XCgsqzn0000144
XCgsqzn0000077
XCgsqzn0000079
XCgsqzn000007a
XCgsqzn000007b
XCgsqzn000007c
XCgsqzn000007d
XCgsqzn000007e
XCgsqzn000007f
XCgsqzn0000080
XCgsqzn0000081
XCgsqzn0000082
XCgsqzn0000086
XCgsqzn000008c
XCgsqzn000008d
XCgsqzn000008e
XCgsqzn000008f
XCgsqzn0000078

View File

@ -0,0 +1,37 @@
LIBRARY libavs-win32
EXPORTS
avs_boot
avs_net_ctrl
avs_shutdown
avs_thread_create
avs_thread_destroy
avs_thread_exit
avs_thread_join
log_body_fatal
log_body_info
log_body_misc
log_body_warning
log_boot
log_change_level
property_create
property_desc_to_buffer
property_destroy
property_file_write
property_insert_read
property_mem_write
property_read_query_memsize
property_search
property_set_flag
property_node_clone
property_node_create
property_node_datasize
property_node_name
property_node_refer
property_node_remove
property_node_type
property_node_traversal
property_node_refdata
std_getenv
std_setenv

View File

@ -0,0 +1,142 @@
LIBRARY libavs-win64-ea3
EXPORTS
XE592acd000000
XE592acd000001
XE592acd000002
XE592acd000003
XE592acd000004
XE592acd000005
XE592acd000006
XE592acd000007
XE592acd000008
XE592acd000009
XE592acd00000a
XE592acd00000b
XE592acd00000c
XE592acd00000d
XE592acd000010
XE592acd000011
XE592acd000012
XE592acd000013
XE592acd000014
XE592acd000015
XE592acd000016
XE592acd000017
XE592acd000019
XE592acd00001a
XE592acd00001b
XE592acd00001c
XE592acd00001d
XE592acd00001e
XE592acd00001f
XE592acd000020
XE592acd000021
XE592acd000022
XE592acd000023
XE592acd000024
XE592acd000025
XE592acd000026
XE592acd000027
XE592acd000028
XE592acd000029
XE592acd00002a
XE592acd00002b
XE592acd00002c
XE592acd00002d
XE592acd00002e
XE592acd00002f
XE592acd000030
XE592acd000031
XE592acd000032
XE592acd000033
XE592acd000034
XE592acd000035
XE592acd000036
XE592acd000037
XE592acd000038
XE592acd00003a
XE592acd00003b
XE592acd00003c
XE592acd00003d
XE592acd00003e
XE592acd00003f
XE592acd000040
XE592acd000041
XE592acd000042
XE592acd000043
XE592acd000044
XE592acd000046
XE592acd000047
XE592acd000048
XE592acd000049
XE592acd00004a
XE592acd00004b
XE592acd00004c
XE592acd00004d
XE592acd00004f
XE592acd000050
XE592acd000051
XE592acd000052
XE592acd000053
XE592acd000054
XE592acd000055
XE592acd000056
XE592acd000057
XE592acd000058
XE592acd000059
XE592acd00005a
XE592acd00005c
XE592acd00005d
XE592acd00005e
XE592acd00005f
XE592acd000060
XE592acd000061
XE592acd000062
XE592acd000063
XE592acd000064
XE592acd000065
XE592acd000066
XE592acd000067
XE592acd000068
XE592acd000069
XE592acd00006a
XE592acd00006b
XE592acd00006c
XE592acd00006d
XE592acd00006e
XE592acd00006f
XE592acd000070
XE592acd000071
XE592acd000072
XE592acd000073
XE592acd000074
XE592acd000075
XE592acd000076
XE592acd000077
XE592acd000078
XE592acd000079
XE592acd00007a
XE592acd00007b
XE592acd00007c
XE592acd00007d
XE592acd00007e
XE592acd00007f
XE592acd000080
XE592acd000081
XE592acd000082
XE592acd000083
XE592acd000084
XE592acd000085
XE592acd000086
XE592acd000087
XE592acd000088
XE592acd000089
XE592acd00008b
XE592acd00008c
XE592acd00008d
XE592acd00008e
XE592acd00008f
XE592acd000090
XE592acd000091
XE592acd000092

View File

@ -0,0 +1,365 @@
LIBRARY libavs-win64
EXPORTS
XCd229cc000000
XCd229cc000001
XCd229cc000002
XCd229cc000003
XCd229cc000004
XCd229cc000005
XCd229cc000006
XCd229cc000007
XCd229cc000009
XCd229cc00000a
XCd229cc00000b
XCd229cc00000c
XCd229cc00000d
XCd229cc00000e
XCd229cc00000f
XCd229cc000010
XCd229cc000011
XCd229cc000012
XCd229cc000013
XCd229cc000014
XCd229cc000015
XCd229cc000016
XCd229cc000017
XCd229cc000018
XCd229cc000019
XCd229cc00001a
XCd229cc00001b
XCd229cc00001d
XCd229cc00001e
XCd229cc00001f
XCd229cc000020
XCd229cc000021
XCd229cc000022
XCd229cc000023
XCd229cc000024
XCd229cc000025
XCd229cc000026
XCd229cc000027
XCd229cc000028
XCd229cc000029
XCd229cc00002a
XCd229cc00002b
XCd229cc00002c
XCd229cc00002d
XCd229cc00002e
XCd229cc00002f
XCd229cc000030
XCd229cc000031
XCd229cc000032
XCd229cc000033
XCd229cc000034
XCd229cc000035
XCd229cc000036
XCd229cc000037
XCd229cc000038
XCd229cc000039
XCd229cc00003a
XCd229cc00003b
XCd229cc00003c
XCd229cc00003d
XCd229cc00003e
XCd229cc00003f
XCd229cc000040
XCd229cc000041
XCd229cc000042
XCd229cc000043
XCd229cc000044
XCd229cc000045
XCd229cc000046
XCd229cc000047
XCd229cc000048
XCd229cc000049
XCd229cc00004a
XCd229cc00004b
XCd229cc00004c
XCd229cc00004d
XCd229cc00004e
XCd229cc00004f
XCd229cc000050
XCd229cc000051
XCd229cc000052
XCd229cc000053
XCd229cc000054
XCd229cc000055
XCd229cc000056
XCd229cc000057
XCd229cc000058
XCd229cc000059
XCd229cc00005a
XCd229cc00005b
XCd229cc00005c
XCd229cc00005d
XCd229cc00005e
XCd229cc00005f
XCd229cc000060
XCd229cc000061
XCd229cc000062
XCd229cc000063
XCd229cc000064
XCd229cc000065
XCd229cc000066
XCd229cc000067
XCd229cc000068
XCd229cc000069
XCd229cc00006a
XCd229cc00006b
XCd229cc00006c
XCd229cc00006d
XCd229cc00006e
XCd229cc00006f
XCd229cc000070
XCd229cc000071
XCd229cc000072
XCd229cc000073
XCd229cc000074
XCd229cc000075
XCd229cc000076
XCd229cc000077
XCd229cc000078
XCd229cc000079
XCd229cc00007a
XCd229cc00007b
XCd229cc00007c
XCd229cc00007d
XCd229cc00007e
XCd229cc00007f
XCd229cc000080
XCd229cc000081
XCd229cc000082
XCd229cc000083
XCd229cc000084
XCd229cc000085
XCd229cc000086
XCd229cc000087
XCd229cc000088
XCd229cc000089
XCd229cc00008a
XCd229cc00008b
XCd229cc00008c
XCd229cc00008d
XCd229cc00008e
XCd229cc00008f
XCd229cc000090
XCd229cc000091
XCd229cc000092
XCd229cc000093
XCd229cc000094
XCd229cc000095
XCd229cc000096
XCd229cc000097
XCd229cc000098
XCd229cc000099
XCd229cc00009a
XCd229cc00009b
XCd229cc00009c
XCd229cc00009d
XCd229cc00009e
XCd229cc00009f
XCd229cc0000a0
XCd229cc0000a1
XCd229cc0000a2
XCd229cc0000a3
XCd229cc0000a4
XCd229cc0000a5
XCd229cc0000a6
XCd229cc0000a7
XCd229cc0000a8
XCd229cc0000a9
XCd229cc0000aa
XCd229cc0000ab
XCd229cc0000ac
XCd229cc0000ad
XCd229cc0000ae
XCd229cc0000af
XCd229cc0000b0
XCd229cc0000b1
XCd229cc0000b2
XCd229cc0000b3
XCd229cc0000b4
XCd229cc0000b5
XCd229cc0000b6
XCd229cc0000b7
XCd229cc0000b8
XCd229cc0000b9
XCd229cc0000ba
XCd229cc0000bb
XCd229cc0000bc
XCd229cc0000bd
XCd229cc0000be
XCd229cc0000bf
XCd229cc0000c0
XCd229cc0000c1
XCd229cc0000c2
XCd229cc0000c3
XCd229cc0000c4
XCd229cc0000c5
XCd229cc0000c6
XCd229cc0000c7
XCd229cc0000c8
XCd229cc0000c9
XCd229cc0000ca
XCd229cc0000cb
XCd229cc0000cc
XCd229cc0000cd
XCd229cc0000ce
XCd229cc0000cf
XCd229cc0000d0
XCd229cc0000d1
XCd229cc0000d2
XCd229cc0000d3
XCd229cc0000d4
XCd229cc0000d5
XCd229cc0000d6
XCd229cc0000d7
XCd229cc0000d8
XCd229cc0000d9
XCd229cc0000da
XCd229cc0000db
XCd229cc0000dc
XCd229cc0000dd
XCd229cc0000de
XCd229cc0000df
XCd229cc0000e0
XCd229cc0000e1
XCd229cc0000e2
XCd229cc0000e3
XCd229cc0000e4
XCd229cc0000e5
XCd229cc0000e6
XCd229cc0000e7
XCd229cc0000e8
XCd229cc0000e9
XCd229cc0000ea
XCd229cc0000eb
XCd229cc0000ec
XCd229cc0000ed
XCd229cc0000ee
XCd229cc0000ef
XCd229cc0000f0
XCd229cc0000f1
XCd229cc0000f2
XCd229cc0000f3
XCd229cc0000f4
XCd229cc0000f6
XCd229cc0000f7
XCd229cc0000f8
XCd229cc0000f9
XCd229cc0000fa
XCd229cc0000fb
XCd229cc0000fc
XCd229cc0000fd
XCd229cc0000fe
XCd229cc0000ff
XCd229cc000100
XCd229cc000102
XCd229cc000103
XCd229cc000104
XCd229cc000105
XCd229cc000106
XCd229cc000107
XCd229cc000108
XCd229cc000109
XCd229cc00010a
XCd229cc00010b
XCd229cc00010c
XCd229cc00010d
XCd229cc00010e
XCd229cc00010f
XCd229cc000110
XCd229cc000111
XCd229cc000112
XCd229cc000113
XCd229cc000114
XCd229cc000115
XCd229cc000116
XCd229cc000117
XCd229cc000118
XCd229cc000119
XCd229cc00011a
XCd229cc00011b
XCd229cc00011c
XCd229cc00011d
XCd229cc00011e
XCd229cc00011f
XCd229cc000120
XCd229cc000121
XCd229cc000122
XCd229cc000123
XCd229cc000124
XCd229cc000125
XCd229cc000126
XCd229cc000127
XCd229cc000128
XCd229cc000129
XCd229cc00012a
XCd229cc00012b
XCd229cc00012c
XCd229cc00012d
XCd229cc00012e
XCd229cc00012f
XCd229cc000130
XCd229cc000131
XCd229cc000132
XCd229cc000133
XCd229cc000134
XCd229cc000135
XCd229cc000136
XCd229cc000137
XCd229cc000138
XCd229cc000139
XCd229cc00013a
XCd229cc00013b
XCd229cc00013c
XCd229cc00013d
XCd229cc00013e
XCd229cc00013f
XCd229cc000140
XCd229cc000141
XCd229cc000142
XCd229cc000143
XCd229cc000144
XCd229cc000145
XCd229cc000146
XCd229cc000147
XCd229cc000148
XCd229cc000149
XCd229cc00014b
XCd229cc00014c
XCd229cc00014d
XCd229cc00014e
XCd229cc00014f
XCd229cc000150
XCd229cc000151
XCd229cc000152
XCd229cc000153
XCd229cc000154
XCd229cc000155
XCd229cc000156
XCd229cc000157
XCd229cc000158
XCd229cc000159
XCd229cc00015a
XCd229cc00015b
XCd229cc00015c
XCd229cc00015d
XCd229cc00015e
XCd229cc00015f
XCd229cc000160
XCd229cc000161
XCd229cc000162
XCd229cc000163
XCd229cc000164
XCd229cc000165
XCd229cc000166
XCd229cc000167
XCd229cc000168
XCd229cc000169
XCd229cc00016a
XCd229cc00016b
XCd229cc00016c
XCd229cc000170
XCd229cc000171

View File

@ -0,0 +1,53 @@
LIBRARY avs2-core
EXPORTS
XCgsqzn0000007
XCgsqzn0000004
XCgsqzn0000006
XCgsqzn000000a
XCgsqzn000000b
XCgsqzn0000076
XCgsqzn0000090
XCgsqzn0000091
XCgsqzn0000092
XCgsqzn0000094
XCgsqzn00000a1
XCgsqzn00000a2
XCgsqzn00000a3
XCgsqzn00000af
XCgsqzn00000b0
XCgsqzn00000b2
XCgsqzn00000b3
XCgsqzn00000d3
XCgsqzn00000d4
XCgsqzn0000129
XCgsqzn000012a
XCgsqzn000017a
XCgsqzn000017b
XCgsqzn000017c
XCgsqzn000017d
XCgsqzn000004e
XCgsqzn0000055
XCgsqzn0000065
XCgsqzn0000068
XCgsqzn00000d5
XCgsqzn0000051
XCgsqzn00000a6
XCgsqzn0000144
XCgsqzn0000077
XCgsqzn0000079
XCgsqzn000007a
XCgsqzn000007b
XCgsqzn000007c
XCgsqzn000007d
XCgsqzn000007e
XCgsqzn000007f
XCgsqzn0000080
XCgsqzn0000081
XCgsqzn0000082
XCgsqzn0000086
XCgsqzn000008c
XCgsqzn000008d
XCgsqzn000008e
XCgsqzn000008f
XCgsqzn0000078

81
minhook/LICENSE.txt Normal file
View File

@ -0,0 +1,81 @@
MinHook - The Minimalistic API Hooking Library for x64/x86
Copyright (C) 2009-2017 Tsuda Kageyu.
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 HOLDER
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.
================================================================================
Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov.
================================================================================
Hacker Disassembler Engine 32 C
Copyright (c) 2008-2009, Vyacheslav Patkov.
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 REGENTS 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.
-------------------------------------------------------------------------------
Hacker Disassembler Engine 64 C
Copyright (c) 2008-2009, Vyacheslav Patkov.
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 REGENTS 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.

8
minhook/Module.mk Normal file
View File

@ -0,0 +1,8 @@
libs += minhook
src_minhook := \
hook.c \
buffer.c \
trampoline.c \
hde32.c \
hde64.c \

312
minhook/buffer.c Normal file
View File

@ -0,0 +1,312 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* 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 HOLDER
* 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 <windows.h>
#include "buffer.h"
// Size of each memory block. (= page size of VirtualAlloc)
#define MEMORY_BLOCK_SIZE 0x1000
// Max range for seeking a memory block. (= 1024MB)
#define MAX_MEMORY_RANGE 0x40000000
// Memory protection flags to check the executable address.
#define PAGE_EXECUTE_FLAGS \
(PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
// Memory slot.
typedef struct _MEMORY_SLOT
{
union
{
struct _MEMORY_SLOT *pNext;
UINT8 buffer[MEMORY_SLOT_SIZE];
};
} MEMORY_SLOT, *PMEMORY_SLOT;
// Memory block info. Placed at the head of each block.
typedef struct _MEMORY_BLOCK
{
struct _MEMORY_BLOCK *pNext;
PMEMORY_SLOT pFree; // First element of the free slot list.
UINT usedCount;
} MEMORY_BLOCK, *PMEMORY_BLOCK;
//-------------------------------------------------------------------------
// Global Variables:
//-------------------------------------------------------------------------
// First element of the memory block list.
PMEMORY_BLOCK g_pMemoryBlocks;
//-------------------------------------------------------------------------
VOID InitializeBuffer(VOID)
{
// Nothing to do for now.
}
//-------------------------------------------------------------------------
VOID UninitializeBuffer(VOID)
{
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
g_pMemoryBlocks = NULL;
while (pBlock)
{
PMEMORY_BLOCK pNext = pBlock->pNext;
VirtualFree(pBlock, 0, MEM_RELEASE);
pBlock = pNext;
}
}
//-------------------------------------------------------------------------
#if defined(_M_X64) || defined(__x86_64__)
static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity)
{
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
// Round down to the allocation granularity.
tryAddr -= tryAddr % dwAllocationGranularity;
// Start from the previous allocation granularity multiply.
tryAddr -= dwAllocationGranularity;
while (tryAddr >= (ULONG_PTR)pMinAddr)
{
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
break;
if (mbi.State == MEM_FREE)
return (LPVOID)tryAddr;
if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity)
break;
tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity;
}
return NULL;
}
#endif
//-------------------------------------------------------------------------
#if defined(_M_X64) || defined(__x86_64__)
static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity)
{
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
// Round down to the allocation granularity.
tryAddr -= tryAddr % dwAllocationGranularity;
// Start from the next allocation granularity multiply.
tryAddr += dwAllocationGranularity;
while (tryAddr <= (ULONG_PTR)pMaxAddr)
{
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
break;
if (mbi.State == MEM_FREE)
return (LPVOID)tryAddr;
tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;
// Round up to the next allocation granularity.
tryAddr += dwAllocationGranularity - 1;
tryAddr -= tryAddr % dwAllocationGranularity;
}
return NULL;
}
#endif
//-------------------------------------------------------------------------
static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)
{
PMEMORY_BLOCK pBlock;
#if defined(_M_X64) || defined(__x86_64__)
ULONG_PTR minAddr;
ULONG_PTR maxAddr;
SYSTEM_INFO si;
GetSystemInfo(&si);
minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress;
maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress;
// pOrigin ± 512MB
if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE)
minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE;
if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE)
maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE;
// Make room for MEMORY_BLOCK_SIZE bytes.
maxAddr -= MEMORY_BLOCK_SIZE - 1;
#endif
// Look the registered blocks for a reachable one.
for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext)
{
#if defined(_M_X64) || defined(__x86_64__)
// Ignore the blocks too far.
if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr)
continue;
#endif
// The block has at least one unused slot.
if (pBlock->pFree != NULL)
return pBlock;
}
#if defined(_M_X64) || defined(__x86_64__)
// Alloc a new block above if not found.
{
LPVOID pAlloc = pOrigin;
while ((ULONG_PTR)pAlloc >= minAddr)
{
pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity);
if (pAlloc == NULL)
break;
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pBlock != NULL)
break;
}
}
// Alloc a new block below if not found.
if (pBlock == NULL)
{
LPVOID pAlloc = pOrigin;
while ((ULONG_PTR)pAlloc <= maxAddr)
{
pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity);
if (pAlloc == NULL)
break;
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pBlock != NULL)
break;
}
}
#else
// In x86 mode, a memory block can be placed anywhere.
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
#endif
if (pBlock != NULL)
{
// Build a linked list of all the slots.
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1;
pBlock->pFree = NULL;
pBlock->usedCount = 0;
do
{
pSlot->pNext = pBlock->pFree;
pBlock->pFree = pSlot;
pSlot++;
} while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE);
pBlock->pNext = g_pMemoryBlocks;
g_pMemoryBlocks = pBlock;
}
return pBlock;
}
//-------------------------------------------------------------------------
LPVOID AllocateBuffer(LPVOID pOrigin)
{
PMEMORY_SLOT pSlot;
PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin);
if (pBlock == NULL)
return NULL;
// Remove an unused slot from the list.
pSlot = pBlock->pFree;
pBlock->pFree = pSlot->pNext;
pBlock->usedCount++;
#ifdef _DEBUG
// Fill the slot with INT3 for debugging.
memset(pSlot, 0xCC, sizeof(MEMORY_SLOT));
#endif
return pSlot;
}
//-------------------------------------------------------------------------
VOID FreeBuffer(LPVOID pBuffer)
{
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
PMEMORY_BLOCK pPrev = NULL;
ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE;
while (pBlock != NULL)
{
if ((ULONG_PTR)pBlock == pTargetBlock)
{
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer;
#ifdef _DEBUG
// Clear the released slot for debugging.
memset(pSlot, 0x00, sizeof(*pSlot));
#endif
// Restore the released slot to the list.
pSlot->pNext = pBlock->pFree;
pBlock->pFree = pSlot;
pBlock->usedCount--;
// Free if unused.
if (pBlock->usedCount == 0)
{
if (pPrev)
pPrev->pNext = pBlock->pNext;
else
g_pMemoryBlocks = pBlock->pNext;
VirtualFree(pBlock, 0, MEM_RELEASE);
}
break;
}
pPrev = pBlock;
pBlock = pBlock->pNext;
}
}
//-------------------------------------------------------------------------
BOOL IsExecutableAddress(LPVOID pAddress)
{
MEMORY_BASIC_INFORMATION mi;
VirtualQuery(pAddress, &mi, sizeof(mi));
return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS));
}

42
minhook/buffer.h Normal file
View File

@ -0,0 +1,42 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* 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 HOLDER
* 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.
*/
#pragma once
// Size of each memory slot.
#if defined(_M_X64) || defined(__x86_64__)
#define MEMORY_SLOT_SIZE 64
#else
#define MEMORY_SLOT_SIZE 32
#endif
VOID InitializeBuffer(VOID);
VOID UninitializeBuffer(VOID);
LPVOID AllocateBuffer(LPVOID pOrigin);
VOID FreeBuffer(LPVOID pBuffer);
BOOL IsExecutableAddress(LPVOID pAddress);

326
minhook/hde32.c Normal file
View File

@ -0,0 +1,326 @@
/*
* Hacker Disassembler Engine 32 C
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
*/
#if defined(_M_IX86) || defined(__i386__)
#include "hde32.h"
#include "table32.h"
unsigned int hde32_disasm(const void *code, hde32s *hs)
{
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0;
// Avoid using memset to reduce the footprint.
#ifndef _MSC_VER
memset((LPBYTE)hs, 0, sizeof(hde32s));
#else
__stosb((LPBYTE)hs, 0, sizeof(hde32s));
#endif
for (x = 16; x; x--)
switch (c = *p++) {
case 0xf3:
hs->p_rep = c;
pref |= PRE_F3;
break;
case 0xf2:
hs->p_rep = c;
pref |= PRE_F2;
break;
case 0xf0:
hs->p_lock = c;
pref |= PRE_LOCK;
break;
case 0x26: case 0x2e: case 0x36:
case 0x3e: case 0x64: case 0x65:
hs->p_seg = c;
pref |= PRE_SEG;
break;
case 0x66:
hs->p_66 = c;
pref |= PRE_66;
break;
case 0x67:
hs->p_67 = c;
pref |= PRE_67;
break;
default:
goto pref_done;
}
pref_done:
hs->flags = (uint32_t)pref << 23;
if (!pref)
pref |= PRE_NONE;
if ((hs->opcode = c) == 0x0f) {
hs->opcode2 = c = *p++;
ht += DELTA_OPCODES;
} else if (c >= 0xa0 && c <= 0xa3) {
if (pref & PRE_67)
pref |= PRE_66;
else
pref &= ~PRE_66;
}
opcode = c;
cflags = ht[ht[opcode / 4] + (opcode % 4)];
if (cflags == C_ERROR) {
hs->flags |= F_ERROR | F_ERROR_OPCODE;
cflags = 0;
if ((opcode & -3) == 0x24)
cflags++;
}
x = 0;
if (cflags & C_GROUP) {
uint16_t t;
t = *(uint16_t *)(ht + (cflags & 0x7f));
cflags = (uint8_t)t;
x = (uint8_t)(t >> 8);
}
if (hs->opcode2) {
ht = hde32_table + DELTA_PREFIXES;
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
hs->flags |= F_ERROR | F_ERROR_OPCODE;
}
if (cflags & C_MODRM) {
hs->flags |= F_MODRM;
hs->modrm = c = *p++;
hs->modrm_mod = m_mod = c >> 6;
hs->modrm_rm = m_rm = c & 7;
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
if (x && ((x << m_reg) & 0x80))
hs->flags |= F_ERROR | F_ERROR_OPCODE;
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
uint8_t t = opcode - 0xd9;
if (m_mod == 3) {
ht = hde32_table + DELTA_FPU_MODRM + t*8;
t = ht[m_reg] << m_rm;
} else {
ht = hde32_table + DELTA_FPU_REG;
t = ht[t] << m_reg;
}
if (t & 0x80)
hs->flags |= F_ERROR | F_ERROR_OPCODE;
}
if (pref & PRE_LOCK) {
if (m_mod == 3) {
hs->flags |= F_ERROR | F_ERROR_LOCK;
} else {
uint8_t *table_end, op = opcode;
if (hs->opcode2) {
ht = hde32_table + DELTA_OP2_LOCK_OK;
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
} else {
ht = hde32_table + DELTA_OP_LOCK_OK;
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
op &= -2;
}
for (; ht != table_end; ht++)
if (*ht++ == op) {
if (!((*ht << m_reg) & 0x80))
goto no_lock_error;
else
break;
}
hs->flags |= F_ERROR | F_ERROR_LOCK;
no_lock_error:
;
}
}
if (hs->opcode2) {
switch (opcode) {
case 0x20: case 0x22:
m_mod = 3;
if (m_reg > 4 || m_reg == 1)
goto error_operand;
else
goto no_error_operand;
case 0x21: case 0x23:
m_mod = 3;
if (m_reg == 4 || m_reg == 5)
goto error_operand;
else
goto no_error_operand;
}
} else {
switch (opcode) {
case 0x8c:
if (m_reg > 5)
goto error_operand;
else
goto no_error_operand;
case 0x8e:
if (m_reg == 1 || m_reg > 5)
goto error_operand;
else
goto no_error_operand;
}
}
if (m_mod == 3) {
uint8_t *table_end;
if (hs->opcode2) {
ht = hde32_table + DELTA_OP2_ONLY_MEM;
table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM;
} else {
ht = hde32_table + DELTA_OP_ONLY_MEM;
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
}
for (; ht != table_end; ht += 2)
if (*ht++ == opcode) {
if (*ht++ & pref && !((*ht << m_reg) & 0x80))
goto error_operand;
else
break;
}
goto no_error_operand;
} else if (hs->opcode2) {
switch (opcode) {
case 0x50: case 0xd7: case 0xf7:
if (pref & (PRE_NONE | PRE_66))
goto error_operand;
break;
case 0xd6:
if (pref & (PRE_F2 | PRE_F3))
goto error_operand;
break;
case 0xc5:
goto error_operand;
}
goto no_error_operand;
} else
goto no_error_operand;
error_operand:
hs->flags |= F_ERROR | F_ERROR_OPERAND;
no_error_operand:
c = *p++;
if (m_reg <= 1) {
if (opcode == 0xf6)
cflags |= C_IMM8;
else if (opcode == 0xf7)
cflags |= C_IMM_P66;
}
switch (m_mod) {
case 0:
if (pref & PRE_67) {
if (m_rm == 6)
disp_size = 2;
} else
if (m_rm == 5)
disp_size = 4;
break;
case 1:
disp_size = 1;
break;
case 2:
disp_size = 2;
if (!(pref & PRE_67))
disp_size <<= 1;
}
if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) {
hs->flags |= F_SIB;
p++;
hs->sib = c;
hs->sib_scale = c >> 6;
hs->sib_index = (c & 0x3f) >> 3;
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
disp_size = 4;
}
p--;
switch (disp_size) {
case 1:
hs->flags |= F_DISP8;
hs->disp.disp8 = *p;
break;
case 2:
hs->flags |= F_DISP16;
hs->disp.disp16 = *(uint16_t *)p;
break;
case 4:
hs->flags |= F_DISP32;
hs->disp.disp32 = *(uint32_t *)p;
}
p += disp_size;
} else if (pref & PRE_LOCK)
hs->flags |= F_ERROR | F_ERROR_LOCK;
if (cflags & C_IMM_P66) {
if (cflags & C_REL32) {
if (pref & PRE_66) {
hs->flags |= F_IMM16 | F_RELATIVE;
hs->imm.imm16 = *(uint16_t *)p;
p += 2;
goto disasm_done;
}
goto rel32_ok;
}
if (pref & PRE_66) {
hs->flags |= F_IMM16;
hs->imm.imm16 = *(uint16_t *)p;
p += 2;
} else {
hs->flags |= F_IMM32;
hs->imm.imm32 = *(uint32_t *)p;
p += 4;
}
}
if (cflags & C_IMM16) {
if (hs->flags & F_IMM32) {
hs->flags |= F_IMM16;
hs->disp.disp16 = *(uint16_t *)p;
} else if (hs->flags & F_IMM16) {
hs->flags |= F_2IMM16;
hs->disp.disp16 = *(uint16_t *)p;
} else {
hs->flags |= F_IMM16;
hs->imm.imm16 = *(uint16_t *)p;
}
p += 2;
}
if (cflags & C_IMM8) {
hs->flags |= F_IMM8;
hs->imm.imm8 = *p++;
}
if (cflags & C_REL32) {
rel32_ok:
hs->flags |= F_IMM32 | F_RELATIVE;
hs->imm.imm32 = *(uint32_t *)p;
p += 4;
} else if (cflags & C_REL8) {
hs->flags |= F_IMM8 | F_RELATIVE;
hs->imm.imm8 = *p++;
}
disasm_done:
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
hs->flags |= F_ERROR | F_ERROR_LENGTH;
hs->len = 15;
}
return (unsigned int)hs->len;
}
#endif // defined(_M_IX86) || defined(__i386__)

105
minhook/hde32.h Normal file
View File

@ -0,0 +1,105 @@
/*
* Hacker Disassembler Engine 32
* Copyright (c) 2006-2009, Vyacheslav Patkov.
* All rights reserved.
*
* hde32.h: C/C++ header file
*
*/
#ifndef _HDE32_H_
#define _HDE32_H_
/* stdint.h - C99 standard header
* http://en.wikipedia.org/wiki/stdint.h
*
* if your compiler doesn't contain "stdint.h" header (for
* example, Microsoft Visual C++), you can download file:
* http://www.azillionmonkeys.com/qed/pstdint.h
* and change next line to:
* #include "pstdint.h"
*/
#include "pstdint.h"
#define F_MODRM 0x00000001
#define F_SIB 0x00000002
#define F_IMM8 0x00000004
#define F_IMM16 0x00000008
#define F_IMM32 0x00000010
#define F_DISP8 0x00000020
#define F_DISP16 0x00000040
#define F_DISP32 0x00000080
#define F_RELATIVE 0x00000100
#define F_2IMM16 0x00000800
#define F_ERROR 0x00001000
#define F_ERROR_OPCODE 0x00002000
#define F_ERROR_LENGTH 0x00004000
#define F_ERROR_LOCK 0x00008000
#define F_ERROR_OPERAND 0x00010000
#define F_PREFIX_REPNZ 0x01000000
#define F_PREFIX_REPX 0x02000000
#define F_PREFIX_REP 0x03000000
#define F_PREFIX_66 0x04000000
#define F_PREFIX_67 0x08000000
#define F_PREFIX_LOCK 0x10000000
#define F_PREFIX_SEG 0x20000000
#define F_PREFIX_ANY 0x3f000000
#define PREFIX_SEGMENT_CS 0x2e
#define PREFIX_SEGMENT_SS 0x36
#define PREFIX_SEGMENT_DS 0x3e
#define PREFIX_SEGMENT_ES 0x26
#define PREFIX_SEGMENT_FS 0x64
#define PREFIX_SEGMENT_GS 0x65
#define PREFIX_LOCK 0xf0
#define PREFIX_REPNZ 0xf2
#define PREFIX_REPX 0xf3
#define PREFIX_OPERAND_SIZE 0x66
#define PREFIX_ADDRESS_SIZE 0x67
#pragma pack(push,1)
typedef struct {
uint8_t len;
uint8_t p_rep;
uint8_t p_lock;
uint8_t p_seg;
uint8_t p_66;
uint8_t p_67;
uint8_t opcode;
uint8_t opcode2;
uint8_t modrm;
uint8_t modrm_mod;
uint8_t modrm_reg;
uint8_t modrm_rm;
uint8_t sib;
uint8_t sib_scale;
uint8_t sib_index;
uint8_t sib_base;
union {
uint8_t imm8;
uint16_t imm16;
uint32_t imm32;
} imm;
union {
uint8_t disp8;
uint16_t disp16;
uint32_t disp32;
} disp;
uint32_t flags;
} hde32s;
#pragma pack(pop)
#ifdef __cplusplus
extern "C" {
#endif
/* __cdecl */
unsigned int hde32_disasm(const void *code, hde32s *hs);
#ifdef __cplusplus
}
#endif
#endif /* _HDE32_H_ */

337
minhook/hde64.c Normal file
View File

@ -0,0 +1,337 @@
/*
* Hacker Disassembler Engine 64 C
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
*/
#if defined(_M_X64) || defined(__x86_64__)
#include "hde64.h"
#include "table64.h"
unsigned int hde64_disasm(const void *code, hde64s *hs)
{
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
uint8_t op64 = 0;
// Avoid using memset to reduce the footprint.
#ifndef _MSC_VER
memset((LPBYTE)hs, 0, sizeof(hde64s));
#else
__stosb((LPBYTE)hs, 0, sizeof(hde64s));
#endif
for (x = 16; x; x--)
switch (c = *p++) {
case 0xf3:
hs->p_rep = c;
pref |= PRE_F3;
break;
case 0xf2:
hs->p_rep = c;
pref |= PRE_F2;
break;
case 0xf0:
hs->p_lock = c;
pref |= PRE_LOCK;
break;
case 0x26: case 0x2e: case 0x36:
case 0x3e: case 0x64: case 0x65:
hs->p_seg = c;
pref |= PRE_SEG;
break;
case 0x66:
hs->p_66 = c;
pref |= PRE_66;
break;
case 0x67:
hs->p_67 = c;
pref |= PRE_67;
break;
default:
goto pref_done;
}
pref_done:
hs->flags = (uint32_t)pref << 23;
if (!pref)
pref |= PRE_NONE;
if ((c & 0xf0) == 0x40) {
hs->flags |= F_PREFIX_REX;
if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)
op64++;
hs->rex_r = (c & 7) >> 2;
hs->rex_x = (c & 3) >> 1;
hs->rex_b = c & 1;
if (((c = *p++) & 0xf0) == 0x40) {
opcode = c;
goto error_opcode;
}
}
if ((hs->opcode = c) == 0x0f) {
hs->opcode2 = c = *p++;
ht += DELTA_OPCODES;
} else if (c >= 0xa0 && c <= 0xa3) {
op64++;
if (pref & PRE_67)
pref |= PRE_66;
else
pref &= ~PRE_66;
}
opcode = c;
cflags = ht[ht[opcode / 4] + (opcode % 4)];
if (cflags == C_ERROR) {
error_opcode:
hs->flags |= F_ERROR | F_ERROR_OPCODE;
cflags = 0;
if ((opcode & -3) == 0x24)
cflags++;
}
x = 0;
if (cflags & C_GROUP) {
uint16_t t;
t = *(uint16_t *)(ht + (cflags & 0x7f));
cflags = (uint8_t)t;
x = (uint8_t)(t >> 8);
}
if (hs->opcode2) {
ht = hde64_table + DELTA_PREFIXES;
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
hs->flags |= F_ERROR | F_ERROR_OPCODE;
}
if (cflags & C_MODRM) {
hs->flags |= F_MODRM;
hs->modrm = c = *p++;
hs->modrm_mod = m_mod = c >> 6;
hs->modrm_rm = m_rm = c & 7;
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
if (x && ((x << m_reg) & 0x80))
hs->flags |= F_ERROR | F_ERROR_OPCODE;
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
uint8_t t = opcode - 0xd9;
if (m_mod == 3) {
ht = hde64_table + DELTA_FPU_MODRM + t*8;
t = ht[m_reg] << m_rm;
} else {
ht = hde64_table + DELTA_FPU_REG;
t = ht[t] << m_reg;
}
if (t & 0x80)
hs->flags |= F_ERROR | F_ERROR_OPCODE;
}
if (pref & PRE_LOCK) {
if (m_mod == 3) {
hs->flags |= F_ERROR | F_ERROR_LOCK;
} else {
uint8_t *table_end, op = opcode;
if (hs->opcode2) {
ht = hde64_table + DELTA_OP2_LOCK_OK;
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
} else {
ht = hde64_table + DELTA_OP_LOCK_OK;
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
op &= -2;
}
for (; ht != table_end; ht++)
if (*ht++ == op) {
if (!((*ht << m_reg) & 0x80))
goto no_lock_error;
else
break;
}
hs->flags |= F_ERROR | F_ERROR_LOCK;
no_lock_error:
;
}
}
if (hs->opcode2) {
switch (opcode) {
case 0x20: case 0x22:
m_mod = 3;
if (m_reg > 4 || m_reg == 1)
goto error_operand;
else
goto no_error_operand;
case 0x21: case 0x23:
m_mod = 3;
if (m_reg == 4 || m_reg == 5)
goto error_operand;
else
goto no_error_operand;
}
} else {
switch (opcode) {
case 0x8c:
if (m_reg > 5)
goto error_operand;
else
goto no_error_operand;
case 0x8e:
if (m_reg == 1 || m_reg > 5)
goto error_operand;
else
goto no_error_operand;
}
}
if (m_mod == 3) {
uint8_t *table_end;
if (hs->opcode2) {
ht = hde64_table + DELTA_OP2_ONLY_MEM;
table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
} else {
ht = hde64_table + DELTA_OP_ONLY_MEM;
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
}
for (; ht != table_end; ht += 2)
if (*ht++ == opcode) {
if (*ht++ & pref && !((*ht << m_reg) & 0x80))
goto error_operand;
else
break;
}
goto no_error_operand;
} else if (hs->opcode2) {
switch (opcode) {
case 0x50: case 0xd7: case 0xf7:
if (pref & (PRE_NONE | PRE_66))
goto error_operand;
break;
case 0xd6:
if (pref & (PRE_F2 | PRE_F3))
goto error_operand;
break;
case 0xc5:
goto error_operand;
}
goto no_error_operand;
} else
goto no_error_operand;
error_operand:
hs->flags |= F_ERROR | F_ERROR_OPERAND;
no_error_operand:
c = *p++;
if (m_reg <= 1) {
if (opcode == 0xf6)
cflags |= C_IMM8;
else if (opcode == 0xf7)
cflags |= C_IMM_P66;
}
switch (m_mod) {
case 0:
if (pref & PRE_67) {
if (m_rm == 6)
disp_size = 2;
} else
if (m_rm == 5)
disp_size = 4;
break;
case 1:
disp_size = 1;
break;
case 2:
disp_size = 2;
if (!(pref & PRE_67))
disp_size <<= 1;
}
if (m_mod != 3 && m_rm == 4) {
hs->flags |= F_SIB;
p++;
hs->sib = c;
hs->sib_scale = c >> 6;
hs->sib_index = (c & 0x3f) >> 3;
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
disp_size = 4;
}
p--;
switch (disp_size) {
case 1:
hs->flags |= F_DISP8;
hs->disp.disp8 = *p;
break;
case 2:
hs->flags |= F_DISP16;
hs->disp.disp16 = *(uint16_t *)p;
break;
case 4:
hs->flags |= F_DISP32;
hs->disp.disp32 = *(uint32_t *)p;
}
p += disp_size;
} else if (pref & PRE_LOCK)
hs->flags |= F_ERROR | F_ERROR_LOCK;
if (cflags & C_IMM_P66) {
if (cflags & C_REL32) {
if (pref & PRE_66) {
hs->flags |= F_IMM16 | F_RELATIVE;
hs->imm.imm16 = *(uint16_t *)p;
p += 2;
goto disasm_done;
}
goto rel32_ok;
}
if (op64) {
hs->flags |= F_IMM64;
hs->imm.imm64 = *(uint64_t *)p;
p += 8;
} else if (!(pref & PRE_66)) {
hs->flags |= F_IMM32;
hs->imm.imm32 = *(uint32_t *)p;
p += 4;
} else
goto imm16_ok;
}
if (cflags & C_IMM16) {
imm16_ok:
hs->flags |= F_IMM16;
hs->imm.imm16 = *(uint16_t *)p;
p += 2;
}
if (cflags & C_IMM8) {
hs->flags |= F_IMM8;
hs->imm.imm8 = *p++;
}
if (cflags & C_REL32) {
rel32_ok:
hs->flags |= F_IMM32 | F_RELATIVE;
hs->imm.imm32 = *(uint32_t *)p;
p += 4;
} else if (cflags & C_REL8) {
hs->flags |= F_IMM8 | F_RELATIVE;
hs->imm.imm8 = *p++;
}
disasm_done:
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
hs->flags |= F_ERROR | F_ERROR_LENGTH;
hs->len = 15;
}
return (unsigned int)hs->len;
}
#endif // defined(_M_X64) || defined(__x86_64__)

112
minhook/hde64.h Normal file
View File

@ -0,0 +1,112 @@
/*
* Hacker Disassembler Engine 64
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
* hde64.h: C/C++ header file
*
*/
#ifndef _HDE64_H_
#define _HDE64_H_
/* stdint.h - C99 standard header
* http://en.wikipedia.org/wiki/stdint.h
*
* if your compiler doesn't contain "stdint.h" header (for
* example, Microsoft Visual C++), you can download file:
* http://www.azillionmonkeys.com/qed/pstdint.h
* and change next line to:
* #include "pstdint.h"
*/
#include "pstdint.h"
#define F_MODRM 0x00000001
#define F_SIB 0x00000002
#define F_IMM8 0x00000004
#define F_IMM16 0x00000008
#define F_IMM32 0x00000010
#define F_IMM64 0x00000020
#define F_DISP8 0x00000040
#define F_DISP16 0x00000080
#define F_DISP32 0x00000100
#define F_RELATIVE 0x00000200
#define F_ERROR 0x00001000
#define F_ERROR_OPCODE 0x00002000
#define F_ERROR_LENGTH 0x00004000
#define F_ERROR_LOCK 0x00008000
#define F_ERROR_OPERAND 0x00010000
#define F_PREFIX_REPNZ 0x01000000
#define F_PREFIX_REPX 0x02000000
#define F_PREFIX_REP 0x03000000
#define F_PREFIX_66 0x04000000
#define F_PREFIX_67 0x08000000
#define F_PREFIX_LOCK 0x10000000
#define F_PREFIX_SEG 0x20000000
#define F_PREFIX_REX 0x40000000
#define F_PREFIX_ANY 0x7f000000
#define PREFIX_SEGMENT_CS 0x2e
#define PREFIX_SEGMENT_SS 0x36
#define PREFIX_SEGMENT_DS 0x3e
#define PREFIX_SEGMENT_ES 0x26
#define PREFIX_SEGMENT_FS 0x64
#define PREFIX_SEGMENT_GS 0x65
#define PREFIX_LOCK 0xf0
#define PREFIX_REPNZ 0xf2
#define PREFIX_REPX 0xf3
#define PREFIX_OPERAND_SIZE 0x66
#define PREFIX_ADDRESS_SIZE 0x67
#pragma pack(push,1)
typedef struct {
uint8_t len;
uint8_t p_rep;
uint8_t p_lock;
uint8_t p_seg;
uint8_t p_66;
uint8_t p_67;
uint8_t rex;
uint8_t rex_w;
uint8_t rex_r;
uint8_t rex_x;
uint8_t rex_b;
uint8_t opcode;
uint8_t opcode2;
uint8_t modrm;
uint8_t modrm_mod;
uint8_t modrm_reg;
uint8_t modrm_rm;
uint8_t sib;
uint8_t sib_scale;
uint8_t sib_index;
uint8_t sib_base;
union {
uint8_t imm8;
uint16_t imm16;
uint32_t imm32;
uint64_t imm64;
} imm;
union {
uint8_t disp8;
uint16_t disp16;
uint32_t disp32;
} disp;
uint32_t flags;
} hde64s;
#pragma pack(pop)
#ifdef __cplusplus
extern "C" {
#endif
/* __cdecl */
unsigned int hde64_disasm(const void *code, hde64s *hs);
#ifdef __cplusplus
}
#endif
#endif /* _HDE64_H_ */

889
minhook/hook.c Normal file
View File

@ -0,0 +1,889 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* 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 HOLDER
* 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 <windows.h>
#include <tlhelp32.h>
#include <limits.h>
#include "include/MinHook.h"
#include "buffer.h"
#include "trampoline.h"
#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
// Initial capacity of the HOOK_ENTRY buffer.
#define INITIAL_HOOK_CAPACITY 32
// Initial capacity of the thread IDs buffer.
#define INITIAL_THREAD_CAPACITY 128
// Special hook position values.
#define INVALID_HOOK_POS UINT_MAX
#define ALL_HOOKS_POS UINT_MAX
// Freeze() action argument defines.
#define ACTION_DISABLE 0
#define ACTION_ENABLE 1
#define ACTION_APPLY_QUEUED 2
// Thread access rights for suspending/resuming threads.
#define THREAD_ACCESS \
(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT)
// Hook information.
typedef struct _HOOK_ENTRY
{
LPVOID pTarget; // Address of the target function.
LPVOID pDetour; // Address of the detour or relay function.
LPVOID pTrampoline; // Address of the trampoline function.
UINT8 backup[8]; // Original prologue of the target function.
UINT8 patchAbove : 1; // Uses the hot patch area.
UINT8 isEnabled : 1; // Enabled.
UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled.
UINT nIP : 4; // Count of the instruction boundaries.
UINT8 oldIPs[8]; // Instruction boundaries of the target function.
UINT8 newIPs[8]; // Instruction boundaries of the trampoline function.
} HOOK_ENTRY, *PHOOK_ENTRY;
// Suspended threads for Freeze()/Unfreeze().
typedef struct _FROZEN_THREADS
{
LPDWORD pItems; // Data heap
UINT capacity; // Size of allocated data heap, items
UINT size; // Actual number of data items
} FROZEN_THREADS, *PFROZEN_THREADS;
//-------------------------------------------------------------------------
// Global Variables:
//-------------------------------------------------------------------------
// Spin lock flag for EnterSpinLock()/LeaveSpinLock().
volatile LONG g_isLocked = FALSE;
// Private heap handle. If not NULL, this library is initialized.
HANDLE g_hHeap = NULL;
// Hook entries.
struct
{
PHOOK_ENTRY pItems; // Data heap
UINT capacity; // Size of allocated data heap, items
UINT size; // Actual number of data items
} g_hooks;
//-------------------------------------------------------------------------
// Returns INVALID_HOOK_POS if not found.
static UINT FindHookEntry(LPVOID pTarget)
{
UINT i;
for (i = 0; i < g_hooks.size; ++i)
{
if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget)
return i;
}
return INVALID_HOOK_POS;
}
//-------------------------------------------------------------------------
static PHOOK_ENTRY AddHookEntry()
{
if (g_hooks.pItems == NULL)
{
g_hooks.capacity = INITIAL_HOOK_CAPACITY;
g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc(
g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY));
if (g_hooks.pItems == NULL)
return NULL;
}
else if (g_hooks.size >= g_hooks.capacity)
{
PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY));
if (p == NULL)
return NULL;
g_hooks.capacity *= 2;
g_hooks.pItems = p;
}
return &g_hooks.pItems[g_hooks.size++];
}
//-------------------------------------------------------------------------
static void DeleteHookEntry(UINT pos)
{
if (pos < g_hooks.size - 1)
g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1];
g_hooks.size--;
if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size)
{
PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY));
if (p == NULL)
return;
g_hooks.capacity /= 2;
g_hooks.pItems = p;
}
}
//-------------------------------------------------------------------------
static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
{
UINT i;
if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL)))
return (DWORD_PTR)pHook->pTarget;
for (i = 0; i < pHook->nIP; ++i)
{
if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]))
return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i];
}
#if defined(_M_X64) || defined(__x86_64__)
// Check relay function.
if (ip == (DWORD_PTR)pHook->pDetour)
return (DWORD_PTR)pHook->pTarget;
#endif
return 0;
}
//-------------------------------------------------------------------------
static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
{
UINT i;
for (i = 0; i < pHook->nIP; ++i)
{
if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]))
return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i];
}
return 0;
}
//-------------------------------------------------------------------------
static void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action)
{
// If the thread suspended in the overwritten area,
// move IP to the proper address.
CONTEXT c;
#if defined(_M_X64) || defined(__x86_64__)
DWORD64 *pIP = &c.Rip;
#else
DWORD *pIP = &c.Eip;
#endif
UINT count;
c.ContextFlags = CONTEXT_CONTROL;
if (!GetThreadContext(hThread, &c))
return;
if (pos == ALL_HOOKS_POS)
{
pos = 0;
count = g_hooks.size;
}
else
{
count = pos + 1;
}
for (; pos < count; ++pos)
{
PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
BOOL enable;
DWORD_PTR ip;
switch (action)
{
case ACTION_DISABLE:
enable = FALSE;
break;
case ACTION_ENABLE:
enable = TRUE;
break;
default: // ACTION_APPLY_QUEUED
enable = pHook->queueEnable;
break;
}
if (pHook->isEnabled == enable)
continue;
if (enable)
ip = FindNewIP(pHook, *pIP);
else
ip = FindOldIP(pHook, *pIP);
if (ip != 0)
{
*pIP = ip;
SetThreadContext(hThread, &c);
}
}
}
//-------------------------------------------------------------------------
static VOID EnumerateThreads(PFROZEN_THREADS pThreads)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
THREADENTRY32 te;
te.dwSize = sizeof(THREADENTRY32);
if (Thread32First(hSnapshot, &te))
{
do
{
if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD))
&& te.th32OwnerProcessID == GetCurrentProcessId()
&& te.th32ThreadID != GetCurrentThreadId())
{
if (pThreads->pItems == NULL)
{
pThreads->capacity = INITIAL_THREAD_CAPACITY;
pThreads->pItems
= (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD));
if (pThreads->pItems == NULL)
break;
}
else if (pThreads->size >= pThreads->capacity)
{
LPDWORD p = (LPDWORD)HeapReAlloc(
g_hHeap, 0, pThreads->pItems, (pThreads->capacity * 2) * sizeof(DWORD));
if (p == NULL)
break;
pThreads->capacity *= 2;
pThreads->pItems = p;
}
pThreads->pItems[pThreads->size++] = te.th32ThreadID;
}
te.dwSize = sizeof(THREADENTRY32);
} while (Thread32Next(hSnapshot, &te));
}
CloseHandle(hSnapshot);
}
}
//-------------------------------------------------------------------------
static VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)
{
pThreads->pItems = NULL;
pThreads->capacity = 0;
pThreads->size = 0;
EnumerateThreads(pThreads);
if (pThreads->pItems != NULL)
{
UINT i;
for (i = 0; i < pThreads->size; ++i)
{
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
if (hThread != NULL)
{
SuspendThread(hThread);
ProcessThreadIPs(hThread, pos, action);
CloseHandle(hThread);
}
}
}
}
//-------------------------------------------------------------------------
static VOID Unfreeze(PFROZEN_THREADS pThreads)
{
if (pThreads->pItems != NULL)
{
UINT i;
for (i = 0; i < pThreads->size; ++i)
{
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
if (hThread != NULL)
{
ResumeThread(hThread);
CloseHandle(hThread);
}
}
HeapFree(g_hHeap, 0, pThreads->pItems);
}
}
//-------------------------------------------------------------------------
static MH_STATUS EnableHookLL(UINT pos, BOOL enable)
{
PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
DWORD oldProtect;
SIZE_T patchSize = sizeof(JMP_REL);
LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget;
if (pHook->patchAbove)
{
pPatchTarget -= sizeof(JMP_REL);
patchSize += sizeof(JMP_REL_SHORT);
}
if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect))
return MH_ERROR_MEMORY_PROTECT;
if (enable)
{
PJMP_REL pJmp = (PJMP_REL)pPatchTarget;
pJmp->opcode = 0xE9;
pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL)));
if (pHook->patchAbove)
{
PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget;
pShortJmp->opcode = 0xEB;
pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL)));
}
}
else
{
if (pHook->patchAbove)
memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
else
memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL));
}
VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect);
// Just-in-case measure.
FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize);
pHook->isEnabled = enable;
pHook->queueEnable = enable;
return MH_OK;
}
//-------------------------------------------------------------------------
static MH_STATUS EnableAllHooksLL(BOOL enable)
{
MH_STATUS status = MH_OK;
UINT i, first = INVALID_HOOK_POS;
for (i = 0; i < g_hooks.size; ++i)
{
if (g_hooks.pItems[i].isEnabled != enable)
{
first = i;
break;
}
}
if (first != INVALID_HOOK_POS)
{
FROZEN_THREADS threads;
Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE);
for (i = first; i < g_hooks.size; ++i)
{
if (g_hooks.pItems[i].isEnabled != enable)
{
status = EnableHookLL(i, enable);
if (status != MH_OK)
break;
}
}
Unfreeze(&threads);
}
return status;
}
//-------------------------------------------------------------------------
static VOID EnterSpinLock(VOID)
{
SIZE_T spinCount = 0;
// Wait until the flag is FALSE.
while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE)
{
// No need to generate a memory barrier here, since InterlockedCompareExchange()
// generates a full memory barrier itself.
// Prevent the loop from being too busy.
if (spinCount < 32)
Sleep(0);
else
Sleep(1);
spinCount++;
}
}
//-------------------------------------------------------------------------
static VOID LeaveSpinLock(VOID)
{
// No need to generate a memory barrier here, since InterlockedExchange()
// generates a full memory barrier itself.
InterlockedExchange(&g_isLocked, FALSE);
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_Initialize(VOID)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap == NULL)
{
g_hHeap = HeapCreate(0, 0, 0);
if (g_hHeap != NULL)
{
// Initialize the internal function buffer.
InitializeBuffer();
}
else
{
status = MH_ERROR_MEMORY_ALLOC;
}
}
else
{
status = MH_ERROR_ALREADY_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_Uninitialize(VOID)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap != NULL)
{
status = EnableAllHooksLL(FALSE);
if (status == MH_OK)
{
// Free the internal function buffer.
// HeapFree is actually not required, but some tools detect a false
// memory leak without HeapFree.
UninitializeBuffer();
HeapFree(g_hHeap, 0, g_hooks.pItems);
HeapDestroy(g_hHeap);
g_hHeap = NULL;
g_hooks.pItems = NULL;
g_hooks.capacity = 0;
g_hooks.size = 0;
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap != NULL)
{
if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour))
{
UINT pos = FindHookEntry(pTarget);
if (pos == INVALID_HOOK_POS)
{
LPVOID pBuffer = AllocateBuffer(pTarget);
if (pBuffer != NULL)
{
TRAMPOLINE ct;
ct.pTarget = pTarget;
ct.pDetour = pDetour;
ct.pTrampoline = pBuffer;
if (CreateTrampolineFunction(&ct))
{
PHOOK_ENTRY pHook = AddHookEntry();
if (pHook != NULL)
{
pHook->pTarget = ct.pTarget;
#if defined(_M_X64) || defined(__x86_64__)
pHook->pDetour = ct.pRelay;
#else
pHook->pDetour = ct.pDetour;
#endif
pHook->pTrampoline = ct.pTrampoline;
pHook->patchAbove = ct.patchAbove;
pHook->isEnabled = FALSE;
pHook->queueEnable = FALSE;
pHook->nIP = ct.nIP;
memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs));
memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs));
// Back up the target function.
if (ct.patchAbove)
{
memcpy(
pHook->backup,
(LPBYTE)pTarget - sizeof(JMP_REL),
sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
}
else
{
memcpy(pHook->backup, pTarget, sizeof(JMP_REL));
}
if (ppOriginal != NULL)
*ppOriginal = pHook->pTrampoline;
}
else
{
status = MH_ERROR_MEMORY_ALLOC;
}
}
else
{
status = MH_ERROR_UNSUPPORTED_FUNCTION;
}
if (status != MH_OK)
{
FreeBuffer(pBuffer);
}
}
else
{
status = MH_ERROR_MEMORY_ALLOC;
}
}
else
{
status = MH_ERROR_ALREADY_CREATED;
}
}
else
{
status = MH_ERROR_NOT_EXECUTABLE;
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap != NULL)
{
UINT pos = FindHookEntry(pTarget);
if (pos != INVALID_HOOK_POS)
{
if (g_hooks.pItems[pos].isEnabled)
{
FROZEN_THREADS threads;
Freeze(&threads, pos, ACTION_DISABLE);
status = EnableHookLL(pos, FALSE);
Unfreeze(&threads);
}
if (status == MH_OK)
{
FreeBuffer(g_hooks.pItems[pos].pTrampoline);
DeleteHookEntry(pos);
}
}
else
{
status = MH_ERROR_NOT_CREATED;
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap != NULL)
{
if (pTarget == MH_ALL_HOOKS)
{
status = EnableAllHooksLL(enable);
}
else
{
FROZEN_THREADS threads;
UINT pos = FindHookEntry(pTarget);
if (pos != INVALID_HOOK_POS)
{
if (g_hooks.pItems[pos].isEnabled != enable)
{
Freeze(&threads, pos, ACTION_ENABLE);
status = EnableHookLL(pos, enable);
Unfreeze(&threads);
}
else
{
status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED;
}
}
else
{
status = MH_ERROR_NOT_CREATED;
}
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget)
{
return EnableHook(pTarget, TRUE);
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget)
{
return EnableHook(pTarget, FALSE);
}
//-------------------------------------------------------------------------
static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap != NULL)
{
if (pTarget == MH_ALL_HOOKS)
{
UINT i;
for (i = 0; i < g_hooks.size; ++i)
g_hooks.pItems[i].queueEnable = queueEnable;
}
else
{
UINT pos = FindHookEntry(pTarget);
if (pos != INVALID_HOOK_POS)
{
g_hooks.pItems[pos].queueEnable = queueEnable;
}
else
{
status = MH_ERROR_NOT_CREATED;
}
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget)
{
return QueueHook(pTarget, TRUE);
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget)
{
return QueueHook(pTarget, FALSE);
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_ApplyQueued(VOID)
{
MH_STATUS status = MH_OK;
UINT i, first = INVALID_HOOK_POS;
EnterSpinLock();
if (g_hHeap != NULL)
{
for (i = 0; i < g_hooks.size; ++i)
{
if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable)
{
first = i;
break;
}
}
if (first != INVALID_HOOK_POS)
{
FROZEN_THREADS threads;
Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED);
for (i = first; i < g_hooks.size; ++i)
{
PHOOK_ENTRY pHook = &g_hooks.pItems[i];
if (pHook->isEnabled != pHook->queueEnable)
{
status = EnableHookLL(i, pHook->queueEnable);
if (status != MH_OK)
break;
}
}
Unfreeze(&threads);
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_CreateHookApiEx(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour,
LPVOID *ppOriginal, LPVOID *ppTarget)
{
HMODULE hModule;
LPVOID pTarget;
hModule = GetModuleHandleW(pszModule);
if (hModule == NULL)
return MH_ERROR_MODULE_NOT_FOUND;
pTarget = (LPVOID)GetProcAddress(hModule, pszProcName);
if (pTarget == NULL)
return MH_ERROR_FUNCTION_NOT_FOUND;
if(ppTarget != NULL)
*ppTarget = pTarget;
return MH_CreateHook(pTarget, pDetour, ppOriginal);
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_CreateHookApi(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal)
{
return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL);
}
//-------------------------------------------------------------------------
const char * WINAPI MH_StatusToString(MH_STATUS status)
{
#define MH_ST2STR(x) \
case x: \
return #x;
switch (status) {
MH_ST2STR(MH_UNKNOWN)
MH_ST2STR(MH_OK)
MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED)
MH_ST2STR(MH_ERROR_NOT_INITIALIZED)
MH_ST2STR(MH_ERROR_ALREADY_CREATED)
MH_ST2STR(MH_ERROR_NOT_CREATED)
MH_ST2STR(MH_ERROR_ENABLED)
MH_ST2STR(MH_ERROR_DISABLED)
MH_ST2STR(MH_ERROR_NOT_EXECUTABLE)
MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION)
MH_ST2STR(MH_ERROR_MEMORY_ALLOC)
MH_ST2STR(MH_ERROR_MEMORY_PROTECT)
MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND)
MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND)
}
#undef MH_ST2STR
return "(unknown)";
}

186
minhook/include/MinHook.h Normal file
View File

@ -0,0 +1,186 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* 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 HOLDER
* 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.
*/
#pragma once
#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
#error MinHook supports only x86 and x64 systems.
#endif
#include <windows.h>
// MinHook Error Codes.
typedef enum MH_STATUS
{
// Unknown error. Should not be returned.
MH_UNKNOWN = -1,
// Successful.
MH_OK = 0,
// MinHook is already initialized.
MH_ERROR_ALREADY_INITIALIZED,
// MinHook is not initialized yet, or already uninitialized.
MH_ERROR_NOT_INITIALIZED,
// The hook for the specified target function is already created.
MH_ERROR_ALREADY_CREATED,
// The hook for the specified target function is not created yet.
MH_ERROR_NOT_CREATED,
// The hook for the specified target function is already enabled.
MH_ERROR_ENABLED,
// The hook for the specified target function is not enabled yet, or already
// disabled.
MH_ERROR_DISABLED,
// The specified pointer is invalid. It points the address of non-allocated
// and/or non-executable region.
MH_ERROR_NOT_EXECUTABLE,
// The specified target function cannot be hooked.
MH_ERROR_UNSUPPORTED_FUNCTION,
// Failed to allocate memory.
MH_ERROR_MEMORY_ALLOC,
// Failed to change the memory protection.
MH_ERROR_MEMORY_PROTECT,
// The specified module is not loaded.
MH_ERROR_MODULE_NOT_FOUND,
// The specified function is not found.
MH_ERROR_FUNCTION_NOT_FOUND
}
MH_STATUS;
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
// MH_QueueEnableHook or MH_QueueDisableHook.
#define MH_ALL_HOOKS NULL
#ifdef __cplusplus
extern "C" {
#endif
// Initialize the MinHook library. You must call this function EXACTLY ONCE
// at the beginning of your program.
MH_STATUS WINAPI MH_Initialize(VOID);
// Uninitialize the MinHook library. You must call this function EXACTLY
// ONCE at the end of your program.
MH_STATUS WINAPI MH_Uninitialize(VOID);
// Creates a Hook for the specified target function, in disabled state.
// Parameters:
// pTarget [in] A pointer to the target function, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
// Creates a Hook for the specified API function, in disabled state.
// Parameters:
// pszModule [in] A pointer to the loaded module name which contains the
// target function.
// pszTarget [in] A pointer to the target function name, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHookApi(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
// Creates a Hook for the specified API function, in disabled state.
// Parameters:
// pszModule [in] A pointer to the loaded module name which contains the
// target function.
// pszTarget [in] A pointer to the target function name, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
// ppTarget [out] A pointer to the target function, which will be used
// with other functions.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHookApiEx(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
// Removes an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
// Enables an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// enabled in one go.
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
// Disables an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// disabled in one go.
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
// Queues to enable an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// queued to be enabled.
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
// Queues to disable an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// queued to be disabled.
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
// Applies all queued changes in one go.
MH_STATUS WINAPI MH_ApplyQueued(VOID);
// Translates the MH_STATUS to its name as a string.
const char * WINAPI MH_StatusToString(MH_STATUS status);
#ifdef __cplusplus
}
#endif

39
minhook/pstdint.h Normal file
View File

@ -0,0 +1,39 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu. 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 AUTHOR "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 AUTHOR 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.
*/
#pragma once
#include <windows.h>
// Integer types for HDE.
typedef INT8 int8_t;
typedef INT16 int16_t;
typedef INT32 int32_t;
typedef INT64 int64_t;
typedef UINT8 uint8_t;
typedef UINT16 uint16_t;
typedef UINT32 uint32_t;
typedef UINT64 uint64_t;

73
minhook/table32.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Hacker Disassembler Engine 32 C
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
*/
#define C_NONE 0x00
#define C_MODRM 0x01
#define C_IMM8 0x02
#define C_IMM16 0x04
#define C_IMM_P66 0x10
#define C_REL8 0x20
#define C_REL32 0x40
#define C_GROUP 0x80
#define C_ERROR 0xff
#define PRE_ANY 0x00
#define PRE_NONE 0x01
#define PRE_F2 0x02
#define PRE_F3 0x04
#define PRE_66 0x08
#define PRE_67 0x10
#define PRE_LOCK 0x20
#define PRE_SEG 0x40
#define PRE_ALL 0xff
#define DELTA_OPCODES 0x4a
#define DELTA_FPU_REG 0xf1
#define DELTA_FPU_MODRM 0xf8
#define DELTA_PREFIXES 0x130
#define DELTA_OP_LOCK_OK 0x1a1
#define DELTA_OP2_LOCK_OK 0x1b9
#define DELTA_OP_ONLY_MEM 0x1cb
#define DELTA_OP2_ONLY_MEM 0x1da
unsigned char hde32_table[] = {
0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,
0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f,
0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3,
0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa,
0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90,
0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f,
0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d,
0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59,
0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,
0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0,
0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01,
0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11,
0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8,
0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca,
0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff,
0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03,
0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,
0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,
0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f,
0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a,
0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,
0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a,
0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06,
0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06,
0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08,
0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,
0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,
0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,
0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,
0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,
0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,
0xe7,0x08,0x00,0xf0,0x02,0x00
};

74
minhook/table64.h Normal file
View File

@ -0,0 +1,74 @@
/*
* Hacker Disassembler Engine 64 C
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
*/
#define C_NONE 0x00
#define C_MODRM 0x01
#define C_IMM8 0x02
#define C_IMM16 0x04
#define C_IMM_P66 0x10
#define C_REL8 0x20
#define C_REL32 0x40
#define C_GROUP 0x80
#define C_ERROR 0xff
#define PRE_ANY 0x00
#define PRE_NONE 0x01
#define PRE_F2 0x02
#define PRE_F3 0x04
#define PRE_66 0x08
#define PRE_67 0x10
#define PRE_LOCK 0x20
#define PRE_SEG 0x40
#define PRE_ALL 0xff
#define DELTA_OPCODES 0x4a
#define DELTA_FPU_REG 0xfd
#define DELTA_FPU_MODRM 0x104
#define DELTA_PREFIXES 0x13c
#define DELTA_OP_LOCK_OK 0x1ae
#define DELTA_OP2_LOCK_OK 0x1c6
#define DELTA_OP_ONLY_MEM 0x1d8
#define DELTA_OP2_ONLY_MEM 0x1e7
unsigned char hde64_table[] = {
0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,
0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,
0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,
0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,
0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,
0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,
0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,
0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,
0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,
0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,
0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,
0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,
0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,
0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,
0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,
0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,
0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,
0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,
0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,
0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,
0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,
0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,
0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,
0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,
0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,
0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,
0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,
0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,
0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,
0x00,0xf0,0x02,0x00
};

316
minhook/trampoline.c Normal file
View File

@ -0,0 +1,316 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* 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 HOLDER
* 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 <windows.h>
#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
#if defined(_M_X64) || defined(__x86_64__)
#include "hde64.h"
typedef hde64s HDE;
#define HDE_DISASM(code, hs) hde64_disasm(code, hs)
#else
#include "hde32.h"
typedef hde32s HDE;
#define HDE_DISASM(code, hs) hde32_disasm(code, hs)
#endif
#include "trampoline.h"
#include "buffer.h"
// Maximum size of a trampoline function.
#if defined(_M_X64) || defined(__x86_64__)
#define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS))
#else
#define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE
#endif
//-------------------------------------------------------------------------
static BOOL IsCodePadding(LPBYTE pInst, UINT size)
{
UINT i;
if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC)
return FALSE;
for (i = 1; i < size; ++i)
{
if (pInst[i] != pInst[0])
return FALSE;
}
return TRUE;
}
//-------------------------------------------------------------------------
BOOL CreateTrampolineFunction(PTRAMPOLINE ct)
{
#if defined(_M_X64) || defined(__x86_64__)
CALL_ABS call = {
0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8]
0xEB, 0x08, // EB 08: JMP +10
0x0000000000000000ULL // Absolute destination address
};
JMP_ABS jmp = {
0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
0x0000000000000000ULL // Absolute destination address
};
JCC_ABS jcc = {
0x70, 0x0E, // 7* 0E: J** +16
0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
0x0000000000000000ULL // Absolute destination address
};
#else
CALL_REL call = {
0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx
0x00000000 // Relative destination address
};
JMP_REL jmp = {
0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx
0x00000000 // Relative destination address
};
JCC_REL jcc = {
0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx
0x00000000 // Relative destination address
};
#endif
UINT8 oldPos = 0;
UINT8 newPos = 0;
ULONG_PTR jmpDest = 0; // Destination address of an internal jump.
BOOL finished = FALSE; // Is the function completed?
#if defined(_M_X64) || defined(__x86_64__)
UINT8 instBuf[16];
#endif
ct->patchAbove = FALSE;
ct->nIP = 0;
do
{
HDE hs;
UINT copySize;
LPVOID pCopySrc;
ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos;
ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos;
copySize = HDE_DISASM((LPVOID)pOldInst, &hs);
if (hs.flags & F_ERROR)
return FALSE;
pCopySrc = (LPVOID)pOldInst;
if (oldPos >= sizeof(JMP_REL))
{
// The trampoline function is long enough.
// Complete the function with the jump to the target function.
#if defined(_M_X64) || defined(__x86_64__)
jmp.address = pOldInst;
#else
jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp)));
#endif
pCopySrc = &jmp;
copySize = sizeof(jmp);
finished = TRUE;
}
#if defined(_M_X64) || defined(__x86_64__)
else if ((hs.modrm & 0xC7) == 0x05)
{
// Instructions using RIP relative addressing. (ModR/M = 00???101B)
// Modify the RIP relative address.
PUINT32 pRelAddr;
// Avoid using memcpy to reduce the footprint.
#ifndef _MSC_VER
memcpy(instBuf, (LPBYTE)pOldInst, copySize);
#else
__movsb(instBuf, (LPBYTE)pOldInst, copySize);
#endif
pCopySrc = instBuf;
// Relative address is stored at (instruction length - immediate value length - 4).
pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4);
*pRelAddr
= (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len));
// Complete the function if JMP (FF /4).
if (hs.opcode == 0xFF && hs.modrm_reg == 4)
finished = TRUE;
}
#endif
else if (hs.opcode == 0xE8)
{
// Direct relative CALL
ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32;
#if defined(_M_X64) || defined(__x86_64__)
call.address = dest;
#else
call.operand = (UINT32)(dest - (pNewInst + sizeof(call)));
#endif
pCopySrc = &call;
copySize = sizeof(call);
}
else if ((hs.opcode & 0xFD) == 0xE9)
{
// Direct relative JMP (EB or E9)
ULONG_PTR dest = pOldInst + hs.len;
if (hs.opcode == 0xEB) // isShort jmp
dest += (INT8)hs.imm.imm8;
else
dest += (INT32)hs.imm.imm32;
// Simply copy an internal jump.
if ((ULONG_PTR)ct->pTarget <= dest
&& dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
{
if (jmpDest < dest)
jmpDest = dest;
}
else
{
#if defined(_M_X64) || defined(__x86_64__)
jmp.address = dest;
#else
jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp)));
#endif
pCopySrc = &jmp;
copySize = sizeof(jmp);
// Exit the function If it is not in the branch
finished = (pOldInst >= jmpDest);
}
}
else if ((hs.opcode & 0xF0) == 0x70
|| (hs.opcode & 0xFC) == 0xE0
|| (hs.opcode2 & 0xF0) == 0x80)
{
// Direct relative Jcc
ULONG_PTR dest = pOldInst + hs.len;
if ((hs.opcode & 0xF0) == 0x70 // Jcc
|| (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ
dest += (INT8)hs.imm.imm8;
else
dest += (INT32)hs.imm.imm32;
// Simply copy an internal jump.
if ((ULONG_PTR)ct->pTarget <= dest
&& dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
{
if (jmpDest < dest)
jmpDest = dest;
}
else if ((hs.opcode & 0xFC) == 0xE0)
{
// LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported.
return FALSE;
}
else
{
UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F);
#if defined(_M_X64) || defined(__x86_64__)
// Invert the condition in x64 mode to simplify the conditional jump logic.
jcc.opcode = 0x71 ^ cond;
jcc.address = dest;
#else
jcc.opcode1 = 0x80 | cond;
jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc)));
#endif
pCopySrc = &jcc;
copySize = sizeof(jcc);
}
}
else if ((hs.opcode & 0xFE) == 0xC2)
{
// RET (C2 or C3)
// Complete the function if not in a branch.
finished = (pOldInst >= jmpDest);
}
// Can't alter the instruction length in a branch.
if (pOldInst < jmpDest && copySize != hs.len)
return FALSE;
// Trampoline function is too large.
if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE)
return FALSE;
// Trampoline function has too many instructions.
if (ct->nIP >= ARRAYSIZE(ct->oldIPs))
return FALSE;
ct->oldIPs[ct->nIP] = oldPos;
ct->newIPs[ct->nIP] = newPos;
ct->nIP++;
// Avoid using memcpy to reduce the footprint.
#ifndef _MSC_VER
memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
#else
__movsb((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
#endif
newPos += copySize;
oldPos += hs.len;
}
while (!finished);
// Is there enough place for a long jump?
if (oldPos < sizeof(JMP_REL)
&& !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos))
{
// Is there enough place for a short jump?
if (oldPos < sizeof(JMP_REL_SHORT)
&& !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos))
{
return FALSE;
}
// Can we place the long jump above the function?
if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL)))
return FALSE;
if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL)))
return FALSE;
ct->patchAbove = TRUE;
}
#if defined(_M_X64) || defined(__x86_64__)
// Create a relay function.
jmp.address = (ULONG_PTR)ct->pDetour;
ct->pRelay = (LPBYTE)ct->pTrampoline + newPos;
memcpy(ct->pRelay, &jmp, sizeof(jmp));
#endif
return TRUE;
}

105
minhook/trampoline.h Normal file
View File

@ -0,0 +1,105 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* 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 HOLDER
* 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.
*/
#pragma once
#pragma pack(push, 1)
// Structs for writing x86/x64 instructions.
// 8-bit relative jump.
typedef struct _JMP_REL_SHORT
{
UINT8 opcode; // EB xx: JMP +2+xx
UINT8 operand;
} JMP_REL_SHORT, *PJMP_REL_SHORT;
// 32-bit direct relative jump/call.
typedef struct _JMP_REL
{
UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx
UINT32 operand; // Relative destination address
} JMP_REL, *PJMP_REL, CALL_REL;
// 64-bit indirect absolute jump.
typedef struct _JMP_ABS
{
UINT8 opcode0; // FF25 00000000: JMP [+6]
UINT8 opcode1;
UINT32 dummy;
UINT64 address; // Absolute destination address
} JMP_ABS, *PJMP_ABS;
// 64-bit indirect absolute call.
typedef struct _CALL_ABS
{
UINT8 opcode0; // FF15 00000002: CALL [+6]
UINT8 opcode1;
UINT32 dummy0;
UINT8 dummy1; // EB 08: JMP +10
UINT8 dummy2;
UINT64 address; // Absolute destination address
} CALL_ABS;
// 32-bit direct relative conditional jumps.
typedef struct _JCC_REL
{
UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx
UINT8 opcode1;
UINT32 operand; // Relative destination address
} JCC_REL;
// 64bit indirect absolute conditional jumps that x64 lacks.
typedef struct _JCC_ABS
{
UINT8 opcode; // 7* 0E: J** +16
UINT8 dummy0;
UINT8 dummy1; // FF25 00000000: JMP [+6]
UINT8 dummy2;
UINT32 dummy3;
UINT64 address; // Absolute destination address
} JCC_ABS;
#pragma pack(pop)
typedef struct _TRAMPOLINE
{
LPVOID pTarget; // [In] Address of the target function.
LPVOID pDetour; // [In] Address of the detour function.
LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function.
#if defined(_M_X64) || defined(__x86_64__)
LPVOID pRelay; // [Out] Address of the relay function.
#endif
BOOL patchAbove; // [Out] Should use the hot patch area?
UINT nIP; // [Out] Number of the instruction boundaries.
UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function.
UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function.
} TRAMPOLINE, *PTRAMPOLINE;
BOOL CreateTrampolineFunction(PTRAMPOLINE ct);

16
popnhax/Module.mk Normal file
View File

@ -0,0 +1,16 @@
avsdlls += popnhax
deplibs_popnhax := \
avs \
ldflags_popnhax := \
-lwinmm -lpsapi
libs_popnhax := \
util \
minhook
srcpp_popnhax := \
dllmain.cc \
loader.cc \
SearchFile.cc

49
popnhax/SearchFile.cc Normal file
View File

@ -0,0 +1,49 @@
#include <windows.h>
#include "SearchFile.h"
vector<string> SearchFile::getResult()
{
auto t = result;
result.clear();
return t;
}
bool SearchFile::search(const char *path, const char *ext, bool subfolders_only)
{
HANDLE hFile;
char buffer[MAX_PATH]={0,};
WIN32_FIND_DATA pNextInfo;
string t;
sprintf(buffer,"%s\\*.*",path);
hFile = FindFirstFileA(buffer,&pNextInfo);
if(!hFile){
return false;
}
while(FindNextFileA(hFile,&pNextInfo))
{
if(pNextInfo.cFileName[0] == '.')// . and ..
continue;
if(pNextInfo.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY && subfolders_only)
{
ZeroMemory(buffer,MAX_PATH);
sprintf(buffer,"%s\\%s",path,pNextInfo.cFileName);
search(buffer,ext,false);
}
if (!subfolders_only)
{
t.assign(path);
t+='\\';
t.append(pNextInfo.cFileName);
if(t.substr(t.size()-strlen(ext))==ext)
{
result.push_back(t);
}
}
}
return true;
}

14
popnhax/SearchFile.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef __SEARCHFILE_H_
#define __SEARCHFILE_H_
#include <vector>
#include <string>
using namespace std;
class SearchFile
{
private:
vector<string> result;
public:
vector<string> getResult();
bool search(const char *path,const char *ext,bool subfolders_only);
};
#endif

21
popnhax/config.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef __POPNHAX_CONFIG__
#define __POPNHAX_CONFIG__
#include <stdbool.h>
struct popnhax_config {
bool force_unlocks;
bool unset_volume;
bool event_mode;
bool remove_timer;
bool freeze_timer;
bool skip_tutorials;
bool patch_db;
bool disable_expansions;
bool disable_redirection;
bool patch_xml_auto;
char patch_xml_filename[MAX_PATH];
};
#endif

1078
popnhax/dllmain.cc Normal file

File diff suppressed because it is too large Load Diff

1282
popnhax/loader.cc Normal file

File diff suppressed because it is too large Load Diff

18
popnhax/loader.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __LOADER_H__
#define __LOADER_H__
#include <stdint.h>
int8_t get_chart_type_override(uint8_t *, uint32_t, uint32_t);
void musichax_core_init(bool force_unlocks, bool is_expansion_allowed, bool is_redirection_allowed,
char *target_datecode, char *base_data, uint64_t music_size,
uint64_t *new_music_size, char *orig_music_data, uint8_t **new_music_table,
uint64_t chart_size, uint64_t *new_chart_size, char *orig_chart_data,
uint8_t **new_chart_table, uint64_t style_size, uint64_t *new_style_size,
char *orig_style_data, uint8_t **new_style_table, uint64_t flavor_size,
uint64_t *new_flavor_size, char *orig_flavor_data,
uint8_t **new_flavor_table, uint64_t chara_size, uint64_t *new_chara_size,
char *orig_chara_data, uint8_t **new_chara_table);
#endif

2
popnhax/popnhax.def Normal file
View File

@ -0,0 +1,2 @@
LIBRARY popnhax
EXPORTS

95
popnhax/tableinfo.h Normal file
View File

@ -0,0 +1,95 @@
#ifndef __TABLEINFO_H__
#define __TABLEINFO_H__
#include <stdint.h>
typedef struct {
uint8_t *folder_ptr;
uint8_t *filename_ptr;
int32_t audio_param1;
int32_t audio_param2;
int32_t audio_param3;
int32_t audio_param4;
uint32_t file_type;
uint16_t used_keys;
uint8_t pad[2];
} chart_entry;
typedef struct {
uint32_t fontface;
uint32_t color;
uint32_t height;
uint32_t width;
} fontstyle_entry;
typedef struct {
uint8_t phrase1[13];
uint8_t phrase2[13];
uint8_t phrase3[13];
uint8_t phrase4[13];
uint8_t phrase5[13];
uint8_t phrase6[13];
uint8_t _pad1[2];
uint8_t *birthday_ptr;
uint8_t chara1_birth_month;
uint8_t chara2_birth_month;
uint8_t chara3_birth_month;
uint8_t chara1_birth_date;
uint8_t chara2_birth_date;
uint8_t chara3_birth_date;
uint16_t style1;
uint16_t style2;
uint16_t style3;
} flavor_entry;
typedef struct {
uint8_t *chara_id_ptr;
uint32_t flags;
uint8_t *folder_ptr;
uint8_t *gg_ptr;
uint8_t *cs_ptr;
uint8_t *icon1_ptr;
uint8_t *icon2_ptr;
uint16_t chara_xw;
uint16_t chara_yh;
uint32_t display_flags;
int16_t flavor_idx;
uint8_t chara_variation_num;
uint8_t _pad1[1];
uint8_t *sort_name_ptr;
uint8_t *disp_name_ptr;
uint32_t file_type;
uint32_t lapis_shape;
uint8_t lapis_color;
uint8_t _pad2[3];
uint8_t *ha_ptr;
uint8_t *catchtext_ptr;
int16_t win2_trigger;
uint8_t _pad3[2];
uint32_t game_version;
} character_entry;
typedef struct {
uint8_t *fw_genre_ptr;
uint8_t *fw_title_ptr;
uint8_t *fw_artist_ptr;
uint8_t *genre_ptr;
uint8_t *title_ptr;
uint8_t *artist_ptr;
uint16_t chara1;
uint16_t chara2;
uint32_t mask;
uint32_t folder;
uint32_t cs_version;
uint32_t categories;
uint8_t diffs[6];
uint16_t charts[7];
uint8_t *ha_ptr;
uint32_t chara_x;
uint32_t chara_y;
uint16_t unk1[32];
uint16_t display_bpm[12];
uint8_t hold_flags[8];
} music_entry;
#endif

134
popnhax/xmlhelper.h Normal file
View File

@ -0,0 +1,134 @@
#define READ_HEX(_xml, _prop, _prop_name, _var_output) \
{unsigned char _temp[256] = {}; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_STR, _temp, sizeof(_temp)); \
_var_output = strtol((const char*)_temp, NULL, 16); \
} \
#define READ_STR_RAW(_xml, _prop, _prop_name, _var_name) \
unsigned char _var_name[256] = {}; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_STR, _var_name, sizeof(_var_name)); \
#define READ_STR(_xml, _prop, _prop_name, _var_name, _var_output) \
unsigned char _var_name[256] = {}; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_STR, _var_name, sizeof(_var_name)); \
uint8_t *_var_output = add_string(_var_name);
#define READ_U8_ARR(_xml, _prop, _prop_name, _var_name, _elm_cnt) \
uint8_t _var_name[_elm_cnt] = {}; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_U8, (char*)&_var_name, sizeof(_var_name[0]) * _elm_cnt);
#define READ_U8(_xml, _prop, _prop_name, _var_name) \
uint8_t _var_name = 0; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_U8, (char*)&_var_name, sizeof(_var_name));
#define READ_S8(_xml, _prop, _prop_name, _var_name) \
int8_t _var_name = 0; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_U8, (char*)&_var_name, sizeof(_var_name));
#define READ_U16_ARR(_xml, _prop, _prop_name, _var_name, _elm_cnt) \
uint16_t _var_name[_elm_cnt] = {}; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_U16, (char*)&_var_name, sizeof(_var_name[0]) * _elm_cnt);
#define READ_U16(_xml, _prop, _prop_name, _var_name) \
uint16_t _var_name = 0; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_U16, (char*)&_var_name, sizeof(_var_name));
#define READ_S16(_xml, _prop, _prop_name, _var_name) \
int16_t _var_name = 0; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_S16, (char*)&_var_name, sizeof(_var_name));
#define READ_U32(_xml, _prop, _prop_name, _var_name) \
uint32_t _var_name = 0; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_U32, (char*)&_var_name, sizeof(_var_name));
#define READ_S32(_xml, _prop, _prop_name, _var_name) \
uint32_t _var_name = 0; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_S32, (char*)&_var_name, sizeof(_var_name));
// Optionals: Update _var_output if _prop_name exists
#define READ_STR_OPT(_xml, _prop, _prop_name, _var_output) \
{ \
if (property_search(_xml, _prop, _prop_name)) { \
unsigned char _var_tempname[256] = {}; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_STR, _var_tempname, sizeof(_var_tempname)); \
_var_output = add_string(_var_tempname); \
} \
}
#define READ_U32_OPT(_xml, _prop, _prop_name, _var_output) \
{ \
if (property_search(_xml, _prop, _prop_name)) { \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_U32, (char*)&_var_output, sizeof(_var_output)); \
} \
}
#define READ_S32_OPT(_xml, _prop, _prop_name, _var_output) \
{ \
if (property_search(_xml, _prop, _prop_name)) { \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_S32, (char*)&_var_output, sizeof(_var_output)); \
} \
}
#define READ_U16_OPT(_xml, _prop, _prop_name, _var_output) \
{ \
if (property_search(_xml, _prop, _prop_name)) { \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_U16, (char*)&_var_output, sizeof(_var_output)); \
} \
}
#define READ_S16_OPT(_xml, _prop, _prop_name, _var_output) \
{ \
if (property_search(_xml, _prop, _prop_name)) { \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_S16, (char*)&_var_output, sizeof(_var_output)); \
} \
}
#define READ_U8_OPT(_xml, _prop, _prop_name, _var_output) \
{ \
if (property_search(_xml, _prop, _prop_name)) { \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_U8, (char*)&_var_output, sizeof(_var_output)); \
} \
}
#define READ_U8_ARR_OPT(_xml, _prop, _prop_name, _var_output, _elm_cnt) \
{ \
if (property_search(_xml, _prop, _prop_name)) { \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_U8, (char*)&_var_output, sizeof(_var_output[0]) * _elm_cnt); \
} \
}
#define READ_U16_ARR_OPT(_xml, _prop, _prop_name, _var_output, _elm_cnt) \
{ \
if (property_search(_xml, _prop, _prop_name)) { \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_U16, (char*)&_var_output, sizeof(_var_output[0]) * _elm_cnt); \
} \
}
#define READ_CHARA_OPT(_xml, _prop, _prop_name, _var_output) \
{ \
if (property_search(_xml, _prop, _prop_name)) { \
unsigned char _var_tempname[256] = {}; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_STR, _var_tempname, sizeof(_var_tempname)); \
_var_output = get_chara_idx(_var_tempname); \
} \
}
#define READ_LAPIS_SHAPE_OPT(_xml, _prop, _prop_name, _var_output) \
{ \
if (property_search(_xml, _prop, _prop_name)) { \
unsigned char _var_tempname[256] = {}; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_STR, _var_tempname, sizeof(_var_tempname)); \
_var_output = get_lapis_shape_id(_var_tempname); \
} \
}
#define READ_LAPIS_COLOR_OPT(_xml, _prop, _prop_name, _var_output) \
{ \
if (property_search(_xml, _prop, _prop_name)) { \
unsigned char _var_tempname[256] = {}; \
property_node_refer(_xml, _prop, _prop_name, PROPERTY_TYPE_STR, _var_tempname, sizeof(_var_tempname)); \
_var_output = get_lapis_color_id(_var_tempname); \
} \
}

6
util/Module.mk Normal file
View File

@ -0,0 +1,6 @@
libs += util
srcpp_util := \
fuzzy_search.cc \
cmdline.cc \
patch.cc \

95
util/cmdline.cc Normal file
View File

@ -0,0 +1,95 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <windows.h>
void *xmalloc(size_t nbytes) {
void *mem;
mem = malloc(nbytes);
if (mem == NULL) {
return NULL;
}
return mem;
}
void *xrealloc(void *mem, size_t nbytes) {
void *newmem;
newmem = realloc(mem, nbytes);
if (newmem == NULL) {
return NULL;
}
return newmem;
}
static void push_argv(int *argc, char ***argv, const char *begin, const char *end) {
size_t nchars;
char *str;
(*argc)++;
*argv = (char **)xrealloc(*argv, *argc * sizeof(char **));
nchars = end - begin;
str = (char *)xmalloc(nchars + 1);
memcpy(str, begin, nchars);
str[nchars] = '\0';
(*argv)[*argc - 1] = str;
}
void args_recover(int *argc_out, char ***argv_out) {
int argc;
char **argv;
char *begin;
char *pos;
bool quote;
argc = 0;
argv = NULL;
quote = false;
for (begin = pos = GetCommandLine(); *pos; pos++) {
switch (*pos) {
case '"':
if (!quote) {
quote = true;
begin = pos + 1;
} else {
push_argv(&argc, &argv, begin, pos);
quote = false;
begin = NULL;
}
break;
case ' ':
if (!quote && begin != NULL) {
push_argv(&argc, &argv, begin, pos);
begin = NULL;
}
break;
default:
if (begin == NULL) {
begin = pos;
}
break;
}
}
if (begin != NULL && !quote) {
push_argv(&argc, &argv, begin, pos);
}
*argc_out = argc;
*argv_out = argv;
}

7
util/cmdline.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef UTIL_CMDLINE_H
#define UTIL_CMDLINE_H
void args_recover(int *argc, char ***argv);
void args_free(int argc, char **argv);
#endif

62
util/fuzzy_search.cc Normal file
View File

@ -0,0 +1,62 @@
#include <memory.h>
#include <stdint.h>
#include "util/fuzzy_search.h"
int find_block_core(char *haystack, size_t haystack_size, fuzzy_search_task *needle,
size_t orig_offset, int dir) {
size_t offset = orig_offset;
haystack_size += orig_offset;
while (offset + 1 < orig_offset + haystack_size) {
size_t offset_temp = offset;
int found = 1;
if (needle->count <= 0) {
found = 0;
}
for (int i = 0; i < needle->count; i++) {
int subfound = -1;
if (needle->blocks[i].type == 1) {
offset_temp += needle->blocks[i].length;
continue;
}
for (int j = 0; j < needle->blocks[i].count; j++) {
if (haystack + offset_temp + needle->blocks[i].data[j].length <
haystack + haystack_size &&
memcmp(haystack + offset_temp, needle->blocks[i].data[j].block,
needle->blocks[i].data[j].length) == 0) {
subfound = j;
break;
}
}
if (subfound == -1) {
found = 0;
break;
}
offset_temp += needle->blocks[i].data[subfound].length;
}
if (found == 1) {
return offset;
} else {
offset += dir;
}
}
return -1;
}
int find_block(char *haystack, size_t haystack_size, fuzzy_search_task *needle,
size_t orig_offset) {
return find_block_core(haystack, haystack_size, needle, orig_offset, 1);
}
int find_block_back(char *haystack, size_t haystack_size, fuzzy_search_task *needle,
size_t orig_offset) {
return find_block_core(haystack, haystack_size, needle, orig_offset, -1);
}

53
util/fuzzy_search.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef __FUZZY_SEARCH_H__
#define __FUZZY_SEARCH_H__
#include <stddef.h>
#define FUZZY_START(task, _count) \
{ \
task.count = _count; \
task.blocks = (fuzzy_search_block *)calloc(task.count, sizeof(fuzzy_search_block)); \
}
#define FUZZY_CODE(task, id, code, len) \
{ \
task.blocks[id].count = 1; \
task.blocks[id].data[0].type = 0; \
task.blocks[id].data[0].length = len; \
task.blocks[id].data[0].block = \
(char *)calloc(task.blocks[id].data[0].length, sizeof(char)); \
memcpy(task.blocks[id].data[0].block, code, task.blocks[id].data[0].length); \
}
#define FUZZY_WILDCARD(task, id, len) \
{ \
task.blocks[id].count = 1; \
task.blocks[id].type = 1; \
task.blocks[id].length = len; \
task.blocks[id].data[0].length = len; \
}
#define FUZZY_SIZE(task, id) (task.blocks[id].data[0].length)
typedef struct fuzzy_search_block_data {
int type;
int length;
char *block;
} fuzzy_search_block_data;
typedef struct fuzzy_search_block {
int type;
int length;
int count;
fuzzy_search_block_data data[0x10];
} fuzzy_search_block;
typedef struct fuzzy_search_task {
int count;
fuzzy_search_block *blocks;
} fuzzy_search_task;
int find_block(char *haystack, size_t haystack_size, fuzzy_search_task *needle, size_t offset);
int find_block_back(char *haystack, size_t haystack_size, fuzzy_search_task *needle, size_t offset);
#endif

27
util/patch.cc Normal file
View File

@ -0,0 +1,27 @@
// clang-format off
#include <windows.h>
#include <psapi.h>
// clang-format on
#include "patch.h"
void patch_memory(uint64_t patch_addr, char *data, size_t len) {
DWORD old_prot;
VirtualProtect((LPVOID)patch_addr, len, PAGE_EXECUTE_READWRITE, &old_prot);
memcpy((LPVOID)patch_addr, data, len);
VirtualProtect((LPVOID)patch_addr, len, old_prot, &old_prot);
}
char *getDllData(const char *dllFilename, DWORD *dllSize) {
HMODULE _moduleBase = GetModuleHandle(dllFilename);
MODULEINFO module_info;
memset(&module_info, 0, sizeof(module_info));
if (!GetModuleInformation(GetCurrentProcess(), _moduleBase, &module_info,
sizeof(module_info))) {
return NULL;
}
*dllSize = module_info.SizeOfImage;
return (char *)module_info.lpBaseOfDll;
}

13
util/patch.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __PATCH_H__
#define __PATCH_H__
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef unsigned long DWORD;
void patch_memory(uint64_t patch_addr, char *data, size_t len);
char *getDllData(const char *dllFilename, DWORD *dllSize);
#endif

100
util/xmlprop.hpp Normal file
View File

@ -0,0 +1,100 @@
#ifndef __XML_H__
#define __XML_H__
#include <stdio.h>
#include "imports/avs.h"
struct property_psmap {
uint8_t type;
uint8_t has_default;
uint16_t field_offset;
uint32_t member_width;
const char *path;
uintptr_t default_value;
} __attribute__((packed));
enum psmap_property_type {
PSMAP_PROPERTY_TYPE_S8 = 0x02,
PSMAP_PROPERTY_TYPE_U8 = 0x03,
PSMAP_PROPERTY_TYPE_S16 = 0x04,
PSMAP_PROPERTY_TYPE_U16 = 0x05,
PSMAP_PROPERTY_TYPE_S32 = 0x06,
PSMAP_PROPERTY_TYPE_U32 = 0x07,
PSMAP_PROPERTY_TYPE_S64 = 0x08,
PSMAP_PROPERTY_TYPE_U64 = 0x09,
PSMAP_PROPERTY_TYPE_STR = 0x0A,
PSMAP_PROPERTY_TYPE_FLOAT = 0x0D,
PSMAP_PROPERTY_TYPE_ATTR = 0x2D,
PSMAP_PROPERTY_TYPE_BOOL = 0x32,
};
#ifndef __offsetof
#define __offsetof(_s, _f) __builtin_offsetof(_s, _f)
#endif
#ifndef __fieldwidth
#define __fieldwidth(_s, _f) sizeof((((_s *)NULL)->_f))
#endif
#define PSMAP_BEGIN(_name, _type) const _type struct property_psmap _name[] = {
#define PSMAP_MEMBER_REQ(_type, _struct, _member, _path) \
{_type, false, __offsetof(_struct, _member), __fieldwidth(_struct, _member), _path, 0},
#define PSMAP_MEMBER_OPT(_type, _struct, _member, _path, _def) \
{_type, true, __offsetof(_struct, _member), __fieldwidth(_struct, _member), \
_path, (uintptr_t)_def},
#define PSMAP_END \
{ 0xff, false, 0, 0, "NULL", 0 } \
} \
;
int reader_callback(uint32_t context, void *bytes, size_t nbytes) {
return fread(bytes, 1, nbytes, (FILE *)TlsGetValue(context));
}
struct property *load_prop_file(const char *filename) {
FILE *file = fopen(filename, "rb");
DWORD tlsIndex = TlsAlloc();
TlsSetValue(tlsIndex, (void *)file);
if (!file) {
printf("Could not open config file: %s\n", filename);
return nullptr;
}
const size_t size = property_read_query_memsize(reader_callback, tlsIndex, NULL, NULL);
rewind(file);
struct property_node *buffer =
(struct property_node *)calloc(size + 0x10000, sizeof(unsigned char));
struct property *config_data = property_create(0x17, buffer, size + 0x10000);
if (size > 0) {
const int ret = property_insert_read(config_data, 0, reader_callback, tlsIndex);
if (ret) {
fclose(file);
} else {
printf("Could not load %s\n", filename);
exit(-6);
}
}
return config_data;
}
void _load_config(const char *filename, void *dest, const struct property_psmap *psmap) {
struct property *config_xml = load_prop_file(filename);
if (!config_xml) {
printf("Couldn't load xml file: %s\n", filename);
return;
}
if (!(property_psmap_import(config_xml, nullptr, dest, psmap))) {
printf("Couldn't parse psmap\n");
}
}
#endif