hasherezade / pe-sieve

Scans a given process. Recognizes and dumps a variety of potentially malicious implants (replaced/injected PEs, shellcodes, hooks, in-memory patches).
https://hshrzd.wordpress.com/pe-sieve/
BSD 2-Clause "Simplified" License
3.09k stars 432 forks source link

DLL injection detection #19

Open simakhan785 opened 6 years ago

simakhan785 commented 6 years ago

Hi, I am currently experimenting with pe-sieve for detection of various DLL injection methods. but I have found it is able to detect only the reflective DLL injection. What about the other mode of DLL injection - such as using -a) CreateRemoteThread, b) NtCreateThreadEx etc. How pe-sieve can be used to detect those things.

thanks, Sima

hasherezade commented 6 years ago

Hi! Indeed, the classic DLL injection (such as this one) is not supported yet. But it is on my TODO list and it will be implemented in the future.

muse117 commented 3 years ago

Hi, Is the classic DLL injection already supported?

muse117 commented 3 years ago

Hi! Indeed, the classic DLL injection (such as this one) is not supported yet. But it is on my TODO list and it will be implemented in the future.

Hi, How to detect a classic DLL injection?

hasherezade commented 3 years ago

Sorry, this is not supported yet. It is rarely used by malware so I give it a low priority. But sure I am planning to add it at some point.

muse117 commented 3 years ago

Sorry, this is not supported yet. It is rarely used by malware so I give it a low priority. But sure I am planning to add it at some point.

I hope to add APC injection. This will be perfect! ^_^

hasherezade commented 3 years ago

I hope to add APC injection. This will be perfect! ^_^

"APC injection" is in reality about how you run the injected code, not about how you implant it. In contrast, the detection in PE-sieve is about how the code was implanted. So, it works the same for all the code running methods - whether you add the code as a new thread, or to the existing thread. This includes APC injection. As long as the implant can be found, PE-sieve detects it.

hasherezade commented 3 years ago

Classic DLL injection is atypical in this way, that the DLL is mapped in a legitimate way - using LoadLibrary. Which means that the characteristics of mapping are indistinguishable from the normally loaded DLL. This is what makes this type of injection more difficult to detect (and also very prone to false positives). It is not about how the code was run (whether you used CreateRemoteThread / NtCreateThreadEx / APC injection / others).

muse117 commented 3 years ago

Classic DLL injection is atypical in this way, that the DLL is mapped in a legitimate way - using LoadLibrary. Which means that the characteristics of mapping are indistinguishable from the normally loaded DLL. This is what makes this type of injection more difficult to detect (and also very prone to false positives). It is not about how the code was run (whether you used CreateRemoteThread / NtCreateThreadEx / APC injection / others).

wonderful! l learn to so much from you, thx a lot of!

hasherezade commented 3 years ago

Classic DLL injection is atypical in this way, that the DLL is mapped in a legitimate way - using LoadLibrary. Which means that the characteristics of mapping are indistinguishable from the normally loaded DLL. This is what makes this type of injection more difficult to detect (and also very prone to false positives). It is not about how the code was run (whether you used CreateRemoteThread / NtCreateThreadEx / APC injection / others).

wonderful! l learn to so much from you, thx a lot of!

If you will like to learn more about PE-sieve internals, I recommend you to see my presentation about it: https://www.youtube.com/watch?v=fwo4XE2xgis

AndyWatterman commented 2 years ago

"APC injection" is in reality about how you run the injected code,

It seems this is a bit incorrect. It is possible to use APC to run gadgets, but not to run the injected code. Thus, it might becomes about "how you implant it".

hasherezade commented 2 years ago

"APC injection" is in reality about how you run the injected code,

It seems this is a bit incorrect. It is possible to use APC to run gadgets, but not to run the injected code. Thus, it might becomes about "how you implant it".

@AndyWatterman - Sorry, but you are incorrect. Running the injected code with APC is totally fine. It really doesn't matter if you add to an APC a pointer to a gadget, or a pointer to the code that you just implanted. It just has to be a pointer that points to valid code. Check out this example:

https://github.com/hasherezade/demos/blob/master/inject_shellcode/src/main.cpp#L54

First you map the shellcode to the remote process, and then you add the pointer to the beginning of the shellcode to the APC of the selected thread, just like this:

 if ((status = NtQueueApcThread(hThread, remote_shellcode_ptr, 0, 0, 0)) != STATUS_SUCCESS)
...

Thus, what I previously said is correct:

"APC injection" is in reality about how you run the injected code

APC is not used for implanting the code, but exactly for running it.

AndyWatterman commented 2 years ago

The question is "Could we use APC to run chain (or some elements from) like VirtualAlloc, VirtualProtect and, then, NtWriteVirtualMemory(or any similar gadget) as many times as necessary to fill previously allocated buffer?". We could construct our shellcode from bytes and gadgets of the original program, not necessary to map anything first. So, if we can do this, thus it means we can use APC for injection without previously mapped shellcode. Therefore, it becomes about "how you implant it" (by using APC), but not only "how to run injected code". Am I right? :-)

As the result: "APC injection" is in reality about how you may inject and run some code.

hasherezade commented 2 years ago

You first wrote:

It is possible to use APC to run gadgets, but not to run the injected code.

so my answer was: sure, you can run gadgets, but it is not just for gadgets - you can use it to run the injected code directly too.

Now regarding:

The question is "Could we use APC to run chain (or some elements from) like VirtualAlloc, VirtualProtect and, then, NtWriteVirtualMemory(or any similar gadget) as many times as necessary to fill previously allocated buffer?". We could construct our shellcode from bytes and gadgets of the original program, not necessary to map anything first. So, if we can do this, thus it means we can use APC for injection without previously mapped shellcode. Therefore, it becomes about "how you implant it" (by using APC), but not only "how to run injected code". Am I right? :-)

As the result: "APC injection" is in reality about how you may inject and run some code.

Sure you can call this sequence via gadgets, but still I would not say that it means that "the APC was used for the injection". APC was just used for running the stub composed of gadgets. What you used for the injection was the sequence of the functions: VirtualAlloc, VirtualProtect, NtWriteVirtualMemory. And why does it matter? Because from the point of view of memory artifacts, it really doesn't matter if you call VirtualAlloc etc. via gadget, or if you call it directly. It will still leave the same artifacts. That's why it does not make it an APC-specific case.

AndyWatterman commented 2 years ago

APC was just used for running the stub composed of gadgets...

...to [purpose] inject a shellcode :-) Easy like this.

it really doesn't matter if you call VirtualAlloc etc. via gadget,

Here I absolutely agree with you.

This seems a wordplay. Thanks for the clarification.

hasherezade commented 2 years ago

APC was just used for running the stub composed of gadgets...

...to [purpose] inject a shellcode :-) Easy like this.

You can call it like this in a colloquial way, but since it is a thread about detecting memory artifacts, I am describing how it looks from this perspective.

Anyways I am glad that we clarified it now!