├── .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
--------------------------------------------------------------------------------