Kernel: Загрузка DLL из памяти (x86)
От: x64 Россия http://x64blog.name
Дата: 06.12.08 15:16
Оценка: 21 (6)
Предлагаю вашему вниманию код, загружающий DLL в а.п. произвольного процесса из памяти. Данный код настраивает секции, таблицу импортов и релоки. Замечания к этому коду следующие:

  • Код предназначен для выполнения из ядерного системного потока, созданного функцией PsCreateSystemThread().
  • В данном коде отсутствует настройка таблицы экспорта, в случае если DLL экспортирует какие-либо функции. Для интересующихся здесь
    Автор(ы): Максим М. Гумеров
    Дата: 20.03.2003
    Не вдаваясь в подробности, скажу лишь, что исследование было начато ради сокрытия использования программой на Delphi некоей DLL (написанной на VC++). То есть оператор видит один только Exe-файл, запускает его, а тот каким-то образом подключает функции, содержащиеся изначально (при компиляции проекта) в некоторой DLL.
    .
  • В коде отсутствуют исходники функций с префиксом Kmlib*. Это приватные функции, используемые в коммерческих проектах и я не могу выкладывать их код, однако интересующимся могу объяснить как они реализованы.
  • Обратите внимание, что данный код не добавляет загруженную DLL в список модулей процесса. По моему, совершенно не скромному мнению, это нафиг не нужно, однако для интересующихся опять же могу рассказать как это делается.
  • Код оттестирован на 32-битных версиях Windows XP/2003/Vista/2008, работает как часы.
  • Кстати, ребят, а вы знаете, что этот и ему подобный код вообще-то стоят немалых денег? ))))))))) И вы знаете, мне не жалко, моя личная прибыль от этого не пострадает, да.

    Ну поехали, пример использования внизу.

    BOOLEAN
    LdrIsImportByOrdinal (
    
        ULONG                        uImportDescriptor)
    
    {
        return ((uImportDescriptor & IMAGE_ORDINAL_FLAG32) != 0);
    }
    
    PIMAGE_NT_HEADERS
    LdrGetNtHeaders (
    
        PVOID                pImageBase)
    
    {
        PIMAGE_NT_HEADERS pNtHeaders = NULL;
        PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER) pImageBase;
    
        if (! pImageBase) return NULL;
    
        if (pDosHeader -> e_magic != IMAGE_DOS_SIGNATURE)
        {
            return NULL;
        }
    
        pNtHeaders = (PIMAGE_NT_HEADERS) ((ULONG_PTR) pImageBase + pDosHeader -> e_lfanew);
        if (pNtHeaders -> Signature != IMAGE_NT_SIGNATURE) return NULL;
    
        return pNtHeaders;
    }
    
    NTSTATUS
    LdrProcessImports (
    
        PEPROCESS                    pProcessObject,
        PBYTE                        pImageBase,
        PIMAGE_NT_HEADERS            pNtHeaders,
        PIMAGE_IMPORT_DESCRIPTOR    pImports)
    
    {
        PRTLX_MODULE_INFORMATION pModuleInfo = NULL;
        PIMAGE_IMPORT_DESCRIPTOR pImport = NULL;
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        PUNICODE_STRING pusModuleName = NULL;
        PUNICODE_STRING pusModuleMask = NULL;
        UNICODE_STRING usAsterisk = {0};
        char* pImportedName = NULL;
        PULONG pRvaImport = NULL;
        char* pModuleName = NULL;
        PVOID pProcAddress = NULL;
        ULONG i = 0;
    
        //
        // Check input parameters
        //
    
        if (! pImageBase) return STATUS_INVALID_PARAMETER;
        if (! pImports) return STATUS_INVALID_PARAMETER;
    
        //
        // Initialize locals
        //
    
        RtlInitUnicodeString (&usAsterisk, L"*");
    
        //
        // Get pointer
        //
    
        pImport = pImports;
    
        //
        // Process import table entries
        //
    
        while (pImport -> Name != 0)
        {
            //
            // Get module name
            //
    
            pModuleName = (char*) (pImageBase + pImport -> Name);
    
            //
            // Convert module name to Unicode
            // and create search pattern
            //
    
            status = KmlibCreateUnicodeStringFromAnsiString (
                &pusModuleName,
                pModuleName);
    
            if (! NT_SUCCESS (status)) goto FINISHED;
    
            status = KmlibPathCombine (
                &usAsterisk,
                pusModuleName,
                &pusModuleMask);
    
            if (! NT_SUCCESS (status)) goto FINISHED;
    
            //
            // Find module base address
            //
    
            status = KmlibProcessFindModule (
                pProcessObject,
                NULL,
                pusModuleMask,
                &pModuleInfo);
    
            if (! NT_SUCCESS (status)) goto FINISHED;
    
            //
            // Free local-used objects
            //
    
            KmlibDeleteUnicodeString (&pusModuleMask);
            KmlibDeleteUnicodeString (&pusModuleName);
    
            //
            // Style detection
            //
    
            if (pImport -> TimeDateStamp == 0)
            {
                pRvaImport = (PULONG) (pImageBase + pImport -> FirstThunk);
            }
            else
            {
                pRvaImport = (PULONG) (pImageBase + pImport -> OriginalFirstThunk);
            }
    
            //
            // Process module entries
            //
    
            while (*pRvaImport != 0)
            {
                //
                // Get entry address
                //
    
                if (LdrIsImportByOrdinal (*pRvaImport))
                {
                    pProcAddress = KmlibGetProcedureAddress (pModuleInfo -> ImageBase, (char*) (*pRvaImport & 0xFFFF));
                }
                else
                {
                    pImportedName = (char*) (pImageBase + *pRvaImport + IMPORTED_NAME_OFFSET);
                    pProcAddress = KmlibGetProcedureAddress (pModuleInfo -> ImageBase, pImportedName);
                }
    
                //
                // Check address
                //
    
    
    
                if (! pProcAddress)
                {
                    status = STATUS_PROCEDURE_NOT_FOUND;
                    goto FINISHED;
                }
    
                //
                // Update imported entry
                //
    
                *((PVOID*) pRvaImport) = pProcAddress;
    
                //
                // Next entry within module
                //
    
                pRvaImport ++;
            }
    
            //
            // Local cleanup
            //
    
            KmlibFree (&pModuleInfo);
    
            //
            // Go to next imported module
            //
    
            pImport ++;
        }
    
        //
        // Here we succeeded ;)
        //
    
        status = STATUS_SUCCESS;
    
    FINISHED:
    
        //
        // Cleanup
        //
    
        if (pusModuleName) KmlibDeleteUnicodeString (&pusModuleName);
        if (pusModuleMask) KmlibDeleteUnicodeString (&pusModuleMask);
        if (pModuleInfo) ExFreePool (pModuleInfo);
    
        //
        // Return result
        //
    
        return status;
    }
    
    PIMAGE_BASE_RELOCATION
    LdrProcessRelocationBlock (
    
        ULONG_PTR        uVA,
        ULONG            uSizeOfBlock,
        PUSHORT            puNextOffset,
        LONG            lDelta)
    
    {
        PBYTE pFixupVA = NULL;
        USHORT uOffset = 0;
        LONG lTemp = 0;
        LONG lTempOrig = 0;
        LONGLONG l64Temp64 = 0;
        LONG_PTR lActualDiff = 0;
    
        while (uSizeOfBlock --)
        {
            uOffset = *puNextOffset & ((USHORT) 0xFFF);
            pFixupVA = (PBYTE) (uVA + uOffset);
    
            //
            // Apply the fixups.
            //
    
            switch ((*puNextOffset) >> 12)
            {
                case IMAGE_REL_BASED_HIGHLOW:
    
                    //
                    // HighLow - (32-bits) relocate the high and low half
                    // of an address.
                    //
    
                    *(LONG UNALIGNED*) pFixupVA += (ULONG) lDelta;
    
                    break;
    
                case IMAGE_REL_BASED_HIGH:
    
                    //
                    // High - (16-bits) relocate the high half of an address.
                    //
    
                    lTemp = *(PUSHORT) pFixupVA << 16;
                    lTemp += (ULONG) lDelta;
                    *(PUSHORT) pFixupVA = (USHORT) (lTemp >> 16);
    
                    break;
    
                case IMAGE_REL_BASED_HIGHADJ:
    
                    //
                    // Adjust high - (16-bits) relocate the high half of an
                    // address and adjust for sign extension of low half.
                    //
                    // If the address has already been relocated then don't
                    // process it again now or information will be lost.
                    //
    
                    if (uOffset & LDRP_RELOCATION_FINAL)
                    {
                        puNextOffset ++;
                        uSizeOfBlock --;
    
                        break;
                    }
    
                    lTemp = *(PUSHORT) pFixupVA << 16;
                    lTempOrig = lTemp;
    
                    puNextOffset ++;
                    uSizeOfBlock --;
    
                    lTemp += (LONG) (*(PSHORT) puNextOffset);
                    lTemp += (ULONG) lDelta;
                    lTemp += 0x8000;
    
                    *(PUSHORT) pFixupVA = (USHORT) (lTemp >> 16);
    
                    lActualDiff = ((((ULONG_PTR) (lTemp - lTempOrig)) >> 16) -
                        (((ULONG_PTR) lDelta) >> 16));
    
                    if (lActualDiff == 1)
                    {
                        //
                        // Mark the relocation as needing an increment if it is
                        // relocated again.
                        //
    
                        *(puNextOffset - 1) |= LDRP_RELOCATION_INCREMENT;
                    }
                    else if (lActualDiff != 0)
                    {
                        //
                        // Mark the relocation as cannot be reprocessed.
                        //
    
                        *(puNextOffset - 1) |= LDRP_RELOCATION_FINAL;
                    }
    
                    break;
    
                case IMAGE_REL_BASED_LOW:
    
                    //
                    // Low - (16-bit) relocate the low half of an address.
                    //
    
                    lTemp = *((PSHORT) pFixupVA);
                    lTemp += (ULONG) lDelta;
                    *((PUSHORT) pFixupVA) = (USHORT) lTemp;
    
                    break;
    
                case IMAGE_REL_BASED_ABSOLUTE:
    
                    //
                    // Absolute - no fixup required.
                    //
    
                    break;
    
                case IMAGE_REL_BASED_SECTION:
    
                    //
                    // Section Relative reloc.  Ignore for now.
                    //
    
                    break;
    
                case IMAGE_REL_BASED_REL32:
    
                    //
                    // Relative intrasection. Ignore for now.
                    //
    
                    break;
    
                case IMAGE_REL_BASED_HIGH3ADJ:
    
                    //
                    // Similar to HIGHADJ except this is the third word.
                    // Adjust low half of high ULONG of an address and adjust for
                    // sign extension of the low ULONG.
                    //
    
                    puNextOffset ++;
                    uSizeOfBlock --;
                    
                    l64Temp64 = *(PUSHORT) pFixupVA << 16;
                    l64Temp64 += (LONG) ((SHORT) puNextOffset [1]);
                    l64Temp64 <<= 16;
                    l64Temp64 += (LONG) ((USHORT) puNextOffset [0]);
                    l64Temp64 += lDelta;
                    l64Temp64 += 0x8000;
                    l64Temp64 >>= 16;
                    l64Temp64 += 0x8000;
    
                    *(PUSHORT) pFixupVA = (USHORT) (l64Temp64 >> 16);
                    
                    puNextOffset ++;
                    uSizeOfBlock --;
                    
                    break;
    
                default:
    
                    //
                    // Illegal - illegal relocation type.
                    //
    
                    return (PIMAGE_BASE_RELOCATION) NULL;
            }
    
            puNextOffset ++;
        }
    
        //
        // Return next relocation block
        //
    
        return (PIMAGE_BASE_RELOCATION) puNextOffset;
    }
    
    NTSTATUS
    LdrProcessRelocations (
    
        PBYTE                    pImageBase,
        LONG                    lImageBaseDelta,
        PIMAGE_NT_HEADERS        pNtHeaders,
        PIMAGE_BASE_RELOCATION    pRelocBlocks)
    
    {
        PIMAGE_BASE_RELOCATION pRelocBlock = NULL;
        ULONG uBlockSize = 0;
        PUSHORT pNextOffset = 0;
        ULONG uVA = 0;
        ULONG uRelocsSize = 0;
    
        //
        // Check input parameters
        //
    
        if (! pImageBase) return STATUS_INVALID_PARAMETER;
        if (lImageBaseDelta == 0) return STATUS_INVALID_PARAMETER;
        if (! pNtHeaders) return STATUS_INVALID_PARAMETER;
        if (! pRelocBlocks) return STATUS_INVALID_PARAMETER;
    
        //
        // Get relocation parameters
        //
    
        pRelocBlock = pRelocBlocks;
        uRelocsSize = pNtHeaders -> OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
    
        //
        // Process relocation blocks
        //
    
        while (uRelocsSize > 0)
        {
            //
            // Calculate size of current
            // relocation block
            //
    
            uBlockSize = pRelocBlock -> SizeOfBlock;
            uRelocsSize -= uBlockSize;
    
            uBlockSize -= sizeof (IMAGE_BASE_RELOCATION);
            uBlockSize /= sizeof (USHORT);
    
            //
            // Calculate other parameters
            // needed to process current
            // relocation block
            //
    
            pNextOffset = (PUSHORT) (((PBYTE) pRelocBlock) + sizeof (IMAGE_BASE_RELOCATION));
            uVA = (ULONG) (pImageBase + pRelocBlock -> VirtualAddress);
    
            //
            // Process current relocation block
            //
    
            pRelocBlock = LdrProcessRelocationBlock (uVA, uBlockSize, pNextOffset, lImageBaseDelta);
            if (! pRelocBlock) return STATUS_ILLEGAL_DLL_RELOCATION;
        }
    
        //
        // Success, yep!
        //
    
        return STATUS_SUCCESS;
    }
    
    ULONG
    LdrGetSectionProtection (
    
        ULONG dwCharacteristics)
    
    {
        ULONG dwProtection = 0;
    
        if ((dwCharacteristics & IMAGE_SCN_MEM_NOT_CACHED) != 0)
        {
            dwProtection |= PAGE_NOCACHE;
        }
    
        if ((dwCharacteristics & IMAGE_SCN_MEM_EXECUTE) != 0 &&
            (dwCharacteristics & IMAGE_SCN_MEM_READ) != 0 &&
            (dwCharacteristics & IMAGE_SCN_MEM_WRITE) != 0)
        {
            dwProtection |= PAGE_EXECUTE_READWRITE;
        }
        else if (
            (dwCharacteristics & IMAGE_SCN_MEM_EXECUTE) != 0 &&
            (dwCharacteristics & IMAGE_SCN_MEM_READ) != 0)
        {
            dwProtection |= PAGE_EXECUTE_READ;
        }
        else if (
            (dwCharacteristics & IMAGE_SCN_MEM_READ) != 0 &&
            (dwCharacteristics & IMAGE_SCN_MEM_WRITE) != 0)
        {
            dwProtection |= PAGE_READWRITE;
        }
        else if (
            (dwCharacteristics & IMAGE_SCN_MEM_WRITE) != 0)
        {
            dwProtection |= PAGE_WRITECOPY;
        }
        else if (
            (dwCharacteristics & IMAGE_SCN_MEM_READ) != 0)
        {
            dwProtection |= PAGE_READONLY;
        }
        else
        {
            dwProtection |= PAGE_EXECUTE_READWRITE;
        }
    
        return dwProtection;
    }         
    
    NTSTATUS
    LdrLoadModule (
    
        HANDLE        hProcess,
        PEPROCESS    pProcess,
        PBYTE        pImage,
        PVOID*        ppImageBase,
        PULONG        puSizeOfImage,
        PVOID*        ppEntryPoint,
        HANDLE*        phModuleHandle)
    
    {
        PBYTE pImageBase = NULL;
        LONG lImageBaseDelta = 0;
        PIMAGE_NT_HEADERS pNtHeaders = NULL;
        PIMAGE_SECTION_HEADER pSections = NULL;
        ULONG uSection = 0;
        PBYTE pSource = NULL;
        PBYTE pSectionBase = NULL;
        ULONG uVirtualSectionSize = 0;
        ULONG uRawSectionSize = 0;
        HANDLE hModule = NULL;
        ULONG dwOldProtect = 0;
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        KAPC_STATE kApcState = {0};
        BOOLEAN bAttached = FALSE;
    
        //
        // Check input parameters
        //
    
        if (! hProcess) return STATUS_INVALID_PARAMETER;
        if (! pProcess) return STATUS_INVALID_PARAMETER;
        if (! pImage) return STATUS_INVALID_PARAMETER;
        if (! phModuleHandle) return STATUS_INVALID_PARAMETER;
    
        //
        // Get required pointers
        //
    
        pSource = pImage;
    
        pNtHeaders = (PIMAGE_NT_HEADERS) (pSource + ((PIMAGE_DOS_HEADER) pSource) -> e_lfanew);
        if (! pNtHeaders) return STATUS_INVALID_IMAGE_FORMAT;
    
        //
        // Check image
        //
    
        if (pNtHeaders -> OptionalHeader.SizeOfImage == 0) return STATUS_INVALID_IMAGE_FORMAT;
        if (pNtHeaders -> Signature != IMAGE_NT_SIGNATURE) return STATUS_INVALID_IMAGE_FORMAT;
        if (pNtHeaders -> FileHeader.Machine != IMAGE_FILE_MACHINE_I386) return STATUS_INVALID_IMAGE_FORMAT;
        if (pNtHeaders -> OptionalHeader.SizeOfHeaders >= pNtHeaders -> OptionalHeader.SizeOfImage) return STATUS_INVALID_IMAGE_FORMAT;
    
        //
        // Allocate image memory block
        //
    
        pImageBase = (PBYTE) KmlibVirtualAllocInProcess (
            hProcess,
            pNtHeaders -> OptionalHeader.SizeOfImage);
    
        if (! pImageBase)
        {
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto FINISHED;
        }
    
        //
        // Here we know real image base
        //
    
        hModule = (HANDLE) pImageBase;
    
        //
        // Calculate delta, if it is more than 0,
        // we should process relocation section;
        // it will be done later
        //
    
        lImageBaseDelta = (LONG) (pImageBase - pNtHeaders -> OptionalHeader.ImageBase);
    
        //
        // Attach to the target
        // process's address space
        //
    
        KeStackAttachProcess (pProcess, &kApcState);
        bAttached = TRUE;
    
        //
        // Get section base
        //
    
        pSectionBase = pImageBase + pNtHeaders -> OptionalHeader.SizeOfHeaders;
    
        //
        // Copy headers and make
        // them read-only
        //
    
        RtlCopyMemory (
            pSectionBase,
            pSource,
            pNtHeaders -> OptionalHeader.SizeOfHeaders);
    
        status = KmlibVirtualProtectInProcess (
            hProcess,
            pSectionBase,
            pNtHeaders -> OptionalHeader.SizeOfHeaders,
            PAGE_READONLY);
    
        if (! NT_SUCCESS (status)) goto FINISHED;
    
        //
        // Get sections start address
        //
    
        pSections = (PIMAGE_SECTION_HEADER)
            (((PBYTE) &pNtHeaders -> OptionalHeader) +
            pNtHeaders -> FileHeader.SizeOfOptionalHeader);
    
        //
        // Process sections
        //
    
        for (uSection = 0; uSection < pNtHeaders -> FileHeader.NumberOfSections; uSection ++)
        {
            //
            // Calculate section sizes
            //
    
            uVirtualSectionSize = pSections [uSection].Misc.VirtualSize;
            uRawSectionSize = pSections [uSection].SizeOfRawData;
    
            if (uVirtualSectionSize < uRawSectionSize)
            {
                uVirtualSectionSize = uVirtualSectionSize ^ uRawSectionSize;
                uRawSectionSize = uVirtualSectionSize ^ uRawSectionSize;
                uVirtualSectionSize = uVirtualSectionSize ^ uRawSectionSize;
            }
    
            //
            // Get section base
            //
    
            pSectionBase = pImageBase + pSections [uSection].VirtualAddress;
    
            //
            // Copy section data to the new address
            //
    
            RtlZeroMemory (pSectionBase, uVirtualSectionSize);
            RtlCopyMemory (pSectionBase, pSource + pSections [uSection].PointerToRawData, uRawSectionSize);
        }
    
        //
        // Check relocation section
        //
    
        if (pNtHeaders -> OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0)
        {
            //
            // Process relocations
            //
    
            status = LdrProcessRelocations (
                pImageBase,
                lImageBaseDelta,
                pNtHeaders,
                (PIMAGE_BASE_RELOCATION) (pImageBase + pNtHeaders -> OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress));
    
            if (! NT_SUCCESS (status)) goto FINISHED;
        }
    
        //
        // Check import section
        //
    
        if (pNtHeaders -> OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != 0)
        {
            //
            // Process imports
            //
    
            status = LdrProcessImports (
                pProcess,
                pImageBase,
                pNtHeaders,
                (PIMAGE_IMPORT_DESCRIPTOR) (pImageBase + pNtHeaders -> OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
    
            if (! NT_SUCCESS (status)) goto FINISHED;
        }
    
        //
        // Set protection for sections' pages
        //
    
        for (uSection = 0; uSection < pNtHeaders -> FileHeader.NumberOfSections; uSection ++)
        {
            //
            // Set section protection
            //
    
            status = KmlibVirtualProtectInProcess (
                hProcess,
                pImageBase + pSections [uSection].VirtualAddress,
                pSections [uSection].Misc.VirtualSize,
                LdrGetSectionProtection (pSections [uSection].Characteristics));
    
            if (! NT_SUCCESS (status)) goto FINISHED;
        }
    
        //
        // Return requested data to the caller
        //
    
        *phModuleHandle = hModule;
    
        if (ppImageBase) *ppImageBase = pImageBase;
        if (puSizeOfImage) *puSizeOfImage = pNtHeaders -> OptionalHeader.SizeOfImage;
        if (ppEntryPoint) *ppEntryPoint = (PVOID) (pImageBase + pNtHeaders -> OptionalHeader.AddressOfEntryPoint);
    
        //
        // Here we succeeded!
        //
    
        status = STATUS_SUCCESS;
    
    FINISHED:
    
        //
        // Cleanup
        //
    
        if (bAttached)
        {
            KeUnstackDetachProcess (&kApcState);
        }
    
        if (! NT_SUCCESS (status))
        {
            if (pImageBase)
            {
                //
                // Free all the memory
                // we allocated in this routine
                //
    
                KmlibVirtualFreeInProcess (
                    hProcess,
                    &pImageBase);
            }
        }
    
        //
        // Return result
        //
    
        return status;
    }
    
    NTSTATUS
    LdrLoadImage (
    
        PEPROCESS        pTargetProcess,
        PBYTE            pRawImage,
        PVOID*            ppImageBase,
        PVOID*            ppEntryPoint)
    
    {
    
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        HANDLE hTargetProcess = NULL;
        HANDLE hModule = NULL;
    
        //
        // Open process by pointer
        //
    
        status = KmlibObjectOpen (
            pTargetProcess,
            PROCESS_ALL_ACCESS,
            &hTargetProcess);
    
        if (! NT_SUCCESS (status)) goto FINISHED;
    
        //
        // Load image into target process's
        // address space
        //
    
        status = LdrLoadModule (
            hTargetProcess,
            pTargetProcess,
            pRawImage,
            ppImageBase,
            NULL,
            ppEntryPoint,
            &hModule);
    
        if (! NT_SUCCESS (status)) goto FINISHED;
    
        //
        // Success ;)
        //
    
        status = STATUS_SUCCESS;
    
    FINISHED:
    
        //
        // Cleanup
        //
    
        if (hTargetProcess) KmlibClose (&hTargetProcess);
    
        //
        // Return result
        //
    
        return status;
    }


    Пример использования, ну тут ничего хитрого нет:

    PVOID pRawImage = ... ;
    PEPROCESS pProcessObject = ... ;
    PVOID pImageBase = NULL;
    PVOID pEntryPoint = NULL;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    
    status = LdrLoadImage (
      pProcessObject,
      pRawImage,
      &pImageBase,
      &pEntryPoint);
    
    if (! NT_SUCCESS (status))
    {
      // ошибка
    }


    Ну а как после завершения работы DLL выгрузить её, думаю, проблем не должно быть? Достаточно освободить (MEM_RELEASE) блок виртуальной памяти по адресу pImageBase, при этом размер образа знать не нужно, можно просто в третьем параметре в ZwFreeVirtualMemory() передать указатель на целое, содержащее 0. Разумеется, перед этим сама DLL должна корректно и полностью завершить работу.

    Ну, для чего это может понадобится, я объяснять не буду, — кому это надо и кто в теме, тот знает. Что касается схемы работы, тут могу предложить такой алгоритм:

    1. Делаем ObReferenceObject() на объект целевого процесса.
    2. Внедряем DLL описанным выше способом в целевой процесс и запихиваем любую полезную информацию о процессе и DLL в список.
    3. Создаём системный поток, в качестве контекста передаёт информацию о загруженном модуле (как минимум — адрес базы), а также указатель на EPROCESS целевого процесса.
    4. В системном потоке делаем non-alertable ожидание в KeWaitForSingleObject() на EPROCESS целевого процесса.
    5. После успешного ожидания подчищаем за процессом, т.е. удаляем из ассоциативного списка информацию, которую запихивали на шаге 2.
    6. Делаем ObDereferenceObject() на EPROCESS целевого процесса.

    Информацию, полученную на шаге 2, мы можем использовать, например, для передачи коду загруженной DLL. Кроме того, можно каким-либо образом предусмотреть преждевременную выгрузку DLL из процесса (по инициативе самой DLL), для этого можно использовать именованные события и проч. и проч. Но это уже совсем другая история... Возможно, я расскажу её позже.

    P.S.
    Попутно не могу не съязвить, что хоть автор вот этой вот статейки, Загрузчик PE-файлов
    Автор(ы): Максим М. Гумеров
    Дата: 20.03.2003
    Не вдаваясь в подробности, скажу лишь, что исследование было начато ради сокрытия использования программой на Delphi некоей DLL (написанной на VC++). То есть оператор видит один только Exe-файл, запускает его, а тот каким-то образом подключает функции, содержащиеся изначально (при компиляции проекта) в некоторой DLL.
    , и пишет, что он-де разбирался в вопросе, но его код, отвечающий за настройку релоков — полное говно, китайчеги переплюнули его на раз-два. Выше приводится правильный код.
  • JID: x64j@jabber.ru
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.