Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Injection into a Process Using KnownDlls

, , 6 Feb 2012 CPOL
In his article, we will consider an interesting, universal and rarely used method of code injection into a Windows process using KnownDlls sections. To demonstrate the method work we will develop a sample project to inject into all running processes and intercept some calls from ws2_32.dll.
WinSectionsHookTrunk.zip
HookInstall
HookInstall.vcxproj.filters
HookInstall.vcxproj.user
HookLib
HookLib.def
HookLib.vcxproj.filters
HookLib.vcxproj.user
lib
Debug
HookCommon.lib
Release
HookCommon.lib
ExternalInclude
#include "stdafx.h"
#include "InjectDll.h"
#include "common.h"
#include <iostream>
#include <sstream>
// Loaded Functions

NTSTATUS (__stdcall *NtOpenSection)(
    OUT PHANDLE  SectionHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes
    );

NTSTATUS (__stdcall *NtOpenDirectoryObject)(
    OUT PHANDLE  DirectoryHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes
    );

VOID (__stdcall *RtlInitUnicodeString)(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PCWSTR  SourceString
    );

VOID (__stdcall *RtlFreeUnicodeString)(
    IN PUNICODE_STRING  SourceString
    );

ULONG (__stdcall *RtlNtStatusToDosError) (
    IN NTSTATUS Status
    );

NTSTATUS (__stdcall *NtOpenFile)(
    OUT PHANDLE FileHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    IN ULONG ShareAccess,
    IN ULONG OpenOptions
    );

NTSTATUS (__stdcall *NtCreateSection)(
    OUT PHANDLE SectionHandle, 
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,  // Optional
    IN PLARGE_INTEGER MaximumSize,           // Optional
    IN ULONG SectionPageProtection,
    IN ULONG AllocationAttributes,
    IN HANDLE FileHandle                     // Optional
    );

NTSTATUS (__stdcall *NtMakePermanentObject) (
    __in HANDLE Handle
    );

NTSTATUS (__stdcall *NtMakeTemporaryObject)(
    IN HANDLE  Handle
    );


NTSTATUS (__stdcall *ZwCreateDirectoryObject)(
    OUT PHANDLE  DirectoryHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes
    );
NTSTATUS (__stdcall *ZwCreateSection)(
    OUT PHANDLE SectionHandle, 
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,  // Optional
    IN PLARGE_INTEGER MaximumSize,           // Optional
    IN ULONG SectionPageProtection,
    IN ULONG AllocationAttributes,
    IN HANDLE FileHandle                     // Optional
    );

namespace dll_inj
{

    SectionInjecter::SectionInjecter(bool isX64, const std::wstring& section_name)
        : m_isX64(isX64)
    {
        LocateEntryPoints();
        if (!isX64)
            m_sectionPath = L"\\" KNOWN_DLLS32_KEY;
        else
            m_sectionPath = L"\\" KNOWN_DLLS64_KEY;

        m_sectionDir = m_sectionPath;
        m_sectionPath.append(L"\\").append(section_name);
    }

    void SectionInjecter::LocateEntryPoints()
    {
        HMODULE hProc = GetModuleHandle(TEXT("ntdll.dll"));
        if( !((FARPROC& )RtlInitUnicodeString = GetProcAddress(hProc,
            "RtlInitUnicodeString" )) ) 
        {
            throw std::runtime_error("Function RtlInitUnicodeString not initialized");
        }
        if( !((FARPROC& )RtlFreeUnicodeString = GetProcAddress(hProc,
            "RtlFreeUnicodeString" )) ) 
        {
            throw std::runtime_error("Function RtlFreeUnicodeString not initialized");
        }
        if( !((FARPROC& )NtOpenFile = GetProcAddress(hProc,
            "NtOpenFile" )) ) 
        {
            throw std::runtime_error("Function NtOpenFile not initialized");
        }
        if( !((FARPROC& )NtOpenDirectoryObject = GetProcAddress(hProc,
            "NtOpenDirectoryObject" )) ) 
        {
            throw std::runtime_error("Function NtOpenDirectoryObject not initialized");
        }
        if( !((FARPROC& )NtOpenSection = GetProcAddress(hProc,
            "NtOpenSection" )) ) 
        {
            throw std::runtime_error("Function NtOpenSection not initialized");
        }
        if( !((FARPROC& )NtMakeTemporaryObject = GetProcAddress(hProc,
            "NtMakeTemporaryObject" )) ) 
        {
            throw std::runtime_error("Function NtMakeTemporaryObject not initialized");
        }
        if( !((FARPROC& )NtCreateSection = GetProcAddress(hProc,
            "NtCreateSection" )) ) 
        {
            throw std::runtime_error("Function NtCreateSection not exist");
        }
        if( !((FARPROC& )NtMakePermanentObject = GetProcAddress(hProc,
            "NtMakePermanentObject" )) ) 
        {
            throw std::runtime_error("Function NtMakePermanentObject not initialized");
        }
    }
    namespace
    {
        void ScopedActionOnCreate(HANDLE& hsec, HANDLE& hfile, HANDLE& hdir)
        {
            if(hfile != NULL)
                CloseHandle(hfile);
            if(hsec != NULL)
                CloseHandle(hsec);
            if(hdir != NULL)
                CloseHandle(hdir);
        }

        void ScopedActionOnDelete(HANDLE& hsec)
        {
            if(hsec != NULL)
                CloseHandle(hsec);
        }
    }

