Thursday, December 8, 2011

Hiding Injected DLL in Windows

Errare humanum est... For some reasons, I have missed an important aspect of DLL injection in my previous article. Namely - hiding your injected DLL. It may be unnecessary when you inject DLL into your own process (e.g. for debugging purposes), but what if you are a tough malware researcher trying to trace the activity of some bad executable? In such case, the less you inform the malware you deal with about your presence - the better.

In this article I will cover the easiest way to hide your injected library from the "victim" process. Intentionally or not, but we will have to dive a bit into Windows internals starting with the TIB (Thread Information Block) and ending with good old UNICODE_STRING data structure.

TIB - Thread Information Block (aka TEB)
You may remember the [FS: 0x00000000] cell. There are thousands of resources mentioning this memory location (and this blog is not an exception) mainly as a location which contains the address of the latest EXCEPTION_REGISTRATION structure added. It is also the first cell of the Thread Information Block (TIB), which is a Win32 structure containing information about the running thread. 

I am not going to provide the full declaration of this structure here, as we have almost no interest in it. Those interested may read this. What we do need, is the data located at offset 0x30 in the TIB - the address of the Process Environment Block (PEB).

Depending on the programming language you are using, you need to do the  following in order to get the PEB address:

for Assemby:
   mov eax, [fs:0x30]  ;FASM syntax
   movl %fs:0x30, %eax   ;AT&T syntax (if you use mingw32, for instance)

for C:
/* Microsoft C */
   mov eax, fs:[0x30]
   mov [addr], eax

/* mingw32 */
__asm__("movl %%fs:0x30, %0":"=r"(addr));

in both cases addr is the name of the variable where you want to store the address of the PEB.

PEB - Process Environment Block
Alright, now we have the PEB address. But how should we store it? All is clear in case of Assembly - just store it as double word, but what about C? There are several options. Given that we are not going to do much with it, you can store it as an unsigned int or void*. In either case, I believe it will be interesting to see what lies beneath the name. Therefore, let's declare the _PEB structure and PEB type (you may take the declaration from here). There are several things that you have to keep in mind if you are writing in Assembly:
  1. BOOL should be defined as db (sizeof(BOOL) equals to sizeof(char)) should be defiend as dd (BOOL is 4 bytes while BOOLEAN is 1 - thanks Krystalgamer for pointing this out);
  2. BYTE speaks for itself and is equal to db;
  3. HANDLE, ULONG, PVOID, PPVOID and other pointers are all double words and should be defined as dd.
Field at offset 0x02 (BeingDebugged) may be used for debugger detection, however, this method may be unreliable and should be backed up by additional checks. But the field of interest for us is the LoaderData, located at offset 0x0C. This field contains the address of the PEB_LDR_DATA structure which will lead us to the list of loaded modules (the main executable that started the process and all the loaded DLLs).

There is not much to say about it. The structure itself is described below:

typedef struct _PEB_LDR_DATA
   ULONG      Length;
   BOOL       Initialized;
   PVOID      SsHandle;
   LIST_ENTRY InLoadOrderModuleList;
   LIST_ENTRY InMemoryOrderModuleList;
   LIST_ENTRY InInitializationOrderModuleList;

The LIST_ENTRY structure is declared as follows:

typedef struct _LIST_ENTRY
   struct _LIST_ENTRY  *Flink;
   struct _LIST_ENTRY  *Blink;

Each LIST_ENTRY structure in PEB_LDR_DATA represents a head of chain of structures, which in turn are parts of the LDR_MODULE structure (we will see that in a minute).
InLoadOrderModuleList represents the linked list of loaded modules ordered by the load order (first loaded module is the main executable).
InMemoryOrderModuleList represents the linked list of loaded modules ordered by their memory location (by their module handles).
InInitializationOrderModuleList represents the linked list of loaded modules in the order they were initialized. However, it is important to remember, that the Flink and Blink point to the LIST_ENTRY structures, not to the LDR_MODULE structures. Let me explain it in the next section.

We finally have reached the structure that we've been looking for. Each LDR_MODULE structure has all the basic information about one of the modules present in memory and the list of these structures is used by several Windows API functions (for example GetModuleHandle).

Let us inspect the declaration of the LDR_MODULE structure before we start looking for one related to our injected DLL:

typedef struct _LDR_MODULE
   LIST_ENTRY      InLoadOrderModuleList;
   LIST_ENTRY      InMemoryOrderModuleList;
   LIST_ENTRY      InInitializationOrderModuleList;
   PVOID           BaseAddress;
   PVOID           EntryPoint;
   ULONG           SizeOfImage;
   ULONG           Flags;
   SHORT           LoadCount;
   SHORT           TlsIndex;
   LIST_ENTRY      HashTableEntry;
   ULONG           TimeDateStamp;

