Often, a malicious author wants to be able to load non-disk backed code into memory. This could include code that was decrypted and unpacked (a second stage providing more functionality) or plugins to existing running code. After this non-disk backed code is loaded via some mechanism, it can be called normally, or a thread can be started in it. A fairly common detection for malware (and the gist behind the Powershell script Get-InjectedThread) is detecting threads running in memory that are not backed by files on disk.
What if I told you that we could create a thread with a built-in Microsoft Win32 API function, and by using this other function, we would not be detected by Get-InjectedThread? You might scoff because surely it could not be that simple.
Enter _beginthreadex: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/beginthread-beginthreadex?view=vs-2019
This lovely little function packs the entry point/arguments that we pass to it, and then starts a thread in msvcrt.dll at _threadstartex, passing to it this newly packed struct as the arguments. Quick note for coders: the function does affect how cleanup is performed, so read the full documentation and test before flipping every thread creation to use this function.
Avoiding Get-InjectedThread basically comes down to having your thread’s entry point backed by a file on disk. Since _threadstartex is the entry point passed to CreateThread, we pass this check and effectively avoid Get-InjectedThread. While this will not work for cross-process injections, it does work if you happen to be pushing down and loading more dynamic code into your already running process or starting threads in memory sections that you decrypt after starting.
Sometimes the simple things work best 🙂