    void SectionInjecter::CreateSection( const std::wstring& dll_path )
    {
        HANDLE          hfile = NULL;
        HANDLE          hsec = NULL;
        HANDLE          hdir = NULL;
        
        NTSTATUS        stat;
        IO_STATUS_BLOCK iosb;

        cmn::scoped_action scp_act(std::bind(&ScopedActionOnCreate, hsec, hfile, hdir));

        // init UNICODE_STRING dll name
        std::wstring buf_dll_path(L"\\DosDevices\\");
        buf_dll_path.append(dll_path);
        UNICODE_STRING normalize_dll_path;
        RtlInitUnicodeString(&normalize_dll_path, buf_dll_path.c_str());

        // Open the new DLL
        OBJECT_ATTRIBUTES fileattributes;

        InitializeObjectAttributes( &fileattributes, &normalize_dll_path,
            OBJ_CASE_INSENSITIVE, NULL, NULL);		
        stat = NtOpenFile(&hfile,
                FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE,
                &fileattributes,
                &iosb,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                0);
        if(!NT_SUCCESS(stat))
        {
            std::stringstream stream;
            stream << __FUNCTION__ << " Could not open your DLL file! Error 0x" << std::hex << stat;
            throw std::runtime_error(stream.str());
        }
        // Create appropriate security descriptor

        SECURITY_DESCRIPTOR sd;
        UNICODE_STRING      dir_string;
        OBJECT_ATTRIBUTES   dir_attr;

        RtlInitUnicodeString( &dir_string, m_sectionDir.c_str());
        InitializeObjectAttributes( &dir_attr, &dir_string,
            OBJ_CASE_INSENSITIVE, NULL, NULL);			

        stat = NtOpenDirectoryObject(&hdir,
            DIRECTORY_ALL_ACCESS,
            &dir_attr);    
        if(!NT_SUCCESS(stat))
        {
            std::stringstream stream;
            stream << __FUNCTION__ << " Could not open KnownDlls directory! Error 0x" << std::hex << stat;
            throw std::runtime_error(stream.str());
        }
        DWORD bytes;
        GetKernelObjectSecurity(hdir, DACL_SECURITY_INFORMATION, &sd, sizeof(SECURITY_DESCRIPTOR), &bytes);		

        // Create a new section

        OBJECT_ATTRIBUTES sectionAttr;
        UNICODE_STRING normalize_section_name;
        RtlInitUnicodeString(&normalize_section_name, m_sectionPath.c_str());
        InitializeObjectAttributes( &sectionAttr, &normalize_section_name,
            0, NULL, NULL);		
    
        stat = NtCreateSection(&hsec,
                SECTION_ALL_ACCESS,
                &sectionAttr,
                NULL,
                PAGE_EXECUTE_READWRITE,
                SEC_IMAGE,
                hfile);

        if(!NT_SUCCESS(stat))
        {
            std::stringstream stream;
            stream << __FUNCTION__ << " Could not create section! Error 0x" << std::hex << stat;
            throw std::runtime_error(stream.str());
        }
        stat = NtMakePermanentObject(hsec);

        if(!NT_SUCCESS(stat))
        {
            std::stringstream stream;
            stream << __FUNCTION__ << "Could not add reference on section! Error 0x" << std::hex << stat;
            throw std::runtime_error(stream.str());
        }
    }

    // Open a Section
    HANDLE SectionInjecter::OpenSection(UNICODE_STRING& section_name)
    {
        HANDLE			section;
        OBJECT_ATTRIBUTES attributes;
        InitializeObjectAttributes( &attributes, &section_name,
            OBJ_CASE_INSENSITIVE, NULL, NULL );			

        if(!NT_SUCCESS(
            NtOpenSection( &section, SECTION_ALL_ACCESS, &attributes )))
                return NULL;

        return section;
    }

    void SectionInjecter::DeleteSection()
    {
        HANDLE          hsec = NULL;
        std::function<void()> scp_func = std::bind(&ScopedActionOnDelete, std::ref(hsec));
        cmn::scoped_action scp_act(scp_func);

        // Open dll section
        UNICODE_STRING normalize_section_name;
        RtlInitUnicodeString(&normalize_section_name, m_sectionPath.c_str());
        if(!(hsec = OpenSection(normalize_section_name))) 
        {
            throw std::runtime_error("DLL section name to delete does not exist!");
        }

        // Switch object from permanent to temporary (decrease lock count)
        NTSTATUS stat = NtMakeTemporaryObject(hsec);
        if(!NT_SUCCESS(stat))
        {
            std::stringstream stream;
            stream << __FUNCTION__ << "Could not set permanent flag on system section! Error 0x" << std::hex << stat;
            throw std::runtime_error(stream.str());
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Authors

Apriorit Inc
Apriorit Inc.
Ukraine Ukraine
ApriorIT is a Software Research and Development company that works in advanced knowledge-intensive scopes.
 
Company offers integrated research&development services for the software projects in such directions as Corporate Security, Remote Control, Mobile Development, Embedded Systems, Virtualization, Drivers and others.
 
Official site http://www.apriorit.com
Group type: Organisation

31 members

Follow on   LinkedIn

Kotik Anton
Software Developer (Junior) ApriorIT
Ukraine Ukraine
No Biography provided

| Advertise | Privacy | Mobile
Web01 | 2.8.141015.1 | Last Updated 6 Feb 2012
Article Copyright 2012 by Apriorit Inc, Kotik Anton
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid