I'm keeping a WhiteList of proceses in KM:
- Paths to executables are stored in UM.
- In ProcessNotifyRoutine I store the PID.
- In ImageNotifyRoutine I get the exepath (based on PID, on first match I discard this PID). And request UM if this program is whitelisted (it also checks the hash of the exe, so not just the path).
I don't really have control over any of the whitelisted processes, it is completely user-defined. So also the access that other programs have to these whitelisted processes is out of my control.
This implementation is working well, so I'm looking at steps to circumvent this setup. One of which is a malicious behaving program could create a remote thread in one of the whitelisted programs and I would see this as 'allowed' (I basically use IoThreadToProcess).
Now I've been looking into ways to at least detect this behavior. First I'd like to state what research I've done, where I am kind of stuck and I hope someone can point me in a correct direction to look.
First of all, I'm looking into ways to do this without having to hook any kernel functions(or any functions for that matter). I've talked to some (anti-)malware expert about this and this was the first thing he suggested. But I hope that there is a clean way to do this.
So I set my journey off looking at the thread and process structures(I have the Windows Internals book as well). I know there is a relation between a thread and it's owning process. And a relation between a process and a parent process. But after CreateRemoteThread the thread belongs to the injected process(correct?), so it will point to the whitelisted process' PEB which in turn gives me WhiteListed's parent.
I know that directly reading from these structures would be undocumented, but I am more confident to have some undocumented code as oppose to dirty code(hooks). Unless of course there is a documented way to get a thread's parent that I have overlooked ;).
So when this was sort-of a dead end I started testing with ThreadNotifyRoutine. I created a 'malicious' behaving process injecting a thread into another process and put an ASSERT in the notify routine.
I saw that when the NotificationRoutine was called, I was still in the context of the Attacker:
1: kd> !thread
THREAD fffffa800d3448c0 Cid 01d0.011c Teb: 000000007efdb000 Win32Thread: 0000000000000000 RUNNING on processor 1
Owning Process fffffa800d376060 Image: Attacker.exe
Which is something I don't understand. As far as I know, the NotificationRoutines are called at the end of Create(Remote)Thread, so I should already be in the context of the injected process.
I think this is where something is wrong with my attacker, I have tried another dll injector and it failed when running in the VM(that is how I do my debugging) but worked on my host.
So I'm guessing that if I DbgPrint in the ThreadNotifyRoutine and run it on my host with dbgview I will see that I am in the context of the injected process, I did not try this yet but I should.
I've looked at the CreateThread disassembly and it basically is a wrapper around CreateRemoteThread with PsGetCurrentProcess[-1] as HANDLE parameter. So I assume there is no real different between how a remote or a local thread is created(e.g. no obvious differences that I could 'expoit'). Except for some dedicated section in CreateRemoteTread where handle==PsGetCurrentProcess();
Next I thought about examining the callstack of a thread(in ThreadNotify isn't very useful.. as this is a new thread) at the point where I want to check if it belongs to a WhiteListed Process. I could then check if the call comes from a module inside the WhiteListed Process that I don't know about (injected DLL)... but there are so many caveats to this I don't consider it a good solution, if even possible atall.
That is basically where I stand at the moment, I know that CreateRemoteThread is not the only way to inject a thread but step by step I want to improve the solidity of the solution.
Hopefully someone can shed some light on this for me (I actually don't understand why there is no supported way to check this... provided of course that I did not miss it).