Injection into a process supposes injection of the custom code into the address space of some processes. In other words, we get access to the process code, its data, the code of the system DLLs, which are loaded to the process, etc.
Why to inject into a third-party process? There can be a lot of causes, both destructive – steal passwords, hack protected application – and peaceful ones: like antivirus analysis and protection, improvement and maintenance of an application, which source code you don’t have.
1. What is KnownDlls
2. Tech Aspects
2.1 Call Redirection
2.2 Function Hooking
- Section Creation
3. Hook testing
What is KnownDlls
KnownDLL is a Windows mechanism to cache frequently used system DLLs. Initially, it was added to accelerate application loading, but also it can be considered as a security mechanism, as it prevents malware from putting Trojan versions of system DLLs to the application folders (as all main DLLs belong to
KnownDLLs, the version from the application folder will be ignored). We cannot say that this security mechanism is very strong (if you have permission to write to the application folder, you can create much more “tools of chaos”), but still it helps to protect the system.
Let’s consider its work. When the loader comes across a record about DLL import in an executive file, it opens the file and tries to map it to the memory. But there are some nuances. In practice, before it happens, OS loader searches for the section (of MMF type) named \KnownDlls\<file-name-DLL>. If this section exists, then instead of opening the file the loader just use the mentioned section, i.e. maps the section to the process address space. Then it continues in accordance with the “classical” DLL loading rules.
If you compare the key
\KnownDlls sections, you’ll notice that the
\KnownDlls container always includes more records than the mentioned registry key. It’s because the sections in
\KnownDlls are the result of the transitive closure of all DLLs listed in the
KnownDLLs. I.e. if a DLL is mentioned in
KnownDLLs, then all the DLLs, which are statically connected with it, are also included to the
Moreover, if you look closer to the
KnownDLLs registry key, you’ll see that the search paths are not indicated there. It’s because all KnownDLLs are supposed to be located in the folder, indicated in the registry key
This is one more security aspect of
KnownDLLs: requirement of that all
KnownDLLs are placed in the same specific folder.
When the system is loading, it looks for the path in the registry
and creates the sections
\KnownDlls\<file-name-DLL> for each DLL, listed in this registry key.
It should be mentioned that starting with Windows Vista it’s impossible to add directly a string parameter with the DLL path to the
KnownDLLs registry hive, as the system protects this hive from record. But if the application is started with the admin permissions, the user can get the permission to write to this hive.
This article is devoted namely to the method of injecting DLLs using the described mechanism.
Pros of the method of intrusion using KnownDlls:
- We tested this method and confirmed its work on the Windows versions starting with XP and up to WinServer 2008 R2.
- We can hook the calls from the substituted DLL without the called function code change. It is very important for those applications, where the code integrity is checked by means of CRC.
- We can intrude into the protected processes with no problems.
- We can substitute and hook system DLLs calls.
- At the moment of this article release, this method was detected only by Kaspersky CRYSTAL Antivirus.
The main shortcoming is that the undocumented APIs are used.
Now let’s proceed to the technology in detail.
In our sample, we will inject custom code to the web browser as a target application. We work with the Windows7 x64 OS and use Mozilla Firefox, although this method will also work for any other browser that starts as the x32 application.
Expected result: replace the text “Wrong_code” with the text “Cool_code!” in all browser requests and server responses. For example, if we enter the search request with the “Wrong_code” text to the search line of our favorite search engine and click the button to start search, the browser forms an HTTP request to the server, and there, our sample will replace the mentioned text with the “Cool_code!” and only after that it will be sent to the server. The same actions are performed when the server response is obtained.
Scheme of function redirection.
To implement the above mentioned functionality, we’ll substitute the section with the native ws2_32.dll with the section with our DLL. In the sample, the substitution is performed in the x32 process, i.e. ws2_32.dll from the C:\Windows\SysWOW64 folder. To get the path to the
SysWOW64, you can call the
In our sample, we’ll hook the
recv calls of winsock.
So, let’s start.
First, we create DLL for substitution. It will have the same name as the native one - ws2_32.dll.
Creating the stub (inside the DLL for substitution). The idea consists in create export table in dll stub, which functions called will be redirect in original dll. Functions which we must hook we will implement in our application and exporting them us usually.
The main goal is achieved using
#pragma comment compiler directive. It has several parameters, including
EXPORT (verbose about this instruction you can read here: http://msdn.microsoft.com/en-us/library/7f0aews7.aspx). Thus, using a string:
#pragma comment(linker, "/export:<src>=<dst>,@<ord>")
<src> - name of the function to redirect;
<dst> - name of the module and function to be called after redirection;
<ord> - function ordinal number,
we can redirect all necessary calls from our .dll module to the original one.
Using this method we create the file of redirections named redirection.h. It looks as follows.
#pragma comment(linker, "/export:FreeAddrInfoEx=wsNative.FreeAddrInfoEx,@25")
#pragma comment(linker, "/export:FreeAddrInfoExW=wsNative.FreeAddrInfoExW,@26")
#pragma comment(linker, "/export:FreeAddrInfoW=wsNative.FreeAddrInfoW,@27")
#pragma comment(linker, "/export:GetAddrInfoExA=wsNative.GetAddrInfoExA,@28")
#pragma comment(linker, "/export:GetAddrInfoExW=wsNative.GetAddrInfoExW,@29")
#pragma comment(linker, "/export:GetAddrInfoW=wsNative.GetAddrInfoW,@30")
#pragma comment(linker, "/export:GetNameInfoW=wsNative.GetNameInfoW,@31")
#pragma comment(linker, "/export:InetNtopW=wsNative.InetNtopW,@32")
The first string shows that we export the
FreeAddrInfoEx function and it will be redirected to the call of
wsNative.dll. It will be exported with the ordinal. Why
wsNative? It’s because if we use
ws2_32.FreeAddrInfoEx, then the loader will try to load the function from our DLL. The order of listing of the
#pragma comment strings is not important, as the linker will sort the functions in the export table by names and letter case.
To create a stub for the native DLL we need to export all the function of the native DLL and moreover, the ordinals of these functions must coincide.
How we’ll make the native
ws2_32.dll to be called by the name
“wsNative.dll”? It is easy, we will create a symbolic link to the
ws2_32.dll in its directory by means of
CreateSymbolicLink. For example, if native DLL is located in
C:\Windows\SysWOW64\ws2_32.dll, we will create the link with the
C:\Windows\SysWOW64\wsNative.dll path name, which points to
Then we initialize the addresses of the hooked functions from the native DLL. To implement that, we first define the function types:
typedef int (WINAPI* PSEND)(SOCKET s, const char FAR *buf, int len, int flags);
typedef int (WINAPI* PRECV)(SOCKET s, char FAR *buf, int len, int flags);
Then we load the original DLL using LoadLibraryW, and that simply initialize them:
PSEND g_pSend = NULL;
PRECV g_pRecv = NULL;
void InitAddr(T& destAdrr, LPCSTR funcName, HMODULE hModule)
destAdrr = (T)GetProcAddress(hModule, funcName);
void Init(HMODULE hModule)
InitAddr(g_pSend, "send", hModule);
InitAddr(g_pRecv, "recv", hModule);
Now it’s time to implement the custom functions (analogues for the substituted ones), which we’ll redirect calls to. Both functions get as parameters the buffer
buf of the length
send function gets the buffer of the browser request to the server as
buf, and for the
recv function, the
buf buffer represents the response of server. So, it’s enough for us to search and replace the necessary text in
res = std::search(res, buf+len, &searchString, &searchString + MAXSTRINGLEN(searchString));
if (res < buf+len)
memcpy(const_cast<char*>(res), replaceString, MAXSTRINGLEN(replaceString));
After the above described functions finished their work, we need to call the same functions from the native DLL with the modified parameters.
return g_pSend(s, buf, len, flags);
return g_pRecv(s, buf, len, flags);
And finally, we need to export our functions for hooking. Export can be performed in different ways, but in our case, it’s required that our functions are exported by the same names as in the native DLL. So, we create the def file:
Here we can see that
send is the name, which our function
_send will be exported with, and just like that
recv=_recv. The ordinal of the function is indicated after the «@» symbol.
Now we can start to implement the loader for our section. We implement the service that runs at the system start and add our section. To install the section we need the Create permanent shared object permission and so the service with the system permissions fits us perfectly. Service installation is a very simple thing, so let’s start with the section creation.
- First we open the file of our DLL.
- Then we open the directory of
KnownDlls Object Manager using the
NtOpenDirectoryObject, function, whose parameter is the name of the directory. For the x32 process section name is
KnownDLLs32, for x64 processes -
KnownDLLs. For x64 processes, ws2_32.dllis is located in C:\Windows\system32\.
- We create a section with the ws2_32.dll name in this directory. It looks as follows.
InitializeObjectAttributes( §ionAttr, &normalize_section_name,
0, NULL, NULL);
stat = NtCreateSection(&hsec,
m_sectionPath equals to "\KnownDlls32\ws2_32.dll".
- Finally, we increment the reference counter for our section using
NtMakePermanentObject, and pass there the section handle. It’s important, or the object manager will delete our section.
To remove hooks, we delete the section:
if(!(hsec = OpenSection(normalize_section_name)))
throw std::runtime_error("DLL section name to delete does not exist!");
NTSTATUS stat = NtMakeTemporaryObject(hsec);
Then just delete symbolic link to native ws2_32.dll by
DeleteFile and restart computer. As ws2_32.dll is always present in the sections, and we’ve replaced it with the custom one, we should restart to put the native DLL back. Surely, we could simple create the section for the native DLL in the same way and not restart.
The project is built, and now we start
Thus we install our server, it will run at the system start. Then we must start the service, we can do it for example typing
SC START HookInstall
HookInstall.exe without parameters. At the service start, the section is created and then the service is terminated.
First, let’s see the results of our work using for example the utility from sysinternals named
WinObj (you can also use other utilities for object view, like
Section creation result in WinObj.
Pay attention that ws2_32.dll is written in lower case while Windows at the system start creates the section with the name written in upper case.
Now let’s test the work of our code. We start a browser – I used Mozilla Firefox – go to the search, for example yandex.com, and type Wrong_code. Enjoy the result.
Results of hook
You can also test this sample for other applications that use sockets, for example, sending or receiving the substituted text in ICQ.
The sample can be also easily improved, for example, by adding the filtration of text change for the specified IP addresses.
In this article, one of the numerous techniques of process intrusion was considered. Let’s list some of the most famous approaches for hooking:
- Using debugging Tools for Windows;
- Buffers overloading;
- Executable module patching directly on the disk;
- Hooking of the windows procedures using SetWindowHook and SetWindowLong;
- Rewriting of the process original DLL with the custom one on the disk;
- Intrusion using the legal Microsoft functions like “block starting”;
- Loading via the AppInit_DLLs registry hive;
- Loading using manifest;
- Creation of the remote thread…
There are intrusion methods for user mode in this list, kernel mode was not considered. But there are a lot of tricks with kernel mode.
To protect the process from intrusion via
KnownDlls you can use kernel mode hook of API function named
NtCreateSection checking the path to DLL. If it doesn't correspond to the system one, the section creation must be blocked.