It may be a good suggestion to use the InLoadOrderModuleList for going through the linked list of LDR_MODULE as its Blink and Flink pointers also point to the beginning of the LDR_MODULE structure, whereas, if you decide to use InMemoryOrderModuleList, you would have to subtract the size of LIST_ENTRY structure from either Flink or Blink in order to get the address of the LDR_MODULE structure. If you are masochistic enough to use InInitializationOrderModuleList, then you would have to subtract sizeof(LIST_ENTRY) * 2. I said masochistic, but it is not really that painful if you keep in mind that you are dealing with pointers and cast your variables properly.

Lets see what we have here. The first is the LIST_ENTRY structure used to link modules in the order they were loaded, the second - in the order they are positioned in virtual memory and the third - in the order they (modules) have been initialized.

BaseAddress is the actual address where the module is loaded at. In ideal case, it is equal to the ImageBase specified in the Optional Header of a PE file, but it may differ. 

EntryPoint is the address of the entry point of that specific module or NULL if the module has not entry point (which is allowable for DLLs).

SizeOfImage - the size of the image in memory.

FullDllName - full name of the module, including full path to the file. Important to mention that it is stored in the form of UNICODE_STRING which has the following format:

typedef struct _LSA_UNICODE_STRING
   USHORT Length;
   USHORT MaximumLength;
   PWSTR  Buffer;

BaseDllName - the name of the file itself. Represented as a UNICODE_STRING as well. Most likely, this is the field that you would use in order to find the entry related to your injected DLL.

Last Step
The last step to take in order to hide your injected DLL is to simply remove it from the linked list  of the LDR_MODULE structures. My assumption is that if you dare to mess with Windows internals, you probably know how to mess with linked lists and, therefore, are able to perform that operation. 

For those who doubt their knowledge this or may be even this link would give the idea.

We're almost done, but let me give you a good suggestion - keep a copy of the LDR_MODULE structure which describes your DLL somewhere and spend some additional time writing a function capable of inserting it back correctly in case of need.

I hope this article is helpful. See you at the next.

Almost forgot! Comments/suggestions are welcome and appreciated.


  1. Great post. This is also the path that a lot of malware uses to find DDLs. They walks one of the lists and check the hash of each name.


    "all double words and should be defined as dw" -->
    "all double words and should be defined as dd"

  2. This will hide your dll from simple scans, but there are others ways to detect dlls even after they have been unlinked from the system lists. For example, you could iterate through all of the allocated memory of a process, and see if there are any dll headers anywhere. Additionally, you could check for pages marked as executable that don't fall in the memory range of loaded dlls.

    A better approach would be to manually map your dll into memory so that it is never linked in the first place. This gives you much better control over the memory space, where your dll resides, allowing you to hide it by modifying the size of another dll in memory.

  3. First of all, there's no way to make it 100% undetectable, but there are numerous ways to prevent or disturb detection.

    Iteration through the allocated memory is a costly operation. More than that, you can clear the headers, so that this method would fail.

    Manual mapping is a good but much more complicated way of injection, as you have to take care of all the relocs and resolve all symbols manually.

    Regular injection does not prevent you from hiding it behind another dll either, but keep in mind that it may crash the application if, for example, the dll you use as a shield is unloaded.

    In addition, this does not give you better control of the memory locations. It gives you exactly the same level of control as regular injection. Even more then that, your sense of control is purely virtual. You may ask the OS for specific location, but you have no guarantee that you will get what you want.

    It is generally a bad habit to rely upon your ability to control anything. The more flexible your solution is, the better it is.

  4. Make topic about Manual mapping DLL into another process. How it work?

    1. Manual mapping is another fancy name for emulation of what Windows loader is responsible for.

      I will make a post in this regard some day, but ask yourself, is mapping all sections and resolving relocations what you really want to do when injecting a DLL first.

  5. Alexey good stuff man. been reading your post the last couple of days. How did you learn all the internals structs? For someone starting on this I would appreciate a good push to the right direction.

    1. Thanks!
      Well, I could've told you about long RE sessions over Windows system files, but let me tell you the real story. MSDN is full of information about those structures. The only problem is that the description found on MSDN is quite lame and many fields are simply named "reserved". In this case you should simply google for the layout of those structures. That would bring you web resources with relevant information.

      In addition, to better understand all that - try it. Write some programs to access and parse those structures.


Note: Only a member of this blog may post a comment.