Запустите x64 PE из памяти - PullRequest
0 голосов
/ 28 апреля 2019

Я могу успешно загрузить и запустить x32 pe в памяти, но когда я настраиваю переменные для работы с исполняемыми файлами x64, программа бесконечно запускает тысячи своих копий, пока вы либо не убьете программу, либо не исчерпаете памятьвместо того, чтобы запускать pe из памяти.

Я исследовал как можно глубже, но я столкнулся с кирпичной стеной.Используя ссылки типа https://reverseengineering.stackexchange.com/questions/17110/run-pe-file-executable-from-memory,, я все равно остаюсь на том же месте.Код x32 отлично запускает x32 PE из памяти.Код x64 не запускает x64 PE из памяти, а вместо этого запускает свои копии в бесконечном цикле.

Рабочий код x32 C ++ со встроенной программой x32 в unsigned char rawData[11264]

#include <iostream>
#include <string>
#include <Windows.h>
#include <TlHelp32.h>

#ifdef _WIN64
typedef IMAGE_NT_HEADERS64  IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS;
typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER;
#else
typedef IMAGE_NT_HEADERS32  IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS;
typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER;
#endif 


int RunPortableExecutable(void* Image){
    IMAGE_DOS_HEADER* DOSHeader; // For Nt DOS Header symbols
    IMAGE_NT_HEADERS* NtHeader; // For Nt PE Header objects & symbols
    IMAGE_SECTION_HEADER* SectionHeader;

    PROCESS_INFORMATION PI;
    STARTUPINFOA SI;
    CONTEXT* CTX;


    DWORD* ImageBase; //Base address of the image
    void* pImageBase; // Pointer to the image base

    int count;
    char CurrentFilePath[1024];

    DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize Variable
    NtHeader = PIMAGE_NT_HEADERS(DWORD(Image) + DOSHeader->e_lfanew); // Initialize

    GetModuleFileNameA(0, CurrentFilePath, 1024); // path to current executable

    if (NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE File.
    {
        ZeroMemory(&PI, sizeof(PI)); // Null the memory
        ZeroMemory(&SI, sizeof(SI)); // Null the memory

        if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE,
            CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) // Create a new instance of current
            //process in suspended state, for the new image.
            {
                // Allocate memory for the context.
                CTX = LPCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE));
                CTX->ContextFlags = CONTEXT_FULL; // Context is allocated

                if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) //if context is in thread
                {
                    // Read instructions
                    ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&ImageBase), 4, 0);

                    pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase),
                        NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);

                    // Write the image to the process
                    WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);

                    for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++)
                    {
                        SectionHeader = PIMAGE_SECTION_HEADER(DWORD(Image) + DOSHeader->e_lfanew + 248 + (count * 40));

                        WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress),
                            LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0);
                    }
                    WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8),
                        LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0);

                    // Move address of entry point to the eax register
                    CTX->Eax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
                    SetThreadContext(PI.hThread, LPCONTEXT(CTX)); 
                    ResumeThread(PI.hThread); 

                    return 0; 
                }
            }
        }
    }

    unsigned char rawData[11264] = {
        0x4D, 0x5A, 0x90, 0x0, 0x3, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0xFF, ... // x32 application bytes
    };


    int main() {
        RunPortableExecutable(rawData); // run executable from the array
        std::cin.get();
    }

BrokenКод x64 C ++ со встроенной программой x64 в unsigned char rawData[12288]

#include <iostream> 
#include <string> 
#include <Windows.h> 
#include <TlHelp32.h> 

#ifdef _WIN64
typedef IMAGE_NT_HEADERS64  IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS;
typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER;
#else
typedef IMAGE_NT_HEADERS32  IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS;
typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER;
#endif 

