├── DLLInjector ├── DLLInjector │ ├── pe.h │ ├── dll_injection.h │ ├── device_handlers.h │ ├── common.h │ ├── process.h │ ├── ProcessReference.h │ ├── consts.h │ ├── DLLInjector.inf │ ├── ProcessReference.cpp │ ├── apc.cpp │ ├── device_handlers.cpp │ ├── apc.h │ ├── main.cpp │ ├── DLLInjector.vcxproj.filters │ ├── dll_injection.cpp │ ├── process.cpp │ ├── DLLInjector.vcxproj │ └── pe.cpp ├── DLLInjectorCom │ ├── DLLInjectorCom.vcxproj.user │ ├── DLLInjectorCom.cpp │ ├── DLLInjectorCom.vcxproj.filters │ └── DLLInjectorCom.vcxproj ├── DLLInjector.sln.DotSettings.user └── DLLInjector.sln ├── .gitignore ├── LICENSE └── README.md /DLLInjector/DLLInjector/pe.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | PVOID get_module_symbol_address(wchar_t* module_name, char* symbol_name); -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/dll_injection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "common.h" 5 | 6 | NTSTATUS inject_dll(const InjectDllArgs& inject_dll_args); -------------------------------------------------------------------------------- /DLLInjector/DLLInjectorCom/DLLInjectorCom.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/device_handlers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | NTSTATUS device_create_close(PDEVICE_OBJECT device_object, PIRP irp); 6 | 7 | NTSTATUS device_ioctl(PDEVICE_OBJECT device_object, PIRP irp); -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct InjectDllArgs { 4 | size_t pid; 5 | wchar_t dll_path[256]; 6 | }; 7 | 8 | #define INJECT_DLL_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1337, METHOD_BUFFERED, FILE_WRITE_DATA) -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/process.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct ProcessInfo { 5 | size_t process_id; 6 | size_t number_of_threads; 7 | size_t* threads_id; 8 | }; 9 | 10 | ProcessInfo* get_processes_info(size_t* number_of_processes); 11 | 12 | NTSTATUS get_process_info_by_pid(size_t pid, ProcessInfo* process_info); -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/ProcessReference.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "consts.h" 6 | 7 | class ProcessReference { 8 | public: 9 | ProcessReference(); 10 | ~ProcessReference(); 11 | 12 | NTSTATUS init(size_t pid, bool attach); 13 | 14 | DELETE_DEFAULT_CTORS(ProcessReference); 15 | private: 16 | PEPROCESS m_process; 17 | bool m_attach{}; 18 | KAPC_STATE* m_apc_state; 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/consts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NT_DEVICE_NAME L"\\Device\\DLLInjector" 4 | #define DOS_DEVICE_NAME L"\\DosDevices\\DLLInjector" 5 | 6 | #define CHECK(ntstatus) if (!NT_SUCCESS(ntstatus)) { return ntstatus;} 7 | 8 | #define DELETE_DEFAULT_CTORS(class_name) \ 9 | class_name(class_name const&) = delete; \ 10 | class_name& operator =(class_name const&) = delete; \ 11 | class_name(class_name&&) = delete; \ 12 | class_name& operator=(class_name&&) = delete \ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | .vs/ 35 | Debug/ 36 | Release/ 37 | x64/ 38 | script.txt 39 | *.ps1 -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/DLLInjector.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; DLLInjector.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=System 8 | ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} 9 | Provider=%ManufacturerName% 10 | DriverVer= 11 | CatalogFile=DLLInjector.cat 12 | 13 | [DestinationDirs] 14 | DefaultDestDir = 12 15 | 16 | 17 | [SourceDisksNames] 18 | 1 = %DiskName%,,,"" 19 | 20 | [SourceDisksFiles] 21 | 22 | 23 | [Manufacturer] 24 | %ManufacturerName%=Standard,NT$ARCH$ 25 | 26 | [Standard.NT$ARCH$] 27 | 28 | 29 | [Strings] 30 | ManufacturerName="" ;TODO: Replace with your manufacturer name 31 | ClassName="" 32 | DiskName="DLLInjector Source Disk" 33 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjectorCom/DLLInjectorCom.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "../DLLInjector/common.h" 6 | 7 | int wmain(int, wchar_t** argv) { 8 | std::cout << "Hello World!\n"; 9 | HANDLE driver = CreateFileA("\\\\.\\DLLInjector", GENERIC_ALL, 0, 10 | nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 11 | if (INVALID_HANDLE_VALUE == driver) { 12 | return 1; 13 | } 14 | InjectDllArgs args = {}; 15 | memcpy(args.dll_path, argv[1], wcslen(argv[1]) * sizeof(wchar_t)); 16 | args.pid = std::stoi(argv[2]); 17 | 18 | DeviceIoControl(driver, INJECT_DLL_IOCTL, &args, sizeof(InjectDllArgs), 19 | nullptr, 0, nullptr, nullptr); 20 | 21 | CloseHandle(driver); 22 | return 0; 23 | } -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/ProcessReference.cpp: -------------------------------------------------------------------------------- 1 | #include "ProcessReference.h" 2 | 3 | ProcessReference::ProcessReference() 4 | : m_process(nullptr) { 5 | } 6 | 7 | ProcessReference::~ProcessReference() { 8 | if (nullptr != m_process) { 9 | ObDereferenceObject(m_process); 10 | if (m_attach) { 11 | KeUnstackDetachProcess(m_apc_state); 12 | ExFreePool(m_apc_state); 13 | } 14 | } 15 | 16 | } 17 | 18 | NTSTATUS ProcessReference::init(size_t pid, bool attach) { 19 | CHECK(PsLookupProcessByProcessId(reinterpret_cast(pid), &m_process)); 20 | m_attach = attach; 21 | if (attach) { 22 | m_apc_state = (KAPC_STATE*)ExAllocatePool(NonPagedPool, sizeof(KAPC_STATE)); 23 | KeStackAttachProcess(m_process, m_apc_state); 24 | } 25 | return STATUS_SUCCESS; 26 | } 27 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/apc.cpp: -------------------------------------------------------------------------------- 1 | #include "apc.h" 2 | 3 | VOID KernelAPC(PVOID, PVOID, PVOID, PVOID, PVOID) { 4 | } 5 | 6 | NTSTATUS call_apc(PKTHREAD target_thread, PVOID target_function, PVOID params) { 7 | KAPC* apc = static_cast(ExAllocatePool(NonPagedPool, sizeof(KAPC))); 8 | if (nullptr == apc) { 9 | return STATUS_UNSUCCESSFUL; 10 | } 11 | KeInitializeApc(apc, 12 | target_thread, 13 | OriginalApcEnvironment, 14 | reinterpret_cast(KernelAPC), 15 | nullptr, 16 | reinterpret_cast(target_function), 17 | UserMode, 18 | params); 19 | 20 | if (!KeInsertQueueApc(apc, nullptr, nullptr, 0)) { 21 | ExFreePool(apc); 22 | return STATUS_UNSUCCESSFUL; 23 | } 24 | return STATUS_SUCCESS; 25 | } -------------------------------------------------------------------------------- /DLLInjector/DLLInjector.sln.DotSettings.user: -------------------------------------------------------------------------------- 1 | 2 | True 3 | (Doc Ln 0 Col 0) 4 | 3CAA899B-B384-42CA-ABB1-7FEEE57B31BB/f:pe.cpp 5 | NumberedBookmarkManager -------------------------------------------------------------------------------- /DLLInjector/DLLInjectorCom/DLLInjectorCom.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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 abhishekemmanuel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/device_handlers.cpp: -------------------------------------------------------------------------------- 1 | #include "device_handlers.h" 2 | 3 | #include "common.h" 4 | #include "dll_injection.h" 5 | 6 | NTSTATUS device_create_close(PDEVICE_OBJECT device_object, PIRP irp) { 7 | UNREFERENCED_PARAMETER(device_object); 8 | irp->IoStatus.Status = STATUS_SUCCESS; 9 | irp->IoStatus.Information = 0; 10 | 11 | IoCompleteRequest(irp, IO_NO_INCREMENT); 12 | 13 | return STATUS_SUCCESS; 14 | } 15 | 16 | NTSTATUS device_ioctl(PDEVICE_OBJECT device_object, PIRP irp) { 17 | UNREFERENCED_PARAMETER(device_object); 18 | 19 | NTSTATUS nt_status; 20 | PIO_STACK_LOCATION irp_stack_location = IoGetCurrentIrpStackLocation(irp); 21 | size_t input_buffer_length = irp_stack_location->Parameters.DeviceIoControl.InputBufferLength; 22 | 23 | switch (irp_stack_location->Parameters.DeviceIoControl.IoControlCode) { 24 | case INJECT_DLL_IOCTL: 25 | { 26 | if (input_buffer_length != sizeof InjectDllArgs) { 27 | nt_status = STATUS_INVALID_PARAMETER; 28 | break; 29 | } 30 | auto args = static_cast(irp->AssociatedIrp.SystemBuffer); 31 | nt_status = inject_dll(*args); 32 | } 33 | break; 34 | default: 35 | { 36 | nt_status = STATUS_INVALID_DEVICE_REQUEST; 37 | } 38 | break; 39 | } 40 | 41 | irp->IoStatus.Status = nt_status; 42 | IoCompleteRequest(irp, IO_NO_INCREMENT); 43 | return nt_status; 44 | } 45 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/apc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef enum _KAPC_ENVIRONMENT { 6 | OriginalApcEnvironment, 7 | AttachedApcEnvironment, 8 | CurrentApcEnvironment, 9 | InsertApcEnvironment 10 | } KAPC_ENVIRONMENT, * PKAPC_ENVIRONMENT; 11 | 12 | typedef VOID(NTAPI* PKNORMAL_ROUTINE)( 13 | _In_ PVOID NormalContext, 14 | _In_ PVOID SystemArgument1, 15 | _In_ PVOID SystemArgument2 16 | ); 17 | 18 | typedef VOID KKERNEL_ROUTINE( 19 | _In_ PRKAPC Apc, 20 | _Inout_opt_ PKNORMAL_ROUTINE* NormalRoutine, 21 | _Inout_opt_ PVOID* NormalContext, 22 | _Inout_ PVOID* SystemArgument1, 23 | _Inout_ PVOID* SystemArgument2 24 | ); 25 | 26 | typedef KKERNEL_ROUTINE(NTAPI* PKKERNEL_ROUTINE); 27 | 28 | typedef VOID(NTAPI* PKRUNDOWN_ROUTINE)(_In_ PRKAPC Apc); 29 | 30 | extern "C" VOID NTAPI KeInitializeApc( 31 | _Out_ PRKAPC Apc, 32 | _In_ PRKTHREAD Thread, 33 | _In_ KAPC_ENVIRONMENT Environment, 34 | _In_ PKKERNEL_ROUTINE KernelRoutine, 35 | _In_opt_ PKRUNDOWN_ROUTINE RundownRoutine, 36 | _In_opt_ PKNORMAL_ROUTINE NormalRoutine, 37 | _In_opt_ KPROCESSOR_MODE ProcessorMode, 38 | _In_opt_ PVOID NormalContext 39 | ); 40 | 41 | extern "C" BOOLEAN NTAPI KeInsertQueueApc( 42 | _Inout_ PRKAPC Apc, 43 | _In_opt_ PVOID SystemArgument1, 44 | _In_opt_ PVOID SystemArgument2, 45 | _In_ KPRIORITY Increment 46 | ); 47 | 48 | NTSTATUS call_apc(PKTHREAD target_thread, PVOID target_function, PVOID params); 49 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "device_handlers.h" 4 | #include "consts.h" 5 | 6 | void driver_unload(PDRIVER_OBJECT driver_object) { 7 | UNICODE_STRING win32_name; 8 | RtlInitUnicodeString(&win32_name, DOS_DEVICE_NAME); 9 | IoDeleteSymbolicLink(&win32_name); 10 | if (nullptr != driver_object->DeviceObject) { 11 | IoDeleteDevice(driver_object->DeviceObject); 12 | } 13 | } 14 | 15 | extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { 16 | UNREFERENCED_PARAMETER(RegistryPath); 17 | 18 | DbgPrint("Hello from driver entry\n"); 19 | 20 | UNICODE_STRING nt_name; 21 | UNICODE_STRING win32_name; 22 | PDEVICE_OBJECT device_object = nullptr; 23 | 24 | RtlInitUnicodeString(&nt_name, NT_DEVICE_NAME); 25 | NTSTATUS nt_status = IoCreateDevice(DriverObject, 0, &nt_name, 26 | FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, 27 | TRUE, &device_object); 28 | 29 | if (!NT_SUCCESS(nt_status)) { 30 | DbgPrint("Couldn't create the device object\n"); 31 | return nt_status; 32 | } 33 | 34 | DriverObject->MajorFunction[IRP_MJ_CREATE] = device_create_close; 35 | DriverObject->MajorFunction[IRP_MJ_CLOSE] = device_create_close; 36 | DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = device_ioctl; 37 | DriverObject->DriverUnload = driver_unload; 38 | 39 | RtlInitUnicodeString(&win32_name, DOS_DEVICE_NAME); 40 | 41 | nt_status = IoCreateSymbolicLink(&win32_name, &nt_name); 42 | if (!NT_SUCCESS(nt_status)) { 43 | DbgPrint("Couldn't create symbolic link\n"); 44 | IoDeleteDevice(device_object); 45 | } 46 | 47 | return nt_status; 48 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # windows-kernel-dll-injector 2 | ## TL;DR 3 | Windows kernel mode to user mode dll injection 4 | 5 | Tested on Windows x64 1909 6 | 7 | Inject a dll to target process from kernel driver 8 | 9 | ## How its works 10 | The injection process is divided into several stages: 11 | 12 | 1. Attach current kernel thread to the virtual address space of the target process (KeStackAttachProcess) 13 | 2. Parse kernel32.dll PE header and locate LoadLibraryW function address 14 | * Get current process PEB (PsGetProcessPeb) 15 | * Iterate over all loaded modules and find kernel32.dll 16 | * Parse kernel32.dll PE header in order to find the address of LoadLibraryW 17 | 3. Allocate and copy to target process the APC callback arguments RW (ZwAllocateVirtualMemory) 18 | 4. Allocate and copy to target process the APC callback RWX (ZwAllocateVirtualMemory) 19 | 5. Detach from target process address space (KeUnstackDetachProcess) 20 | 6. Find all target process threads 21 | * ZwQuerySystemInformation(SystemProcessInformation...) 22 | * Iterate over all processes and find the target process by its id 23 | * Return all threads id of the target process 24 | 7. Inject APC to target process in order to execute our APC callback which loads the dll (KeInitializeApc & KeInsertQueueApc) 25 | 26 | The whole process described above happens in the kernel driver. The only things that the kernel module needs are: target pid, dll file path. 27 | 28 | ## Limitations 29 | * The current version supports only in x64 binaries 30 | * The current version doesn't release the APC callback or the APC callback arguments allocations 31 | 32 | ## Usage 33 | 34 | sc create DllInjector binPath= {driver_path} type= kernel 35 | 36 | sc start DllInjector 37 | 38 | DLLInjectorCom.exe {dll_path} {pid} 39 | 40 | DONE!!! 41 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/DLLInjector.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 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/dll_injection.cpp: -------------------------------------------------------------------------------- 1 | #include "dll_injection.h" 2 | 3 | #include 4 | 5 | #include "consts.h" 6 | #include "ProcessReference.h" 7 | #include "apc.h" 8 | #include "process.h" 9 | #include "pe.h" 10 | 11 | using LoadLibraryW = HANDLE(*)(LPCWSTR lpLibFileName); 12 | 13 | struct UserApcArgs { 14 | wchar_t dll_path[256]; 15 | LoadLibraryW load_library; 16 | }; 17 | 18 | #pragma optimize("", off) 19 | #pragma runtime_checks("", off ) 20 | void user_mode_apc_callback(UserApcArgs* args, PVOID, PVOID) { 21 | args->load_library(args->dll_path); 22 | } 23 | 24 | void user_mode_apc_callback_end() {} 25 | #pragma runtime_checks("", restore) 26 | #pragma optimize("", on) 27 | 28 | 29 | NTSTATUS inject_dll(const InjectDllArgs& inject_dll_args) { 30 | PVOID injected_apc_args = nullptr; 31 | PVOID injected_apc_callback = nullptr; 32 | ProcessInfo process_info; 33 | PKTHREAD target_thread; 34 | { 35 | // Attack to target process 36 | ProcessReference process_reference; 37 | CHECK(process_reference.init(inject_dll_args.pid, true)); 38 | 39 | UserApcArgs user_apc_args; 40 | memcpy(&user_apc_args.dll_path, &inject_dll_args.dll_path, 256); 41 | user_apc_args.load_library = (LoadLibraryW)get_module_symbol_address((wchar_t*)L"KERNEL32.DLL", "LoadLibraryW"); 42 | if (nullptr == user_apc_args.load_library) { 43 | return STATUS_UNSUCCESSFUL; 44 | } 45 | 46 | // Allocate and copy the dll path to target process 47 | SIZE_T apc_args_allocation_size = sizeof(UserApcArgs); 48 | CHECK(ZwAllocateVirtualMemory(NtCurrentProcess(), &injected_apc_args, 0, &apc_args_allocation_size, MEM_COMMIT, PAGE_READWRITE)); 49 | RtlCopyMemory(injected_apc_args, &user_apc_args, sizeof(UserApcArgs)); 50 | 51 | // Allocate and copy the apc user mode callback code to target process 52 | SIZE_T code_size = reinterpret_cast(user_mode_apc_callback_end) - reinterpret_cast(user_mode_apc_callback); 53 | if (!NT_SUCCESS(ZwAllocateVirtualMemory(NtCurrentProcess(), &injected_apc_callback, NULL, &code_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE))) { 54 | ZwFreeVirtualMemory(NtCurrentProcess(), &injected_apc_args, &apc_args_allocation_size, MEM_RELEASE); 55 | return STATUS_UNSUCCESSFUL; 56 | } 57 | 58 | RtlCopyMemory(injected_apc_callback, &user_mode_apc_callback, reinterpret_cast(user_mode_apc_callback_end) - reinterpret_cast(user_mode_apc_callback)); 59 | } 60 | 61 | CHECK(get_process_info_by_pid(inject_dll_args.pid, &process_info)); 62 | 63 | for (size_t i = 0; i < process_info.number_of_threads; i++) { 64 | if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE)process_info.threads_id[i], &target_thread))) { 65 | ExFreePool(process_info.threads_id); 66 | return STATUS_UNSUCCESSFUL; 67 | } 68 | 69 | // Execute LoadLibrary in the target process in order to load our dll 70 | call_apc(target_thread, injected_apc_callback, injected_apc_args); 71 | ObDereferenceObject(target_thread); 72 | } 73 | return STATUS_SUCCESS; 74 | } 75 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30907.101 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLLInjector", "DLLInjector\DLLInjector.vcxproj", "{3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLLInjectorCom", "DLLInjectorCom\DLLInjectorCom.vcxproj", "{3B559C45-3EBD-4B6C-A434-9E03BA55C797}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|ARM = Debug|ARM 13 | Debug|ARM64 = Debug|ARM64 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|ARM = Release|ARM 17 | Release|ARM64 = Release|ARM64 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|ARM.ActiveCfg = Debug|ARM 23 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|ARM.Build.0 = Debug|ARM 24 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|ARM.Deploy.0 = Debug|ARM 25 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|ARM64.ActiveCfg = Debug|ARM64 26 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|ARM64.Build.0 = Debug|ARM64 27 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|ARM64.Deploy.0 = Debug|ARM64 28 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|x64.ActiveCfg = Debug|x64 29 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|x64.Build.0 = Debug|x64 30 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|x64.Deploy.0 = Debug|x64 31 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|x86.ActiveCfg = Debug|Win32 32 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|x86.Build.0 = Debug|Win32 33 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Debug|x86.Deploy.0 = Debug|Win32 34 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|ARM.ActiveCfg = Release|ARM 35 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|ARM.Build.0 = Release|ARM 36 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|ARM.Deploy.0 = Release|ARM 37 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|ARM64.ActiveCfg = Release|ARM64 38 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|ARM64.Build.0 = Release|ARM64 39 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|ARM64.Deploy.0 = Release|ARM64 40 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|x64.ActiveCfg = Release|x64 41 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|x64.Build.0 = Release|x64 42 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|x64.Deploy.0 = Release|x64 43 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|x86.ActiveCfg = Release|Win32 44 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|x86.Build.0 = Release|Win32 45 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB}.Release|x86.Deploy.0 = Release|Win32 46 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Debug|ARM.ActiveCfg = Debug|Win32 47 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Debug|ARM64.ActiveCfg = Debug|Win32 48 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Debug|x64.ActiveCfg = Debug|x64 49 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Debug|x64.Build.0 = Debug|x64 50 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Debug|x86.ActiveCfg = Debug|Win32 51 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Debug|x86.Build.0 = Debug|Win32 52 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Release|ARM.ActiveCfg = Release|Win32 53 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Release|ARM64.ActiveCfg = Release|Win32 54 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Release|x64.ActiveCfg = Release|x64 55 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Release|x64.Build.0 = Release|x64 56 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Release|x86.ActiveCfg = Release|Win32 57 | {3B559C45-3EBD-4B6C-A434-9E03BA55C797}.Release|x86.Build.0 = Release|Win32 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(ExtensibilityGlobals) = postSolution 63 | SolutionGuid = {3A47E694-3390-40C4-9923-73A6A58F54E7} 64 | EndGlobalSection 65 | EndGlobal 66 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/process.cpp: -------------------------------------------------------------------------------- 1 | #include "process.h" 2 | 3 | #include 4 | 5 | #define SystemProcessInformation 5 6 | 7 | extern "C" NTSTATUS NTAPI ZwQuerySystemInformation(IN size_t SystemInformationClass, 8 | OUT PVOID SystemInformation, 9 | IN ULONG SystemInformationLength, 10 | OUT PULONG ReturnLength OPTIONAL); 11 | typedef struct _VM_COUNTERS { 12 | SIZE_T PeakVirtualSize; 13 | SIZE_T VirtualSize; 14 | ULONG PageFaultCount; 15 | // Padding here in 64-bit 16 | SIZE_T PeakWorkingSetSize; 17 | SIZE_T WorkingSetSize; 18 | SIZE_T QuotaPeakPagedPoolUsage; 19 | SIZE_T QuotaPagedPoolUsage; 20 | SIZE_T QuotaPeakNonPagedPoolUsage; 21 | SIZE_T QuotaNonPagedPoolUsage; 22 | SIZE_T PagefileUsage; 23 | SIZE_T PeakPagefileUsage; 24 | } VM_COUNTERS; 25 | 26 | struct SYSTEM_THREAD_INFORMATION { 27 | ULONGLONG KernelTime; 28 | ULONGLONG UserTime; 29 | ULONGLONG CreateTime; 30 | ULONG WaitTime; 31 | // Padding here in 64-bit 32 | PVOID StartAddress; 33 | CLIENT_ID ClientId; 34 | KPRIORITY Priority; 35 | LONG BasePriority; 36 | ULONG ContextSwitchCount; 37 | ULONG State; 38 | KWAIT_REASON WaitReason; 39 | }; 40 | 41 | typedef struct _IO_COUNTERS { 42 | ULONGLONG ReadOperationCount; 43 | ULONGLONG WriteOperationCount; 44 | ULONGLONG OtherOperationCount; 45 | ULONGLONG ReadTransferCount; 46 | ULONGLONG WriteTransferCount; 47 | ULONGLONG OtherTransferCount; 48 | } IO_COUNTERS; 49 | 50 | struct SYSTEM_PROCESS_INFORMATION { 51 | ULONG NextEntryOffset; 52 | ULONG NumberOfThreads; 53 | ULONGLONG WorkingSetPrivateSize; 54 | ULONG HardFaultCount; 55 | ULONG Reserved1; 56 | ULONGLONG CycleTime; 57 | ULONGLONG CreateTime; 58 | ULONGLONG UserTime; 59 | ULONGLONG KernelTime; 60 | UNICODE_STRING ImageName; 61 | KPRIORITY BasePriority; 62 | HANDLE ProcessId; 63 | HANDLE ParentProcessId; 64 | ULONG HandleCount; 65 | ULONG Reserved2[2]; 66 | // Padding here in 64-bit 67 | VM_COUNTERS VirtualMemoryCounters; 68 | size_t Reserved3; 69 | IO_COUNTERS IoCounters; 70 | SYSTEM_THREAD_INFORMATION Threads[1]; 71 | }; 72 | 73 | PVOID get_all_processes() { 74 | size_t processes_allocation_size = 0; 75 | PVOID processes_pool = nullptr; 76 | 77 | while (true) { 78 | processes_allocation_size += 0x10000; 79 | processes_pool = ExAllocatePool(PagedPool, processes_allocation_size); 80 | 81 | auto status = ZwQuerySystemInformation(SystemProcessInformation, processes_pool, (ULONG)processes_allocation_size, nullptr); 82 | if (status == STATUS_INFO_LENGTH_MISMATCH) { 83 | ExFreePool(processes_pool); 84 | } 85 | else { 86 | break; 87 | } 88 | } 89 | return processes_pool; 90 | } 91 | 92 | NTSTATUS get_process_info_by_pid(size_t pid, ProcessInfo* process_info) { 93 | size_t number_of_processes = 0; 94 | ProcessInfo* processes = get_processes_info(&number_of_processes); 95 | if (nullptr == processes) { 96 | return STATUS_UNSUCCESSFUL; 97 | } 98 | for (size_t i = 0; i < number_of_processes; i++) { 99 | if (pid == (processes + i)->process_id) { 100 | *process_info = *(processes + i); 101 | (processes + i)->threads_id = nullptr; 102 | } 103 | } 104 | for (size_t i = 0; i < number_of_processes; i++) { 105 | if (nullptr != (processes + i)->threads_id && (processes + i)->number_of_threads > 0) { 106 | ExFreePool((processes + i)->threads_id); 107 | } 108 | } 109 | ExFreePool(processes); 110 | return STATUS_SUCCESS; 111 | } 112 | 113 | ProcessInfo* get_processes_info(size_t* number_of_processes) { 114 | PVOID all_processes = get_all_processes(); 115 | if (nullptr == all_processes) { 116 | return nullptr; 117 | } 118 | *number_of_processes = 0; 119 | for (auto process = (SYSTEM_PROCESS_INFORMATION*)all_processes; process->NextEntryOffset != 0; 120 | process = (SYSTEM_PROCESS_INFORMATION*)((char*)process + process->NextEntryOffset)) { 121 | *number_of_processes += 1; 122 | } 123 | 124 | auto processes_info = (ProcessInfo*)ExAllocatePool(PagedPool, sizeof(ProcessInfo) * *number_of_processes); 125 | 126 | size_t i = 0; 127 | for (auto process = (SYSTEM_PROCESS_INFORMATION*)all_processes; process->NextEntryOffset != 0; 128 | process = (SYSTEM_PROCESS_INFORMATION*)((char*)process + process->NextEntryOffset), ++i) { 129 | (processes_info + i)->process_id = (size_t)process->ProcessId; 130 | (processes_info + i)->number_of_threads = (size_t)process->NumberOfThreads; 131 | if (0 == process->NumberOfThreads) { 132 | continue; 133 | } 134 | (processes_info + i)->threads_id = (size_t*)ExAllocatePool(PagedPool, sizeof(size_t) * process->NumberOfThreads); 135 | for (size_t j = 0; j < process->NumberOfThreads; j++) { 136 | *(((ProcessInfo*)(processes_info + i))->threads_id + j) = (size_t)process->Threads[j].ClientId.UniqueThread; 137 | } 138 | } 139 | 140 | ExFreePool(all_processes); 141 | return processes_info; 142 | } 143 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjectorCom/DLLInjectorCom.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 | {3b559c45-3ebd-4b6c-a434-9e03ba55c797} 25 | DLLInjectorCom 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) 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) 118 | true 119 | MultiThreadedDebug 120 | 121 | 122 | Console 123 | true 124 | 125 | 126 | 127 | 128 | Level3 129 | true 130 | true 131 | true 132 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 133 | true 134 | MultiThreaded 135 | 136 | 137 | Console 138 | true 139 | true 140 | true 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/DLLInjector.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 | Debug 22 | ARM 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Debug 30 | ARM64 31 | 32 | 33 | Release 34 | ARM64 35 | 36 | 37 | 38 | {3CAA899B-B384-42CA-ABB1-7FEEE57B31BB} 39 | {dd38f7fc-d7bd-488b-9242-7d8754cde80d} 40 | v4.5 41 | 12.0 42 | Debug 43 | Win32 44 | DLLInjector 45 | 46 | 47 | 48 | Windows10 49 | true 50 | WindowsKernelModeDriver10.0 51 | Driver 52 | WDM 53 | 54 | 55 | Windows10 56 | false 57 | WindowsKernelModeDriver10.0 58 | Driver 59 | WDM 60 | 61 | 62 | Windows10 63 | true 64 | WindowsKernelModeDriver10.0 65 | Driver 66 | WDM 67 | 68 | 69 | Windows10 70 | false 71 | WindowsKernelModeDriver10.0 72 | Driver 73 | WDM 74 | 75 | 76 | Windows10 77 | true 78 | WindowsKernelModeDriver10.0 79 | Driver 80 | WDM 81 | 82 | 83 | Windows10 84 | false 85 | WindowsKernelModeDriver10.0 86 | Driver 87 | WDM 88 | 89 | 90 | Windows10 91 | true 92 | WindowsKernelModeDriver10.0 93 | Driver 94 | WDM 95 | 96 | 97 | Windows10 98 | false 99 | WindowsKernelModeDriver10.0 100 | Driver 101 | WDM 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | DbgengKernelDebugger 113 | 114 | 115 | DbgengKernelDebugger 116 | 117 | 118 | DbgengKernelDebugger 119 | 120 | 121 | DbgengKernelDebugger 122 | 123 | 124 | DbgengKernelDebugger 125 | 126 | 127 | DbgengKernelDebugger 128 | 129 | 130 | DbgengKernelDebugger 131 | 132 | 133 | DbgengKernelDebugger 134 | 135 | 136 | 137 | false 138 | 139 | 140 | 141 | 142 | false 143 | 144 | 145 | 146 | 147 | false 148 | 149 | 150 | 151 | 152 | false 153 | 154 | 155 | 156 | 157 | false 158 | 159 | 160 | 161 | 162 | false 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /DLLInjector/DLLInjector/pe.cpp: -------------------------------------------------------------------------------- 1 | #include "pe.h" 2 | 3 | #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 4 | #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 5 | 6 | typedef unsigned long DWORD; 7 | typedef int BOOL; 8 | typedef unsigned char BYTE; 9 | typedef unsigned short WORD; 10 | 11 | typedef struct _PEB_LDR_DATA { 12 | ULONG Length; 13 | BOOLEAN Initialized; 14 | PVOID SsHandle; 15 | LIST_ENTRY InLoadOrderModuleList; 16 | LIST_ENTRY InMemoryOrderModuleList; 17 | LIST_ENTRY InInitializationOrderModuleList; 18 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 19 | 20 | 21 | typedef struct _PEB { 22 | BYTE Reserved1[2]; 23 | BYTE BeingDebugged; 24 | BYTE Reserved2[1]; 25 | PVOID Reserved3[2]; 26 | PPEB_LDR_DATA Ldr; 27 | PVOID ProcessParameters; 28 | PVOID Reserved4[3]; 29 | PVOID AtlThunkSListPtr; 30 | PVOID Reserved5; 31 | ULONG Reserved6; 32 | PVOID Reserved7; 33 | ULONG Reserved8; 34 | ULONG AtlThunkSListPtr32; 35 | PVOID Reserved9[45]; 36 | BYTE Reserved10[96]; 37 | PVOID PostProcessInitRoutine; 38 | BYTE Reserved11[128]; 39 | PVOID Reserved12[1]; 40 | ULONG SessionId; 41 | } PEB, * PPEB; 42 | 43 | //0x110 bytes (sizeof) 44 | struct LDR_DATA_TABLE_ENTRY { 45 | struct _LIST_ENTRY InLoadOrderLinks; //0x0 46 | struct _LIST_ENTRY InMemoryOrderLinks; //0x10 47 | union 48 | { 49 | struct _LIST_ENTRY InInitializationOrderLinks; //0x20 50 | struct _LIST_ENTRY InProgressLinks; //0x20 51 | }; 52 | VOID* DllBase; //0x30 53 | VOID* EntryPoint; //0x38 54 | ULONG SizeOfImage; //0x40 55 | struct _UNICODE_STRING FullDllName; //0x48 56 | struct _UNICODE_STRING BaseDllName; //0x58 57 | union 58 | { 59 | UCHAR FlagGroup[4]; //0x68 60 | ULONG Flags; //0x68 61 | struct 62 | { 63 | ULONG PackagedBinary : 1; //0x68 64 | ULONG MarkedForRemoval : 1; //0x68 65 | ULONG ImageDll : 1; //0x68 66 | ULONG LoadNotificationsSent : 1; //0x68 67 | ULONG TelemetryEntryProcessed : 1; //0x68 68 | ULONG ProcessStaticImport : 1; //0x68 69 | ULONG InLegacyLists : 1; //0x68 70 | ULONG InIndexes : 1; //0x68 71 | ULONG ShimDll : 1; //0x68 72 | ULONG InExceptionTable : 1; //0x68 73 | ULONG ReservedFlags1 : 2; //0x68 74 | ULONG LoadInProgress : 1; //0x68 75 | ULONG ReservedFlags2 : 1; //0x68 76 | ULONG EntryProcessed : 1; //0x68 77 | ULONG ReservedFlags3 : 3; //0x68 78 | ULONG DontCallForThreads : 1; //0x68 79 | ULONG ProcessAttachCalled : 1; //0x68 80 | ULONG ProcessAttachFailed : 1; //0x68 81 | ULONG CorDeferredValidate : 1; //0x68 82 | ULONG CorImage : 1; //0x68 83 | ULONG DontRelocate : 1; //0x68 84 | ULONG CorILOnly : 1; //0x68 85 | ULONG ReservedFlags5 : 3; //0x68 86 | ULONG Redirected : 1; //0x68 87 | ULONG ReservedFlags6 : 2; //0x68 88 | ULONG CompatDatabaseProcessed : 1; //0x68 89 | }A; 90 | }; 91 | USHORT ObsoleteLoadCount; //0x6c 92 | USHORT TlsIndex; //0x6e 93 | struct _LIST_ENTRY HashLinks; //0x70 94 | ULONG TimeDateStamp; //0x80 95 | struct _ACTIVATION_CONTEXT* EntryPointActivationContext; //0x88 96 | VOID* PatchInformation; //0x90 97 | struct _LDR_DDAG_NODE* DdagNode; //0x98 98 | struct _LIST_ENTRY NodeModuleLink; //0xa0 99 | struct _LDRP_DLL_SNAP_CONTEXT* SnapContext; //0xb0 100 | VOID* ParentDllBase; //0xb8 101 | VOID* SwitchBackContext; //0xc0 102 | struct _RTL_BALANCED_NODE BaseAddressIndexNode; //0xc8 103 | struct _RTL_BALANCED_NODE MappingInfoIndexNode; //0xe0 104 | ULONGLONG OriginalBase; //0xf8 105 | union _LARGE_INTEGER LoadTime; //0x100 106 | ULONG BaseNameHashValue; //0x108 107 | enum _LDR_DLL_LOAD_REASON LoadReason; //0x10c 108 | }; 109 | 110 | typedef struct _IMAGE_DOS_HEADER 111 | { 112 | WORD e_magic; 113 | WORD e_cblp; 114 | WORD e_cp; 115 | WORD e_crlc; 116 | WORD e_cparhdr; 117 | WORD e_minalloc; 118 | WORD e_maxalloc; 119 | WORD e_ss; 120 | WORD e_sp; 121 | WORD e_csum; 122 | WORD e_ip; 123 | WORD e_cs; 124 | WORD e_lfarlc; 125 | WORD e_ovno; 126 | WORD e_res[4]; 127 | WORD e_oemid; 128 | WORD e_oeminfo; 129 | WORD e_res2[10]; 130 | LONG e_lfanew; 131 | } IMAGE_DOS_HEADER, * PIMAGE_DOS_HEADER; 132 | 133 | typedef struct _IMAGE_FILE_HEADER { 134 | WORD Machine; 135 | WORD NumberOfSections; 136 | DWORD TimeDateStamp; 137 | DWORD PointerToSymbolTable; 138 | DWORD NumberOfSymbols; 139 | WORD SizeOfOptionalHeader; 140 | WORD Characteristics; 141 | } IMAGE_FILE_HEADER, * PIMAGE_FILE_HEADER; 142 | 143 | typedef struct _IMAGE_DATA_DIRECTORY { 144 | DWORD VirtualAddress; 145 | DWORD Size; 146 | } IMAGE_DATA_DIRECTORY, * PIMAGE_DATA_DIRECTORY; 147 | 148 | typedef struct _IMAGE_OPTIONAL_HEADER64 { 149 | WORD Magic; 150 | BYTE MajorLinkerVersion; 151 | BYTE MinorLinkerVersion; 152 | DWORD SizeOfCode; 153 | DWORD SizeOfInitializedData; 154 | DWORD SizeOfUninitializedData; 155 | DWORD AddressOfEntryPoint; 156 | DWORD BaseOfCode; 157 | ULONGLONG ImageBase; 158 | DWORD SectionAlignment; 159 | DWORD FileAlignment; 160 | WORD MajorOperatingSystemVersion; 161 | WORD MinorOperatingSystemVersion; 162 | WORD MajorImageVersion; 163 | WORD MinorImageVersion; 164 | WORD MajorSubsystemVersion; 165 | WORD MinorSubsystemVersion; 166 | DWORD Win32VersionValue; 167 | DWORD SizeOfImage; 168 | DWORD SizeOfHeaders; 169 | DWORD CheckSum; 170 | WORD Subsystem; 171 | WORD DllCharacteristics; 172 | ULONGLONG SizeOfStackReserve; 173 | ULONGLONG SizeOfStackCommit; 174 | ULONGLONG SizeOfHeapReserve; 175 | ULONGLONG SizeOfHeapCommit; 176 | DWORD LoaderFlags; 177 | DWORD NumberOfRvaAndSizes; 178 | IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 179 | } IMAGE_OPTIONAL_HEADER64, * PIMAGE_OPTIONAL_HEADER64; 180 | 181 | typedef struct _IMAGE_NT_HEADERS64 { 182 | DWORD Signature; 183 | IMAGE_FILE_HEADER FileHeader; 184 | IMAGE_OPTIONAL_HEADER64 OptionalHeader; 185 | } IMAGE_NT_HEADERS64, * PIMAGE_NT_HEADERS64; 186 | 187 | typedef struct _IMAGE_EXPORT_DIRECTORY { 188 | ULONG Characteristics; 189 | ULONG TimeDateStamp; 190 | USHORT MajorVersion; 191 | USHORT MinorVersion; 192 | ULONG Name; 193 | ULONG Base; 194 | ULONG NumberOfFunctions; 195 | ULONG NumberOfNames; 196 | ULONG AddressOfFunctions; 197 | ULONG AddressOfNames; 198 | ULONG AddressOfNameOrdinals; 199 | } IMAGE_EXPORT_DIRECTORY, * PIMAGE_EXPORT_DIRECTORY; 200 | 201 | extern "C" PPEB NTAPI PsGetProcessPeb(IN PEPROCESS Process); 202 | 203 | PVOID find_symbol_address(BYTE* module_address, char* symbol_name) { 204 | auto dos_header = (IMAGE_DOS_HEADER*)module_address; 205 | auto nt_headers64 = (IMAGE_NT_HEADERS64*)(module_address + dos_header->e_lfanew); 206 | auto optional_header = (IMAGE_OPTIONAL_HEADER64*)&nt_headers64->OptionalHeader; 207 | auto export_directory = &optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 208 | auto export_table = (IMAGE_EXPORT_DIRECTORY*)(module_address + export_directory->VirtualAddress); 209 | for (size_t i = 0; i < export_table->NumberOfNames; i++) { 210 | auto function_name_offset = *(ULONG*)(module_address + export_table->AddressOfNames + (sizeof(export_table->AddressOfNames) * i)); 211 | auto function_name = (char*)module_address + (size_t)function_name_offset; 212 | if (0 == strcmp(function_name, symbol_name)) { 213 | return module_address + *(ULONG*)(module_address + export_table->AddressOfFunctions + (sizeof(export_table->AddressOfFunctions) * i)); 214 | } 215 | } 216 | return nullptr; 217 | } 218 | 219 | PVOID get_module_symbol_address(wchar_t* module_name, char* symbol_name) { 220 | PPEB peb = PsGetProcessPeb(PsGetCurrentProcess()); 221 | auto module_entry = (LDR_DATA_TABLE_ENTRY*)((char*)peb->Ldr->InLoadOrderModuleList.Flink); 222 | do { 223 | if (nullptr != wcsstr(module_entry->FullDllName.Buffer, module_name)) { 224 | return find_symbol_address((BYTE*)module_entry->DllBase, symbol_name); 225 | } 226 | module_entry = (LDR_DATA_TABLE_ENTRY*)((char*)module_entry->InLoadOrderLinks.Flink); 227 | } 228 | while (module_entry != nullptr); 229 | return nullptr; 230 | } --------------------------------------------------------------------------------