Injected code could represented by, but not limited to:
Remotely created thread could be detected by several techniques:
- Periodically check if process threads were created by current process using
NtQueryProcessInformation
.
For each thread check if it is running from the address space of the original executable and not from some orphaned memory page:
NtQueryInformationThread
- Set second parameter to
ThreadQuerySetWin32StartAddress
GetModuleInformation
- check if the thread starting address is in the range of each of the loaded modules and those modules are legit (by known list/by path).
- Check here too.
Monitor thread creating API inside current process and also check if the creating PID belong to current process - NtQueryProcessInformation
, CreateToolhelp32Snapshot
.
- Monitor memory protection APIs (
VirtualProtect
) to detect if someone tries to modify your code and then check if that "someone" belongs to legit process address space.
- By keeping the list of legit loaded modules, one also can check if each thread in process belong to address space of a legit module from the list.
- Monitor
LoadLibrary
for a chance someone trying to load unknown module into your process.
Injected code without thread
Check the integrity of your process - look for hot patching of various APIs, depends on the process. Injected code could be triggered by some patch inside current process.
Monitor APC creating API (KiUserApcDispatcher
) if the target code belongs to current process. OS's APC also could be filtered out.
There are other ways to inject code, even before the legit process will start to run and place its protections - using combination of WriteProcessMemory
/GetThreadContext
/SetThreadContext
which theoretically could bypass all your implemented protections. When your code and injected one are only running in the same ring (user mode), it all goes down to who is gaining control first. Look for code cave method and think for example when malcode is injected into explorer.exe and you are starting your program :-).
Of cause, you can load your driver into kernel, which will give you more solid control over the code injection to your process and a good protection, but that of cause depends on the skills and what you are trying to protect.