int RunPortableExecutable(void* Image)
{
    IMAGE_DOS_HEADER* DOSHeader; // For Nt DOS Header symbols
    IMAGE_NT_HEADERS* NtHeader; // For Nt PE Header objects & symbols
    IMAGE_SECTION_HEADER* SectionHeader;

    PROCESS_INFORMATION PI;
    STARTUPINFOA SI;

    CONTEXT* CTX;

    ULONG_PTR* ImageBase; //Base address of the image
    void* pImageBase; // Pointer to the image base

    int count;
    char CurrentFilePath[1024];

    DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize Variable
    NtHeader = PIMAGE_NT_HEADERS(ULONG_PTR(Image) + DOSHeader->e_lfanew); // Initialize

    GetModuleFileNameA(0, CurrentFilePath, 1024); // path to current executable

    if (NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE File.
    {
        ZeroMemory(&PI, sizeof(PI)); // Null the memory
        ZeroMemory(&SI, sizeof(SI)); // Null the memory

        if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE,
            CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) // Create a new instance of current
            //process in suspended state, for the new image.
        {
            // Allocate memory for the context.
            CTX = LPCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE));
            CTX->ContextFlags = CONTEXT_FULL; // Context is allocated

            if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) //if context is in thread
            {
                // Read instructions
                ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Rbx + 8), LPVOID(&ImageBase), 4, 0);

                pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase),
                    NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);

                // Write the image to the process
                WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);

                for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++)
                {
                    SectionHeader = PIMAGE_SECTION_HEADER(ULONG_PTR(Image) + DOSHeader->e_lfanew + 248 + (ULONG_PTR)(count * 40));

                    WriteProcessMemory(PI.hProcess, LPVOID(ULONG_PTR(pImageBase) + SectionHeader->VirtualAddress),
                        LPVOID(ULONG_PTR(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0);
                }
                WriteProcessMemory(PI.hProcess, LPVOID(CTX->Rbx + 8),
                    LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0);

                // Move address of entry point to the rax register
                CTX->Rax = ULONG_PTR(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
                SetThreadContext(PI.hThread, LPCONTEXT(CTX));
                ResumeThread(PI.hThread);

                return 0;
            }
        }
    }
}

unsigned char rawData[12288] = {
    0x4D, 0x5A, 0x90, 0x0, 0x3, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0xFF, ... // x64 application bytes
};

int main()
{
    RunPortableExecutable(rawData); // run executable from the array
    std::cin.get();
}

Если честно, я не понимаю, почему версия x32 работает отлично, но версия x64 запускает свои копии вместо встроеннойPE ... Единственное, о чем я могу думать, это то, что он запускается не из того места в памяти.

РЕДАКТИРОВАТЬ: я понимаю, что нет реальной практической цели для этого вне того, где используется runPE (в вирусесоздание), но я хочу лучше понять, как они создаются.Нет злого умысла, просто любопытно

1 Ответ

0 голосов
/ 02 мая 2019

Нашел ответ, который искал.Наткнулся на «Форкинг» для Linux, и через несколько дней копания наткнулся на этот древний пост с 2010 года. https://progamercity.net/c-code/218-c-process-forking-running-process-memory.html

, который привел меня глубже к чему-то, что действительно работало для моего случая http://www.rohitab.com/discuss/topic/43043-64bit-pe-loader/

Имеет все необходимое и

//Basic 64bit pe loader...
//Coded by Mist
#include <Windows.h>
#include <stdio.h>
#include "ezyloader.h"
#include "resource.h"

VOID FixImageIAT( PIMAGE_DOS_HEADER dos_header, PIMAGE_NT_HEADERS nt_header)
{
    PIMAGE_THUNK_DATA thunk;
    PIMAGE_THUNK_DATA fixup;
    DWORD iat_rva;
    SIZE_T iat_size;
    HMODULE import_base;
    PIMAGE_IMPORT_DESCRIPTOR import_table =
        (PIMAGE_IMPORT_DESCRIPTOR)(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + 
            (UINT_PTR)dos_header);

    DWORD iat_loc =
        (nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) ? 
        IMAGE_DIRECTORY_ENTRY_IAT : 
        IMAGE_DIRECTORY_ENTRY_IMPORT;

    iat_rva = nt_header->OptionalHeader.DataDirectory[iat_loc].VirtualAddress;
    iat_size = nt_header->OptionalHeader.DataDirectory[iat_loc].Size;

    LPVOID iat = (LPVOID)(iat_rva + (UINT_PTR)dos_header);
    DWORD op;
    VirtualProtect(iat, iat_size, PAGE_READWRITE, &op);
    __try {
        while (import_table->Name) {
            import_base = LoadLibraryA((LPCSTR)(import_table->Name + (UINT_PTR)dos_header));
            fixup = (PIMAGE_THUNK_DATA)(import_table->FirstThunk + (UINT_PTR)dos_header);
            if (import_table->OriginalFirstThunk) {
                thunk = (PIMAGE_THUNK_DATA)(import_table->OriginalFirstThunk + (UINT_PTR)dos_header);
            } else {
                thunk = (PIMAGE_THUNK_DATA)(import_table->FirstThunk + (UINT_PTR)dos_header);
            }

            while (thunk->u1.Function) {
                PCHAR func_name;
                if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64) {
                    fixup->u1.Function = 
                        (UINT_PTR)GetProcAddress(import_base, (LPCSTR)(thunk->u1.Ordinal & 0xFFFF));

                } else {
                    func_name = 
                        (PCHAR)(((PIMAGE_IMPORT_BY_NAME)(thunk->u1.AddressOfData))->Name + (UINT_PTR)dos_header);
                    fixup->u1.Function = (UINT_PTR)GetProcAddress(import_base, func_name);
                }
                fixup++;
                thunk++;
            }
            import_table++;
        }
    }
    __except (1) {

    }
    return;
}

