Доброе время суток! - Пишу программу на '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. -> Убедительно прошу, не нужно мне советовать следующее: А чем плох приём извлечения программы на диск с последующим запуском... - Задача конкретно поставлена. (Файл не должен извлекаться из ресурсов)
Не помню, имеет ли процесс создаваемый с атрибутами безопасности по умолчанию права PROCESS_VM_WRITE ... Судя по всему прав для записи не хватает. Нда и у мну начали появлятся смутные подозрения, что атрибуты безопасности по умолчанию для релиза и дебага разные используются ??? Попробуй вручную задать нужные права. Если нет, будем дальше смотреть )).
- Мои тестирования приводят к тому, что правила безопастности для режимов Debug и Release разные. - Сейчас посмотрю в инете, покуралесю и отпишусь. # Добавлено: Что-то я не могу понять, как задать атрибут PROCESS_VM_WRITE через функцию CreateProcess(). (Через OpenProcess Нашел, а вот с Create что-то не могу) - Метод научного тыка тоже не помог. - На MSDN касательно структуры: SECURITY_ATTRIBUTES практически ничего не сказано)
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..."); } - Использую эту функцию.
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 В кратце, можно задать используя специальную функцию для создания процесса, или заполнить секьюрити дескриптор, ктр как раз таки находится в структуре секьюрити аттрибутес. Он не прозрачен и управляется через спец функции