├── Injector.vcxproj
├── Injector.vcxproj.filters
├── Injector.vcxproj.user
├── README.md
├── driver
├── Driver.cpp
└── Driver.h
├── includes.h
├── inject
├── Inject.cpp
└── Inject.h
├── main.cpp
├── showcase.gif
└── utils
├── lazy_importer.h
├── utils.h
└── xor.h
/Injector.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 | {b2d29888-2215-4b6c-b623-da991e6914ce}
25 | Injector
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v142
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 | true
75 |
76 |
77 | false
78 |
79 |
80 | true
81 |
82 |
83 | false
84 |
85 |
86 |
87 | Level3
88 | true
89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS
90 | true
91 |
92 |
93 | Console
94 | true
95 |
96 |
97 |
98 |
99 | Level3
100 | true
101 | true
102 | true
103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
104 | true
105 |
106 |
107 | Console
108 | true
109 | true
110 | true
111 |
112 |
113 |
114 |
115 | Level3
116 | true
117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS
118 | true
119 |
120 |
121 | Console
122 | true
123 |
124 |
125 |
126 |
127 | Level3
128 | true
129 | true
130 |
131 |
132 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS
133 | true
134 | MaxSpeed
135 | true
136 | stdcpp17
137 | false
138 |
139 |
140 | Console
141 | true
142 | true
143 | true
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/Injector.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 | {9a87fbbb-36a5-4d6d-8994-1b05f651b25c}
14 |
15 |
16 | {5676a617-28f7-4add-9dea-0056231826cc}
17 |
18 |
19 | {fc6c7489-c664-4f1c-83cd-f611b732931b}
20 |
21 |
22 |
23 |
24 | Driver
25 |
26 |
27 | Inject
28 |
29 |
30 | Source Files
31 |
32 |
33 |
34 |
35 | Utils
36 |
37 |
38 | Utils
39 |
40 |
41 | Utils
42 |
43 |
44 | Driver
45 |
46 |
47 | Inject
48 |
49 |
50 | Header Files
51 |
52 |
53 |
--------------------------------------------------------------------------------
/Injector.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Kernel-Manual-Map-Injector
2 |
3 | # What is this
4 | > This is a kenrel DLL injector using SetWinEventHook to call the Entry Point of the DLL
5 |
6 | # Will this work on EAC & BE protected games?
7 | > Yes it will. But dont think that will this be undetected without editing the code
8 |
9 | # I need help what do I do ?
10 | > You can add me on discord kidra#6986
11 | # Showcase
12 | 
13 | # Credits
14 |
15 | [Kernel Driver used](https://github.com/mactec0/Kernelmode-manual-mapping-through-IAT)
16 |
17 | [Shellcode (edited)](https://github.com/TheCruZ/Simple-Manual-Map-Injector)
18 |
--------------------------------------------------------------------------------
/driver/Driver.cpp:
--------------------------------------------------------------------------------
1 | #include "Driver.h"
2 |
3 | Driver::Driver(const wchar_t* driver_name, int target_process_id)
4 | {
5 | this->driver_handle = CreateFileW(driver_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
6 | this->target_process_id = target_process_id; // yes i am lazy
7 | }
8 | Driver::~Driver()
9 | {
10 | CloseHandle(driver_handle);
11 | }
12 | uintptr_t Driver::get_base_address(const wchar_t* process_name)
13 | {
14 | if (!driver_handle) return 0;
15 |
16 | k_get_base_module_request request;
17 | request.pid = target_process_id;
18 |
19 | memset(request.name, 0, sizeof(WCHAR) * 260);
20 | wcscpy(request.name, process_name);
21 | request.handle = 0; // Make Sure that it is 0 so it doesnt return another one
22 |
23 | DeviceIoControl(driver_handle, ioctl_get_module_base, &request, sizeof(k_get_base_module_request), &request, sizeof(k_get_base_module_request), 0, 0);
24 | return request.handle;
25 | }
26 |
27 | uintptr_t Driver::allocate_virtual_memory(int size, int allocation_type, int protect_type)
28 | {
29 | if (!driver_handle) return 0;
30 | k_alloc_mem_request request;
31 | request.pid = this->target_process_id;
32 | request.addr = (PVOID)(0);
33 | request.size = size;
34 | request.allocation_type = allocation_type;
35 | request.protect = protect_type;
36 | DeviceIoControl(driver_handle, ioctl_allocate_virtual_memory, &request, sizeof(k_alloc_mem_request), &request, sizeof(k_alloc_mem_request), 0, 0);
37 | return (uintptr_t)request.addr;
38 |
39 | }
40 | bool Driver::write_memory(uintptr_t destination, uintptr_t source, int size)
41 | {
42 | if (driver_handle == INVALID_HANDLE_VALUE) return 0;
43 | k_rw_request request;
44 | request.pid = this->target_process_id;
45 | request.dst = destination;
46 | request.src = source;
47 | request.size = size;
48 | return DeviceIoControl(driver_handle, ioctl_write_memory, &request, sizeof(k_rw_request), 0, 0, 0, 0);
49 | }
50 | bool Driver::read_memory(uintptr_t source, uintptr_t destination, int size)
51 | {
52 | if (driver_handle == INVALID_HANDLE_VALUE) return 0;
53 | k_rw_request request;
54 | request.pid = this->target_process_id;
55 | request.dst = destination;
56 | request.src = source;
57 | request.size = size;
58 | return DeviceIoControl(driver_handle, ioctl_read_memory, &request, sizeof(k_rw_request), 0, 0, 0, 0);
59 | }
60 |
61 | bool Driver::protect_virtual_memory(uintptr_t address, int size, int protect_type)
62 | {
63 | if (!driver_handle) return 0;
64 | k_protect_mem_request request;
65 | request.pid = this->target_process_id;
66 | request.addr = address;
67 | request.size = size;
68 | request.protect = protect_type;
69 | return DeviceIoControl(driver_handle, ioctl_protect_virutal_memory, &request, sizeof(k_protect_mem_request), &request, sizeof(k_protect_mem_request), 0, 0);
70 |
71 | }
--------------------------------------------------------------------------------
/driver/Driver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "../includes.h"
3 |
4 | class Driver
5 | {
6 | public:
7 | Driver(const wchar_t* driver_name, int target_process_id);
8 | ~Driver();
9 | uintptr_t get_base_address(const wchar_t* process_name);
10 | uintptr_t allocate_virtual_memory(int size, int allocation_type, int protect_type);
11 | bool protect_virtual_memory(uintptr_t address, int size, int protect_type);
12 | bool write_memory(uintptr_t destination, uintptr_t source, int size);
13 | bool read_memory(uintptr_t source, uintptr_t destination, int size);
14 | HANDLE driver_handle;
15 | int target_process_id;
16 | private:
17 |
18 | /*
19 | Driver Structs
20 | */
21 | typedef struct _k_get_base_module_request {
22 | ULONG pid;
23 | ULONGLONG handle;
24 | WCHAR name[260];
25 | } k_get_base_module_request, * pk_get_base_module_request;
26 |
27 | typedef struct _k_rw_request {
28 | ULONG pid;
29 | ULONGLONG src;
30 | ULONGLONG dst;
31 | ULONGLONG size;
32 | } k_rw_request, * pk_rw_request;
33 |
34 | typedef struct _k_alloc_mem_request {
35 | ULONG pid, allocation_type, protect;
36 | PVOID addr;
37 | SIZE_T size;
38 | } k_alloc_mem_request, * pk_alloc_mem_request;
39 |
40 | typedef struct _k_protect_mem_request {
41 | ULONG pid, protect;
42 | ULONGLONG addr;
43 | SIZE_T size;
44 | } k_protect_mem_request, * pk_protect_mem_request;
45 |
46 | /*
47 | Driver IOCTL codes
48 | */
49 | #define ioctl_read_memory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x093286, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
50 | #define ioctl_write_memory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x729823, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
51 | #define ioctl_get_module_base CTL_CODE(FILE_DEVICE_UNKNOWN, 0x461419, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
52 | #define ioctl_protect_virutal_memory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x433146, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
53 | #define ioctl_allocate_virtual_memory CTL_CODE(FILE_DEVICE_UNKNOWN, 0x523794, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
54 |
55 |
56 | };
57 |
--------------------------------------------------------------------------------
/includes.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "utils/lazy_importer.h"
8 | #include "utils/utils.h"
9 | #include "utils/xor.h"
10 | #include "Driver/Driver.h"
11 | #include "Inject/inject.h"
--------------------------------------------------------------------------------
/inject/Inject.cpp:
--------------------------------------------------------------------------------
1 | #include "Inject.h"
2 | /*
3 | !!!IMPORTANT!!! for this to work correctly please disable Security Check (/GS-)
4 | */
5 | #define RELOC_FLAG64(RelInfo) ((RelInfo >> 0x0C) == IMAGE_REL_BASED_DIR64)
6 |
7 | //keep this
8 | #pragma runtime_checks( "", off )
9 | #pragma optimize( "", off )
10 | void __stdcall shellcode()
11 | {
12 | uintptr_t base = 0x15846254168; // random
13 | uintptr_t pointer_address = 0x24856841253; // random
14 |
15 | memset((void*)pointer_address, 0x69, 1);
16 |
17 | BYTE* pBase = (BYTE*)base;
18 | auto* pOpt = &reinterpret_cast(pBase + reinterpret_cast((uintptr_t)pBase)->e_lfanew)->OptionalHeader;
19 |
20 | auto _LoadLibraryA = LI_FN(LoadLibraryA).get();
21 | auto _GetProcAddress = LI_FN(GetProcAddress).get();
22 | auto _RtlAddFunctionTable = LI_FN(RtlAddFunctionTable).get();
23 |
24 | auto _DllMain = reinterpret_cast(pBase + pOpt->AddressOfEntryPoint);
25 |
26 | BYTE* LocationDelta = pBase - pOpt->ImageBase;
27 | if (LocationDelta) {
28 | if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) {
29 | auto* pRelocData = reinterpret_cast(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
30 | const auto* pRelocEnd = reinterpret_cast(reinterpret_cast(pRelocData) + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
31 | while (pRelocData < pRelocEnd && pRelocData->SizeOfBlock) {
32 | UINT AmountOfEntries = (pRelocData->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
33 | WORD* pRelativeInfo = reinterpret_cast(pRelocData + 1);
34 |
35 | for (UINT i = 0; i != AmountOfEntries; ++i, ++pRelativeInfo) {
36 | if (RELOC_FLAG64(*pRelativeInfo)) {
37 | UINT_PTR* pPatch = reinterpret_cast(pBase + pRelocData->VirtualAddress + ((*pRelativeInfo) & 0xFFF));
38 | *pPatch += reinterpret_cast(LocationDelta);
39 | }
40 | }
41 | pRelocData = reinterpret_cast(reinterpret_cast(pRelocData) + pRelocData->SizeOfBlock);
42 | }
43 | }
44 | }
45 |
46 | if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) {
47 | auto* pImportDescr = reinterpret_cast(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
48 | while (pImportDescr->Name) {
49 | char* szMod = reinterpret_cast(pBase + pImportDescr->Name);
50 | HINSTANCE hDll = _LoadLibraryA(szMod);
51 |
52 | ULONG_PTR* pThunkRef = reinterpret_cast(pBase + pImportDescr->OriginalFirstThunk);
53 | ULONG_PTR* pFuncRef = reinterpret_cast(pBase + pImportDescr->FirstThunk);
54 |
55 | if (!pThunkRef)
56 | pThunkRef = pFuncRef;
57 |
58 | for (; *pThunkRef; ++pThunkRef, ++pFuncRef) {
59 | if (IMAGE_SNAP_BY_ORDINAL(*pThunkRef)) {
60 | *pFuncRef = (ULONG_PTR)_GetProcAddress(hDll, reinterpret_cast(*pThunkRef & 0xFFFF));
61 | }
62 | else {
63 | auto* pImport = reinterpret_cast(pBase + (*pThunkRef));
64 | *pFuncRef = (ULONG_PTR)_GetProcAddress(hDll, pImport->Name);
65 | }
66 | }
67 | ++pImportDescr;
68 | }
69 | }
70 |
71 | if (pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size) {
72 | auto* pTLS = reinterpret_cast(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
73 | auto* pCallback = reinterpret_cast(pTLS->AddressOfCallBacks);
74 | for (; pCallback && *pCallback; ++pCallback)
75 | (*pCallback)(pBase, DLL_PROCESS_ATTACH, nullptr);
76 | }
77 |
78 |
79 | //SEH SUPPORT
80 | auto excep = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
81 | if (excep.Size) {
82 | if (!_RtlAddFunctionTable(
83 | reinterpret_cast(pBase + excep.VirtualAddress),
84 | excep.Size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY), (DWORD64)pBase)) {
85 | }
86 | }
87 |
88 | _DllMain(pBase, DLL_PROCESS_ATTACH, 0);
89 | }
90 |
91 |
92 | bool Inject::inject_module_from_path_to_process_by_name(const wchar_t* module_path, const wchar_t* process_name)
93 | {
94 | int target_process_id = utils::get_pid_from_name(process_name);
95 |
96 | if (!target_process_id)
97 | {
98 | printf(xor_a("Target Process not found!\n"));
99 | return false;
100 | }
101 |
102 | printf(xor_a("Target Process Id is : %i\n"), target_process_id);
103 |
104 | auto target_process_hwnd = utils::get_hwnd_of_process_id(target_process_id); // HWND needed for hook
105 | auto nt_dll = LoadLibraryA(xor_a("ntdll.dll"));
106 | auto thread_id = GetWindowThreadProcessId(target_process_hwnd, 0); // also needed for hook
107 |
108 |
109 | uintptr_t target_file = utils::read_file_by_name(module_path);
110 |
111 | if (!target_file)
112 | {
113 | printf(xor_a("Target File not found!\n"));
114 | return false;
115 | }
116 |
117 | printf(xor_a("Target File is : %p\n"), target_file);
118 |
119 |
120 | PIMAGE_NT_HEADERS nt_header = utils::get_nt_header(target_file);
121 |
122 |
123 |
124 | Driver* driver = new Driver(xor_w(L"\\\\.\\drivernamehere"), target_process_id);
125 |
126 | uintptr_t target_process_base_address = driver->get_base_address(process_name);
127 |
128 | uintptr_t allocated_base = driver->allocate_virtual_memory(nt_header->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE );
129 |
130 | driver->protect_virtual_memory((uintptr_t)allocated_base, nt_header->OptionalHeader.SizeOfImage, PAGE_EXECUTE_READWRITE);
131 |
132 | printf(xor_a("Allocated 0x%p at %p\n"), nt_header->OptionalHeader.SizeOfImage, allocated_base);
133 |
134 | if (!driver->write_memory((uintptr_t)allocated_base, (uintptr_t)target_file, 0x1000))
135 | {
136 | printf(xor_a("Failed writing memory at %p\n"), allocated_base);
137 | }
138 | printf(xor_a("Successfully wrote at %p\n"), allocated_base);
139 |
140 | IMAGE_SECTION_HEADER* section_header = IMAGE_FIRST_SECTION(nt_header);
141 | for (int i = 0; i != nt_header->FileHeader.NumberOfSections; i++, ++section_header)
142 | {
143 | if (section_header->SizeOfRawData)
144 | {
145 | if (!driver->write_memory((uintptr_t)allocated_base + section_header->VirtualAddress, (uintptr_t)target_file + section_header->PointerToRawData, section_header->SizeOfRawData)) {
146 | printf(xor_a("Failed writing memory at %p\n"), allocated_base + section_header->VirtualAddress);
147 |
148 | return false;
149 | }
150 | }
151 | }
152 | printf(xor_a("Successfully wrote sections!\n"));
153 |
154 | uintptr_t allocated_shellcode = driver->allocate_virtual_memory(0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
155 | uintptr_t shellcode_value = driver->allocate_virtual_memory(sizeof(int), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); // there we set the value to stop the hook once the shellcode is called!
156 | printf(xor_a("Allocated 0x%p at %p\n"), 0x1000, allocated_shellcode);
157 |
158 |
159 | uintptr_t allocatedbase_offset = uintptr_t((uintptr_t)utils::find_pattern(xor_a("\x68\x41\x25\x46\x58\x01\x00\x00"), xor_a("xxxxxx??")) - (uintptr_t)&shellcode); //scans the value 0x15846254168 in shellcode
160 | uintptr_t allocatedvalue_offset = uintptr_t((uintptr_t)utils::find_pattern(xor_a("\x53\x12\x84\x56\x48\x02\x00\x00"), xor_a("xxxxxx??")) - (uintptr_t)&shellcode); // scans the value 0x24856841253 in shellcode
161 | if (!allocatedbase_offset || !allocatedvalue_offset)
162 | {
163 | printf(xor_a("Check signatures !\n"));
164 | return false;
165 | }
166 |
167 | auto shellcodefunction_length = utils::get_function_length(&shellcode);
168 | uintptr_t localshellcodealloc = (uintptr_t)VirtualAlloc(0, shellcodefunction_length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
169 |
170 | memcpy((PVOID)localshellcodealloc, &shellcode, shellcodefunction_length);
171 |
172 | *(uintptr_t*)(localshellcodealloc + allocatedbase_offset) = allocated_base;
173 | *(uintptr_t*)(localshellcodealloc + allocatedvalue_offset) = shellcode_value;
174 |
175 | driver->write_memory(allocated_shellcode, localshellcodealloc, 0x1000);
176 |
177 | auto win_event_hook = SetWinEventHook(EVENT_MIN, EVENT_MAX, nt_dll, (WINEVENTPROC)allocated_shellcode, target_process_id, thread_id, WINEVENT_INCONTEXT);
178 | printf(xor_a("Hook created at : %p\nWaiting..."), win_event_hook);
179 | while (true)
180 | {
181 |
182 | int buffer;
183 | driver->read_memory(shellcode_value, (uintptr_t)&buffer, sizeof(int));
184 | if (buffer == 0x69) { // if shellcode called
185 | UnhookWinEvent(win_event_hook);
186 | return true;
187 | }
188 | }
189 | return false;
190 | }
191 |
--------------------------------------------------------------------------------
/inject/Inject.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "../includes.h"
3 |
4 | class Inject
5 | {
6 | public:
7 | Inject() {};
8 | ~Inject() {};
9 | bool inject_module_from_path_to_process_by_name(const wchar_t* module_path, const wchar_t* process_name);
10 |
11 | private:
12 |
13 | };
14 |
15 |
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | #include "includes.h"
2 |
3 | int main()
4 | {
5 | Inject* inject = new Inject();
6 | inject->inject_module_from_path_to_process_by_name(xor_w(L"C:\\module_to_inject.dll"), xor_w(L"notepad.exe"));
7 | }
--------------------------------------------------------------------------------
/showcase.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TTKKO/Kernel-Manual-Map-Injector/ebb45196f1e26685fb919bbb2c844611c37ecb75/showcase.gif
--------------------------------------------------------------------------------
/utils/lazy_importer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018-2022 Justas Masiulis
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | // === FAQ === documentation is available at https://github.com/JustasMasiulis/lazy_importer
18 | // * Code doesn't compile with errors about pointer conversion:
19 | // - Try using `nullptr` instead of `NULL` or call `get()` instead of using the overloaded operator()
20 | // * Lazy importer can't find the function I want:
21 | // - Double check that the module in which it's located in is actually loaded
22 | // - Try #define LAZY_IMPORTER_CASE_INSENSITIVE
23 | // This will start using case insensitive comparison globally
24 | // - Try #define LAZY_IMPORTER_RESOLVE_FORWARDED_EXPORTS
25 | // This will enable forwarded export resolution globally instead of needing explicit `forwarded()` calls
26 |
27 | #ifndef LAZY_IMPORTER_HPP
28 | #define LAZY_IMPORTER_HPP
29 |
30 |
31 | #define LI_FN(name) ::li::detail::lazy_function()
32 |
33 | #define LI_FN_DEF(name) ::li::detail::lazy_function()
34 |
35 | #define LI_MODULE(name) ::li::detail::lazy_module()
36 |
37 | #ifndef LAZY_IMPORTER_CPP_FORWARD
38 | #ifdef LAZY_IMPORTER_NO_CPP_FORWARD
39 | #define LAZY_IMPORTER_CPP_FORWARD(t, v) v
40 | #else
41 | #include
42 | #define LAZY_IMPORTER_CPP_FORWARD(t, v) std::forward( v )
43 | #endif
44 | #endif
45 |
46 | #include
47 |
48 | #ifndef LAZY_IMPORTER_NO_FORCEINLINE
49 | #if defined(_MSC_VER)
50 | #define LAZY_IMPORTER_FORCEINLINE __forceinline
51 | #elif defined(__GNUC__) && __GNUC__ > 3
52 | #define LAZY_IMPORTER_FORCEINLINE inline __attribute__((__always_inline__))
53 | #else
54 | #define LAZY_IMPORTER_FORCEINLINE inline
55 | #endif
56 | #else
57 | #define LAZY_IMPORTER_FORCEINLINE inline
58 | #endif
59 |
60 |
61 | #ifdef LAZY_IMPORTER_CASE_INSENSITIVE
62 | #define LAZY_IMPORTER_CASE_SENSITIVITY false
63 | #else
64 | #define LAZY_IMPORTER_CASE_SENSITIVITY true
65 | #endif
66 |
67 | #define LAZY_IMPORTER_STRINGIZE(x) #x
68 | #define LAZY_IMPORTER_STRINGIZE_EXPAND(x) LAZY_IMPORTER_STRINGIZE(x)
69 |
70 | #define LAZY_IMPORTER_KHASH(str) ::li::detail::khash(str, \
71 | ::li::detail::khash_impl( __TIME__ __DATE__ LAZY_IMPORTER_STRINGIZE_EXPAND(__LINE__) LAZY_IMPORTER_STRINGIZE_EXPAND(__COUNTER__), 2166136261 ))
72 |
73 | namespace li {
74 | namespace detail {
75 |
76 | namespace win {
77 |
78 | struct LIST_ENTRY_T {
79 | const char* Flink;
80 | const char* Blink;
81 | };
82 |
83 | struct UNICODE_STRING_T {
84 | unsigned short Length;
85 | unsigned short MaximumLength;
86 | wchar_t* Buffer;
87 | };
88 |
89 | struct PEB_LDR_DATA_T {
90 | unsigned long Length;
91 | unsigned long Initialized;
92 | const char* SsHandle;
93 | LIST_ENTRY_T InLoadOrderModuleList;
94 | };
95 |
96 | struct PEB_T {
97 | unsigned char Reserved1[2];
98 | unsigned char BeingDebugged;
99 | unsigned char Reserved2[1];
100 | const char* Reserved3[2];
101 | PEB_LDR_DATA_T* Ldr;
102 | };
103 |
104 | struct LDR_DATA_TABLE_ENTRY_T {
105 | LIST_ENTRY_T InLoadOrderLinks;
106 | LIST_ENTRY_T InMemoryOrderLinks;
107 | LIST_ENTRY_T InInitializationOrderLinks;
108 | const char* DllBase;
109 | const char* EntryPoint;
110 | union {
111 | unsigned long SizeOfImage;
112 | const char* _dummy;
113 | };
114 | UNICODE_STRING_T FullDllName;
115 | UNICODE_STRING_T BaseDllName;
116 |
117 | LAZY_IMPORTER_FORCEINLINE const LDR_DATA_TABLE_ENTRY_T*
118 | load_order_next() const noexcept
119 | {
120 | return reinterpret_cast(
121 | InLoadOrderLinks.Flink);
122 | }
123 | };
124 |
125 | struct IMAGE_DOS_HEADER { // DOS .EXE header
126 | unsigned short e_magic; // Magic number
127 | unsigned short e_cblp; // Bytes on last page of file
128 | unsigned short e_cp; // Pages in file
129 | unsigned short e_crlc; // Relocations
130 | unsigned short e_cparhdr; // Size of header in paragraphs
131 | unsigned short e_minalloc; // Minimum extra paragraphs needed
132 | unsigned short e_maxalloc; // Maximum extra paragraphs needed
133 | unsigned short e_ss; // Initial (relative) SS value
134 | unsigned short e_sp; // Initial SP value
135 | unsigned short e_csum; // Checksum
136 | unsigned short e_ip; // Initial IP value
137 | unsigned short e_cs; // Initial (relative) CS value
138 | unsigned short e_lfarlc; // File address of relocation table
139 | unsigned short e_ovno; // Overlay number
140 | unsigned short e_res[4]; // Reserved words
141 | unsigned short e_oemid; // OEM identifier (for e_oeminfo)
142 | unsigned short e_oeminfo; // OEM information; e_oemid specific
143 | unsigned short e_res2[10]; // Reserved words
144 | long e_lfanew; // File address of new exe header
145 | };
146 |
147 | struct IMAGE_FILE_HEADER {
148 | unsigned short Machine;
149 | unsigned short NumberOfSections;
150 | unsigned long TimeDateStamp;
151 | unsigned long PointerToSymbolTable;
152 | unsigned long NumberOfSymbols;
153 | unsigned short SizeOfOptionalHeader;
154 | unsigned short Characteristics;
155 | };
156 |
157 | struct IMAGE_EXPORT_DIRECTORY {
158 | unsigned long Characteristics;
159 | unsigned long TimeDateStamp;
160 | unsigned short MajorVersion;
161 | unsigned short MinorVersion;
162 | unsigned long Name;
163 | unsigned long Base;
164 | unsigned long NumberOfFunctions;
165 | unsigned long NumberOfNames;
166 | unsigned long AddressOfFunctions; // RVA from base of image
167 | unsigned long AddressOfNames; // RVA from base of image
168 | unsigned long AddressOfNameOrdinals; // RVA from base of image
169 | };
170 |
171 | struct IMAGE_DATA_DIRECTORY {
172 | unsigned long VirtualAddress;
173 | unsigned long Size;
174 | };
175 |
176 | struct IMAGE_OPTIONAL_HEADER64 {
177 | unsigned short Magic;
178 | unsigned char MajorLinkerVersion;
179 | unsigned char MinorLinkerVersion;
180 | unsigned long SizeOfCode;
181 | unsigned long SizeOfInitializedData;
182 | unsigned long SizeOfUninitializedData;
183 | unsigned long AddressOfEntryPoint;
184 | unsigned long BaseOfCode;
185 | unsigned long long ImageBase;
186 | unsigned long SectionAlignment;
187 | unsigned long FileAlignment;
188 | unsigned short MajorOperatingSystemVersion;
189 | unsigned short MinorOperatingSystemVersion;
190 | unsigned short MajorImageVersion;
191 | unsigned short MinorImageVersion;
192 | unsigned short MajorSubsystemVersion;
193 | unsigned short MinorSubsystemVersion;
194 | unsigned long Win32VersionValue;
195 | unsigned long SizeOfImage;
196 | unsigned long SizeOfHeaders;
197 | unsigned long CheckSum;
198 | unsigned short Subsystem;
199 | unsigned short DllCharacteristics;
200 | unsigned long long SizeOfStackReserve;
201 | unsigned long long SizeOfStackCommit;
202 | unsigned long long SizeOfHeapReserve;
203 | unsigned long long SizeOfHeapCommit;
204 | unsigned long LoaderFlags;
205 | unsigned long NumberOfRvaAndSizes;
206 | IMAGE_DATA_DIRECTORY DataDirectory[16];
207 | };
208 |
209 | struct IMAGE_OPTIONAL_HEADER32 {
210 | unsigned short Magic;
211 | unsigned char MajorLinkerVersion;
212 | unsigned char MinorLinkerVersion;
213 | unsigned long SizeOfCode;
214 | unsigned long SizeOfInitializedData;
215 | unsigned long SizeOfUninitializedData;
216 | unsigned long AddressOfEntryPoint;
217 | unsigned long BaseOfCode;
218 | unsigned long BaseOfData;
219 | unsigned long ImageBase;
220 | unsigned long SectionAlignment;
221 | unsigned long FileAlignment;
222 | unsigned short MajorOperatingSystemVersion;
223 | unsigned short MinorOperatingSystemVersion;
224 | unsigned short MajorImageVersion;
225 | unsigned short MinorImageVersion;
226 | unsigned short MajorSubsystemVersion;
227 | unsigned short MinorSubsystemVersion;
228 | unsigned long Win32VersionValue;
229 | unsigned long SizeOfImage;
230 | unsigned long SizeOfHeaders;
231 | unsigned long CheckSum;
232 | unsigned short Subsystem;
233 | unsigned short DllCharacteristics;
234 | unsigned long SizeOfStackReserve;
235 | unsigned long SizeOfStackCommit;
236 | unsigned long SizeOfHeapReserve;
237 | unsigned long SizeOfHeapCommit;
238 | unsigned long LoaderFlags;
239 | unsigned long NumberOfRvaAndSizes;
240 | IMAGE_DATA_DIRECTORY DataDirectory[16];
241 | };
242 |
243 | struct IMAGE_NT_HEADERS {
244 | unsigned long Signature;
245 | IMAGE_FILE_HEADER FileHeader;
246 | #ifdef _WIN64
247 | IMAGE_OPTIONAL_HEADER64 OptionalHeader;
248 | #else
249 | IMAGE_OPTIONAL_HEADER32 OptionalHeader;
250 | #endif
251 | };
252 |
253 | } // namespace win
254 |
255 | struct forwarded_hashes {
256 | unsigned module_hash;
257 | unsigned function_hash;
258 | };
259 |
260 | // 64 bit integer where 32 bits are used for the hash offset
261 | // and remaining 32 bits are used for the hash computed using it
262 | using offset_hash_pair = unsigned long long;
263 |
264 | LAZY_IMPORTER_FORCEINLINE constexpr unsigned get_hash(offset_hash_pair pair) noexcept { return (pair & 0xFFFFFFFF); }
265 |
266 | LAZY_IMPORTER_FORCEINLINE constexpr unsigned get_offset(offset_hash_pair pair) noexcept { return (pair >> 32); }
267 |
268 | template
269 | LAZY_IMPORTER_FORCEINLINE constexpr unsigned hash_single(unsigned value, char c) noexcept
270 | {
271 | return static_cast(
272 | (value ^ ((!CaseSensitive && c >= 'A' && c <= 'Z') ? (c | (1 << 5)) : c)) *
273 | static_cast(16777619));
274 | }
275 |
276 | LAZY_IMPORTER_FORCEINLINE constexpr unsigned
277 | khash_impl(const char* str, unsigned value) noexcept
278 | {
279 | return (*str ? khash_impl(str + 1, hash_single(value, *str)) : value);
280 | }
281 |
282 | LAZY_IMPORTER_FORCEINLINE constexpr offset_hash_pair khash(
283 | const char* str, unsigned offset) noexcept
284 | {
285 | return ((offset_hash_pair{ offset } << 32) | khash_impl(str, offset));
286 | }
287 |
288 | template
289 | LAZY_IMPORTER_FORCEINLINE unsigned hash(const CharT* str, unsigned offset) noexcept
290 | {
291 | unsigned value = offset;
292 |
293 | for (;;) {
294 | char c = *str++;
295 | if (!c)
296 | return value;
297 | value = hash_single(value, c);
298 | }
299 | }
300 |
301 | LAZY_IMPORTER_FORCEINLINE unsigned hash(
302 | const win::UNICODE_STRING_T& str, unsigned offset) noexcept
303 | {
304 | auto first = str.Buffer;
305 | const auto last = first + (str.Length / sizeof(wchar_t));
306 | auto value = offset;
307 | for (; first != last; ++first)
308 | value = hash_single(value, static_cast(*first));
309 |
310 | return value;
311 | }
312 |
313 | LAZY_IMPORTER_FORCEINLINE forwarded_hashes hash_forwarded(
314 | const char* str, unsigned offset) noexcept
315 | {
316 | forwarded_hashes res{ offset, offset };
317 |
318 | for (; *str != '.'; ++str)
319 | res.module_hash = hash_single(res.module_hash, *str);
320 |
321 | ++str;
322 |
323 | for (; *str; ++str)
324 | res.function_hash = hash_single(res.function_hash, *str);
325 |
326 | return res;
327 | }
328 |
329 | // some helper functions
330 | LAZY_IMPORTER_FORCEINLINE const win::PEB_T* peb() noexcept
331 | {
332 | #if defined(_M_X64) || defined(__amd64__)
333 | return reinterpret_cast(__readgsqword(0x60));
334 | #elif defined(_M_IX86) || defined(__i386__)
335 | return reinterpret_cast(__readfsdword(0x30));
336 | #elif defined(_M_ARM) || defined(__arm__)
337 | return *reinterpret_cast(_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30);
338 | #elif defined(_M_ARM64) || defined(__aarch64__)
339 | return *reinterpret_cast(__getReg(18) + 0x60);
340 | #elif defined(_M_IA64) || defined(__ia64__)
341 | return *reinterpret_cast(static_cast(_rdteb()) + 0x60);
342 | #else
343 | #error Unsupported platform. Open an issue and I'll probably add support.
344 | #endif
345 | }
346 |
347 | LAZY_IMPORTER_FORCEINLINE const win::PEB_LDR_DATA_T* ldr()
348 | {
349 | return reinterpret_cast(peb()->Ldr);
350 | }
351 |
352 | LAZY_IMPORTER_FORCEINLINE const win::IMAGE_NT_HEADERS* nt_headers(
353 | const char* base) noexcept
354 | {
355 | return reinterpret_cast(
356 | base + reinterpret_cast(base)->e_lfanew);
357 | }
358 |
359 | LAZY_IMPORTER_FORCEINLINE const win::IMAGE_EXPORT_DIRECTORY* image_export_dir(
360 | const char* base) noexcept
361 | {
362 | return reinterpret_cast(
363 | base + nt_headers(base)->OptionalHeader.DataDirectory->VirtualAddress);
364 | }
365 |
366 | LAZY_IMPORTER_FORCEINLINE const win::LDR_DATA_TABLE_ENTRY_T* ldr_data_entry() noexcept
367 | {
368 | return reinterpret_cast(
369 | ldr()->InLoadOrderModuleList.Flink);
370 | }
371 |
372 | struct exports_directory {
373 | const char* _base;
374 | const win::IMAGE_EXPORT_DIRECTORY* _ied;
375 | unsigned long _ied_size;
376 |
377 | public:
378 | using size_type = unsigned long;
379 |
380 | LAZY_IMPORTER_FORCEINLINE
381 | exports_directory(const char* base) noexcept : _base(base)
382 | {
383 | const auto ied_data_dir = nt_headers(base)->OptionalHeader.DataDirectory[0];
384 | _ied = reinterpret_cast(
385 | base + ied_data_dir.VirtualAddress);
386 | _ied_size = ied_data_dir.Size;
387 | }
388 |
389 | LAZY_IMPORTER_FORCEINLINE explicit operator bool() const noexcept
390 | {
391 | return reinterpret_cast(_ied) != _base;
392 | }
393 |
394 | LAZY_IMPORTER_FORCEINLINE size_type size() const noexcept
395 | {
396 | return _ied->NumberOfNames;
397 | }
398 |
399 | LAZY_IMPORTER_FORCEINLINE const char* base() const noexcept { return _base; }
400 | LAZY_IMPORTER_FORCEINLINE const win::IMAGE_EXPORT_DIRECTORY* ied() const noexcept
401 | {
402 | return _ied;
403 | }
404 |
405 | LAZY_IMPORTER_FORCEINLINE const char* name(size_type index) const noexcept
406 | {
407 | return reinterpret_cast(
408 | _base + reinterpret_cast(
409 | _base + _ied->AddressOfNames)[index]);
410 | }
411 |
412 | LAZY_IMPORTER_FORCEINLINE const char* address(size_type index) const noexcept
413 | {
414 | const auto* const rva_table =
415 | reinterpret_cast(_base + _ied->AddressOfFunctions);
416 |
417 | const auto* const ord_table = reinterpret_cast(
418 | _base + _ied->AddressOfNameOrdinals);
419 |
420 | return _base + rva_table[ord_table[index]];
421 | }
422 |
423 | LAZY_IMPORTER_FORCEINLINE bool is_forwarded(
424 | const char* export_address) const noexcept
425 | {
426 | const auto ui_ied = reinterpret_cast(_ied);
427 | return (export_address > ui_ied && export_address < ui_ied + _ied_size);
428 | }
429 | };
430 |
431 | struct safe_module_enumerator {
432 | using value_type = const detail::win::LDR_DATA_TABLE_ENTRY_T;
433 | value_type* value;
434 | value_type* head;
435 |
436 | LAZY_IMPORTER_FORCEINLINE safe_module_enumerator() noexcept
437 | : safe_module_enumerator(ldr_data_entry())
438 | {}
439 |
440 | LAZY_IMPORTER_FORCEINLINE
441 | safe_module_enumerator(const detail::win::LDR_DATA_TABLE_ENTRY_T* ldr) noexcept
442 | : value(ldr->load_order_next()), head(value)
443 | {}
444 |
445 | LAZY_IMPORTER_FORCEINLINE void reset() noexcept
446 | {
447 | value = head->load_order_next();
448 | }
449 |
450 | LAZY_IMPORTER_FORCEINLINE bool next() noexcept
451 | {
452 | value = value->load_order_next();
453 |
454 | return value != head && value->DllBase;
455 | }
456 | };
457 |
458 | struct unsafe_module_enumerator {
459 | using value_type = const detail::win::LDR_DATA_TABLE_ENTRY_T*;
460 | value_type value;
461 |
462 | LAZY_IMPORTER_FORCEINLINE unsafe_module_enumerator() noexcept
463 | : value(ldr_data_entry())
464 | {}
465 |
466 | LAZY_IMPORTER_FORCEINLINE void reset() noexcept { value = ldr_data_entry(); }
467 |
468 | LAZY_IMPORTER_FORCEINLINE bool next() noexcept
469 | {
470 | value = value->load_order_next();
471 | return true;
472 | }
473 | };
474 |
475 | // provides the cached functions which use Derive classes methods
476 | template
477 | class lazy_base {
478 | protected:
479 | // This function is needed because every templated function
480 | // with different args has its own static buffer
481 | LAZY_IMPORTER_FORCEINLINE static void*& _cache() noexcept
482 | {
483 | static void* value = nullptr;
484 | return value;
485 | }
486 |
487 | public:
488 | template
489 | LAZY_IMPORTER_FORCEINLINE static T safe() noexcept
490 | {
491 | return Derived::template get();
492 | }
493 |
494 | template
495 | LAZY_IMPORTER_FORCEINLINE static T cached() noexcept
496 | {
497 | auto& cached = _cache();
498 | if (!cached)
499 | cached = Derived::template get();
500 |
501 | return (T)(cached);
502 | }
503 |
504 | template
505 | LAZY_IMPORTER_FORCEINLINE static T safe_cached() noexcept
506 | {
507 | return cached();
508 | }
509 | };
510 |
511 | template
512 | struct lazy_module : lazy_base> {
513 | template
514 | LAZY_IMPORTER_FORCEINLINE static T get() noexcept
515 | {
516 | Enum e;
517 | do {
518 | if (hash(e.value->BaseDllName, get_offset(OHP)) == get_hash(OHP))
519 | return (T)(e.value->DllBase);
520 | } while (e.next());
521 | return {};
522 | }
523 |
524 | template
525 | LAZY_IMPORTER_FORCEINLINE static T in(Ldr ldr) noexcept
526 | {
527 | safe_module_enumerator e((const detail::win::LDR_DATA_TABLE_ENTRY_T*)(ldr));
528 | do {
529 | if (hash(e.value->BaseDllName, get_offset(OHP)) == get_hash(OHP))
530 | return (T)(e.value->DllBase);
531 | } while (e.next());
532 | return {};
533 | }
534 |
535 | template
536 | LAZY_IMPORTER_FORCEINLINE static T in_cached(Ldr ldr) noexcept
537 | {
538 | auto& cached = lazy_base>::_cache();
539 | if (!cached)
540 | cached = in(ldr);
541 |
542 | return (T)(cached);
543 | }
544 | };
545 |
546 | template
547 | struct lazy_function : lazy_base, T> {
548 | using base_type = lazy_base, T>;
549 |
550 | template
551 | LAZY_IMPORTER_FORCEINLINE decltype(auto) operator()(Args&&... args) const
552 | {
553 | #ifndef LAZY_IMPORTER_CACHE_OPERATOR_PARENS
554 | return get()(LAZY_IMPORTER_CPP_FORWARD(Args, args)...);
555 | #else
556 | return this->cached()(LAZY_IMPORTER_CPP_FORWARD(Args, args)...);
557 | #endif
558 | }
559 |
560 | template
561 | LAZY_IMPORTER_FORCEINLINE static F get() noexcept
562 | {
563 | // for backwards compatability.
564 | // Before 2.0 it was only possible to resolve forwarded exports when
565 | // this macro was enabled
566 | #ifdef LAZY_IMPORTER_RESOLVE_FORWARDED_EXPORTS
567 | return forwarded();
568 | #else
569 |
570 | Enum e;
571 |
572 | do {
573 | #ifdef LAZY_IMPORTER_HARDENED_MODULE_CHECKS
574 | if (!e.value->DllBase || !e.value->FullDllName.Length)
575 | continue;
576 | #endif
577 |
578 | const exports_directory exports(e.value->DllBase);
579 |
580 | if (exports) {
581 | auto export_index = exports.size();
582 | while (export_index--)
583 | if (hash(exports.name(export_index), get_offset(OHP)) == get_hash(OHP))
584 | return (F)(exports.address(export_index));
585 | }
586 | } while (e.next());
587 | return {};
588 | #endif
589 | }
590 |
591 | template
592 | LAZY_IMPORTER_FORCEINLINE static F forwarded() noexcept
593 | {
594 | detail::win::UNICODE_STRING_T name;
595 | forwarded_hashes hashes{ 0, get_hash(OHP) };
596 |
597 | Enum e;
598 | do {
599 | name = e.value->BaseDllName;
600 | name.Length -= 8; // get rid of .dll extension
601 |
602 | if (!hashes.module_hash || hash(name, get_offset(OHP)) == hashes.module_hash) {
603 | const exports_directory exports(e.value->DllBase);
604 |
605 | if (exports) {
606 | auto export_index = exports.size();
607 | while (export_index--)
608 | if (hash(exports.name(export_index), get_offset(OHP)) == hashes.function_hash) {
609 | const auto addr = exports.address(export_index);
610 |
611 | if (exports.is_forwarded(addr)) {
612 | hashes = hash_forwarded(
613 | reinterpret_cast(addr),
614 | get_offset(OHP));
615 |
616 | e.reset();
617 | break;
618 | }
619 | return (F)(addr);
620 | }
621 | }
622 | }
623 | } while (e.next());
624 | return {};
625 | }
626 |
627 | template
628 | LAZY_IMPORTER_FORCEINLINE static F forwarded_safe() noexcept
629 | {
630 | return forwarded();
631 | }
632 |
633 | template
634 | LAZY_IMPORTER_FORCEINLINE static F forwarded_cached() noexcept
635 | {
636 | auto& value = base_type::_cache();
637 | if (!value)
638 | value = forwarded();
639 | return (F)(value);
640 | }
641 |
642 | template
643 | LAZY_IMPORTER_FORCEINLINE static F forwarded_safe_cached() noexcept
644 | {
645 | return forwarded_cached();
646 | }
647 |
648 | template
649 | LAZY_IMPORTER_FORCEINLINE static F in(Module m) noexcept
650 | {
651 | if (IsSafe && !m)
652 | return {};
653 |
654 | const exports_directory exports((const char*)(m));
655 | if (IsSafe && !exports)
656 | return {};
657 |
658 | for (unsigned long i{};; ++i) {
659 | if (IsSafe && i == exports.size())
660 | break;
661 |
662 | if (hash(exports.name(i), get_offset(OHP)) == get_hash(OHP))
663 | return (F)(exports.address(i));
664 | }
665 | return {};
666 | }
667 |
668 | template
669 | LAZY_IMPORTER_FORCEINLINE static F in_safe(Module m) noexcept
670 | {
671 | return in(m);
672 | }
673 |
674 | template
675 | LAZY_IMPORTER_FORCEINLINE static F in_cached(Module m) noexcept
676 | {
677 | auto& value = base_type::_cache();
678 | if (!value)
679 | value = in(m);
680 | return (F)(value);
681 | }
682 |
683 | template
684 | LAZY_IMPORTER_FORCEINLINE static F in_safe_cached(Module m) noexcept
685 | {
686 | return in_cached(m);
687 | }
688 |
689 | template
690 | LAZY_IMPORTER_FORCEINLINE static F nt() noexcept
691 | {
692 | return in(ldr_data_entry()->load_order_next()->DllBase);
693 | }
694 |
695 | template
696 | LAZY_IMPORTER_FORCEINLINE static F nt_safe() noexcept
697 | {
698 | return in_safe(ldr_data_entry()->load_order_next()->DllBase);
699 | }
700 |
701 | template
702 | LAZY_IMPORTER_FORCEINLINE static F nt_cached() noexcept
703 | {
704 | return in_cached(ldr_data_entry()->load_order_next()->DllBase);
705 | }
706 |
707 | template
708 | LAZY_IMPORTER_FORCEINLINE static F nt_safe_cached() noexcept
709 | {
710 | return in_safe_cached(ldr_data_entry()->load_order_next()->DllBase);
711 | }
712 | };
713 |
714 | }
715 | } // namespace li::detail
716 |
717 | #endif // include guard
--------------------------------------------------------------------------------
/utils/utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace utils
5 | {
6 | inline int get_pid_from_name(const wchar_t* name)
7 | {
8 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
9 | PROCESSENTRY32 entry;
10 | entry.dwSize = sizeof(PROCESSENTRY32);
11 | Process32First(snapshot, &entry);
12 | do
13 | {
14 | if (wcscmp(entry.szExeFile, name) == 0)
15 | {
16 | return entry.th32ProcessID;
17 | }
18 |
19 | } while (Process32Next(snapshot, &entry));
20 |
21 | return 0; // if not found
22 | }
23 | inline uintptr_t read_file_by_name(const wchar_t* file_path)
24 | {
25 | HANDLE h_dll = CreateFileW(file_path ,GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
26 | if (h_dll == INVALID_HANDLE_VALUE) return 0;
27 | int file_size = GetFileSize(h_dll, 0);
28 | PVOID buffer = VirtualAlloc(0, file_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
29 | if (!ReadFile(h_dll, buffer, file_size, 0, FALSE) || *(int*)(buffer) != 9460301) // MZ CHECK
30 | {
31 |
32 | CloseHandle(h_dll);
33 | VirtualFree(buffer,0, MEM_RELEASE);
34 | return 0;
35 | }
36 | else
37 | {
38 | CloseHandle(h_dll);
39 | return (uintptr_t)buffer;
40 | }
41 | }
42 | inline PIMAGE_NT_HEADERS get_nt_header(uintptr_t base)
43 | {
44 | PIMAGE_DOS_HEADER dos_headers = PIMAGE_DOS_HEADER(base);
45 | return PIMAGE_NT_HEADERS(base + dos_headers->e_lfanew);
46 | }
47 | inline bool mask_compare(void* buffer, const char* pattern, const char* mask)
48 | {
49 | for (auto b = reinterpret_cast(buffer); *mask; ++pattern, ++mask, ++b)
50 | {
51 | if (*mask == 'x' && *reinterpret_cast(pattern) != *b)
52 | {
53 | return FALSE;
54 | }
55 | }
56 | return TRUE;
57 | }
58 | inline PBYTE find_pattern(const char* pattern, const char* mask)
59 | {
60 | MODULEINFO info = {0};
61 | GetModuleInformation(GetCurrentProcess(), GetModuleHandleA(0), &info, sizeof(info));
62 | info.SizeOfImage -= static_cast(strlen(mask));
63 | for (auto i = 0UL; i < info.SizeOfImage; i++)
64 | {
65 | auto addr = reinterpret_cast(info.lpBaseOfDll) + i;
66 | if (mask_compare(addr, pattern, mask))
67 | {
68 | return addr;
69 | }
70 | }
71 | }
72 | inline int get_function_length(void* funcaddress)
73 | {
74 | int length = 0;
75 | for (length = 0; *((UINT32*)(&((unsigned char*)funcaddress)[length])) != 0xCCCCCCCC; ++length);
76 | return length;
77 | }
78 | inline HWND hwndout;
79 | inline BOOL EnumWindowProcMy(HWND input, LPARAM lParam)
80 | {
81 |
82 | DWORD lpdwProcessId;
83 | GetWindowThreadProcessId(input, &lpdwProcessId);
84 | if (lpdwProcessId == lParam)
85 | {
86 | hwndout = input;
87 | return FALSE;
88 | }
89 | return true;
90 | }
91 | inline HWND get_hwnd_of_process_id(int target_process_id)
92 | {
93 | EnumWindows(EnumWindowProcMy, target_process_id);
94 | return hwndout;
95 | }
96 |
97 |
98 | }
--------------------------------------------------------------------------------
/utils/xor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | template struct EnsureCompileTime {
4 | enum : int {
5 | Value = X
6 | };
7 | };
8 | #define Seed ((__TIME__[7] - '0') * 1 + (__TIME__[6] - '0') * 10 + \
9 | (__TIME__[4] - '0') * 60 + (__TIME__[3] - '0') * 600 + \
10 | (__TIME__[1] - '0') * 3600 + (__TIME__[0] - '0') * 36000)
11 |
12 | __forceinline constexpr int LinearCongruentGenerator(int Rounds) {
13 | return 1013904223 + 1664525 * ((Rounds > 0) ? LinearCongruentGenerator(Rounds - 1) : Seed & 0xFFFFFFFF);
14 | }
15 | #define Random() EnsureCompileTime::Value
16 | #define RandomNumber(Min, Max) (Min + (Random() % (Max - Min + 1)))
17 | template struct IndexList {};
18 | template struct Append;
19 | template struct Append, Right> {
20 | typedef IndexList Result;
21 | };
22 | template struct ConstructIndexList {
23 | typedef typename Append::Result, N - 1>::Result Result;
24 | };
25 | template <> struct ConstructIndexList<0> {
26 | typedef IndexList<> Result;
27 | };
28 | const char XORKEY_A = static_cast(0x13);
29 | const wchar_t XORKEY_W = static_cast(0x133);
30 | __declspec(noinline) constexpr char EncryptCharacterA(const char Character, int Index) {
31 | return Character ^ (XORKEY_A + Index);
32 | }
33 | template class CingA;
34 | template class CingA > {
35 | private:
36 | char Value[sizeof...(Index) + 1];
37 | public:
38 | __forceinline constexpr CingA(const char* const String)
39 | : Value{ EncryptCharacterA(String[Index], Index)... } {}
40 |
41 | __forceinline char* decrypt() {
42 | for (int t = 0; t < sizeof...(Index); t++) {
43 | Value[t] = Value[t] ^ (XORKEY_A + t);
44 | }
45 | Value[sizeof...(Index)] = '\0';
46 | return Value;
47 | }
48 |
49 | __forceinline char* get() {
50 | return Value;
51 | }
52 | };
53 | __declspec(noinline) constexpr wchar_t EncryptCharacterW(const wchar_t Character, int Index) {
54 | return Character ^ (XORKEY_W + Index);
55 | }
56 | template class CingW;
57 | template class CingW > {
58 | private:
59 | wchar_t Value[sizeof...(Index) + 1];
60 | public:
61 | __forceinline constexpr CingW(const wchar_t* const String)
62 | : Value{ EncryptCharacterW(String[Index], Index)... } {}
63 |
64 | __forceinline wchar_t* decrypt() {
65 | for (int t = 0; t < sizeof...(Index); t++) {
66 | Value[t] = Value[t] ^ (XORKEY_W + t);
67 | }
68 | Value[sizeof...(Index)] = '\0\0';
69 | return Value;
70 | }
71 |
72 | __forceinline wchar_t* get() {
73 | return Value;
74 | }
75 | };
76 |
77 | #define xor_a( String ) ( CingA::Result>( String ).decrypt() )
78 | #define xor_w( String ) ( CingW::Result>( String ).decrypt() )
79 |
--------------------------------------------------------------------------------