//works with manually mapped files
HANDLE GetImageActCtx(HMODULE module)
{
    WCHAR temp_path[MAX_PATH];
    WCHAR temp_filename[MAX_PATH];
    for (int i = 1; i <= 3; i++) {
        HRSRC resource_info = FindResource(module, MAKEINTRESOURCE(i), RT_MANIFEST); 
        if (resource_info) {
            HGLOBAL resource = LoadResource(module, resource_info);
            DWORD resource_size = SizeofResource(module, resource_info);
            const PBYTE resource_data = (const PBYTE)LockResource(resource);
            if (resource_data && resource_size) {
                FILE *fp;
                errno_t err;
                DWORD ret_val = GetTempPath(MAX_PATH, temp_path);  

                if (0 == GetTempFileName(temp_path, L"manifest.tmp", 0, temp_filename))  
                    return NULL;

                err = _wfopen_s(&fp, temp_filename, L"w");

                if (errno) 
                    return NULL;

                fprintf(fp, resource_data);
                fclose(fp);
                break;
            } else { 
                return NULL;
            }
        } 
    }

    ACTCTXW act = { sizeof(act) };
    act.lpSource = temp_filename;
    return CreateActCtx(&act);
}

//if base_addr points to a byte stream in memory then load module from that
//if base_addr is NULL then attempt to map module into memory from resource
//***note if module is memory mapped manually then it has no loaded module handle 
//and some modules use the module base as the handle for a call and it will fail
LPVOID MapImageToMemory(LPVOID base_addr)
{
    LPVOID mem_image_base = NULL;
    __try {

        PIMAGE_DOS_HEADER raw_image_base = (PIMAGE_DOS_HEADER)base_addr;
        if (!base_addr) {
            HMODULE proc_base = GetModuleHandle(NULL);
            HRSRC resource_info = FindResource(proc_base, MAKEINTRESOURCE(IDR_EXE_FILE1), L"exe_file"); //add your own resource
            if (resource_info) {
                HGLOBAL resource = LoadResource(proc_base, resource_info);
                DWORD resource_size = SizeofResource(proc_base, resource_info);
                const PBYTE resource_data = (const PBYTE)LockResource(resource);
                raw_image_base = (PIMAGE_DOS_HEADER)LockResource(resource);
            }
        } 

        if (IMAGE_DOS_SIGNATURE != raw_image_base->e_magic)
            return NULL;

        PIMAGE_NT_HEADERS nt_header = (PIMAGE_NT_HEADERS)(raw_image_base->e_lfanew + (UINT_PTR)raw_image_base);
        if (IMAGE_NT_SIGNATURE != nt_header->Signature)
            return NULL;

        //only 64bit modules will be loaded
        if (IMAGE_FILE_MACHINE_AMD64 != nt_header->FileHeader.Machine)
            return NULL; 

        //Not going to bother with .net
        if (nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress)
            return NULL;

        PIMAGE_SECTION_HEADER section_header = 
            (PIMAGE_SECTION_HEADER)(raw_image_base->e_lfanew + sizeof(*nt_header) + (UINT_PTR)raw_image_base);

        mem_image_base = VirtualAlloc(
            (LPVOID)(nt_header->OptionalHeader.ImageBase), 
            nt_header->OptionalHeader.SizeOfImage , 
            MEM_COMMIT | MEM_RESERVE, 
            PAGE_EXECUTE_READWRITE);

        if (NULL == mem_image_base) {
            mem_image_base = VirtualAlloc(
                NULL,
                nt_header->OptionalHeader.SizeOfImage,
                MEM_COMMIT | MEM_RESERVE,
                PAGE_EXECUTE_READWRITE);
        }

        if (NULL == mem_image_base)
            return NULL;

        memcpy(mem_image_base, (LPVOID)raw_image_base, nt_header->OptionalHeader.SizeOfHeaders);

        for (int i = 0; i < nt_header->FileHeader.NumberOfSections; i++) {
            memcpy(
                (LPVOID)(section_header->VirtualAddress + (UINT_PTR)mem_image_base), 
                (LPVOID)(section_header->PointerToRawData + (UINT_PTR)raw_image_base), 
                section_header->SizeOfRawData);
            section_header++;
        }
    } 
    __except (1) {

    }
    return mem_image_base;
}

