diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9a45936
--- /dev/null
+++ b/Makefile
@@ -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)
+
diff --git a/Module.mk b/Module.mk
new file mode 100644
index 0000000..c4baf77
--- /dev/null
+++ b/Module.mk
@@ -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
diff --git a/README.md b/README.md
index 436fb8b..17fbcfe 100644
--- a/README.md
+++ b/README.md
@@ -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
+
+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`.
diff --git a/clang-format.py b/clang-format.py
new file mode 100644
index 0000000..97a7db3
--- /dev/null
+++ b/clang-format.py
@@ -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()
diff --git a/clang-tidy.sh b/clang-tidy.sh
new file mode 100644
index 0000000..f0558b1
--- /dev/null
+++ b/clang-tidy.sh
@@ -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
diff --git a/dist/popnhax/popnhax.xml b/dist/popnhax/popnhax.xml
new file mode 100644
index 0000000..8f27cad
--- /dev/null
+++ b/dist/popnhax/popnhax.xml
@@ -0,0 +1,26 @@
+
+
+
+ 1
+
+ 0
+
+ 1
+
+ 0
+
+ 0
+
+ 1
+
+
+ 1
+
+ 0
+
+ 0
+
+ 1
+
+
+
diff --git a/imports/avs-ea3.h b/imports/avs-ea3.h
new file mode 100644
index 0000000..e12589a
--- /dev/null
+++ b/imports/avs-ea3.h
@@ -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
diff --git a/imports/avs.h b/imports/avs.h
new file mode 100644
index 0000000..5a93c94
--- /dev/null
+++ b/imports/avs.h
@@ -0,0 +1,188 @@
+#ifndef IMPORTS_AVS_H
+#define IMPORTS_AVS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+#include
+
+#include
+
+#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
diff --git a/imports/import_32_0_avs.def b/imports/import_32_0_avs.def
new file mode 100644
index 0000000..cb2ea9d
--- /dev/null
+++ b/imports/import_32_0_avs.def
@@ -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
+
diff --git a/imports/import_32_1101_avs.def b/imports/import_32_1101_avs.def
new file mode 100644
index 0000000..1b63626
--- /dev/null
+++ b/imports/import_32_1101_avs.def
@@ -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
diff --git a/imports/import_32_1304_avs.def b/imports/import_32_1304_avs.def
new file mode 100644
index 0000000..5a98e5a
--- /dev/null
+++ b/imports/import_32_1304_avs.def
@@ -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
diff --git a/imports/import_32_1403_avs.def b/imports/import_32_1403_avs.def
new file mode 100644
index 0000000..32d68b1
--- /dev/null
+++ b/imports/import_32_1403_avs.def
@@ -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
diff --git a/imports/import_32_1508_avs.def b/imports/import_32_1508_avs.def
new file mode 100644
index 0000000..2406cb0
--- /dev/null
+++ b/imports/import_32_1508_avs.def
@@ -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
+
+
diff --git a/imports/import_32_1601_avs.def b/imports/import_32_1601_avs.def
new file mode 100644
index 0000000..e260a8c
--- /dev/null
+++ b/imports/import_32_1601_avs.def
@@ -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
+
diff --git a/imports/import_32_1603_avs.def b/imports/import_32_1603_avs.def
new file mode 100644
index 0000000..98f5fe7
--- /dev/null
+++ b/imports/import_32_1603_avs.def
@@ -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
diff --git a/imports/import_32_1700_avs.def b/imports/import_32_1700_avs.def
new file mode 100644
index 0000000..18fefc8
--- /dev/null
+++ b/imports/import_32_1700_avs.def
@@ -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
diff --git a/imports/import_32_803_avs.def b/imports/import_32_803_avs.def
new file mode 100644
index 0000000..a7f59b5
--- /dev/null
+++ b/imports/import_32_803_avs.def
@@ -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
+
diff --git a/imports/import_64_1509_avs-ea3.def b/imports/import_64_1509_avs-ea3.def
new file mode 100644
index 0000000..67a9653
--- /dev/null
+++ b/imports/import_64_1509_avs-ea3.def
@@ -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
diff --git a/imports/import_64_1509_avs.def b/imports/import_64_1509_avs.def
new file mode 100644
index 0000000..62ca959
--- /dev/null
+++ b/imports/import_64_1509_avs.def
@@ -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
diff --git a/imports/import_64_1700_avs.def b/imports/import_64_1700_avs.def
new file mode 100644
index 0000000..18fefc8
--- /dev/null
+++ b/imports/import_64_1700_avs.def
@@ -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
diff --git a/minhook/LICENSE.txt b/minhook/LICENSE.txt
new file mode 100644
index 0000000..74dea27
--- /dev/null
+++ b/minhook/LICENSE.txt
@@ -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.
diff --git a/minhook/Module.mk b/minhook/Module.mk
new file mode 100644
index 0000000..0380232
--- /dev/null
+++ b/minhook/Module.mk
@@ -0,0 +1,8 @@
+libs += minhook
+
+src_minhook := \
+ hook.c \
+ buffer.c \
+ trampoline.c \
+ hde32.c \
+ hde64.c \
diff --git a/minhook/buffer.c b/minhook/buffer.c
new file mode 100644
index 0000000..8f9fbce
--- /dev/null
+++ b/minhook/buffer.c
@@ -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
+#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));
+}
diff --git a/minhook/buffer.h b/minhook/buffer.h
new file mode 100644
index 0000000..204d551
--- /dev/null
+++ b/minhook/buffer.h
@@ -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);
diff --git a/minhook/hde32.c b/minhook/hde32.c
new file mode 100644
index 0000000..08fa25b
--- /dev/null
+++ b/minhook/hde32.c
@@ -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__)
diff --git a/minhook/hde32.h b/minhook/hde32.h
new file mode 100644
index 0000000..1112450
--- /dev/null
+++ b/minhook/hde32.h
@@ -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_ */
diff --git a/minhook/hde64.c b/minhook/hde64.c
new file mode 100644
index 0000000..c23e2fc
--- /dev/null
+++ b/minhook/hde64.c
@@ -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__)
diff --git a/minhook/hde64.h b/minhook/hde64.h
new file mode 100644
index 0000000..ecbf4df
--- /dev/null
+++ b/minhook/hde64.h
@@ -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_ */
diff --git a/minhook/hook.c b/minhook/hook.c
new file mode 100644
index 0000000..8250d8f
--- /dev/null
+++ b/minhook/hook.c
@@ -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
+#include
+#include
+
+#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)";
+}
diff --git a/minhook/include/MinHook.h b/minhook/include/MinHook.h
new file mode 100644
index 0000000..15c0a87
--- /dev/null
+++ b/minhook/include/MinHook.h
@@ -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
+
+// 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
+
diff --git a/minhook/pstdint.h b/minhook/pstdint.h
new file mode 100644
index 0000000..84d82a0
--- /dev/null
+++ b/minhook/pstdint.h
@@ -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
+
+// 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;
diff --git a/minhook/table32.h b/minhook/table32.h
new file mode 100644
index 0000000..7b3e12e
--- /dev/null
+++ b/minhook/table32.h
@@ -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
+};
diff --git a/minhook/table64.h b/minhook/table64.h
new file mode 100644
index 0000000..01d4541
--- /dev/null
+++ b/minhook/table64.h
@@ -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
+};
diff --git a/minhook/trampoline.c b/minhook/trampoline.c
new file mode 100644
index 0000000..b707411
--- /dev/null
+++ b/minhook/trampoline.c
@@ -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
+
+#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;
+}
diff --git a/minhook/trampoline.h b/minhook/trampoline.h
new file mode 100644
index 0000000..bdffdac
--- /dev/null
+++ b/minhook/trampoline.h
@@ -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);
diff --git a/popnhax/Module.mk b/popnhax/Module.mk
new file mode 100644
index 0000000..3d64988
--- /dev/null
+++ b/popnhax/Module.mk
@@ -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
diff --git a/popnhax/SearchFile.cc b/popnhax/SearchFile.cc
new file mode 100644
index 0000000..71c986c
--- /dev/null
+++ b/popnhax/SearchFile.cc
@@ -0,0 +1,49 @@
+
+#include
+#include "SearchFile.h"
+
+vector 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;
+}
+
diff --git a/popnhax/SearchFile.h b/popnhax/SearchFile.h
new file mode 100644
index 0000000..1775e3c
--- /dev/null
+++ b/popnhax/SearchFile.h
@@ -0,0 +1,14 @@
+#ifndef __SEARCHFILE_H_
+#define __SEARCHFILE_H_
+#include
+#include
+using namespace std;
+class SearchFile
+{
+private:
+ vector result;
+public:
+ vector getResult();
+ bool search(const char *path,const char *ext,bool subfolders_only);
+};
+#endif
diff --git a/popnhax/config.h b/popnhax/config.h
new file mode 100644
index 0000000..af632f4
--- /dev/null
+++ b/popnhax/config.h
@@ -0,0 +1,21 @@
+#ifndef __POPNHAX_CONFIG__
+#define __POPNHAX_CONFIG__
+
+#include
+
+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
diff --git a/popnhax/dllmain.cc b/popnhax/dllmain.cc
new file mode 100644
index 0000000..98a00f8
--- /dev/null
+++ b/popnhax/dllmain.cc
@@ -0,0 +1,1078 @@
+// clang-format off
+#include
+#include
+// clang-format on
+
+#include
+
+#include
+#include
+#include
+
+#include "util/fuzzy_search.h"
+
+#include "minhook/hde32.h"
+#include "minhook/include/MinHook.h"
+
+#include "popnhax/config.h"
+#include "util/patch.h"
+#include "util/xmlprop.hpp"
+#include "xmlhelper.h"
+
+#include "tableinfo.h"
+#include "loader.h"
+
+#include "SearchFile.h"
+
+uint8_t *add_string(uint8_t *input);
+
+struct popnhax_config config = {};
+
+PSMAP_BEGIN(config_psmap, static)
+PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, force_unlocks,
+ "/popnhax/force_unlocks")
+PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, unset_volume,
+ "/popnhax/unset_volume")
+PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, event_mode, "/popnhax/event_mode")
+PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, remove_timer,
+ "/popnhax/remove_timer")
+PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, freeze_timer,
+ "/popnhax/freeze_timer")
+PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, skip_tutorials,
+ "/popnhax/skip_tutorials")
+PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, patch_db,
+ "/popnhax/patch_db")
+PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, disable_expansions,
+ "/popnhax/disable_expansions")
+PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, disable_redirection,
+ "/popnhax/disable_redirection")
+PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, patch_xml_auto,
+ "/popnhax/patch_xml_auto")
+PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_STR, struct popnhax_config, patch_xml_filename,
+ "/popnhax/patch_xml_filename")
+PSMAP_END
+
+enum BufferIndexes {
+ MUSIC_TABLE_IDX = 0,
+ CHART_TABLE_IDX,
+ STYLE_TABLE_IDX,
+ FLAVOR_TABLE_IDX,
+ CHARA_TABLE_IDX,
+};
+
+typedef struct {
+ uint64_t type;
+ uint64_t method;
+ uint64_t offset;
+ uint64_t expectedValue;
+ uint64_t size;
+} UpdateOtherEntry;
+
+typedef struct {
+ uint64_t type;
+ uint64_t offset;
+ uint64_t size;
+} UpdateBufferEntry;
+
+typedef struct {
+ uint64_t method;
+ uint64_t offset;
+} HookEntry;
+
+const size_t LIMIT_TABLE_SIZE = 5;
+uint64_t limit_table[LIMIT_TABLE_SIZE] = {0};
+uint64_t new_limit_table[LIMIT_TABLE_SIZE] = {0};
+uint64_t buffer_addrs[LIMIT_TABLE_SIZE] = {0};
+
+uint8_t *new_buffer_addrs[LIMIT_TABLE_SIZE] = {NULL};
+
+std::vector buffer_offsets;
+std::vector other_offsets;
+std::vector hook_offsets;
+
+void (*real_omnimix_patch_jbx)();
+void omnimix_patch_jbx() {
+ __asm("mov al, 'X'\n");
+ __asm("mov byte [edi+4], al\n");
+ real_omnimix_patch_jbx();
+}
+
+void (*real_check_music_idx)();
+extern "C" void check_music_idx();
+
+extern "C" int8_t check_music_idx_handler(int32_t music_idx, int32_t chart_idx, int32_t result) {
+ int8_t override_flag = get_chart_type_override(new_buffer_addrs[MUSIC_TABLE_IDX], music_idx & 0xffff, chart_idx & 0x0f);
+
+ printf("music_idx: %d, result: %d, override_flag: %d\n", music_idx & 0xffff, result, override_flag);
+
+ if (override_flag != -1) {
+ return override_flag;
+ }
+
+ return (music_idx & 0xffff) > limit_table[CHART_TABLE_IDX] ? 1 : result;
+}
+
+asm(
+".global _check_music_idx\n"
+"_check_music_idx:\n"
+" call [_real_check_music_idx]\n"
+" movzx eax, al\n"
+" push eax\n"
+" push ebx\n"
+" push esi\n"
+" call _check_music_idx_handler\n"
+" add esp, 12\n"
+" ret\n"
+);
+
+void (*real_check_music_idx_usaneko)();
+extern "C" void check_music_idx_usaneko();
+extern "C" int8_t check_music_idx_handler_usaneko(int32_t result, int32_t chart_idx, int32_t music_idx) {
+ return check_music_idx_handler(music_idx, chart_idx, result);
+}
+
+asm(
+".global _check_music_idx_usaneko\n"
+"_check_music_idx_usaneko:\n"
+" push edi\n"
+" push ebx\n"
+" cmp eax, 0x18\n"
+" setl al\n"
+" movzx eax, al\n"
+" push eax\n"
+" call _check_music_idx_handler_usaneko\n"
+" add esp, 12\n"
+" jmp [_real_check_music_idx_usaneko]\n"
+);
+
+void patch_string(const char *input_string, const char *new_string) {
+ DWORD dllSize = 0;
+ char *data = getDllData("popn22.dll", &dllSize);
+
+ while (1) {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, input_string, strlen(input_string))
+
+ int64_t pattern_offset = find_block(data, dllSize, &task, 0);
+ if (pattern_offset == -1) {
+ break;
+ }
+
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ char *new_string_buff = (char*)calloc(strlen(new_string) + 1, sizeof(char));
+ memcpy(new_string_buff, new_string, strlen(new_string));
+ patch_memory(patch_addr, new_string_buff, strlen(new_string) + 1);
+ free(new_string_buff);
+ }
+}
+
+char *parse_patchdb(const char *input_filename, char *base_data) {
+ const char *folder = "data_mods\\";
+ char *input_filepath = (char*)calloc(strlen(input_filename) + strlen(folder) + 1, sizeof(char));
+
+ sprintf(input_filepath, "%s%s", folder, input_filename);
+
+ property* config_xml = load_prop_file(input_filepath);
+
+ free(input_filepath);
+
+ char *target = (char*)calloc(64, sizeof(char));
+ property_node_refer(config_xml, property_search(config_xml, NULL, "/patches"), "target@", PROPERTY_TYPE_ATTR, target, 64);
+
+ READ_U32(config_xml, NULL, "/patches/limits/music", limit_music)
+ READ_U32(config_xml, NULL, "/patches/limits/chart", limit_chart)
+ READ_U32(config_xml, NULL, "/patches/limits/style", limit_style)
+ READ_U32(config_xml, NULL, "/patches/limits/flavor", limit_flavor)
+ READ_U32(config_xml, NULL, "/patches/limits/chara", limit_chara)
+
+ limit_table[MUSIC_TABLE_IDX] = limit_music;
+ limit_table[CHART_TABLE_IDX] = limit_chart;
+ limit_table[STYLE_TABLE_IDX] = limit_style;
+ limit_table[FLAVOR_TABLE_IDX] = limit_flavor;
+ limit_table[CHARA_TABLE_IDX] = limit_chara;
+
+ READ_HEX(config_xml, NULL, "/patches/buffer_base_addrs/music", buffer_addrs[MUSIC_TABLE_IDX])
+ buffer_addrs[MUSIC_TABLE_IDX] = buffer_addrs[MUSIC_TABLE_IDX] > 0 ? (uint64_t)base_data + (buffer_addrs[MUSIC_TABLE_IDX] - 0x10000000) : buffer_addrs[MUSIC_TABLE_IDX];
+
+ READ_HEX(config_xml, NULL, "/patches/buffer_base_addrs/chart", buffer_addrs[CHART_TABLE_IDX])
+ buffer_addrs[CHART_TABLE_IDX] = buffer_addrs[CHART_TABLE_IDX] > 0 ? (uint64_t)base_data + (buffer_addrs[CHART_TABLE_IDX] - 0x10000000) : buffer_addrs[CHART_TABLE_IDX];
+
+ READ_HEX(config_xml, NULL, "/patches/buffer_base_addrs/style", buffer_addrs[STYLE_TABLE_IDX])
+ buffer_addrs[STYLE_TABLE_IDX] = buffer_addrs[STYLE_TABLE_IDX] > 0 ? (uint64_t)base_data + (buffer_addrs[STYLE_TABLE_IDX] - 0x10000000) : buffer_addrs[STYLE_TABLE_IDX];
+
+ READ_HEX(config_xml, NULL, "/patches/buffer_base_addrs/flavor", buffer_addrs[FLAVOR_TABLE_IDX])
+ buffer_addrs[FLAVOR_TABLE_IDX] = buffer_addrs[FLAVOR_TABLE_IDX] > 0 ? (uint64_t)base_data + (buffer_addrs[FLAVOR_TABLE_IDX] - 0x10000000) : buffer_addrs[FLAVOR_TABLE_IDX];
+
+ READ_HEX(config_xml, NULL, "/patches/buffer_base_addrs/chara", buffer_addrs[CHARA_TABLE_IDX])
+ buffer_addrs[CHARA_TABLE_IDX] = buffer_addrs[CHARA_TABLE_IDX] > 0 ? (uint64_t)base_data + (buffer_addrs[CHARA_TABLE_IDX] - 0x10000000) : buffer_addrs[CHARA_TABLE_IDX];
+
+ printf("limit music: %lld\n", limit_table[MUSIC_TABLE_IDX]);
+ printf("limit chart: %lld\n", limit_table[CHART_TABLE_IDX]);
+ printf("limit style: %lld\n", limit_table[STYLE_TABLE_IDX]);
+ printf("limit flavor: %lld\n", limit_table[FLAVOR_TABLE_IDX]);
+ printf("limit chara: %lld\n", limit_table[CHARA_TABLE_IDX]);
+
+ printf("buffer music: %llx\n", buffer_addrs[MUSIC_TABLE_IDX]);
+ printf("buffer chart: %llx\n", buffer_addrs[CHART_TABLE_IDX]);
+ printf("buffer style: %llx\n", buffer_addrs[STYLE_TABLE_IDX]);
+ printf("buffer flavor: %llx\n", buffer_addrs[FLAVOR_TABLE_IDX]);
+ printf("buffer chara: %llx\n", buffer_addrs[CHARA_TABLE_IDX]);
+
+ const char *types[LIMIT_TABLE_SIZE] = {"music", "chart", "style", "flavor", "chara"};
+
+ // Read buffers_patch_addrs
+ for (size_t i = 0; i < LIMIT_TABLE_SIZE; i++) {
+ const char strbase[] = "/patches/buffers_patch_addrs";
+ size_t search_str_len = strlen(strbase) + 1 + strlen(types[i]) + 1;
+ char *search_str = (char*)calloc(search_str_len, sizeof(char));
+
+ if (!search_str) {
+ printf("Couldn't create buffer of size %d\n", search_str_len);
+ exit(1);
+ }
+
+ sprintf(search_str, "%s/%s", strbase, types[i]);
+ printf("search_str: %s\n", search_str);
+
+ property_node* prop = NULL;
+ if ((prop = property_search(config_xml, NULL, search_str))) {
+ for (; prop != NULL; prop = property_node_traversal(prop, TRAVERSE_NEXT_SEARCH_RESULT)) {
+ uint64_t offset = 0;
+ READ_HEX(config_xml, prop, "", offset)
+
+ printf("offset ptr: %llx\n", offset);
+
+ UpdateBufferEntry *buffer_offset = new UpdateBufferEntry();
+ buffer_offset->type = i;
+ buffer_offset->offset = offset;
+ buffer_offsets.push_back(buffer_offset);
+ }
+ }
+ }
+
+ // Read other_patches
+ for (size_t i = 0; i < LIMIT_TABLE_SIZE; i++) {
+ const char strbase[] = "/patches/other_patches";
+ size_t search_str_len = strlen(strbase) + 1 + strlen(types[i]) + 1;
+ char *search_str = (char*)calloc(search_str_len, sizeof(char));
+
+ if (!search_str) {
+ printf("Couldn't create buffer of size %d\n", search_str_len);
+ exit(1);
+ }
+
+ sprintf(search_str, "%s/%s", strbase, types[i]);
+ printf("search_str: %s\n", search_str);
+
+ property_node* prop = NULL;
+ if ((prop = property_search(config_xml, NULL, search_str))) {
+ for (; prop != NULL; prop = property_node_traversal(prop, TRAVERSE_NEXT_SEARCH_RESULT)) {
+ char methodStr[256] = {};
+ property_node_refer(config_xml, prop, "method@", PROPERTY_TYPE_ATTR, methodStr, sizeof(methodStr));
+ uint32_t method = atoi(methodStr);
+
+ char expectedStr[256] = {};
+ property_node_refer(config_xml, prop, "expected@", PROPERTY_TYPE_ATTR, expectedStr, sizeof(expectedStr));
+ uint64_t expected = strtol((const char*)expectedStr, NULL, 16);
+
+ char sizeStr[256] = {};
+ property_node_refer(config_xml, prop, "size@", PROPERTY_TYPE_ATTR, sizeStr, sizeof(sizeStr));
+ uint64_t size = strtol((const char*)sizeStr, NULL, 16);
+
+ if (size == 0) {
+ // I can't think of any patches that require a different size than 4 bytes
+ size = 4;
+ }
+
+ uint64_t offset = 0;
+ READ_HEX(config_xml, prop, "", offset)
+
+ printf("offset ptr: %llx, method = %d, expected = %llx, size = %lld\n", offset, method, expected, size);
+
+ UpdateOtherEntry *other_offset = new UpdateOtherEntry();
+ other_offset->type = i;
+ other_offset->method = method;
+ other_offset->offset = offset;
+ other_offset->expectedValue = expected;
+ other_offset->size = size;
+ other_offsets.push_back(other_offset);
+ }
+ }
+ }
+
+ // Read hook_addrs
+ {
+ property_node* prop = NULL;
+ if ((prop = property_search(config_xml, NULL, "/patches/hook_addrs/offset"))) {
+ for (; prop != NULL; prop = property_node_traversal(prop, TRAVERSE_NEXT_SEARCH_RESULT)) {
+ char methodStr[256] = {};
+ property_node_refer(config_xml, prop, "method@", PROPERTY_TYPE_ATTR, methodStr, sizeof(methodStr));
+ uint32_t method = atoi(methodStr);
+
+ uint64_t offset = 0;
+ READ_HEX(config_xml, prop, "", offset)
+
+ printf("offset ptr: %llx\n", offset);
+
+ HookEntry *hook_offset = new HookEntry();
+ hook_offset->offset = offset;
+ hook_offset->method = method;
+ hook_offsets.push_back(hook_offset);
+ }
+ }
+ }
+
+ return target;
+}
+
+static bool patch_database(bool force_unlocks) {
+ DWORD dllSize = 0;
+ char *data = getDllData("popn22.dll", &dllSize);
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x8D\x44\x24\x10\x88\x4C\x24\x10\x88\x5C\x24\x11\x8D\x50\x01", 15)
+
+ int64_t pattern_offset = find_block(data, dllSize, &task, 0);
+ if (pattern_offset != -1) {
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ MH_CreateHook((LPVOID)patch_addr, (LPVOID)omnimix_patch_jbx,
+ (void **)&real_omnimix_patch_jbx);
+
+ printf("popnhax: Patched X rev for omnimix\n");
+ } else {
+ printf("popnhax: Couldn't find rev patch\n");
+ }
+ }
+
+ char *target;
+
+ if (config.patch_xml_auto) {
+ const char *filename = NULL;
+ SearchFile s;
+ uint8_t *datecode = NULL;
+ bool found = false;
+
+ printf("pophax: auto detect patch file\n");
+ property *config_xml = load_prop_file("prop/ea3-config.xml");
+ READ_STR_OPT(config_xml, property_search(config_xml, NULL, "/ea3/soft"), "ext", datecode)
+ free(config_xml);
+
+ if (datecode == NULL) {
+ printf("popnhax: (patch_xml_auto) failed to retrieve datecode from ea3-config. Please disable patch_xml_auto option and use patch_xml_filename to specify which file should be used.\n");
+ return false;
+ }
+
+ printf("popnhax: (patch_xml_auto) datecode from ea3-config : %s\n", datecode);
+ printf("popnhax: (patch_xml_auto) XML patch files search...\n");
+ s.search("data_mods", "xml", false);
+ auto result = s.getResult();
+
+ printf("popnhax: (patch_xml_auto) found %d xml files in data_mods\n",result.size());
+ for (uint16_t i=0; ioffset == 0 || buffer_addrs[buffer_offsets[i]->type] == 0) {
+ continue;
+ }
+
+ // buffer_base_offsets is required because it will point to the beginning of all of the buffers to calculate offsets
+ uint64_t patch_addr = (int64_t)data + (buffer_offsets[i]->offset - 0x10000000);
+ uint64_t cur_addr = *(int32_t*)patch_addr;
+
+ uint64_t mem_addr = (uint64_t)new_buffer_addrs[buffer_offsets[i]->type] + (cur_addr - buffer_addrs[buffer_offsets[i]->type]);
+
+ printf("Patching %llx -> %llx @ %llx (%llx - %llx = %llx)\n", cur_addr, mem_addr, buffer_offsets[i]->offset, cur_addr, buffer_addrs[buffer_offsets[i]->type], cur_addr - buffer_addrs[buffer_offsets[i]->type]);
+
+ patch_memory(patch_addr, (char*)&mem_addr, 4);
+ }
+
+ printf("popnhax: patched memory db locations\n");
+
+ if (config.disable_expansions) {
+ printf("Expansion-related code is disabled, buffer size and related patches will not be applied");
+ return true;
+ }
+
+ for (size_t i = 0; i < other_offsets.size(); i++) {
+ // Get current limit so it can be used for later calculations
+ uint32_t cur_limit = limit_table[other_offsets[i]->type];
+ uint32_t limit_diff = cur_limit < new_limit_table[other_offsets[i]->type]
+ ? new_limit_table[other_offsets[i]->type] - cur_limit
+ : 0;
+
+ if (limit_diff != 0)
+ {
+ uint64_t cur_value = 0;
+
+ if (other_offsets[i]->size == 1) {
+ cur_value = *(uint8_t*)(data + (other_offsets[i]->offset - 0x10000000));
+ } else if (other_offsets[i]->size == 2) {
+ cur_value = *(uint16_t*)(data + (other_offsets[i]->offset - 0x10000000));
+ } else if (other_offsets[i]->size == 4) {
+ cur_value = *(uint32_t*)(data + (other_offsets[i]->offset - 0x10000000));
+ } else if (other_offsets[i]->size == 8) {
+ cur_value = *(uint64_t*)(data + (other_offsets[i]->offset - 0x10000000));
+ }
+
+ if (other_offsets[i]->method != 12 && cur_value != other_offsets[i]->expectedValue) {
+ printf("ERROR! Expected %llx, found %llx @ %llx!\n", other_offsets[i]->expectedValue, cur_value, other_offsets[i]->offset);
+ exit(1);
+ }
+
+ uint64_t value = cur_value;
+ uint32_t patch_size = 4;
+ switch (other_offsets[i]->method) {
+ // Add limit_diff to value
+ case 0:
+ value = cur_value + limit_diff;
+ break;
+
+ // Add limit_diff * 4 to value
+ case 1:
+ value = cur_value + (limit_diff * 4);
+ break;
+
+ // Add limit diff * 6 * 4 (number of charts * 4?)
+ case 2:
+ value = cur_value + ((limit_diff * 6) * 4);
+ break;
+
+ // Add limit_diff * 6
+ case 3:
+ value = cur_value + (limit_diff * 6);
+ break;
+
+ // Add limit_diff * 0x90
+ case 4:
+ value = cur_value + (limit_diff * 0x90);
+ break;
+
+ // Add limit_diff * 0x48
+ case 5:
+ value = cur_value + (limit_diff * 0x48);
+ break;
+
+ // Add limit_diff * 0x120
+ case 6:
+ value = cur_value + (limit_diff * 0x120);
+ break;
+
+ // Add limit_diff * 0x440
+ case 7:
+ value = cur_value + (limit_diff * 0x440);
+ break;
+
+ // Add limit_diff * 0x0c
+ case 8:
+ value = cur_value + (limit_diff * 0x0c);
+ break;
+
+ // Add limit_diff * 0x3d0
+ case 9:
+ value = cur_value + (limit_diff * 0x3d0);
+ break;
+
+ // Add (limit_diff * 0x3d0) + (limit_diff * 0x9c)
+ case 10:
+ value = cur_value + (limit_diff * 0x3d0) + (limit_diff * 0x9c);
+ break;
+
+ // Add (limit_diff * 0x3d0) + (limit_diff * 0x9c) + (limit_diff * 0x2a0)
+ case 11:
+ value = cur_value + (limit_diff * 0x3d0) + (limit_diff * 0x9c) + (limit_diff * 0x2a0);
+ break;
+
+ // NOP
+ case 12:
+ value = 0x9090909090909090;
+ patch_size = other_offsets[i]->size;
+ break;
+
+ default:
+ printf("Unknown command: %lld\n", other_offsets[i]->method);
+ break;
+ }
+
+ if (value != cur_value) {
+ uint64_t patch_addr = (int64_t)data + (other_offsets[i]->offset - 0x10000000);
+ patch_memory(patch_addr, (char*)&value, patch_size);
+
+ printf("Patched %llx: %llx -> %llx\n", other_offsets[i]->offset, cur_value, value);
+ }
+ }
+ }
+
+ HMODULE _moduleBase = GetModuleHandle("popn22.dll");
+ for (size_t i = 0; i < hook_offsets.size(); i++) {
+ switch (hook_offsets[i]->method) {
+ case 0: {
+ // Peace hook
+ printf("Hooking %llx %p\n", hook_offsets[i]->offset, _moduleBase);
+ MH_CreateHook((void*)((uint8_t*)_moduleBase + (hook_offsets[i]->offset - 0x10000000)), (void *)&check_music_idx, (void **)&real_check_music_idx);
+ break;
+ }
+
+ case 1: {
+ // Usaneko hook
+ printf("Hooking %llx %p\n", hook_offsets[i]->offset, _moduleBase);
+ uint8_t nops[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
+ patch_memory((uint64_t)((uint8_t*)_moduleBase + (hook_offsets[i]->offset - 0x10000000) - 6), (char *)&nops, 6);
+ MH_CreateHook((void*)((uint8_t*)_moduleBase + (hook_offsets[i]->offset - 0x10000000)), (void *)&check_music_idx_usaneko, (void **)&real_check_music_idx_usaneko);
+ break;
+ }
+
+ default:
+ printf("Unknown hook command: %lld\n", hook_offsets[i]->method);
+ break;
+ }
+ }
+
+ printf("popnhax: patched limit-related code\n");
+
+ return true;
+}
+
+static bool patch_unset_volume() {
+ DWORD dllSize = 0;
+ char *data = getDllData("popn22.dll", &dllSize);
+
+ int64_t first_loc = 0;
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x04\x00\x81\xC4\x00\x01\x00\x00\xC3\xCC", 10)
+
+ first_loc = find_block(data, dllSize, &task, 0);
+ if (first_loc == -1) {
+ return false;
+ }
+ }
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x83", 1)
+
+ int64_t pattern_offset = find_block(data, 0x10, &task, first_loc);
+ if (pattern_offset == -1) {
+ return false;
+ }
+
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ patch_memory(patch_addr, (char *)"\xC3", 1);
+ }
+
+ printf("popnhax: windows volume untouched\n");
+
+ return true;
+}
+
+static bool patch_event_mode() {
+ DWORD dllSize = 0;
+ char *data = getDllData("popn22.dll", &dllSize);
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0,
+ "\x8B\x00\xC3\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC"
+ "\xCC\xCC\xC7",
+ 17)
+
+ int64_t pattern_offset = find_block(data, dllSize, &task, 0);
+ if (pattern_offset == -1) {
+ return false;
+ }
+
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ patch_memory(patch_addr, (char *)"\x31\xC0\x40\xC3", 4);
+ }
+
+ printf("popnhax: event mode forced\n");
+
+ return true;
+}
+
+static bool patch_remove_timer() {
+ DWORD dllSize = 0;
+ char *data = getDllData("popn22.dll", &dllSize);
+
+ int64_t first_loc = 0;
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x8B\xAC\x24\x68\x01", 5)
+
+ first_loc = find_block(data, dllSize, &task, 0);
+ if (first_loc == -1) {
+ return false;
+ }
+ }
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x0F", 1)
+
+ int64_t pattern_offset = find_block(data, 0x15, &task, first_loc);
+ if (pattern_offset == -1) {
+ return false;
+ }
+
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ patch_memory(patch_addr, (char *)"\x90\xE9", 2);
+ }
+
+ printf("popnhax: timer removed\n");
+
+ return true;
+}
+
+static bool patch_freeze_timer() {
+ DWORD dllSize = 0;
+ char *data = getDllData("popn22.dll", &dllSize);
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\xC7\x45\x38\x09\x00\x00\x00", 7)
+
+ int64_t pattern_offset = find_block(data, dllSize, &task, 0);
+ if (pattern_offset == -1) {
+ return false;
+ }
+
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ patch_memory(patch_addr, (char *)"\x90\x90\x90\x90\x90\x90\x90", 7);
+ }
+
+ printf("popnhax: timer frozen at 10 seconds remaining\n");
+
+ return true;
+}
+
+static bool patch_skip_tutorials() {
+ DWORD dllSize = 0;
+ char *data = getDllData("popn22.dll", &dllSize);
+
+ int64_t first_loc = 0;
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\xFD\xFF\x5E\xC2\x04\x00\xE8", 7)
+
+ first_loc = find_block(data, dllSize, &task, 0);
+ if (first_loc == -1) {
+ return false;
+ }
+ }
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x74", 1)
+
+ int64_t pattern_offset = find_block(data, 0x10, &task, first_loc);
+ if (pattern_offset == -1) {
+ return false;
+ }
+
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ patch_memory(patch_addr, (char *)"\xEB", 1);
+ }
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x66\x85\xC0\x75\x5E\x6A", 6)
+
+ int64_t pattern_offset = find_block(data, dllSize, &task, 0);
+ if (pattern_offset == -1) {
+ return false;
+ }
+
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ patch_memory(patch_addr, (char *)"\x66\x85\xC0\xEB\x5E\x6A", 6);
+ }
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x00\x5F\x5E\x66\x83\xF8\x01\x75", 8)
+
+ int64_t pattern_offset = find_block(data, dllSize, &task, 0);
+ if (pattern_offset == -1) {
+ return false;
+ }
+
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ patch_memory(patch_addr, (char *)"\x00\x5F\x5E\x66\x83\xF8\x01\xEB", 8);
+ }
+
+ printf("popnhax: menu and long note tutorials skipped\n");
+
+ return true;
+}
+
+bool force_unlock_deco_parts() {
+ DWORD dllSize = 0;
+ char *data = getDllData("popn22.dll", &dllSize);
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x83\xC4\x04\x83\x38\x00\x75\x22", 8)
+
+ int64_t pattern_offset = find_block(data, dllSize, &task, 0);
+ if (pattern_offset == -1) {
+ printf("popnhax: couldn't unlock deco parts\n");
+ return false;
+ }
+
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ patch_memory(patch_addr, (char *)"\x83\xC4\x04\x83\x38\x00\x90\x90", 8);
+ }
+
+ printf("popnhax: unlocked deco parts\n");
+
+ return true;
+}
+
+bool force_unlock_songs() {
+ DWORD dllSize = 0;
+ char *data = getDllData("popn22.dll", &dllSize);
+
+ int music_unlocks = 0, chart_unlocks = 0;
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x69\xC0\xAC\x00\x00\x00\x8B\x80", 8) // 0xac here is the size of music_entry. May change in the future
+
+ int64_t pattern_offset = find_block(data, dllSize, &task, 0);
+ if (pattern_offset == -1) {
+ printf("popnhax: couldn't unlock songs and charts\n");
+ return false;
+ }
+
+ uint32_t buffer_offset = *(uint32_t*)((int64_t)data + pattern_offset + task.blocks[0].data[0].length);
+ buffer_offset -= 0x1c; // The difference between music_entry.mask and music_entry.fw_genre_ptr to put it at the beginning of the entry
+ music_entry *entry = (music_entry*)buffer_offset;
+
+ for (int32_t i = 0; ; i++) {
+ // Detect end of table
+ // Kind of iffy but I think it should work
+ if (entry->charts[6] != 0 && entry->hold_flags[7] != 0) {
+ // These should *probably* always be 0 but won't be after the table ends
+ break;
+ }
+
+ if ((entry->mask & 0x08000000) != 0) {
+ printf("[%04d] Unlocking %s\n", i, entry->title_ptr);
+ music_unlocks++;
+ }
+
+ if ((entry->mask & 0x00000080) != 0) {
+ printf("[%04d] Unlocking charts for %s\n", i, entry->title_ptr);
+ chart_unlocks++;
+ }
+
+ if ((entry->mask & 0x08000080) != 0) {
+ uint32_t new_mask = entry->mask & ~0x08000080;
+ patch_memory((uint64_t)&entry->mask, (char *)&new_mask, 4);
+ }
+
+ entry++; // Move to the next music entry
+ }
+ }
+
+ printf("popnhax: unlocked %d songs and %d charts\n", music_unlocks, chart_unlocks);
+
+ return true;
+}
+
+bool force_unlock_charas() {
+ DWORD dllSize = 0;
+ char *data = getDllData("popn22.dll", &dllSize);
+
+ int chara_unlocks = 0;
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x98\x6B\xC0\x4C\x8B\x80", 6) // 0x4c here is the size of character_entry. May change in the future
+
+ int64_t pattern_offset = find_block(data, dllSize, &task, 0);
+ if (pattern_offset == -1) {
+ printf("popnhax: couldn't unlock characters\n");
+ return false;
+ }
+
+ uint32_t buffer_offset = *(uint32_t*)((int64_t)data + pattern_offset + task.blocks[0].data[0].length);
+ buffer_offset -= 0x48; // The difference between character_entry.game_version and character_entry.chara_id_ptr to put it at the beginning of the entry
+ character_entry *entry = (character_entry*)buffer_offset;
+
+ for (int32_t i = 0; ; i++) {
+ // Detect end of table
+ // Kind of iffy but I think it should work
+ if (entry->_pad1[0] != 0 || entry->_pad2[0] != 0 || entry->_pad2[1] != 0 || entry->_pad2[2] != 0) {
+ // These should *probably* always be 0 but won't be after the table ends
+ break;
+ }
+
+ uint32_t new_flags = entry->flags & ~3;
+
+ if (new_flags != entry->flags && entry->disp_name_ptr != NULL && strlen((char*)entry->disp_name_ptr) > 0) {
+ printf("Unlocking [%04d] %s... %08x -> %08x\n", i, entry->disp_name_ptr, entry->flags, new_flags);
+ patch_memory((uint64_t)&entry->flags, (char *)&new_flags, sizeof(uint32_t));
+
+ if ((entry->flavor_idx == 0 || entry->flavor_idx == -1)) {
+ int flavor_idx = 1;
+ patch_memory((uint64_t)&entry->flavor_idx, (char *)&flavor_idx, sizeof(uint32_t));
+ printf("Setting default flavor for chara id %d\n", i);
+ }
+
+ chara_unlocks++;
+ }
+
+ entry++; // Move to the next character entry
+ }
+ }
+
+ printf("popnhax: unlocked %d characters\n", chara_unlocks);
+
+ return true;
+}
+
+static bool patch_unlocks_offline() {
+ DWORD dllSize = 0;
+ char *data = getDllData("popn22.dll", &dllSize);
+
+ int64_t first_loc = 0;
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x8B\xE5\x5D\xC2\x04\x00\xC3", 7)
+
+ first_loc = find_block(data, dllSize, &task, 0);
+ if (first_loc == -1) {
+ printf("Couldn't find unlock loc 1\n");
+ return false;
+ }
+ }
+
+ int64_t second_loc = 0;
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x00\x00\x50\x8B", 4)
+
+ second_loc = find_block(data, 0x50, &task, first_loc);
+ if (first_loc == -1) {
+ printf("Couldn't find unlock loc 2\n");
+ return false;
+ }
+ }
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\x00\x00\x84\xC0\x74", 5)
+
+ int64_t pattern_offset = find_block(data, 0x10, &task, second_loc);
+ if (pattern_offset == -1) {
+ printf("Couldn't find first song unlock\n");
+ return false;
+ }
+
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ patch_memory(patch_addr, (char *)"\x00\x00\x84\xC0\x90\x90", 6);
+ }
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\xFF\xFF\xA9\x06\x00\x00\x68\x74", 8)
+
+ int64_t pattern_offset = find_block(data, 0xDD, &task, second_loc);
+ if (pattern_offset == -1) {
+ printf("Couldn't find second song unlock\n");
+ return false;
+ }
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ patch_memory(patch_addr, (char *)"\xFF\xFF\xA9\x06\x00\x00\x68\xEB", 8);
+
+ printf("popnhax: songs unlocked for offline\n");
+ }
+
+ {
+ fuzzy_search_task task;
+
+ FUZZY_START(task, 1)
+ FUZZY_CODE(task, 0, "\xA9\x50\x01\x00\x00\x74", 6)
+
+ int64_t pattern_offset = find_block_back(data, 0x50000, &task, second_loc);
+ if (pattern_offset == -1) {
+ printf("Couldn't find character unlock\n");
+ return false;
+ }
+ uint64_t patch_addr = (int64_t)data + pattern_offset;
+ patch_memory(patch_addr, (char *)"\xA9\x50\x01\x00\x00\xEB", 6);
+
+ printf("popnhax: characters unlocked for offline\n");
+ }
+
+ return true;
+}
+
+BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
+ switch (ul_reason_for_call) {
+ case DLL_PROCESS_ATTACH: {
+ if (MH_Initialize() != MH_OK) {
+ printf("Failed to initialize minhook\n");
+ exit(1);
+ return TRUE;
+ }
+
+ _load_config("popnhax.xml", &config, config_psmap);
+
+ if (config.unset_volume) {
+ patch_unset_volume();
+ }
+
+ if (config.event_mode) {
+ patch_event_mode();
+ }
+
+ if (config.remove_timer) {
+ patch_remove_timer();
+ }
+
+ if (config.freeze_timer) {
+ patch_freeze_timer();
+ }
+
+ if (config.skip_tutorials) {
+ patch_skip_tutorials();
+ }
+
+ if (config.patch_db) {
+ patch_database(config.force_unlocks);
+ }
+
+ if (config.force_unlocks) {
+ if (!config.patch_db) {
+ // Only unlock using these methods if it's not done directly through the database hooks
+ force_unlock_songs();
+ force_unlock_charas();
+ }
+
+ patch_unlocks_offline();
+ force_unlock_deco_parts();
+ }
+
+ MH_EnableHook(MH_ALL_HOOKS);
+
+ break;
+ }
+
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+
+ return TRUE;
+}
diff --git a/popnhax/loader.cc b/popnhax/loader.cc
new file mode 100644
index 0000000..ae5e924
--- /dev/null
+++ b/popnhax/loader.cc
@@ -0,0 +1,1282 @@
+#include
+#include
+#include
+#include
+
+#include "imports/avs.h"
+#include "util/patch.h"
+#include "xmlhelper.h"
+
+#include "tableinfo.h"
+#include "loader.h"
+#include
+#include