├── .gitignore
├── build
├── DLL-Loader.sln
├── DLL-Loader.vcxproj
└── DLL-Loader.vcxproj.filters
└── src
├── Config_Control.h
├── Logger.cpp
├── Logger.h
├── main.cpp
├── main.h
├── minhook
├── include
│ └── MinHook.h
└── src
│ ├── buffer.c
│ ├── buffer.h
│ ├── hde
│ ├── hde32.c
│ ├── hde32.h
│ ├── hde64.c
│ ├── hde64.h
│ ├── pstdint.h
│ ├── table32.h
│ └── table64.h
│ ├── hook.c
│ ├── trampoline.c
│ └── trampoline.h
└── shim
├── avifil32.cpp
├── avifil32.def
└── avifil32_impl.asm
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Visual Studio ###
2 |
3 | # User-specific files
4 | *.suo
5 | *.user
6 | *.userosscache
7 | *.sln.docstates
8 |
9 | # User-specific files
10 | *.userprefs
11 |
12 | # Build results
13 | [Dd]ebug/
14 | [Dd]ebugPublic/
15 | [Rr]elease/
16 | [Rr]eleases/
17 | x64/
18 | x86/
19 | bld/
20 | [Bb]in/
21 | [Oo]bj/
22 | [Ll]og/
23 |
24 | # Visual Studio 2015 cache/options directory
25 | .vs/
26 |
27 | *_i.c
28 | *_p.c
29 | *_i.h
30 | *.ilk
31 | *.meta
32 | *.obj
33 | *.pch
34 | *.pdb
35 | *.pgc
36 | *.pgd
37 | *.rsp
38 | *.sbr
39 | *.tlb
40 | *.tli
41 | *.tlh
42 | *.tmp
43 | *.tmp_proj
44 | *.log
45 | *.vspscc
46 | *.vssscc
47 | .builds
48 | *.pidb
49 | *.svclog
50 | *.scc
51 |
52 | # Visual C++ cache files
53 | ipch/
54 | *.aps
55 | *.ncb
56 | *.opendb
57 | *.opensdf
58 | *.sdf
59 | *.cachefile
60 | *.VC.db
61 | *.VC.VC.opendb
62 |
63 | # Visual Studio cache files
64 | # files ending in .cache can be ignored
65 | *.[Cc]ache
66 | # but keep track of directories ending in .cache
67 | !*.[Cc]ache/
68 |
--------------------------------------------------------------------------------
/build/DLL-Loader.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2042
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLL-Loader", "DLL-Loader.vcxproj", "{F17AA248-2384-4B49-B4BB-29CB512751DB}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Release|x64 = Release|x64
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {F17AA248-2384-4B49-B4BB-29CB512751DB}.Debug|x64.ActiveCfg = Debug|x64
15 | {F17AA248-2384-4B49-B4BB-29CB512751DB}.Debug|x64.Build.0 = Debug|x64
16 | {F17AA248-2384-4B49-B4BB-29CB512751DB}.Release|x64.ActiveCfg = Release|x64
17 | {F17AA248-2384-4B49-B4BB-29CB512751DB}.Release|x64.Build.0 = Release|x64
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {88A54DFE-B209-42DA-B8E1-970D396E7329}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/build/DLL-Loader.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 15.0
23 | {F17AA248-2384-4B49-B4BB-29CB512751DB}
24 | Win32Proj
25 | DLLLoader
26 | 10.0.17134.0
27 |
28 |
29 |
30 | DynamicLibrary
31 | true
32 | v141
33 | Unicode
34 |
35 |
36 | DynamicLibrary
37 | false
38 | v141
39 | true
40 | Unicode
41 |
42 |
43 | DynamicLibrary
44 | true
45 | v141
46 | Unicode
47 |
48 |
49 | DynamicLibrary
50 | false
51 | v141
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | true
76 | avifil32
77 |
78 |
79 | true
80 | avifil32
81 |
82 |
83 | false
84 | avifil32
85 |
86 |
87 | false
88 | avifil32
89 |
90 |
91 |
92 | Level3
93 | Disabled
94 | WIN32;_DEBUG;DLLLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
95 | true
96 |
97 |
98 | true
99 | Windows
100 | ../src/shim/avifil32.def
101 |
102 |
103 |
104 |
105 | Level3
106 | Disabled
107 | _DEBUG;DLLLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
108 | true
109 |
110 |
111 | true
112 | Windows
113 | ../src/shim/avifil32.def
114 |
115 |
116 |
117 |
118 | Level3
119 | MaxSpeed
120 | true
121 | true
122 | WIN32;NDEBUG;DLLLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
123 | true
124 |
125 |
126 | true
127 | true
128 | true
129 | Windows
130 | ../src/shim/avifil32.def
131 |
132 |
133 |
134 |
135 | Level3
136 | MaxSpeed
137 | true
138 | true
139 | NDEBUG;DLLLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
140 | true
141 |
142 |
143 | true
144 | true
145 | true
146 | Windows
147 | ../src/shim/avifil32.def
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
--------------------------------------------------------------------------------
/build/DLL-Loader.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {6a9546d3-e29d-4366-b5e0-c88093922e64}
18 |
19 |
20 | {77392aa3-e57b-4761-bf0a-56fb1689a5b9}
21 |
22 |
23 | {e42e6eaf-e4e8-4277-b764-fb4d0c55759c}
24 |
25 |
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 | minhook\hde
35 |
36 |
37 | minhook\hde
38 |
39 |
40 | minhook
41 |
42 |
43 | minhook
44 |
45 |
46 | minhook
47 |
48 |
49 | shim
50 |
51 |
52 |
53 |
54 | Header Files
55 |
56 |
57 | Header Files
58 |
59 |
60 | minhook\hde
61 |
62 |
63 | minhook\hde
64 |
65 |
66 | minhook\hde
67 |
68 |
69 | minhook\hde
70 |
71 |
72 | minhook\hde
73 |
74 |
75 | minhook
76 |
77 |
78 | minhook
79 |
80 |
81 | minhook
82 |
83 |
84 | Header Files
85 |
86 |
87 |
88 |
89 | shim
90 |
91 |
92 |
93 |
94 | shim
95 |
96 |
97 |
--------------------------------------------------------------------------------
/src/Config_Control.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | //-----------------------
4 | // Module Information
5 | //-----------------------
6 | #define MODULE_VERSION_STRING "1.0"
7 | #define MODULE_NAME_LONG "Control Plugin Loader"
8 |
9 | //-----------------------
10 | // Configuration
11 | //-----------------------
12 | const char* PLUGINS_DIR = "plugins";
13 | const char* LOG_PATH = "%LOCALAPPDATA%\\Remedy\\Control\\PluginLoader.log";
14 |
--------------------------------------------------------------------------------
/src/Logger.cpp:
--------------------------------------------------------------------------------
1 | #include "Logger.h"
2 | #include
3 | #include
4 | #include
5 |
6 | FILE* logfile = nullptr;
7 |
8 | Logger::Logger()
9 | {
10 | }
11 |
12 | Logger::~Logger()
13 | {
14 | }
15 |
16 | bool Logger::Open(const char * path)
17 | {
18 | logfile = _fsopen(path, "w", _SH_DENYWR);
19 | return logfile != NULL;
20 | }
21 |
22 | void Logger::Close()
23 | {
24 | if (logfile) fclose(logfile);
25 | }
26 |
27 | void Logger::Log(const char * format, ...)
28 | {
29 | static char outputBuf[8192];
30 | if (logfile) {
31 | va_list args; va_start(args, format);
32 | vsnprintf(outputBuf, sizeof(outputBuf), format, args);
33 | va_end(args);
34 | fprintf(logfile, "%s\n", outputBuf);
35 | fflush(logfile);
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/src/Logger.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | class Logger
3 | {
4 | public:
5 | Logger();
6 | ~Logger();
7 |
8 | static bool Open(const char* path);
9 | static void Close();
10 |
11 | static void Log(const char* format, ...);
12 | };
13 |
14 | extern Logger g_logger;
15 |
16 | #define _LOG(...) g_logger.Log(__VA_ARGS__)
17 |
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | DLL Loader by reg2k
3 | Plugins are loaded on entry into the process entry point.
4 | This ensures all linked libraries have already been loaded when plugins are initialized.
5 | */
6 | #include "main.h"
7 |
8 | #define WIN32_LEAN_AND_MEAN
9 | #include
10 | #include
11 | #include
12 |
13 | #include "Config_Control.h"
14 | #include "Logger.h"
15 | #include "minhook/include/MinHook.h"
16 |
17 | static Logger g_logger;
18 |
19 | namespace DLL_Loader {
20 | // Hooks
21 | int (*EntryPoint_Original)(void) = nullptr;
22 |
23 | void LoadDLL(const std::string& pluginName) {
24 | char pluginPath[MAX_PATH];
25 | snprintf(pluginPath, MAX_PATH, "%s\\%s", PLUGINS_DIR, pluginName.c_str());
26 |
27 | _LOG("Loading plugin: %s", pluginName.c_str());
28 | HMODULE hMod = LoadLibraryA(pluginPath);
29 | if (!hMod) {
30 | _LOG("> Failed to load plugin. Error code: 0x%X.", GetLastError());
31 | }
32 | }
33 |
34 | // Given a directory, returns the list of files in it.
35 | std::vector GetFileList(const char* dir, const char* pattern = "*") {
36 | std::vector fileList;
37 | HANDLE hFind;
38 | WIN32_FIND_DATAA findData;
39 |
40 | char findStr[MAX_PATH];
41 | snprintf(findStr, MAX_PATH, "%s\\%s", dir, pattern);
42 |
43 | hFind = FindFirstFileA(findStr, &findData);
44 | if (hFind != INVALID_HANDLE_VALUE) {
45 | do {
46 | if (!strcmp(findData.cFileName, ".") || !strcmp(findData.cFileName, "..")) continue;
47 | if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
48 |
49 | fileList.emplace_back(findData.cFileName);
50 |
51 | } while (FindNextFileA(hFind, &findData));
52 | FindClose(hFind);
53 | }
54 | return fileList;
55 | }
56 |
57 | int EntryPoint_Hook() {
58 | // Get all DLLs in folder
59 | auto pluginList = GetFileList(PLUGINS_DIR, "*.dll");
60 | _LOG("Number of installed plugins: %d", pluginList.size());
61 |
62 | // Load plugins
63 | for (auto const& pluginName : pluginList) {
64 | LoadDLL(pluginName);
65 | }
66 |
67 | return EntryPoint_Original();
68 | }
69 | }
70 |
71 | void start() {
72 | using namespace DLL_Loader;
73 |
74 | // Initialize logger
75 | char szLogPath[MAX_PATH] = "";
76 | ExpandEnvironmentStringsA(LOG_PATH, szLogPath, sizeof(szLogPath));
77 | g_logger.Open(szLogPath);
78 | _LOG("%s v%s by reg2k", MODULE_NAME_LONG, MODULE_VERSION_STRING);
79 |
80 | // Get process entry point
81 | HMODULE hMod = GetModuleHandleA(NULL);
82 | IMAGE_DOS_HEADER* pDOSHeader = reinterpret_cast(hMod);
83 | IMAGE_NT_HEADERS* pNTHeaders = reinterpret_cast((char*)pDOSHeader + pDOSHeader->e_lfanew);
84 | DWORD entryPointRVA = pNTHeaders->OptionalHeader.AddressOfEntryPoint;
85 | void* entryPoint = (char*)hMod + entryPointRVA;
86 | _LOG("Module base: %p", hMod);
87 | _LOG("Process entry point at %p", entryPoint);
88 |
89 | // Hook entry point
90 | MH_Initialize();
91 | MH_CreateHook(entryPoint, EntryPoint_Hook, reinterpret_cast(&EntryPoint_Original));
92 | if (MH_EnableHook(entryPoint) != MH_OK) {
93 | _LOG("FATAL: Failed to install entry point hook.");
94 | return;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | void start();
--------------------------------------------------------------------------------
/src/minhook/include/MinHook.h:
--------------------------------------------------------------------------------
1 | /*
2 | * MinHook - The Minimalistic API Hooking Library for x64/x86
3 | * Copyright (C) 2009-2017 Tsuda Kageyu.
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | *
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | #pragma once
30 |
31 | #if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
32 | #error MinHook supports only x86 and x64 systems.
33 | #endif
34 |
35 | #include
36 |
37 | // MinHook Error Codes.
38 | typedef enum MH_STATUS
39 | {
40 | // Unknown error. Should not be returned.
41 | MH_UNKNOWN = -1,
42 |
43 | // Successful.
44 | MH_OK = 0,
45 |
46 | // MinHook is already initialized.
47 | MH_ERROR_ALREADY_INITIALIZED,
48 |
49 | // MinHook is not initialized yet, or already uninitialized.
50 | MH_ERROR_NOT_INITIALIZED,
51 |
52 | // The hook for the specified target function is already created.
53 | MH_ERROR_ALREADY_CREATED,
54 |
55 | // The hook for the specified target function is not created yet.
56 | MH_ERROR_NOT_CREATED,
57 |
58 | // The hook for the specified target function is already enabled.
59 | MH_ERROR_ENABLED,
60 |
61 | // The hook for the specified target function is not enabled yet, or already
62 | // disabled.
63 | MH_ERROR_DISABLED,
64 |
65 | // The specified pointer is invalid. It points the address of non-allocated
66 | // and/or non-executable region.
67 | MH_ERROR_NOT_EXECUTABLE,
68 |
69 | // The specified target function cannot be hooked.
70 | MH_ERROR_UNSUPPORTED_FUNCTION,
71 |
72 | // Failed to allocate memory.
73 | MH_ERROR_MEMORY_ALLOC,
74 |
75 | // Failed to change the memory protection.
76 | MH_ERROR_MEMORY_PROTECT,
77 |
78 | // The specified module is not loaded.
79 | MH_ERROR_MODULE_NOT_FOUND,
80 |
81 | // The specified function is not found.
82 | MH_ERROR_FUNCTION_NOT_FOUND
83 | }
84 | MH_STATUS;
85 |
86 | // Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
87 | // MH_QueueEnableHook or MH_QueueDisableHook.
88 | #define MH_ALL_HOOKS NULL
89 |
90 | #ifdef __cplusplus
91 | extern "C" {
92 | #endif
93 |
94 | // Initialize the MinHook library. You must call this function EXACTLY ONCE
95 | // at the beginning of your program.
96 | MH_STATUS WINAPI MH_Initialize(VOID);
97 |
98 | // Uninitialize the MinHook library. You must call this function EXACTLY
99 | // ONCE at the end of your program.
100 | MH_STATUS WINAPI MH_Uninitialize(VOID);
101 |
102 | // Creates a Hook for the specified target function, in disabled state.
103 | // Parameters:
104 | // pTarget [in] A pointer to the target function, which will be
105 | // overridden by the detour function.
106 | // pDetour [in] A pointer to the detour function, which will override
107 | // the target function.
108 | // ppOriginal [out] A pointer to the trampoline function, which will be
109 | // used to call the original target function.
110 | // This parameter can be NULL.
111 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
112 |
113 | // Creates a Hook for the specified API function, in disabled state.
114 | // Parameters:
115 | // pszModule [in] A pointer to the loaded module name which contains the
116 | // target function.
117 | // pszTarget [in] A pointer to the target function name, which will be
118 | // overridden by the detour function.
119 | // pDetour [in] A pointer to the detour function, which will override
120 | // the target function.
121 | // ppOriginal [out] A pointer to the trampoline function, which will be
122 | // used to call the original target function.
123 | // This parameter can be NULL.
124 | MH_STATUS WINAPI MH_CreateHookApi(
125 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
126 |
127 | // Creates a Hook for the specified API function, in disabled state.
128 | // Parameters:
129 | // pszModule [in] A pointer to the loaded module name which contains the
130 | // target function.
131 | // pszTarget [in] A pointer to the target function name, which will be
132 | // overridden by the detour function.
133 | // pDetour [in] A pointer to the detour function, which will override
134 | // the target function.
135 | // ppOriginal [out] A pointer to the trampoline function, which will be
136 | // used to call the original target function.
137 | // This parameter can be NULL.
138 | // ppTarget [out] A pointer to the target function, which will be used
139 | // with other functions.
140 | // This parameter can be NULL.
141 | MH_STATUS WINAPI MH_CreateHookApiEx(
142 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
143 |
144 | // Removes an already created hook.
145 | // Parameters:
146 | // pTarget [in] A pointer to the target function.
147 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
148 |
149 | // Enables an already created hook.
150 | // Parameters:
151 | // pTarget [in] A pointer to the target function.
152 | // If this parameter is MH_ALL_HOOKS, all created hooks are
153 | // enabled in one go.
154 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
155 |
156 | // Disables an already created hook.
157 | // Parameters:
158 | // pTarget [in] A pointer to the target function.
159 | // If this parameter is MH_ALL_HOOKS, all created hooks are
160 | // disabled in one go.
161 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
162 |
163 | // Queues to enable an already created hook.
164 | // Parameters:
165 | // pTarget [in] A pointer to the target function.
166 | // If this parameter is MH_ALL_HOOKS, all created hooks are
167 | // queued to be enabled.
168 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
169 |
170 | // Queues to disable an already created hook.
171 | // Parameters:
172 | // pTarget [in] A pointer to the target function.
173 | // If this parameter is MH_ALL_HOOKS, all created hooks are
174 | // queued to be disabled.
175 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
176 |
177 | // Applies all queued changes in one go.
178 | MH_STATUS WINAPI MH_ApplyQueued(VOID);
179 |
180 | // Translates the MH_STATUS to its name as a string.
181 | const char * WINAPI MH_StatusToString(MH_STATUS status);
182 |
183 | #ifdef __cplusplus
184 | }
185 | #endif
186 |
187 |
--------------------------------------------------------------------------------
/src/minhook/src/buffer.c:
--------------------------------------------------------------------------------
1 | /*
2 | * MinHook - The Minimalistic API Hooking Library for x64/x86
3 | * Copyright (C) 2009-2017 Tsuda Kageyu.
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | *
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | #include
30 | #include "buffer.h"
31 |
32 | // Size of each memory block. (= page size of VirtualAlloc)
33 | #define MEMORY_BLOCK_SIZE 0x1000
34 |
35 | // Max range for seeking a memory block. (= 1024MB)
36 | #define MAX_MEMORY_RANGE 0x40000000
37 |
38 | // Memory protection flags to check the executable address.
39 | #define PAGE_EXECUTE_FLAGS \
40 | (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
41 |
42 | // Memory slot.
43 | typedef struct _MEMORY_SLOT
44 | {
45 | union
46 | {
47 | struct _MEMORY_SLOT *pNext;
48 | UINT8 buffer[MEMORY_SLOT_SIZE];
49 | };
50 | } MEMORY_SLOT, *PMEMORY_SLOT;
51 |
52 | // Memory block info. Placed at the head of each block.
53 | typedef struct _MEMORY_BLOCK
54 | {
55 | struct _MEMORY_BLOCK *pNext;
56 | PMEMORY_SLOT pFree; // First element of the free slot list.
57 | UINT usedCount;
58 | } MEMORY_BLOCK, *PMEMORY_BLOCK;
59 |
60 | //-------------------------------------------------------------------------
61 | // Global Variables:
62 | //-------------------------------------------------------------------------
63 |
64 | // First element of the memory block list.
65 | PMEMORY_BLOCK g_pMemoryBlocks;
66 |
67 | //-------------------------------------------------------------------------
68 | VOID InitializeBuffer(VOID)
69 | {
70 | // Nothing to do for now.
71 | }
72 |
73 | //-------------------------------------------------------------------------
74 | VOID UninitializeBuffer(VOID)
75 | {
76 | PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
77 | g_pMemoryBlocks = NULL;
78 |
79 | while (pBlock)
80 | {
81 | PMEMORY_BLOCK pNext = pBlock->pNext;
82 | VirtualFree(pBlock, 0, MEM_RELEASE);
83 | pBlock = pNext;
84 | }
85 | }
86 |
87 | //-------------------------------------------------------------------------
88 | #if defined(_M_X64) || defined(__x86_64__)
89 | static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity)
90 | {
91 | ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
92 |
93 | // Round down to the allocation granularity.
94 | tryAddr -= tryAddr % dwAllocationGranularity;
95 |
96 | // Start from the previous allocation granularity multiply.
97 | tryAddr -= dwAllocationGranularity;
98 |
99 | while (tryAddr >= (ULONG_PTR)pMinAddr)
100 | {
101 | MEMORY_BASIC_INFORMATION mbi;
102 | if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
103 | break;
104 |
105 | if (mbi.State == MEM_FREE)
106 | return (LPVOID)tryAddr;
107 |
108 | if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity)
109 | break;
110 |
111 | tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity;
112 | }
113 |
114 | return NULL;
115 | }
116 | #endif
117 |
118 | //-------------------------------------------------------------------------
119 | #if defined(_M_X64) || defined(__x86_64__)
120 | static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity)
121 | {
122 | ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
123 |
124 | // Round down to the allocation granularity.
125 | tryAddr -= tryAddr % dwAllocationGranularity;
126 |
127 | // Start from the next allocation granularity multiply.
128 | tryAddr += dwAllocationGranularity;
129 |
130 | while (tryAddr <= (ULONG_PTR)pMaxAddr)
131 | {
132 | MEMORY_BASIC_INFORMATION mbi;
133 | if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
134 | break;
135 |
136 | if (mbi.State == MEM_FREE)
137 | return (LPVOID)tryAddr;
138 |
139 | tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;
140 |
141 | // Round up to the next allocation granularity.
142 | tryAddr += dwAllocationGranularity - 1;
143 | tryAddr -= tryAddr % dwAllocationGranularity;
144 | }
145 |
146 | return NULL;
147 | }
148 | #endif
149 |
150 | //-------------------------------------------------------------------------
151 | static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)
152 | {
153 | PMEMORY_BLOCK pBlock;
154 | #if defined(_M_X64) || defined(__x86_64__)
155 | ULONG_PTR minAddr;
156 | ULONG_PTR maxAddr;
157 |
158 | SYSTEM_INFO si;
159 | GetSystemInfo(&si);
160 | minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress;
161 | maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress;
162 |
163 | // pOrigin ± 512MB
164 | if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE)
165 | minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE;
166 |
167 | if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE)
168 | maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE;
169 |
170 | // Make room for MEMORY_BLOCK_SIZE bytes.
171 | maxAddr -= MEMORY_BLOCK_SIZE - 1;
172 | #endif
173 |
174 | // Look the registered blocks for a reachable one.
175 | for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext)
176 | {
177 | #if defined(_M_X64) || defined(__x86_64__)
178 | // Ignore the blocks too far.
179 | if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr)
180 | continue;
181 | #endif
182 | // The block has at least one unused slot.
183 | if (pBlock->pFree != NULL)
184 | return pBlock;
185 | }
186 |
187 | #if defined(_M_X64) || defined(__x86_64__)
188 | // Alloc a new block above if not found.
189 | {
190 | LPVOID pAlloc = pOrigin;
191 | while ((ULONG_PTR)pAlloc >= minAddr)
192 | {
193 | pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity);
194 | if (pAlloc == NULL)
195 | break;
196 |
197 | pBlock = (PMEMORY_BLOCK)VirtualAlloc(
198 | pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
199 | if (pBlock != NULL)
200 | break;
201 | }
202 | }
203 |
204 | // Alloc a new block below if not found.
205 | if (pBlock == NULL)
206 | {
207 | LPVOID pAlloc = pOrigin;
208 | while ((ULONG_PTR)pAlloc <= maxAddr)
209 | {
210 | pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity);
211 | if (pAlloc == NULL)
212 | break;
213 |
214 | pBlock = (PMEMORY_BLOCK)VirtualAlloc(
215 | pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
216 | if (pBlock != NULL)
217 | break;
218 | }
219 | }
220 | #else
221 | // In x86 mode, a memory block can be placed anywhere.
222 | pBlock = (PMEMORY_BLOCK)VirtualAlloc(
223 | NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
224 | #endif
225 |
226 | if (pBlock != NULL)
227 | {
228 | // Build a linked list of all the slots.
229 | PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1;
230 | pBlock->pFree = NULL;
231 | pBlock->usedCount = 0;
232 | do
233 | {
234 | pSlot->pNext = pBlock->pFree;
235 | pBlock->pFree = pSlot;
236 | pSlot++;
237 | } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE);
238 |
239 | pBlock->pNext = g_pMemoryBlocks;
240 | g_pMemoryBlocks = pBlock;
241 | }
242 |
243 | return pBlock;
244 | }
245 |
246 | //-------------------------------------------------------------------------
247 | LPVOID AllocateBuffer(LPVOID pOrigin)
248 | {
249 | PMEMORY_SLOT pSlot;
250 | PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin);
251 | if (pBlock == NULL)
252 | return NULL;
253 |
254 | // Remove an unused slot from the list.
255 | pSlot = pBlock->pFree;
256 | pBlock->pFree = pSlot->pNext;
257 | pBlock->usedCount++;
258 | #ifdef _DEBUG
259 | // Fill the slot with INT3 for debugging.
260 | memset(pSlot, 0xCC, sizeof(MEMORY_SLOT));
261 | #endif
262 | return pSlot;
263 | }
264 |
265 | //-------------------------------------------------------------------------
266 | VOID FreeBuffer(LPVOID pBuffer)
267 | {
268 | PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
269 | PMEMORY_BLOCK pPrev = NULL;
270 | ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE;
271 |
272 | while (pBlock != NULL)
273 | {
274 | if ((ULONG_PTR)pBlock == pTargetBlock)
275 | {
276 | PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer;
277 | #ifdef _DEBUG
278 | // Clear the released slot for debugging.
279 | memset(pSlot, 0x00, sizeof(*pSlot));
280 | #endif
281 | // Restore the released slot to the list.
282 | pSlot->pNext = pBlock->pFree;
283 | pBlock->pFree = pSlot;
284 | pBlock->usedCount--;
285 |
286 | // Free if unused.
287 | if (pBlock->usedCount == 0)
288 | {
289 | if (pPrev)
290 | pPrev->pNext = pBlock->pNext;
291 | else
292 | g_pMemoryBlocks = pBlock->pNext;
293 |
294 | VirtualFree(pBlock, 0, MEM_RELEASE);
295 | }
296 |
297 | break;
298 | }
299 |
300 | pPrev = pBlock;
301 | pBlock = pBlock->pNext;
302 | }
303 | }
304 |
305 | //-------------------------------------------------------------------------
306 | BOOL IsExecutableAddress(LPVOID pAddress)
307 | {
308 | MEMORY_BASIC_INFORMATION mi;
309 | VirtualQuery(pAddress, &mi, sizeof(mi));
310 |
311 | return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS));
312 | }
313 |
--------------------------------------------------------------------------------
/src/minhook/src/buffer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * MinHook - The Minimalistic API Hooking Library for x64/x86
3 | * Copyright (C) 2009-2017 Tsuda Kageyu.
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | *
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | #pragma once
30 |
31 | // Size of each memory slot.
32 | #if defined(_M_X64) || defined(__x86_64__)
33 | #define MEMORY_SLOT_SIZE 64
34 | #else
35 | #define MEMORY_SLOT_SIZE 32
36 | #endif
37 |
38 | VOID InitializeBuffer(VOID);
39 | VOID UninitializeBuffer(VOID);
40 | LPVOID AllocateBuffer(LPVOID pOrigin);
41 | VOID FreeBuffer(LPVOID pBuffer);
42 | BOOL IsExecutableAddress(LPVOID pAddress);
43 |
--------------------------------------------------------------------------------
/src/minhook/src/hde/hde32.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Hacker Disassembler Engine 32 C
3 | * Copyright (c) 2008-2009, Vyacheslav Patkov.
4 | * All rights reserved.
5 | *
6 | */
7 |
8 | #if defined(_M_IX86) || defined(__i386__)
9 |
10 | #include "hde32.h"
11 | #include "table32.h"
12 |
13 | unsigned int hde32_disasm(const void *code, hde32s *hs)
14 | {
15 | uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
16 | uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0;
17 |
18 | // Avoid using memset to reduce the footprint.
19 | #ifndef _MSC_VER
20 | memset((LPBYTE)hs, 0, sizeof(hde32s));
21 | #else
22 | __stosb((LPBYTE)hs, 0, sizeof(hde32s));
23 | #endif
24 |
25 | for (x = 16; x; x--)
26 | switch (c = *p++) {
27 | case 0xf3:
28 | hs->p_rep = c;
29 | pref |= PRE_F3;
30 | break;
31 | case 0xf2:
32 | hs->p_rep = c;
33 | pref |= PRE_F2;
34 | break;
35 | case 0xf0:
36 | hs->p_lock = c;
37 | pref |= PRE_LOCK;
38 | break;
39 | case 0x26: case 0x2e: case 0x36:
40 | case 0x3e: case 0x64: case 0x65:
41 | hs->p_seg = c;
42 | pref |= PRE_SEG;
43 | break;
44 | case 0x66:
45 | hs->p_66 = c;
46 | pref |= PRE_66;
47 | break;
48 | case 0x67:
49 | hs->p_67 = c;
50 | pref |= PRE_67;
51 | break;
52 | default:
53 | goto pref_done;
54 | }
55 | pref_done:
56 |
57 | hs->flags = (uint32_t)pref << 23;
58 |
59 | if (!pref)
60 | pref |= PRE_NONE;
61 |
62 | if ((hs->opcode = c) == 0x0f) {
63 | hs->opcode2 = c = *p++;
64 | ht += DELTA_OPCODES;
65 | } else if (c >= 0xa0 && c <= 0xa3) {
66 | if (pref & PRE_67)
67 | pref |= PRE_66;
68 | else
69 | pref &= ~PRE_66;
70 | }
71 |
72 | opcode = c;
73 | cflags = ht[ht[opcode / 4] + (opcode % 4)];
74 |
75 | if (cflags == C_ERROR) {
76 | hs->flags |= F_ERROR | F_ERROR_OPCODE;
77 | cflags = 0;
78 | if ((opcode & -3) == 0x24)
79 | cflags++;
80 | }
81 |
82 | x = 0;
83 | if (cflags & C_GROUP) {
84 | uint16_t t;
85 | t = *(uint16_t *)(ht + (cflags & 0x7f));
86 | cflags = (uint8_t)t;
87 | x = (uint8_t)(t >> 8);
88 | }
89 |
90 | if (hs->opcode2) {
91 | ht = hde32_table + DELTA_PREFIXES;
92 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
93 | hs->flags |= F_ERROR | F_ERROR_OPCODE;
94 | }
95 |
96 | if (cflags & C_MODRM) {
97 | hs->flags |= F_MODRM;
98 | hs->modrm = c = *p++;
99 | hs->modrm_mod = m_mod = c >> 6;
100 | hs->modrm_rm = m_rm = c & 7;
101 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
102 |
103 | if (x && ((x << m_reg) & 0x80))
104 | hs->flags |= F_ERROR | F_ERROR_OPCODE;
105 |
106 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
107 | uint8_t t = opcode - 0xd9;
108 | if (m_mod == 3) {
109 | ht = hde32_table + DELTA_FPU_MODRM + t*8;
110 | t = ht[m_reg] << m_rm;
111 | } else {
112 | ht = hde32_table + DELTA_FPU_REG;
113 | t = ht[t] << m_reg;
114 | }
115 | if (t & 0x80)
116 | hs->flags |= F_ERROR | F_ERROR_OPCODE;
117 | }
118 |
119 | if (pref & PRE_LOCK) {
120 | if (m_mod == 3) {
121 | hs->flags |= F_ERROR | F_ERROR_LOCK;
122 | } else {
123 | uint8_t *table_end, op = opcode;
124 | if (hs->opcode2) {
125 | ht = hde32_table + DELTA_OP2_LOCK_OK;
126 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
127 | } else {
128 | ht = hde32_table + DELTA_OP_LOCK_OK;
129 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
130 | op &= -2;
131 | }
132 | for (; ht != table_end; ht++)
133 | if (*ht++ == op) {
134 | if (!((*ht << m_reg) & 0x80))
135 | goto no_lock_error;
136 | else
137 | break;
138 | }
139 | hs->flags |= F_ERROR | F_ERROR_LOCK;
140 | no_lock_error:
141 | ;
142 | }
143 | }
144 |
145 | if (hs->opcode2) {
146 | switch (opcode) {
147 | case 0x20: case 0x22:
148 | m_mod = 3;
149 | if (m_reg > 4 || m_reg == 1)
150 | goto error_operand;
151 | else
152 | goto no_error_operand;
153 | case 0x21: case 0x23:
154 | m_mod = 3;
155 | if (m_reg == 4 || m_reg == 5)
156 | goto error_operand;
157 | else
158 | goto no_error_operand;
159 | }
160 | } else {
161 | switch (opcode) {
162 | case 0x8c:
163 | if (m_reg > 5)
164 | goto error_operand;
165 | else
166 | goto no_error_operand;
167 | case 0x8e:
168 | if (m_reg == 1 || m_reg > 5)
169 | goto error_operand;
170 | else
171 | goto no_error_operand;
172 | }
173 | }
174 |
175 | if (m_mod == 3) {
176 | uint8_t *table_end;
177 | if (hs->opcode2) {
178 | ht = hde32_table + DELTA_OP2_ONLY_MEM;
179 | table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM;
180 | } else {
181 | ht = hde32_table + DELTA_OP_ONLY_MEM;
182 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
183 | }
184 | for (; ht != table_end; ht += 2)
185 | if (*ht++ == opcode) {
186 | if (*ht++ & pref && !((*ht << m_reg) & 0x80))
187 | goto error_operand;
188 | else
189 | break;
190 | }
191 | goto no_error_operand;
192 | } else if (hs->opcode2) {
193 | switch (opcode) {
194 | case 0x50: case 0xd7: case 0xf7:
195 | if (pref & (PRE_NONE | PRE_66))
196 | goto error_operand;
197 | break;
198 | case 0xd6:
199 | if (pref & (PRE_F2 | PRE_F3))
200 | goto error_operand;
201 | break;
202 | case 0xc5:
203 | goto error_operand;
204 | }
205 | goto no_error_operand;
206 | } else
207 | goto no_error_operand;
208 |
209 | error_operand:
210 | hs->flags |= F_ERROR | F_ERROR_OPERAND;
211 | no_error_operand:
212 |
213 | c = *p++;
214 | if (m_reg <= 1) {
215 | if (opcode == 0xf6)
216 | cflags |= C_IMM8;
217 | else if (opcode == 0xf7)
218 | cflags |= C_IMM_P66;
219 | }
220 |
221 | switch (m_mod) {
222 | case 0:
223 | if (pref & PRE_67) {
224 | if (m_rm == 6)
225 | disp_size = 2;
226 | } else
227 | if (m_rm == 5)
228 | disp_size = 4;
229 | break;
230 | case 1:
231 | disp_size = 1;
232 | break;
233 | case 2:
234 | disp_size = 2;
235 | if (!(pref & PRE_67))
236 | disp_size <<= 1;
237 | }
238 |
239 | if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) {
240 | hs->flags |= F_SIB;
241 | p++;
242 | hs->sib = c;
243 | hs->sib_scale = c >> 6;
244 | hs->sib_index = (c & 0x3f) >> 3;
245 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
246 | disp_size = 4;
247 | }
248 |
249 | p--;
250 | switch (disp_size) {
251 | case 1:
252 | hs->flags |= F_DISP8;
253 | hs->disp.disp8 = *p;
254 | break;
255 | case 2:
256 | hs->flags |= F_DISP16;
257 | hs->disp.disp16 = *(uint16_t *)p;
258 | break;
259 | case 4:
260 | hs->flags |= F_DISP32;
261 | hs->disp.disp32 = *(uint32_t *)p;
262 | }
263 | p += disp_size;
264 | } else if (pref & PRE_LOCK)
265 | hs->flags |= F_ERROR | F_ERROR_LOCK;
266 |
267 | if (cflags & C_IMM_P66) {
268 | if (cflags & C_REL32) {
269 | if (pref & PRE_66) {
270 | hs->flags |= F_IMM16 | F_RELATIVE;
271 | hs->imm.imm16 = *(uint16_t *)p;
272 | p += 2;
273 | goto disasm_done;
274 | }
275 | goto rel32_ok;
276 | }
277 | if (pref & PRE_66) {
278 | hs->flags |= F_IMM16;
279 | hs->imm.imm16 = *(uint16_t *)p;
280 | p += 2;
281 | } else {
282 | hs->flags |= F_IMM32;
283 | hs->imm.imm32 = *(uint32_t *)p;
284 | p += 4;
285 | }
286 | }
287 |
288 | if (cflags & C_IMM16) {
289 | if (hs->flags & F_IMM32) {
290 | hs->flags |= F_IMM16;
291 | hs->disp.disp16 = *(uint16_t *)p;
292 | } else if (hs->flags & F_IMM16) {
293 | hs->flags |= F_2IMM16;
294 | hs->disp.disp16 = *(uint16_t *)p;
295 | } else {
296 | hs->flags |= F_IMM16;
297 | hs->imm.imm16 = *(uint16_t *)p;
298 | }
299 | p += 2;
300 | }
301 | if (cflags & C_IMM8) {
302 | hs->flags |= F_IMM8;
303 | hs->imm.imm8 = *p++;
304 | }
305 |
306 | if (cflags & C_REL32) {
307 | rel32_ok:
308 | hs->flags |= F_IMM32 | F_RELATIVE;
309 | hs->imm.imm32 = *(uint32_t *)p;
310 | p += 4;
311 | } else if (cflags & C_REL8) {
312 | hs->flags |= F_IMM8 | F_RELATIVE;
313 | hs->imm.imm8 = *p++;
314 | }
315 |
316 | disasm_done:
317 |
318 | if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
319 | hs->flags |= F_ERROR | F_ERROR_LENGTH;
320 | hs->len = 15;
321 | }
322 |
323 | return (unsigned int)hs->len;
324 | }
325 |
326 | #endif // defined(_M_IX86) || defined(__i386__)
327 |
--------------------------------------------------------------------------------
/src/minhook/src/hde/hde32.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Hacker Disassembler Engine 32
3 | * Copyright (c) 2006-2009, Vyacheslav Patkov.
4 | * All rights reserved.
5 | *
6 | * hde32.h: C/C++ header file
7 | *
8 | */
9 |
10 | #ifndef _HDE32_H_
11 | #define _HDE32_H_
12 |
13 | /* stdint.h - C99 standard header
14 | * http://en.wikipedia.org/wiki/stdint.h
15 | *
16 | * if your compiler doesn't contain "stdint.h" header (for
17 | * example, Microsoft Visual C++), you can download file:
18 | * http://www.azillionmonkeys.com/qed/pstdint.h
19 | * and change next line to:
20 | * #include "pstdint.h"
21 | */
22 | #include "pstdint.h"
23 |
24 | #define F_MODRM 0x00000001
25 | #define F_SIB 0x00000002
26 | #define F_IMM8 0x00000004
27 | #define F_IMM16 0x00000008
28 | #define F_IMM32 0x00000010
29 | #define F_DISP8 0x00000020
30 | #define F_DISP16 0x00000040
31 | #define F_DISP32 0x00000080
32 | #define F_RELATIVE 0x00000100
33 | #define F_2IMM16 0x00000800
34 | #define F_ERROR 0x00001000
35 | #define F_ERROR_OPCODE 0x00002000
36 | #define F_ERROR_LENGTH 0x00004000
37 | #define F_ERROR_LOCK 0x00008000
38 | #define F_ERROR_OPERAND 0x00010000
39 | #define F_PREFIX_REPNZ 0x01000000
40 | #define F_PREFIX_REPX 0x02000000
41 | #define F_PREFIX_REP 0x03000000
42 | #define F_PREFIX_66 0x04000000
43 | #define F_PREFIX_67 0x08000000
44 | #define F_PREFIX_LOCK 0x10000000
45 | #define F_PREFIX_SEG 0x20000000
46 | #define F_PREFIX_ANY 0x3f000000
47 |
48 | #define PREFIX_SEGMENT_CS 0x2e
49 | #define PREFIX_SEGMENT_SS 0x36
50 | #define PREFIX_SEGMENT_DS 0x3e
51 | #define PREFIX_SEGMENT_ES 0x26
52 | #define PREFIX_SEGMENT_FS 0x64
53 | #define PREFIX_SEGMENT_GS 0x65
54 | #define PREFIX_LOCK 0xf0
55 | #define PREFIX_REPNZ 0xf2
56 | #define PREFIX_REPX 0xf3
57 | #define PREFIX_OPERAND_SIZE 0x66
58 | #define PREFIX_ADDRESS_SIZE 0x67
59 |
60 | #pragma pack(push,1)
61 |
62 | typedef struct {
63 | uint8_t len;
64 | uint8_t p_rep;
65 | uint8_t p_lock;
66 | uint8_t p_seg;
67 | uint8_t p_66;
68 | uint8_t p_67;
69 | uint8_t opcode;
70 | uint8_t opcode2;
71 | uint8_t modrm;
72 | uint8_t modrm_mod;
73 | uint8_t modrm_reg;
74 | uint8_t modrm_rm;
75 | uint8_t sib;
76 | uint8_t sib_scale;
77 | uint8_t sib_index;
78 | uint8_t sib_base;
79 | union {
80 | uint8_t imm8;
81 | uint16_t imm16;
82 | uint32_t imm32;
83 | } imm;
84 | union {
85 | uint8_t disp8;
86 | uint16_t disp16;
87 | uint32_t disp32;
88 | } disp;
89 | uint32_t flags;
90 | } hde32s;
91 |
92 | #pragma pack(pop)
93 |
94 | #ifdef __cplusplus
95 | extern "C" {
96 | #endif
97 |
98 | /* __cdecl */
99 | unsigned int hde32_disasm(const void *code, hde32s *hs);
100 |
101 | #ifdef __cplusplus
102 | }
103 | #endif
104 |
105 | #endif /* _HDE32_H_ */
106 |
--------------------------------------------------------------------------------
/src/minhook/src/hde/hde64.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Hacker Disassembler Engine 64 C
3 | * Copyright (c) 2008-2009, Vyacheslav Patkov.
4 | * All rights reserved.
5 | *
6 | */
7 |
8 | #if defined(_M_X64) || defined(__x86_64__)
9 |
10 | #include "hde64.h"
11 | #include "table64.h"
12 |
13 | unsigned int hde64_disasm(const void *code, hde64s *hs)
14 | {
15 | uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
16 | uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
17 | uint8_t op64 = 0;
18 |
19 | // Avoid using memset to reduce the footprint.
20 | #ifndef _MSC_VER
21 | memset((LPBYTE)hs, 0, sizeof(hde64s));
22 | #else
23 | __stosb((LPBYTE)hs, 0, sizeof(hde64s));
24 | #endif
25 |
26 | for (x = 16; x; x--)
27 | switch (c = *p++) {
28 | case 0xf3:
29 | hs->p_rep = c;
30 | pref |= PRE_F3;
31 | break;
32 | case 0xf2:
33 | hs->p_rep = c;
34 | pref |= PRE_F2;
35 | break;
36 | case 0xf0:
37 | hs->p_lock = c;
38 | pref |= PRE_LOCK;
39 | break;
40 | case 0x26: case 0x2e: case 0x36:
41 | case 0x3e: case 0x64: case 0x65:
42 | hs->p_seg = c;
43 | pref |= PRE_SEG;
44 | break;
45 | case 0x66:
46 | hs->p_66 = c;
47 | pref |= PRE_66;
48 | break;
49 | case 0x67:
50 | hs->p_67 = c;
51 | pref |= PRE_67;
52 | break;
53 | default:
54 | goto pref_done;
55 | }
56 | pref_done:
57 |
58 | hs->flags = (uint32_t)pref << 23;
59 |
60 | if (!pref)
61 | pref |= PRE_NONE;
62 |
63 | if ((c & 0xf0) == 0x40) {
64 | hs->flags |= F_PREFIX_REX;
65 | if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)
66 | op64++;
67 | hs->rex_r = (c & 7) >> 2;
68 | hs->rex_x = (c & 3) >> 1;
69 | hs->rex_b = c & 1;
70 | if (((c = *p++) & 0xf0) == 0x40) {
71 | opcode = c;
72 | goto error_opcode;
73 | }
74 | }
75 |
76 | if ((hs->opcode = c) == 0x0f) {
77 | hs->opcode2 = c = *p++;
78 | ht += DELTA_OPCODES;
79 | } else if (c >= 0xa0 && c <= 0xa3) {
80 | op64++;
81 | if (pref & PRE_67)
82 | pref |= PRE_66;
83 | else
84 | pref &= ~PRE_66;
85 | }
86 |
87 | opcode = c;
88 | cflags = ht[ht[opcode / 4] + (opcode % 4)];
89 |
90 | if (cflags == C_ERROR) {
91 | error_opcode:
92 | hs->flags |= F_ERROR | F_ERROR_OPCODE;
93 | cflags = 0;
94 | if ((opcode & -3) == 0x24)
95 | cflags++;
96 | }
97 |
98 | x = 0;
99 | if (cflags & C_GROUP) {
100 | uint16_t t;
101 | t = *(uint16_t *)(ht + (cflags & 0x7f));
102 | cflags = (uint8_t)t;
103 | x = (uint8_t)(t >> 8);
104 | }
105 |
106 | if (hs->opcode2) {
107 | ht = hde64_table + DELTA_PREFIXES;
108 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
109 | hs->flags |= F_ERROR | F_ERROR_OPCODE;
110 | }
111 |
112 | if (cflags & C_MODRM) {
113 | hs->flags |= F_MODRM;
114 | hs->modrm = c = *p++;
115 | hs->modrm_mod = m_mod = c >> 6;
116 | hs->modrm_rm = m_rm = c & 7;
117 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
118 |
119 | if (x && ((x << m_reg) & 0x80))
120 | hs->flags |= F_ERROR | F_ERROR_OPCODE;
121 |
122 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
123 | uint8_t t = opcode - 0xd9;
124 | if (m_mod == 3) {
125 | ht = hde64_table + DELTA_FPU_MODRM + t*8;
126 | t = ht[m_reg] << m_rm;
127 | } else {
128 | ht = hde64_table + DELTA_FPU_REG;
129 | t = ht[t] << m_reg;
130 | }
131 | if (t & 0x80)
132 | hs->flags |= F_ERROR | F_ERROR_OPCODE;
133 | }
134 |
135 | if (pref & PRE_LOCK) {
136 | if (m_mod == 3) {
137 | hs->flags |= F_ERROR | F_ERROR_LOCK;
138 | } else {
139 | uint8_t *table_end, op = opcode;
140 | if (hs->opcode2) {
141 | ht = hde64_table + DELTA_OP2_LOCK_OK;
142 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
143 | } else {
144 | ht = hde64_table + DELTA_OP_LOCK_OK;
145 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
146 | op &= -2;
147 | }
148 | for (; ht != table_end; ht++)
149 | if (*ht++ == op) {
150 | if (!((*ht << m_reg) & 0x80))
151 | goto no_lock_error;
152 | else
153 | break;
154 | }
155 | hs->flags |= F_ERROR | F_ERROR_LOCK;
156 | no_lock_error:
157 | ;
158 | }
159 | }
160 |
161 | if (hs->opcode2) {
162 | switch (opcode) {
163 | case 0x20: case 0x22:
164 | m_mod = 3;
165 | if (m_reg > 4 || m_reg == 1)
166 | goto error_operand;
167 | else
168 | goto no_error_operand;
169 | case 0x21: case 0x23:
170 | m_mod = 3;
171 | if (m_reg == 4 || m_reg == 5)
172 | goto error_operand;
173 | else
174 | goto no_error_operand;
175 | }
176 | } else {
177 | switch (opcode) {
178 | case 0x8c:
179 | if (m_reg > 5)
180 | goto error_operand;
181 | else
182 | goto no_error_operand;
183 | case 0x8e:
184 | if (m_reg == 1 || m_reg > 5)
185 | goto error_operand;
186 | else
187 | goto no_error_operand;
188 | }
189 | }
190 |
191 | if (m_mod == 3) {
192 | uint8_t *table_end;
193 | if (hs->opcode2) {
194 | ht = hde64_table + DELTA_OP2_ONLY_MEM;
195 | table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
196 | } else {
197 | ht = hde64_table + DELTA_OP_ONLY_MEM;
198 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
199 | }
200 | for (; ht != table_end; ht += 2)
201 | if (*ht++ == opcode) {
202 | if (*ht++ & pref && !((*ht << m_reg) & 0x80))
203 | goto error_operand;
204 | else
205 | break;
206 | }
207 | goto no_error_operand;
208 | } else if (hs->opcode2) {
209 | switch (opcode) {
210 | case 0x50: case 0xd7: case 0xf7:
211 | if (pref & (PRE_NONE | PRE_66))
212 | goto error_operand;
213 | break;
214 | case 0xd6:
215 | if (pref & (PRE_F2 | PRE_F3))
216 | goto error_operand;
217 | break;
218 | case 0xc5:
219 | goto error_operand;
220 | }
221 | goto no_error_operand;
222 | } else
223 | goto no_error_operand;
224 |
225 | error_operand:
226 | hs->flags |= F_ERROR | F_ERROR_OPERAND;
227 | no_error_operand:
228 |
229 | c = *p++;
230 | if (m_reg <= 1) {
231 | if (opcode == 0xf6)
232 | cflags |= C_IMM8;
233 | else if (opcode == 0xf7)
234 | cflags |= C_IMM_P66;
235 | }
236 |
237 | switch (m_mod) {
238 | case 0:
239 | if (pref & PRE_67) {
240 | if (m_rm == 6)
241 | disp_size = 2;
242 | } else
243 | if (m_rm == 5)
244 | disp_size = 4;
245 | break;
246 | case 1:
247 | disp_size = 1;
248 | break;
249 | case 2:
250 | disp_size = 2;
251 | if (!(pref & PRE_67))
252 | disp_size <<= 1;
253 | }
254 |
255 | if (m_mod != 3 && m_rm == 4) {
256 | hs->flags |= F_SIB;
257 | p++;
258 | hs->sib = c;
259 | hs->sib_scale = c >> 6;
260 | hs->sib_index = (c & 0x3f) >> 3;
261 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
262 | disp_size = 4;
263 | }
264 |
265 | p--;
266 | switch (disp_size) {
267 | case 1:
268 | hs->flags |= F_DISP8;
269 | hs->disp.disp8 = *p;
270 | break;
271 | case 2:
272 | hs->flags |= F_DISP16;
273 | hs->disp.disp16 = *(uint16_t *)p;
274 | break;
275 | case 4:
276 | hs->flags |= F_DISP32;
277 | hs->disp.disp32 = *(uint32_t *)p;
278 | }
279 | p += disp_size;
280 | } else if (pref & PRE_LOCK)
281 | hs->flags |= F_ERROR | F_ERROR_LOCK;
282 |
283 | if (cflags & C_IMM_P66) {
284 | if (cflags & C_REL32) {
285 | if (pref & PRE_66) {
286 | hs->flags |= F_IMM16 | F_RELATIVE;
287 | hs->imm.imm16 = *(uint16_t *)p;
288 | p += 2;
289 | goto disasm_done;
290 | }
291 | goto rel32_ok;
292 | }
293 | if (op64) {
294 | hs->flags |= F_IMM64;
295 | hs->imm.imm64 = *(uint64_t *)p;
296 | p += 8;
297 | } else if (!(pref & PRE_66)) {
298 | hs->flags |= F_IMM32;
299 | hs->imm.imm32 = *(uint32_t *)p;
300 | p += 4;
301 | } else
302 | goto imm16_ok;
303 | }
304 |
305 |
306 | if (cflags & C_IMM16) {
307 | imm16_ok:
308 | hs->flags |= F_IMM16;
309 | hs->imm.imm16 = *(uint16_t *)p;
310 | p += 2;
311 | }
312 | if (cflags & C_IMM8) {
313 | hs->flags |= F_IMM8;
314 | hs->imm.imm8 = *p++;
315 | }
316 |
317 | if (cflags & C_REL32) {
318 | rel32_ok:
319 | hs->flags |= F_IMM32 | F_RELATIVE;
320 | hs->imm.imm32 = *(uint32_t *)p;
321 | p += 4;
322 | } else if (cflags & C_REL8) {
323 | hs->flags |= F_IMM8 | F_RELATIVE;
324 | hs->imm.imm8 = *p++;
325 | }
326 |
327 | disasm_done:
328 |
329 | if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
330 | hs->flags |= F_ERROR | F_ERROR_LENGTH;
331 | hs->len = 15;
332 | }
333 |
334 | return (unsigned int)hs->len;
335 | }
336 |
337 | #endif // defined(_M_X64) || defined(__x86_64__)
338 |
--------------------------------------------------------------------------------
/src/minhook/src/hde/hde64.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Hacker Disassembler Engine 64
3 | * Copyright (c) 2008-2009, Vyacheslav Patkov.
4 | * All rights reserved.
5 | *
6 | * hde64.h: C/C++ header file
7 | *
8 | */
9 |
10 | #ifndef _HDE64_H_
11 | #define _HDE64_H_
12 |
13 | /* stdint.h - C99 standard header
14 | * http://en.wikipedia.org/wiki/stdint.h
15 | *
16 | * if your compiler doesn't contain "stdint.h" header (for
17 | * example, Microsoft Visual C++), you can download file:
18 | * http://www.azillionmonkeys.com/qed/pstdint.h
19 | * and change next line to:
20 | * #include "pstdint.h"
21 | */
22 | #include "pstdint.h"
23 |
24 | #define F_MODRM 0x00000001
25 | #define F_SIB 0x00000002
26 | #define F_IMM8 0x00000004
27 | #define F_IMM16 0x00000008
28 | #define F_IMM32 0x00000010
29 | #define F_IMM64 0x00000020
30 | #define F_DISP8 0x00000040
31 | #define F_DISP16 0x00000080
32 | #define F_DISP32 0x00000100
33 | #define F_RELATIVE 0x00000200
34 | #define F_ERROR 0x00001000
35 | #define F_ERROR_OPCODE 0x00002000
36 | #define F_ERROR_LENGTH 0x00004000
37 | #define F_ERROR_LOCK 0x00008000
38 | #define F_ERROR_OPERAND 0x00010000
39 | #define F_PREFIX_REPNZ 0x01000000
40 | #define F_PREFIX_REPX 0x02000000
41 | #define F_PREFIX_REP 0x03000000
42 | #define F_PREFIX_66 0x04000000
43 | #define F_PREFIX_67 0x08000000
44 | #define F_PREFIX_LOCK 0x10000000
45 | #define F_PREFIX_SEG 0x20000000
46 | #define F_PREFIX_REX 0x40000000
47 | #define F_PREFIX_ANY 0x7f000000
48 |
49 | #define PREFIX_SEGMENT_CS 0x2e
50 | #define PREFIX_SEGMENT_SS 0x36
51 | #define PREFIX_SEGMENT_DS 0x3e
52 | #define PREFIX_SEGMENT_ES 0x26
53 | #define PREFIX_SEGMENT_FS 0x64
54 | #define PREFIX_SEGMENT_GS 0x65
55 | #define PREFIX_LOCK 0xf0
56 | #define PREFIX_REPNZ 0xf2
57 | #define PREFIX_REPX 0xf3
58 | #define PREFIX_OPERAND_SIZE 0x66
59 | #define PREFIX_ADDRESS_SIZE 0x67
60 |
61 | #pragma pack(push,1)
62 |
63 | typedef struct {
64 | uint8_t len;
65 | uint8_t p_rep;
66 | uint8_t p_lock;
67 | uint8_t p_seg;
68 | uint8_t p_66;
69 | uint8_t p_67;
70 | uint8_t rex;
71 | uint8_t rex_w;
72 | uint8_t rex_r;
73 | uint8_t rex_x;
74 | uint8_t rex_b;
75 | uint8_t opcode;
76 | uint8_t opcode2;
77 | uint8_t modrm;
78 | uint8_t modrm_mod;
79 | uint8_t modrm_reg;
80 | uint8_t modrm_rm;
81 | uint8_t sib;
82 | uint8_t sib_scale;
83 | uint8_t sib_index;
84 | uint8_t sib_base;
85 | union {
86 | uint8_t imm8;
87 | uint16_t imm16;
88 | uint32_t imm32;
89 | uint64_t imm64;
90 | } imm;
91 | union {
92 | uint8_t disp8;
93 | uint16_t disp16;
94 | uint32_t disp32;
95 | } disp;
96 | uint32_t flags;
97 | } hde64s;
98 |
99 | #pragma pack(pop)
100 |
101 | #ifdef __cplusplus
102 | extern "C" {
103 | #endif
104 |
105 | /* __cdecl */
106 | unsigned int hde64_disasm(const void *code, hde64s *hs);
107 |
108 | #ifdef __cplusplus
109 | }
110 | #endif
111 |
112 | #endif /* _HDE64_H_ */
113 |
--------------------------------------------------------------------------------
/src/minhook/src/hde/pstdint.h:
--------------------------------------------------------------------------------
1 | /*
2 | * MinHook - The Minimalistic API Hooking Library for x64/x86
3 | * Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | *
9 | * 1. Redistributions of source code must retain the above copyright
10 | * notice, this list of conditions and the following disclaimer.
11 | * 2. Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 | */
26 |
27 | #pragma once
28 |
29 | #include
30 |
31 | // Integer types for HDE.
32 | typedef INT8 int8_t;
33 | typedef INT16 int16_t;
34 | typedef INT32 int32_t;
35 | typedef INT64 int64_t;
36 | typedef UINT8 uint8_t;
37 | typedef UINT16 uint16_t;
38 | typedef UINT32 uint32_t;
39 | typedef UINT64 uint64_t;
40 |
--------------------------------------------------------------------------------
/src/minhook/src/hde/table32.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Hacker Disassembler Engine 32 C
3 | * Copyright (c) 2008-2009, Vyacheslav Patkov.
4 | * All rights reserved.
5 | *
6 | */
7 |
8 | #define C_NONE 0x00
9 | #define C_MODRM 0x01
10 | #define C_IMM8 0x02
11 | #define C_IMM16 0x04
12 | #define C_IMM_P66 0x10
13 | #define C_REL8 0x20
14 | #define C_REL32 0x40
15 | #define C_GROUP 0x80
16 | #define C_ERROR 0xff
17 |
18 | #define PRE_ANY 0x00
19 | #define PRE_NONE 0x01
20 | #define PRE_F2 0x02
21 | #define PRE_F3 0x04
22 | #define PRE_66 0x08
23 | #define PRE_67 0x10
24 | #define PRE_LOCK 0x20
25 | #define PRE_SEG 0x40
26 | #define PRE_ALL 0xff
27 |
28 | #define DELTA_OPCODES 0x4a
29 | #define DELTA_FPU_REG 0xf1
30 | #define DELTA_FPU_MODRM 0xf8
31 | #define DELTA_PREFIXES 0x130
32 | #define DELTA_OP_LOCK_OK 0x1a1
33 | #define DELTA_OP2_LOCK_OK 0x1b9
34 | #define DELTA_OP_ONLY_MEM 0x1cb
35 | #define DELTA_OP2_ONLY_MEM 0x1da
36 |
37 | unsigned char hde32_table[] = {
38 | 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,
39 | 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f,
40 | 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3,
41 | 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa,
42 | 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90,
43 | 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f,
44 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d,
45 | 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59,
46 | 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,
47 | 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0,
48 | 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01,
49 | 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11,
50 | 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8,
51 | 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca,
52 | 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff,
53 | 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03,
54 | 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,
55 | 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,
56 | 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
57 | 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
58 | 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f,
59 | 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a,
60 | 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,
61 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a,
62 | 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06,
63 | 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06,
64 | 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
65 | 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08,
66 | 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,
67 | 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,
68 | 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,
69 | 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,
70 | 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,
71 | 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,
72 | 0xe7,0x08,0x00,0xf0,0x02,0x00
73 | };
74 |
--------------------------------------------------------------------------------
/src/minhook/src/hde/table64.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Hacker Disassembler Engine 64 C
3 | * Copyright (c) 2008-2009, Vyacheslav Patkov.
4 | * All rights reserved.
5 | *
6 | */
7 |
8 | #define C_NONE 0x00
9 | #define C_MODRM 0x01
10 | #define C_IMM8 0x02
11 | #define C_IMM16 0x04
12 | #define C_IMM_P66 0x10
13 | #define C_REL8 0x20
14 | #define C_REL32 0x40
15 | #define C_GROUP 0x80
16 | #define C_ERROR 0xff
17 |
18 | #define PRE_ANY 0x00
19 | #define PRE_NONE 0x01
20 | #define PRE_F2 0x02
21 | #define PRE_F3 0x04
22 | #define PRE_66 0x08
23 | #define PRE_67 0x10
24 | #define PRE_LOCK 0x20
25 | #define PRE_SEG 0x40
26 | #define PRE_ALL 0xff
27 |
28 | #define DELTA_OPCODES 0x4a
29 | #define DELTA_FPU_REG 0xfd
30 | #define DELTA_FPU_MODRM 0x104
31 | #define DELTA_PREFIXES 0x13c
32 | #define DELTA_OP_LOCK_OK 0x1ae
33 | #define DELTA_OP2_LOCK_OK 0x1c6
34 | #define DELTA_OP_ONLY_MEM 0x1d8
35 | #define DELTA_OP2_ONLY_MEM 0x1e7
36 |
37 | unsigned char hde64_table[] = {
38 | 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,
39 | 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,
40 | 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,
41 | 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,
42 | 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,
43 | 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,
44 | 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,
45 | 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,
46 | 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,
47 | 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,
48 | 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,
49 | 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,
50 | 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,
51 | 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,
52 | 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,
53 | 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,
54 | 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,
55 | 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,
56 | 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,
57 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
58 | 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,
59 | 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,
60 | 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,
61 | 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
62 | 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,
63 | 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,
64 | 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,
65 | 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
66 | 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,
67 | 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,
68 | 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,
69 | 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,
70 | 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,
71 | 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,
72 | 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,
73 | 0x00,0xf0,0x02,0x00
74 | };
75 |
--------------------------------------------------------------------------------
/src/minhook/src/hook.c:
--------------------------------------------------------------------------------
1 | /*
2 | * MinHook - The Minimalistic API Hooking Library for x64/x86
3 | * Copyright (C) 2009-2017 Tsuda Kageyu.
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | *
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | #include
30 | #include
31 | #include
32 |
33 | #include "../include/MinHook.h"
34 | #include "buffer.h"
35 | #include "trampoline.h"
36 |
37 | #ifndef ARRAYSIZE
38 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
39 | #endif
40 |
41 | // Initial capacity of the HOOK_ENTRY buffer.
42 | #define INITIAL_HOOK_CAPACITY 32
43 |
44 | // Initial capacity of the thread IDs buffer.
45 | #define INITIAL_THREAD_CAPACITY 128
46 |
47 | // Special hook position values.
48 | #define INVALID_HOOK_POS UINT_MAX
49 | #define ALL_HOOKS_POS UINT_MAX
50 |
51 | // Freeze() action argument defines.
52 | #define ACTION_DISABLE 0
53 | #define ACTION_ENABLE 1
54 | #define ACTION_APPLY_QUEUED 2
55 |
56 | // Thread access rights for suspending/resuming threads.
57 | #define THREAD_ACCESS \
58 | (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT)
59 |
60 | // Hook information.
61 | typedef struct _HOOK_ENTRY
62 | {
63 | LPVOID pTarget; // Address of the target function.
64 | LPVOID pDetour; // Address of the detour or relay function.
65 | LPVOID pTrampoline; // Address of the trampoline function.
66 | UINT8 backup[8]; // Original prologue of the target function.
67 |
68 | UINT8 patchAbove : 1; // Uses the hot patch area.
69 | UINT8 isEnabled : 1; // Enabled.
70 | UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled.
71 |
72 | UINT nIP : 4; // Count of the instruction boundaries.
73 | UINT8 oldIPs[8]; // Instruction boundaries of the target function.
74 | UINT8 newIPs[8]; // Instruction boundaries of the trampoline function.
75 | } HOOK_ENTRY, *PHOOK_ENTRY;
76 |
77 | // Suspended threads for Freeze()/Unfreeze().
78 | typedef struct _FROZEN_THREADS
79 | {
80 | LPDWORD pItems; // Data heap
81 | UINT capacity; // Size of allocated data heap, items
82 | UINT size; // Actual number of data items
83 | } FROZEN_THREADS, *PFROZEN_THREADS;
84 |
85 | //-------------------------------------------------------------------------
86 | // Global Variables:
87 | //-------------------------------------------------------------------------
88 |
89 | // Spin lock flag for EnterSpinLock()/LeaveSpinLock().
90 | volatile LONG g_isLocked = FALSE;
91 |
92 | // Private heap handle. If not NULL, this library is initialized.
93 | HANDLE g_hHeap = NULL;
94 |
95 | // Hook entries.
96 | struct
97 | {
98 | PHOOK_ENTRY pItems; // Data heap
99 | UINT capacity; // Size of allocated data heap, items
100 | UINT size; // Actual number of data items
101 | } g_hooks;
102 |
103 | //-------------------------------------------------------------------------
104 | // Returns INVALID_HOOK_POS if not found.
105 | static UINT FindHookEntry(LPVOID pTarget)
106 | {
107 | UINT i;
108 | for (i = 0; i < g_hooks.size; ++i)
109 | {
110 | if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget)
111 | return i;
112 | }
113 |
114 | return INVALID_HOOK_POS;
115 | }
116 |
117 | //-------------------------------------------------------------------------
118 | static PHOOK_ENTRY AddHookEntry()
119 | {
120 | if (g_hooks.pItems == NULL)
121 | {
122 | g_hooks.capacity = INITIAL_HOOK_CAPACITY;
123 | g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc(
124 | g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY));
125 | if (g_hooks.pItems == NULL)
126 | return NULL;
127 | }
128 | else if (g_hooks.size >= g_hooks.capacity)
129 | {
130 | PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
131 | g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY));
132 | if (p == NULL)
133 | return NULL;
134 |
135 | g_hooks.capacity *= 2;
136 | g_hooks.pItems = p;
137 | }
138 |
139 | return &g_hooks.pItems[g_hooks.size++];
140 | }
141 |
142 | //-------------------------------------------------------------------------
143 | static void DeleteHookEntry(UINT pos)
144 | {
145 | if (pos < g_hooks.size - 1)
146 | g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1];
147 |
148 | g_hooks.size--;
149 |
150 | if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size)
151 | {
152 | PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
153 | g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY));
154 | if (p == NULL)
155 | return;
156 |
157 | g_hooks.capacity /= 2;
158 | g_hooks.pItems = p;
159 | }
160 | }
161 |
162 | //-------------------------------------------------------------------------
163 | static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
164 | {
165 | UINT i;
166 |
167 | if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL)))
168 | return (DWORD_PTR)pHook->pTarget;
169 |
170 | for (i = 0; i < pHook->nIP; ++i)
171 | {
172 | if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]))
173 | return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i];
174 | }
175 |
176 | #if defined(_M_X64) || defined(__x86_64__)
177 | // Check relay function.
178 | if (ip == (DWORD_PTR)pHook->pDetour)
179 | return (DWORD_PTR)pHook->pTarget;
180 | #endif
181 |
182 | return 0;
183 | }
184 |
185 | //-------------------------------------------------------------------------
186 | static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
187 | {
188 | UINT i;
189 | for (i = 0; i < pHook->nIP; ++i)
190 | {
191 | if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]))
192 | return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i];
193 | }
194 |
195 | return 0;
196 | }
197 |
198 | //-------------------------------------------------------------------------
199 | static void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action)
200 | {
201 | // If the thread suspended in the overwritten area,
202 | // move IP to the proper address.
203 |
204 | CONTEXT c;
205 | #if defined(_M_X64) || defined(__x86_64__)
206 | DWORD64 *pIP = &c.Rip;
207 | #else
208 | DWORD *pIP = &c.Eip;
209 | #endif
210 | UINT count;
211 |
212 | c.ContextFlags = CONTEXT_CONTROL;
213 | if (!GetThreadContext(hThread, &c))
214 | return;
215 |
216 | if (pos == ALL_HOOKS_POS)
217 | {
218 | pos = 0;
219 | count = g_hooks.size;
220 | }
221 | else
222 | {
223 | count = pos + 1;
224 | }
225 |
226 | for (; pos < count; ++pos)
227 | {
228 | PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
229 | BOOL enable;
230 | DWORD_PTR ip;
231 |
232 | switch (action)
233 | {
234 | case ACTION_DISABLE:
235 | enable = FALSE;
236 | break;
237 |
238 | case ACTION_ENABLE:
239 | enable = TRUE;
240 | break;
241 |
242 | default: // ACTION_APPLY_QUEUED
243 | enable = pHook->queueEnable;
244 | break;
245 | }
246 | if (pHook->isEnabled == enable)
247 | continue;
248 |
249 | if (enable)
250 | ip = FindNewIP(pHook, *pIP);
251 | else
252 | ip = FindOldIP(pHook, *pIP);
253 |
254 | if (ip != 0)
255 | {
256 | *pIP = ip;
257 | SetThreadContext(hThread, &c);
258 | }
259 | }
260 | }
261 |
262 | //-------------------------------------------------------------------------
263 | static VOID EnumerateThreads(PFROZEN_THREADS pThreads)
264 | {
265 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
266 | if (hSnapshot != INVALID_HANDLE_VALUE)
267 | {
268 | THREADENTRY32 te;
269 | te.dwSize = sizeof(THREADENTRY32);
270 | if (Thread32First(hSnapshot, &te))
271 | {
272 | do
273 | {
274 | if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD))
275 | && te.th32OwnerProcessID == GetCurrentProcessId()
276 | && te.th32ThreadID != GetCurrentThreadId())
277 | {
278 | if (pThreads->pItems == NULL)
279 | {
280 | pThreads->capacity = INITIAL_THREAD_CAPACITY;
281 | pThreads->pItems
282 | = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD));
283 | if (pThreads->pItems == NULL)
284 | break;
285 | }
286 | else if (pThreads->size >= pThreads->capacity)
287 | {
288 | LPDWORD p = (LPDWORD)HeapReAlloc(
289 | g_hHeap, 0, pThreads->pItems, (pThreads->capacity * 2) * sizeof(DWORD));
290 | if (p == NULL)
291 | break;
292 |
293 | pThreads->capacity *= 2;
294 | pThreads->pItems = p;
295 | }
296 | pThreads->pItems[pThreads->size++] = te.th32ThreadID;
297 | }
298 |
299 | te.dwSize = sizeof(THREADENTRY32);
300 | } while (Thread32Next(hSnapshot, &te));
301 | }
302 | CloseHandle(hSnapshot);
303 | }
304 | }
305 |
306 | //-------------------------------------------------------------------------
307 | static VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)
308 | {
309 | pThreads->pItems = NULL;
310 | pThreads->capacity = 0;
311 | pThreads->size = 0;
312 | EnumerateThreads(pThreads);
313 |
314 | if (pThreads->pItems != NULL)
315 | {
316 | UINT i;
317 | for (i = 0; i < pThreads->size; ++i)
318 | {
319 | HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
320 | if (hThread != NULL)
321 | {
322 | SuspendThread(hThread);
323 | ProcessThreadIPs(hThread, pos, action);
324 | CloseHandle(hThread);
325 | }
326 | }
327 | }
328 | }
329 |
330 | //-------------------------------------------------------------------------
331 | static VOID Unfreeze(PFROZEN_THREADS pThreads)
332 | {
333 | if (pThreads->pItems != NULL)
334 | {
335 | UINT i;
336 | for (i = 0; i < pThreads->size; ++i)
337 | {
338 | HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
339 | if (hThread != NULL)
340 | {
341 | ResumeThread(hThread);
342 | CloseHandle(hThread);
343 | }
344 | }
345 |
346 | HeapFree(g_hHeap, 0, pThreads->pItems);
347 | }
348 | }
349 |
350 | //-------------------------------------------------------------------------
351 | static MH_STATUS EnableHookLL(UINT pos, BOOL enable)
352 | {
353 | PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
354 | DWORD oldProtect;
355 | SIZE_T patchSize = sizeof(JMP_REL);
356 | LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget;
357 |
358 | if (pHook->patchAbove)
359 | {
360 | pPatchTarget -= sizeof(JMP_REL);
361 | patchSize += sizeof(JMP_REL_SHORT);
362 | }
363 |
364 | if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect))
365 | return MH_ERROR_MEMORY_PROTECT;
366 |
367 | if (enable)
368 | {
369 | PJMP_REL pJmp = (PJMP_REL)pPatchTarget;
370 | pJmp->opcode = 0xE9;
371 | pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL)));
372 |
373 | if (pHook->patchAbove)
374 | {
375 | PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget;
376 | pShortJmp->opcode = 0xEB;
377 | pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL)));
378 | }
379 | }
380 | else
381 | {
382 | if (pHook->patchAbove)
383 | memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
384 | else
385 | memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL));
386 | }
387 |
388 | VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect);
389 |
390 | // Just-in-case measure.
391 | FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize);
392 |
393 | pHook->isEnabled = enable;
394 | pHook->queueEnable = enable;
395 |
396 | return MH_OK;
397 | }
398 |
399 | //-------------------------------------------------------------------------
400 | static MH_STATUS EnableAllHooksLL(BOOL enable)
401 | {
402 | MH_STATUS status = MH_OK;
403 | UINT i, first = INVALID_HOOK_POS;
404 |
405 | for (i = 0; i < g_hooks.size; ++i)
406 | {
407 | if (g_hooks.pItems[i].isEnabled != enable)
408 | {
409 | first = i;
410 | break;
411 | }
412 | }
413 |
414 | if (first != INVALID_HOOK_POS)
415 | {
416 | FROZEN_THREADS threads;
417 | Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE);
418 |
419 | for (i = first; i < g_hooks.size; ++i)
420 | {
421 | if (g_hooks.pItems[i].isEnabled != enable)
422 | {
423 | status = EnableHookLL(i, enable);
424 | if (status != MH_OK)
425 | break;
426 | }
427 | }
428 |
429 | Unfreeze(&threads);
430 | }
431 |
432 | return status;
433 | }
434 |
435 | //-------------------------------------------------------------------------
436 | static VOID EnterSpinLock(VOID)
437 | {
438 | SIZE_T spinCount = 0;
439 |
440 | // Wait until the flag is FALSE.
441 | while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE)
442 | {
443 | // No need to generate a memory barrier here, since InterlockedCompareExchange()
444 | // generates a full memory barrier itself.
445 |
446 | // Prevent the loop from being too busy.
447 | if (spinCount < 32)
448 | Sleep(0);
449 | else
450 | Sleep(1);
451 |
452 | spinCount++;
453 | }
454 | }
455 |
456 | //-------------------------------------------------------------------------
457 | static VOID LeaveSpinLock(VOID)
458 | {
459 | // No need to generate a memory barrier here, since InterlockedExchange()
460 | // generates a full memory barrier itself.
461 |
462 | InterlockedExchange(&g_isLocked, FALSE);
463 | }
464 |
465 | //-------------------------------------------------------------------------
466 | MH_STATUS WINAPI MH_Initialize(VOID)
467 | {
468 | MH_STATUS status = MH_OK;
469 |
470 | EnterSpinLock();
471 |
472 | if (g_hHeap == NULL)
473 | {
474 | g_hHeap = HeapCreate(0, 0, 0);
475 | if (g_hHeap != NULL)
476 | {
477 | // Initialize the internal function buffer.
478 | InitializeBuffer();
479 | }
480 | else
481 | {
482 | status = MH_ERROR_MEMORY_ALLOC;
483 | }
484 | }
485 | else
486 | {
487 | status = MH_ERROR_ALREADY_INITIALIZED;
488 | }
489 |
490 | LeaveSpinLock();
491 |
492 | return status;
493 | }
494 |
495 | //-------------------------------------------------------------------------
496 | MH_STATUS WINAPI MH_Uninitialize(VOID)
497 | {
498 | MH_STATUS status = MH_OK;
499 |
500 | EnterSpinLock();
501 |
502 | if (g_hHeap != NULL)
503 | {
504 | status = EnableAllHooksLL(FALSE);
505 | if (status == MH_OK)
506 | {
507 | // Free the internal function buffer.
508 |
509 | // HeapFree is actually not required, but some tools detect a false
510 | // memory leak without HeapFree.
511 |
512 | UninitializeBuffer();
513 |
514 | HeapFree(g_hHeap, 0, g_hooks.pItems);
515 | HeapDestroy(g_hHeap);
516 |
517 | g_hHeap = NULL;
518 |
519 | g_hooks.pItems = NULL;
520 | g_hooks.capacity = 0;
521 | g_hooks.size = 0;
522 | }
523 | }
524 | else
525 | {
526 | status = MH_ERROR_NOT_INITIALIZED;
527 | }
528 |
529 | LeaveSpinLock();
530 |
531 | return status;
532 | }
533 |
534 | //-------------------------------------------------------------------------
535 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal)
536 | {
537 | MH_STATUS status = MH_OK;
538 |
539 | EnterSpinLock();
540 |
541 | if (g_hHeap != NULL)
542 | {
543 | if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour))
544 | {
545 | UINT pos = FindHookEntry(pTarget);
546 | if (pos == INVALID_HOOK_POS)
547 | {
548 | LPVOID pBuffer = AllocateBuffer(pTarget);
549 | if (pBuffer != NULL)
550 | {
551 | TRAMPOLINE ct;
552 |
553 | ct.pTarget = pTarget;
554 | ct.pDetour = pDetour;
555 | ct.pTrampoline = pBuffer;
556 | if (CreateTrampolineFunction(&ct))
557 | {
558 | PHOOK_ENTRY pHook = AddHookEntry();
559 | if (pHook != NULL)
560 | {
561 | pHook->pTarget = ct.pTarget;
562 | #if defined(_M_X64) || defined(__x86_64__)
563 | pHook->pDetour = ct.pRelay;
564 | #else
565 | pHook->pDetour = ct.pDetour;
566 | #endif
567 | pHook->pTrampoline = ct.pTrampoline;
568 | pHook->patchAbove = ct.patchAbove;
569 | pHook->isEnabled = FALSE;
570 | pHook->queueEnable = FALSE;
571 | pHook->nIP = ct.nIP;
572 | memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs));
573 | memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs));
574 |
575 | // Back up the target function.
576 |
577 | if (ct.patchAbove)
578 | {
579 | memcpy(
580 | pHook->backup,
581 | (LPBYTE)pTarget - sizeof(JMP_REL),
582 | sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
583 | }
584 | else
585 | {
586 | memcpy(pHook->backup, pTarget, sizeof(JMP_REL));
587 | }
588 |
589 | if (ppOriginal != NULL)
590 | *ppOriginal = pHook->pTrampoline;
591 | }
592 | else
593 | {
594 | status = MH_ERROR_MEMORY_ALLOC;
595 | }
596 | }
597 | else
598 | {
599 | status = MH_ERROR_UNSUPPORTED_FUNCTION;
600 | }
601 |
602 | if (status != MH_OK)
603 | {
604 | FreeBuffer(pBuffer);
605 | }
606 | }
607 | else
608 | {
609 | status = MH_ERROR_MEMORY_ALLOC;
610 | }
611 | }
612 | else
613 | {
614 | status = MH_ERROR_ALREADY_CREATED;
615 | }
616 | }
617 | else
618 | {
619 | status = MH_ERROR_NOT_EXECUTABLE;
620 | }
621 | }
622 | else
623 | {
624 | status = MH_ERROR_NOT_INITIALIZED;
625 | }
626 |
627 | LeaveSpinLock();
628 |
629 | return status;
630 | }
631 |
632 | //-------------------------------------------------------------------------
633 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget)
634 | {
635 | MH_STATUS status = MH_OK;
636 |
637 | EnterSpinLock();
638 |
639 | if (g_hHeap != NULL)
640 | {
641 | UINT pos = FindHookEntry(pTarget);
642 | if (pos != INVALID_HOOK_POS)
643 | {
644 | if (g_hooks.pItems[pos].isEnabled)
645 | {
646 | FROZEN_THREADS threads;
647 | Freeze(&threads, pos, ACTION_DISABLE);
648 |
649 | status = EnableHookLL(pos, FALSE);
650 |
651 | Unfreeze(&threads);
652 | }
653 |
654 | if (status == MH_OK)
655 | {
656 | FreeBuffer(g_hooks.pItems[pos].pTrampoline);
657 | DeleteHookEntry(pos);
658 | }
659 | }
660 | else
661 | {
662 | status = MH_ERROR_NOT_CREATED;
663 | }
664 | }
665 | else
666 | {
667 | status = MH_ERROR_NOT_INITIALIZED;
668 | }
669 |
670 | LeaveSpinLock();
671 |
672 | return status;
673 | }
674 |
675 | //-------------------------------------------------------------------------
676 | static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable)
677 | {
678 | MH_STATUS status = MH_OK;
679 |
680 | EnterSpinLock();
681 |
682 | if (g_hHeap != NULL)
683 | {
684 | if (pTarget == MH_ALL_HOOKS)
685 | {
686 | status = EnableAllHooksLL(enable);
687 | }
688 | else
689 | {
690 | FROZEN_THREADS threads;
691 | UINT pos = FindHookEntry(pTarget);
692 | if (pos != INVALID_HOOK_POS)
693 | {
694 | if (g_hooks.pItems[pos].isEnabled != enable)
695 | {
696 | Freeze(&threads, pos, ACTION_ENABLE);
697 |
698 | status = EnableHookLL(pos, enable);
699 |
700 | Unfreeze(&threads);
701 | }
702 | else
703 | {
704 | status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED;
705 | }
706 | }
707 | else
708 | {
709 | status = MH_ERROR_NOT_CREATED;
710 | }
711 | }
712 | }
713 | else
714 | {
715 | status = MH_ERROR_NOT_INITIALIZED;
716 | }
717 |
718 | LeaveSpinLock();
719 |
720 | return status;
721 | }
722 |
723 | //-------------------------------------------------------------------------
724 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget)
725 | {
726 | return EnableHook(pTarget, TRUE);
727 | }
728 |
729 | //-------------------------------------------------------------------------
730 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget)
731 | {
732 | return EnableHook(pTarget, FALSE);
733 | }
734 |
735 | //-------------------------------------------------------------------------
736 | static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable)
737 | {
738 | MH_STATUS status = MH_OK;
739 |
740 | EnterSpinLock();
741 |
742 | if (g_hHeap != NULL)
743 | {
744 | if (pTarget == MH_ALL_HOOKS)
745 | {
746 | UINT i;
747 | for (i = 0; i < g_hooks.size; ++i)
748 | g_hooks.pItems[i].queueEnable = queueEnable;
749 | }
750 | else
751 | {
752 | UINT pos = FindHookEntry(pTarget);
753 | if (pos != INVALID_HOOK_POS)
754 | {
755 | g_hooks.pItems[pos].queueEnable = queueEnable;
756 | }
757 | else
758 | {
759 | status = MH_ERROR_NOT_CREATED;
760 | }
761 | }
762 | }
763 | else
764 | {
765 | status = MH_ERROR_NOT_INITIALIZED;
766 | }
767 |
768 | LeaveSpinLock();
769 |
770 | return status;
771 | }
772 |
773 | //-------------------------------------------------------------------------
774 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget)
775 | {
776 | return QueueHook(pTarget, TRUE);
777 | }
778 |
779 | //-------------------------------------------------------------------------
780 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget)
781 | {
782 | return QueueHook(pTarget, FALSE);
783 | }
784 |
785 | //-------------------------------------------------------------------------
786 | MH_STATUS WINAPI MH_ApplyQueued(VOID)
787 | {
788 | MH_STATUS status = MH_OK;
789 | UINT i, first = INVALID_HOOK_POS;
790 |
791 | EnterSpinLock();
792 |
793 | if (g_hHeap != NULL)
794 | {
795 | for (i = 0; i < g_hooks.size; ++i)
796 | {
797 | if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable)
798 | {
799 | first = i;
800 | break;
801 | }
802 | }
803 |
804 | if (first != INVALID_HOOK_POS)
805 | {
806 | FROZEN_THREADS threads;
807 | Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED);
808 |
809 | for (i = first; i < g_hooks.size; ++i)
810 | {
811 | PHOOK_ENTRY pHook = &g_hooks.pItems[i];
812 | if (pHook->isEnabled != pHook->queueEnable)
813 | {
814 | status = EnableHookLL(i, pHook->queueEnable);
815 | if (status != MH_OK)
816 | break;
817 | }
818 | }
819 |
820 | Unfreeze(&threads);
821 | }
822 | }
823 | else
824 | {
825 | status = MH_ERROR_NOT_INITIALIZED;
826 | }
827 |
828 | LeaveSpinLock();
829 |
830 | return status;
831 | }
832 |
833 | //-------------------------------------------------------------------------
834 | MH_STATUS WINAPI MH_CreateHookApiEx(
835 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour,
836 | LPVOID *ppOriginal, LPVOID *ppTarget)
837 | {
838 | HMODULE hModule;
839 | LPVOID pTarget;
840 |
841 | hModule = GetModuleHandleW(pszModule);
842 | if (hModule == NULL)
843 | return MH_ERROR_MODULE_NOT_FOUND;
844 |
845 | pTarget = (LPVOID)GetProcAddress(hModule, pszProcName);
846 | if (pTarget == NULL)
847 | return MH_ERROR_FUNCTION_NOT_FOUND;
848 |
849 | if(ppTarget != NULL)
850 | *ppTarget = pTarget;
851 |
852 | return MH_CreateHook(pTarget, pDetour, ppOriginal);
853 | }
854 |
855 | //-------------------------------------------------------------------------
856 | MH_STATUS WINAPI MH_CreateHookApi(
857 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal)
858 | {
859 | return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL);
860 | }
861 |
862 | //-------------------------------------------------------------------------
863 | const char * WINAPI MH_StatusToString(MH_STATUS status)
864 | {
865 | #define MH_ST2STR(x) \
866 | case x: \
867 | return #x;
868 |
869 | switch (status) {
870 | MH_ST2STR(MH_UNKNOWN)
871 | MH_ST2STR(MH_OK)
872 | MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED)
873 | MH_ST2STR(MH_ERROR_NOT_INITIALIZED)
874 | MH_ST2STR(MH_ERROR_ALREADY_CREATED)
875 | MH_ST2STR(MH_ERROR_NOT_CREATED)
876 | MH_ST2STR(MH_ERROR_ENABLED)
877 | MH_ST2STR(MH_ERROR_DISABLED)
878 | MH_ST2STR(MH_ERROR_NOT_EXECUTABLE)
879 | MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION)
880 | MH_ST2STR(MH_ERROR_MEMORY_ALLOC)
881 | MH_ST2STR(MH_ERROR_MEMORY_PROTECT)
882 | MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND)
883 | MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND)
884 | }
885 |
886 | #undef MH_ST2STR
887 |
888 | return "(unknown)";
889 | }
890 |
--------------------------------------------------------------------------------
/src/minhook/src/trampoline.c:
--------------------------------------------------------------------------------
1 | /*
2 | * MinHook - The Minimalistic API Hooking Library for x64/x86
3 | * Copyright (C) 2009-2017 Tsuda Kageyu.
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | *
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | #include
30 |
31 | #ifndef ARRAYSIZE
32 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
33 | #endif
34 |
35 | #if defined(_M_X64) || defined(__x86_64__)
36 | #include "./hde/hde64.h"
37 | typedef hde64s HDE;
38 | #define HDE_DISASM(code, hs) hde64_disasm(code, hs)
39 | #else
40 | #include "./hde/hde32.h"
41 | typedef hde32s HDE;
42 | #define HDE_DISASM(code, hs) hde32_disasm(code, hs)
43 | #endif
44 |
45 | #include "trampoline.h"
46 | #include "buffer.h"
47 |
48 | // Maximum size of a trampoline function.
49 | #if defined(_M_X64) || defined(__x86_64__)
50 | #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS))
51 | #else
52 | #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE
53 | #endif
54 |
55 | //-------------------------------------------------------------------------
56 | static BOOL IsCodePadding(LPBYTE pInst, UINT size)
57 | {
58 | UINT i;
59 |
60 | if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC)
61 | return FALSE;
62 |
63 | for (i = 1; i < size; ++i)
64 | {
65 | if (pInst[i] != pInst[0])
66 | return FALSE;
67 | }
68 | return TRUE;
69 | }
70 |
71 | //-------------------------------------------------------------------------
72 | BOOL CreateTrampolineFunction(PTRAMPOLINE ct)
73 | {
74 | #if defined(_M_X64) || defined(__x86_64__)
75 | CALL_ABS call = {
76 | 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8]
77 | 0xEB, 0x08, // EB 08: JMP +10
78 | 0x0000000000000000ULL // Absolute destination address
79 | };
80 | JMP_ABS jmp = {
81 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
82 | 0x0000000000000000ULL // Absolute destination address
83 | };
84 | JCC_ABS jcc = {
85 | 0x70, 0x0E, // 7* 0E: J** +16
86 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
87 | 0x0000000000000000ULL // Absolute destination address
88 | };
89 | #else
90 | CALL_REL call = {
91 | 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx
92 | 0x00000000 // Relative destination address
93 | };
94 | JMP_REL jmp = {
95 | 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx
96 | 0x00000000 // Relative destination address
97 | };
98 | JCC_REL jcc = {
99 | 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx
100 | 0x00000000 // Relative destination address
101 | };
102 | #endif
103 |
104 | UINT8 oldPos = 0;
105 | UINT8 newPos = 0;
106 | ULONG_PTR jmpDest = 0; // Destination address of an internal jump.
107 | BOOL finished = FALSE; // Is the function completed?
108 | #if defined(_M_X64) || defined(__x86_64__)
109 | UINT8 instBuf[16];
110 | #endif
111 |
112 | ct->patchAbove = FALSE;
113 | ct->nIP = 0;
114 |
115 | do
116 | {
117 | HDE hs;
118 | UINT copySize;
119 | LPVOID pCopySrc;
120 | ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos;
121 | ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos;
122 |
123 | copySize = HDE_DISASM((LPVOID)pOldInst, &hs);
124 | if (hs.flags & F_ERROR)
125 | return FALSE;
126 |
127 | pCopySrc = (LPVOID)pOldInst;
128 | if (oldPos >= sizeof(JMP_REL))
129 | {
130 | // The trampoline function is long enough.
131 | // Complete the function with the jump to the target function.
132 | #if defined(_M_X64) || defined(__x86_64__)
133 | jmp.address = pOldInst;
134 | #else
135 | jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp)));
136 | #endif
137 | pCopySrc = &jmp;
138 | copySize = sizeof(jmp);
139 |
140 | finished = TRUE;
141 | }
142 | #if defined(_M_X64) || defined(__x86_64__)
143 | else if ((hs.modrm & 0xC7) == 0x05)
144 | {
145 | // Instructions using RIP relative addressing. (ModR/M = 00???101B)
146 |
147 | // Modify the RIP relative address.
148 | PUINT32 pRelAddr;
149 |
150 | // Avoid using memcpy to reduce the footprint.
151 | #ifndef _MSC_VER
152 | memcpy(instBuf, (LPBYTE)pOldInst, copySize);
153 | #else
154 | __movsb(instBuf, (LPBYTE)pOldInst, copySize);
155 | #endif
156 | pCopySrc = instBuf;
157 |
158 | // Relative address is stored at (instruction length - immediate value length - 4).
159 | pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4);
160 | *pRelAddr
161 | = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len));
162 |
163 | // Complete the function if JMP (FF /4).
164 | if (hs.opcode == 0xFF && hs.modrm_reg == 4)
165 | finished = TRUE;
166 | }
167 | #endif
168 | else if (hs.opcode == 0xE8)
169 | {
170 | // Direct relative CALL
171 | ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32;
172 | #if defined(_M_X64) || defined(__x86_64__)
173 | call.address = dest;
174 | #else
175 | call.operand = (UINT32)(dest - (pNewInst + sizeof(call)));
176 | #endif
177 | pCopySrc = &call;
178 | copySize = sizeof(call);
179 | }
180 | else if ((hs.opcode & 0xFD) == 0xE9)
181 | {
182 | // Direct relative JMP (EB or E9)
183 | ULONG_PTR dest = pOldInst + hs.len;
184 |
185 | if (hs.opcode == 0xEB) // isShort jmp
186 | dest += (INT8)hs.imm.imm8;
187 | else
188 | dest += (INT32)hs.imm.imm32;
189 |
190 | // Simply copy an internal jump.
191 | if ((ULONG_PTR)ct->pTarget <= dest
192 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
193 | {
194 | if (jmpDest < dest)
195 | jmpDest = dest;
196 | }
197 | else
198 | {
199 | #if defined(_M_X64) || defined(__x86_64__)
200 | jmp.address = dest;
201 | #else
202 | jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp)));
203 | #endif
204 | pCopySrc = &jmp;
205 | copySize = sizeof(jmp);
206 |
207 | // Exit the function If it is not in the branch
208 | finished = (pOldInst >= jmpDest);
209 | }
210 | }
211 | else if ((hs.opcode & 0xF0) == 0x70
212 | || (hs.opcode & 0xFC) == 0xE0
213 | || (hs.opcode2 & 0xF0) == 0x80)
214 | {
215 | // Direct relative Jcc
216 | ULONG_PTR dest = pOldInst + hs.len;
217 |
218 | if ((hs.opcode & 0xF0) == 0x70 // Jcc
219 | || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ
220 | dest += (INT8)hs.imm.imm8;
221 | else
222 | dest += (INT32)hs.imm.imm32;
223 |
224 | // Simply copy an internal jump.
225 | if ((ULONG_PTR)ct->pTarget <= dest
226 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
227 | {
228 | if (jmpDest < dest)
229 | jmpDest = dest;
230 | }
231 | else if ((hs.opcode & 0xFC) == 0xE0)
232 | {
233 | // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported.
234 | return FALSE;
235 | }
236 | else
237 | {
238 | UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F);
239 | #if defined(_M_X64) || defined(__x86_64__)
240 | // Invert the condition in x64 mode to simplify the conditional jump logic.
241 | jcc.opcode = 0x71 ^ cond;
242 | jcc.address = dest;
243 | #else
244 | jcc.opcode1 = 0x80 | cond;
245 | jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc)));
246 | #endif
247 | pCopySrc = &jcc;
248 | copySize = sizeof(jcc);
249 | }
250 | }
251 | else if ((hs.opcode & 0xFE) == 0xC2)
252 | {
253 | // RET (C2 or C3)
254 |
255 | // Complete the function if not in a branch.
256 | finished = (pOldInst >= jmpDest);
257 | }
258 |
259 | // Can't alter the instruction length in a branch.
260 | if (pOldInst < jmpDest && copySize != hs.len)
261 | return FALSE;
262 |
263 | // Trampoline function is too large.
264 | if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE)
265 | return FALSE;
266 |
267 | // Trampoline function has too many instructions.
268 | if (ct->nIP >= ARRAYSIZE(ct->oldIPs))
269 | return FALSE;
270 |
271 | ct->oldIPs[ct->nIP] = oldPos;
272 | ct->newIPs[ct->nIP] = newPos;
273 | ct->nIP++;
274 |
275 | // Avoid using memcpy to reduce the footprint.
276 | #ifndef _MSC_VER
277 | memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
278 | #else
279 | __movsb((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
280 | #endif
281 | newPos += copySize;
282 | oldPos += hs.len;
283 | }
284 | while (!finished);
285 |
286 | // Is there enough place for a long jump?
287 | if (oldPos < sizeof(JMP_REL)
288 | && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos))
289 | {
290 | // Is there enough place for a short jump?
291 | if (oldPos < sizeof(JMP_REL_SHORT)
292 | && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos))
293 | {
294 | return FALSE;
295 | }
296 |
297 | // Can we place the long jump above the function?
298 | if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL)))
299 | return FALSE;
300 |
301 | if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL)))
302 | return FALSE;
303 |
304 | ct->patchAbove = TRUE;
305 | }
306 |
307 | #if defined(_M_X64) || defined(__x86_64__)
308 | // Create a relay function.
309 | jmp.address = (ULONG_PTR)ct->pDetour;
310 |
311 | ct->pRelay = (LPBYTE)ct->pTrampoline + newPos;
312 | memcpy(ct->pRelay, &jmp, sizeof(jmp));
313 | #endif
314 |
315 | return TRUE;
316 | }
317 |
--------------------------------------------------------------------------------
/src/minhook/src/trampoline.h:
--------------------------------------------------------------------------------
1 | /*
2 | * MinHook - The Minimalistic API Hooking Library for x64/x86
3 | * Copyright (C) 2009-2017 Tsuda Kageyu.
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions
8 | * are met:
9 | *
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | #pragma once
30 |
31 | #pragma pack(push, 1)
32 |
33 | // Structs for writing x86/x64 instructions.
34 |
35 | // 8-bit relative jump.
36 | typedef struct _JMP_REL_SHORT
37 | {
38 | UINT8 opcode; // EB xx: JMP +2+xx
39 | UINT8 operand;
40 | } JMP_REL_SHORT, *PJMP_REL_SHORT;
41 |
42 | // 32-bit direct relative jump/call.
43 | typedef struct _JMP_REL
44 | {
45 | UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx
46 | UINT32 operand; // Relative destination address
47 | } JMP_REL, *PJMP_REL, CALL_REL;
48 |
49 | // 64-bit indirect absolute jump.
50 | typedef struct _JMP_ABS
51 | {
52 | UINT8 opcode0; // FF25 00000000: JMP [+6]
53 | UINT8 opcode1;
54 | UINT32 dummy;
55 | UINT64 address; // Absolute destination address
56 | } JMP_ABS, *PJMP_ABS;
57 |
58 | // 64-bit indirect absolute call.
59 | typedef struct _CALL_ABS
60 | {
61 | UINT8 opcode0; // FF15 00000002: CALL [+6]
62 | UINT8 opcode1;
63 | UINT32 dummy0;
64 | UINT8 dummy1; // EB 08: JMP +10
65 | UINT8 dummy2;
66 | UINT64 address; // Absolute destination address
67 | } CALL_ABS;
68 |
69 | // 32-bit direct relative conditional jumps.
70 | typedef struct _JCC_REL
71 | {
72 | UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx
73 | UINT8 opcode1;
74 | UINT32 operand; // Relative destination address
75 | } JCC_REL;
76 |
77 | // 64bit indirect absolute conditional jumps that x64 lacks.
78 | typedef struct _JCC_ABS
79 | {
80 | UINT8 opcode; // 7* 0E: J** +16
81 | UINT8 dummy0;
82 | UINT8 dummy1; // FF25 00000000: JMP [+6]
83 | UINT8 dummy2;
84 | UINT32 dummy3;
85 | UINT64 address; // Absolute destination address
86 | } JCC_ABS;
87 |
88 | #pragma pack(pop)
89 |
90 | typedef struct _TRAMPOLINE
91 | {
92 | LPVOID pTarget; // [In] Address of the target function.
93 | LPVOID pDetour; // [In] Address of the detour function.
94 | LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function.
95 |
96 | #if defined(_M_X64) || defined(__x86_64__)
97 | LPVOID pRelay; // [Out] Address of the relay function.
98 | #endif
99 | BOOL patchAbove; // [Out] Should use the hot patch area?
100 | UINT nIP; // [Out] Number of the instruction boundaries.
101 | UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function.
102 | UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function.
103 | } TRAMPOLINE, *PTRAMPOLINE;
104 |
105 | BOOL CreateTrampolineFunction(PTRAMPOLINE ct);
106 |
--------------------------------------------------------------------------------
/src/shim/avifil32.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "../main.h"
3 |
4 | static HMODULE g_hModule = NULL;
5 |
6 | extern "C" {
7 | FARPROC O_AVIBuildFilter;
8 | FARPROC O_AVIBuildFilterA;
9 | FARPROC O_AVIBuildFilterW;
10 | FARPROC O_AVIClearClipboard;
11 | FARPROC O_AVIFileAddRef;
12 | FARPROC O_AVIFileCreateStream;
13 | FARPROC O_AVIFileCreateStreamA;
14 | FARPROC O_AVIFileCreateStreamW;
15 | FARPROC O_AVIFileEndRecord;
16 | FARPROC O_AVIFileExit;
17 | FARPROC O_AVIFileGetStream;
18 | FARPROC O_AVIFileInfo;
19 | FARPROC O_AVIFileInfoA;
20 | FARPROC O_AVIFileInfoW;
21 | FARPROC O_AVIFileInit;
22 | FARPROC O_AVIFileOpen;
23 | FARPROC O_AVIFileOpenA;
24 | FARPROC O_AVIFileOpenW;
25 | FARPROC O_AVIFileReadData;
26 | FARPROC O_AVIFileRelease;
27 | FARPROC O_AVIFileWriteData;
28 | FARPROC O_AVIGetFromClipboard;
29 | FARPROC O_AVIMakeCompressedStream;
30 | FARPROC O_AVIMakeFileFromStreams;
31 | FARPROC O_AVIMakeStreamFromClipboard;
32 | FARPROC O_AVIPutFileOnClipboard;
33 | FARPROC O_AVISave;
34 | FARPROC O_AVISaveA;
35 | FARPROC O_AVISaveOptions;
36 | FARPROC O_AVISaveOptionsFree;
37 | FARPROC O_AVISaveV;
38 | FARPROC O_AVISaveVA;
39 | FARPROC O_AVISaveVW;
40 | FARPROC O_AVISaveW;
41 | FARPROC O_AVIStreamAddRef;
42 | FARPROC O_AVIStreamBeginStreaming;
43 | FARPROC O_AVIStreamCreate;
44 | FARPROC O_AVIStreamEndStreaming;
45 | FARPROC O_AVIStreamFindSample;
46 | FARPROC O_AVIStreamGetFrame;
47 | FARPROC O_AVIStreamGetFrameClose;
48 | FARPROC O_AVIStreamGetFrameOpen;
49 | FARPROC O_AVIStreamInfo;
50 | FARPROC O_AVIStreamInfoA;
51 | FARPROC O_AVIStreamInfoW;
52 | FARPROC O_AVIStreamLength;
53 | FARPROC O_AVIStreamOpenFromFile;
54 | FARPROC O_AVIStreamOpenFromFileA;
55 | FARPROC O_AVIStreamOpenFromFileW;
56 | FARPROC O_AVIStreamRead;
57 | FARPROC O_AVIStreamReadData;
58 | FARPROC O_AVIStreamReadFormat;
59 | FARPROC O_AVIStreamRelease;
60 | FARPROC O_AVIStreamSampleToTime;
61 | FARPROC O_AVIStreamSetFormat;
62 | FARPROC O_AVIStreamStart;
63 | FARPROC O_AVIStreamTimeToSample;
64 | FARPROC O_AVIStreamWrite;
65 | FARPROC O_AVIStreamWriteData;
66 | FARPROC O_CreateEditableStream;
67 | FARPROC O_DllCanUnloadNow;
68 | FARPROC O_DllGetClassObject;
69 | FARPROC O_EditStreamClone;
70 | FARPROC O_EditStreamCopy;
71 | FARPROC O_EditStreamCut;
72 | FARPROC O_EditStreamPaste;
73 | FARPROC O_EditStreamSetInfo;
74 | FARPROC O_EditStreamSetInfoA;
75 | FARPROC O_EditStreamSetInfoW;
76 | FARPROC O_EditStreamSetName;
77 | FARPROC O_EditStreamSetNameA;
78 | FARPROC O_EditStreamSetNameW;
79 | FARPROC O_IID_IAVIEditStream;
80 | FARPROC O_IID_IAVIFile;
81 | FARPROC O_IID_IAVIStream;
82 | FARPROC O_IID_IGetFrame;
83 | }
84 |
85 | static void PopulateAddresses() {
86 | O_AVIBuildFilter = GetProcAddress(g_hModule, "AVIBuildFilter");
87 | O_AVIBuildFilterA = GetProcAddress(g_hModule, "AVIBuildFilterA");
88 | O_AVIBuildFilterW = GetProcAddress(g_hModule, "AVIBuildFilterW");
89 | O_AVIClearClipboard = GetProcAddress(g_hModule, "AVIClearClipboard");
90 | O_AVIFileAddRef = GetProcAddress(g_hModule, "AVIFileAddRef");
91 | O_AVIFileCreateStream = GetProcAddress(g_hModule, "AVIFileCreateStream");
92 | O_AVIFileCreateStreamA = GetProcAddress(g_hModule, "AVIFileCreateStreamA");
93 | O_AVIFileCreateStreamW = GetProcAddress(g_hModule, "AVIFileCreateStreamW");
94 | O_AVIFileEndRecord = GetProcAddress(g_hModule, "AVIFileEndRecord");
95 | O_AVIFileExit = GetProcAddress(g_hModule, "AVIFileExit");
96 | O_AVIFileGetStream = GetProcAddress(g_hModule, "AVIFileGetStream");
97 | O_AVIFileInfo = GetProcAddress(g_hModule, "AVIFileInfo");
98 | O_AVIFileInfoA = GetProcAddress(g_hModule, "AVIFileInfoA");
99 | O_AVIFileInfoW = GetProcAddress(g_hModule, "AVIFileInfoW");
100 | O_AVIFileInit = GetProcAddress(g_hModule, "AVIFileInit");
101 | O_AVIFileOpen = GetProcAddress(g_hModule, "AVIFileOpen");
102 | O_AVIFileOpenA = GetProcAddress(g_hModule, "AVIFileOpenA");
103 | O_AVIFileOpenW = GetProcAddress(g_hModule, "AVIFileOpenW");
104 | O_AVIFileReadData = GetProcAddress(g_hModule, "AVIFileReadData");
105 | O_AVIFileRelease = GetProcAddress(g_hModule, "AVIFileRelease");
106 | O_AVIFileWriteData = GetProcAddress(g_hModule, "AVIFileWriteData");
107 | O_AVIGetFromClipboard = GetProcAddress(g_hModule, "AVIGetFromClipboard");
108 | O_AVIMakeCompressedStream = GetProcAddress(g_hModule, "AVIMakeCompressedStream");
109 | O_AVIMakeFileFromStreams = GetProcAddress(g_hModule, "AVIMakeFileFromStreams");
110 | O_AVIMakeStreamFromClipboard = GetProcAddress(g_hModule, "AVIMakeStreamFromClipboard");
111 | O_AVIPutFileOnClipboard = GetProcAddress(g_hModule, "AVIPutFileOnClipboard");
112 | O_AVISave = GetProcAddress(g_hModule, "AVISave");
113 | O_AVISaveA = GetProcAddress(g_hModule, "AVISaveA");
114 | O_AVISaveOptions = GetProcAddress(g_hModule, "AVISaveOptions");
115 | O_AVISaveOptionsFree = GetProcAddress(g_hModule, "AVISaveOptionsFree");
116 | O_AVISaveV = GetProcAddress(g_hModule, "AVISaveV");
117 | O_AVISaveVA = GetProcAddress(g_hModule, "AVISaveVA");
118 | O_AVISaveVW = GetProcAddress(g_hModule, "AVISaveVW");
119 | O_AVISaveW = GetProcAddress(g_hModule, "AVISaveW");
120 | O_AVIStreamAddRef = GetProcAddress(g_hModule, "AVIStreamAddRef");
121 | O_AVIStreamBeginStreaming = GetProcAddress(g_hModule, "AVIStreamBeginStreaming");
122 | O_AVIStreamCreate = GetProcAddress(g_hModule, "AVIStreamCreate");
123 | O_AVIStreamEndStreaming = GetProcAddress(g_hModule, "AVIStreamEndStreaming");
124 | O_AVIStreamFindSample = GetProcAddress(g_hModule, "AVIStreamFindSample");
125 | O_AVIStreamGetFrame = GetProcAddress(g_hModule, "AVIStreamGetFrame");
126 | O_AVIStreamGetFrameClose = GetProcAddress(g_hModule, "AVIStreamGetFrameClose");
127 | O_AVIStreamGetFrameOpen = GetProcAddress(g_hModule, "AVIStreamGetFrameOpen");
128 | O_AVIStreamInfo = GetProcAddress(g_hModule, "AVIStreamInfo");
129 | O_AVIStreamInfoA = GetProcAddress(g_hModule, "AVIStreamInfoA");
130 | O_AVIStreamInfoW = GetProcAddress(g_hModule, "AVIStreamInfoW");
131 | O_AVIStreamLength = GetProcAddress(g_hModule, "AVIStreamLength");
132 | O_AVIStreamOpenFromFile = GetProcAddress(g_hModule, "AVIStreamOpenFromFile");
133 | O_AVIStreamOpenFromFileA = GetProcAddress(g_hModule, "AVIStreamOpenFromFileA");
134 | O_AVIStreamOpenFromFileW = GetProcAddress(g_hModule, "AVIStreamOpenFromFileW");
135 | O_AVIStreamRead = GetProcAddress(g_hModule, "AVIStreamRead");
136 | O_AVIStreamReadData = GetProcAddress(g_hModule, "AVIStreamReadData");
137 | O_AVIStreamReadFormat = GetProcAddress(g_hModule, "AVIStreamReadFormat");
138 | O_AVIStreamRelease = GetProcAddress(g_hModule, "AVIStreamRelease");
139 | O_AVIStreamSampleToTime = GetProcAddress(g_hModule, "AVIStreamSampleToTime");
140 | O_AVIStreamSetFormat = GetProcAddress(g_hModule, "AVIStreamSetFormat");
141 | O_AVIStreamStart = GetProcAddress(g_hModule, "AVIStreamStart");
142 | O_AVIStreamTimeToSample = GetProcAddress(g_hModule, "AVIStreamTimeToSample");
143 | O_AVIStreamWrite = GetProcAddress(g_hModule, "AVIStreamWrite");
144 | O_AVIStreamWriteData = GetProcAddress(g_hModule, "AVIStreamWriteData");
145 | O_CreateEditableStream = GetProcAddress(g_hModule, "CreateEditableStream");
146 | O_DllCanUnloadNow = GetProcAddress(g_hModule, "DllCanUnloadNow");
147 | O_DllGetClassObject = GetProcAddress(g_hModule, "DllGetClassObject");
148 | O_EditStreamClone = GetProcAddress(g_hModule, "EditStreamClone");
149 | O_EditStreamCopy = GetProcAddress(g_hModule, "EditStreamCopy");
150 | O_EditStreamCut = GetProcAddress(g_hModule, "EditStreamCut");
151 | O_EditStreamPaste = GetProcAddress(g_hModule, "EditStreamPaste");
152 | O_EditStreamSetInfo = GetProcAddress(g_hModule, "EditStreamSetInfo");
153 | O_EditStreamSetInfoA = GetProcAddress(g_hModule, "EditStreamSetInfoA");
154 | O_EditStreamSetInfoW = GetProcAddress(g_hModule, "EditStreamSetInfoW");
155 | O_EditStreamSetName = GetProcAddress(g_hModule, "EditStreamSetName");
156 | O_EditStreamSetNameA = GetProcAddress(g_hModule, "EditStreamSetNameA");
157 | O_EditStreamSetNameW = GetProcAddress(g_hModule, "EditStreamSetNameW");
158 | O_IID_IAVIEditStream = GetProcAddress(g_hModule, "IID_IAVIEditStream");
159 | O_IID_IAVIFile = GetProcAddress(g_hModule, "IID_IAVIFile");
160 | O_IID_IAVIStream = GetProcAddress(g_hModule, "IID_IAVIStream");
161 | O_IID_IGetFrame = GetProcAddress(g_hModule, "IID_IGetFrame");
162 | }
163 |
164 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
165 | if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
166 | // Load original DLL
167 | char path[MAX_PATH];
168 | GetSystemDirectoryA(path, MAX_PATH);
169 | strcat_s(path, "\\avifil32.dll");
170 | g_hModule = LoadLibraryA(path);
171 | if (!g_hModule) return FALSE;
172 |
173 | // Retrieve exported function pointers
174 | PopulateAddresses();
175 |
176 | // Call entry point
177 | start();
178 | return TRUE;
179 | }
180 | else if (ul_reason_for_call == DLL_PROCESS_DETACH) {
181 | FreeLibrary(g_hModule);
182 | return TRUE;
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/src/shim/avifil32.def:
--------------------------------------------------------------------------------
1 | LIBRARY avifil32
2 |
3 | EXPORTS
4 |
5 | AVIBuildFilter = _AVIBuildFilter @1
6 | AVIBuildFilterA = _AVIBuildFilterA @2
7 | AVIBuildFilterW = _AVIBuildFilterW @3
8 | AVIClearClipboard = _AVIClearClipboard @4
9 | AVIFileAddRef = _AVIFileAddRef @5
10 | AVIFileCreateStream = _AVIFileCreateStream @6
11 | AVIFileCreateStreamA = _AVIFileCreateStreamA @7
12 | AVIFileCreateStreamW = _AVIFileCreateStreamW @8
13 | AVIFileEndRecord = _AVIFileEndRecord @9
14 | AVIFileExit = _AVIFileExit @10
15 | AVIFileGetStream = _AVIFileGetStream @11
16 | AVIFileInfo = _AVIFileInfo @12
17 | AVIFileInfoA = _AVIFileInfoA @13
18 | AVIFileInfoW = _AVIFileInfoW @14
19 | AVIFileInit = _AVIFileInit @15
20 | AVIFileOpen = _AVIFileOpen @16
21 | AVIFileOpenA = _AVIFileOpenA @17
22 | AVIFileOpenW = _AVIFileOpenW @18
23 | AVIFileReadData = _AVIFileReadData @19
24 | AVIFileRelease = _AVIFileRelease @20
25 | AVIFileWriteData = _AVIFileWriteData @21
26 | AVIGetFromClipboard = _AVIGetFromClipboard @22
27 | AVIMakeCompressedStream = _AVIMakeCompressedStream @23
28 | AVIMakeFileFromStreams = _AVIMakeFileFromStreams @24
29 | AVIMakeStreamFromClipboard = _AVIMakeStreamFromClipboard @25
30 | AVIPutFileOnClipboard = _AVIPutFileOnClipboard @26
31 | AVISave = _AVISave @27
32 | AVISaveA = _AVISaveA @28
33 | AVISaveOptions = _AVISaveOptions @29
34 | AVISaveOptionsFree = _AVISaveOptionsFree @30
35 | AVISaveV = _AVISaveV @31
36 | AVISaveVA = _AVISaveVA @32
37 | AVISaveVW = _AVISaveVW @33
38 | AVISaveW = _AVISaveW @34
39 | AVIStreamAddRef = _AVIStreamAddRef @35
40 | AVIStreamBeginStreaming = _AVIStreamBeginStreaming @36
41 | AVIStreamCreate = _AVIStreamCreate @37
42 | AVIStreamEndStreaming = _AVIStreamEndStreaming @38
43 | AVIStreamFindSample = _AVIStreamFindSample @39
44 | AVIStreamGetFrame = _AVIStreamGetFrame @40
45 | AVIStreamGetFrameClose = _AVIStreamGetFrameClose @41
46 | AVIStreamGetFrameOpen = _AVIStreamGetFrameOpen @42
47 | AVIStreamInfo = _AVIStreamInfo @43
48 | AVIStreamInfoA = _AVIStreamInfoA @44
49 | AVIStreamInfoW = _AVIStreamInfoW @45
50 | AVIStreamLength = _AVIStreamLength @46
51 | AVIStreamOpenFromFile = _AVIStreamOpenFromFile @47
52 | AVIStreamOpenFromFileA = _AVIStreamOpenFromFileA @48
53 | AVIStreamOpenFromFileW = _AVIStreamOpenFromFileW @49
54 | AVIStreamRead = _AVIStreamRead @50
55 | AVIStreamReadData = _AVIStreamReadData @51
56 | AVIStreamReadFormat = _AVIStreamReadFormat @52
57 | AVIStreamRelease = _AVIStreamRelease @53
58 | AVIStreamSampleToTime = _AVIStreamSampleToTime @54
59 | AVIStreamSetFormat = _AVIStreamSetFormat @55
60 | AVIStreamStart = _AVIStreamStart @56
61 | AVIStreamTimeToSample = _AVIStreamTimeToSample @57
62 | AVIStreamWrite = _AVIStreamWrite @58
63 | AVIStreamWriteData = _AVIStreamWriteData @59
64 | CreateEditableStream = _CreateEditableStream @60
65 | EditStreamClone = _EditStreamClone @63
66 | EditStreamCopy = _EditStreamCopy @64
67 | EditStreamCut = _EditStreamCut @65
68 | EditStreamPaste = _EditStreamPaste @66
69 | EditStreamSetInfo = _EditStreamSetInfo @67
70 | EditStreamSetInfoA = _EditStreamSetInfoA @68
71 | EditStreamSetInfoW = _EditStreamSetInfoW @69
72 | EditStreamSetName = _EditStreamSetName @70
73 | EditStreamSetNameA = _EditStreamSetNameA @71
74 | EditStreamSetNameW = _EditStreamSetNameW @72
75 | IID_IAVIEditStream = _IID_IAVIEditStream @73
76 | IID_IAVIFile = _IID_IAVIFile @74
77 | IID_IAVIStream = _IID_IAVIStream @75
78 | IID_IGetFrame = _IID_IGetFrame @76
79 |
--------------------------------------------------------------------------------
/src/shim/avifil32_impl.asm:
--------------------------------------------------------------------------------
1 | shim MACRO fnName
2 | _&fnName& PROC
3 | EXTERN O_&fnName& : qword
4 | mov rax, O_&fnName&
5 | jmp rax
6 | _&fnName& ENDP
7 | PUBLIC _&fnName&
8 | ENDM
9 |
10 | .code
11 | shim AVIBuildFilter
12 | shim AVIBuildFilterA
13 | shim AVIBuildFilterW
14 | shim AVIClearClipboard
15 | shim AVIFileAddRef
16 | shim AVIFileCreateStream
17 | shim AVIFileCreateStreamA
18 | shim AVIFileCreateStreamW
19 | shim AVIFileEndRecord
20 | shim AVIFileExit
21 | shim AVIFileGetStream
22 | shim AVIFileInfo
23 | shim AVIFileInfoA
24 | shim AVIFileInfoW
25 | shim AVIFileInit
26 | shim AVIFileOpen
27 | shim AVIFileOpenA
28 | shim AVIFileOpenW
29 | shim AVIFileReadData
30 | shim AVIFileRelease
31 | shim AVIFileWriteData
32 | shim AVIGetFromClipboard
33 | shim AVIMakeCompressedStream
34 | shim AVIMakeFileFromStreams
35 | shim AVIMakeStreamFromClipboard
36 | shim AVIPutFileOnClipboard
37 | shim AVISave
38 | shim AVISaveA
39 | shim AVISaveOptions
40 | shim AVISaveOptionsFree
41 | shim AVISaveV
42 | shim AVISaveVA
43 | shim AVISaveVW
44 | shim AVISaveW
45 | shim AVIStreamAddRef
46 | shim AVIStreamBeginStreaming
47 | shim AVIStreamCreate
48 | shim AVIStreamEndStreaming
49 | shim AVIStreamFindSample
50 | shim AVIStreamGetFrame
51 | shim AVIStreamGetFrameClose
52 | shim AVIStreamGetFrameOpen
53 | shim AVIStreamInfo
54 | shim AVIStreamInfoA
55 | shim AVIStreamInfoW
56 | shim AVIStreamLength
57 | shim AVIStreamOpenFromFile
58 | shim AVIStreamOpenFromFileA
59 | shim AVIStreamOpenFromFileW
60 | shim AVIStreamRead
61 | shim AVIStreamReadData
62 | shim AVIStreamReadFormat
63 | shim AVIStreamRelease
64 | shim AVIStreamSampleToTime
65 | shim AVIStreamSetFormat
66 | shim AVIStreamStart
67 | shim AVIStreamTimeToSample
68 | shim AVIStreamWrite
69 | shim AVIStreamWriteData
70 | shim CreateEditableStream
71 | shim DllCanUnloadNow
72 | shim DllGetClassObject
73 | shim EditStreamClone
74 | shim EditStreamCopy
75 | shim EditStreamCut
76 | shim EditStreamPaste
77 | shim EditStreamSetInfo
78 | shim EditStreamSetInfoA
79 | shim EditStreamSetInfoW
80 | shim EditStreamSetName
81 | shim EditStreamSetNameA
82 | shim EditStreamSetNameW
83 | shim IID_IAVIEditStream
84 | shim IID_IAVIFile
85 | shim IID_IAVIStream
86 | shim IID_IGetFrame
87 |
88 | END
89 |
--------------------------------------------------------------------------------