BOOL FixImageRelocations(PIMAGE_DOS_HEADER dos_header, PIMAGE_NT_HEADERS nt_header, ULONG_PTR delta)
{
    ULONG_PTR size;
    PULONG_PTR intruction;
    PIMAGE_BASE_RELOCATION reloc_block =
        (PIMAGE_BASE_RELOCATION)(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress +
            (UINT_PTR)dos_header);

    while (reloc_block->VirtualAddress) {
        size = (reloc_block->SizeOfBlock - sizeof(reloc_block)) / sizeof(WORD);
        PWORD fixup = (PWORD)((ULONG_PTR)reloc_block + sizeof(reloc_block));
        for (int i = 0; i < size; i++, fixup++) {
            if (IMAGE_REL_BASED_DIR64 == *fixup >> 12) {
                intruction = (PULONG_PTR)(reloc_block->VirtualAddress + (ULONG_PTR)dos_header + (*fixup & 0xfff));
                *intruction += delta;
            } 
        }
        reloc_block = (PIMAGE_BASE_RELOCATION)(reloc_block->SizeOfBlock + (ULONG_PTR)reloc_block);
    }
    return TRUE;
}

int main(int argc, char *argv[])
{
    //three options for loading the image from either 1.memory array 2.resource 3.file
    PIMAGE_DOS_HEADER image_base = (PIMAGE_DOS_HEADER)MapImageToMemory((LPVOID)rawData);
    //PIMAGE_DOS_HEADER image_base = (PIMAGE_DOS_HEADER)MapImageToMemory(NULL);//not working with some files like notepad etc
    //PIMAGE_DOS_HEADER image_base = (PIMAGE_DOS_HEADER)LoadLibrary(L"mspaint.exe");//works
    if (!image_base) {
        return 1;
    }

    PIMAGE_NT_HEADERS nt_header = (PIMAGE_NT_HEADERS)(image_base->e_lfanew + (UINT_PTR)image_base);
    HANDLE actctx = NULL;
    UINT_PTR cookie = 0;
    BOOL changed_ctx = FALSE;
    if (nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress) {
        actctx = GetImageActCtx((HMODULE)image_base);
        if (actctx) 
            changed_ctx = ActivateActCtx(actctx, &cookie);
    }

    FixImageIAT(image_base, nt_header);

    if (nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) {
        ptrdiff_t delta = (ptrdiff_t)((PBYTE)image_base - (PBYTE)nt_header->OptionalHeader.ImageBase);
        if (delta)
            FixImageRelocations(image_base, nt_header, delta);
    }

    LPVOID oep = (LPVOID)(nt_header->OptionalHeader.AddressOfEntryPoint + (UINT_PTR)image_base);
    ((void(*)())(oep))();
    //DWORD tid;
    //PCONTEXT ctx;
    //CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)oep, NULL, 0, &tid);

    if (changed_ctx) {
        DeactivateActCtx(0, cookie);
        ReleaseActCtx(actctx);
    }

    getchar();
    return 0;
}

Несколько переменных были названы неверно, и после нескольких быстрых исправлений код отлично работает для загрузки x64 PE.Убраны также вызовы MAKEINTRESOURCE, так как я не буду загружать файл, код уже будет храниться в массиве байтов.

...