├── .gitattributes ├── .gitignore ├── NT APC Injector.sln ├── NT APC Injector ├── NT APC Injector.vcxproj ├── NT APC Injector.vcxproj.filters ├── header.h ├── inject.cpp ├── inject.h ├── main.cpp ├── ntapi.cpp ├── ntapi.h ├── process.cpp └── process.h └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /NT APC Injector.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.12 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NT APC Injector", "NT APC Injector\NT APC Injector.vcxproj", "{2AB2B13A-E425-4DD9-B278-231F0722D7D0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {2AB2B13A-E425-4DD9-B278-231F0722D7D0}.Debug|x64.ActiveCfg = Debug|x64 17 | {2AB2B13A-E425-4DD9-B278-231F0722D7D0}.Debug|x64.Build.0 = Debug|x64 18 | {2AB2B13A-E425-4DD9-B278-231F0722D7D0}.Debug|x86.ActiveCfg = Debug|Win32 19 | {2AB2B13A-E425-4DD9-B278-231F0722D7D0}.Debug|x86.Build.0 = Debug|Win32 20 | {2AB2B13A-E425-4DD9-B278-231F0722D7D0}.Release|x64.ActiveCfg = Release|x64 21 | {2AB2B13A-E425-4DD9-B278-231F0722D7D0}.Release|x64.Build.0 = Release|x64 22 | {2AB2B13A-E425-4DD9-B278-231F0722D7D0}.Release|x86.ActiveCfg = Release|Win32 23 | {2AB2B13A-E425-4DD9-B278-231F0722D7D0}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {48E79868-4FBC-4A7D-A645-B60130552404} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /NT APC Injector/NT APC 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 | 15.0 23 | {2AB2B13A-E425-4DD9-B278-231F0722D7D0} 24 | NTAPCInjector 25 | 10.0.15063.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | 79 | 80 | 81 | 82 | Level3 83 | Disabled 84 | true 85 | 86 | 87 | 88 | 89 | Level3 90 | MaxSpeed 91 | true 92 | true 93 | true 94 | 95 | 96 | true 97 | true 98 | 99 | 100 | 101 | 102 | Level3 103 | MaxSpeed 104 | true 105 | true 106 | true 107 | MultiThreaded 108 | 109 | 110 | true 111 | true 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /NT APC Injector/NT APC Injector.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;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 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | -------------------------------------------------------------------------------- /NT APC Injector/header.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "ntapi.h" 7 | #include "process.h" 8 | #include "inject.h" -------------------------------------------------------------------------------- /NT APC Injector/inject.cpp: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | using namespace std; 3 | 4 | BOOL ApcInjectDll(HANDLE ProcessHandle, BOOL bSuspendWake, char *DllPath) 5 | { 6 | NTSTATUS NtStatus; 7 | DWORD dwProcessId = GetProcessId(ProcessHandle); 8 | PVOID pvDllMemory = 0; // used later for memory allocation 9 | SIZE_T sDllLength = strlen(DllPath); // calculation for DLL path lenth 10 | SIZE_T NumberOfBytesWritten = 0; // used for memory write 11 | 12 | // check if the process handle exists 13 | if (!ProcessHandle || !dwProcessId) 14 | { 15 | return FALSE; 16 | } 17 | 18 | // array of function addresses 19 | FARPROC fpAddresses[6] = { 20 | GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"), 21 | GetProcAddress(GetModuleHandle("ntdll.dll"), "NtAllocateVirtualMemory"), 22 | GetProcAddress(GetModuleHandle("ntdll.dll"), "NtWriteVirtualMemory"), 23 | GetProcAddress(GetModuleHandle("ntdll.dll"), "NtSuspendThread"), 24 | GetProcAddress(GetModuleHandle("ntdll.dll"), "NtAlertResumeThread"), 25 | GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueueApcThread") 26 | }; 27 | 28 | // loop through the array 29 | for (FARPROC &fpAddress : fpAddresses) 30 | { 31 | if (!fpAddress) // address couldn't be obtained 32 | { 33 | // return nothing 34 | return 0; 35 | } 36 | } 37 | 38 | // setup for NTAPI functions 39 | pNtAllocateVirtualMemory fNtAllocateVirtualMemory = (pNtAllocateVirtualMemory)fpAddresses[1]; 40 | pNtWriteVirtualMemory fNtWriteVirtualMemory = (pNtWriteVirtualMemory)fpAddresses[2]; 41 | pNtSuspendThread fNtSuspendThread = (pNtSuspendThread)fpAddresses[3]; 42 | pNtAlertResumeThread fNtAlertResumeThread = (pNtAlertResumeThread)fpAddresses[4]; 43 | pNtQueueApcThread fNtQueueApcThread = (pNtQueueApcThread)fpAddresses[5]; 44 | 45 | // allocate memory with NtAllocateVirtualMemory 46 | if (NT_SUCCESS(fNtAllocateVirtualMemory(ProcessHandle, &pvDllMemory, NULL, &sDllLength, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) 47 | { 48 | 49 | // write to allocated memory with NtWriteVirtualMemory . store DLL file path 50 | if (NT_SUCCESS(fNtWriteVirtualMemory(ProcessHandle, pvDllMemory, DllPath, sDllLength, NULL))) 51 | { 52 | 53 | try { 54 | 55 | HANDLE ThreadHandle, hThreadHandle; 56 | THREADENTRY32 ThreadEntry32; 57 | ThreadEntry32.dwSize = sizeof(THREADENTRY32); 58 | hThreadHandle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 59 | 60 | // loop threads 61 | do { 62 | // check if the thread is within the target process we want to inject into 63 | if (ThreadEntry32.th32OwnerProcessID == dwProcessId) 64 | { 65 | // open thread handle with NtOpenThread 66 | ThreadHandle = NtOpenThread(dwProcessId, ThreadEntry32.th32ThreadID); 67 | 68 | // check if handle could be opened 69 | if (ThreadHandle) 70 | { 71 | 72 | if (bSuspendWake) 73 | { 74 | NtStatus = fNtSuspendThread(ThreadHandle, NULL); 75 | if (!NT_SUCCESS(NtStatus)) 76 | { 77 | goto cleanup; 78 | } 79 | } 80 | 81 | NtStatus = fNtQueueApcThread(ThreadHandle, (PIO_APC_ROUTINE)fpAddresses[0], pvDllMemory, NULL, NULL); 82 | 83 | if(bSuspendWake) 84 | { 85 | NtStatus = fNtAlertResumeThread(ThreadHandle, NULL); 86 | if (!NT_SUCCESS(NtStatus)) 87 | { 88 | goto cleanup; 89 | } 90 | } 91 | } 92 | 93 | // cleanup 94 | CloseHandle(ThreadHandle); 95 | } 96 | } while (Thread32Next(hThreadHandle, &ThreadEntry32)); 97 | } 98 | catch (...) 99 | { 100 | goto cleanup; 101 | } 102 | } 103 | } 104 | 105 | // cleanup 106 | cleanup: 107 | if (pvDllMemory) 108 | { 109 | VirtualFreeEx(ProcessHandle, pvDllMemory, sDllLength, MEM_RELEASE); 110 | } 111 | return FALSE; 112 | } -------------------------------------------------------------------------------- /NT APC Injector/inject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "header.h" 3 | 4 | BOOL ApcInjectDll(HANDLE ProcessHandle, BOOL bSuspendWake, char *DllPath); -------------------------------------------------------------------------------- /NT APC Injector/main.cpp: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | using namespace std; 3 | 4 | int main() 5 | { 6 | HANDLE ProcessHandle = NtOpenProcess(dwRetProcessId("notepad.exe")); 7 | if (ProcessHandle) 8 | { 9 | ApcInjectDll(ProcessHandle, TRUE, "C:\\opcode.dll"); 10 | } 11 | getchar(); 12 | return 0; 13 | } -------------------------------------------------------------------------------- /NT APC Injector/ntapi.cpp: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | 3 | HANDLE NtOpenProcess(DWORD dwProcessId) 4 | { 5 | FARPROC fpNtOpenProcess = GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenProcess"); 6 | if (fpNtOpenProcess && dwProcessId != NULL) 7 | { 8 | HANDLE ProcessHandle = 0; 9 | CLIENT_ID ClientId; 10 | OBJECT_ATTRIBUTES ObjectAttributes; 11 | InitializeObjectAttributes(&ObjectAttributes, NULL, NULL, NULL, NULL); 12 | ClientId.UniqueProcess = (PVOID)dwProcessId; 13 | ClientId.UniqueThread = (PVOID)0; 14 | pNtOpenProcess fNtOpenProcess = (pNtOpenProcess)fpNtOpenProcess; 15 | if (NT_SUCCESS(fNtOpenProcess(&ProcessHandle, MAXIMUM_ALLOWED, &ObjectAttributes, &ClientId))) 16 | { 17 | return ProcessHandle; 18 | } 19 | } 20 | return 0; 21 | } 22 | 23 | HANDLE NtOpenThread(DWORD dwProcessId, DWORD dwThreadId) 24 | { 25 | FARPROC fpNtOpenThread = GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenThread"); 26 | if (fpNtOpenThread) 27 | { 28 | HANDLE ThreadHandle = 0; 29 | OBJECT_ATTRIBUTES ObjectAttributes; 30 | CLIENT_ID ClientId; 31 | InitializeObjectAttributes(&ObjectAttributes, NULL, NULL, NULL, NULL); 32 | ClientId.UniqueProcess = (PVOID)dwProcessId; 33 | ClientId.UniqueThread = (PVOID)dwThreadId; 34 | pNtOpenThread fNtOpenThread = (pNtOpenThread)fpNtOpenThread; 35 | if (NT_SUCCESS(fNtOpenThread(&ThreadHandle, MAXIMUM_ALLOWED, &ObjectAttributes, &ClientId))) 36 | { 37 | if (ThreadHandle) 38 | { 39 | return ThreadHandle; 40 | } 41 | } 42 | } 43 | return 0; 44 | } -------------------------------------------------------------------------------- /NT APC Injector/ntapi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "header.h" 3 | 4 | #define STATUS_SUCCESS 0x00000000 5 | #define STATUS_UNSUCCESSFUL 0xC0000001 6 | #define STATUS_ACCESS_DENIED 0xC0000022 7 | 8 | typedef struct _CLIENT_ID { 9 | PVOID UniqueProcess; 10 | PVOID UniqueThread; 11 | }CLIENT_ID, *PCLIENT_ID; 12 | 13 | typedef NTSTATUS(NTAPI *pNtOpenProcess)(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId); 14 | typedef NTSTATUS(NTAPI *pNtOpenThread)(PHANDLE ThreadHandle, ACCESS_MASK AccessMask, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID); 15 | typedef NTSTATUS(NTAPI *pNtSuspendThread)(HANDLE ThreadHandle, PULONG SuspendCount); 16 | typedef NTSTATUS(NTAPI *pNtAlertResumeThread)(HANDLE ThreadHandle, PULONG SuspendCount); 17 | typedef NTSTATUS(NTAPI *pNtAllocateVirtualMemory)(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect); 18 | typedef NTSTATUS(NTAPI *pNtWriteVirtualMemory)(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, ULONG NumberOfBytesToWrite, PULONG NumberOfBytesWritten); 19 | typedef NTSTATUS(NTAPI *pNtQueueApcThread)(HANDLE ThreadHandle, PIO_APC_ROUTINE ApcRoutine, PVOID ApcRoutineContext OPTIONAL, PIO_STATUS_BLOCK ApcStatusBlock OPTIONAL, ULONG ApcReserved OPTIONAL); 20 | 21 | HANDLE NtOpenProcess(DWORD dwProcessId); 22 | HANDLE NtOpenThread(DWORD dwProcessId, DWORD dwThreadId); -------------------------------------------------------------------------------- /NT APC Injector/process.cpp: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | 3 | DWORD dwRetProcessId(std::string processname) 4 | { 5 | HANDLE hProcess; 6 | PROCESSENTRY32 processEntry32; 7 | processEntry32.dwSize = sizeof(PROCESSENTRY32); 8 | hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 9 | do { 10 | if (!strcmp(processEntry32.szExeFile, processname.c_str())) 11 | { 12 | CloseHandle(hProcess); 13 | return processEntry32.th32ProcessID; 14 | } 15 | } while (Process32Next(hProcess, &processEntry32)); 16 | CloseHandle(hProcess); 17 | return 0; 18 | } -------------------------------------------------------------------------------- /NT APC Injector/process.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "header.h" 3 | 4 | DWORD dwRetProcessId(std::string processname); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NT APC Injector 2 | 3 | bonjour 4 | 5 | This project demonstrates how you can use Asynchronous Procedure Calls (APC) to inject a DLL into another process; this project uses the NTAPI functions instead of Win32 API (NtQueueApcThread instead of QueueUserAPC and NtOpenThread instead of OpenThread). There is also an additional feature which supports suspending the thread (NtSuspendThread) prior to the APC injection and then resuming the thread with NtAlertResumeThread (wakes it up for APC to be executed - all optional though). 6 | 7 | I am not responsible for how you use this project, use it responsibly please. 8 | 9 | Merci bien --------------------------------------------------------------------------------